-
Notifications
You must be signed in to change notification settings - Fork 1
/
EnvelopeGenerator.cpp
115 lines (107 loc) · 3.58 KB
/
EnvelopeGenerator.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
#include "EnvelopeGenerator.h"
double EnvelopeGenerator::sampleRate = 44100.0;
double EnvelopeGenerator::nextSample() {
if (currentStage != ENVELOPE_STAGE_OFF &&
currentStage != ENVELOPE_STAGE_SUSTAIN) {
if (currentSampleIndex == nextStageSampleIndex) {
EnvelopeStage newStage = static_cast<EnvelopeStage>(
(currentStage + 1) % kNumEnvelopeStages
);
enterStage(newStage);
}
currentLevel *= multiplier;
currentSampleIndex++;
}
return currentLevel;
}
void EnvelopeGenerator::calculateMultiplier(double startLevel,
double endLevel,
unsigned long long lengthInSamples) {
multiplier = 1.0 + ( log(endLevel) - log(startLevel)) / (lengthInSamples);
}
void EnvelopeGenerator::enterStage(EnvelopeStage newStage) {
if (currentStage == newStage) return;
if (currentStage == ENVELOPE_STAGE_OFF) {
beganEnvelopeCycle();
}
if (newStage == ENVELOPE_STAGE_OFF) {
finishedEnvelopeCycle();
}
currentStage = newStage;
currentSampleIndex = 0;
if (currentStage == ENVELOPE_STAGE_OFF ||
currentStage == ENVELOPE_STAGE_SUSTAIN) {
nextStageSampleIndex = 0;
} else {
nextStageSampleIndex = stageValue[currentStage] * sampleRate;
}
switch (newStage) {
case ENVELOPE_STAGE_OFF:
currentLevel = 0.0;
multiplier = 1.0;
break;
case ENVELOPE_STAGE_ATTACK:
currentLevel = minimumLevel;
calculateMultiplier(currentLevel, 1.0, nextStageSampleIndex);
break;
case ENVELOPE_STAGE_DECAY:
currentLevel = 1.0;
calculateMultiplier(currentLevel, fmax(stageValue[ENVELOPE_STAGE_SUSTAIN], minimumLevel), nextStageSampleIndex);
break;
case ENVELOPE_STAGE_SUSTAIN:
currentLevel = stageValue[ENVELOPE_STAGE_SUSTAIN];
multiplier = 1.0;
break;
case ENVELOPE_STAGE_RELEASE:
// we could go from ATTACK/DECAY to RELEASE,
// so we're not chaning currentLevel here.
calculateMultiplier(currentLevel, minimumLevel, nextStageSampleIndex);
break;
default:
break;
}
}
void EnvelopeGenerator::setSampleRate(double newSampleRate) {
sampleRate = newSampleRate;
}
void EnvelopeGenerator::setStageValue(EnvelopeStage stage, double value) {
stageValue[stage] = value;
if (stage == currentStage) {
// Re-calculate the multiplier and nextStageSampleIndex
if (currentStage == ENVELOPE_STAGE_ATTACK ||
currentStage == ENVELOPE_STAGE_DECAY ||
currentStage == ENVELOPE_STAGE_RELEASE) {
double nextLevelValue;
switch (currentStage) {
case ENVELOPE_STAGE_ATTACK:
nextLevelValue = 1.0;
break;
case ENVELOPE_STAGE_DECAY:
nextLevelValue = fmax(stageValue[ENVELOPE_STAGE_SUSTAIN], minimumLevel);
break;
case ENVELOPE_STAGE_RELEASE:
nextLevelValue = minimumLevel;
break;
default:
break;
}
// How far the generator is into the current stage:
double currentStageProcess = (currentSampleIndex + 0.0) / nextStageSampleIndex;
// How much of the current stage is left:
double remainingStageProcess = 1.0 - currentStageProcess;
unsigned long long samplesUntilNextStage = remainingStageProcess * value * sampleRate;
nextStageSampleIndex = currentSampleIndex + samplesUntilNextStage;
calculateMultiplier(currentLevel, nextLevelValue, samplesUntilNextStage);
}
else if (currentStage == ENVELOPE_STAGE_SUSTAIN) {
currentLevel = value;
}
}
if (currentStage == ENVELOPE_STAGE_DECAY &&
stage == ENVELOPE_STAGE_SUSTAIN) {
// We have to decay to a different sustain value than before.
// Re-calculate multiplier
unsigned long long samplesUntilNextStage = nextStageSampleIndex - currentSampleIndex;
calculateMultiplier(currentLevel, fmax(stageValue[ENVELOPE_STAGE_SUSTAIN], minimumLevel), samplesUntilNextStage);
}
}