summaryrefslogtreecommitdiffstats
path: root/audio/filter/af_scaletempo2.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/filter/af_scaletempo2.c')
-rw-r--r--audio/filter/af_scaletempo2.c90
1 files changed, 50 insertions, 40 deletions
diff --git a/audio/filter/af_scaletempo2.c b/audio/filter/af_scaletempo2.c
index ceac919d5d..749e219454 100644
--- a/audio/filter/af_scaletempo2.c
+++ b/audio/filter/af_scaletempo2.c
@@ -8,21 +8,20 @@
#include "options/m_option.h"
struct priv {
- struct mp_scaletempo2 data;
+ struct mp_scaletempo2 *data;
struct mp_pin *in_pin;
struct mp_aframe *cur_format;
struct mp_aframe_pool *out_pool;
bool sent_final;
struct mp_aframe *pending;
bool initialized;
- double frame_delay;
float speed;
};
static bool init_scaletempo2(struct mp_filter *f);
-static void reset(struct mp_filter *f);
+static void af_scaletempo2_reset(struct mp_filter *f);
-static void process(struct mp_filter *f)
+static void af_scaletempo2_process(struct mp_filter *f)
{
struct priv *p = f->priv;
@@ -30,7 +29,7 @@ static void process(struct mp_filter *f)
return;
while (!p->initialized || !p->pending ||
- !mp_scaletempo2_frames_available(&p->data))
+ !mp_scaletempo2_frames_available(p->data, p->speed))
{
bool eof = false;
if (!p->pending || !mp_aframe_get_size(p->pending)) {
@@ -65,14 +64,16 @@ static void process(struct mp_filter *f)
if (p->pending && !format_change && !p->sent_final) {
int frame_size = mp_aframe_get_size(p->pending);
uint8_t **planes = mp_aframe_get_data_ro(p->pending);
- int read = mp_scaletempo2_fill_input_buffer(&p->data,
- planes, frame_size, final);
- p->frame_delay += read;
+ int read = mp_scaletempo2_fill_input_buffer(p->data,
+ planes, frame_size, p->speed);
mp_aframe_skip_samples(p->pending, read);
}
- p->sent_final |= final;
+ if (final && p->pending && !p->sent_final) {
+ mp_scaletempo2_set_final(p->data);
+ p->sent_final = true;
+ }
- if (mp_scaletempo2_frames_available(&p->data)) {
+ if (mp_scaletempo2_frames_available(p->data, p->speed)) {
if (eof) {
mp_pin_out_repeat_eof(p->in_pin); // drain more next time
}
@@ -82,18 +83,15 @@ static void process(struct mp_filter *f)
if (eof) {
mp_pin_in_write(f->ppins[1], MP_EOF_FRAME);
return;
- } else if (format_change) {
- // go on with proper reinit on the next iteration
- p->initialized = false;
- p->sent_final = false;
}
+ // for format change go on with proper reinit on the next iteration
}
}
assert(p->pending);
- if (mp_scaletempo2_frames_available(&p->data)) {
+ if (mp_scaletempo2_frames_available(p->data, p->speed)) {
struct mp_aframe *out = mp_aframe_new_ref(p->cur_format);
- int out_samples = p->data.ola_hop_size;
+ int out_samples = p->data->ola_hop_size;
if (mp_aframe_pool_allocate(p->out_pool, out, out_samples) < 0) {
talloc_free(out);
goto error;
@@ -103,17 +101,30 @@ static void process(struct mp_filter *f)
uint8_t **planes = mp_aframe_get_data_rw(out);
assert(planes);
- assert(mp_aframe_get_planes(out) == p->data.channels);
+ assert(mp_aframe_get_planes(out) == p->data->channels);
- out_samples = mp_scaletempo2_fill_buffer(&p->data,
+ out_samples = mp_scaletempo2_fill_buffer(p->data,
(float**)planes, out_samples, p->speed);
double pts = mp_aframe_get_pts(p->pending);
- p->frame_delay -= out_samples * p->speed;
-
if (pts != MP_NOPTS_VALUE) {
- double delay = p->frame_delay / mp_aframe_get_effective_rate(out);
- mp_aframe_set_pts(out, pts - delay);
+ double frame_delay = mp_scaletempo2_get_latency(p->data, p->speed)
+ + out_samples * p->speed;
+ mp_aframe_set_pts(out, pts - frame_delay / mp_aframe_get_effective_rate(out));
+
+ if (p->sent_final) {
+ double remain_pts = pts - mp_aframe_get_pts(out);
+ double rate = mp_aframe_get_effective_rate(out) / p->speed;
+ int max_samples = MPMAX(0, (int) (remain_pts * rate));
+ // truncate final packet to expected length
+ if (out_samples >= max_samples) {
+ out_samples = max_samples;
+
+ // reset the filter to ensure it stops generating audio
+ // and mp_scaletempo2_frames_available returns false
+ mp_scaletempo2_reset(p->data);
+ }
+ }
}
mp_aframe_set_size(out, out_samples);
@@ -137,16 +148,15 @@ static bool init_scaletempo2(struct mp_filter *f)
mp_aframe_reset(p->cur_format);
p->initialized = true;
p->sent_final = false;
- p->frame_delay = 0;
mp_aframe_config_copy(p->cur_format, p->pending);
- mp_scaletempo2_init(&p->data, mp_aframe_get_channels(p->pending),
+ mp_scaletempo2_init(p->data, mp_aframe_get_channels(p->pending),
mp_aframe_get_rate(p->pending));
return true;
}
-static bool command(struct mp_filter *f, struct mp_filter_command *cmd)
+static bool af_scaletempo2_command(struct mp_filter *f, struct mp_filter_command *cmd)
{
struct priv *p = f->priv;
@@ -159,29 +169,28 @@ static bool command(struct mp_filter *f, struct mp_filter_command *cmd)
return false;
}
-static void reset(struct mp_filter *f)
+static void af_scaletempo2_reset(struct mp_filter *f)
{
struct priv *p = f->priv;
- mp_scaletempo2_reset(&p->data);
- p->frame_delay = 0;
+ mp_scaletempo2_reset(p->data);
p->initialized = false;
TA_FREEP(&p->pending);
}
-static void destroy(struct mp_filter *f)
+static void af_scaletempo2_destroy(struct mp_filter *f)
{
struct priv *p = f->priv;
- mp_scaletempo2_destroy(&p->data);
- talloc_free(p->pending);
+ TA_FREEP(&p->data);
+ TA_FREEP(&p->pending);
}
static const struct mp_filter_info af_scaletempo2_filter = {
.name = "scaletempo2",
.priv_size = sizeof(struct priv),
- .process = process,
- .command = command,
- .reset = reset,
- .destroy = destroy,
+ .process = af_scaletempo2_process,
+ .command = af_scaletempo2_command,
+ .reset = af_scaletempo2_reset,
+ .destroy = af_scaletempo2_destroy,
};
static struct mp_filter *af_scaletempo2_create(
@@ -197,7 +206,8 @@ static struct mp_filter *af_scaletempo2_create(
mp_filter_add_pin(f, MP_PIN_OUT, "out");
struct priv *p = f->priv;
- p->data.opts = talloc_steal(p, options);
+ p->data = talloc_zero(p, struct mp_scaletempo2);
+ p->data->opts = talloc_steal(p, options);
p->speed = 1.0;
p->cur_format = talloc_steal(p, mp_aframe_create());
p->out_pool = mp_aframe_pool_create(p);
@@ -225,12 +235,12 @@ const struct mp_user_filter_entry af_scaletempo2 = {
.priv_size = sizeof(OPT_BASE_STRUCT),
.priv_defaults = &(const OPT_BASE_STRUCT) {
.min_playback_rate = 0.25,
- .max_playback_rate = 4.0,
- .ola_window_size_ms = 20,
- .wsola_search_interval_ms = 30,
+ .max_playback_rate = 8.0,
+ .ola_window_size_ms = 12,
+ .wsola_search_interval_ms = 40,
},
.options = (const struct m_option[]) {
- {"search-interval",
+ {"search-interval",
OPT_FLOAT(wsola_search_interval_ms), M_RANGE(1, 1000)},
{"window-size",
OPT_FLOAT(ola_window_size_ms), M_RANGE(1, 1000)},