summaryrefslogtreecommitdiffstats
path: root/libao2
diff options
context:
space:
mode:
authorpl <pl@b3059339-0415-0410-9bf9-f77b7e298cf2>2002-03-05 09:17:36 +0000
committerpl <pl@b3059339-0415-0410-9bf9-f77b7e298cf2>2002-03-05 09:17:36 +0000
commitbb18f52a7a344552e38d0fa6ba5f1f6b6342bfec (patch)
treecc15cee2eb8e43a8d5105b11fc5af4ecb718e3cc /libao2
parentfd4c906d13fadddc28a85ae78e004352f36b3293 (diff)
downloadmpv-bb18f52a7a344552e38d0fa6ba5f1f6b6342bfec.tar.bz2
mpv-bb18f52a7a344552e38d0fa6ba5f1f6b6342bfec.tar.xz
volume normalizer plugin support
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@4942 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libao2')
-rw-r--r--libao2/Makefile2
-rw-r--r--libao2/audio_plugin.h4
-rw-r--r--libao2/pl_volnorm.c171
3 files changed, 175 insertions, 2 deletions
diff --git a/libao2/Makefile b/libao2/Makefile
index 1701e6dd73..0e106b6008 100644
--- a/libao2/Makefile
+++ b/libao2/Makefile
@@ -4,7 +4,7 @@ include config.mak
LIBNAME = libao2.a
# TODO: moveout ao_sdl.c so it's only used when SDL is detected
-SRCS=afmt.c audio_out.c ao_mpegpes.c ao_null.c ao_pcm.c ao_plugin.c pl_delay.c pl_format.c pl_surround.c remez.c pl_resample.c pl_volume.c pl_extrastereo.c $(OPTIONAL_SRCS)
+SRCS=afmt.c audio_out.c ao_mpegpes.c ao_null.c ao_pcm.c ao_plugin.c pl_delay.c pl_format.c pl_surround.c remez.c pl_resample.c pl_volume.c pl_extrastereo.c pl_volnorm.c $(OPTIONAL_SRCS)
OBJS=$(SRCS:.c=.o)
diff --git a/libao2/audio_plugin.h b/libao2/audio_plugin.h
index 4ee8f1c145..4d31c19bf2 100644
--- a/libao2/audio_plugin.h
+++ b/libao2/audio_plugin.h
@@ -54,7 +54,7 @@ extern ao_plugin_cfg_t ao_plugin_cfg;
// This block should not be available in the pl_xxxx files
// due to compilation issues
#ifndef PLUGIN
-#define NPL 6+1 // Number of PLugins ( +1 list ends with NULL )
+#define NPL 7+1 // Number of PLugins ( +1 list ends with NULL )
// List of plugins
extern ao_plugin_functions_t audio_plugin_delay;
extern ao_plugin_functions_t audio_plugin_format;
@@ -62,6 +62,7 @@ extern ao_plugin_functions_t audio_plugin_surround;
extern ao_plugin_functions_t audio_plugin_resample;
extern ao_plugin_functions_t audio_plugin_volume;
extern ao_plugin_functions_t audio_plugin_extrastereo;
+extern ao_plugin_functions_t audio_plugin_volnorm;
#define AO_PLUGINS { \
@@ -71,6 +72,7 @@ extern ao_plugin_functions_t audio_plugin_extrastereo;
&audio_plugin_resample, \
&audio_plugin_volume, \
&audio_plugin_extrastereo, \
+ &audio_plugin_volnorm, \
NULL \
}
#endif /* PLUGIN */
diff --git a/libao2/pl_volnorm.c b/libao2/pl_volnorm.c
new file mode 100644
index 0000000000..6ae270cfa7
--- /dev/null
+++ b/libao2/pl_volnorm.c
@@ -0,0 +1,171 @@
+/* Normalizer plugin
+ *
+ * Limitations:
+ * - only AFMT_S16_LE supported
+ * - no parameters yet => tweak the values by editing the #defines
+ *
+ * License: GPLv2
+ * Author: pl <p_l@gmx.fr> (c) 2002 and beyond...
+ *
+ * Sources: some ideas from volnorm for xmms
+ *
+ * */
+
+#define PLUGIN
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <math.h> // for sqrt()
+
+#include "audio_out.h"
+#include "audio_plugin.h"
+#include "audio_plugin_internal.h"
+#include "afmt.h"
+
+static ao_info_t info = {
+ "Volume normalizer",
+ "volnorm",
+ "pl <p_l@gmx.fr>",
+ ""
+};
+
+LIBAO_PLUGIN_EXTERN(volnorm)
+
+// 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 15.0
+static float mul;
+
+// "history" value of the filter
+static float lastavg;
+
+// SMOOTH_* must be in ]0.0, 1.0[
+// The new value accounts for SMOOTH_MUL in the value and history
+#define SMOOTH_MUL 0.06
+#define SMOOTH_LASTAVG 0.06
+
+// ideal average level
+#define MID_S16 (INT16_MAX * 0.25)
+
+// silence level
+#define SIL_S16 (INT16_MAX * 0.02)
+
+// local data
+static struct {
+ int inuse; // This plugin is in use TRUE, FALSE
+ int format; // sample fomat
+} pl_volnorm = {0, 0};
+
+
+// minimal interface
+static int control(int cmd,int arg){
+ switch(cmd){
+ case AOCONTROL_PLUGIN_SET_LEN:
+ return CONTROL_OK;
+ }
+ return CONTROL_UNKNOWN;
+}
+
+// minimal interface
+// open & setup audio device
+// return: 1=success 0=fail
+static int init(){
+ switch(ao_plugin_data.format){
+ case(AFMT_S16_LE):
+ break;
+ default:
+ fprintf(stderr,"[pl_volnorm] Audio format not yet supported.\n");
+ return 0;
+ }
+
+ pl_volnorm.format = ao_plugin_data.format;
+ pl_volnorm.inuse = 1;
+
+ reset();
+
+ printf("[pl_volnorm] Normalizer plugin in use.\n");
+ return 1;
+}
+
+// close plugin
+static void uninit(){
+ pl_volnorm.inuse=0;
+}
+
+// empty buffers
+static void reset(){
+ mul = MUL_INIT;
+ switch(ao_plugin_data.format) {
+ case(AFMT_S16_LE):
+ lastavg = MID_S16;
+ break;
+ default:
+ fprintf(stderr,"[pl_volnorm] internal inconsistency - please bugreport.\n");
+ *(char *) 0 = 0;
+ }
+}
+
+// processes 'ao_plugin_data.len' bytes of 'data'
+// called for every block of data
+static int play(){
+
+ switch(pl_volnorm.format){
+ case(AFMT_S16_LE): {
+
+#define CLAMP(x,m,M) do { if ((x)<(m)) (x) = (m); else if ((x)>(M)) (x) = (M); } while(0)
+
+ int16_t* data=(int16_t*)ao_plugin_data.data;
+ int len=ao_plugin_data.len / 2; // 16 bits samples
+
+ int32_t i;
+ register int32_t tmp;
+ register float curavg;
+ float newavg;
+ float neededmul;
+
+ // average of the current samples
+ curavg = 0.0;
+ for (i = 0; i < len ; ++i) {
+ tmp = data[i];
+ curavg += tmp * tmp;
+ }
+ curavg = sqrt(curavg / (float) len);
+
+ if (curavg > SIL_S16) {
+ neededmul = MID_S16 / ( curavg * mul);
+ mul = (1.0 - SMOOTH_MUL) * mul + SMOOTH_MUL * neededmul;
+
+ // Clamp the mul coefficient
+ CLAMP(mul, MUL_MIN, MUL_MAX);
+ }
+
+ // Scale & clamp the samples
+ for (i=0; i < len ; ++i) {
+ tmp = data[i] * mul;
+ CLAMP(tmp, INT16_MIN, INT16_MAX);
+ data[i] = tmp;
+ }
+
+ // Evaluation of newavg (not 100% accurate because of values clamping)
+ newavg = mul * curavg;
+
+#if 0
+ printf("time = %d len = %d curavg = %6.0f lastavg = %6.0f newavg = %6.0f\n"
+ " 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;
+
+ break;
+ }
+ default:
+ return 0;
+ }
+ return 1;
+
+}
+