From 57eca14a4537429df498b3b76578ee87debf166c Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Tue, 20 Sep 2016 00:56:10 +0900 Subject: [PATCH] af_rubberband: add af-command and option to change the pitch This allows both fixed and dynamic control over the audio pitch using librubberband, which was previously not exposed to the user. --- DOCS/man/af.rst | 15 +++++++++++++-- audio/filter/af_rubberband.c | 25 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/DOCS/man/af.rst b/DOCS/man/af.rst index 71b5bbf975..31d365722f 100644 --- a/DOCS/man/af.rst +++ b/DOCS/man/af.rst @@ -413,9 +413,13 @@ Available filters are: ``rubberband`` High quality pitch correction with librubberband. This can be used in place of ``scaletempo``, and will be used to adjust audio pitch when playing - at speed different from normal. + at speed different from normal. It can also be used to adjust audio pitch + without changing playback speed. - This filter has a number of sub-options. You can list them with + ```` + Sets the pitch scaling factor. Frequencies are multiplied by this value. + + This filter has a number of additional sub-options. You can list them with ``mpv --af=rubberband=help``. This will also show the default values for each option. The options are not documented here, because they are merely passed to librubberband. Look at the librubberband documentation @@ -424,6 +428,13 @@ Available filters are: (The mapping of the mpv rubberband filter sub-option names and values to those of librubberband follows a simple pattern: ``"Option" + Name + Value``.) + This filter supports the following ``af-command`` commands: + + ``set-pitch`` + Set the ```` argument dynamically. This can be used to + change the playback pitch at runtime. Note that speed is controlled + using the standard ``speed`` property, not ``af-command``. + ``lavfi=graph`` Filter audio using FFmpeg's libavfilter. diff --git a/audio/filter/af_rubberband.c b/audio/filter/af_rubberband.c index 48bb510679..529c252a12 100644 --- a/audio/filter/af_rubberband.c +++ b/audio/filter/af_rubberband.c @@ -26,6 +26,7 @@ struct priv { RubberBandState rubber; double speed; + double pitch; struct mp_audio *pending; bool needs_reset; // Estimate how much librubberband has buffered internally. @@ -44,6 +45,14 @@ static void update_speed(struct af_instance *af, double new_speed) rubberband_set_time_ratio(p->rubber, 1.0 / p->speed); } +static void update_pitch(struct af_instance *af, double new_pitch) +{ + struct priv *p = af->priv; + + p->pitch = new_pitch; + rubberband_set_pitch_scale(p->rubber, p->pitch); +} + static int control(struct af_instance *af, int cmd, void *arg) { struct priv *p = af->priv; @@ -72,6 +81,7 @@ static int control(struct af_instance *af, int cmd, void *arg) } update_speed(af, p->speed); + update_pitch(af, p->pitch); control(af, AF_CONTROL_RESET, NULL); return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE; @@ -87,6 +97,19 @@ static int control(struct af_instance *af, int cmd, void *arg) p->pending = NULL; p->rubber_delay = 0; return AF_OK; + case AF_CONTROL_COMMAND: { + char **args = arg; + if (!strcmp(args[0], "set-pitch")) { + char *endptr; + double pitch = strtod(args[1], &endptr); + if (*endptr || pitch < 0.01 || pitch > 100.0) + return CONTROL_ERROR; + update_pitch(af, pitch); + return CONTROL_OK; + } else { + return CONTROL_ERROR; + } + } } return AF_UNKNOWN; } @@ -187,6 +210,7 @@ const struct af_info af_info_rubberband = { .priv_size = sizeof(struct priv), .priv_defaults = &(const struct priv) { .speed = 1.0, + .pitch = 1.0, .opt_pitch = RubberBandOptionPitchHighConsistency, .opt_transients = RubberBandOptionTransientsMixed, .opt_formant = RubberBandOptionFormantPreserved, @@ -220,6 +244,7 @@ const struct af_info af_info_rubberband = { OPT_CHOICE("channels", opt_channels, 0, ({"apart", RubberBandOptionChannelsApart}, {"together", RubberBandOptionChannelsTogether})), + OPT_DOUBLE("pitch-scale", pitch, M_OPT_RANGE, .min = 0.01, .max = 100), {0} }, };