Nico AD Nico AD - 5 days ago 7
Python Question

scipy.io : can't write wavfile

I have an issue writing a 2d numpy array as a wave file (audio)

According to the doc I should write a 2d int16 numpy array

https://docs.scipy.org/doc/scipy-0.18.1/reference/generated/scipy.io.wavfile.write.html

16-bit PCM -32768 +32767 int16


As my numpy array in range (-1,1) in float32 format I first convert it to 16 bits int

stereoAudio = ((stereoAudio * bits16max)).astype('int16')

print "argmax : " + str(np.amax(stereoAudio))
print "argmin : " + str(np.amin(stereoAudio))

outWaveFileName = "out/file.wav"
print "writing " + outWaveFileName
wavfile.write(outWaveFileName,44100,stereoAudio)


I get the following output :

argmax : 4389
argmin : -4381
writing out/file.wav
Traceback (most recent call last):
File "/Users/me/file.py", line 132, in <module>
wavfile.write(outWaveFileName,44100,stereoAudio)
File "//anaconda/lib/python2.7/site-packages/scipy/io/wavfile.py", line 353, in write
bytes_per_second, block_align, bit_depth)
error: ushort format requires 0 <= number <= USHRT_MAX


as my values are between -4391 and 4389 in 16bits format it should be ok. but my data looks interpreted as ushort

Answer

The write function in scipy.io.wavfile expects the input array to have the shape (num_samples, num_channels). I suspect your array has shape (num_channels, num_samples). Then write tries to put num_samples in a 16 bit field in a structure that gets written to the WAV file, but the value of num_samples is too big for a 16 bit value. (Note that if num_samples were small enough, you would not get an error, but the file would not have the correct format.)

A quick fix is to write the transpose of your array:

wavfile.write(outWaveFileName, 44100, stereoAudio.T)

For example, here is some code that demonstrates the error; x and y have shape (2, 40000):

In [12]: x = (2*np.random.rand(2, 40000) - 1).astype(np.float32)

In [13]: y = (x*32767).astype('int16')

In [14]: from scipy.io import wavfile

In [15]: wavfile.write('foo.wav', 44100, y)
---------------------------------------------------------------------------
error                                     Traceback (most recent call last)
<ipython-input-15-36b8cd0e729c> in <module>()
----> 1 wavfile.write('foo.wav', 44100, y)

/Users/warren/anaconda/lib/python2.7/site-packages/scipy/io/wavfile.pyc in write(filename, rate, data)
    351 
    352         fmt_chunk_data = struct.pack('<HHIIHH', format_tag, channels, fs,
--> 353                                      bytes_per_second, block_align, bit_depth)
    354         if not (dkind == 'i' or dkind == 'u'):
    355             # add cbSize field for non-PCM files

error: ushort format requires 0 <= number <= USHRT_MAX

Transpose the array so the input to wavfile.write has the expected shape:

In [16]: wavfile.write('foo.wav', 44100, y.T)

Read back the data to verify that it worked as expected:

In [22]: fs, z = wavfile.read('foo.wav')

In [23]: np.allclose(z, y.T)
Out[23]: True
Comments