|
""" |
|
This module provides scipy versions of high_pass_filter, and low_pass_filter |
|
as well as an additional band_pass_filter. |
|
|
|
Of course, you will need to install scipy for these to work. |
|
|
|
When this module is imported the high and low pass filters from this module |
|
will be used when calling audio_segment.high_pass_filter() and |
|
audio_segment.high_pass_filter() instead of the slower, less powerful versions |
|
provided by pydub.effects. |
|
""" |
|
from scipy.signal import butter, sosfilt |
|
from .utils import (register_pydub_effect,stereo_to_ms,ms_to_stereo) |
|
|
|
|
|
def _mk_butter_filter(freq, type, order): |
|
""" |
|
Args: |
|
freq: The cutoff frequency for highpass and lowpass filters. For |
|
band filters, a list of [low_cutoff, high_cutoff] |
|
type: "lowpass", "highpass", or "band" |
|
order: nth order butterworth filter (default: 5th order). The |
|
attenuation is -6dB/octave beyond the cutoff frequency (for 1st |
|
order). A Higher order filter will have more attenuation, each level |
|
adding an additional -6dB (so a 3rd order butterworth filter would |
|
be -18dB/octave). |
|
|
|
Returns: |
|
function which can filter a mono audio segment |
|
|
|
""" |
|
def filter_fn(seg): |
|
assert seg.channels == 1 |
|
|
|
nyq = 0.5 * seg.frame_rate |
|
try: |
|
freqs = [f / nyq for f in freq] |
|
except TypeError: |
|
freqs = freq / nyq |
|
|
|
sos = butter(order, freqs, btype=type, output='sos') |
|
y = sosfilt(sos, seg.get_array_of_samples()) |
|
|
|
return seg._spawn(y.astype(seg.array_type)) |
|
|
|
return filter_fn |
|
|
|
|
|
@register_pydub_effect |
|
def band_pass_filter(seg, low_cutoff_freq, high_cutoff_freq, order=5): |
|
filter_fn = _mk_butter_filter([low_cutoff_freq, high_cutoff_freq], 'band', order=order) |
|
return seg.apply_mono_filter_to_each_channel(filter_fn) |
|
|
|
|
|
@register_pydub_effect |
|
def high_pass_filter(seg, cutoff_freq, order=5): |
|
filter_fn = _mk_butter_filter(cutoff_freq, 'highpass', order=order) |
|
return seg.apply_mono_filter_to_each_channel(filter_fn) |
|
|
|
|
|
@register_pydub_effect |
|
def low_pass_filter(seg, cutoff_freq, order=5): |
|
filter_fn = _mk_butter_filter(cutoff_freq, 'lowpass', order=order) |
|
return seg.apply_mono_filter_to_each_channel(filter_fn) |
|
|
|
|
|
@register_pydub_effect |
|
def _eq(seg, focus_freq, bandwidth=100, mode="peak", gain_dB=0, order=2): |
|
""" |
|
Args: |
|
focus_freq - middle frequency or known frequency of band (in Hz) |
|
bandwidth - range of the equalizer band |
|
mode - Mode of Equalization(Peak/Notch(Bell Curve),High Shelf, Low Shelf) |
|
order - Rolloff factor(1 - 6dB/Octave 2 - 12dB/Octave) |
|
|
|
Returns: |
|
Equalized/Filtered AudioSegment |
|
""" |
|
filt_mode = ["peak", "low_shelf", "high_shelf"] |
|
if mode not in filt_mode: |
|
raise ValueError("Incorrect Mode Selection") |
|
|
|
if gain_dB >= 0: |
|
if mode == "peak": |
|
sec = band_pass_filter(seg, focus_freq - bandwidth/2, focus_freq + bandwidth/2, order = order) |
|
seg = seg.overlay(sec - (3 - gain_dB)) |
|
return seg |
|
|
|
if mode == "low_shelf": |
|
sec = low_pass_filter(seg, focus_freq, order=order) |
|
seg = seg.overlay(sec - (3 - gain_dB)) |
|
return seg |
|
|
|
if mode == "high_shelf": |
|
sec = high_pass_filter(seg, focus_freq, order=order) |
|
seg = seg.overlay(sec - (3 - gain_dB)) |
|
return seg |
|
|
|
if gain_dB < 0: |
|
if mode == "peak": |
|
sec = high_pass_filter(seg, focus_freq - bandwidth/2, order=order) |
|
seg = seg.overlay(sec - (3 + gain_dB)) + gain_dB |
|
sec = low_pass_filter(seg, focus_freq + bandwidth/2, order=order) |
|
seg = seg.overlay(sec - (3 + gain_dB)) + gain_dB |
|
return seg |
|
|
|
if mode == "low_shelf": |
|
sec = high_pass_filter(seg, focus_freq, order=order) |
|
seg = seg.overlay(sec - (3 + gain_dB)) + gain_dB |
|
return seg |
|
|
|
if mode=="high_shelf": |
|
sec=low_pass_filter(seg, focus_freq, order=order) |
|
seg=seg.overlay(sec - (3 + gain_dB)) +gain_dB |
|
return seg |
|
|
|
|
|
@register_pydub_effect |
|
def eq(seg, focus_freq, bandwidth=100, channel_mode="L+R", filter_mode="peak", gain_dB=0, order=2): |
|
""" |
|
Args: |
|
focus_freq - middle frequency or known frequency of band (in Hz) |
|
bandwidth - range of the equalizer band |
|
channel_mode - Select Channels to be affected by the filter. |
|
L+R - Standard Stereo Filter |
|
L - Only Left Channel is Filtered |
|
R - Only Right Channel is Filtered |
|
M+S - Blumlien Stereo Filter(Mid-Side) |
|
M - Only Mid Channel is Filtered |
|
S - Only Side Channel is Filtered |
|
Mono Audio Segments are completely filtered. |
|
filter_mode - Mode of Equalization(Peak/Notch(Bell Curve),High Shelf, Low Shelf) |
|
order - Rolloff factor(1 - 6dB/Octave 2 - 12dB/Octave) |
|
|
|
Returns: |
|
Equalized/Filtered AudioSegment |
|
""" |
|
channel_modes = ["L+R", "M+S", "L", "R", "M", "S"] |
|
if channel_mode not in channel_modes: |
|
raise ValueError("Incorrect Channel Mode Selection") |
|
|
|
if seg.channels == 1: |
|
return _eq(seg, focus_freq, bandwidth, filter_mode, gain_dB, order) |
|
|
|
if channel_mode == "L+R": |
|
return _eq(seg, focus_freq, bandwidth, filter_mode, gain_dB, order) |
|
|
|
if channel_mode == "L": |
|
seg = seg.split_to_mono() |
|
seg = [_eq(seg[0], focus_freq, bandwidth, filter_mode, gain_dB, order), seg[1]] |
|
return AudioSegment.from_mono_audio_segements(seg[0], seg[1]) |
|
|
|
if channel_mode == "R": |
|
seg = seg.split_to_mono() |
|
seg = [seg[0], _eq(seg[1], focus_freq, bandwidth, filter_mode, gain_dB, order)] |
|
return AudioSegment.from_mono_audio_segements(seg[0], seg[1]) |
|
|
|
if channel_mode == "M+S": |
|
seg = stereo_to_ms(seg) |
|
seg = _eq(seg, focus_freq, bandwidth, filter_mode, gain_dB, order) |
|
return ms_to_stereo(seg) |
|
|
|
if channel_mode == "M": |
|
seg = stereo_to_ms(seg).split_to_mono() |
|
seg = [_eq(seg[0], focus_freq, bandwidth, filter_mode, gain_dB, order), seg[1]] |
|
seg = AudioSegment.from_mono_audio_segements(seg[0], seg[1]) |
|
return ms_to_stereo(seg) |
|
|
|
if channel_mode == "S": |
|
seg = stereo_to_ms(seg).split_to_mono() |
|
seg = [seg[0], _eq(seg[1], focus_freq, bandwidth, filter_mode, gain_dB, order)] |
|
seg = AudioSegment.from_mono_audio_segements(seg[0], seg[1]) |
|
return ms_to_stereo(seg) |
|
|
|
|
|
|