From 1dd66e3e7c80a95dbd4fedeb7978b3f32f66d2b1 Mon Sep 17 00:00:00 2001 From: Andre Date: Mon, 13 Mar 2006 01:35:25 +0100 Subject: [PATCH] speed up the compress filter Complete rewrite of the core loop of the compress filter. The gprof output of para_audiod (see below) indicates that CPU usage goes down to about 40%. new: ~~~~ Each sample counts as 0.01 seconds. % cumulative self self total time seconds seconds calls s/call s/call name 35.94 1.47 1.47 7414 0.00 0.00 compress 22.74 2.40 0.93 57319 0.00 0.00 mp3dec 16.87 3.09 0.69 1 0.69 4.04 audiod_mainloop 34.59 1.47 1.47 7414 0.00 0.00 compress 22.59 2.43 0.96 1 0.96 4.20 audiod_mainloop 17.53 3.17 0.74 61285 0.00 0.00 mp3dec 35.41 1.48 1.48 7414 0.00 0.00 compress 20.10 2.32 0.84 1 0.84 4.15 audiod_mainloop 17.82 3.06 0.74 58675 0.00 0.00 mp3dec Average of self-seconds (3rd column): compress 1.47 audiod_mainloop 0.83 mp3dec 0.80 0.2.11: ~~~~~~~ Each sample counts as 0.01 seconds. % cumulative self self total time seconds seconds calls s/call s/call name 56.38 3.31 3.31 7414 0.00 0.00 compress 12.93 4.08 0.76 57566 0.00 0.00 mp3dec 11.39 4.75 0.67 1 0.67 5.86 audiod_mainloop 57.59 3.38 3.38 7414 0.00 0.00 compress 14.08 4.20 0.82 63095 0.00 0.00 mp3dec 11.26 4.86 0.66 1 0.66 5.82 audiod_mainloop 57.79 4.12 4.12 7414 0.00 0.00 compress 13.62 5.08 0.97 1 0.97 7.07 audiod_mainloop 8.08 5.66 0.57 57196 0.00 0.00 mp3dec Average of self-seconds (3rd column): compress 3.60 audiod_mainloop 0.76 mp3dec 0.71 --- compress.c | 146 ++++++++++++++++++-------------------------- compress_filter.ggo | 12 ++-- 2 files changed, 64 insertions(+), 94 deletions(-) diff --git a/compress.c b/compress.c index bad4ada4..b7ddc285 100644 --- a/compress.c +++ b/compress.c @@ -19,7 +19,7 @@ /** \file compress.c paraslash's dynamic audio range compressor */ /* - * Based on AudioCompress, (C) 2002-2004 M. Hari Nezumi + * Used ideas of AudioCompress, (C) 2002-2004 M. Hari Nezumi */ #include "para.h" @@ -28,113 +28,83 @@ #include "filter.h" #include "string.h" -/** how fine-grained the gain is */ -#define GAINSHIFT 10 /** the size of the output data buffer */ #define COMPRESS_CHUNK_SIZE 40960 /** data specific to the compress filter */ struct private_compress_data { - /** an array holding the previous peak values */ - int *peaks; - /** current bucket number to be modified */ - unsigned pn; - /** number of times clipping occured */ - unsigned clip; /** the current multiplier */ - int current_gain; - /** the target multiplier */ - int target_gain; - /** pointer to the configuration data for this instance of the compress filter */ + unsigned current_gain; + /** points to the configuration data for this instance of the compress filter */ struct gengetopt_args_info *conf; + /** minimal admissible gain */ + unsigned min_gain; + /** maximal admissible gain */ + unsigned max_gain; + /** number of samples already seen */ + unsigned num_samples; + /** absolute value of the maximal sample in the current block */ + unsigned peak; }; static ssize_t compress(char *inbuf, size_t inbuf_len, struct filter_node *fn) { - int16_t *audio = (int16_t *) inbuf, *ip = audio, *op; - int peak = 1, pos = 0, i, gr, gf, gn; - size_t length = MIN((inbuf_len / 2) * 2, (fn->bufsize - fn->loaded) / 2 * 2); + size_t i, length = MIN((inbuf_len / 2) * 2, (fn->bufsize - fn->loaded) / 2 * 2); struct private_compress_data *pcd = fn->private_data; + int16_t *ip = (int16_t *)inbuf, *op = (int16_t *)(fn->buf + fn->loaded); + unsigned gain_shift = pcd->conf->inertia_arg + pcd->conf->damp_arg, + mask = (1 << pcd->conf->blocksize_arg) - 1; if (!length) return 0; - /* determine peak's value and position */ - for (i = 0; i < length / 2; i++, ip++) { - int val = ABS(*ip); - if (val > peak) { - peak = val; - pos = i; - } - } - pcd->peaks[pcd->pn] = peak; - for (i = 0; i < pcd->conf->buckets_arg; i++) { - if (pcd->peaks[i] > peak) { - peak = pcd->peaks[i]; - pos = 0; - } - } - /* determine target gain */ - gn = (1 << GAINSHIFT) * pcd->conf->target_level_arg / peak; - if (gn < (1 << GAINSHIFT)) - gn = 1 << GAINSHIFT; - pcd->target_gain = (pcd->target_gain * ((1 << pcd->conf->gain_smooth_arg) - 1) + gn) - >> pcd->conf->gain_smooth_arg; - /* give it an extra insignificant nudge to counteract possible - * rounding error - */ - if (gn < pcd->target_gain) - pcd->target_gain--; - else if (gn > pcd->target_gain) - pcd->target_gain++; - if (pcd->target_gain > pcd->conf->gain_max_arg << GAINSHIFT) - pcd->target_gain = pcd->conf->gain_max_arg << GAINSHIFT; - /* see if a peak is going to clip */ - gn = (1 << GAINSHIFT) * 32768 / peak; - if (gn < pcd->target_gain) { - pcd->target_gain = gn; - if (pcd->conf->anticlip_given) - pos = 0; - } else - /* we're ramping up, so draw it out over the whole frame */ - pos = length; - /* determine gain rate necessary to make target */ - if (!pos) - pos = 1; - gr = ((pcd->target_gain - pcd->current_gain) << 16) / pos; - gf = pcd->current_gain << 16; - ip = audio; - op = (int16_t *)(fn->buf + fn->loaded); for (i = 0; i < length / 2; i++) { - int sample; - /* interpolate the gain */ - pcd->current_gain = gf >> 16; - if (i < pos) - gf += gr; - else if (i == pos) - gf = pcd->target_gain << 16; - /* amplify */ - sample = (*ip++) * pcd->current_gain * pcd->conf->volume_arg / 10 >> GAINSHIFT; - if (sample < -32768) { - pcd->clip++; - sample = -32768; - } else if (sample > 32767) { - pcd->clip++; - sample = 32767; + /* be careful in that heat, my dear */ + int sample = *ip++, adjusted_sample; + + if (sample > 0) { + adjusted_sample = (sample * pcd->current_gain) + >> gain_shift; + if (unlikely(adjusted_sample > 32767)) { + adjusted_sample = 32767; + pcd->current_gain = (pcd->current_gain + + (1 << pcd->conf->inertia_arg)) / 2; + pcd->peak = 0; + } else + if (adjusted_sample > pcd->peak) + pcd->peak = sample; + } else { + adjusted_sample = -((-sample * pcd->current_gain) + >> gain_shift); + if (unlikely(adjusted_sample < -32768)) { + adjusted_sample = -32768; + pcd->current_gain = (pcd->current_gain + + (1 << pcd->conf->inertia_arg)) / 2; + pcd->peak = 0; + } else + if (-adjusted_sample > pcd->peak) + pcd->peak = -adjusted_sample; + } + *op++ = adjusted_sample; + if (likely(++pcd->num_samples & mask)) + continue; + if (pcd->peak < pcd->conf->target_level_arg) { + if (pcd->current_gain < pcd->max_gain) + pcd->current_gain++; + } else { + if (pcd->current_gain > pcd->min_gain + 1) + pcd->current_gain -= 2; } - *op++ = sample; +// PARA_DEBUG_LOG("gain: %lu, peak: %d\n", pcd->current_gain, +// pcd->peak); + pcd->peak = 0; +// PARA_INFO_LOG("sample: %lu\n", ABS(sample)); } - pcd->pn = (pcd->pn + 1) % pcd->conf->buckets_arg; - PARA_DEBUG_LOG("bucket: %03i, input len: %zd, length: %zd, peak: %05i, " - "current gain: %03i, clipped: %d\n", pcd->pn, inbuf_len, - length, peak, pcd->current_gain, pcd->clip); - fn->loaded = length; + fn->loaded += length; return length; } static void close_compress(struct filter_node *fn) { - struct private_compress_data *pcd = fn->private_data; - free(pcd->peaks); free(fn->private_data); free(fn->buf); } @@ -152,13 +122,13 @@ static void open_compress(struct filter_node *fn) { struct private_compress_data *pcd = para_calloc( sizeof(struct private_compress_data)); -// compress_cmdline_parser(fn->argc, fn->argv, &pcd->conf); pcd->conf = fn->conf; - pcd->peaks = para_calloc(pcd->conf->buckets_arg * sizeof(int)); fn->private_data = pcd; fn->bufsize = COMPRESS_CHUNK_SIZE; fn->buf = para_malloc(fn->bufsize); - fn->loaded = 0; + pcd->current_gain = 1 << pcd->conf->inertia_arg; + pcd->min_gain = 1 << (pcd->conf->inertia_arg - pcd->conf->aggressiveness_arg); + pcd->max_gain = 1 << (pcd->conf->inertia_arg + pcd->conf->aggressiveness_arg); } /** the init function of the compress filter */ diff --git a/compress_filter.ggo b/compress_filter.ggo index 6a6d7630..f4ba7a83 100644 --- a/compress_filter.ggo +++ b/compress_filter.ggo @@ -1,7 +1,7 @@ section "The dynamic audio range compressor" -option "anticlip" c "enable clipping protection" flag on -option "buckets" b "history length" int typestr="number" default="400" no -option "target_level" t "target signal level (1-32767)" int typestr="number" default="25000" no -option "gain_max" g "maximum amount to amplify by" int typestr="number" default="4" no -option "gain_smooth" i "how much inertia ramping has" int typestr="number" default="5" no -option "volume" v "set soft volume (0-10)" int typestr="number" default="10" no + +option "blocksize" b "larger blocksize means fewer volume adjustments per time unit" int typestr="number" default="16" no +option "aggressiveness" a "controls the maximum amount to amplify by" int typestr="number" default="2" no +option "inertia" i "how much inertia ramping has" int typestr="number" default="6" no +option "target_level" t "target signal level (0-32768)" int typestr="number" default="25000" no +option "damp" d "if non-zero, scale down after normalizing" int typestr="number" default="0" no -- 2.39.5