📄 af_volnorm.c
字号:
/*=============================================================================// // This software has been released under the terms of the GNU General Public// license. See http://www.gnu.org/copyleft/gpl.html for details.//// Copyright 2004 Alex Beregszaszi & Pierre Lombard////=============================================================================*/#include <stdio.h>#include <stdlib.h>#include <string.h> #include <unistd.h>#include <inttypes.h>#include <math.h>#include <limits.h>#include "af.h"// Methods:// 1: uses a 1 value memory and coefficients new=a*old+b*cur (with a+b=1)// 2: uses several samples to smooth the variations (standard weighted mean// on past samples)// Size of the memory array// FIXME: should depend on the frequency of the data (should be a few seconds)#define NSAMPLES 128// If summing all the mem[].len is lower than MIN_SAMPLE_SIZE bytes, then we// choose to ignore the computed value as it's not significant enough// FIXME: should depend on the frequency of the data (0.5s maybe)#define MIN_SAMPLE_SIZE 32000// mul is the value by which the samples are scaled// and has to be in [MUL_MIN, MUL_MAX]#define MUL_INIT 1.0#define MUL_MIN 0.1#define MUL_MAX 5.0// "Ideal" level#define MID_S16 (SHRT_MAX * 0.25)#define MID_FLOAT (INT_MAX * 0.25)// Silence level// FIXME: should be relative to the level of the samples#define SIL_S16 (SHRT_MAX * 0.01)#define SIL_FLOAT (INT_MAX * 0.01) // FIXME// smooth must be in ]0.0, 1.0[#define SMOOTH_MUL 0.06#define SMOOTH_LASTAVG 0.06// Data for specific instances of this filtertypedef struct af_volume_s{ int method; // method used float mul; // method 1 float lastavg; // history value of the filter // method 2 int idx; struct { float avg; // average level of the sample int len; // sample size (weight) } mem[NSAMPLES];}af_volnorm_t;// Initialization and runtime controlstatic int control(struct af_instance_s* af, int cmd, void* arg){ af_volnorm_t* s = (af_volnorm_t*)af->setup; switch(cmd){ case AF_CONTROL_REINIT: // Sanity check if(!arg) return AF_ERROR; af->data->rate = ((af_data_t*)arg)->rate; af->data->nch = ((af_data_t*)arg)->nch; if(((af_data_t*)arg)->format == (AF_FORMAT_S16_NE)){ af->data->format = AF_FORMAT_S16_NE; af->data->bps = 2; }else{ af->data->format = AF_FORMAT_FLOAT_NE; af->data->bps = 4; } return af_test_output(af,(af_data_t*)arg); case AF_CONTROL_COMMAND_LINE:{ int i; sscanf((char*)arg,"%d", &i); if (i != 1 && i != 2) return AF_ERROR; s->method = i-1; return AF_OK; } } return AF_UNKNOWN;}// Deallocate memory static void uninit(struct af_instance_s* af){ if(af->data) free(af->data); if(af->setup) free(af->setup);}static void method1_int16(af_volnorm_t *s, af_data_t *c){ register int i = 0; int16_t *data = (int16_t*)c->audio; // Audio data int len = c->len/2; // Number of samples float curavg = 0.0, newavg, neededmul; int tmp; for (i = 0; i < len; i++) { tmp = data[i]; curavg += tmp * tmp; } curavg = sqrt(curavg / (float) len); // Evaluate an adequate 'mul' coefficient based on previous state, current // samples level, etc if (curavg > SIL_S16) { neededmul = MID_S16 / (curavg * s->mul); s->mul = (1.0 - SMOOTH_MUL) * s->mul + SMOOTH_MUL * neededmul; // clamp the mul coefficient s->mul = clamp(s->mul, MUL_MIN, MUL_MAX); } // Scale & clamp the samples for (i = 0; i < len; i++) { tmp = s->mul * data[i]; tmp = clamp(tmp, SHRT_MIN, SHRT_MAX); data[i] = tmp; } // Evaulation of newavg (not 100% accurate because of values clamping) newavg = s->mul * curavg; // Stores computed values for future smoothing s->lastavg = (1.0 - SMOOTH_LASTAVG) * s->lastavg + SMOOTH_LASTAVG * newavg;}static void method1_float(af_volnorm_t *s, af_data_t *c){ register int i = 0; float *data = (float*)c->audio; // Audio data int len = c->len/4; // Number of samples float curavg = 0.0, newavg, neededmul, tmp; for (i = 0; i < len; i++) { tmp = data[i]; curavg += tmp * tmp; } curavg = sqrt(curavg / (float) len); // Evaluate an adequate 'mul' coefficient based on previous state, current // samples level, etc if (curavg > SIL_FLOAT) // FIXME { neededmul = MID_FLOAT / (curavg * s->mul); s->mul = (1.0 - SMOOTH_MUL) * s->mul + SMOOTH_MUL * neededmul; // clamp the mul coefficient s->mul = clamp(s->mul, MUL_MIN, MUL_MAX); } // Scale & clamp the samples for (i = 0; i < len; i++) data[i] *= s->mul; // Evaulation of newavg (not 100% accurate because of values clamping) newavg = s->mul * curavg; // Stores computed values for future smoothing s->lastavg = (1.0 - SMOOTH_LASTAVG) * s->lastavg + SMOOTH_LASTAVG * newavg;}static void method2_int16(af_volnorm_t *s, af_data_t *c){ register int i = 0; int16_t *data = (int16_t*)c->audio; // Audio data int len = c->len/2; // Number of samples float curavg = 0.0, newavg, avg = 0.0; int tmp, totallen = 0; for (i = 0; i < len; i++) { tmp = data[i]; curavg += tmp * tmp; } curavg = sqrt(curavg / (float) len); // Evaluate an adequate 'mul' coefficient based on previous state, current // samples level, etc for (i = 0; i < NSAMPLES; i++) { avg += s->mem[i].avg * (float)s->mem[i].len; totallen += s->mem[i].len; } if (totallen > MIN_SAMPLE_SIZE) { avg /= (float)totallen; if (avg >= SIL_S16) { s->mul = MID_S16 / avg; s->mul = clamp(s->mul, MUL_MIN, MUL_MAX); } } // Scale & clamp the samples for (i = 0; i < len; i++) { tmp = s->mul * data[i]; tmp = clamp(tmp, SHRT_MIN, SHRT_MAX); data[i] = tmp; } // Evaulation of newavg (not 100% accurate because of values clamping) newavg = s->mul * curavg; // Stores computed values for future smoothing s->mem[s->idx].len = len; s->mem[s->idx].avg = newavg; s->idx = (s->idx + 1) % NSAMPLES;}static void method2_float(af_volnorm_t *s, af_data_t *c){ register int i = 0; float *data = (float*)c->audio; // Audio data int len = c->len/4; // Number of samples float curavg = 0.0, newavg, avg = 0.0, tmp; int totallen = 0; for (i = 0; i < len; i++) { tmp = data[i]; curavg += tmp * tmp; } curavg = sqrt(curavg / (float) len); // Evaluate an adequate 'mul' coefficient based on previous state, current // samples level, etc for (i = 0; i < NSAMPLES; i++) { avg += s->mem[i].avg * (float)s->mem[i].len; totallen += s->mem[i].len; } if (totallen > MIN_SAMPLE_SIZE) { avg /= (float)totallen; if (avg >= SIL_FLOAT) { s->mul = MID_FLOAT / avg; s->mul = clamp(s->mul, MUL_MIN, MUL_MAX); } } // Scale & clamp the samples for (i = 0; i < len; i++) data[i] *= s->mul; // Evaulation of newavg (not 100% accurate because of values clamping) newavg = s->mul * curavg; // Stores computed values for future smoothing s->mem[s->idx].len = len; s->mem[s->idx].avg = newavg; s->idx = (s->idx + 1) % NSAMPLES;}// Filter data through filterstatic af_data_t* play(struct af_instance_s* af, af_data_t* data){ af_volnorm_t *s = af->setup; if(af->data->format == (AF_FORMAT_S16_NE)) { if (s->method) method2_int16(s, data); else method1_int16(s, data); } else if(af->data->format == (AF_FORMAT_FLOAT_NE)) { if (s->method) method2_float(s, data); else method1_float(s, data); } return data;}// Allocate memory and set function pointersstatic int open(af_instance_t* af){ int i = 0; af->control=control; af->uninit=uninit; af->play=play; af->mul.n=1; af->mul.d=1; af->data=calloc(1,sizeof(af_data_t)); af->setup=calloc(1,sizeof(af_volnorm_t)); if(af->data == NULL || af->setup == NULL) return AF_ERROR; ((af_volnorm_t*)af->setup)->mul = MUL_INIT; ((af_volnorm_t*)af->setup)->lastavg = MID_S16; ((af_volnorm_t*)af->setup)->idx = 0; for (i = 0; i < NSAMPLES; i++) { ((af_volnorm_t*)af->setup)->mem[i].len = 0; ((af_volnorm_t*)af->setup)->mem[i].avg = 0; } return AF_OK;}// Description of this filteraf_info_t af_info_volnorm = { "Volume normalizer filter", "volnorm", "Alex Beregszaszi & Pierre Lombard", "", AF_FLAGS_NOT_REENTRANT, open};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -