Implementing (Butterworth) filter in Python and creating wav file

2.7k views Asked by At

I’m trying to implement a Butterworth bandpass filter to implement on wav files in Python (to which I'm very new). The code I’ve got at the moment is as follows

import wave
import numpy
import matplotlib.pyplot as plt
from scipy import signal
from scipy.signal import filtfilt

# open the audio file and extract some information
spf = wave.open('clip.wav','r')
(nChannels, sampWidth, sampleRate, nFrames, compType, compName) = spf.getparams()

# extract audio from wav file
input_signal = spf.readframes(-1)
input_signal = numpy.fromstring(input_signal, 'Int16')
spf.close()

# create the filter
N = 4
nyq = 0.5 * sampleRate
low = 100 / nyq
high = 500 / nyq
b, a = signal.butter(N, [low, high], btype='band')

# apply filter
output_signal = signal.filtfilt(b, a, input_signal)

# ceate output file
wav_out = wave.open("output.wav", "w")
wav_out.setparams((nChannels, sampWidth, sampleRate, nFrames, compType, compName))

# write to output file
wav_out.writeframes(output_signal.tobytes())
wav_out.close()

# plot the signals
t = numpy.linspace(0, nFrames/sampWidth, nFrames, endpoint = False)
plt.plot(t, input_signal, label='Input')
plt.plot(t, output_signal, label='Output')
plt.show()

Everything works fine (I think), but a problem occurs when I write the filtered data (output_signal) to the output.wav file. For some reason when I listen to the output wav file, it just sounds like loud noise. Also, it’s length (timewise) is four times that of the input file. The strange thing is that when I plot both the input and the output in the time domain, I see that the output signal is a filtered version of the input. However, when analyzing the time-domain of the output sound clip in Audacity it is just loud noise, and doesn’t look like the plotted time-domain figure from Python at all.

I guess I’m doing something wrong when using the filtfilt function or the .tobytes function, since the output array after using .tobytes is much larger than the input array when it is converted by the .fromstring, but I can’t figure out what I am doing wrong.

Thanks!

1

There are 1 answers

0
iggy_poop On

The input signal should be normalized. The graph data shows the y axis from 30000 to -30000. If you normalize the amplitude from 1.0 to -1.0 then you'll be able able to listen to the wave file on audacity.

I used this code to normalize the input signal for 1 channel

amp = 1.0
input_signal = amp * input_signal / max(abs(max(input_signal)),abs(min(input_signal)))

I normalized the amplitude after reading in the input signal using your code and before writing to the output file(after filtering).