|
|
@@ -123,8 +123,9 @@ typedef struct { |
|
|
|
// 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]; |
|
|
@@ -159,6 +160,16 @@ static const AVOption atempo_options[] = { |
|
|
|
|
|
|
|
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. |
|
|
|
*/ |
|
|
@@ -168,13 +179,15 @@ static void yae_clear(ATempoContext *atempo) |
|
|
|
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; |
|
|
@@ -308,6 +321,7 @@ static int yae_reset(ATempoContext *atempo, |
|
|
|
|
|
|
|
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); |
|
|
@@ -323,20 +337,13 @@ static int yae_set_tempo(AVFilterContext *ctx, const char *arg_tempo) |
|
|
|
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. |
|
|
@@ -689,12 +696,21 @@ static int yae_adjust_position(ATempoContext *atempo) |
|
|
|
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); |
|
|
|
|
|
|
@@ -704,9 +720,6 @@ static int yae_adjust_position(ATempoContext *atempo) |
|
|
|
|
|
|
|
// clear so that the fragment can be reloaded: |
|
|
|
frag->nsamples = 0; |
|
|
|
|
|
|
|
// update cumulative correction drift counter: |
|
|
|
atempo->drift += correction; |
|
|
|
} |
|
|
|
|
|
|
|
return correction; |
|
|
|