I am trying to use the NumPy library for Python to do some frequency analysis. I have two .wav files that both contain a 440 Hz sine wave. One of them I generated with the NumPy sine function, and the other I generated in Audacity. The FFT works on the Python-generated one, but does nothing on the Audacity one.
Here are links to the two files:
The non-working file: 440_audacity.wav
The working file: 440_gen.wav
This is the code I am using to do the Fourier transform:
import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile as wave
infile = "440_gen.wav"
rate, data = wave.read(infile)
data = np.array(data)
data_fft = np.fft.fft(data)
frequencies = np.abs(data_fft)
plt.subplot(2,1,1)
plt.plot(data[:800])
plt.title("Original wave: " + infile)
plt.subplot(2,1,2)
plt.plot(frequencies)
plt.title("Fourier transform results")
plt.xlim(0, 1000)
plt.tight_layout()
plt.show()
I have two 16-bit PCM .wav files, one from Audacity and one created with the NumPy sine function. The NumPy-generated one gives the following (correct) result, with the spike at 440Hz:
The one I created with Audacity, although the waveform appears identical, does not give any result on the Fourier transform:
I admit I am at a loss here. The two files should contain in effect the same data. They are encoded the same way, and the wave forms appear identical on the upper graph.
Here is the code used to generate the working file:
import numpy as np
import wave
import struct
import matplotlib.pyplot as plt
from operator import add
freq_one = 440.0
num_samples = 44100
sample_rate = 44100.0
amplitude = 12800
file = "440_gen.wav"
s1 = [np.sin(2 * np.pi * freq_one * x/sample_rate) * amplitude for x in range(num_samples)]
sine_one = np.array(s1)
nframes = num_samples
comptype = "NONE"
compname="not compressed"
nchannels = 1
sampwidth = 2
wav_file = wave.open(file, 'w')
wav_file.setparams((nchannels, sampwidth, int(sample_rate), nframes, comptype, compname))
for s in sine_one:
wav_file.writeframes(struct.pack('h', int(s)))
Since answering this question @Konyukh Fyodorov was able to provide a better and properly justified solution (below).
The following worked for me and produced the plots as expected. Unfortunately I cannot piece together quite why this works, but I'm sharing this solution in the hope it may assist someone else to make that leap.
import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile as wave
infile = "440_gen.wav"
rate, data = wave.read(infile)
data = np.array(data)
# Use first 44100 datapoints in transform
data_fft = np.fft.fft(data[:44100])
frequencies = np.abs(data_fft)
plt.subplot(2,1,1)
plt.plot(data[:800])
plt.title("Original wave: " + infile)
plt.subplot(2,1,2)
plt.plot(frequencies)
plt.title("Fourier transform results")
plt.xlim(0, 1000)
plt.tight_layout()
plt.show()