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.
This commit is contained in:
Hector Martin
2016-09-20 00:56:10 +09:00
committed by wm4
parent ed8540c38e
commit 57eca14a45
2 changed files with 38 additions and 2 deletions

View File

@@ -413,9 +413,13 @@ Available filters are:
``rubberband`` ``rubberband``
High quality pitch correction with librubberband. This can be used in place High quality pitch correction with librubberband. This can be used in place
of ``scaletempo``, and will be used to adjust audio pitch when playing 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 ``<pitch-scale>``
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 ``mpv --af=rubberband=help``. This will also show the default values
for each option. The options are not documented here, because they are for each option. The options are not documented here, because they are
merely passed to librubberband. Look at the librubberband documentation 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 (The mapping of the mpv rubberband filter sub-option names and values to
those of librubberband follows a simple pattern: ``"Option" + Name + Value``.) those of librubberband follows a simple pattern: ``"Option" + Name + Value``.)
This filter supports the following ``af-command`` commands:
``set-pitch``
Set the ``<pitch-scale>`` 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`` ``lavfi=graph``
Filter audio using FFmpeg's libavfilter. Filter audio using FFmpeg's libavfilter.

View File

@@ -26,6 +26,7 @@
struct priv { struct priv {
RubberBandState rubber; RubberBandState rubber;
double speed; double speed;
double pitch;
struct mp_audio *pending; struct mp_audio *pending;
bool needs_reset; bool needs_reset;
// Estimate how much librubberband has buffered internally. // 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); 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) static int control(struct af_instance *af, int cmd, void *arg)
{ {
struct priv *p = af->priv; 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_speed(af, p->speed);
update_pitch(af, p->pitch);
control(af, AF_CONTROL_RESET, NULL); control(af, AF_CONTROL_RESET, NULL);
return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE; 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->pending = NULL;
p->rubber_delay = 0; p->rubber_delay = 0;
return AF_OK; 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; return AF_UNKNOWN;
} }
@@ -187,6 +210,7 @@ const struct af_info af_info_rubberband = {
.priv_size = sizeof(struct priv), .priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) { .priv_defaults = &(const struct priv) {
.speed = 1.0, .speed = 1.0,
.pitch = 1.0,
.opt_pitch = RubberBandOptionPitchHighConsistency, .opt_pitch = RubberBandOptionPitchHighConsistency,
.opt_transients = RubberBandOptionTransientsMixed, .opt_transients = RubberBandOptionTransientsMixed,
.opt_formant = RubberBandOptionFormantPreserved, .opt_formant = RubberBandOptionFormantPreserved,
@@ -220,6 +244,7 @@ const struct af_info af_info_rubberband = {
OPT_CHOICE("channels", opt_channels, 0, OPT_CHOICE("channels", opt_channels, 0,
({"apart", RubberBandOptionChannelsApart}, ({"apart", RubberBandOptionChannelsApart},
{"together", RubberBandOptionChannelsTogether})), {"together", RubberBandOptionChannelsTogether})),
OPT_DOUBLE("pitch-scale", pitch, M_OPT_RANGE, .min = 0.01, .max = 100),
{0} {0}
}, },
}; };