-
Notifications
You must be signed in to change notification settings - Fork 0
/
SpaSynth.cpp
302 lines (251 loc) · 7.65 KB
/
SpaSynth.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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
#include "daisy_seed.h"
#include "daisysp.h"
// Use the daisy namespace to prevent having to type
// daisy:: before all libdaisy functions
using namespace daisy;
using namespace daisysp;
// Declare a DaisySeed object called hardware
DaisySeed hardware;
// Polyphony
const int VOICE_COUNT = 8;
const int STEP_COUNT = 32;
int steps[STEP_COUNT][VOICE_COUNT];
int current_voice = 0;
int step = 0;
// Notes/Scales
int base_note = 48; // C3
const int minor_scale[] = {0, 2, 3, 5, 7, 8, 10, 12};
// DSP
#define MAX_DELAY static_cast<size_t>(48000 * 2.0f)
DelayLine<float, MAX_DELAY> dl;
Metro clock;
Oscillator osc[VOICE_COUNT];
AdEnv env[VOICE_COUNT];
Svf flt[VOICE_COUNT];
Svf hp;
Oscillator mod_dl;
// Controls
AnalogControl controls[16];
Switch button1, button2, button3;
const int UPDATE_RATE = 4;
int update_step = 0;
// Parameters
Parameter clock_speed, note_spread, main_amp, atk, decay, filter_depth,
delay_time, delay_feedback, dl_mod_depth, dl_mod_freq;
;
void UpdateDigitalControls();
void UpdateParameters();
void TraverseQuintCircle();
void AdvanceSequencer();
void SetEnvelopeParameters();
void NextSamples(float &sig);
void AudioCallback(AudioHandle::InterleavingInputBuffer in,
AudioHandle::InterleavingOutputBuffer out,
size_t size)
{
float sig;
if(update_step == 0)
{
UpdateParameters();
}
update_step++;
update_step %= UPDATE_RATE;
UpdateDigitalControls();
AdvanceSequencer();
SetEnvelopeParameters();
if(button1.Pressed())
{
TraverseQuintCircle();
}
clock.SetFreq(clock_speed.Value());
sig = 0;
for(size_t i = 0; i < size; i += 2)
{
NextSamples(sig);
sig = tanh(sig);
hp.Process(sig);
sig = hp.High();
sig *= main_amp.Value();
out[i] = sig;
out[i + 1] = sig;
}
}
int main(void)
{
// Configure and Initialize the Daisy Seed
// These are separate to allow reconfiguration of any of the internal
// components before initialization.
hardware.Configure();
hardware.Init();
hardware.SetAudioBlockSize(1);
//How many samples we'll output per second
float samplerate = hardware.AudioSampleRate();
clock.Init(60 / 60, samplerate);
//Create an ADC configuration
AdcChannelConfig adcConfig[2];
adcConfig[0].InitMux(seed::A4, 8, seed::D20, seed::D21, seed::D22);
adcConfig[1].InitMux(seed::A11, 8, seed::D12, seed::D13, seed::D14);
//Initialize the buttons
button1.Init(seed::D25);
button2.Init(seed::D24);
button3.Init(seed::D23);
//Set the ADC to use our configuration
hardware.adc.Init(adcConfig, 2);
//Initialize the analog controls
int channel_idx = 0;
for(int i = 0; i < 16; i++)
{
if(i != 0 && i % 8 == 0)
{
channel_idx++;
}
controls[i].Init(hardware.adc.GetMuxPtr(channel_idx, i % 8),
samplerate / UPDATE_RATE,
false,
false,
0.1);
}
//Initialize the parameters
clock_speed.Init(
controls[8], 0.125 * STEP_COUNT, 10 * STEP_COUNT, Parameter::LINEAR);
note_spread.Init(controls[9], 0, 1, Parameter::LINEAR);
main_amp.Init(controls[10], 0, 1, Parameter::LINEAR);
atk.Init(controls[11], 0.01, 4, Parameter::EXPONENTIAL);
decay.Init(controls[12], 0.01, 8, Parameter::EXPONENTIAL);
filter_depth.Init(controls[13], 0, 4000, Parameter::EXPONENTIAL);
delay_time.Init(controls[14], 0, MAX_DELAY - 0.1f, Parameter::LINEAR);
delay_feedback.Init(controls[15], 0.001, 0.999, Parameter::LINEAR);
dl_mod_depth.Init(controls[0], 0, MAX_DELAY / 8, Parameter::EXPONENTIAL);
dl_mod_freq.Init(controls[1], 0.0001, 4, Parameter::LINEAR);
//Set up oscillators
for(int i = 0; i < VOICE_COUNT; i++)
{
osc[i].Init(samplerate);
osc[i].SetWaveform(osc[i].WAVE_SAW);
osc[i].SetAmp(1.f);
osc[i].SetFreq(1000);
}
mod_dl.Init(samplerate);
mod_dl.SetWaveform(mod_dl.WAVE_SIN);
mod_dl.SetAmp(1);
mod_dl.SetFreq(1);
//Set up volume envelopes
for(int i = 0; i < VOICE_COUNT; i++)
{
env[i].Init(samplerate);
env[i].SetTime(ADENV_SEG_ATTACK, .01);
env[i].SetTime(ADENV_SEG_DECAY, .4);
env[i].SetMin(0.0);
env[i].SetMax(1.f);
env[i].SetCurve(0);
}
//Set up filters
for(int i = 0; i < VOICE_COUNT; i++)
{
flt[i].Init(samplerate);
flt[i].SetFreq(1000);
flt[i].SetRes(0.5);
}
hp.Init(samplerate);
hp.SetFreq(20);
hp.SetRes(0.1);
// Initialize the delay line
dl.Init();
//Start the adc
hardware.adc.Start();
//Start calling the audio callback
hardware.StartAudio(AudioCallback);
// Loop forever
for(;;) {}
}
void UpdateDigitalControls()
{
// debounce Buttons
button1.Debounce();
button2.Debounce();
button3.Debounce();
}
void UpdateParameters()
{
clock_speed.Process();
note_spread.Process();
main_amp.Process();
atk.Process();
decay.Process();
filter_depth.Process();
delay_time.Process();
delay_feedback.Process();
dl_mod_depth.Process();
dl_mod_freq.Process();
}
void SetEnvelopeParameters()
{
for(int i = 0; i < VOICE_COUNT; i++)
{
env[i].SetTime(ADENV_SEG_ATTACK, atk.Value());
env[i].SetTime(ADENV_SEG_DECAY, decay.Value());
}
}
void AdvanceSequencer()
{
if(clock.Process())
{
// if step == 0 repopulate steps
if(step == 0)
{
int rand_note = rand() / ((RAND_MAX + 1u) / 8);
int current_base_note = base_note + minor_scale[rand_note];
steps[0][current_voice] = current_base_note;
current_voice++;
current_voice %= VOICE_COUNT;
int max_offset = floor((STEP_COUNT - 1) * note_spread.Value()) + 1;
int rand_step = rand() / ((RAND_MAX + 1u) / max_offset);
steps[rand_step][current_voice]
= current_base_note + minor_scale[(rand_note + 2) % 8];
current_voice++;
current_voice %= VOICE_COUNT;
rand_step = rand() / ((RAND_MAX + 1u) / max_offset);
steps[rand_step][current_voice]
= current_base_note + minor_scale[(rand_note + 4) % 8];
current_voice++;
current_voice %= VOICE_COUNT;
}
// trigger notes
for(int i = 0; i < VOICE_COUNT; i++)
{
int current_note = steps[step][i];
if(current_note > 0)
{
osc[i].SetFreq(mtof(current_note));
env[i].Trigger();
steps[step][i] = 0;
}
}
// advance step
step++;
step %= STEP_COUNT;
}
}
void NextSamples(float &sig)
{
for(int i = 0; i < VOICE_COUNT; i++)
{
float env_out = env[i].Process();
osc[i].SetAmp(env_out);
float current_sig = osc[i].Process() * 0.5f;
flt[i].SetFreq(200 + (env_out * filter_depth.Value()));
flt[i].Process(current_sig);
sig += flt[i].Low() * 0.6f;
}
mod_dl.SetFreq(dl_mod_freq.Value());
float mod_sig = (mod_dl.Process() / 2) + 1;
dl.SetDelay(delay_time.Value() - (dl_mod_depth.Value() * mod_sig));
float delay_sig = sig + dl.Read();
dl.Write(delay_sig * delay_feedback.Value());
sig = delay_sig;
}
void TraverseQuintCircle()
{
base_note += 7;
base_note %= 127;
}