summaryrefslogtreecommitdiffstats
path: root/libaf/af_delay.c
blob: f19dc1934bab144535c11424964bc7c45b9e5d3a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "af.h"

// 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
}af_delay_t;

// Initialization and runtime control
static int control(struct af_instance_s* af, int cmd, void* arg)
{
  switch(cmd){
  case AF_CONTROL_REINIT:{
    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_SET_LEN,&((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);
  }  
  case AF_CONTROL_DELAY_SET_LEN:{
    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;
    }

    // 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 AF_OK;
  }
  }
  return AF_UNKNOWN;
}

// Deallocate memory 
static void uninit(struct af_instance_s* af)
{
  if(af->data->audio)
    free(af->data->audio);
  if(af->data)
    free(af->data);
  if(((af_delay_t*)(af->setup))->buf)
    free(((af_delay_t*)(af->setup))->buf);
  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_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);
  }
  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;

  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_delay_t));
  if(af->data == NULL || af->setup == NULL)
    return AF_ERROR;
  return AF_OK;
}

// Description of this filter
af_info_t af_info_delay = {
    "Delay audio filter",
    "delay",
    "Anders",
    "",
    AF_FLAGS_REENTRANT,
    open
};