diff options
author | anders <anders@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2002-12-28 13:59:53 +0000 |
---|---|---|
committer | anders <anders@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2002-12-28 13:59:53 +0000 |
commit | 6adaa78ee935ef89439d4b38550165f13e880320 (patch) | |
tree | 6612adc09121e661363b1370cb43981007d36b60 | |
parent | 0e9c0e8aa2aa7df6aad5d78c4b664927a9d2421e (diff) | |
download | mpv-6adaa78ee935ef89439d4b38550165f13e880320.tar.bz2 mpv-6adaa78ee935ef89439d4b38550165f13e880320.tar.xz |
Changes includes:
- Improved runtime control system
- 3 New filter panning, compressor/limiter and a noise gate
- The compressor/limiter and the noise gate are not yet finished
- The panning filter does combined mixing and channel routing and
can be used to down-mix from stereo to mono (for example)
- Improvements to volume and channel
- volume now has a very good soft clipping using sin()
- channel can handle generic routing of audio data
- Conversion of all filters to handle floating point data
- Cleanup of message printing
- Fix for the sig 11 bug reported by Denes
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@8608 b3059339-0415-0410-9bf9-f77b7e298cf2
-rw-r--r-- | libaf/Makefile | 2 | ||||
-rw-r--r-- | libaf/af.c | 60 | ||||
-rw-r--r-- | libaf/af.h | 13 | ||||
-rw-r--r-- | libaf/af_channels.c | 168 | ||||
-rw-r--r-- | libaf/af_comp.c | 161 | ||||
-rw-r--r-- | libaf/af_delay.c | 13 | ||||
-rw-r--r-- | libaf/af_equalizer.c | 87 | ||||
-rw-r--r-- | libaf/af_format.c | 74 | ||||
-rw-r--r-- | libaf/af_gate.c | 157 | ||||
-rw-r--r-- | libaf/af_pan.c | 184 | ||||
-rw-r--r-- | libaf/af_resample.c | 277 | ||||
-rw-r--r-- | libaf/af_resample.h | 161 | ||||
-rw-r--r-- | libaf/af_tools.c | 79 | ||||
-rw-r--r-- | libaf/af_volume.c | 266 | ||||
-rw-r--r-- | libaf/control.h | 183 |
15 files changed, 1459 insertions, 426 deletions
diff --git a/libaf/Makefile b/libaf/Makefile index 05aac6d3cb..d66aa8b4ee 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 +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 OBJS=$(SRCS:.c=.o) diff --git a/libaf/af.c b/libaf/af.c index 5216c6dcdb..3f86ab9654 100644 --- a/libaf/af.c +++ b/libaf/af.c @@ -16,6 +16,9 @@ extern af_info_t af_info_format; extern af_info_t af_info_resample; extern af_info_t af_info_volume; extern af_info_t af_info_equalizer; +extern af_info_t af_info_gate; +extern af_info_t af_info_comp; +extern af_info_t af_info_pan; static af_info_t* filter_list[]={ \ &af_info_dummy,\ @@ -25,6 +28,9 @@ static af_info_t* filter_list[]={ \ &af_info_resample,\ &af_info_volume,\ &af_info_equalizer,\ + &af_info_gate,\ + &af_info_comp,\ + &af_info_pan,\ NULL \ }; @@ -72,7 +78,7 @@ af_instance_t* af_create(af_stream_t* s, char* name) // Allocate space for the new filter and reset all pointers af_instance_t* new=malloc(sizeof(af_instance_t)); if(!new){ - af_msg(AF_MSG_ERROR,"Could not allocate memory\n"); + af_msg(AF_MSG_ERROR,"[libaf] Could not allocate memory\n"); return NULL; } memset(new,0,sizeof(af_instance_t)); @@ -88,13 +94,14 @@ af_instance_t* af_create(af_stream_t* s, char* name) non-reentrant */ if(new->info->flags & AF_FLAGS_NOT_REENTRANT){ if(af_get(s,name)){ - af_msg(AF_MSG_ERROR,"There can only be one instance of the filter '%s' in each stream\n",name); + af_msg(AF_MSG_ERROR,"[libaf] There can only be one instance of" + " the filter '%s' in each stream\n",name); free(new); return NULL; } } - af_msg(AF_MSG_VERBOSE,"Adding filter %s \n",name); + af_msg(AF_MSG_VERBOSE,"[libaf] Adding filter %s \n",name); // Initialize the new filter if(AF_OK == new->info->open(new) && @@ -108,7 +115,8 @@ af_instance_t* af_create(af_stream_t* s, char* name) } free(new); - af_msg(AF_MSG_ERROR,"Couldn't create or open audio filter '%s'\n",name); + af_msg(AF_MSG_ERROR,"[libaf] Couldn't create or open audio filter '%s'\n", + name); return NULL; } @@ -165,6 +173,9 @@ void af_remove(af_stream_t* s, af_instance_t* af) { if(!af) return; + // Print friendly message + af_msg(AF_MSG_VERBOSE,"[libaf] Removing filter %s \n",af->info->name); + // Notify filter before changing anything af->control(af,AF_CONTROL_PRE_DESTROY,0); @@ -234,8 +245,9 @@ int af_reinit(af_stream_t* s, af_instance_t* af) // Create format filter if(NULL == (new = af_prepend(s,af,"format"))) return AF_ERROR; - // Set output format - if(AF_OK != (rv = new->control(new,AF_CONTROL_FORMAT,&in))) + // Set output bits per sample + if(AF_OK != (rv = new->control(new,AF_CONTROL_FORMAT_BPS,&in.bps)) || + AF_OK != (rv = new->control(new,AF_CONTROL_FORMAT_FMT,&in.format))) return rv; // Initialize format filter if(!new->prev) @@ -245,8 +257,11 @@ int af_reinit(af_stream_t* s, af_instance_t* af) if(AF_OK != (rv = new->control(new,AF_CONTROL_REINIT,&in))) return rv; } - if(!new) // Should _never_ happen + if(!new){ // Should _never_ happen + af_msg(AF_MSG_ERROR,"[libaf] Unable to correct audio format. " + "This error should never uccur, please send bugreport.\n"); return AF_ERROR; + } af=new; } break; @@ -264,10 +279,17 @@ int af_reinit(af_stream_t* s, af_instance_t* af) break; } default: - af_msg(AF_MSG_ERROR,"Reinitialization did not work, audio filter '%s' returned error code %i\n",af->info->name,rv); + af_msg(AF_MSG_ERROR,"[libaf] Reinitialization did not work, audio" + " filter '%s' returned error code %i\n",af->info->name,rv); return AF_ERROR; } - af=af->next; + // Check if there are any filters left in the list + if(NULL == af){ + if(!af_append(s,s->first,"dummy")) + return -1; + } + else + af=af->next; }while(af); return AF_OK; } @@ -315,7 +337,7 @@ int af_init(af_stream_t* s) } } } - + // Init filters if(AF_OK != af_reinit(s,s->first)) return -1; @@ -340,7 +362,8 @@ int af_init(af_stream_t* s) } } // Init the new filter - if(!af || (AF_OK != af->control(af,AF_CONTROL_RESAMPLE,&(s->output.rate)))) + if(!af || (AF_OK != af->control(af,AF_CONTROL_RESAMPLE_RATE, + &(s->output.rate)))) return -1; if(AF_OK != af_reinit(s,af)) return -1; @@ -368,7 +391,8 @@ int af_init(af_stream_t* s) else af = s->last; // Init the new filter - if(!af ||(AF_OK != af->control(af,AF_CONTROL_FORMAT,&(s->output)))) + if(!af ||(AF_OK != af->control(af,AF_CONTROL_FORMAT_BPS,&(s->output.bps))) + || (AF_OK != af->control(af,AF_CONTROL_FORMAT_FMT,&(s->output.format)))) return -1; if(AF_OK != af_reinit(s,af)) return -1; @@ -383,7 +407,8 @@ int af_init(af_stream_t* s) (s->last->data->nch != s->output.nch) || (s->last->data->rate != s->output.rate)) { // Something is stuffed audio out will not work - af_msg(AF_MSG_ERROR,"Unable to setup filter system can not meet sound-card demands, please report this error on MPlayer development mailing list. \n"); + af_msg(AF_MSG_ERROR,"[libaf] Unable to setup filter system can not" + " meet sound-card demands, please send bugreport. \n"); af_uninit(s); return -1; } @@ -493,6 +518,10 @@ int af_calc_insize_constrained(af_stream_t* s, int len, mul.d *= af->mul.d; af=af->next; }while(af); + // Sanity check + if(!mul.n || !mul.d) + return -1; + in = t * (((len/t) * mul.d - 1)/mul.n); if(in>max_insize) in=t*(max_insize/t); @@ -531,14 +560,15 @@ inline int af_resize_local_buffer(af_instance_t* af, af_data_t* data) { // Calculate new length register int len = af_lencalc(af->mul,data); - af_msg(AF_MSG_VERBOSE,"Reallocating memory in module %s, old len = %i, new len = %i\n",af->info->name,af->data->len,len); + af_msg(AF_MSG_VERBOSE,"[libaf] Reallocating memory in module %s, " + "old len = %i, new len = %i\n",af->info->name,af->data->len,len); // If there is a buffer free it if(af->data->audio) free(af->data->audio); // Create new buffer and check that it is OK af->data->audio = malloc(len); if(!af->data->audio){ - af_msg(AF_MSG_FATAL,"Could not allocate memory \n"); + af_msg(AF_MSG_FATAL,"[libaf] Could not allocate memory \n"); return AF_ERROR; } af->data->len=len; diff --git a/libaf/af.h b/libaf/af.h index dc542bb7e0..48dfbc5b17 100644 --- a/libaf/af.h +++ b/libaf/af.h @@ -180,6 +180,19 @@ int af_resize_local_buffer(af_instance_t* af, af_data_t* data); needed */ int af_lencalc(frac_t mul, af_data_t* data); +/* Helper function used to convert to gain value from dB. Returns + AF_OK if of and AF_ERROR if fail */ +int af_from_dB(int n, float* in, float* out, float k, float mi, float ma); +/* Helper function used to convert from gain value to dB. Returns + AF_OK if of and AF_ERROR if fail */ +int af_to_dB(int n, float* in, float* out, float k); +/* Helper function used to convert from ms to sample time*/ +int af_from_ms(int n, float* in, float* out, int rate, float mi, float ma); +/* Helper function used to convert from sample time to ms */ +int af_to_ms(int n, float* in, float* out, int rate); +/* Helper function for testing the output format */ +int af_test_output(struct af_instance_s* af, af_data_t* out); + /* Memory reallocation macro: if a local buffer is used (i.e. if the filter doesn't operate on the incoming buffer this macro must be called to ensure the buffer is big enough. */ diff --git a/libaf/af_channels.c b/libaf/af_channels.c index f6cdba172c..e5f54ceb54 100644 --- a/libaf/af_channels.c +++ b/libaf/af_channels.c @@ -10,6 +10,15 @@ #include "af.h" +#define FR 0 +#define TO 1 + +typedef struct af_channels_s{ + int route[AF_NCH][2]; + int nr; + int router; +}af_channels_t; + // Local function for copying data void copy(void* in, void* out, int ins, int inos,int outs, int outos, int len, int bps) { @@ -67,41 +76,140 @@ void copy(void* in, void* out, int ins, int inos,int outs, int outos, int len, i break; } default: - af_msg(AF_MSG_ERROR,"[channels] Unsupported number of bytes/sample: %i please report this error on the MPlayer mailing list. \n",bps); + af_msg(AF_MSG_ERROR,"[channels] Unsupported number of bytes/sample: %i" + " please report this error on the MPlayer mailing list. \n",bps); + } +} + +// Make sure the routes are sane +static int check_routes(af_channels_t* s, int nin, int nout) +{ + int i; + if((s->nr < 1) || (s->nr > AF_NCH)){ + af_msg(AF_MSG_ERROR,"[channels] The number of routing pairs musst be" + " between 1 and %i. Current value is %i\n",AF_NCH,s->nr); + return AF_ERROR; + } + + for(i=0;i<s->nr;i++){ + if((s->route[i][FR] >= nin) || (s->route[i][TO] >= nout)){ + af_msg(AF_MSG_ERROR,"[channels] Invalid routing in pair nr. %i.\n", i); + return AF_ERROR; + } } + return AF_OK; } // Initialization and runtime control static int control(struct af_instance_s* af, int cmd, void* arg) { + af_channels_t* s = af->setup; switch(cmd){ case AF_CONTROL_REINIT: - // Make sure this filter isn't redundant - if(af->data->nch == ((af_data_t*)arg)->nch) - return AF_DETACH; + + // Set default channel assignment + if(!s->router){ + int i; + // Make sure this filter isn't redundant + if(af->data->nch == ((af_data_t*)arg)->nch) + return AF_DETACH; + + // If mono: fake stereo + if(((af_data_t*)arg)->nch == 1){ + s->nr = min(af->data->nch,2); + for(i=0;i<s->nr;i++){ + s->route[i][FR] = 0; + s->route[i][TO] = i; + } + } + else{ + s->nr = min(af->data->nch, ((af_data_t*)arg)->nch); + for(i=0;i<s->nr;i++){ + s->route[i][FR] = i; + s->route[i][TO] = i; + } + } + } af->data->rate = ((af_data_t*)arg)->rate; af->data->format = ((af_data_t*)arg)->format; af->data->bps = ((af_data_t*)arg)->bps; af->mul.n = af->data->nch; af->mul.d = ((af_data_t*)arg)->nch; - return AF_OK; + return check_routes(s,((af_data_t*)arg)->nch,af->data->nch); case AF_CONTROL_COMMAND_LINE:{ int nch = 0; - sscanf((char*)arg,"%i",&nch); - return af->control(af,AF_CONTROL_CHANNELS,&nch); - } - case AF_CONTROL_CHANNELS: + int n = 0; + // Check number of channels and number of routing pairs + sscanf(arg, "%i:%i%n", &nch, &s->nr, &n); + + // If router scan commandline for routing pairs + if(s->nr){ + char* cp = &((char*)arg)[n]; + int ch = 0; + // Sanity check + if((s->nr < 1) || (s->nr > AF_NCH)){ + af_msg(AF_MSG_ERROR,"[channels] The number of routing pairs musst be" + " between 1 and %i. Current value is %i\n",AF_NCH,s->nr); + } + s->router = 1; + // Scan for pairs on commandline + while((*cp == ':') && (ch < s->nr)){ + sscanf(cp, ":%i:%i%n" ,&s->route[ch][FR], &s->route[ch][TO], &n); + af_msg(AF_MSG_DEBUG0,"[channels] Routing from channel %i to" + " channel %i\n",s->route[ch][FR],s->route[ch][TO]); + cp = &cp[n]; + ch++; + } + } + + if(AF_OK != af->control(af,AF_CONTROL_CHANNELS | AF_CONTROL_SET ,&nch)) + return AF_ERROR; + return AF_OK; + } + case AF_CONTROL_CHANNELS | AF_CONTROL_SET: // Reinit must be called after this function has been called // Sanity check if(((int*)arg)[0] <= 0 || ((int*)arg)[0] > 6){ - af_msg(AF_MSG_ERROR,"[channels] The number of output channels must be between 1 and 6. Current value is%i \n",((int*)arg)[0]); + af_msg(AF_MSG_ERROR,"[channels] The number of output channels must be" + " between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]); return AF_ERROR; } af->data->nch=((int*)arg)[0]; - af_msg(AF_MSG_VERBOSE,"[channels] Changing number of channels to %i\n",af->data->nch); + if(!s->router) + af_msg(AF_MSG_VERBOSE,"[channels] Changing number of channels" + " to %i\n",af->data->nch); + return AF_OK; + case AF_CONTROL_CHANNELS | AF_CONTROL_GET: + *(int*)arg = af->data->nch; + return AF_OK; + case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_SET:{ + int ch = ((af_control_ext_t*)arg)->ch; + int* route = ((af_control_ext_t*)arg)->arg; + s->route[ch][FR] = route[FR]; + s->route[ch][TO] = route[TO]; + return AF_OK; + } + case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_GET:{ + int ch = ((af_control_ext_t*)arg)->ch; + int* route = ((af_control_ext_t*)arg)->arg; + route[FR] = s->route[ch][FR]; + route[TO] = s->route[ch][TO]; + return AF_OK; + } + case AF_CONTROL_CHANNELS_NR | AF_CONTROL_SET: + s->nr = *(int*)arg; + return AF_OK; + case AF_CONTROL_CHANNELS_NR | AF_CONTROL_GET: + *(int*)arg = s->nr; + return AF_OK; + case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_SET: + s->router = *(int*)arg; + return AF_OK; + case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_GET: + *(int*)arg = s->router; return AF_OK; } return AF_UNKNOWN; @@ -110,6 +218,8 @@ static int control(struct af_instance_s* af, int cmd, void* arg) // Deallocate memory static void uninit(struct af_instance_s* af) { + if(af->setup) + free(af->setup); if(af->data) free(af->data); } @@ -117,32 +227,21 @@ static void uninit(struct af_instance_s* af) // 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_data_t* l = af->data; // Local data - + af_data_t* c = data; // Current working data + af_data_t* l = af->data; // Local data + af_channels_t* s = af->setup; + int i; + if(AF_OK != RESIZE_LOCAL_BUFFER(af,data)) return NULL; - // Reset unused channels if nch in < nch out - if(af->mul.n > af->mul.d) - memset(l->audio,0,(c->len*af->mul.n)/af->mul.d); + // Reset unused channels + memset(l->audio,0,(c->len*af->mul.n)/af->mul.d); - // Special case always output L & R - if(c->nch == 1){ - copy(c->audio,l->audio,1,0,l->nch,0,c->len,c->bps); - copy(c->audio,l->audio,1,0,l->nch,1,c->len,c->bps); - } - else{ - int i; - if(l->nch < c->nch){ - for(i=0;i<l->nch;i++) // Truncates R if l->nch == 1 not good need mixing - copy(c->audio,l->audio,c->nch,i,l->nch,i,c->len,c->bps); - } - else{ - for(i=0;i<c->nch;i++) - copy(c->audio,l->audio,c->nch,i,l->nch,i,c->len,c->bps); - } - } + if(AF_OK == check_routes(s,c->nch,l->nch)) + for(i=0;i<s->nr;i++) + copy(c->audio,l->audio,c->nch,s->route[i][FR], + l->nch,s->route[i][TO],c->len,c->bps); // Set output data c->audio = l->audio; @@ -160,7 +259,8 @@ static int open(af_instance_t* af){ af->mul.n=1; af->mul.d=1; af->data=calloc(1,sizeof(af_data_t)); - if(af->data == NULL) + af->setup=calloc(1,sizeof(af_channels_t)); + if((af->data == NULL) || (af->setup == NULL)) return AF_ERROR; return AF_OK; } diff --git a/libaf/af_comp.c b/libaf/af_comp.c new file mode 100644 index 0000000000..0282ff2f89 --- /dev/null +++ b/libaf/af_comp.c @@ -0,0 +1,161 @@ +/*============================================================================= +// +// This software has been released under the terms of the GNU Public +// license. See http://www.gnu.org/copyleft/gpl.html for details. +// +// Copyright 2002 Anders Johansson ajh@atri.curtin.edu.au +// +//============================================================================= +*/ + +#include <stdio.h> +#include <stdlib.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_comp_s +{ + int enable[AF_NCH]; // Enable/disable / channel + float time[AF_NCH]; // Forgetting factor for power estimate + float pow[AF_NCH]; // Estimated power level [dB] + float tresh[AF_NCH]; // Threshold [dB] + float attack[AF_NCH]; // Attack time [ms] + float release[AF_NCH]; // Release time [ms] + float ratio[AF_NCH]; // Compression ratio +}af_comp_t; + +// Initialization and runtime control +static int control(struct af_instance_s* af, int cmd, void* arg) +{ + af_comp_t* s = (af_comp_t*)af->setup; + int i; + + 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 = AF_FORMAT_F | AF_FORMAT_NE; + af->data->bps = 4; + + // Time constant set to 0.1s + // s->alpha = (1.0/0.2)/(2.0*M_PI*(float)((af_data_t*)arg)->rate); + return af_test_output(af,(af_data_t*)arg); + case AF_CONTROL_COMMAND_LINE:{ +/* float v=-10.0; */ +/* float vol[AF_NCH]; */ +/* float s=0.0; */ +/* float clipp[AF_NCH]; */ +/* int i; */ +/* sscanf((char*)arg,"%f:%f", &v, &s); */ +/* for(i=0;i<AF_NCH;i++){ */ +/* vol[i]=v; */ +/* clipp[i]=s; */ +/* } */ +/* if(AF_OK != control(af,AF_CONTROL_VOLUME_SOFTCLIP | AF_CONTROL_SET, clipp)) */ +/* return AF_ERROR; */ +/* return control(af,AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, vol); */ + } + case AF_CONTROL_COMP_ON_OFF | AF_CONTROL_SET: + memcpy(s->enable,(int*)arg,AF_NCH*sizeof(int)); + return AF_OK; + case AF_CONTROL_COMP_ON_OFF | AF_CONTROL_GET: + memcpy((int*)arg,s->enable,AF_NCH*sizeof(int)); + return AF_OK; + case AF_CONTROL_COMP_THRESH | AF_CONTROL_SET: + return af_from_dB(AF_NCH,(float*)arg,s->tresh,20.0,-60.0,-1.0); + case AF_CONTROL_COMP_THRESH | AF_CONTROL_GET: + return af_to_dB(AF_NCH,s->tresh,(float*)arg,10.0); + case AF_CONTROL_COMP_ATTACK | AF_CONTROL_SET: + return af_from_ms(AF_NCH,(float*)arg,s->attack,af->data->rate,500.0,0.1); + case AF_CONTROL_COMP_ATTACK | AF_CONTROL_GET: + return af_to_ms(AF_NCH,s->attack,(float*)arg,af->data->rate); + case AF_CONTROL_COMP_RELEASE | AF_CONTROL_SET: + return af_from_ms(AF_NCH,(float*)arg,s->release,af->data->rate,3000.0,10.0); + case AF_CONTROL_COMP_RELEASE | AF_CONTROL_GET: + return af_to_ms(AF_NCH,s->release,(float*)arg,af->data->rate); + case AF_CONTROL_COMP_RATIO | AF_CONTROL_SET: + for(i=0;i<AF_NCH;i++) + s->ratio[i] = clamp(((float*)arg)[i],1.0,10.0); + return AF_OK; + case AF_CONTROL_COMP_RATIO | AF_CONTROL_GET: + for(i=0;i<AF_NCH;i++) + ((float*)arg)[i] = s->ratio[i]; + 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_comp_t* s = (af_comp_t*)af->setup; // Setup for this instance + float* a = (float*)c->audio; // Audio data + int len = c->len/4; // Number of samples + int ch = 0; // Channel counter + register int nch = c->nch; // Number of channels + register int i = 0; + + // Compress/expand + for(ch = 0; ch < nch ; ch++){ + if(s->enable[ch]){ + float t = 1.0 - s->time[ch]; + for(i=ch;i<len;i+=nch){ + register float x = a[i]; + register float pow = x*x; + s->pow[ch] = t*s->pow[ch] + + pow*s->time[ch]; // LP filter + if(pow < s->pow[ch]){ + ; + } + else{ + ; + } + a[i] = x; + } + } + } + return c; +} + +// 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_comp_t)); + if(af->data == NULL || af->setup == NULL) + return AF_ERROR; + return AF_OK; +} + +// Description of this filter +af_info_t af_info_comp = { + "Compressor/expander audio filter", + "comp", + "Anders", + "", + AF_FLAGS_NOT_REENTRANT, + open +}; diff --git a/libaf/af_delay.c b/libaf/af_delay.c index 6ee94c2427..2f35e73a6f 100644 --- a/libaf/af_delay.c +++ b/libaf/af_delay.c @@ -27,14 +27,15 @@ 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_DELAY_SET_LEN,&((af_delay_t*)af->setup)->tlen); + return af->control(af,AF_CONTROL_DELAY_LEN | AF_CONTROL_SET, + &((af_delay_t*)af->setup)->tlen); } case AF_CONTROL_COMMAND_LINE:{ float d = 0; sscanf((char*)arg,"%f",&d); - return af->control(af,AF_CONTROL_DELAY_SET_LEN,&d); + return af->control(af,AF_CONTROL_DELAY_LEN | AF_CONTROL_SET,&d); } - case AF_CONTROL_DELAY_SET_LEN:{ + case AF_CONTROL_DELAY_LEN | AF_CONTROL_SET:{ af_delay_t* s = (af_delay_t*)af->setup; void* bt = s->buf; // Old buffer int lt = s->len; // Old len @@ -50,8 +51,7 @@ static int control(struct af_instance_s* af, int cmd, void* arg) // Set new len and allocate new buffer s->tlen = *((float*)arg); af->delay = s->tlen * 1000.0; -// s->len = af->data->rate*af->data->bps*af->data->nch*(int)s->tlen; - s->len = ((int)(af->data->rate*s->tlen))*af->data->bps*af->data->nch; + s->len = af->data->rate*af->data->bps*af->data->nch*(int)s->tlen; s->buf = malloc(s->len); af_msg(AF_MSG_DEBUG0,"[delay] Delaying audio output by %0.2fs\n",s->tlen); af_msg(AF_MSG_DEBUG1,"[delay] Delaying audio output by %i bytes\n",s->len); @@ -74,6 +74,9 @@ static int control(struct af_instance_s* af, int cmd, void* arg) } return AF_OK; } + case AF_CONTROL_DELAY_LEN | AF_CONTROL_GET: + *((float*)arg) = ((af_delay_t*)af->setup)->tlen; + return AF_OK; } return AF_UNKNOWN; } diff --git a/libaf/af_equalizer.c b/libaf/af_equalizer.c index d33e84d47f..256c7e7e5d 100644 --- a/libaf/af_equalizer.c +++ b/libaf/af_equalizer.c @@ -22,16 +22,27 @@ #include <math.h> #include "af.h" -#include "equalizer.h" -#define NCH AF_NCH // Number of channels #define L 2 // Storage for filter taps #define KM 10 // Max number of bands #define Q 1.2247449 /* Q value for band-pass filters 1.2247=(3/2)^(1/2) gives 4dB suppression @ Fc*2 and Fc/2 */ -// Center frequencies for band-pass filters +/* Center frequencies for band-pass filters + The different frequency bands are: + nr. center frequency + 0 31.25 Hz + 1 62.50 Hz + 2 125.0 Hz + 3 250.0 Hz + 4 500.0 Hz + 5 1.000 kHz + 6 2.000 kHz + 7 4.000 kHz + 8 8.000 kHz + 9 16.00 kHz +*/ #define CF {31.25,62.5,125,250,500,1000,2000,4000,8000,16000} // Maximum and minimum gain for the bands @@ -41,12 +52,12 @@ // Data for specific instances of this filter typedef struct af_equalizer_s { - float a[KM][L]; // A weights - float b[KM][L]; // B weights - float wq[NCH][KM][L]; // Circular buffer for W data - float g[NCH][KM]; // Gain factor for each channel and band - int K; // Number of used eq bands - int channels; // Number of channels + float a[KM][L]; // A weights + float b[KM][L]; // B weights + float wq[AF_NCH][KM][L]; // Circular buffer for W data + float g[AF_NCH][KM]; // Gain factor for each channel and band + int K; // Number of used eq bands + int channels; // Number of channels } af_equalizer_t; // 2nd order Band-pass Filter design @@ -76,8 +87,8 @@ static int control(struct af_instance_s* af, int cmd, void* arg) af->data->rate = ((af_data_t*)arg)->rate; af->data->nch = ((af_data_t*)arg)->nch; - af->data->format = AF_FORMAT_NE | AF_FORMAT_SI; - af->data->bps = 2; + af->data->format = AF_FORMAT_NE | AF_FORMAT_F; + af->data->bps = 4; // Calculate number of active filters s->K=KM; @@ -85,7 +96,8 @@ static int control(struct af_instance_s* af, int cmd, void* arg) s->K--; if(s->K != KM) - af_msg(AF_MSG_INFO,"Limiting the number of filters to %i due to low sample rate.\n",s->K); + af_msg(AF_MSG_INFO,"[equalizer] Limiting the number of filters to" + " %i due to low sample rate.\n",s->K); // Generate filter taps for(k=0;k<s->K;k++) @@ -94,18 +106,14 @@ static int control(struct af_instance_s* af, int cmd, void* arg) // Calculate how much this plugin adds to the overall time delay af->delay += 2000.0/((float)af->data->rate); - // Only signed 16 bit little endian is supported - if(af->data->format != ((af_data_t*)arg)->format || - af->data->bps != ((af_data_t*)arg)->bps) - return AF_FALSE; - return AF_OK; + return af_test_output(af,arg); } case AF_CONTROL_COMMAND_LINE:{ float g[10]={0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0}; int i,j; sscanf((char*)arg,"%f:%f:%f:%f:%f:%f:%f:%f:%f:%f", &g[0], &g[1], &g[2], &g[3], &g[4], &g[5], &g[6], &g[7], &g[8] ,&g[9]); - for(i=0;i<NCH;i++){ + for(i=0;i<AF_NCH;i++){ for(j=0;j<KM;j++){ ((af_equalizer_t*)af->setup)->g[i][j] = pow(10.0,clamp(g[j],G_MIN,G_MAX)/20.0)-1.0; @@ -113,23 +121,28 @@ static int control(struct af_instance_s* af, int cmd, void* arg) } return AF_OK; } - case AF_CONTROL_EQUALIZER_SET_GAIN:{ - float gain = ((equalizer_t*)arg)->gain; - int ch = ((equalizer_t*)arg)->channel; - int band = ((equalizer_t*)arg)->band; - if(ch > NCH || ch < 0 || band > KM || band < 0) + case AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_SET:{ + float* gain = ((af_control_ext_t*)arg)->arg; + int ch = ((af_control_ext_t*)arg)->ch; + int k; + if(ch > AF_NCH || ch < 0) return AF_ERROR; - - s->g[ch][band] = pow(10.0,clamp(gain,G_MIN,G_MAX)/20.0)-1.0; + + for(k = 0 ; k<KM ; k++) + s->g[ch][k] = pow(10.0,clamp(gain[k],G_MIN,G_MAX)/20.0)-1.0; + return AF_OK; } - case AF_CONTROL_EQUALIZER_GET_GAIN:{ - int ch =((equalizer_t*)arg)->channel; - int band =((equalizer_t*)arg)->band; - if(ch > NCH || ch < 0 || band > KM || band < 0) + case AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_GET:{ + float* gain = ((af_control_ext_t*)arg)->arg; + int ch = ((af_control_ext_t*)arg)->ch; + int k; + if(ch > AF_NCH || ch < 0) return AF_ERROR; - - ((equalizer_t*)arg)->gain = log10(s->g[ch][band]+1.0) * 20.0; + + for(k = 0 ; k<KM ; k++) + gain[k] = log10(s->g[ch][k]+1.0) * 20.0; + return AF_OK; } } @@ -155,13 +168,13 @@ static af_data_t* play(struct af_instance_s* af, af_data_t* data) while(ci--){ float* g = s->g[ci]; // Gain factor - int16_t* in = ((int16_t*)c->audio)+ci; - int16_t* out = ((int16_t*)c->audio)+ci; - int16_t* end = in + c->len/2; // Block loop end + float* in = ((float*)c->audio)+ci; + float* out = ((float*)c->audio)+ci; + float* end = in + c->len/4; // Block loop end while(in < end){ - register uint32_t k = 0; // Frequency band index - register float yt = (float)(*in); // Current input sample + register uint32_t k = 0; // Frequency band index + register float yt = *in; // Current input sample in+=nch; // Run the filters @@ -177,7 +190,7 @@ static af_data_t* play(struct af_instance_s* af, af_data_t* data) wq[0] = w; } // Calculate output - *out=(int16_t)(yt/(4.0*10.0)); + *out=yt/(4.0*10.0); out+=nch; } } diff --git a/libaf/af_format.c b/libaf/af_format.c index 98dc63ad30..55d151abdf 100644 --- a/libaf/af_format.c +++ b/libaf/af_format.c @@ -126,26 +126,32 @@ static char* fmt2str(int format, char* str, size_t size) return str; } -// Helper function to check sanity for input arguments -int check_sanity(af_data_t* data) +// Helper functions to check sanity for input arguments + +// Sanity check for bytes per sample +int check_bps(int bps) { - char buf[256]; - // Sanity check for bytes per sample - if(data->bps != 4 && data->bps != 2 && data->bps != 1){ - af_msg(AF_MSG_ERROR,"[format] The number of bytes per sample must be 1, 2 or 4. Current value is %i \n",data->bps); + if(bps != 4 && bps != 2 && bps != 1){ + af_msg(AF_MSG_ERROR,"[format] The number of bytes per sample" + " must be 1, 2 or 4. Current value is %i \n",bps); return AF_ERROR; } + return AF_OK; +} - // Check for unsupported formats - switch(data->format & AF_FORMAT_SPECIAL_MASK){ +// Check for unsupported formats +int check_format(int format) +{ + char buf[256]; + switch(format & AF_FORMAT_SPECIAL_MASK){ case(AF_FORMAT_MPEG2): case(AF_FORMAT_AC3): af_msg(AF_MSG_ERROR,"[format] Sample format %s not yet supported \n", - fmt2str(data->format,buf,255)); + fmt2str(format,buf,255)); return AF_ERROR; } retu |