summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libaf/Makefile2
-rw-r--r--libaf/af.c60
-rw-r--r--libaf/af.h13
-rw-r--r--libaf/af_channels.c168
-rw-r--r--libaf/af_comp.c161
-rw-r--r--libaf/af_delay.c13
-rw-r--r--libaf/af_equalizer.c87
-rw-r--r--libaf/af_format.c74
-rw-r--r--libaf/af_gate.c157
-rw-r--r--libaf/af_pan.c184
-rw-r--r--libaf/af_resample.c277
-rw-r--r--libaf/af_resample.h161
-rw-r--r--libaf/af_tools.c79
-rw-r--r--libaf/af_volume.c266
-rw-r--r--libaf/control.h183
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;
}
return AF_OK;
-}
+}
// Initialization and runtime control
static int control(struct af_instance_s* af, int cmd, void* arg)
@@ -158,10 +164,12 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
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 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
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_SPE