/
adsr.c
132 lines (114 loc) · 3.42 KB
/
adsr.c
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
// ADSR.c
//
// Originally Created by Nigel Redmon on 12/18/12.
// EarLevel Engineering: earlevel.com
// Copyright 2012 Nigel Redmon
// C Port 2013 Francesco D'Este
//
// For a complete explanation of the ADSR envelope generator and code,
// read the series of articles by the author, starting here:
// http://www.earlevel.com/main/2013/06/01/envelope-generators/
//
// License:
//
// This source code is provided as is, without warranty.
// You may copy and distribute verbatim copies of this document.
// You may modify and use this source code to create binary code for your own
// purposes, free or commercial.
//
#include "adsr.h"
#include <math.h>
#include <nds.h>
void initADSR(ADSR *ptr) {
resetADSR(ptr);
setAttackRate(ptr, 0);
setDecayRate(ptr, 0);
setReleaseRate(ptr, 0);
setSustainLevel(ptr, 1.0);
setTargetRatioA(ptr, 0.3);
setTargetRatioDR(ptr, 0.0001);
}
void destroyADSR() {}
void setAttackRate(ADSR *ptr, float rate) {
ptr->attackRate = rate;
ptr->attackCoef = calcCoef(rate, ptr->targetRatioA);
ptr->attackBase = (1.0 + ptr->targetRatioA) * (1.0 - ptr->attackCoef);
}
void setDecayRate(ADSR *ptr, float rate) {
ptr->decayRate = rate;
ptr->decayCoef = calcCoef(rate, ptr->targetRatioDR);
ptr->decayBase =
(ptr->sustainLevel - ptr->targetRatioDR) * (1.0 - ptr->decayCoef);
}
void setReleaseRate(ADSR *ptr, float rate) {
ptr->releaseRate = rate;
ptr->releaseCoef = calcCoef(rate, ptr->targetRatioDR);
ptr->releaseBase = -ptr->targetRatioDR * (1.0 - ptr->releaseCoef);
}
float calcCoef(float rate, float targetRatio) {
return exp(-log((1.0 + targetRatio) / targetRatio) / rate);
}
void setSustainLevel(ADSR *ptr, float level) {
ptr->sustainLevel = level;
ptr->decayBase =
(ptr->sustainLevel - ptr->targetRatioDR) * (1.0 - ptr->decayCoef);
}
void setTargetRatioA(ADSR *ptr, float targetRatio) {
if (targetRatio < 0.000000001)
targetRatio = 0.000000001; // -180 dB
ptr->targetRatioA = targetRatio;
ptr->attackBase = (1.0 + ptr->targetRatioA) * (1.0 - ptr->attackCoef);
}
void setTargetRatioDR(ADSR *ptr, float targetRatio) {
if (targetRatio < 0.000000001)
targetRatio = 0.000000001; // -180 dB
ptr->targetRatioDR = targetRatio;
ptr->decayBase =
(ptr->sustainLevel - ptr->targetRatioDR) * (1.0 - ptr->decayCoef);
ptr->releaseBase = -ptr->targetRatioDR * (1.0 - ptr->releaseCoef);
}
float process(ADSR *ptr) {
switch (ptr->state) {
case env_idle:
break;
case env_attack:
ptr->output = ptr->attackBase + ptr->output * ptr->attackCoef;
if (ptr->output >= 1.0) {
ptr->output = 1.0;
ptr->state = env_decay;
}
break;
case env_decay:
ptr->output = ptr->decayBase + ptr->output * ptr->decayCoef;
if (ptr->output <= ptr->sustainLevel) {
ptr->output = ptr->sustainLevel;
ptr->state = env_sustain;
}
break;
case env_sustain:
break;
case env_release:
ptr->output = ptr->releaseBase + ptr->output * ptr->releaseCoef;
if (ptr->output <= 0.0) {
ptr->output = 0.0;
ptr->state = env_idle;
}
}
return ptr->output;
}
void gate(ADSR *ptr) {
if (ptr->gate == 0) {
ptr->state = env_attack;
ptr->gate = 1;
} else if (ptr->state != env_idle) {
ptr->state = env_release;
ptr->gate = 0;
}
}
int getState(ADSR *ptr) { return ptr->state; }
void resetADSR(ADSR *ptr) {
ptr->gate = 0;
ptr->state = env_idle;
ptr->output = 0.0;
}
float getOutput(ADSR *ptr) { return ptr->output; }