// tempo scaling factor:
double tempo;
- // cumulative alignment drift:
- int drift;
+ // a snapshot of previous fragment input and output position values
+ // captured when the tempo scale factor was set most recently:
+ int64_t origin[2];
// current/previous fragment ring-buffer:
AudioFragment frag[2];
AVFILTER_DEFINE_CLASS(atempo);
+inline static AudioFragment *yae_curr_frag(ATempoContext *atempo)
+{
+ return &atempo->frag[atempo->nfrag % 2];
+}
+
+inline static AudioFragment *yae_prev_frag(ATempoContext *atempo)
+{
+ return &atempo->frag[(atempo->nfrag + 1) % 2];
+}
+
/**
* Reset filter to initial state, do not deallocate existing local buffers.
*/
atempo->head = 0;
atempo->tail = 0;
- atempo->drift = 0;
atempo->nfrag = 0;
atempo->state = YAE_LOAD_FRAGMENT;
atempo->position[0] = 0;
atempo->position[1] = 0;
+ atempo->origin[0] = 0;
+ atempo->origin[1] = 0;
+
atempo->frag[0].position[0] = 0;
atempo->frag[0].position[1] = 0;
atempo->frag[0].nsamples = 0;
static int yae_set_tempo(AVFilterContext *ctx, const char *arg_tempo)
{
+ const AudioFragment *prev;
ATempoContext *atempo = ctx->priv;
char *tail = NULL;
double tempo = av_strtod(arg_tempo, &tail);
return AVERROR(EINVAL);
}
+ prev = yae_prev_frag(atempo);
+ atempo->origin[0] = prev->position[0] + atempo->window / 2;
+ atempo->origin[1] = prev->position[1] + atempo->window / 2;
atempo->tempo = tempo;
return 0;
}
-inline static AudioFragment *yae_curr_frag(ATempoContext *atempo)
-{
- return &atempo->frag[atempo->nfrag % 2];
-}
-
-inline static AudioFragment *yae_prev_frag(ATempoContext *atempo)
-{
- return &atempo->frag[(atempo->nfrag + 1) % 2];
-}
-
/**
* A helper macro for initializing complex data buffer with scalar data
* of a given type.
const AudioFragment *prev = yae_prev_frag(atempo);
AudioFragment *frag = yae_curr_frag(atempo);
+ const double prev_output_position =
+ (double)(prev->position[1] - atempo->origin[1] + atempo->window / 2);
+
+ const double ideal_output_position =
+ (double)(prev->position[0] - atempo->origin[0] + atempo->window / 2) /
+ atempo->tempo;
+
+ const int drift = (int)(prev_output_position - ideal_output_position);
+
const int delta_max = atempo->window / 2;
const int correction = yae_align(frag,
prev,
atempo->window,
delta_max,
- atempo->drift,
+ drift,
atempo->correlation,
atempo->complex_to_real);
// clear so that the fragment can be reloaded:
frag->nsamples = 0;
-
- // update cumulative correction drift counter:
- atempo->drift += correction;
}
return correction;
yae_apply(atempo, &src, src_end, &atempo->dst, atempo->dst_end);
if (atempo->dst == atempo->dst_end) {
- ret = push_samples(atempo, outlink, n_out);
+ int n_samples = ((atempo->dst - atempo->dst_buffer->data[0]) /
+ atempo->stride);
+ ret = push_samples(atempo, outlink, n_samples);
if (ret < 0)
goto end;
}