1 #include <stdlib.h>
2 #include <math.h>
3 #include "soundpipe.h"
4 
5 enum { CLEAR, ATTACK, DECAY, SUSTAIN, RELEASE };
6 
sp_adsr_create(sp_adsr ** p)7 int sp_adsr_create(sp_adsr **p)
8 {
9     *p = malloc(sizeof(sp_adsr));
10     return SP_OK;
11 }
12 
sp_adsr_destroy(sp_adsr ** p)13 int sp_adsr_destroy(sp_adsr **p)
14 {
15     free(*p);
16     return SP_OK;
17 }
18 
sp_adsr_init(sp_data * sp,sp_adsr * p)19 int sp_adsr_init(sp_data *sp, sp_adsr *p)
20 {
21     p->atk = 0.1;
22     p->dec = 0.1;
23     p->sus = 0.5;
24     p->rel = 0.3;
25     p->timer = 0;
26     p->a = 0;
27     p->b = 0;
28     p->y = 0;
29     p->x = 0;
30     p->prev = 0;
31     p->atk_time = p->atk * sp->sr;
32     p->mode = CLEAR;
33     return SP_OK;
34 }
35 
tau2pole(sp_data * sp,sp_adsr * p,SPFLOAT tau)36 static SPFLOAT tau2pole(sp_data *sp, sp_adsr *p, SPFLOAT tau)
37 {
38     return exp(-1.0 / (tau * sp->sr));
39 }
40 
adsr_filter(sp_data * sp,sp_adsr * p)41 static SPFLOAT adsr_filter(sp_data *sp, sp_adsr *p)
42 {
43     p->y = p->b * p->x  + p->a * p->y;
44     return p->y;
45 }
46 
sp_adsr_compute(sp_data * sp,sp_adsr * p,SPFLOAT * in,SPFLOAT * out)47 int sp_adsr_compute(sp_data *sp, sp_adsr *p, SPFLOAT *in, SPFLOAT *out)
48 {
49     SPFLOAT pole;
50     if(p->prev < *in && p->mode != DECAY) {
51         p->mode = ATTACK;
52         p->timer = 0;
53         /* quick fix: uncomment if broken */
54         /* pole = tau2pole(sp, p, p->atk * 0.75); */
55         /* p->atk_time = p->atk * sp->sr * 1.5; */
56         pole = tau2pole(sp, p, p->atk * 0.6);
57         p->atk_time = p->atk * sp->sr;
58         p->a = pole;
59         p->b = 1 - pole;
60     } else if(p->prev > *in) {
61         p->mode = RELEASE;
62         pole = tau2pole(sp, p, p->rel);
63         p->a = pole;
64         p->b = 1 - pole;
65     }
66 
67     p->x = *in;
68     p->prev = *in;
69 
70     switch(p->mode) {
71         case CLEAR:
72             *out = 0;
73             break;
74         case ATTACK:
75             p->timer++;
76             *out = adsr_filter(sp, p);
77             /* quick fix: uncomment if broken */
78             /* if(p->timer > p->atk_time) { */
79             if(*out > 0.99) {
80                 p->mode = DECAY;
81                 pole = tau2pole(sp, p, p->dec);
82                 p->a = pole;
83                 p->b = 1 - pole;
84             }
85             break;
86         case DECAY:
87         case RELEASE:
88             p->x *= p->sus;
89             *out = adsr_filter(sp, p);
90         default:
91             break;
92     }
93 
94     return SP_OK;
95 }
96