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 */