Mercurial > mplayer.hg
changeset 8607:d6f40a06867b
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
author | anders |
---|---|
date | Sat, 28 Dec 2002 13:59:53 +0000 |
parents | d80edba39db9 |
children | 677d4443af55 |
files | libaf/Makefile libaf/af.c libaf/af.h libaf/af_channels.c libaf/af_comp.c libaf/af_delay.c libaf/af_equalizer.c libaf/af_format.c libaf/af_gate.c libaf/af_pan.c libaf/af_resample.c libaf/af_resample.h libaf/af_tools.c libaf/af_volume.c libaf/control.h |
diffstat | 15 files changed, 1467 insertions(+), 434 deletions(-) [+] |
line wrap: on
line diff
--- a/libaf/Makefile Sat Dec 28 13:53:31 2002 +0000 +++ b/libaf/Makefile Sat Dec 28 13:59:53 2002 +0000 @@ -2,7 +2,7 @@ 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)
--- a/libaf/af.c Sat Dec 28 13:53:31 2002 +0000 +++ b/libaf/af.c Sat Dec 28 13:59:53 2002 +0000 @@ -16,6 +16,9 @@ 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 @@ &af_info_resample,\ &af_info_volume,\ &af_info_equalizer,\ + &af_info_gate,\ + &af_info_comp,\ + &af_info_pan,\ NULL \ }; @@ -72,7 +78,7 @@ // 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 @@ 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 @@ } 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 @@ { 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 @@ // 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 @@ 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 @@ 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 @@ } } } - + // Init filters if(AF_OK != af_reinit(s,s->first)) return -1; @@ -340,7 +362,8 @@ } } // 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 @@ 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 @@ (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 @@ 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 @@ { // 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;
--- a/libaf/af.h Sat Dec 28 13:53:31 2002 +0000 +++ b/libaf/af.h Sat Dec 28 13:59:53 2002 +0000 @@ -180,6 +180,19 @@ 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. */
--- a/libaf/af_channels.c Sat Dec 28 13:53:31 2002 +0000 +++ b/libaf/af_channels.c Sat Dec 28 13:59:53 2002 +0000 @@ -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 @@ 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 @@ // 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 @@ // 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 @@ 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; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libaf/af_comp.c Sat Dec 28 13:59:53 2002 +0000 @@ -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 +};
--- a/libaf/af_delay.c Sat Dec 28 13:53:31 2002 +0000 +++ b/libaf/af_delay.c Sat Dec 28 13:59:53 2002 +0000 @@ -27,14 +27,15 @@ 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 @@ // 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 @@ } 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; }
--- a/libaf/af_equalizer.c Sat Dec 28 13:53:31 2002 +0000 +++ b/libaf/af_equalizer.c Sat Dec 28 13:59:53 2002 +0000 @@ -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 @@ 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 @@ 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 @@ // 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 @@ } 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 @@ 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 @@ wq[0] = w; } // Calculate output - *out=(int16_t)(yt/(4.0*10.0)); + *out=yt/(4.0*10.0); out+=nch; } }
--- a/libaf/af_format.c Sat Dec 28 13:53:31 2002 +0000 +++ b/libaf/af_format.c Sat Dec 28 13:59:53 2002 +0000 @@ -126,26 +126,32 @@ 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) +{ + 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 +int check_format(int format) { 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); - return AF_ERROR; - } - - // Check for unsupported formats - switch(data->format & AF_FORMAT_SPECIAL_MASK){ + 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; } return AF_OK; -} +} // Initialization and runtime control static int control(struct af_instance_s* af, int cmd, void* arg) @@ -158,10 +164,12 @@ if(af->data->format == ((af_data_t*)arg)->format && af->data->bps == ((af_data_t*)arg)->bps) return AF_DETACH; - + // Check for errors in configuraton - if(AF_OK != check_sanity((af_data_t*)arg) || - AF_OK != check_sanity(af->data)) + if((AF_OK != check_bps(((af_data_t*)arg)->bps)) || + (AF_OK != check_format(((af_data_t*)arg)->format)) || + (AF_OK != check_bps(af->data->bps)) || + (AF_OK != check_format(af->data->format))) return AF_ERROR; af_msg(AF_MSG_VERBOSE,"[format] Changing sample format from %ibit %sto %ibit %s \n", @@ -175,35 +183,47 @@ return AF_OK; } case AF_CONTROL_COMMAND_LINE:{ - af_data_t d={NULL,0,0,0,0,2}; + int bps = 2; + int format = AF_FORMAT_NE; char str[256]; str[0] = '\0'; - sscanf((char*)arg,"%i:%s",&(d.bps),str); + sscanf((char*)arg,"%i:%s",&bps,str); // Convert string to format - d.format = str2fmt(str); + format = str2fmt(str); // Automatic correction of errors - switch(d.format & AF_FORMAT_SPECIAL_MASK){ + switch(format & AF_FORMAT_SPECIAL_MASK){ case(AF_FORMAT_A_LAW): case(AF_FORMAT_MU_LAW): - d.bps=1; break; + bps=1; break; case(AF_FORMAT_AC3): - d.bps=4; break; // I think + bps=4; break; // I think } - if(AF_FORMAT_F == (d.format & AF_FORMAT_POINT_MASK)) - d.bps=4; - - return af->control(af,AF_CONTROL_FORMAT,&d); + if(AF_FORMAT_F == (format & AF_FORMAT_POINT_MASK)) + bps=4; + + if((AF_OK != af->control(af,AF_CONTROL_FORMAT_BPS | AF_CONTROL_SET,&bps)) || + (AF_OK != af->control(af,AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET,&format))) + return AF_ERROR; + return AF_OK; } - case AF_CONTROL_FORMAT: + case AF_CONTROL_FORMAT_BPS | AF_CONTROL_SET: // Reinit must be called after this function has been called // Check for errors in configuraton - if(AF_OK != check_sanity((af_data_t*)arg)) + if(AF_OK != check_bps(*(int*)arg)) return AF_ERROR; - af->data->format = ((af_data_t*)arg)->format; - af->data->bps=((af_data_t*)arg)->bps; + af->data->bps = *(int*)arg; + return AF_OK; + case AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET: + // Reinit must be called after this function has been called + + // Check for errors in configuraton + if(AF_OK != check_format(*(int*)arg)) + return AF_ERROR; + + af->data->format = *(int*)arg; return AF_OK; } return AF_UNKNOWN;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libaf/af_gate.c Sat Dec 28 13:59:53 2002 +0000 @@ -0,0 +1,157 @@ +/*============================================================================= +// +// 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_gate_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 range[AF_NCH]; // Range level [dB] +}af_gate_t; + +// Initialization and runtime control +static int control(struct af_instance_s* af, int cmd, void* arg) +{ + af_gate_t* s = (af_gate_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 = 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_GATE_ON_OFF | AF_CONTROL_SET: + memcpy(s->enable,(int*)arg,AF_NCH*sizeof(int)); + return AF_OK; + case AF_CONTROL_GATE_ON_OFF | AF_CONTROL_GET: + memcpy((int*)arg,s->enable,AF_NCH*sizeof(int)); + return AF_OK; + case AF_CONTROL_GATE_THRESH | AF_CONTROL_SET: + return af_from_dB(AF_NCH,(float*)arg,s->tresh,20.0,-60.0,-1.0); + case AF_CONTROL_GATE_THRESH | AF_CONTROL_GET: + return af_to_dB(AF_NCH,s->tresh,(float*)arg,10.0); + case AF_CONTROL_GATE_ATTACK | AF_CONTROL_SET: + return af_from_ms(AF_NCH,(float*)arg,s->attack,af->data->rate,500.0,0.1); + case AF_CONTROL_GATE_ATTACK | AF_CONTROL_GET: + return af_to_ms(AF_NCH,s->attack,(float*)arg,af->data->rate); + case AF_CONTROL_GATE_RELEASE | AF_CONTROL_SET: + return af_from_ms(AF_NCH,(float*)arg,s->release,af->data->rate,3000.0,10.0); + case AF_CONTROL_GATE_RELEASE | AF_CONTROL_GET: + return af_to_ms(AF_NCH,s->release,(float*)arg,af->data->rate); + case AF_CONTROL_GATE_RANGE | AF_CONTROL_SET: + return af_from_dB(AF_NCH,(float*)arg,s->range,20.0,100.0,0.0); + case AF_CONTROL_GATE_RANGE | AF_CONTROL_GET: + return af_to_dB(AF_NCH,s->range,(float*)arg,10.0); + } + 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_gate_t* s = (af_gate_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; + + + // Noise gate + 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_gate_t)); + if(af->data == NULL || af->setup == NULL) + return AF_ERROR; + return AF_OK; +} + +// Description of this filter +af_info_t af_info_gate = { + "Noise gate audio filter", + "gate", + "Anders", + "", + AF_FLAGS_NOT_REENTRANT, + open +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libaf/af_pan.c Sat Dec 28 13:59:53 2002 +0000 @@ -0,0 +1,184 @@ +/*============================================================================= +// +// 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_pan_s +{ + float level[AF_NCH][AF_NCH]; // Gain level for each channel +}af_pan_t; + +// Initialization and runtime control +static int control(struct af_instance_s* af, int cmd, void* arg) +{ + af_pan_t* s = 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->format = AF_FORMAT_F | AF_FORMAT_NE; + af->data->bps = 4; + af->mul.n = af->data->nch; + af->mul.d = ((af_data_t*)arg)->nch; + + if((af->data->format != ((af_data_t*)arg)->format) || + (af->data->bps != ((af_data_t*)arg)->bps)){ + ((af_data_t*)arg)->format = af->data->format; + ((af_data_t*)arg)->bps = af->data->bps; + return AF_FALSE; + } + return control(af,AF_CONTROL_PAN_NOUT | AF_CONTROL_SET, &af->data->nch); + case AF_CONTROL_COMMAND_LINE:{ + int nch = 0; + int n = 0; + char* cp = NULL; + int j,k; + // Read number of outputs + sscanf((char*)arg,"%i%n", &nch,&n); + if(AF_OK != control(af,AF_CONTROL_PAN_NOUT | AF_CONTROL_SET, &nch)) + return AF_ERROR; + + // Read pan values + cp = &((char*)arg)[n]; + j = 0; k = 0; + while((*cp == ':') && (k < AF_NCH)){ + sscanf(cp, ":%f%n" , &s->level[k][j], &n); + s->level[k][j] = clamp(s->level[k][j],0.0,1.0); + af_msg(AF_MSG_VERBOSE,"[pan] Pan level from channel %i to" + " channel %i = %f\n",j,k,s->level[k][j]); + cp =&cp[n]; + j++; + if(j>=nch){ + j = 0; + k++; + } + } + return AF_OK; + } + case AF_CONTROL_PAN_LEVEL | AF_CONTROL_SET:{ + int i; + int ch = ((af_control_ext_t*)arg)->ch; + float* level = ((af_control_ext_t*)arg)->arg; + for(i=0;i<AF_NCH;i++) + s->level[ch][i] = clamp(level[i],0.0,1.0); + return AF_OK; + } + case AF_CONTROL_PAN_LEVEL | AF_CONTROL_GET:{ + int i; + int ch = ((af_control_ext_t*)arg)->ch; + float* level = ((af_control_ext_t*)arg)->arg; + for(i=0;i<AF_NCH;i++) + level[i] = s->level[ch][i]; + return AF_OK; + } + case AF_CONTROL_PAN_NOUT | 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,"[pan] 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]; + return AF_OK; + case AF_CONTROL_PAN_NOUT | AF_CONTROL_GET: + *(int*)arg = af->data->nch; + 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_data_t* l = af->data; // Local data + af_pan_t* s = af->setup; // Setup for this instance + float* in = c->audio; // Input audio data + float* out = NULL; // Output audio data + float* end = in+c->len/4; // End of loop + int nchi = c->nch; // Number of input channels + int ncho = l->nch; // Number of output channels + register int j,k; + + if(AF_OK != RESIZE_LOCAL_BUFFER(af,data)) + return NULL; + + out = l->audio; + // Execute panning + // FIXME: Too slow + while(in < end){ + for(j=0;j<ncho;j++){ + register float x = 0.0; + register float* tin = in; + for(k=0;k<nchi;k++) + x += tin[k] * s->level[j][k]; + out[j] = x; + } + out+= ncho; + in+= nchi; + } + + // Set output data + c->audio = l->audio; + c->len = (c->len*af->mul.n)/af->mul.d; + c->nch = l->nch; + + 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_pan_t)); + if(af->data == NULL || af->setup == NULL) + return AF_ERROR; + // Set initial pan to pass-through. + return AF_OK; +} + +// Description of this filter +af_info_t af_info_pan = { + "Panning audio filter", + "pan", + "Anders", + "", + AF_FLAGS_NOT_REENTRANT, + open +};
--- a/libaf/af_resample.c Sat Dec 28 13:53:31 2002 +0000 +++ b/libaf/af_resample.c Sat Dec 28 13:59:53 2002 +0000 @@ -25,45 +25,36 @@ slow and to 16 if the machine is fast and has MMX. */ -#if !defined(HAVE_SSE) && !defined(HAVE_3DNOW) // This machine is slow +#if !defined(HAVE_MMX) // This machine is slow +#define L8 +#else +#define L16 +#endif -#define L 8 // Filter length -// Unrolled loop to speed up execution -#define FIR(x,w,y) \ - (y[0]) = ( w[0]*x[0]+w[1]*x[1]+w[2]*x[2]+w[3]*x[3] \ - + w[4]*x[4]+w[5]*x[5]+w[6]*x[6]+w[7]*x[7] ) >> 16 - -#else /* Fast machine */ +#include "af_resample.h" -#define L 16 -// Unrolled loop to speed up execution -#define FIR(x,w,y) \ - y[0] = ( w[0] *x[0] +w[1] *x[1] +w[2] *x[2] +w[3] *x[3] \ - + w[4] *x[4] +w[5] *x[5] +w[6] *x[6] +w[7] *x[7] \ - + w[8] *x[8] +w[9] *x[9] +w[10]*x[10]+w[11]*x[11] \ - + w[12]*x[12]+w[13]*x[13]+w[14]*x[14]+w[15]*x[15] ) >> 16 +// Filtering types +#define TYPE_LIN 0 // Linear interpolation +#define TYPE_INT 1 // 16 bit integer +#define TYPE_FLOAT 2 // 32 bit floating point -#endif /* Fast machine */ - -// Macro to add data to circular que -#define ADDQUE(xi,xq,in)\ - xq[xi]=xq[xi+L]=(*in);\ - xi=(xi-1)&(L-1); - - +// Accuracy for linear interpolation +#define STEPACCURACY 32 // local data typedef struct af_resample_s { - int16_t* w; // Current filter weights - int16_t** xq; // Circular buffers + void* w; // Current filter weights + void** xq; // Circular buffers uint32_t xi; // Index for circular buffers uint32_t wi; // Index for w - uint32_t i; // Number of new samples to put in x queue + uint32_t i; // Number of new samples to put in x queue uint32_t dn; // Down sampling factor uint32_t up; // Up sampling factor + uint64_t step; // Step size for linear interpolation + uint64_t pt; // Pointer remainder for linear interpolation int sloppy; // Enable sloppy resampling to reduce memory usage - int fast; // Enable linear interpolation instead of filtering + int type; // Filter type } af_resample_t; // Euclids algorithm for calculating Greatest Common Divisor GCD(a,b) @@ -82,96 +73,50 @@ return b; } -static int upsample(af_data_t* c,af_data_t* l, af_resample_t* s) +// Fast linear interpolation resample with modest audio quality +static int linint(af_data_t* c,af_data_t* l, af_resample_t* s) { - uint32_t ci = l->nch; // Index for channels - uint32_t len = 0; // Number of input samples - uint32_t nch = l->nch; // Number of channels - uint32_t inc = s->up/s->dn; - uint32_t level = s->up%s->dn; - uint32_t up = s->up; - uint32_t dn = s->dn; - - register int16_t* w = s->w; - register uint32_t wi = 0; - register uint32_t xi = 0; - - // Index current channel - while(ci--){ - // Temporary pointers - register int16_t* x = s->xq[ci]; - register int16_t* in = ((int16_t*)c->audio)+ci; - register int16_t* out = ((int16_t*)l->audio)+ci; - int16_t* end = in+c->len/2; // Block loop end - wi = s->wi; xi = s->xi; - - while(in < end){ - register uint32_t i = inc; - if(wi<level) i++; - - ADDQUE(xi,x,in); - in+=nch; - while(i--){ - // Run the FIR filter - FIR((&x[xi]),(&w[wi*L]),out); - len++; out+=nch; - // Update wi to point at the correct polyphase component - wi=(wi+dn)%up; - } + uint32_t len = 0; // Number of input samples + uint32_t nch = l->nch; // Words pre transfer + uint64_t step = s->step; + int16_t* in16 = ((int16_t*)c->audio); + int16_t* out16 = ((int16_t*)l->audio); + int32_t* in32 = ((int32_t*)c->audio); + int32_t* out32 = ((int32_t*)l->audio); + uint64_t end = ((((uint64_t)c->len)/2LL)<<STEPACCURACY); + uint64_t pt = s->pt; + uint16_t tmp; + + switch (nch){ + case 1: + while(pt < end){ + out16[len++]=in16[pt>>STEPACCURACY]; + pt+=step; } + s->pt=pt & ((1LL<<STEPACCURACY)-1); + break; + case 2: + end/=2; + while(pt < end){ + out32[len++]=in32[pt>>STEPACCURACY]; + pt+=step; + } + len=(len<<1); + s->pt=pt & ((1LL<<STEPACCURACY)-1); + break; + default: + end /=nch; + while(pt < end){ + tmp=nch; + do { + tmp--; + out16[len+tmp]=in16[tmp+(pt>>STEPACCURACY)*nch]; + } while (tmp); + len+=nch; + pt+=step; + } + s->pt=pt & ((1LL<<STEPACCURACY)-1); } - // Save values that needs to be kept for next time - s->wi = wi; - s->xi = xi; - return len; -} - -static int downsample(af_data_t* c,af_data_t* l, af_resample_t* s) -{ - uint32_t ci = l->nch; // Index for channels - uint32_t len = 0; // Number of output samples - uint32_t nch = l->nch; // Number of channels - uint32_t inc = s->dn/s->up; - uint32_t level = s->dn%s->up; - uint32_t up = s->up; - uint32_t dn = s->dn; - - register int32_t i = 0; - register uint32_t wi = 0; - register uint32_t xi = 0; - - // Index current channel - while(ci--){ - // Temporary pointers - register int16_t* x = s->xq[ci]; - register int16_t* in = ((int16_t*)c->audio)+ci; - register int16_t* out = ((int16_t*)l->audio)+ci; - register int16_t* end = in+c->len/2; // Block loop end - i = s->i; wi = s->wi; xi = s->xi; - - while(in < end){ - - ADDQUE(xi,x,in); - in+=nch; - if((--i)<=0){ - // Run the FIR filter - FIR((&x[xi]),(&s->w[wi*L]),out); - len++; out+=nch; - - // Update wi to point at the correct polyphase component - wi=(wi+dn)%up; - - // Insert i number of new samples in queue - i = inc; - if(wi<level) i++; - } - } - } - // Save values that needs to be kept for next time - s->wi = wi; - s->xi = xi; - s->i = i; - return len; } @@ -184,13 +129,24 @@ af_data_t* n = (af_data_t*)arg; // New configureation int i,d = 0; int rv = AF_OK; + size_t tsz = (s->type==TYPE_INT) ? sizeof(int16_t) : sizeof(float); // Make sure this filter isn't redundant if(af->data->rate == n->rate) return AF_DETACH; + // If linear interpolation + if(s->type == TYPE_LIN){ + s->pt=0LL; + s->step=((uint64_t)n->rate<<STEPACCURACY)/(uint64_t)af->data->rate+1LL; + af_msg(AF_MSG_VERBOSE,"[resample] Linear interpolation step: 0x%016X.\n", + s->step); + af->mul.n = af->data->rate; + af->mul.d = n->rate; + } + // Create space for circular bufers (if nesessary) - if(af->data->nch != n->nch){ + if((af->data->nch != n->nch) && (s->type != TYPE_LIN)){ // First free the old ones if(s->xq){ for(i=1;i<af->data->nch;i++) @@ -199,20 +155,30 @@ free(s->xq); } // ... then create new - s->xq = malloc(n->nch*sizeof(int16_t*)); + s->xq = malloc(n->nch*sizeof(void*)); for(i=0;i<n->nch;i++) - s->xq[i] = malloc(2*L*sizeof(int16_t)); + s->xq[i] = malloc(2*L*tsz); s->xi = 0; } // Set parameters af->data->nch = n->nch; - af->data->format = AF_FORMAT_NE | AF_FORMAT_SI; - af->data->bps = 2; + if(s->type == TYPE_INT || s->type == TYPE_LIN){ + af->data->format = AF_FORMAT_NE | AF_FORMAT_SI; + af->data->bps = 2; + } + else{ + af->data->format = AF_FORMAT_NE | AF_FORMAT_F; + af->data->bps = 4; + } if(af->data->format != n->format || af->data->bps != n->bps) rv = AF_FALSE; - n->format = AF_FORMAT_NE | AF_FORMAT_SI; - n->bps = 2; + n->format = af->data->format; + n->bps = af->data->bps; + + // If linear interpolation is used the setup is done. + if(s->type == TYPE_LIN) + return rv; // Calculate up and down sampling factors d=gcd(af->data->rate,n->rate); @@ -244,7 +210,7 @@ w = malloc(sizeof(float) * s->up *L); if(NULL != s->w) free(s->w); - s->w = malloc(L*s->up*sizeof(int16_t)); + s->w = malloc(L*s->up*tsz); // Design prototype filter type using Kaiser window with beta = 10 if(NULL == w || NULL == s->w || @@ -256,13 +222,18 @@ wt=w; for(j=0;j<L;j++){//Columns for(i=0;i<s->up;i++){//Rows - float t=(float)s->up*32767.0*(*wt); - s->w[i*L+j] = (int16_t)((t>=0.0)?(t+0.5):(t-0.5)); + if(s->type == TYPE_INT){ + float t=(float)s->up*32767.0*(*wt); + ((int16_t*)s->w)[i*L+j] = (int16_t)((t>=0.0)?(t+0.5):(t-0.5)); + } + else + ((float*)s->w)[i*L+j] = (float)s->up*(*wt); wt++; } } free(w); - af_msg(AF_MSG_VERBOSE,"[resample] New filter designed up: %i down: %i\n", s->up, s->dn); + af_msg(AF_MSG_VERBOSE,"[resample] New filter designed up: %i " + "down: %i\n", s->up, s->dn); } // Set multiplier and delay @@ -274,20 +245,30 @@ case AF_CONTROL_COMMAND_LINE:{ af_resample_t* s = (af_resample_t*)af->setup; int rate=0; - sscanf((char*)arg,"%i:%i:%i",&rate,&(s->sloppy), &(s->fast)); - return af->control(af,AF_CONTROL_RESAMPLE,&rate); + int lin=0; + sscanf((char*)arg,"%i:%i:%i", &rate, &(s->sloppy), &lin); + if(lin) + s->type = TYPE_LIN; + return af->control(af,AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET, &rate); } - case AF_CONTROL_RESAMPLE: + case AF_CONTROL_POST_CREATE: + ((af_resample_t*)af->setup)->type = + ((af_cfg_t*)arg)->force == AF_INIT_SLOW ? TYPE_INT : TYPE_FLOAT; + return AF_OK; + case AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET: // Reinit must be called after this function has been called // Sanity check if(((int*)arg)[0] < 8000 || ((int*)arg)[0] > 192000){ - af_msg(AF_MSG_ERROR,"[resample] The output sample frequency must be between 8kHz and 192kHz. Current value is %i \n",((int*)arg)[0]); + af_msg(AF_MSG_ERROR,"[resample] The output sample frequency " + "must be between 8kHz and 192kHz. Current value is %i \n", + ((int*)arg)[0]); return AF_ERROR; } af->data->rate=((int*)arg)[0]; - af_msg(AF_MSG_VERBOSE,"[resample] Changing sample rate to %iHz\n",af->data->rate); + af_msg(AF_MSG_VERBOSE,"[resample] Changing sample rate " + "to %iHz\n",af->data->rate); return AF_OK; } return AF_UNKNOWN; @@ -312,14 +293,42 @@ return NULL; // Run resampling - if(s->up>s->dn) - len = upsample(c,l,s); - else - len = downsample(c,l,s); + switch(s->type){ + case(TYPE_INT): +# define FORMAT_I 1 + if(s->up>s->dn){ +# define UP +# include "af_resample.h" +# undef UP + } + else{ +# define DN +# include "af_resample.h" +# undef DN + } + break; + case(TYPE_FLOAT): +# undef FORMAT_I +# define FORMAT_F 1 + if(s->up>s->dn){ +# define UP +# include "af_resample.h" +# undef UP + } + else{ +# define DN +# include "af_resample.h" +# undef DN + } + break; + case(TYPE_LIN): + len = linint(c, l, s); + break; + } // Set output data c->audio = l->audio; - c->len = len*2; + c->len = len*l->bps; c->rate = l->rate; return c;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libaf/af_resample.h Sat Dec 28 13:59:53 2002 +0000 @@ -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 +// +//============================================================================= +*/ + +/* This file contains the resampling engine, the sample format is + controlled by the FORMAT parameter, the filter length by the L + parameter and the resampling type by UP and DN. This file should + only be included by af_resample.c +*/ + +#undef L +#undef SHIFT +#undef FORMAT +#undef FIR +#undef ADDQUE + +/* The lenght Lxx definition selects the length of each poly phase + component. Valid definitions are L8 and L16 where the number + defines the nuber of taps. This definition affects the + computational complexity, the performance and the memory usage. +*/ + +/* The FORMAT_x parameter selects the sample format type currently + float and int16 are supported. Thes two formats are selected by + defining eiter FORMAT_F or FORMAT_I. The advantage of using float + is that the amplitude and therefore the SNR isn't affected by the + filtering, the disadvantage is that it is a lot slower. +*/ + +#if defined(FORMAT_I) +#define SHIFT >>16 +#define FORMAT int16_t +#else +#define SHIFT +#define FORMAT float +#endif + +// Short filter +#if defined(L8) + +#define L 8 // Filter length +// Unrolled loop to speed up execution +#define FIR(x,w,y) \ + (y[0]) = ( w[0]*x[0]+w[1]*x[1]+w[2]*x[2]+w[3]*x[3] \ + + w[4]*x[4]+w[5]*x[5]+w[6]*x[6]+w[7]*x[7] ) SHIFT + + + +#else /* L8/L16 */ + +#define L 16 +// Unrolled loop to speed up execution +#define FIR(x,w,y) \ + y[0] = ( w[0] *x[0] +w[1] *x[1] +w[2] *x[2] +w[3] *x[3] \ + + w[4] *x[4] +w[5] *x[5] +w[6] *x[6] +w[7] *x[7] \ + + w[8] *x[8] +w[9] *x[9] +w[10]*x[10]+w[11]*x[11] \ + + w[12]*x[12]+w[13]*x[13]+w[14]*x[14]+w[15]*x[15] ) SHIFT + +#endif /* L8/L16 */ + +// Macro to add data to circular que +#define ADDQUE(xi,xq,in)\ + xq[xi]=xq[xi+L]=(*in);\ + xi=(xi-1)&(L-1); + +#if defined(UP) + + uint32_t ci = l->nch; // Index for channels + uint32_t nch = l->nch; // Number of channels + uint32_t inc = s->up/s->dn; + uint32_t level = s->up%s->dn; + uint32_t up = s->up; + uint32_t dn = s->dn; + uint32_t ns = c->len/l->bps; + register FORMAT* w = s->w; + + register uint32_t wi = 0; + register uint32_t xi = 0; + + // Index current channel + while(ci--){ + // Temporary pointers + register FORMAT* x = s->xq[ci]; + register FORMAT* in = ((FORMAT*)c->audio)+ci; + register FORMAT* out = ((FORMAT*)l->audio)+ci; + FORMAT* end = in+ns; // Block loop end + wi = s->wi; xi = s->xi; + + while(in < end){ + register uint32_t i = inc; + if(wi<level) i++; + + ADDQUE(xi,x,in); + in+=nch; + while(i--){ + // Run the FIR filter + FIR((&x[xi]),(&w[wi*L]),out); + len++; out+=nch; + // Update wi to point at the correct polyphase component + wi=(wi+dn)%up; + } + } + + } + // Save values that needs to be kept for next time + s->wi = wi; + s->xi = xi; +#endif /* UP */ + +#if defined(DN) /* DN */ + uint32_t ci = l->nch; // Index for channels + uint32_t nch = l->nch; // Number of channels + uint32_t inc = s->dn/s->up; + uint32_t level = s->dn%s->up; + uint32_t up = s->up; + uint32_t dn = s->dn; + uint32_t ns = c->len/l->bps; + FORMAT* w = s->w; + + register int32_t i = 0; + register uint32_t wi = 0; + register uint32_t xi = 0; + + // Index current channel + while(ci--){ + // Temporary pointers + register FORMAT* x = s->xq[ci]; + register FORMAT* in = ((FORMAT*)c->audio)+ci; + register FORMAT* out = ((FORMAT*)l->audio)+ci; + register FORMAT* end = in+ns; // Block loop end + i = s->i; wi = s->wi; xi = s->xi; + + while(in < end){ + + ADDQUE(xi,x,in); + in+=nch; + if((--i)<=0){ + // Run the FIR filter + FIR((&x[xi]),(&w[wi*L]),out); + len++; out+=nch; + + // Update wi to point at the correct polyphase component + wi=(wi+dn)%up; + + // Insert i number of new samples in queue + i = inc; + if(wi<level) i++; + } + } + } + // Save values that needs to be kept for next time + s->wi = wi; + s->xi = xi; + s->i = i; +#endif /* DN */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libaf/af_tools.c Sat Dec 28 13:59:53 2002 +0000 @@ -0,0 +1,79 @@ +#include <math.h> +#include <af.h> + +/* Convert to gain value from dB. Returns AF_OK if of and AF_ERROR if + fail */ +inline int af_from_dB(int n, float* in, float* out, float k, float mi, float ma) +{ + int i = 0; + // Sanity check + if(!in || !out) + return AF_ERROR; + + for(i=0;i<n;i++){ + if(in[i]<=-200) + out[i]=0.0; + else + out[i]=pow(10.0,clamp(in[i],mi,ma)/k); + } + return AF_OK; +} + +/* Convert from gain value to dB. Returns AF_OK if of and AF_ERROR if + fail */ +inline int af_to_dB(int n, float* in, float* out, float k) +{ + int i = 0; + // Sanity check + if(!in || !out) + return AF_ERROR; + + for(i=0;i<AF_NCH;i++){ + if(in[i] == 0.0) + out[i]=-200.0; + else + out[i]=k*log10(in[i]); + } + return AF_OK; +} + +/* Convert from ms to sample time*/ +inline int af_from_ms(int n, float* in, float* out, int rate, float mi, float ma) +{ + int i = 0; + // Sanity check + if(!in || !out) + return AF_ERROR; + + for(i=0;i<AF_NCH;i++) + out[i]=clamp(in[i],ma,mi); + + return AF_OK; +} + +/* Convert from sample time to ms */ +inline int af_to_ms(int n, float* in, float* out, int rate) +{ + int i = 0; + // Sanity check + if(!in || !out) + return AF_ERROR; + + for(i=0;i<AF_NCH;i++) + out[i]=in[i]; + + return AF_OK; +} + +/* Helper function for testing the output format */ +inline int af_test_output(struct af_instance_s* af, af_data_t* out) +{ + if((af->data->format != out->format) || + (af->data->bps != out->bps) || + (af->data->rate != out->rate) || + (af->data->nch != out->nch)){ + memcpy(out,af->data,sizeof(af_data_t)); + return AF_FALSE; + } + return AF_OK; +}
--- a/libaf/af_volume.c Sat Dec 28 13:53:31 2002 +0000 +++ b/libaf/af_volume.c Sat Dec 28 13:59:53 2002 +0000 @@ -1,19 +1,27 @@ +/*============================================================================= +// +// 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 +// +//============================================================================= +*/ + /* 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 + when the mixer doesn't support the PCM channel. It can handle between 1 and 6 channels. The volume can be adjusted between -60dB - to +20dB 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. + to +20dB and is set on a per channels basis. The is accessed through + AF_CONTROL_VOLUME_LEVEL. - The plugin has support for softclipping, it is enabled by + The filter has support for soft-clipping, 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 + instantaneous 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. + probed values are calculated in dB. */ #include <stdio.h> @@ -22,66 +30,22 @@ #include <unistd.h> #include <inttypes.h> #include <math.h> +#include <limits.h> #include "af.h" -// Some limits -#define NCH AF_NCH // Number of channels - -#define MIN_S16 -32650 -#define MAX_S16 32650 - -#define MAX_VOL +40.0 -#define MIN_VOL -200.0 - // Data for specific instances of this filter typedef struct af_volume_s { - float volume[NCH]; // Volume for each channel - float power[NCH]; // Instantaneous power in each channel - float maxpower[NCH]; // Maximum power in each channel - float alpha; // Forgetting factor for power estimate - int softclip; // Soft clippng on/off - int probe; // Probing on/off - int onoff; // Volume control on/off + int enable[AF_NCH]; // Enable/disable / channel + float pow[AF_NCH]; // Estimated power level [dB] + float max[AF_NCH]; // Max Power level [dB] + float level[AF_NCH]; // Gain level for each channel + float time; // Forgetting factor for power estimate + int soft; // Enable/disable soft clipping + int fast; // Use fix-point volume control }af_volume_t; -/* Convert to gain value from dB. Returns AF_OK if of and AF_ERROR if - fail */ -inline int from_dB(float* in, float* out, float k) -{ - int i = 0; - // Sanity check - if(!in || !out) - return AF_ERROR; - - for(i=0;i<NCH;i++){ - if(in[i]<MIN_VOL) - out[i]=0.0; - else - out[i]=pow(10.0,clamp(in[i],MIN_VOL,MAX_VOL)/k); - } - return AF_OK; -} - -/* Convert from gain value to dB. Returns AF_OK if of and AF_ERROR if - fail */ -inline int to_dB(float* in, float* out, float k) -{ - int i = 0; - // Sanity check - if(!in || !out) - return AF_ERROR; - - for(i=0;i<NCH;i++){ - if(in[i] == 0.0) - out[i]=MIN_VOL; - else - out[i]=k*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) { @@ -94,48 +58,57 @@ af->data->rate = ((af_data_t*)arg)->rate; af->data->nch = ((af_data_t*)arg)->nch; - af->data->format = AF_FORMAT_SI | AF_FORMAT_LE; - af->data->bps = 2; - // Time constant set to 0.1s - s->alpha = (1.0/0.2)/(2.0*M_PI*(float)((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; + if(s->fast){ + af->data->format = AF_FORMAT_SI | AF_FORMAT_NE; + af->data->bps = 2; + } + else{ + // Cutoff set to 10Hz for forgetting factor + float x = 2.0*M_PI*15.0/(float)af->data->rate; + float t = 2.0-cos(x); + s->time = 1.0 - (t - sqrt(t*t - 1)); + af_msg(AF_MSG_DEBUG0,"[volume] Forgetting factor = %0.5f\n",s->time); + 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:{ float v=-10.0; - float vol[6]; - int i; - sscanf((char*)arg,"%f:%i:%i:%i", &v, - &(s->softclip), &(s->probe), &(s->onoff)); - for(i=0;i<NCH;i++) vol[i]=v; - return from_dB(vol,s->volume,20.0); + float vol[AF_NCH]; + int i; + sscanf((char*)arg,"%f:%i", &v, &s->soft); + for(i=0;i<AF_NCH;i++) vol[i]=v; + return control(af,AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET, vol); } - case AF_CONTROL_VOLUME_SET: - return from_dB((float*)arg,s->volume,20.0); - case AF_CONTROL_VOLUME_GET: - return to_dB(s->volume,(float*)arg,20.0); - case AF_CONTROL_VOLUME_PROBE_GET: - return to_dB(s->power,(float*)arg,10.0); - case AF_CONTROL_VOLUME_PROBE_GET_MAX: - return to_dB(s->maxpower,(float*)arg,10.0); - case AF_CONTROL_VOLUME_SOFTCLIP: - s->softclip = (int)arg; + case AF_CONTROL_POST_CREATE: + s->fast = ((af_cfg_t*)arg)->force == AF_INIT_SLOW ? 1 : 0; 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; + case AF_CONTROL_VOLUME_ON_OFF | AF_CONTROL_SET: + memcpy(s->enable,(int*)arg,AF_NCH*sizeof(int)); + return AF_OK; + case AF_CONTROL_VOLUME_ON_OFF | AF_CONTROL_GET: + memcpy((int*)arg,s->enable,AF_NCH*sizeof(int)); + return AF_OK; + case AF_CONTROL_VOLUME_SOFTCLIP | AF_CONTROL_SET: + s->soft = *(int*)arg; + return AF_OK; + case AF_CONTROL_VOLUME_SOFTCLIP | AF_CONTROL_GET: + *(int*)arg = s->soft; + return AF_OK; + case AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET: + return af_from_dB(AF_NCH,(float*)arg,s->level,20.0,-200.0,60.0); + case AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_GET: + return af_to_dB(AF_NCH,s->level,(float*)arg,20.0); + case AF_CONTROL_VOLUME_PROBE | AF_CONTROL_GET: + return af_to_dB(AF_NCH,s->pow,(float*)arg,10.0); + case AF_CONTROL_VOLUME_PROBE_MAX | AF_CONTROL_GET: + return af_to_dB(AF_NCH,s->max,(float*)arg,10.0); case AF_CONTROL_PRE_DESTROY:{ float m = 0.0; int i; - for(i=0;i<NCH;i++) - m=max(m,s->maxpower[i]); + for(i=0;i<AF_NCH;i++) + m=max(m,s->max[i]); af_msg(AF_MSG_INFO,"The maximum volume was %0.2fdB \n",10*log10(m)); return AF_OK; } @@ -155,57 +128,66 @@ // 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){ + af_data_t* c = data; // Current working data + af_volume_t* s = (af_volume_t*)af->setup; // Setup for this instance + int ch = 0; // Channel counter + register int nch = c->nch; // Number of channels + register int i = 0; + + // Basic operation volume control only (used on slow machines) + if(af->data->format == (AF_FORMAT_SI | AF_FORMAT_NE)){ + int16_t* a = (int16_t*)c->audio; // Audio data + int len = c->len/2; // Number of samples for(ch = 0; ch < nch ; ch++){ - float alpha = s->alpha; - float beta = 1 - alpha; - float pow = s->power[ch]; - float maxpow = s->maxpower[ch]; - register float t = 0; - for(i=ch;i<len;i+=nch){ - t = ((float)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; + if(s->enable[ch]){ + register int vol = (int)(255.0 * s->level[ch]); + for(i=ch;i<len;i+=nch){ + register int x = (a[i] * vol) >> 8; + a[i]=clamp(x,SHRT_MIN,SHRT_MAX); } - a[i]=clamp(x,MIN_S16,MAX_S16); } } } - + // Machine is fast and data is floating point + else if(af->data->format == (AF_FORMAT_F | AF_FORMAT_NE)){ + float* a = (float*)c->audio; // Audio data + int len = c->len/4; // Number of samples + for(ch = 0; ch < nch ; ch++){ + // Volume control (fader) + if(s->enable[ch]){ + float t = 1.0 - s->time; + for(i=ch;i<len;i+=nch){ + register float x = a[i]; + register float pow = x*x; + // Check maximum power value + if(pow > s->max[ch]) + s->max[ch] = pow; + // Set volume + x *= s->level[ch]; + // Peak meter + pow = x*x; + if(pow > s->pow[ch]) + s->pow[ch] = pow; + else + s->pow[ch] = t*s->pow[ch] + pow*s->time; // LP filter + /* Soft clipping, the sound of a dream, thanks to Jon Wattes + post to Musicdsp.org */ + if(s->soft){ + if (x >= M_PI/2) + x = 1.0; + else if(x <= -M_PI/2) + x = -1.0; + else + x = sin(x); + } + // Hard clipping + else + x=clamp(x,-1.0,1.0); + a[i] = x; + } + } + } + } return c; } @@ -222,13 +204,13 @@ if(af->data == NULL || af->setup == NULL) return AF_ERROR; /* Enable volume control and set initial volume to 0.1 this is a - safety mesure to ensure that the user doesn't blow his + safety measure to ensure that the user doesn't blow his speakers. If the user isn't happy with this he can use the - commandline parameters to set the initial volume */ - ((af_volume_t*)af->setup)->onoff = 1; - for(i=0;i<NCH;i++) - ((af_volume_t*)af->setup)->volume[i]=0.1; - + command-line parameters to set the initial volume */ + for(i=0;i<AF_NCH;i++){ + ((af_volume_t*)af->setup)->enable[i] = 1; + ((af_volume_t*)af->setup)->level[i] = 0.1; + } return AF_OK; }
--- a/libaf/control.h Sat Dec 28 13:53:31 2002 +0000 +++ b/libaf/control.h Sat Dec 28 13:59:53 2002 +0000 @@ -2,6 +2,57 @@ #define __af_control_h /********************************************* +// Control info struct. +// +// This struct is the argument in a info call to a filter. +*/ + +// Argument types +#define AF_CONTROL_TYPE_BOOL (0x0<<0) +#define AF_CONTROL_TYPE_CHAR (0x1<<0) +#define AF_CONTROL_TYPE_INT (0x2<<0) +#define AF_CONTROL_TYPE_FLOAT (0x3<<0) +#define AF_CONTROL_TYPE_STRUCT (0x4<<0) +#define AF_CONTROL_TYPE_SPECIAL (0x5<<0) // a pointer to a function for example +#define AF_CONTROL_TYPE_MASK (0x7<<0) +// Argument geometry +#define AF_CONTROL_GEOM_SCALAR (0x0<<3) +#define AF_CONTROL_GEOM_ARRAY (0x1<<3) +#define AF_CONTROL_GEOM_MATRIX (0x2<<3) +#define AF_CONTROL_GEOM_MASK (0x3<<3) +// Argument properties +#define AF_CONTROL_PROP_READ (0x0<<5) // The argument can be read +#define AF_CONTROL_PROP_WRITE (0x1<<5) // The argument can be written +#define AF_CONTROL_PROP_SAVE (0x2<<5) // Can be saved +#define AF_CONTROL_PROP_RUNTIME (0x4<<5) // Acessable during execution +#define AF_CONTROL_PROP_CHANNEL (0x8<<5) // Argument is set per channel +#define AF_CONTROL_PROP_MASK (0xF<<5) + +typedef struct af_control_info_s{ + int def; // Control enumrification + char* name; // Name of argument + char* info; // Description of what it does + int flags; // Flags as defined above + float max; // Max and min value + float min; // (only aplicable on float and int) + int xdim; // 1st dimension + int ydim; // 2nd dimension (=0 for everything except matrix) + size_t sz; // Size of argument in bytes + int ch; // Channel number (for future use) + void* arg; // Data (for future use) +}af_control_info_t; + + +/********************************************* +// Extended control used with arguments that operates on only one +// channel at the time +*/ +typedef struct af_control_ext_s{ + void* arg; // Argument + int ch; // Chanel number +}af_control_ext_t; + +/********************************************* // Control parameters */ @@ -11,9 +62,9 @@ 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 +#define AF_CONTROL_MANDATORY 0x10000000 +#define AF_CONTROL_OPTIONAL 0x20000000 +#define AF_CONTROL_FILTER_SPECIFIC 0x40000000 // MANDATORY CALLS @@ -23,66 +74,136 @@ 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 +#define AF_CONTROL_REINIT 0x00000100 | AF_CONTROL_MANDATORY // 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 */ -#define AF_CONTROL_POST_CREATE 1 + AF_CONTROL_OPTIONAL_BASE +#define AF_CONTROL_POST_CREATE 0x00000100 | AF_CONTROL_OPTIONAL // Called just before destruction of a filter -#define AF_CONTROL_PRE_DESTROY 2 + AF_CONTROL_OPTIONAL_BASE +#define AF_CONTROL_PRE_DESTROY 0x00000200 | AF_CONTROL_OPTIONAL /* Commandline parameters. If there were any commandline parameters for this specific filter, they will be given as a char* in the argument */ -#define AF_CONTROL_COMMAND_LINE 3 + AF_CONTROL_OPTIONAL_BASE +#define AF_CONTROL_COMMAND_LINE 0x00000300 | AF_CONTROL_OPTIONAL // FILTER SPECIFIC CALLS +// Basic operations: These can be ored with any of the below calls +// Set argument +#define AF_CONTROL_SET 0x00000000 +// Get argument +#define AF_CONTROL_GET 0x00000001 +// Get info about the control, i.e fill in everything except argument +#define AF_CONTROL_INFO 0x00000002 + +// Resample + // Set output rate in resample -#define AF_CONTROL_RESAMPLE 1 + AF_CONTROL_FILTER_SPECIFIC_BASE +#define AF_CONTROL_RESAMPLE_RATE 0x00000100 | AF_CONTROL_FILTER_SPECIFIC -// Set output format in format -#define AF_CONTROL_FORMAT 2 + AF_CONTROL_FILTER_SPECIFIC_BASE +// Enable sloppy resampling +#define AF_CONTROL_RESAMPLE_SLOPPY 0x00000200 | AF_CONTROL_FILTER_SPECIFIC + +// Set resampling accuracy +#define AF_CONTROL_RESAMPLE_ACCURACY 0x00000300 | AF_CONTROL_FILTER_SPECIFIC + +// Format + +// Set output format bits per sample +#define AF_CONTROL_FORMAT_BPS 0x00000400 | AF_CONTROL_FILTER_SPECIFIC + +// Set output format sample format +#define AF_CONTROL_FORMAT_FMT 0x00000500 | AF_CONTROL_FILTER_SPECIFIC + +// Channels // Set number of output channels in channels -#define AF_CONTROL_CHANNELS 3 + AF_CONTROL_FILTER_SPECIFIC_BASE +#define AF_CONTROL_CHANNELS 0x00000600 | AF_CONTROL_FILTER_SPECIFIC + +// Set number of channel routes +#define AF_CONTROL_CHANNELS_ROUTES 0x00000700 | AF_CONTROL_FILTER_SPECIFIC + +// Set channel routing pair, arg is int[2] and ch is used +#define AF_CONTROL_CHANNELS_ROUTING 0x00000800 | AF_CONTROL_FILTER_SPECIFIC + +// Set nuber of channel routing pairs, arg is int* +#define AF_CONTROL_CHANNELS_NR 0x00000900 | AF_CONTROL_FILTER_SPECIFIC -// Set delay length in delay -#define AF_CONTROL_DELAY_SET_LEN 4 + AF_CONTROL_FILTER_SPECIFIC_BASE +// Set make af_channels into a router +#define AF_CONTROL_CHANNELS_ROUTER 0x00000A00 | AF_CONTROL_FILTER_SPECIFIC + +// Volume -// Volume +// Turn volume control on and off, arg is int* +#define AF_CONTROL_VOLUME_ON_OFF 0x00000B00 | AF_CONTROL_FILTER_SPECIFIC + +// Turn soft clipping of the volume on and off, arg is binary +#define AF_CONTROL_VOLUME_SOFTCLIP 0x00000C00 | AF_CONTROL_FILTER_SPECIFIC // 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 +#define AF_CONTROL_VOLUME_LEVEL 0x00000D00 | AF_CONTROL_FILTER_SPECIFIC + +// Probed power level for all channels, arg is a float* +#define AF_CONTROL_VOLUME_PROBE 0x00000E00 | AF_CONTROL_FILTER_SPECIFIC -/* 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 +// Maximum probed power level for all channels, arg is a float* +#define AF_CONTROL_VOLUME_PROBE_MAX 0x00000F00 | AF_CONTROL_FILTER_SPECIFIC + +// Compressor/expander + +// Turn compressor/expander on and off +#define AF_CONTROL_COMP_ON_OFF 0x00001000 | AF_CONTROL_FILTER_SPECIFIC -// Turn volume control on and off, arg is binary -#define AF_CONTROL_VOLUME_ON_OFF 7 + AF_CONTROL_FILTER_SPECIFIC_BASE +// Compression/expansion threshold [dB] +#define AF_CONTROL_COMP_THRESH 0x00001100 | AF_CONTROL_FILTER_SPECIFIC + +// Compression/expansion attack time [ms] +#define AF_CONTROL_COMP_ATTACK 0x00001200 | AF_CONTROL_FILTER_SPECIFIC -// Turn soft clipping of the volume on and off, arg is binary -#define AF_CONTROL_VOLUME_SOFTCLIP 8 + AF_CONTROL_FILTER_SPECIFIC_BASE +// Compression/expansion release time [ms] +#define AF_CONTROL_COMP_RELEASE 0x00001300 | AF_CONTROL_FILTER_SPECIFIC + +// Compression/expansion gain level [dB] +#define AF_CONTROL_COMP_RATIO 0x00001400 | AF_CONTROL_FILTER_SPECIFIC + +// Noise gate -// Get the probed power level for all channels, arg is a float* -#define AF_CONTROL_VOLUME_PROBE_GET 9 + AF_CONTROL_FILTER_SPECIFIC_BASE +// Turn noise gate on an off +#define AF_CONTROL_GATE_ON_OFF 0x00001500 | AF_CONTROL_FILTER_SPECIFIC + +// Noise gate threshold [dB] +#define AF_CONTROL_GATE_THRESH 0x00001600 | AF_CONTROL_FILTER_SPECIFIC -// 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 +// Noise gate attack time [ms] +#define AF_CONTROL_GATE_ATTACK 0x00001700 | AF_CONTROL_FILTER_SPECIFIC + +// Noise gate release time [ms] +#define AF_CONTROL_GATE_RELEASE 0x00001800 | AF_CONTROL_FILTER_SPECIFIC + +// Noise gate release range level [dB] +#define AF_CONTROL_GATE_RANGE 0x00001900 | AF_CONTROL_FILTER_SPECIFIC -// Turn probing on and off, arg is binary -#define AF_CONTROL_VOLUME_PROBE_ON_OFF 11 + AF_CONTROL_FILTER_SPECIFIC_BASE +// Pan + +// Pan levels, arg is a control_ext with a float* +#define AF_CONTROL_PAN_LEVEL 0x00001A00 | AF_CONTROL_FILTER_SPECIFIC -// Set equalizer gain, arg is an equalizer_t* -#define AF_CONTROL_EQUALIZER_SET_GAIN 12 + AF_CONTROL_FILTER_SPECIFIC_BASE +// Number of outputs from pan, arg is int* +#define AF_CONTROL_PAN_NOUT 0x00001B00 | AF_CONTROL_FILTER_SPECIFIC + -// Get equalizer gain, arg is an equalizer_t* -#define AF_CONTROL_EQUALIZER_GET_GAIN 13 + AF_CONTROL_FILTER_SPECIFIC_BASE +// Set equalizer gain, arg is a control_ext with a float* +#define AF_CONTROL_EQUALIZER_GAIN 0x00001C00 | AF_CONTROL_FILTER_SPECIFIC + + +// Set delay length in seconds +#define AF_CONTROL_DELAY_LEN 0x00001D00 | AF_CONTROL_FILTER_SPECIFIC + #endif /*__af_control_h */