Aqui está uma solução Python 3 usando o módulo de onda embutido [1], que funciona para n canais e 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
Você pode transformar o resultado em uma matriz NumPy.
import numpy as np
data, rate = read_wav(path)
data = np.array(data)
Observe, tentei torná-lo legível em vez de rápido. Descobri que ler todos os dados de uma vez foi quase 2x mais rápido. Por exemplo
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:
...
Embora python-soundfile seja cerca de 2 ordens de magnitude mais rápido (difícil aproximar essa velocidade com CPython puro).
[1] https://docs.python.org/3/library/wave.html