Pass_band filter in Python

Viewed 53

I've develop a script that given an input file, extract the voice signal and give in output the signal WITHOUT voice (so the signal that containts the noise):

!pip install pydub
from pydub import AudioSegment
from matplotlib import pyplot as plt
import pandas as pd
import numpy as np
audio = AudioSegment.from_file('fileInput.mp3')

Download fileInput.mp3

enter image description here

samples = audio.get_array_of_samples()
plt.plot(list(samples))

enter image description here

from scipy import signal
sos = signal.butter(10, [100, 4000], 'bandstop', fs=44100, output='sos')

filtered = signal.sosfilt(sos, np.array(samples))

plt.figure(figsize=(10,10))
plt.plot(np.array(samples))
plt.plot(filtered)

plt.title('After 1 - 10 Hz pass-band filter')

plt.tight_layout()

plt.show()

enter image description here

To export the file filtered (so the file that contains the noise) i write that following line:

from scipy.io.wavfile import write

write('./test.wav', 44100, filtered.astype(np.int16))

That codes save a file but the file don't have the same lenght of the original (input) one. enter image description here

As you can notice, the input file has 36second lenght instead the output is 1:12 ...

Download Output file

1 Answers

The input file is stereo. The pydub documentation states that:

AudioSegment(…).get_array_of_samples() Returns the raw audio data as an array of (numeric) samples. Note: if the audio has multiple channels, the samples for each channel will be serialized – for example, stereo audio would look like [sample_1_L, sample_1_R, sample_2_L, sample_2_R, …]

for scipy this is just 1 "long" channel. it can not know that the samples are split like this. A filter also has state. Meaning it can not process data that is shuffled like this and produce the desired output.

either you reshape the data from AudioSegment for example into 2 mono channels like:

[sample1L, sample2L, ...] 

and

[sample1R, sample2R, ...]

and process these individually.

OR

you simply convert the AudioSegment to mono. like so:

audio = AudioSegment.from_file('fileInput.mp3')
audio = audio.set_channels(1)

either way I highly recommend you use the sample rate of the input file, wherever a sample rate is required. else loading a file with other sample rate will shift the filter frequencies and change the length and playback speed of the output file. e.g.

sos = signal.butter(10, [100, 4000], 'bandstop', fs=audio.frame_rate, output='sos')
Related