-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathADSR.cpp
161 lines (139 loc) · 4.21 KB
/
ADSR.cpp
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
152
153
154
155
156
157
158
159
160
161
//
// ADSR.cpp
//
// Created by Nigel Redmon on 12/18/12.
// EarLevel Engineering: earlevel.com
// Copyright 2012 Nigel Redmon
//
// 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.
//
// 1.01 2016-01-02 njr added calcCoef to SetTargetRatio functions that were in the ADSR widget but missing in this code
// 1.02 2017-01-04 njr in calcCoef, checked for rate 0, to support non-IEEE compliant compilers
// 1.03 2020-04-08 njr changed float to float; large target ratio and rate resulted in exp returning 1 in calcCoef
//
#include "ADSR.h"
#include <math.h>
#include <iostream>
using namespace SYNTHPI;
using namespace audio;
ADSR::ADSR() {
this-> sampleratef=static_cast<float> (samplerate);
reset();
setAttackRate(0.1*sampleratef);
setDecayRate(0.3*sampleratef);
setReleaseRate(0.1*sampleratef);
setSustainLevel(0.7);
setTargetRatioA(0.3);
setTargetRatioDR(0.0001);
}
ADSR::~ADSR() {
}
void ADSR::setAttackRate(float rate) {
attackRate = rate;
attackCoef = calcCoef(rate, targetRatioA);
attackBase = (1.0 + targetRatioA) * (1.0 - attackCoef);
}
void ADSR::setDecayRate(float rate) {
decayRate = rate;
decayCoef = calcCoef(rate, targetRatioDR);
decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef);
}
void ADSR::setReleaseRate(float rate) {
releaseRate = rate;
releaseCoef = calcCoef(rate, targetRatioDR);
releaseBase = -targetRatioDR * (1.0 - releaseCoef);
}
float ADSR::calcCoef(float rate, float targetRatio) {
return (rate <= 0) ? 0.0 : exp(-log((1.0 + targetRatio) / targetRatio) / rate);
}
void ADSR::setSustainLevel(float level) {
sustainLevel = level;
decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef);
}
void ADSR::setTargetRatioA(float targetRatio) {
if (targetRatio < 0.000000001)
targetRatio = 0.000000001; // -180 dB
targetRatioA = targetRatio;
attackCoef = calcCoef(attackRate, targetRatioA);
attackBase = (1.0 + targetRatioA) * (1.0 - attackCoef);
}
void ADSR::setTargetRatioDR(float targetRatio) {
if (targetRatio < 0.000000001)
targetRatio = 0.000000001; // -180 dB
targetRatioDR = targetRatio;
decayCoef = calcCoef(decayRate, targetRatioDR);
releaseCoef = calcCoef(releaseRate, targetRatioDR);
decayBase = (sustainLevel - targetRatioDR) * (1.0 - decayCoef);
releaseBase = -targetRatioDR * (1.0 - releaseCoef);
}
void ADSR::gate(bool gate) {
if (gate)
state = env_attack;
else if (state != env_idle)
state = env_release;
}
bool ADSR::inRelease(){
if (state==env_release){
inrelease=true;
}
else{
inrelease=false;
}
return inrelease;
}
int ADSR::getState() {
return state;
}
void ADSR::reset() {
state = env_idle;
output = 0.0;
}
float ADSR::process() {
int state_buffer=getState();
switch (state_buffer) {
case env_idle:
output=0.;
break;
case env_attack:
output = attackBase + output * attackCoef;
if (output >= 1.0) {
output = 1.0;
state = env_decay;
}
break;
case env_decay:
output = decayBase + output * decayCoef;
if (output <= sustainLevel) {
output = sustainLevel;
state = env_sustain;
}
break;
case env_sustain:
output=sustainLevel;
break;
case env_release:
output = releaseBase + output * releaseCoef;
if (output <= 0.0) {
output = 0.0;
state = env_idle;
}
break;
}
return output;
}
std::vector<sample_t> ADSR::getSamples(int nSamples) {
adsr.clear();
adsr.resize(nSamples);
for (unsigned int i=0;i<nSamples;i++){
adsr[i]=process();
}
return adsr;
}