2
votes

I have 2D array of numpy.int16 (44100Hz) audio samples (1376 of them). Each sample has this format (example values):

[ -4 4 -5 -10 -5 -6 -11 -4 -9 -7 -10 1 -4 -8 -9 -8 -4 -13 -14 -11 -12 -4 -14 -13 -9 -2 -2 -16 -5 -5 -4 3 -5 -4 -8 -11 -10 -12 -16 -7 -8 -14 -14 -14 -16 -17 -8 -13 -9 -6 -9 -6 -9 -8 -12 -1 -4 -8 -2 -2 -2 -8 -8 2 1 -8 3 2 0 -6 0 9 0 -2 0 -1 0 -3 -1 1 -2 -2 0 -6 -1 -2 -3 5 -3 1 -1 -5 -3 0 -3 0 -3 -3 -2 -1 -2 1 -4 1 -6 -3 -2 -4 1 1 -1 -6 2 -1 -2 -5 -6 -5 -6 -2 -4 -1 0 -3 -6 -4 -5 -3]

The entire array is called sample_list (yes, very surprising)

I am attempting to perform a bandpass filter on the sample set in the frequency domain, and then convert it back into the time domain format above. This code below converts the samples perfectly from time domain to frequency domain and then back to time domain, although I still need to apply my bandpass filter to it:

import numpy as np

for samp in sample_list:

    time = np.linspace(0,1,44100) # currently not using

    float_samp = np.float32(samp)
    fft_spectrum = np.fft.rfft(float_samp)

    freqs = np.fft.rfftfreq(len(fft_spectrum), d=time[1]-time[0])  # currently not using

    ### need bandpass filter here (brickwall is fine) - 5000Hz to 8000Hz

    time_domain = np.fft.irfft(fft_spectrum)
    converted = np.int16(time_domain) 

Once filtered, I plan to run my filtered samples through the code found on this page: Python frequency detection to find the fundamental frequency of the tone. The frequency detection code currently works just fine on my unfiltered samples - although it will give me the frequency of the loudest tone, not necessarily the frequency of the tone i'm looking for... thus my need to filter.

A brick-wall filter is fine because I'm looking for the timing and presence of my test tones, and not necessarily the quality.I'm also concerned about extra processing cycles if they're not needed.

I cannot use Scipy and its fft/filtering library, unfortunately, because I am running the code on Android and Scipy is not available for the code platform I'm using (Kivy). I have to use strictly the Numpy library.

Any help/direction is greatly appreciated.

1

1 Answers

0
votes

If a brick wall filter is acceptable, you can just use,

bw_filter = np.zeros(freqs.shape, dtype='float32')
f_0 = 0.5*(8000 + 5000)
df_0 = 0.5*(8000-5000)
bw_filter[np.abs(freqs - f_0) < df_0] = 1.0

fft_spectrum *= bw_filter

I would have been better to use, for instance scipy.signal.butter, but since you don't have access to scipy, reimplementing it might take time.