diff options
author | anders <anders@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2002-10-16 01:49:40 +0000 |
---|---|---|
committer | anders <anders@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2002-10-16 01:49:40 +0000 |
commit | 4d6e54d22d40d50f50d2095773f24b5c5913d9b9 (patch) | |
tree | dd9b825c6b794f80d96a946ce9264ecaed3c12c3 /libaf | |
parent | dd84f32ef0620de9570953c22791a0da7ff179ea (diff) |
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/Makefile | 4 | ||||
-rw-r--r-- | libaf/af.c | 21 | ||||
-rw-r--r-- | libaf/af.h | 60 | ||||
-rw-r--r-- | libaf/af_delay.c | 4 | ||||
-rw-r--r-- | libaf/af_volume.c | 222 | ||||
-rw-r--r-- | libaf/control.h | 77 |
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 */ |