Showing the changes to TOOLS/lua/acompressor.lua (1 of 1 file). Show all
Unified · Split
| @@ -0,0 +1,126 @@ | ||
| 1 | +-- This script adds control to the dynamic range compression ffmpeg | |
| 2 | +-- filter including key bindings for adjusting parameters. | |
| 3 | +-- | |
| 4 | +-- See https://ffmpeg.org/ffmpeg-filters.html#acompressor for explanation | |
| 5 | +-- of the parameteres. | |
| 6 | +-- | |
| 7 | +-- Default key bindings: | |
| 8 | +-- n: Toggle dynamic range compression on or off | |
| 9 | +-- F1/Shift+F1: Increase/Decrease threshold parameter | |
| 10 | +-- F2/Shift+F2: Increase/Decrease ratio parameter | |
| 11 | +-- F3/Shift+F3: Increase/Decrease knee parameter | |
| 12 | +-- F4/Shift+F4: Increase/Decrease makeup gain parameter | |
| 13 | +-- F5/Shift+F5: Increase/Decrease attack parameter | |
| 14 | +-- F6/Shift+F6: Increase/Decrease release parameter | |
| 15 | +-- | |
| 16 | +-- To change key bindings in input.conf use: | |
| 17 | +-- BINDING script-message-to acompressor toggle-acompressor | |
| 18 | +-- BINDING script-message-to acompressor update-param PARAM INCREMENT | |
| 19 | +-- BINDING is the key binding to use, PARAM is either 'attack', 'release', | |
| 20 | +-- 'threshold', 'ratio', 'knee' or 'makeup' and INCREMENT is a signed floating | |
| 21 | +-- point value to add to the current parameter value. | |
| 22 | +-- | |
| 23 | +-- You may also just adjust default parameters to your liking in this table. | |
| 24 | +local params = { | |
| 25 | + -- 'hide' defines wether the parameter should be hidden from OSD display (it will still be included in ffmpeg filter graph). | |
| 26 | + -- 'input_format' is used to parse the value back from a obtained filter graph. | |
| 27 | + -- 'output_format' defines how the value shall be formatted for creating the filter graph. | |
| 28 | + { name = 'Attack', value= 20, min=0.01, max=2000, hide= 20, input_format='attack=(%d+[.%d+]*)', output_format='%g' }, | |
| 29 | + { name = 'Release', value=250, min=0.01, max=9000, hide=250, input_format='release=(%d+[.%d+]*)', output_format='%g' }, | |
| 30 | + { name = 'Threshold', value=-25, min= -30, max= 0, hide=nil, input_format='threshold=(-%d+[.%d+]*)dB', output_format='%gdB' }, | |
| 31 | + { name = 'Ratio', value= 3, min= 1, max= 20, hide=nil, input_format='ratio=(%d+[.%d+]*)', output_format='%g' }, | |
| 32 | + { name = 'Knee', value= 2, min= 1, max= 10, hide= 2, input_format='knee=(%d+[.%d+]*)dB', output_format='%gdB' }, | |
| 33 | + { name = 'Makeup', value= 8, min= 0, max= 24, hide=nil, input_format='makeup=(%d+[.%d+]*)dB', output_format='%gdB' } | |
| 34 | +} | |
| 35 | + | |
| 36 | +-- Defines the mpv filter label to be used. This allows us to easily add/replace/remove it, so | |
| 37 | +-- it should be left so something meaningful and unique. | |
| 38 | +local filter_label = 'acompressor' | |
| 39 | + | |
| 40 | +local function update_filter() | |
| 41 | + local graph = {} | |
| 42 | + local pretty = {} | |
| 43 | + | |
| 44 | + for _,param in pairs(params) do | |
| 45 | + graph[#graph+1] = string.format('%s=' .. param.output_format, string.lower(param.name), param.value) | |
| 46 | + if param.hide ~= param.value then | |
| 47 | + pretty[#pretty+1] = string.format('%s: ' .. param.output_format, param.name, param.value) | |
| 48 | + end | |
| 49 | + end | |
| 50 | + | |
| 51 | + if #pretty == 0 then | |
| 52 | + pretty = '' | |
| 53 | + else | |
| 54 | + pretty = '\n(' .. table.concat(pretty, ', ') .. ')' | |
| 55 | + end | |
| 56 | + | |
| 57 | + mp.command(string.format('no-osd af add @%s:lavfi=[acompressor=%s]; show-text "Dynamic range compressor: enabled%s" 4000', filter_label, table.concat(graph, ':'), pretty)) | |
| 58 | +end | |
| 59 | + | |
| 60 | +local function read_filter() | |
| 61 | + local graph = nil | |
| 62 | + local af = mp.get_property_native('af', {}) | |
| 63 | + | |
| 64 | + for i = 1, #af do | |
| 65 | + if af[i]['name'] == 'lavfi' and af[i]['label'] == 'acompressor' then | |
| 66 | + graph = af[i]['params']['graph'] | |
| 67 | + break | |
| 68 | + end | |
| 69 | + end | |
| 70 | + | |
| 71 | + if graph == nil then | |
| 72 | + return false | |
| 73 | + end | |
| 74 | + | |
| 75 | + for _,param in pairs(params) do | |
| 76 | + local value = tonumber(string.match(graph, param.input_format)) | |
| 77 | + if value ~= nil and value >= param.min and value <= param.max then | |
| 78 | + param.value = value | |
| 79 | + end | |
| 80 | + end | |
| 81 | + return true | |
| 82 | +end | |
| 83 | + | |
| 84 | +local function toggle_acompressor() | |
| 85 | + if read_filter() then | |
| 86 | + mp.command(string.format('no-osd af del @%s; show-text "Dynamic range compressor: disabled"', filter_label)) | |
| 87 | + else | |
| 88 | + update_filter() | |
| 89 | + end | |
| 90 | +end | |
| 91 | + | |
| 92 | +local function update_param(name, increment) | |
| 93 | + -- The current filter values could come from a watch_later config. | |
| 94 | + -- read_filter() will parse them, so that we don't clobber those with our default values. | |
| 95 | + read_filter() | |
| 96 | + for _,param in pairs(params) do | |
| 97 | + if string.lower(param.name) == string.lower(name) then | |
| 98 | + param.value = math.max(param.min, math.min(param.value + increment, param.max)) | |
| 99 | + update_filter() | |
| 100 | + return | |
| 101 | + end | |
| 102 | + end | |
| 103 | + | |
| 104 | + mp.msg.error('Unknown parameter "' .. name .. '"') | |
| 105 | +end | |
| 106 | + | |
| 107 | +mp.add_key_binding("n", "toggle-acompressor", toggle_acompressor) | |
| 108 | +mp.register_script_message('update-param', update_param) | |
| 109 | + | |
| 110 | +mp.add_key_binding("F1", 'acompressor-inc-threshold', function() update_param('threshold', -5); end, { repeatable = true }) | |
| 111 | +mp.add_key_binding("Shift+F1", 'acompressor-dec-threshold', function() update_param('Threshold', 5); end, { repeatable = true }) | |
| 112 | + | |
| 113 | +mp.add_key_binding("F2", 'acompressor-inc-ratio', function() update_param('Ratio', 1); end, { repeatable = true }) | |
| 114 | +mp.add_key_binding("Shift+F2", 'acompressor-dec-ratio', function() update_param('Ratio', -1); end, { repeatable = true }) | |
| 115 | + | |
| 116 | +mp.add_key_binding("F3", 'acompressor-inc-knee', function() update_param('Knee', 1); end, { repeatable = true }) | |
| 117 | +mp.add_key_binding("Shift+F3", 'acompressor-dec-knee', function() update_param('Knee', -1); end, { repeatable = true }) | |
| 118 | + | |
| 119 | +mp.add_key_binding("F4", 'acompressor-inc-makeup', function() update_param('Makeup', 1); end, { repeatable = true }) | |
| 120 | +mp.add_key_binding("Shift+F4", 'acompressor-dec-makeup', function() update_param('Makeup', -1); end, { repeatable = true }) | |
| 121 | + | |
| 122 | +mp.add_key_binding("F5", 'acompressor-inc-attack', function() update_param('Attack', 10); end, { repeatable = true }) | |
| 123 | +mp.add_key_binding("Shift+F5", 'acompressor-dec-attack', function() update_param('Attack', -10); end, { repeatable = true }) | |
| 124 | + | |
| 125 | +mp.add_key_binding("F6", 'acompressor-inc-release', function() update_param('Release', 10); end, { repeatable = true }) | |
| 126 | +mp.add_key_binding("Shift+F6", 'acompressor-dec-release', function() update_param('Release', -10); end, { repeatable = true }) | |