|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef ftype |
|
#undef FABS |
|
#undef FMAX |
|
#undef SAMPLE_FORMAT |
|
#undef SQRT |
|
#undef ZERO |
|
#undef ONE |
|
#undef TMIN |
|
#if DEPTH == 32 |
|
#define SAMPLE_FORMAT flt |
|
#define SQRT sqrtf |
|
#define FMAX fmaxf |
|
#define FABS fabsf |
|
#define ftype float |
|
#define ZERO 0.f |
|
#define ONE 1.f |
|
#define TMIN -FLT_MAX |
|
#else |
|
#define SAMPLE_FORMAT dbl |
|
#define SQRT sqrt |
|
#define FMAX fmax |
|
#define FABS fabs |
|
#define ftype double |
|
#define ZERO 0.0 |
|
#define ONE 1.0 |
|
#define TMIN -DBL_MAX |
|
#endif |
|
|
|
#define fn3(a,b) a##_##b |
|
#define fn2(a,b) fn3(a,b) |
|
#define fn(a) fn2(a, SAMPLE_FORMAT) |
|
|
|
static void fn(flush)(ftype *dst, const ftype *src, int src_pos, |
|
int nb_channels, int count, int src_nb_samples, |
|
int *out_nb_samples) |
|
{ |
|
int oidx, out_count = count; |
|
int sidx = src_pos; |
|
|
|
if (count <= 0) |
|
return; |
|
|
|
oidx = *out_nb_samples + out_count - 1; |
|
*out_nb_samples += out_count; |
|
while (out_count-- > 0) { |
|
const int spos = sidx * nb_channels; |
|
const int opos = oidx * nb_channels; |
|
|
|
for (int ch = 0; ch < nb_channels; ch++) |
|
dst[opos + ch] = src[spos + ch]; |
|
|
|
oidx--; |
|
sidx--; |
|
if (sidx < 0) |
|
sidx = src_nb_samples - 1; |
|
} |
|
} |
|
|
|
static void fn(queue_sample)(AVFilterContext *ctx, |
|
const ftype *src, |
|
ftype *queue, |
|
int *queue_pos, |
|
int *queue_size, |
|
int *window_pos, |
|
int *window_size, |
|
const int nb_channels, |
|
const int nb_samples, |
|
const int window_nb_samples) |
|
{ |
|
const int pos = *queue_pos * nb_channels; |
|
|
|
for (int ch = 0; ch < nb_channels; ch++) |
|
queue[pos + ch] = src[ch]; |
|
|
|
(*queue_pos)++; |
|
if (*queue_pos >= nb_samples) |
|
*queue_pos = 0; |
|
|
|
if (*queue_size < nb_samples) |
|
(*queue_size)++; |
|
|
|
if (*window_size < window_nb_samples) |
|
(*window_size)++; |
|
|
|
(*window_pos)++; |
|
if (*window_pos >= window_nb_samples) |
|
*window_pos = 0; |
|
} |
|
|
|
static ftype fn(compute_avg)(ftype *cache, ftype x, ftype px, |
|
int window_size, int *unused, int *unused2) |
|
{ |
|
ftype r; |
|
|
|
cache[0] += FABS(x); |
|
cache[0] -= FABS(px); |
|
cache[0] = r = FMAX(cache[0], ZERO); |
|
|
|
return r / window_size; |
|
} |
|
|
|
#define PEAKS(empty_value,op,sample, psample)\ |
|
if (!empty && psample == ss[front]) { \ |
|
ss[front] = empty_value; \ |
|
if (back != front) { \ |
|
front--; \ |
|
if (front < 0) \ |
|
front = n - 1; \ |
|
} \ |
|
empty = front == back; \ |
|
} \ |
|
\ |
|
if (!empty && sample op ss[front]) { \ |
|
while (1) { \ |
|
ss[front] = empty_value; \ |
|
if (back == front) { \ |
|
empty = 1; \ |
|
break; \ |
|
} \ |
|
front--; \ |
|
if (front < 0) \ |
|
front = n - 1; \ |
|
} \ |
|
} \ |
|
\ |
|
while (!empty && sample op ss[back]) { \ |
|
ss[back] = empty_value; \ |
|
if (back == front) { \ |
|
empty = 1; \ |
|
break; \ |
|
} \ |
|
back++; \ |
|
if (back >= n) \ |
|
back = 0; \ |
|
} \ |
|
\ |
|
if (!empty) { \ |
|
back--; \ |
|
if (back < 0) \ |
|
back = n - 1; \ |
|
} |
|
|
|
static ftype fn(compute_median)(ftype *ss, ftype x, ftype px, |
|
int n, int *ffront, int *bback) |
|
{ |
|
ftype r, ax = FABS(x); |
|
int front = *ffront; |
|
int back = *bback; |
|
int empty = front == back && ss[front] == -ONE; |
|
int idx; |
|
|
|
PEAKS(-ONE, >, ax, FABS(px)) |
|
|
|
ss[back] = ax; |
|
idx = (back <= front) ? back + (front - back + 1) / 2 : back + (n + front - back + 1) / 2; |
|
if (idx >= n) |
|
idx -= n; |
|
av_assert2(idx >= 0 && idx < n); |
|
r = ss[idx]; |
|
|
|
*ffront = front; |
|
*bback = back; |
|
|
|
return r; |
|
} |
|
|
|
static ftype fn(compute_peak)(ftype *ss, ftype x, ftype px, |
|
int n, int *ffront, int *bback) |
|
{ |
|
ftype r, ax = FABS(x); |
|
int front = *ffront; |
|
int back = *bback; |
|
int empty = front == back && ss[front] == ZERO; |
|
|
|
PEAKS(ZERO, >=, ax, FABS(px)) |
|
|
|
ss[back] = ax; |
|
r = ss[front]; |
|
|
|
*ffront = front; |
|
*bback = back; |
|
|
|
return r; |
|
} |
|
|
|
static ftype fn(compute_ptp)(ftype *ss, ftype x, ftype px, |
|
int n, int *ffront, int *bback) |
|
{ |
|
int front = *ffront; |
|
int back = *bback; |
|
int empty = front == back && ss[front] == TMIN; |
|
ftype r, max, min; |
|
|
|
PEAKS(TMIN, >=, x, px) |
|
|
|
ss[back] = x; |
|
max = ss[front]; |
|
min = x; |
|
r = FABS(min) + FABS(max - min); |
|
|
|
*ffront = front; |
|
*bback = back; |
|
|
|
return r; |
|
} |
|
|
|
static ftype fn(compute_rms)(ftype *cache, ftype x, ftype px, |
|
int window_size, int *unused, int *unused2) |
|
{ |
|
ftype r; |
|
|
|
cache[0] += x * x; |
|
cache[0] -= px * px; |
|
cache[0] = r = FMAX(cache[0], ZERO); |
|
|
|
return SQRT(r / window_size); |
|
} |
|
|
|
static ftype fn(compute_dev)(ftype *ss, ftype x, ftype px, |
|
int n, int *unused, int *unused2) |
|
{ |
|
ftype r; |
|
|
|
ss[0] += x; |
|
ss[0] -= px; |
|
|
|
ss[1] += x * x; |
|
ss[1] -= px * px; |
|
ss[1] = FMAX(ss[1], ZERO); |
|
|
|
r = FMAX(ss[1] - ss[0] * ss[0] / n, ZERO) / n; |
|
|
|
return SQRT(r); |
|
} |
|
|
|
static void fn(filter_start)(AVFilterContext *ctx, |
|
const ftype *src, ftype *dst, |
|
int *nb_out_samples, |
|
const int nb_channels) |
|
{ |
|
SilenceRemoveContext *s = ctx->priv; |
|
const int start_periods = s->start_periods; |
|
int out_nb_samples = *nb_out_samples; |
|
const int start_window_nb_samples = s->start_window->nb_samples; |
|
const int start_nb_samples = s->start_queuef->nb_samples; |
|
const int start_wpos = s->start_window_pos * nb_channels; |
|
const int start_pos = s->start_queue_pos * nb_channels; |
|
ftype *startw = (ftype *)s->start_window->data[0]; |
|
ftype *start = (ftype *)s->start_queuef->data[0]; |
|
const ftype start_threshold = s->start_threshold; |
|
const int start_mode = s->start_mode; |
|
int start_thres = (start_mode == T_ANY) ? 0 : 1; |
|
const int start_duration = s->start_duration; |
|
ftype *start_cache = (ftype *)s->start_cache; |
|
const int start_silence = s->start_silence; |
|
int window_size = start_window_nb_samples; |
|
const int cache_size = s->cache_size; |
|
int *front = s->start_front; |
|
int *back = s->start_back; |
|
|
|
fn(queue_sample)(ctx, src, start, |
|
&s->start_queue_pos, |
|
&s->start_queue_size, |
|
&s->start_window_pos, |
|
&s->start_window_size, |
|
nb_channels, |
|
start_nb_samples, |
|
start_window_nb_samples); |
|
|
|
if (s->start_found_periods < 0) |
|
goto skip; |
|
|
|
if (s->detection != D_PEAK && s->detection != D_MEDIAN && |
|
s->detection != D_PTP) |
|
window_size = s->start_window_size; |
|
|
|
for (int ch = 0; ch < nb_channels; ch++) { |
|
ftype start_sample = start[start_pos + ch]; |
|
ftype start_ow = startw[start_wpos + ch]; |
|
ftype tstart; |
|
|
|
tstart = fn(s->compute)(start_cache + ch * cache_size, |
|
start_sample, |
|
start_ow, |
|
window_size, |
|
front + ch, |
|
back + ch); |
|
|
|
startw[start_wpos + ch] = start_sample; |
|
|
|
if (start_mode == T_ANY) { |
|
start_thres |= tstart > start_threshold; |
|
} else { |
|
start_thres &= tstart > start_threshold; |
|
} |
|
} |
|
|
|
if (s->start_found_periods >= 0) { |
|
if (start_silence > 0) { |
|
s->start_silence_count++; |
|
if (s->start_silence_count > start_silence) |
|
s->start_silence_count = start_silence; |
|
} |
|
|
|
s->start_sample_count += start_thres; |
|
} |
|
|
|
if (s->start_sample_count > start_duration) { |
|
s->start_found_periods++; |
|
if (s->start_found_periods >= start_periods) { |
|
if (!ctx->is_disabled) |
|
fn(flush)(dst, start, s->start_queue_pos, nb_channels, |
|
s->start_silence_count, start_nb_samples, |
|
&out_nb_samples); |
|
s->start_silence_count = 0; |
|
s->start_found_periods = -1; |
|
} |
|
|
|
s->start_sample_count = 0; |
|
} |
|
|
|
skip: |
|
if (s->start_found_periods < 0 || ctx->is_disabled) { |
|
const int dst_pos = out_nb_samples * nb_channels; |
|
for (int ch = 0; ch < nb_channels; ch++) |
|
dst[dst_pos + ch] = start[start_pos + ch]; |
|
out_nb_samples++; |
|
} |
|
|
|
*nb_out_samples = out_nb_samples; |
|
} |
|
|
|
static void fn(filter_stop)(AVFilterContext *ctx, |
|
const ftype *src, ftype *dst, |
|
int *nb_out_samples, |
|
const int nb_channels) |
|
{ |
|
SilenceRemoveContext *s = ctx->priv; |
|
const int stop_periods = s->stop_periods; |
|
int out_nb_samples = *nb_out_samples; |
|
const int stop_window_nb_samples = s->stop_window->nb_samples; |
|
const int stop_nb_samples = s->stop_queuef->nb_samples; |
|
const int stop_wpos = s->stop_window_pos * nb_channels; |
|
const int stop_pos = s->stop_queue_pos * nb_channels; |
|
ftype *stopw = (ftype *)s->stop_window->data[0]; |
|
const ftype stop_threshold = s->stop_threshold; |
|
ftype *stop = (ftype *)s->stop_queuef->data[0]; |
|
const int stop_mode = s->stop_mode; |
|
int stop_thres = (stop_mode == T_ANY) ? 0 : 1; |
|
const int stop_duration = s->stop_duration; |
|
ftype *stop_cache = (ftype *)s->stop_cache; |
|
const int stop_silence = s->stop_silence; |
|
int window_size = stop_window_nb_samples; |
|
const int cache_size = s->cache_size; |
|
const int restart = s->restart; |
|
int *front = s->stop_front; |
|
int *back = s->stop_back; |
|
|
|
fn(queue_sample)(ctx, src, stop, |
|
&s->stop_queue_pos, |
|
&s->stop_queue_size, |
|
&s->stop_window_pos, |
|
&s->stop_window_size, |
|
nb_channels, |
|
stop_nb_samples, |
|
stop_window_nb_samples); |
|
|
|
if (s->detection != D_PEAK && s->detection != D_MEDIAN && |
|
s->detection != D_PTP) |
|
window_size = s->stop_window_size; |
|
|
|
for (int ch = 0; ch < nb_channels; ch++) { |
|
ftype stop_sample = stop[stop_pos + ch]; |
|
ftype stop_ow = stopw[stop_wpos + ch]; |
|
ftype tstop; |
|
|
|
tstop = fn(s->compute)(stop_cache + ch * cache_size, |
|
stop_sample, |
|
stop_ow, |
|
window_size, |
|
front + ch, |
|
back + ch); |
|
|
|
stopw[stop_wpos + ch] = stop_sample; |
|
|
|
if (stop_mode == T_ANY) { |
|
stop_thres |= tstop <= stop_threshold; |
|
} else { |
|
stop_thres &= tstop <= stop_threshold; |
|
} |
|
} |
|
|
|
s->found_nonsilence = FFMAX(s->found_nonsilence, !stop_thres); |
|
if (restart && !stop_thres) |
|
s->stop_found_periods = 0; |
|
|
|
if (s->stop_found_periods >= 0 || ctx->is_disabled) { |
|
if (s->found_nonsilence) { |
|
s->stop_sample_count += stop_thres; |
|
s->stop_sample_count *= stop_thres; |
|
} |
|
} else if (s->stop_silence_count > 0) { |
|
const int dst_pos = out_nb_samples * nb_channels; |
|
for (int ch = 0; ch < nb_channels; ch++) |
|
dst[dst_pos + ch] = stop[stop_pos + ch]; |
|
s->stop_silence_count--; |
|
out_nb_samples++; |
|
} |
|
|
|
if (s->stop_sample_count > stop_duration) { |
|
s->stop_found_periods++; |
|
if (s->stop_found_periods >= stop_periods) { |
|
s->stop_found_periods = -1; |
|
s->stop_silence_count = stop_silence; |
|
} |
|
|
|
s->stop_sample_count = 0; |
|
} |
|
|
|
if (s->stop_found_periods >= 0 || ctx->is_disabled) { |
|
const int dst_pos = out_nb_samples * nb_channels; |
|
for (int ch = 0; ch < nb_channels; ch++) |
|
dst[dst_pos + ch] = stop[stop_pos + ch]; |
|
out_nb_samples++; |
|
} |
|
|
|
*nb_out_samples = out_nb_samples; |
|
} |
|
|