Parsing Wave Files in Python
It sounds like a simple task – grab some WAVE audio files and parse them so we can read the metadata and samples in Python. I mean, the WAVE (really, RIFF with WAVE) format is ancient and contains uncompressed samples. Surely it’s just a matter of using the built-in chunks library.
If only. The chunk library can only really read the header and dumps the rest on you. If you’re not wary, you’ll get caught in the trap of only reading the RIFF chunk that acts as the wrapper for the file. The interesting bits are in sub-chunks embedded in the body of the RIFF chunk.
You’ll also need to hand-crank decoding the contents of the chunks. Not world ending but a bit of fun with pack/unpack. These audio files are packed binary formats. Even the header consists of a 4 char name and 32 bit length. Note that with the RIFF outer chunk, that puts a hard limit on file size.
The most important chunks are left for you to decode – format (fmt) and data. These indicate the format the data is encoded in and contain the encoded audio samples. Sample rate, number of channels and bit depth are important characteristics.
At this point, it’s time for a little known fact, WAVE files can be compressed. There’s nothing stopping MP2/3 encoding being used. It’s less common nowadays but made sense when storage space was more of a premium and these were dominant digital audio tape encodings. Heck, MP2 is still in active service on DAB multiplexes (DAB+ is AAC for reference).
I’m not so interested in compressed audio files but do need to know when I’ve got one and send it through a different path for decoding. What I am interested in is CART chunk. Like all good broadcast industry standards, it costs money to get the details. A shame really as it’s critical for sharing metadata and especially cue points between playout systems.
As you can imagine, there’s little out there with support for it. I’ve written the odd PowerShell and even JS/TS encoder/decoder in the past but I couldn’t find anything for Python.
Until now – I’ve written and released wave-chunk-parser. It can both parse and encode WAVE files with CART chunk as well. I’ve done all that nasty pack/unpack stuff for you. Though admittedly it wasn’t rocket science – most of the material I’ve seen defines chunks in C structs!
Using the library is simple:
from wave_chunk_parser.chunks import RiffChunk
with open("file.wav", "rb") as file:
riff_chunk = RiffChunk.from_file(file)
There are RIFF, format, data and cart chunks supported. With a file read in as a RIFF chunk, you can access the sub chunks through riff_chunk.sub_chunks. It’s a dictionary pinned on the binary string chunk names such as b”data”.
The data chunk uses numpy arrays to hold the vectors of audio samples. You can then use or mainuplate this as you like.
The library also supports generating a blob to write to a file. To do this, you’ll need a list of chunks:
chunks = [FormatChunk, DataChunk, CartChunk]
Note that the format chunk must come before the data chunk! We need to know how to decode it later. The cart chunk can appear anywhere in the list and is completely optional.
To get the blob itself:
riff_chunk = RiffChunk(chunks)
blob = riff_chunk.to_bytes()
You can then write this out to a file. It’s as simple as that and there’s some examples in the test suite.
So, what’s stopping you from pip install wave-chunk-parser?