-
-
Save avih/41acff712abd32e1f436235388c8b523 to your computer and use it in GitHub Desktop.
--[[ | |
mpv 5-bands equalizer with visual feedback. | |
Copyright 2016 Avi Halachmi ( https://github.com/avih ) | |
License: public domain | |
Default config: | |
- Enter/exit equilizer keys mode: ctrl+e | |
- Equalizer keys: 2/w control bass ... 6/y control treble, and middles in between | |
- Toggle equalizer without changing its values: ctrl+E (ctrl+shift+e) | |
- Reset equalizer values: alt+ctrl+e | |
- See ffmpeg filter description below the config section | |
--]] | |
-- ------ config ------- | |
local start_keys_enabled = false -- if true then choose the up/down keys wisely | |
local key_toggle_bindings = 'ctrl+e' -- enable/disable equalizer key bindings | |
local key_toggle_equalizer = 'ctrl+E' -- enable/disable equalizer | |
local key_reset_equalizer = 'alt+ctrl+e' -- sets all bands to gain 0 | |
-- reduce clicks (update the filter chain inplace). requires ffmpeg >= 4.0 | |
local inplace = true | |
-- configure the equalizer keys, bands, and initial gain value for each band | |
local bands = { | |
-- octave is x2. e.g. two octaves range around f is from f/2 to f*2 | |
-- {up down} | |
{keys = {'2', 'w'}, filter = {'equalizer=f=64:width_type=o:w=3.3:g=', 0}}, -- 20-200 | |
{keys = {'3', 'e'}, filter = {'equalizer=f=400:width_type=o:w=2.0:g=', 0}}, -- 200-800 | |
{keys = {'4', 'r'}, filter = {'equalizer=f=1250:width_type=o:w=1.3:g=', 0}}, -- 800-2k | |
{keys = {'5', 't'}, filter = {'equalizer=f=2830:width_type=o:w=1.0:g=', 0}}, -- 2k-4k | |
{keys = {'6', 'y'}, filter = {'equalizer=f=5600:width_type=o:w=1.0:g=', 0}}, -- 4k-8k | |
--{keys = {'7', 'u'}, filter = {'equalizer=f=12500:width_type=o:w=1.3:g=', 0}} -- - 20k | |
} | |
--[[ | |
https://ffmpeg.org/ffmpeg-filters.html#equalizer | |
Apply a two-pole peaking equalisation (EQ) filter. With this filter, the signal-level | |
at and around a selected frequency can be increased or decreased, whilst (unlike | |
bandpass and bandreject filters) that at all other frequencies is unchanged. | |
In order to produce complex equalisation curves, this filter can be given several | |
times, each with a different central frequency. | |
The filter accepts the following options: | |
frequency, f: Set the filter's central frequency in Hz. | |
width_type: Set method to specify band-width of filter. | |
h Hz | |
q Q-Factor | |
o octave | |
s slope | |
width, w: Specify the band-width of a filter in width_type units. | |
gain, g: Set the required gain or attenuation in dB. Beware of clipping when | |
using a positive gain. | |
--]] | |
-- ------- utils -------- | |
function iff(cc, a, b) if cc then return a else return b end end | |
function ss(s, from, to) return s:sub(from, to - 1) end | |
--[[-- utils | |
local mp_msg = require 'mp.msg' | |
function midwidth(min, max) -- range --> middle freq and width in octaves | |
local wo = math.log(max / min) / math.log(2) | |
mp_msg.info(min, max / (2 ^ (wo / 2)) .. ' <' .. wo .. '>', max) | |
end | |
function range(f, wo) -- middle freq and width in octaves --> range | |
local h = 2 ^ (wo / 2) | |
mp_msg.info(f / h, '' .. f .. ' <' .. wo .. '>' , f * h) | |
end | |
--]] | |
-- return the filter as numbers {frequency, gain} | |
local function filter_data(filter) | |
return { tonumber(ss(filter[1], 13, filter[1]:find(':', 14, true))), filter[2] } | |
end | |
-- the mpv command string for adding the filter (only used when gain != 0) | |
local function get_cmd(filter) | |
return 'no-osd af add lavfi=[' .. filter[1] .. filter[2] .. ']' | |
end | |
-- setup named filter equalizer<band> | |
local function get_cmd_band_inplace_setup(filter, band, reset) | |
local v = reset and 0 or filter[2] | |
return 'no-osd af add @equalizer'.. band ..':lavfi=[' .. filter[1] .. v .. ']' | |
end | |
-- update gain of named filter equalizer<band> inplace | |
local function get_cmd_band_inplace(filter, band, reset) | |
local v = reset and 0 or filter[2] | |
return 'no-osd af-command equalizer'.. band ..' g '.. v | |
end | |
-- these two vars are used globally | |
local bindings_enabled = start_keys_enabled | |
local eq_enabled = true -- but af is not touched before the equalizer is modified | |
local inplace_init = false | |
-- ------ OSD handling ------- | |
local function ass(x) | |
-- local gpo = mp.get_property_osd | |
-- return gpo('osd-ass-cc/0') .. x .. gpo('osd-ass-cc/1') | |
-- seemingly it's impossible to enable ass escaping with mp.set_osd_ass, | |
-- so we're already in ass mode, and no need to unescape first. | |
return x | |
end | |
local function fsize(s) -- 100 is the normal font size | |
return ass('{\\fscx' .. s .. '\\fscy' .. s ..'}') | |
end | |
local function color(c) -- c is RRGGBB | |
return ass('{\\1c&H' .. ss(c, 5, 7) .. ss(c, 3, 5) .. ss(c, 1, 3) .. '&}') | |
end | |
local function cnorm() return color('ffffff') end -- white | |
local function cdis() return color('909090') end -- grey | |
local function ceq() return iff(eq_enabled, color('ffff90'), cdis()) end -- yellow-ish | |
local function ckeys() return iff(bindings_enabled, color('90FF90'), cdis()) end -- green-ish | |
local DUR_DEFAULT = 1.5 -- seconds | |
local osd_timer = nil | |
-- duration: seconds, or default if missing/nil, or infinite if 0 (or negative) | |
local function ass_osd(msg, duration) -- empty or missing msg -> just clears the OSD | |
duration = duration or DUR_DEFAULT | |
if not msg or msg == '' then | |
msg = '{}' -- the API ignores empty string, but '{}' works to clean it up | |
duration = 0 | |
end | |
mp.set_osd_ass(0, 0, msg) | |
if osd_timer then | |
osd_timer:kill() | |
osd_timer = nil | |
end | |
if duration > 0 then | |
osd_timer = mp.add_timeout(duration, ass_osd) -- ass_osd() clears without a timer | |
end | |
end | |
-- some visual messing about | |
local function updateOSD() | |
local msg1 = fsize(70) .. 'Equalizer: ' .. ceq() .. iff(eq_enabled, 'On', 'Off') | |
.. ' [' .. key_toggle_equalizer .. ']' .. cnorm() | |
local msg2 = fsize(70) | |
.. 'Key-bindings: ' .. ckeys() .. iff(bindings_enabled, 'On', 'Off') | |
.. ' [' .. key_toggle_bindings .. ']' .. cnorm() | |
local msg3 = '' | |
for i = 1, #bands do | |
local data = filter_data(bands[i].filter) | |
local info = | |
ceq() .. fsize(50) .. data[1] .. ' hz ' .. fsize(100) | |
.. iff(data[2] ~= 0 and eq_enabled, '', cdis()) .. data[2] .. ceq() | |
.. fsize(50) .. ckeys() .. ' [' .. bands[i].keys[1] .. '/' .. bands[i].keys[2] .. ']' | |
.. ceq() .. fsize(100) .. cnorm() | |
msg3 = msg3 .. iff(i > 1, ' ', '') .. info | |
end | |
local nlb = '\n' .. ass('{\\an1}') -- new line and "align bottom for next" | |
local msg = ass('{\\an1}') .. msg3 .. nlb .. msg2 .. nlb .. msg1 | |
local duration = iff(start_keys_enabled, iff(bindings_enabled and eq_enabled, 5, nil) | |
, iff(bindings_enabled, 0, nil)) | |
ass_osd(msg, duration) | |
end | |
-- ------- actual functionality ------ | |
local function updateAF_simple() -- setup an audio filter chain which applies the equalizer | |
mp.command('no-osd af clr ""') -- af clr must have two double-quotes | |
if not eq_enabled then return end | |
for i = 1, #bands do | |
local f = bands[i].filter | |
if f[2] ~= 0 then -- insert filters only were the gain is non default | |
mp.command(get_cmd(f)) | |
end | |
end | |
end | |
-- update gains of the whole equalizer inplace, also setup on first time | |
local function updateAF_inplace() | |
for i = 1, #bands do | |
local f = bands[i].filter | |
if not inplace_init then | |
mp.command(get_cmd_band_inplace_setup(f, i, not eq_enabled)) | |
end | |
mp.command(get_cmd_band_inplace(f, i, not eq_enabled)) | |
end | |
inplace_init = true | |
end | |
if inplace then | |
updateAF = updateAF_inplace | |
else | |
updateAF = updateAF_simple | |
end | |
local function getBind(filter, delta) | |
return function() -- onKey | |
filter[2] = filter[2] + delta | |
updateAF() | |
updateOSD() | |
end | |
end | |
local function update_key_binding(enable, key, name, fn) | |
if enable then | |
mp.add_forced_key_binding(key, name, fn, 'repeatable') | |
else | |
mp.remove_key_binding(name) | |
end | |
end | |
local function toggle_bindings(explicit, no_osd) | |
bindings_enabled = iff(explicit ~= nil, explicit, not bindings_enabled) | |
for i = 1, #bands do | |
local k = bands[i].keys | |
local f = bands[i].filter | |
update_key_binding(bindings_enabled, k[1], 'eq' .. k[1], getBind(f, 1)) -- up | |
update_key_binding(bindings_enabled, k[2], 'eq' .. k[2], getBind(f, -1)) -- down | |
end | |
if not no_osd then updateOSD() end | |
end | |
local function toggle_equalizer() | |
eq_enabled = not eq_enabled | |
updateAF() | |
updateOSD() | |
end | |
local function reset_equalizer() | |
for i = 1, #bands do | |
bands[i].filter[2] = 0 | |
end | |
updateAF() | |
updateOSD() | |
end | |
mp.add_forced_key_binding(key_toggle_equalizer, toggle_equalizer) | |
mp.add_forced_key_binding(key_toggle_bindings, toggle_bindings) | |
mp.add_forced_key_binding(key_reset_equalizer, reset_equalizer) | |
if bindings_enabled then toggle_bindings(true, true) end | |
if inplace then | |
-- inplace changes (using af-command LABEL ...) don't recreate the filter | |
-- chain and can reduce perceptible discontinuities, however, they also | |
-- don't seem to persist across playlist items (probably reset on re-init). | |
-- this hook persists the current values between files, by replacing the | |
-- filters with new ones with the current values (not sub-values inplace). | |
mp.add_hook("on_before_start_file", 50, function() | |
inplace_init = false -- ensure the filters are recreated if exist | |
updateAF() | |
end) | |
end | |
-- init: setup the equalizer if the initial gain is not 0 | |
for i = 1, #bands do | |
if bands[i].filter[2] ~= 0 then | |
updateAF() | |
break | |
end | |
end |
The thing is that I want to use this on the MPV-android app, and I can't really toggle because there's no keyboard
But this entire script is about changing the equalizer with a KB. If you don't have an KB then this script is not for you.
But I did try setting start keys to true and yes its working on my pc from the get-go but it's not equalizing anything.
Doesn't equalize anything right away? or doesn't equalize even after you press e.g. the 2/w keys? For me it does equalize after I press e.g. 2/w.
The script defaults to all values at 0, so it's not supposed to equalize anything on startup even when the keys are enabled. Note the keys are enabled, not some preset equalizer value. There are no preset values with this script. It loads with 0 gain on all bands and then you modify it with the KB (when keys are enabled). That's what the script does.
Did the previous version of the script work for you? I.e. is it a regression? or is it the first time you try to use this script?
But this entire script is about changing the equalizer with a KB. If you don't have an KB then this script is not for you.
Oh, I see sorry.
Doesn't equalize anything right away? or doesn't equalize even after you press e.g. the 2/w keys? For me it does equalize after I press e.g. 2/w.
Yeah on my laptop I can use it perfectly fine, it equalizes when i press the 2/w keys
Did the previous version of the script work for you? I.e. is it a regression? or is it the first time you try to use this script?
Yeah the previous one's have worked and this one does too. I've been using this script for a while now and it's really helpful
Thanks.
OK, so the older and newer versions work on the laptop?
And on android you can't use it because you don't have a KB there? and neither the older nor the newer version "work" like you want it to (i.e. set fixed equalizer preset by default - which is not supported by the script to begin with).
Correct?
So the issue you reported today (on android) also didn't work with the previous version, right?
I've just uploaded a new version which:
- Fixes enable/disable the equalizer with inplace mode enabled.
- Allows setting initial equalizer (bands) values which apply on startup if at least one of them is not 0.
@aeseok hopefully this new version will allow you to use it on android. There's no need to enable the keys on startup if you don't intend to use the keys. Just change the initial gains on each band from 0 to anything else (at the bands =
section), and it should apply on startup without having to press any key.
I'm sorry for getting back to you so late. Bro are you a god or something? Because wow, you are amazing like honestly this works like a charm on Mpv-android and being able to set the gain values and have it working as soon as I open up a video file is just so satisfying. I feel bad for making you spend your time fixing up your already perfect script just for me. Thanks again so much.
You're welcome.
Note that if you only want to configure some equalizer value then you don't need the script at all. Just add these lines (and modify the gain values) to your mpv.conf
and that's it. No script required:
af-add=lavfi=[equalizer=f=64:width_type=o:w=3.3:g=0] # 20-200
af-add=lavfi=[equalizer=f=400:width_type=o:w=2.0:g=0] # 200-800
af-add=lavfi=[equalizer=f=1250:width_type=o:w=1.3:g=0] # 800-2k
af-add=lavfi=[equalizer=f=2830:width_type=o:w=1.0:g=0] # 2k-4k
af-add=lavfi=[equalizer=f=5600:width_type=o:w=1.0:g=0] # 4k-8k
af-add=lavfi=[equalizer=f=12500:width_type=o:w=1.3:g=0] # 8k-20k
Thank you for this script, easy to use and works perfectly. It rocks.
You're welcome.
Note that if you only want to configure some equalizer value then you don't need the script at all. Just add these lines (and modify the gain values) to your
mpv.conf
and that's it. No script required:af-add=lavfi=[equalizer=f=64:width_type=o:w=3.3:g=0] # 20-200 af-add=lavfi=[equalizer=f=400:width_type=o:w=2.0:g=0] # 200-800 af-add=lavfi=[equalizer=f=1250:width_type=o:w=1.3:g=0] # 800-2k af-add=lavfi=[equalizer=f=2830:width_type=o:w=1.0:g=0] # 2k-4k af-add=lavfi=[equalizer=f=5600:width_type=o:w=1.0:g=0] # 4k-8k af-add=lavfi=[equalizer=f=12500:width_type=o:w=1.3:g=0] # 8k-20k
OMG thanks so much. For the script and the tips.
af-add=lavfi=[equalizer=f=64:width_type=o:w=3.3:g=0] # 20-200
af-add=lavfi=[equalizer=f=400:width_type=o:w=2.0:g=0] # 200-800
Could you tell me which specified value to gain frequency between 50-100Hz/30Hz-500Hz/40-400Hz or 20Hz-530Hz?
ref: studybass
afaik
--af-add=lavfi=[equalizer=frequency=200:width_type=h:width=2.0:gain=0:precision=f64] # 0-400
Is it wrong?
Could you tell me which specified value to gain frequency between ...
No, because I don't know them by heart. Read the docs https://ffmpeg.org/ffmpeg-filters.html#equalizer or check the source code of this script to help calculate these values. You probably want the midwidth
function, which is commented out (and you're on your own here).
Nice script, but only works on the currently playing item, once the next one starts it has no effect, I have to toggle ctrl+E twice to get it working again.
2023-02-05: updated to persist between playlist items.
@escapezn thanks for the report. Should now be fixed.
It seems the equalizer stops working when seeking if inplace = true
, and starts working again after pressing Ctrl+E twice.
Is this intended or is there a problem with my setup (mpv 0.36.0 and ffmpeg 6.0)?
Hi, is there any way to set the gains by default?
I'm trying to edit it in {keys = {'2', 'w'}, filter = {'equalizer=f=64:width_type=o:w=3.3:g=', 0}}, -- 20-200
for example but it does nothing
I tried to add the gain after "g=" and I also tried changing the 0 at the end, but no luck so far, am I doing it wrong? or maybe I'm missing something?
The script works fine with the keyboard, it's just I use the player to watch anime and it's very inconvenient having to set it up every time
Thanks in advance
edit: I just saw that the info says there's a superequalizer, not sure if there's part of your script, but I can't find any other equalizer in my folders...
(https://i.imgur.com/6kQ1pFt.png)
@Erikcb91 The only thing which this script does is allow to configure the equalizer using the KB.
If you don't need that, and you just want a fixed equalizer preset, then you don't need the script. Just configure mpv with the preset you want, either with your mpv.conf file, or using command line options.
I also tried that, for some reason it's not working for me :S
Anyway, here where I live is late, so I'll try some more stuff tomorrow, thanks
Hi everyone, is it working now?
If it is not like some above comments, is there any way to make the audio bass boosted in mpv player?
Can you add some presets to it ? Because there's some nice presets you can find from EasyEffects: https://github.com/JackHack96/EasyEffects-Presets
Having presets for Classic Music, Rock, Commentary would improve experience of using mpv a lot.
Some presets for experimenting:
https://gist.github.com/kra3/9781800
https://github.com/schollz/Winamp-Original-Presets/tree/master/resources
There's some essential presets like Rock, Live, Classic.. that exists in almost all music players.
Can you add some presets to it ?
I could, but I don't intend to.
Do feel free to enhance it to include present, and you can post here a link to your version.
I also changed the inplace to false and that didn't seem to change anything.