summaryrefslogtreecommitdiffstats
path: root/libaf
diff options
context:
space:
mode:
authoralex <alex@b3059339-0415-0410-9bf9-f77b7e298cf2>2004-10-04 19:11:05 +0000
committeralex <alex@b3059339-0415-0410-9bf9-f77b7e298cf2>2004-10-04 19:11:05 +0000
commitb7d2e203d8716a64a47f3a1e5f9ef0256e6fb83a (patch)
tree97f212db2709b255566d7c701a9970da89446da1 /libaf
parent41cd2f8d7d5e3825484ae47b426cf866e98027f5 (diff)
downloadmpv-b7d2e203d8716a64a47f3a1e5f9ef0256e6fb83a.tar.bz2
mpv-b7d2e203d8716a64a47f3a1e5f9ef0256e6fb83a.tar.xz
reimplementation of the pl_extrastereo and pl_volnorm plugins
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@13551 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libaf')
-rw-r--r--libaf/Makefile2
-rw-r--r--libaf/af.c4
-rw-r--r--libaf/af_extrastereo.c120
-rw-r--r--libaf/af_format.h2
-rw-r--r--libaf/af_volnorm.c344
-rw-r--r--libaf/control.h4
6 files changed, 474 insertions, 2 deletions
diff --git a/libaf/Makefile b/libaf/Makefile
index 15b988b822..188a0cee0a 100644
--- a/libaf/Makefile
+++ b/libaf/Makefile
@@ -2,7 +2,7 @@ include ../config.mak
LIBNAME = libaf.a
-SRCS=af.c af_mp.c af_dummy.c af_delay.c af_channels.c af_format.c af_resample.c window.c filter.c af_volume.c af_equalizer.c af_tools.c af_comp.c af_gate.c af_pan.c af_surround.c af_sub.c af_export.c
+SRCS=af.c af_mp.c af_dummy.c af_delay.c af_channels.c af_format.c af_resample.c window.c filter.c af_volume.c af_equalizer.c af_tools.c af_comp.c af_gate.c af_pan.c af_surround.c af_sub.c af_export.c af_volnorm.c af_extrastereo.c
OBJS=$(SRCS:.c=.o)
diff --git a/libaf/af.c b/libaf/af.c
index 5728095ab3..7b1aeeda8e 100644
--- a/libaf/af.c
+++ b/libaf/af.c
@@ -23,6 +23,8 @@ extern af_info_t af_info_pan;
extern af_info_t af_info_surround;
extern af_info_t af_info_sub;
extern af_info_t af_info_export;
+extern af_info_t af_info_volnorm;
+extern af_info_t af_info_extrastereo;
static af_info_t* filter_list[]={
&af_info_dummy,
@@ -40,6 +42,8 @@ static af_info_t* filter_list[]={
#ifdef HAVE_SYS_MMAN_H
&af_info_export,
#endif
+ &af_info_volnorm,
+ &af_info_extrastereo,
NULL
};
diff --git a/libaf/af_extrastereo.c b/libaf/af_extrastereo.c
new file mode 100644
index 0000000000..a8857b4b33
--- /dev/null
+++ b/libaf/af_extrastereo.c
@@ -0,0 +1,120 @@
+/*=============================================================================
+//
+// This software has been released under the terms of the GNU 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"
+
+// Data for specific instances of this filter
+typedef struct af_extrastereo_s
+{
+ float mul;
+}af_extrastereo_t;
+
+// Initialization and runtime control
+static int control(struct af_instance_s* af, int cmd, void* arg)
+{
+ af_extrastereo_t* s = (af_extrastereo_t*)af->setup;
+
+ switch(cmd){
+ case AF_CONTROL_REINIT:
+ // Sanity check
+ if(!arg) return AF_ERROR;
+
+ if(((af_data_t*)arg)->format != (AF_FORMAT_SI | AF_FORMAT_NE) ||
+ (((af_data_t*)arg)->nch != 2))
+ return AF_ERROR;
+
+ af->data->rate = ((af_data_t*)arg)->rate;
+ af->data->nch = 2;
+ af->data->format = AF_FORMAT_SI | AF_FORMAT_NE;
+ af->data->bps = 2;
+
+ return af_test_output(af,(af_data_t*)arg);
+ case AF_CONTROL_COMMAND_LINE:{
+ float f;
+ sscanf((char*)arg,"%f", &f);
+ s->mul = f;
+ return AF_OK;
+ }
+ case AF_CONTROL_ES_MUL | AF_CONTROL_SET:
+ s->mul = *(float*)arg;
+ return AF_OK;
+ case AF_CONTROL_ES_MUL | AF_CONTROL_GET:
+ *(float*)arg = s->mul;
+ 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);
+}
+
+// Filter data through filter
+static af_data_t* play(struct af_instance_s* af, af_data_t* data)
+{
+ af_extrastereo_t *s = af->setup;
+ register int i = 0;
+ int16_t *a = (int16_t*)data->audio; // Audio data
+ int len = data->len/2; // Number of samples
+ int avg, l, r;
+
+ for (i = 0; i < len; i+=2)
+ {
+ avg = (a[i] + a[i + 1]) / 2;
+
+ l = avg + (int)(s->mul * (a[i] - avg));
+ r = avg + (int)(s->mul * (a[i + 1] - avg));
+
+ a[i] = clamp(l, SHRT_MIN, SHRT_MAX);
+ a[i + 1] = clamp(r, SHRT_MIN, SHRT_MAX);
+ }
+
+ return data;
+}
+
+// Allocate memory and set function pointers
+static int open(af_instance_t* af){
+ 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_extrastereo_t));
+ if(af->data == NULL || af->setup == NULL)
+ return AF_ERROR;
+
+ ((af_extrastereo_t*)af->setup)->mul = 2.5;
+ return AF_OK;
+}
+
+// Description of this filter
+af_info_t af_info_extrastereo = {
+ "Extra stereo",
+ "extrastereo",
+ "Alex Beregszaszi & Pierre Lombard",
+ "",
+ AF_FLAGS_NOT_REENTRANT,
+ open
+};
diff --git a/libaf/af_format.h b/libaf/af_format.h
index 931a9b88ee..f7b2a15b16 100644
--- a/libaf/af_format.h
+++ b/libaf/af_format.h
@@ -18,7 +18,7 @@
#define AF_FORMAT_US (1<<1) // Un Signed
#define AF_FORMAT_SIGN_MASK (1<<1)
-// Fixed of floating point
+// Fixed or floating point
#define AF_FORMAT_I (0<<2) // Int
#define AF_FORMAT_F (1<<2) // Foating point
#define AF_FORMAT_POINT_MASK (1<<2)
diff --git a/libaf/af_volnorm.c b/libaf/af_volnorm.c
new file mode 100644
index 0000000000..8ad44c858b
--- /dev/null
+++ b/libaf/af_volnorm.c
@@ -0,0 +1,344 @@
+/*=============================================================================
+//
+// This software has been released under the terms of the GNU 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 filter
+typedef 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 control
+static 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_F | AF_FORMAT_NE) &&
+ ((af_data_t*)arg)->format != (AF_FORMAT_SI | AF_FORMAT_NE))
+ return AF_ERROR;
+
+ if(((af_data_t*)arg)->format == (AF_FORMAT_SI | AF_FORMAT_NE)){
+ af->data->format = AF_FORMAT_SI | AF_FORMAT_NE;
+ af->data->bps = 2;
+ }else{
+ af->data->format = AF_FORMAT_F | AF_FORMAT_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 filter
+static 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_SI | AF_FORMAT_NE))
+ {
+ if (s->method)
+ method2_int16(s, data);
+ else
+ method1_int16(s, data);
+ }
+ else if(af->data->format == (AF_FORMAT_F | AF_FORMAT_NE))
+ {
+ if (s->method)
+ method2_float(s, data);
+ else
+ method1_float(s, data);
+ }
+ return data;
+}
+
+// Allocate memory and set function pointers
+static 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 filter
+af_info_t af_info_volnorm = {
+ "Volume normalizer filter",
+ "volnorm",
+ "Alex Beregszaszi & Pierre Lombard",
+ "",
+ AF_FLAGS_NOT_REENTRANT,
+ open
+};
diff --git a/libaf/control.h b/libaf/control.h
index f2deb83dbd..31ad012b0b 100644
--- a/libaf/control.h
+++ b/libaf/control.h
@@ -218,4 +218,8 @@ typedef struct af_control_ext_s{
// Export
#define AF_CONTROL_EXPORT_SZ 0x00002000 | AF_CONTROL_FILTER_SPECIFIC
+
+// ExtraStereo Multiplier
+#define AF_CONTROL_ES_MUL 0x00002100 | AF_CONTROL_FILTER_SPECIFIC
+
#endif /*__af_control_h */