5

I'm trying to make a simple 10-bands equalizer with python. I have written two functions in order to make this but I have a issue with gain. I want to set a gain for each band but it not works.

Here there is an example. It is required a mono-channel wav "audio.wav" file to work.

import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile as wav
from scipy import signal
from scipy.signal import butter, lfilter

def bandpass_filter(data, lowcut, highcut, fs, order=5):
    nyq = 0.5 * fs
    low = lowcut / nyq
    high = highcut / nyq
    b, a = butter(order, [low, high], btype='bandpass')
    filtered = lfilter(b, a, data)
    return filtered

def equalizer_10band (data, fs, gain1=0, gain2=0, gain3=0, gain4=0, gain5=0, gain6=0, gain7=0, gain8=0, gain9=0, gain10=0):
    band1 = bandpass_filter(data, 20, 39, fs, order=2)* 10**(gain1/20)
    band2 = bandpass_filter(data, 40, 79, fs, order=3)*10**(gain2/20)
    band3 = bandpass_filter(data, 80, 159, fs, order=3)*10**(gain3/20)
    band4 = bandpass_filter(data, 160, 299, fs, order=3)* 10**(gain4/20)
    band5 = bandpass_filter(data, 300, 599, fs, order=3)* 10**(gain5/20)
    band6 = bandpass_filter(data, 600, 1199, fs, order=3)* 10**(gain6/20)
    band7 = bandpass_filter(data, 1200, 2399, fs, order=3)* 10**(gain7/20)
    band8 = bandpass_filter(data, 2400, 4999, fs, order=3)* 10**(gain8/20)
    band9 = bandpass_filter(data, 5000, 9999, fs, order=3)* 10**(gain9/20)
    band10 = bandpass_filter(data, 10000, 20000, fs, order=3)* 10**(gain10/20)
    signal = band1 + band2 + band3 + band4 + band5 + band6 + band7 + band8 + band9 + band10
    return signal


freq_s, data = wav.read("audio.wav")

N = len(data)
t  = 1/freq_s * np.arange(N) 
f  = freq_s/N * np.arange(N)

#computing fft of original signal
F_data = np.fft.fft(data)/N

#appying equalizer
equalized = equalizer_10band(data, freq_s, -100,-100,-100,0,0,0,0,0,0,0)

#computing fft of filtered signal
Y = np.fft.fft(equalized)/N

plt.figure(figsize=(10, 8))
plt.subplot(2,1,1)
plt.plot(t, equalized,'-b',label=r"$Filtered amplitude(t)$")
plt.xlabel('time[s]')
plt.subplot(2,1,1)
plt.plot(t, data,'-r',label=r"$Original amplitude(t)$")
plt.xlabel('time[s]')
plt.legend()
plt.grid()

plt.subplot(2,1,2)
plt.plot(f[:N//2],np.abs(F_data[:N//2]),'-r',label=r"$Original magnitude(f)$")
plt.xlabel('f [Hz]')
plt.xlim([0,5e3])
plt.plot(f[:N//2],np.abs(Y[:N//2]),'-b',label=r"$Filtered magnitude(f)$")
plt.xlabel('f [Hz]')
plt.xlim([0,5e3])
plt.legend()
plt.tight_layout()
plt.grid()

In the second plot, which shows the spectrum of original and filtered signal overlapped, I would expect to see the filtered signal with the frequencies of the first three bands at zero level, but they remain about the same of the original signal. I attach also a snapshot of the spectrum graphic.

spectrum graphic

Can you help me, please?

Federico
  • 51
  • 1
  • 1
  • 3
  • 1
    See this lovely [debug](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) blog for help. – Prune Feb 28 '19 at 19:38
  • Looking at the plot you attached, I can see that the blue bars for frequencies 1..160 Hz are indeed much lower (near zero) than the red bars. Perhaps mark with a circle the location where you think the outcome does not match your expectation. Adding `plt.gca().set_xscale('log')` to the second plot and adjusting the range with `xlim()` may be useful. – dolphin Jun 04 '20 at 12:55
  • My first guess would be that your audio file is longer than one second, so that the unit of frequencies of the dft is scaled to the lower end of the spectrum (by a factor 1/duration). Solutions would be to process the file in chunks of 1 s or to rescale the frequencies. – alphanum Feb 09 '21 at 11:10

0 Answers0