Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EQ effect for AudioSegment #492

Merged
merged 24 commits into from Mar 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
406c20d
Issue #316
anubhav-narayan Mar 26, 2020
fb1c943
Update effects.py
anubhav-narayan Mar 27, 2020
6971689
Update scipy_effects.py
anubhav-narayan Mar 27, 2020
eea265d
Added Mid-Side and Reverse Conversion
anubhav-narayan Mar 27, 2020
68d1f7c
Update README.markdown
anubhav-narayan Mar 27, 2020
0d13866
Update README.markdown
anubhav-narayan Mar 27, 2020
bb5faf5
Update utils.py
anubhav-narayan Mar 27, 2020
8909412
Update utils.py
anubhav-narayan Mar 27, 2020
fe1dbea
Update Documentation for eq()
anubhav-narayan May 20, 2020
91c7559
Merge branch 'master' into master
anubhav-narayan May 20, 2020
aa8eb38
Merge branch 'master' into master
anubhav-narayan May 31, 2020
efbbf5b
Merge branch 'master' into master
anubhav-narayan Jun 3, 2020
1b98b78
New eq function
anubhav-narayan Jun 15, 2020
ce47bcb
Merge branch 'master' into anubhav-narayan-eq-patch-1
anubhav-narayan Jun 15, 2020
9469675
Cleaning
anubhav-narayan Jun 16, 2020
c92a2c4
Cleaned
anubhav-narayan Jun 16, 2020
cf8438b
Update scipy_effects.py
anubhav-narayan Jun 16, 2020
28a04c0
Update utils.py
anubhav-narayan Jun 16, 2020
682b20e
Cleaning
anubhav-narayan Jun 16, 2020
3a68fda
Merge branch 'master' into anubhav-narayan-eq-patch-1
anubhav-narayan Jul 26, 2020
408424c
Merge branch 'master' into anubhav-narayan-eq-patch-1
jiaaro Aug 25, 2020
b5d51df
Merge branch 'master' into anubhav-narayan-eq-patch-1
anubhav-narayan Oct 8, 2020
fda49e3
Merge branch 'master' into anubhav-narayan-eq-patch-1
jiaaro Jan 18, 2021
2c3800c
Merge branch 'master' into anubhav-narayan-eq-patch-1
jiaaro Mar 6, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
113 changes: 112 additions & 1 deletion pydub/scipy_effects.py
Expand Up @@ -10,7 +10,7 @@
provided by pydub.effects.
"""
from scipy.signal import butter, sosfilt
from .utils import register_pydub_effect
from .utils import (register_pydub_effect,stereo_to_ms,ms_to_stereo)


def _mk_butter_filter(freq, type, order):
Expand Down Expand Up @@ -62,3 +62,114 @@ def high_pass_filter(seg, cutoff_freq, order=5):
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
"""
filt_mode = ["L+R", "M+S", "L", "R", "M", "S"]
if mode not in filt_mode:
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)


17 changes: 17 additions & 0 deletions pydub/utils.py
Expand Up @@ -415,3 +415,20 @@ def get_supported_decoders():

def get_supported_encoders():
return get_supported_codecs()[1]

def stereo_to_ms(audio_segment):
'''
Left-Right -> Mid-Side
'''
channel = audio_segment.split_to_mono()
channel = [channel[0].overlay(channel[1]), channel[0].overlay(channel[1].invert_phase())]
return AudioSegment.from_mono_audiosegments(channel[0], channel[1])

def ms_to_stereo(audio_segment):
'''
Mid-Side -> Left-Right
'''
channel = audio_segment.split_to_mono()
channel = [channel[0].overlay(channel[1]) - 3, channel[0].overlay(channel[1].invert_phase()) - 3]
return AudioSegment.from_mono_audiosegments(channel[0], channel[1])