Rohit Pandey
Rohit Pandey

Reputation: 2681

wavfile.write: Identical arrays but only one works

I have two arrays that are identical (by design because I obtained the second one by doing an FFT and then inverse FFT of the first one). However, when I write the first one to a .wav file, I get sound-producing file as opposed to not when I do the same with the second one. I get no sound. Here is my code:

fs, data = wavfile.read(filename)
a = data.T[0]
c = fft(a)
y2 = fftp.ifft(c)
y2 = np.array([int(round(i)) for i in y2.real])

Now when I try:

sum(y2==a)==len(a)

I get True, which means the two arrays are identical. The only difference is that one has "dtype=int16":

In [322]: a
Out[322]: array([ 1,  1,  1, ..., 21, 20, 21], dtype=int16)
In [321]: y2
Out[321]: array([ 1,  1,  1, ..., 21, 20, 21])

How do I convert the second array to a format where it produces a valid .wav file as well?

Upvotes: 1

Views: 319

Answers (1)

abarnert
abarnert

Reputation: 365597

That "only difference" is a huge difference.

The WAV format, by default, stores samples as signed little-endian 16-bit integers. So, when you write an array of int16 values as raw data, you get a playable WAV file (on a little-endian system, at least).

But when you write an array of int32 values, you get nonsense—each number turns into 2 samples, one of which is the high word of your data, the next of which is the low word. So, you've got your original audio samples at half speed, and interleaves with what's effectively random noise.


Or, alternatively, you can use a non-default WAV format. You didn't show enough of your code to show how you're handling this, but you can write WAV files in a variety of different formats, from 8-bit unsigned int to 32-bit float, and 32-bit signed ints are a valid format. WAV files can even handle compression (including MP3).

But less-common formats may not actually play with every tool; a lot of programs assume a WAV is 16-bit integers, and won't know what to do with anything else.

So, you're probably better off writing 16-bit integers.


Or, maybe you're already doing that—writing 32-bit int values with the right header—and maybe your player is handling them properly.

But you're writing 32-bit int values between -32768 and 32767. Which means you're only using 1/65536th of the dynamic range, so everything will be incredibly quiet. If you want to write 32-bit int values, you want to normalize them to the 32-bit int range, not the 16-bit int range.


The simplest solution to all of these problems is: convert the values back to int16 before writing them:

y3 = y2.astype(np.int16)

Upvotes: 2

Related Questions