changeset 8675:54c386615a70

Extending delay to have different delays for different channels
author anders
date Tue, 31 Dec 2002 05:44:50 +0000
parents 93212da0032e
children 579405800083
files libaf/af_delay.c
diffstat 1 files changed, 115 insertions(+), 82 deletions(-) [+]
line wrap: on
line diff
--- a/libaf/af_delay.c	Tue Dec 31 05:42:20 2002 +0000
+++ b/libaf/af_delay.c	Tue Dec 31 05:44:50 2002 +0000
@@ -1,7 +1,6 @@
-/* This audio filter doesn't really do anything useful but serves an
-   example of how audio filters work. It delays the output signal by
-   the number of seconds set by delay=n where n is the number of
-   seconds.
+/* This audio filter delays the output signal for the different
+   channels and can be used for simple position panning. Extension for
+   this filter would be a reverb.
 */
 #include <stdio.h>
 #include <stdlib.h>
@@ -9,87 +8,96 @@
 
 #include "af.h"
 
+#define L 65536
+
+#define UPDATEQI(qi) qi=(qi+1)&(L-1)
+
 // Data for specific instances of this filter
 typedef struct af_delay_s
 {
-  void* buf; 	    // data block used for delaying audio signal
-  int   len;        // local buffer length
-  float tlen;       // Delay in seconds
+  void* q[AF_NCH];   	// Circular queues used for delaying audio signal
+  int 	wi[AF_NCH];  	// Write index
+  int 	ri;		// Read index
+  float	d[AF_NCH];   	// Delay [ms] 	
 }af_delay_t;
 
 // Initialization and runtime control
 static int control(struct af_instance_s* af, int cmd, void* arg)
 {
+  af_delay_t* s = af->setup;
   switch(cmd){
   case AF_CONTROL_REINIT:{
+    int i;
+
+    // Free prevous delay queues
+    for(i=0;i<af->data->nch;i++){
+      if(s->q[i])
+	free(s->q[i]);
+    }
+
     af->data->rate   = ((af_data_t*)arg)->rate;
     af->data->nch    = ((af_data_t*)arg)->nch;
     af->data->format = ((af_data_t*)arg)->format;
     af->data->bps    = ((af_data_t*)arg)->bps;
-    
-    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_LEN | AF_CONTROL_SET,&d);
-  }  
-  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
 
-    if(*((float*)arg) > 30 || *((float*)arg) < 0){
-      af_msg(AF_MSG_ERROR,"Error setting delay length in af_delay. Delay must be between 0s and 30s\n");
-      s->len=0;
-      s->tlen=0.0;
-      af->delay=0.0;
-      return AF_ERROR;
+    // Allocate new delay queues
+    for(i=0;i<af->data->nch;i++){
+      s->q[i] = calloc(L,af->data->bps);
+      if(NULL == s->q[i])
+	af_msg(AF_MSG_FATAL,"[delay] Out of memory\n");
     }
 
-    // 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->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);
-
-    // Out of memory error
-    if(!s->buf){
-      s->len = 0;
-      free(bt);
-      return AF_ERROR;
-    }
-      
-    // Clear the new buffer
-    memset(s->buf, 0, s->len);
-    
-    /* Copy old buffer to avoid click in output 
-       sound (at least most of it) and release it */
-    if(bt){
-      memcpy(s->buf,bt,min(lt,s->len));
-      free(bt);
+    return control(af,AF_CONTROL_DELAY_LEN | AF_CONTROL_SET,s->d);
+  }
+  case AF_CONTROL_COMMAND_LINE:{
+    int n = 1;
+    int i = 0;
+    char* cl = arg;
+    while(n && i < AF_NCH ){
+      sscanf(cl,"%f:%n",&s->d[i],&n);
+      if(n==0 || cl[n-1] == '\0')
+	break;
+      cl=&cl[n];
+      i++;
     }
     return AF_OK;
   }
-  case AF_CONTROL_DELAY_LEN | AF_CONTROL_GET:
-    *((float*)arg) = ((af_delay_t*)af->setup)->tlen;
+  case AF_CONTROL_DELAY_LEN | AF_CONTROL_SET:{
+    int i;
+    if(AF_OK != af_from_ms(AF_NCH, arg, s->wi, af->data->rate, 0.0, 1000.0))
+      return AF_ERROR;
+    s->ri = 0;
+    for(i=0;i<AF_NCH;i++){
+      af_msg(AF_MSG_DEBUG0,"[delay] Channel %i delayed by %0.3fms\n",
+	     i,clamp(s->d[i],0.0,1000.0));
+      af_msg(AF_MSG_DEBUG1,"[delay] Channel %i delayed by %i samples\n",
+	     i,s->wi[i]);
+    }
     return AF_OK;
   }
+  case AF_CONTROL_DELAY_LEN | AF_CONTROL_GET:{
+    int i;
+    for(i=0;i<AF_NCH;i++){
+      if(s->ri > s->wi[i])
+	s->wi[i] = L - (s->ri - s->wi[i]);
+      else
+	s->wi[i] = s->wi[i] - s->ri;
+    }
+    return af_to_ms(AF_NCH, s->wi, arg, af->data->rate);
+  }
+  }
   return AF_UNKNOWN;
 }
 
 // Deallocate memory 
 static void uninit(struct af_instance_s* af)
 {
-  if(af->data->audio)
-    free(af->data->audio);
+  int i;
   if(af->data)
     free(af->data);
-  if(((af_delay_t*)(af->setup))->buf)
-    free(((af_delay_t*)(af->setup))->buf);
+  for(i=0;i<AF_NCH;i++)
+    if(((af_delay_t*)(af->setup))->q[i])
+      free(((af_delay_t*)(af->setup))->q[i]);
   if(af->setup)
     free(af->setup);
 }
@@ -97,34 +105,59 @@
 // 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_delay_t*  s = (af_delay_t*)af->setup; 	// Setup for this instance
- 
-  
-  if(AF_OK != RESIZE_LOCAL_BUFFER(af , data))
-    return NULL;
-  
-  if(s->len > c->len){ // Delay bigger than buffer
-    // Copy beginning of buffer to beginning of output buffer
-    memcpy(l->audio,s->buf,c->len);
-    // Move buffer left
-    memmove(s->buf,s->buf+c->len,s->len-c->len);
-    // Save away current audio to end of buffer
-    memcpy(s->buf+s->len-c->len,c->audio,c->len);
+  af_data_t*   	c   = data;	 // Current working data
+  af_delay_t*  	s   = af->setup; // Setup for this instance
+  int 		nch = c->nch;	 // Number of channels
+  int		len = c->len/c->bps; // Number of sample in data chunk
+  int		ri  = 0;
+  int 		ch,i;
+  for(ch=0;ch<nch;ch++){
+    switch(c->bps){
+    case 1:{
+      int8_t* a = c->audio;
+      int8_t* q = s->q[ch]; 
+      int wi = s->wi[ch];
+      ri = s->ri;
+      for(i=ch;i<len;i+=nch){
+	q[wi] = a[i];
+	a[i]  = q[ri];
+	UPDATEQI(wi);
+	UPDATEQI(ri);
+      }
+      s->wi[ch] = wi;
+      break;
+    }
+    case 2:{
+      int16_t* a = c->audio;
+      int16_t* q = s->q[ch]; 
+      int wi = s->wi[ch];
+      ri = s->ri;
+      for(i=ch;i<len;i+=nch){
+	q[wi] = a[i];
+	a[i]  = q[ri];
+	UPDATEQI(wi);
+	UPDATEQI(ri);
+      }
+      s->wi[ch] = wi;
+      break;
+    }
+    case 4:{
+      int32_t* a = c->audio;
+      int32_t* q = s->q[ch]; 
+      int wi = s->wi[ch];
+      ri = s->ri;
+      for(i=ch;i<len;i+=nch){
+	q[wi] = a[i];
+	a[i]  = q[ri];
+	UPDATEQI(wi);
+	UPDATEQI(ri);
+      }
+      s->wi[ch] = wi;
+      break;
+    }
+    }
   }
-  else{
-    // Copy end of previous block to beginning of output buffer
-    memcpy(l->audio,s->buf,s->len);
-    // Copy current block except end
-    memcpy(l->audio+s->len,c->audio,c->len-s->len);
-    // Save away end of current block for next call
-    memcpy(s->buf,c->audio+c->len-s->len,s->len);
-  }
-  
-  // Set output data
-  c->audio=l->audio;
-
+  s->ri = ri;
   return c;
 }