-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathEnvelope.cpp
118 lines (107 loc) · 2.97 KB
/
Envelope.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
/*
MINI VIRTUAL ANALOG SYNTHESIZER
Copyright 2014 Kenneth D. Miller III
Envelope Generator
*/
#include "StdAfx.h"
#include "Envelope.h"
#include "Math.h"
#include "Voice.h"
// envelope bias values to make the exponential decay arrive in finite time
// the attack part is set up to be more linear (and shorter) than the decay/release part
static const float ENV_ATTACK_CONSTANT = 1.0f;
static const float ENV_DECAY_CONSTANT = 3.0f;
static float const ENV_ATTACK_BIAS = 1.0f / (1.0f - expf(-ENV_ATTACK_CONSTANT)) - 1.0f;
static float const ENV_DECAY_BIAS = 1.0f - 1.0f / (1.0f - expf(-ENV_DECAY_CONSTANT));
// envelope config constructor
EnvelopeConfig::EnvelopeConfig(bool const enable, float const attack_time, float const decay_time, float const sustain_level, float const release_time)
: enable(enable)
, attack_time(attack_time)
, attack_rate(1 / (attack_time + FLT_MIN))
, decay_time(decay_time)
, decay_rate(1 / (decay_time + FLT_MIN))
, sustain_level(sustain_level)
, release_time(release_time)
, release_rate(1 / (release_time + FLT_MIN))
{
}
// envelope state constructor
EnvelopeState::EnvelopeState()
: gate(false)
, state(OFF)
, amplitude(0.0f)
{
}
// gate envelope generator
void EnvelopeState::Gate(EnvelopeConfig const &config, bool on)
{
if (gate == on)
return;
gate = on;
if (gate)
{
if (config.enable && config.attack_time)
state = EnvelopeState::ATTACK;
else if (config.enable && config.decay_time)
state = EnvelopeState::DECAY, amplitude = 1;
else
state = EnvelopeState::SUSTAIN, amplitude = config.sustain_level;
}
else
{
if (config.enable && config.release_time)
state = EnvelopeState::RELEASE;
else
state = EnvelopeState::OFF, amplitude = 0;
}
}
// update envelope generator
float EnvelopeState::Update(EnvelopeConfig const &config, float const step)
{
if (!config.enable)
return gate;
float env_target;
switch (state)
{
case ATTACK:
env_target = 1.0f + ENV_ATTACK_BIAS;
amplitude += (env_target - amplitude) * config.attack_rate * step;
if (amplitude >= 1.0f)
{
amplitude = 1.0f;
if (config.sustain_level < 1.0f)
state = DECAY;
else
state = SUSTAIN;
}
break;
case DECAY:
env_target = config.sustain_level + (1.0f - config.sustain_level) * ENV_DECAY_BIAS;
amplitude += (env_target - amplitude) * config.decay_rate * step;
if (amplitude <= config.sustain_level)
{
amplitude = config.sustain_level;
state = SUSTAIN;
}
break;
case RELEASE:
env_target = ENV_DECAY_BIAS;
if (amplitude <= config.sustain_level || config.decay_rate < config.release_rate)
{
amplitude += (env_target - amplitude) * config.release_rate * step;
}
else
{
amplitude += (env_target - amplitude) * config.decay_rate * step;
if (amplitude <= config.sustain_level)
amplitude = config.sustain_level;
}
if (amplitude <= 0.0f)
{
amplitude = 0.0f;
state = OFF;
}
break;
}
return amplitude;
}