Here's a Python 3 solution using the built in wave module [1], that works for n channels, and 8,16,24... bits.
import sys
import wave
def read_wav(path):
with wave.open(path, "rb") as wav:
nchannels, sampwidth, framerate, nframes, _, _ = wav.getparams()
print(wav.getparams(), "\nBits per sample =", sampwidth * 8)
signed = sampwidth > 1
byteorder = sys.byteorder
values = []
for _ in range(nframes):
frame = wav.readframes(1)
channel_vals = []
for channel in range(nchannels):
as_bytes = frame[channel * sampwidth: (channel + 1) * sampwidth]
as_int = int.from_bytes(as_bytes, byteorder, signed=signed)
channel_vals.append(as_int)
values.append(channel_vals)
return values, framerate
You can turn the result into a NumPy array.
import numpy as np
data, rate = read_wav(path)
data = np.array(data)
Note, I've tried to make it readable rather than fast. I found reading all the data at once was almost 2x faster. E.g.
with wave.open(path, "rb") as wav:
nchannels, sampwidth, framerate, nframes, _, _ = wav.getparams()
all_bytes = wav.readframes(-1)
framewidth = sampwidth * nchannels
frames = (all_bytes[i * framewidth: (i + 1) * framewidth]
for i in range(nframes))
for frame in frames:
...
Although python-soundfile is roughly 2 orders of magnitude faster (hard to approach this speed with pure CPython).
[1] https://docs.python.org/3/library/wave.html