1
0
mirror of https://github.com/mpv-player/mpv synced 2025-04-21 22:57:00 +00:00
mpv/TOOLS/python/acompressor.py
8lurry fea5db26bb
python: optimize source, add feature
- lint
- better error message through check_error when mpv api(s) return with an error
- add function hook_add
- add function hook_continue
- add event handler for MPV_EVENT_HOOK
2025-04-09 13:43:16 +06:00

212 lines
5.9 KiB
Python

# This script adds control to the dynamic range compression ffmpeg
# filter including key bindings for adjusting parameters.
#
# See https://ffmpeg.org/ffmpeg-filters.html#acompressor for explanation
# of the parameters.
import re
import typing
from mpvclient import mpv # type: ignore
o = dict(
default_enable = False,
show_osd = True,
osd_timeout = 4000,
filter_label = mpv.name,
key_toggle = "n",
key_increase_threshold = "F1",
key_decrease_threshold = "Shift+F1",
key_increase_ratio = "F2",
key_decrease_ratio = "Shift+F2",
key_increase_knee = "F3",
key_decrease_knee = "Shift+F3",
key_increase_makeup = "F4",
key_decrease_makeup = "Shift+F4",
key_increase_attack = "F5",
key_decrease_attack = "Shift+F5",
key_increase_release = "F6",
key_decrease_release = "Shift+F6",
default_threshold = -25.0,
default_ratio = 3.0,
default_knee = 2.0,
default_makeup = 8.0,
default_attack = 20.0,
default_release = 250.0,
step_threshold = -2.5,
step_ratio = 1.0,
step_knee = 1.0,
step_makeup = 1.0,
step_attack = 10.0,
step_release = 10.0,
)
mpv.options.read_options(o)
params = [
dict(name = "attack", min=0.01, max=2000, hide_default=True, dB="" ),
dict(name = "release", min=0.01, max=9000, hide_default=True, dB="" ),
dict(name = "threshold", min= -30, max= 0, hide_default=False, dB="dB" ),
dict(name = "ratio", min= 1, max= 20, hide_default=False, dB="" ),
dict(name = "knee", min= 1, max= 10, hide_default=True, dB="dB" ),
dict(name = "makeup", min= 0, max= 24, hide_default=False, dB="dB" ),
]
def parse_value(value):
try:
return float(re.sub("dB$", "", value))
except ValueError:
return None
def format_value(value, decibel):
return f"{value}{decibel}"
def show_osd(filter): # noqa: A002
global o
if not o["show_osd"]:
return
if not filter["enabled"]:
mpv.commandv("show-text", "Dynamic range compressor: disabled", o["osd_timeout"])
return
pretty: typing.Union[str, list] = []
for param in params:
value = parse_value(filter["params"][param["name"]])
if not (param["hide_default"] and value == o["default_" + param["name"]]): # type: ignore
pretty.append(f"{param["name"].capitalize()}: {value}{param["dB"]}") # type: ignore
if not pretty:
pretty = ""
else:
pretty = "\n(" + ", ".join(pretty) + ")" # type: ignore
mpv.commandv("show-text", "Dynamic range compressor: enabled" + pretty, o["osd_timeout"])
def get_filter():
af = mpv.get_property_node("af")
for i in range(len(af)):
if af[i]["label"] == o["filter_label"]:
return af, i
af.append(dict(
name = "acompressor",
label = o["filter_label"],
enabled = False,
params = {},
))
for param in params:
af[len(af) - 1]["params"][param["name"]] = format_value(
o["default_" + param["name"]], param["dB"]) # type: ignore
return af, len(af)
def toggle_acompressor():
af, i = get_filter()
af[-1]["enabled"] = not af[-1]["enabled"]
mpv.set_property_node("af", af)
show_osd(af[-1])
def update_param(name, increment):
for param in params:
if param["name"] == name.lower():
af, i = get_filter()
value = parse_value(af[-1]["params"][param["name"]])
value = max(param["min"], min(value + increment, param["max"]))
af[-1]["params"][param["name"]] = format_value(value, param["dB"])
af[-1]["enabled"] = True
mpv.set_property_node("af", af)
show_osd(af[-1])
return
mpv.error("Unknown parameter '" + name + "'")
mpv.add_binding(o["key_toggle"], name="toggle-acompressor")(toggle_acompressor)
@mpv.add_binding(o["key_increase_threshold"],
name="acompressor-increase-threshold", repeatable=True)
def increase_threshold():
update_param("threshold", o["step_threshold"])
@mpv.add_binding(o["key_decrease_threshold"],
name="acompressor-decrease-threshold", repeatable=True)
def decrease_threshold():
update_param("threshold", -1 * o["step_threshold"])
@mpv.add_binding(o["key_increase_ratio"],
name="acompressor-increase-ratio", repeatable=True)
def increase_ratio():
update_param("ratio", o["step_ratio"])
@mpv.add_binding(o["key_decrease_ratio"],
name="acompressor-decrease-ratio", repeatable=True)
def decrease_ratio():
update_param("ratio", -1 * o["step_ratio"])
@mpv.add_binding(o["key_increase_knee"],
name="acompressor-increase-knee", repeatable=True)
def increase_knee():
update_param("knee", o["step_knee"])
@mpv.add_binding(o["key_decrease_knee"],
name="acompressor-decrease-knee", repeatable=True)
def decrease_knee():
update_param("knee", -1 * o["step_knee"])
@mpv.add_binding(o["key_increase_makeup"],
name="acompressor-increase-makeup", repeatable=True)
def increase_makeup():
update_param("makeup", o["step_makeup"])
@mpv.add_binding(o["key_decrease_makeup"],
name="acompressor-decrease-makeup", repeatable=True)
def decrease_makeup():
update_param("makeup", -1 * o["step_makeup"])
@mpv.add_binding(o["key_increase_attack"],
name="acompressor-increase-attack", repeatable=True)
def increase_attack():
update_param("attack", o["step_attack"])
@mpv.add_binding(o["key_decrease_attack"],
name="acompressor-decrease-attack", repeatable=True)
def decrease_attack():
update_param("attack", -1 * o["step_attack"])
@mpv.add_binding(o["key_increase_release"],
name="acompressor-increase-release", repeatable=True)
def increase_release():
update_param("release", o["step_release"])
@mpv.add_binding(o["key_decrease_release"],
name="acompressor-decrease-release", repeatable=True)
def decrease_release():
update_param("release", -1 * o["step_release"])
if o["default_enable"]:
af, i = get_filter()
af[-1]["enabled"] = True
mpv.set_property_node("af", af)