Skip to main content

python-wavefile

CI Coverage Status PyPi Downloads PyPi Version

Pythonic libsndfile wrapper to read and write audio files.

Features

  • Wave file resources open and close as context managers (with)
  • Property accessors for format, channels, length, sample rate... and metadata (ID3...)
  • Real multichannel (not just mono/stereo, but also surround, ambisonics and virtually any number of channels)
  • All libsndfile formats supported, floating point encodings used by default
  • Numpy based interface
  • Generators for efficient block-by-block access
  • Alternative Matlab-like whole-file interface. Less efficient, but convenient for quick and dirty scripts.
  • Shortened constant names for formats (Using namespaces instead of prefixes)
  • Tools for listing available formats
  • Transparent Unicode handling for filenames and text strings
  • No module compilation required (wraps the dll using ctypes)
  • Compatible with Python >= 3.8

You can find the latest version at: https://github.com/vokimon/python-wavefile

Installation

Latest Version Supported Python Versions

Binary dependencies

Python dependencies are managed by the setup.py script. But still there are a couple of binary dependencies. In Debian/Ubuntu, you can install them by casting:

sudo apt-get install -y libsndfile1 portaudio19-dev

PortAudio and its Python wrapper, PyAudio, are just required in order to run the examples.

Using PyPi

pip install wavefile

From sources

If you want to develop, installing editable is recomended. From the source directory:

pip install -e .

Examples

Whole file (slow) processing

Writing and reading whole audio files (like Mathlab primitives do) is not as efficient than block based processing to process long audios. But it could be quite convenient on occassions to have quickly something working.

import wavefile
import numpy as np

def sinusoid(samples, f, samplerate=44100):
    return np.sin( np.linspace(0, 2*np.pi*f*samples/samplerate, samples))[:,np.newaxis]

def channels(*args):
    return np.hstack(args).T


audio = channels(
    sinusoid(100000,  440),
    sinusoid(100000,  880),
    sinusoid(100000, 1760),
)

wavefile.save("sinusoid.wav", audio, 44100)

loadedsamplerate, loaded = wavefile.load("sinusoid.wav")

loaded.shape() # 3, 100000

Block writing example

from wavefile import WaveWriter, Format
import numpy as np

BUFFERSIZE = 512
NCHANNELS = 2

with WaveWriter(
    'synth.ogg',
    channels=NCHANNELS,
    format=Format.OGG|Format.VORBIS,
) as w:
    w.metadata.title = "Some Noise"
    w.metadata.artist = "The Artists"
    data = np.zeros((NCHANNELS,BUFFERSIZE), np.float32)
    for x in range(256):
        # First channel: Saw wave sweep
        data[0,:] = (x*np.arange(BUFFERSIZE, dtype=np.float32)%BUFFERSIZE/BUFFERSIZE)
        # Second channel: Modulated square wave
        data[1,BUFFERSIZE-x*2:] =  1
        data[1,:BUFFERSIZE-x*2] = -1

        # Write it down
        w.write(data)

Block playback example (using pyaudio)

import pyaudio, sys
from wavefile import WaveReader

p = pyaudio.PyAudio()
with WaveReader(sys.argv[1]) as r:

    # Print info
    print("Title: {r.metadata.title}")
    print("Artist: {r.metadata.artist}")
    print(f"Channels: {r.channels}")
    print(f"Format: 0x{r.format:x}")
    print(f"Sample Rate: {r.samplerate}")

    # open pyaudio stream
    stream = p.open(
        format = pyaudio.paFloat32,
        channels = r.channels,
        rate = r.samplerate,
        frames_per_buffer = 512,
        output = True,
    )

    # iterator interface (reuses one array)
    # beware of the frame size, not always 512, but 512 at least
    for frame in r.read_iter(size=512):
        stream.write(frame.flatten(), frame.shape[1])
        sys.stdout.write("."); sys.stdout.flush()

    stream.close()

Block processing example

import sys
from wavefile import WaveReader, WaveWriter

with WaveReader(sys.argv[1]) as r:
    with WaveWriter(
        'output.wav',
        channels=r.channels,
        samplerate=r.samplerate,
    ) as w:
        w.metadata.title = r.metadata.title + " II"
        w.metadata.artist = r.metadata.artist

        for data in r.read_iter(size=512):
            sys.stdout.write("."); sys.stdout.flush()
            w.write(.8*data)

read_iter simplifies the code by transparently:

  • allocating the data block for you,
  • reusing it for each block, and
  • slicing it when the last incomplete block arrives.

Arquitecture

The library consists of two layers

  • libsndfile.py: a plain ctypes based wrapper that provides 1:1 access to the functions of the sndlib library
  • wavefile.py: an interface layer that provides the Pythonic sugar calling the former one.

Existing alternatives (what i like and dislike)

This is 'yet another' wrapper for sndfile. A lot of them appeared just because the standard 'wave' module is quite limited on what and how it does. But none of the wrappers I found around fully suit my needs and that's because I wrote this small and incomplete one, to fit my needs. So this is a summary of what I found, just in case it is useful to anyone.

  • Standard 'wave' module:

    • http://docs.python.org/library/wave.html
    • I think this is the main reason why there are many wrappers around. The standard module to do wave file loading is crap.
    • Based on sndfile but it just writes .wav files.
    • It lacks support for floating point samples, patch provided but ignored see http://bugs.python.org/issue1144504
    • unreadable getX() methods instead of properties.
    • no numpy integration
    • generators, context managers... what?
    • no whole-file shortcuts provided
  • scikits.audiolab

    • git clone https://github.com/cournape/audiolab
    • Cython based + python layer
    • Dual interface: matlab like and OO
    • Property accessors to samplerate...
    • Numpy integration
    • Inplace processing
    • Not in Ubuntu
    • Within a big library
  • pysndfile

  • libsndfile-python

  • libsndfilectypes

python-wavefile reuses most of the libsndfilectypes ctypes wrapper, as not requiring module compilation was seen as a good point. A pythonic layer was added on the top of it.

Metadata

Release files for wavefile 1.6.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wavefile 1.6.3
File Size Uploaded
wavefile-1.6.3.tar.gz 26.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for wavefile 1.6.3
File Interpreter ABI Platform
wavefile-1.6.3-py3-none-any.whl Python 3 none any Details

Total release size: 52.1 kB

Release files / wavefile-1.6.3.tar.gz

Download URL wavefile-1.6.3.tar.gz
Size 26.0 kB
Tags Source
SHA-256 checksum
How to use checksums
f7c4f7ec62199c7a0a7beeeff9e83c00d40848d85d32d288329b01df07001988
BLAKE2b-256 checksum
How to use checksums
5f13822007b324d6d0a3c6a522602db6029975328f4b099d24409107e70b2b73
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.0.1 CPython/3.9.20

Release files / wavefile-1.6.3-py3-none-any.whl

Download URL wavefile-1.6.3-py3-none-any.whl
Size 26.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5c470a594a0aff0151e0a860d3deb18c0ee50f05f9cafb60d93fb54714ada088
BLAKE2b-256 checksum
How to use checksums
f798e633a3bb0c98225b493b0147a36a6168e7e9fb38b17c2fe4c1fe8d46b9c2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.0.1 CPython/3.9.20

Release history Release notifications | RSS feed

This release

1.6.3 This release

2 release files

1.6.2

2 release files

1.5

1 release file

1.4

1 release file

1.3

1 release file

1.1

1 release file

1.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page