-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathVoice.cpp
128 lines (102 loc) · 2.79 KB
/
Voice.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
#include "StdAfx.h"
#include "Voice.h"
#include "OscillatorNote.h"
#include "Filter.h"
#include "Amplifier.h"
#include "Control.h"
// current note assignemnts
// (via keyboard or midi input)
unsigned char voice_note[VOICES];
unsigned char voice_vel[VOICES];
unsigned char note_voice[NOTES];
// most recent voice triggered
int voice_most_recent;
// most recent note key pressed
// (via keyboard or midi input)
int note_most_recent;
// choose a voice
int ChooseVoice(int note)
{
int voice = -1;
// quietest voice
int quietest_voice = -1;
float quietest_amplitude = FLT_MAX;
// find a voice to use
for (int v = 0; v < VOICES; ++v)
{
// if retriggering the voice or the voice is currently off...
if (voice_note[v] == note || amp_env_state[v].state == EnvelopeState::OFF)
{
// use this voice
voice = v;
break;
}
// if the voice is quieter than the current quietest...
if (amp_env_state[v].amplitude < quietest_amplitude)
{
// use that
quietest_voice = v;
quietest_amplitude = amp_env_state[v].amplitude;
}
}
// use the quietest voice if not already assigned a voice
if (voice < 0)
{
voice = quietest_voice;
}
return voice;
}
// note frequency
float NoteFrequency(int note, float follow)
{
float const base = (note - 60) / 12.0f + Control::pitch_offset;
return powf(2, follow * base) * middle_c_frequency;
}
// note on
int NoteOn(int note, int velocity)
{
// choose a voice
int voice = ChooseVoice(note);
if (voice < 0)
return voice;
// set most recent voice and note
voice_most_recent = voice;
note_most_recent = note;
// set voice note
voice_note[voice] = unsigned char(note);
note_voice[note] = unsigned char(voice);
// set voice velocity
voice_vel[voice] = unsigned char(velocity);
// start the oscillator
// (assume restart on key)
for (int o = 0; o < NUM_OSCILLATORS; ++o)
osc_state[voice][o].Start();
// start the filter
flt_state[voice].Reset();
// if the volume envelope is off, reset the filter envelope
// (it should be free-running instead)
if (amp_env_state[voice].state == EnvelopeState::OFF)
{
flt_env_state[voice].state = EnvelopeState::OFF;
flt_env_state[voice].amplitude = 0;
}
// gate the volume envelope
amp_env_state[voice].Gate(amp_env_config, true);
// gate the filter envelope
flt_env_state[voice].Gate(flt_env_config, true);
return voice;
}
// note off
int NoteOff(int note, int velocity)
{
// find the voice for the note
int voice = note_voice[note];
if (voice < 0)
return voice;
// TO DO: use note-off velocity
// gate the volume envelope
amp_env_state[voice].Gate(amp_env_config, false);
// gate the filter envelope
flt_env_state[voice].Gate(flt_env_config, false);
return voice;
}