new smoothing method ('#define AVG 2' to enable'n'test it)

should be better and smoother but still some glitches in it :/


git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@5026 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
pl 2002-03-10 13:53:38 +00:00
parent 0b980e55aa
commit 85aedd0005
1 changed files with 97 additions and 21 deletions

View File

@ -7,12 +7,21 @@
* License: GPLv2 * License: GPLv2
* Author: pl <p_l@gmx.fr> (c) 2002 and beyond... * Author: pl <p_l@gmx.fr> (c) 2002 and beyond...
* *
* Sources: some ideas from volnorm for xmms * Sources: some ideas from volnorm plugin for xmms
* *
* */ * */
#define PLUGIN #define PLUGIN
/* Values for AVG:
* 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)
*
* */
#define AVG 1
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <inttypes.h> #include <inttypes.h>
@ -36,9 +45,11 @@ LIBAO_PLUGIN_EXTERN(volnorm)
// and has to be in [MUL_MIN, MUL_MAX] // and has to be in [MUL_MIN, MUL_MAX]
#define MUL_INIT 1.0 #define MUL_INIT 1.0
#define MUL_MIN 0.1 #define MUL_MIN 0.1
#define MUL_MAX 15.0 #define MUL_MAX 5.0
static float mul; static float mul;
#if AVG==1
// "history" value of the filter // "history" value of the filter
static float lastavg; static float lastavg;
@ -47,17 +58,44 @@ static float lastavg;
#define SMOOTH_MUL 0.06 #define SMOOTH_MUL 0.06
#define SMOOTH_LASTAVG 0.06 #define SMOOTH_LASTAVG 0.06
#elif AVG==2
// Size of the memory array
// FIXME: should depend on the frequency of the data (should be a few seconds)
#define NSAMPLES 128
// Indicates where to write (in 0..NSAMPLES-1)
static int idx;
// The array
static struct {
float avg; // average level of the sample
int32_t len; // sample size (weight)
} mem[NSAMPLES];
// 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
#else
// Kab00m !
#error "Unknown AVG"
#endif
// Some limits // Some limits
#define MIN_S16 -32768 #define MIN_S16 -32768
#define MAX_S16 32767 #define MAX_S16 32767
// ideal average level // "Ideal" level
#define MID_S16 (MAX_S16 * 0.25) #define MID_S16 (MAX_S16 * 0.25)
// silence level // Silence level
#define SIL_S16 (MAX_S16 * 0.02) // FIXME: should be relative to the level of the samples
#define SIL_S16 (MAX_S16 * 0.01)
// local data
// Local data
static struct { static struct {
int inuse; // This plugin is in use TRUE, FALSE int inuse; // This plugin is in use TRUE, FALSE
int format; // sample fomat int format; // sample fomat
@ -101,13 +139,23 @@ static void uninit(){
// empty buffers // empty buffers
static void reset(){ static void reset(){
int i;
mul = MUL_INIT; mul = MUL_INIT;
switch(ao_plugin_data.format) { switch(ao_plugin_data.format) {
case(AFMT_S16_LE): case(AFMT_S16_LE):
#if AVG==1
lastavg = MID_S16; lastavg = MID_S16;
#elif AVG==2
for(i=0; i < NSAMPLES; ++i) {
mem[i].len = 0;
mem[i].avg = 0;
}
idx = 0;
#endif
break; break;
default: default:
fprintf(stderr,"[pl_volnorm] internal inconsistency - please bugreport.\n"); fprintf(stderr,"[pl_volnorm] internal inconsistency - bugreport !\n");
*(char *) 0 = 0; *(char *) 0 = 0;
} }
} }
@ -124,13 +172,17 @@ static int play(){
int16_t* data=(int16_t*)ao_plugin_data.data; int16_t* data=(int16_t*)ao_plugin_data.data;
int len=ao_plugin_data.len / 2; // 16 bits samples int len=ao_plugin_data.len / 2; // 16 bits samples
int32_t i; int32_t i, tmp;
register int32_t tmp; float curavg, newavg;
register float curavg;
float newavg;
float neededmul;
// average of the current samples #if AVG==1
float neededmul;
#elif AVG==2
float avg;
int32_t totallen;
#endif
// Evaluate current samples average level
curavg = 0.0; curavg = 0.0;
for (i = 0; i < len ; ++i) { for (i = 0; i < len ; ++i) {
tmp = data[i]; tmp = data[i];
@ -138,6 +190,9 @@ static int play(){
} }
curavg = sqrt(curavg / (float) len); curavg = sqrt(curavg / (float) len);
// Evaluate an adequate 'mul' coefficient based on previous state, current
// samples level, etc
#if AVG==1
if (curavg > SIL_S16) { if (curavg > SIL_S16) {
neededmul = MID_S16 / ( curavg * mul); neededmul = MID_S16 / ( curavg * mul);
mul = (1.0 - SMOOTH_MUL) * mul + SMOOTH_MUL * neededmul; mul = (1.0 - SMOOTH_MUL) * mul + SMOOTH_MUL * neededmul;
@ -145,10 +200,27 @@ static int play(){
// Clamp the mul coefficient // Clamp the mul coefficient
CLAMP(mul, MUL_MIN, MUL_MAX); CLAMP(mul, MUL_MIN, MUL_MAX);
} }
#elif AVG==2
avg = 0.0;
totallen = 0;
for (i = 0; i < NSAMPLES; ++i) {
avg += mem[i].avg * (float) mem[i].len;
totallen += mem[i].len;
}
if (totallen > MIN_SAMPLE_SIZE) {
avg /= (float) totallen;
if (avg >= SIL_S16) {
mul = (float) MID_S16 / avg;
CLAMP(mul, MUL_MIN, MUL_MAX);
}
}
#endif
// Scale & clamp the samples // Scale & clamp the samples
for (i = 0; i < len ; ++i) { for (i = 0; i < len ; ++i) {
tmp = data[i] * mul; tmp = mul * data[i];
CLAMP(tmp, MIN_S16, MAX_S16); CLAMP(tmp, MIN_S16, MAX_S16);
data[i] = tmp; data[i] = tmp;
} }
@ -156,13 +228,17 @@ static int play(){
// Evaluation of newavg (not 100% accurate because of values clamping) // Evaluation of newavg (not 100% accurate because of values clamping)
newavg = mul * curavg; newavg = mul * curavg;
#if 0 // Stores computed values for future smoothing
printf("time = %d len = %d curavg = %6.0f lastavg = %6.0f newavg = %6.0f\n" #if AVG==1
" needed_m = %2.2f m = %2.2f\n\n",
time(NULL), len, curavg, lastavg, newavg, neededmul, mul);
#endif
lastavg = (1.0 - SMOOTH_LASTAVG) * lastavg + SMOOTH_LASTAVG * newavg; lastavg = (1.0 - SMOOTH_LASTAVG) * lastavg + SMOOTH_LASTAVG * newavg;
//printf("\rmul=%02.1f ", mul);
#elif AVG==2
mem[idx].len = len;
mem[idx].avg = newavg;
idx = (idx + 1) % NSAMPLES;
//printf("\rmul=%02.1f (%04dKiB) ", mul, totallen/1024);
#endif
//fflush(stdout);
break; break;
} }