summaryrefslogtreecommitdiffstats
path: root/libaf
diff options
context:
space:
mode:
authoranders <anders@b3059339-0415-0410-9bf9-f77b7e298cf2>2002-10-16 01:49:40 +0000
committeranders <anders@b3059339-0415-0410-9bf9-f77b7e298cf2>2002-10-16 01:49:40 +0000
commit4d6e54d22d40d50f50d2095773f24b5c5913d9b9 (patch)
treedd9b825c6b794f80d96a946ce9264ecaed3c12c3 /libaf
parentdd84f32ef0620de9570953c22791a0da7ff179ea (diff)
downloadmpv-4d6e54d22d40d50f50d2095773f24b5c5913d9b9.tar.bz2
mpv-4d6e54d22d40d50f50d2095773f24b5c5913d9b9.tar.xz
Adding volume control and moving control() call parameters to a seperate file
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@7746 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libaf')
-rw-r--r--libaf/Makefile4
-rw-r--r--libaf/af.c21
-rw-r--r--libaf/af.h60
-rw-r--r--libaf/af_delay.c4
-rw-r--r--libaf/af_volume.c222
-rw-r--r--libaf/control.h77
6 files changed, 333 insertions, 55 deletions
diff --git a/libaf/Makefile b/libaf/Makefile
index eec59367f8..acac0afada 100644
--- a/libaf/Makefile
+++ b/libaf/Makefile
@@ -2,7 +2,7 @@ include ../config.mak
LIBNAME = libaf.a
-SRCS=af.c af_dummy.c af_delay.c af_channels.c af_format.c af_resample.c window.c filter.c
+SRCS=af.c af_dummy.c af_delay.c af_channels.c af_format.c af_resample.c window.c filter.c af_volume.c
OBJS=$(SRCS:.c=.o)
@@ -15,7 +15,7 @@ CFLAGS = $(OPTFLAGS) -I. -Wall
$(LIBNAME): $(OBJS) Makefile
$(AR) r $(LIBNAME) $(OBJS)
-$(OBJS):af.h dsp.h filter.h window.h
+$(OBJS):af.h control.h dsp.h filter.h window.h
all: $(LIBNAME)
diff --git a/libaf/af.c b/libaf/af.c
index 14b06624cd..fae93452a1 100644
--- a/libaf/af.c
+++ b/libaf/af.c
@@ -80,9 +80,10 @@ af_instance_t* af_create(af_stream_t* s, char* name)
}
// Initialize the new filter
- if(AF_OK==new->info->open(new))
+ if(AF_OK == new->info->open(new) &&
+ AF_ERROR < new->control(new,AF_CONTROL_POST_CREATE,&s->cfg))
return new;
-
+
free(new);
mp_msg(MSGT_AFILTER,MSGL_ERR,"Couldn't create audio filter '%s'\n",name);
return NULL;
@@ -141,6 +142,9 @@ void af_remove(af_stream_t* s, af_instance_t* af)
{
if(!af) return;
+ // Notify filter before changing anything
+ af->control(af,AF_CONTROL_PRE_DESTROY,0);
+
// Detach pointers
if(af->prev)
af->prev->next=af->next;
@@ -255,7 +259,6 @@ void af_uninit(af_stream_t* s)
-1 if failure */
int af_init(af_stream_t* s)
{
- int cfg=SLOW; // configuration type
int i=0;
// Sanity check
@@ -266,13 +269,11 @@ int af_init(af_stream_t* s)
s->input.len = s->output.len = 0;
// Figure out how fast the machine is
- if(s->cfg.force)
- cfg=s->cfg.force;
- else{
+ if(AF_INIT_AUTO == (AF_INIT_TYPE_MASK & s->cfg.force)){
# if defined(HAVE_SSE) || defined(HAVE_3DNOWEX)
- cfg=FAST;
+ s->cfg.force = (s->cfg.force & ~AF_INIT_TYPE_MASK) | AF_INIT_FAST;
# else
- cfg=SLOW;
+ s->cfg.force = (s->cfg.force & ~AF_INIT_TYPE_MASK) | AF_INIT_SLOW;
# endif
}
@@ -296,12 +297,12 @@ int af_init(af_stream_t* s)
return -1;
// Check output format
- if(cfg!=FORCE){
+ if((AF_INIT_TYPE_MASK & s->cfg.force) != AF_INIT_FORCE){
af_instance_t* af = NULL; // New filter
// Check output frequency if not OK fix with resample
if(s->last->data->rate!=s->output.rate){
if(NULL==(af=af_get(s,"resample"))){
- if(cfg==SLOW){
+ if((AF_INIT_TYPE_MASK & s->cfg.force) == AF_INIT_SLOW){
if(!strcmp(s->first->info->name,"format"))
af = af_append(s,s->first,"resample");
else
diff --git a/libaf/af.h b/libaf/af.h
index 73c7eefe1c..7c37f39c75 100644
--- a/libaf/af.h
+++ b/libaf/af.h
@@ -1,3 +1,5 @@
+#include "control.h"
+
#ifndef __aop_h__
#define __aop_h__
@@ -53,10 +55,12 @@ typedef struct af_instance_s
the length of the buffer. */
}af_instance_t;
-// Initialization types
-#define SLOW 1
-#define FAST 2
-#define FORCE 3
+// Initialization flags
+#define AF_INIT_AUTO 0x00000000
+#define AF_INIT_SLOW 0x00000001
+#define AF_INIT_FAST 0x00000002
+#define AF_INIT_FORCE 0x00000003
+#define AF_INIT_TYPE_MASK 0x00000003
// Configuration switches
typedef struct af_cfg_s{
@@ -79,43 +83,6 @@ typedef struct af_stream_s
}af_stream_t;
/*********************************************
-// Control parameters
-*/
-
-/* The control system is divided into 3 levels
- mandatory calls - all filters must answer to all of these
- optional calls - are optional
- filter specific calls - applies only to some filters
-*/
-
-#define AF_CONTROL_MANDATORY_BASE 0
-#define AF_CONTROL_OPTIONAL_BASE 100
-#define AF_CONTROL_FILTER_SPECIFIC_BASE 200
-
-// MANDATORY CALLS
-
-/* Reinitialize filter. The optional argument contains the new
- configuration in form of a af_data_t struct. If the filter does not
- support the new format the struct should be changed and AF_FALSE
- should be returned. If the incoming and outgoing data streams are
- identical the filter can return AF_DETACH. This will remove the
- filter. */
-#define AF_CONTROL_REINIT 1 + AF_CONTROL_MANDATORY_BASE
-
-// OPTIONAL CALLS
-
-
-// FILTER SPECIFIC CALLS
-
-// Set output rate in resample
-#define AF_CONTROL_RESAMPLE 1 + AF_CONTROL_FILTER_SPECIFIC_BASE
-// Set output format in format
-#define AF_CONTROL_FORMAT 2 + AF_CONTROL_FILTER_SPECIFIC_BASE
-// Set number of output channels in channels
-#define AF_CONTROL_CHANNELS 3 + AF_CONTROL_FILTER_SPECIFIC_BASE
-// Set delay length in delay
-#define AF_CONTROL_SET_DELAY_LEN 4 + AF_CONTROL_FILTER_SPECIFIC_BASE
-/*********************************************
// Return values
*/
@@ -129,7 +96,9 @@ typedef struct af_stream_s
+/*********************************************
// Export functions
+*/
/* Initialize the stream "s". This function creates a new fileterlist
if nessesary according to the values set in input and output. Input
@@ -201,6 +170,7 @@ int af_lencalc(frac_t mul, af_data_t* data);
#define RESIZE_LOCAL_BUFFER(a,d)\
((a->data->len < af_lencalc(a->mul,d))?af_resize_local_buffer(a,d):AF_OK)
+/* Some other useful macro definitions*/
#ifndef min
#define min(a,b)(((a)>(b))?(b):(a))
#endif
@@ -209,4 +179,12 @@ int af_lencalc(frac_t mul, af_data_t* data);
#define max(a,b)(((a)>(b))?(a):(b))
#endif
+#ifndef clamp
+#define clamp(a,min,max) (((a)>(max))?(max):(((a)<(min))?(min):(a)))
+#endif
+
+#ifndef sign
+#define sign(a) (((x)>0)?(1):(-1))
+#endif
+
#endif
diff --git a/libaf/af_delay.c b/libaf/af_delay.c
index 9477f58aea..6eb3965a36 100644
--- a/libaf/af_delay.c
+++ b/libaf/af_delay.c
@@ -30,9 +30,9 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
af->data->format = ((af_data_t*)arg)->format;
af->data->bps = ((af_data_t*)arg)->bps;
- return af->control(af,AF_CONTROL_SET_DELAY_LEN,&((af_delay_t*)af->setup)->tlen);
+ return af->control(af,AF_CONTROL_DELAY_SET_LEN,&((af_delay_t*)af->setup)->tlen);
}
- case AF_CONTROL_SET_DELAY_LEN:{
+ case AF_CONTROL_DELAY_SET_LEN:{
af_delay_t* s = (af_delay_t*)af->setup;
void* bt = s->buf; // Old buffer
int lt = s->len; // Old len
diff --git a/libaf/af_volume.c b/libaf/af_volume.c
new file mode 100644
index 0000000000..7d0d2fd0f0
--- /dev/null
+++ b/libaf/af_volume.c
@@ -0,0 +1,222 @@
+/* This audio filter changes the volume of the sound, and can be used
+ when the mixer doesn't support the PCM channel. It can handel
+ between 1 and 6 channels. The volume can be adjusted between -60dB
+ to +10dB and is set on a per channels basis. The volume can be
+ written ad read by AF_CONTROL_VOLUME_SET and AF_CONTROL_VOLUME_GET
+ respectivly.
+
+ The plugin has support for softclipping, it is enabled by
+ AF_CONTROL_VOLUME_SOFTCLIPP. It has also a probing feature which
+ can be used to measure the power in the audio stream, both an
+ instantanious value and the maximum value can be probed. The
+ probing is enable by AF_CONTROL_VOLUME_PROBE_ON_OFF and is done on a
+ per channel basis. The result from the probing is obtained using
+ AF_CONTROL_VOLUME_PROBE_GET and AF_CONTROL_VOLUME_PROBE_GET_MAX. The
+ probed values are calculated in dB. The control of the volume can
+ be turned off by the AF_CONTROL_VOLUME_ON_OFF switch.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <unistd.h>
+#include <inttypes.h>
+#include <math.h>
+
+#include "../config.h"
+#include "../mp_msg.h"
+
+#include "af.h"
+
+// Some limits
+#define MIN_S16 -32650
+#define MAX_S16 32650
+
+#define MAX_VOL +10.0
+#define MIN_VOL -60.0
+
+// Number of channels
+#define NCH 6
+
+#include "../libao2/afmt.h"
+
+
+// Data for specific instances of this filter
+typedef struct af_volume_s
+{
+ double volume[NCH]; // Volume for each channel
+ double power[NCH]; // Instantaneous power in each channel
+ double maxpower[NCH]; // Maximum power in each channel
+ double alpha; // Forgetting factor for power estimate
+ int softclip; // Soft clippng on/off
+ int probe; // Probing on/off
+ int onoff; // Volume control on/off
+}af_volume_t;
+
+/* Convert to gain value from dB. Returns AF_OK if of and AF_ERROR if
+ fail */
+inline int from_dB(double* in, double* out)
+{
+ int i = 0;
+ // Sanity check
+ if(!in || !out)
+ return AF_ERROR;
+
+ for(i=0;i<NCH;i++)
+ out[i]=pow(10.0,clamp(in[i],MIN_VOL,MAX_VOL)/10.0);
+ return AF_OK;
+}
+
+/* Convert from gain value to dB. Returns AF_OK if of and AF_ERROR if
+ fail */
+inline int to_dB(double* in, double* out)
+{
+ int i = 0;
+ // Sanity check
+ if(!in || !out)
+ return AF_ERROR;
+
+ for(i=0;i<NCH;i++)
+ out[i]=10.0*log10(clamp(in[i],MIN_VOL,MAX_VOL));
+ return AF_OK;
+}
+
+// Initialization and runtime control
+static int control(struct af_instance_s* af, int cmd, void* arg)
+{
+ af_volume_t* s = (af_volume_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;
+ af->data->format = AFMT_S16_LE;
+ af->data->bps = 2;
+
+ // Time constant set to 0.1s
+ s->alpha = (1.0/0.2)/(2.0*M_PI*(double)((af_data_t*)arg)->rate);
+
+ // Only AFMT_S16_LE is supported for now
+ if(af->data->format != ((af_data_t*)arg)->format ||
+ af->data->bps != ((af_data_t*)arg)->bps)
+ return AF_FALSE;
+ return AF_OK;
+ case AF_CONTROL_VOLUME_SET:
+ return from_dB((double*)arg,s->volume);
+ case AF_CONTROL_VOLUME_GET:
+ return to_dB(s->volume,(double*)arg);
+ case AF_CONTROL_VOLUME_PROBE_GET:
+ return to_dB(s->power,(double*)arg);
+ case AF_CONTROL_VOLUME_PROBE_GET_MAX:
+ return to_dB(s->maxpower,(double*)arg);
+ case AF_CONTROL_VOLUME_SOFTCLIP:
+ s->softclip = (int)arg;
+ return AF_OK;
+ case AF_CONTROL_VOLUME_PROBE_ON_OFF:
+ s->probe = (int)arg;
+ return AF_OK;
+ case AF_CONTROL_VOLUME_ON_OFF:
+ s->onoff = (int)arg;
+ 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_data_t* c = data; // Current working data
+ af_volume_t* s = (af_volume_t*)af->setup; // Setup for this instance
+ int16_t* a = (int16_t*)c->audio; // Audio data
+ int len = c->len/2; // Number of samples
+ int ch = 0; // Channel counter
+ register int nch = c->nch; // Number of channels
+ register int i = 0;
+
+ // Probe the data stream
+ if(s->probe){
+ for(ch = 0; ch < nch ; ch++){
+ double alpha = s->alpha;
+ double beta = 1 - alpha;
+ double pow = s->power[ch];
+ double maxpow = s->maxpower[ch];
+ register double t = 0;
+ for(i=ch;i<len;i+=nch){
+ t = ((double)a[i])/32768.0;
+ t *= t;
+ // Check maximum power value
+ if(t>maxpow)
+ maxpow=t;
+ // Power estimate made using first order AR model
+ if(t>pow)
+ pow=t;
+ else
+ pow = beta*pow+alpha*t;
+ }
+ s->power[ch] = pow;
+ s->maxpower[ch] = maxpow;
+ }
+ }
+
+ // Change the volume.
+ if(s->onoff){
+ register int sc = s->softclip;
+ for(ch = 0; ch < nch ; ch++){
+ register int vol = (int)(255.0 * s->volume[ch]);
+ for(i=ch;i<len;i+=nch){
+ register int x;
+ x=(a[i] * vol) >> 8;
+ if(sc){
+ int64_t t=x*x;
+ t=(t*x) >> 30;
+ x = (3*x - (int)t) >> 1;
+ }
+ a[i]=clamp(x,MIN_S16,MAX_S16);
+ }
+ }
+ }
+
+ return c;
+}
+
+// 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_volume_t));
+ if(af->data == NULL || af->setup == NULL)
+ return AF_ERROR;
+ // Enable volume control and set initial volume to 0.1
+ ((af_volume_t*)af->setup)->onoff = 1;
+ for(i=0;i<NCH;i++)
+ ((af_volume_t*)af->setup)->volume[i]=0.1;
+
+ return AF_OK;
+}
+
+// Description of this filter
+af_info_t af_info_volume = {
+ "Volume control audio filter",
+ "volume",
+ "Anders",
+ "",
+ AF_FLAGS_NOT_REENTRANT,
+ open
+};
diff --git a/libaf/control.h b/libaf/control.h
new file mode 100644
index 0000000000..6c44a76efe
--- /dev/null
+++ b/libaf/control.h
@@ -0,0 +1,77 @@
+#ifndef __af_control_h
+#define __af_control_h
+
+/*********************************************
+// Control parameters
+*/
+
+/* The control system is divided into 3 levels
+ mandatory calls - all filters must answer to all of these
+ optional calls - are optional
+ filter specific calls - applies only to some filters
+*/
+
+#define AF_CONTROL_MANDATORY_BASE 0
+#define AF_CONTROL_OPTIONAL_BASE 100
+#define AF_CONTROL_FILTER_SPECIFIC_BASE 200
+
+// MANDATORY CALLS
+
+/* Reinitialize filter. The optional argument contains the new
+ configuration in form of a af_data_t struct. If the filter does not
+ support the new format the struct should be changed and AF_FALSE
+ should be returned. If the incoming and outgoing data streams are
+ identical the filter can return AF_DETACH. This will remove the
+ filter. */
+#define AF_CONTROL_REINIT 01 + AF_CONTROL_MANDATORY_BASE
+
+// OPTIONAL CALLS
+
+/* Called just after creation with the af_cfg for the stream in which
+ the filter resides as input parameter this call can be used by the
+ filter to initialize itself using commandline parameters */
+#define AF_CONTROL_POST_CREATE 1 + AF_CONTROL_OPTIONAL_BASE
+
+// Called just before destruction of a filter
+#define AF_CONTROL_PRE_DESTROY 2 + AF_CONTROL_OPTIONAL_BASE
+
+
+// FILTER SPECIFIC CALLS
+
+// Set output rate in resample
+#define AF_CONTROL_RESAMPLE 1 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+// Set output format in format
+#define AF_CONTROL_FORMAT 2 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+// Set number of output channels in channels
+#define AF_CONTROL_CHANNELS 3 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+// Set delay length in delay
+#define AF_CONTROL_DELAY_SET_LEN 4 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+// Volume
+
+// Set volume level, arg is a float* with the volume for all the channels
+#define AF_CONTROL_VOLUME_SET 5 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+/* Get volume level for all channels, arg is a float* that will
+ contain the volume for all the channels */
+#define AF_CONTROL_VOLUME_GET 6 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+// Turn volume control on and off, arg is binary
+#define AF_CONTROL_VOLUME_ON_OFF 7 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+// Turn soft clipping of the volume on and off, arg is binary
+#define AF_CONTROL_VOLUME_SOFTCLIP 8 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+// Get the probed power level for all channels, arg is a float*
+#define AF_CONTROL_VOLUME_PROBE_GET 9 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+// Get the maximum probed power level for all channels, arg is a float*
+#define AF_CONTROL_VOLUME_PROBE_GET_MAX 10 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+// Turn probing on and off, arg is binary
+#define AF_CONTROL_VOLUME_PROBE_ON_OFF 11 + AF_CONTROL_FILTER_SPECIFIC_BASE
+
+#endif /*__af_control_h */