Search code examples
pythonnumpyscipyfftaudacity

NumPy Fast Fourier transform (FFT) does not work on sine wave generated in Audacity


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: FFT on the numpy generated file

The one I created with Audacity, although the waveform appears identical, does not give any result on the Fourier transform: FFT on the audacity generated file

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)))

Solution

  • 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()
    

    enter image description here

    enter image description here