1 // Copyright 2017 Emilie Gillet.
2 //
3 // Author: Emilie Gillet (emilie.o.gillet@gmail.com)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // THE SOFTWARE.
22 //
23 // See http://creativecommons.org/licenses/MIT/ for more information.
24
25 #include <stm32f37x_conf.h>
26
27 #include "stmlib/dsp/dsp.h"
28
29 #include "stmlib/dsp/dsp.h"
30 #include "stmlib/dsp/units.h"
31 #include "stages/chain_state.h"
32 #include "stages/drivers/dac.h"
33 #include "stages/drivers/gate_inputs.h"
34 #include "stages/drivers/serial_link.h"
35 #include "stages/drivers/system.h"
36 #include "stages/cv_reader.h"
37 #include "stages/factory_test.h"
38 #include "stages/io_buffer.h"
39 #include "stages/oscillator.h"
40 #include "stages/resources.h"
41 #include "stages/segment_generator.h"
42 #include "stages/settings.h"
43 #include "stages/ui.h"
44
45 using namespace stages;
46 using namespace std;
47 using namespace stmlib;
48
49 const bool skip_factory_test = false;
50 const bool test_adc_noise = false;
51
52 ChainState chain_state;
53 CvReader cv_reader;
54 Dac dac;
55 FactoryTest factory_test;
56 GateFlags no_gate[kBlockSize];
57 GateInputs gate_inputs;
58 SegmentGenerator segment_generator[kNumChannels];
59 Oscillator oscillator[kNumChannels];
60 IOBuffer io_buffer;
61 SerialLink left_link;
62 SerialLink right_link;
63 Settings settings;
64 Ui ui;
65
66 // Default interrupt handlers.
67 extern "C" {
68
NMI_Handler()69 void NMI_Handler() { }
HardFault_Handler()70 void HardFault_Handler() { while (1); }
MemManage_Handler()71 void MemManage_Handler() { while (1); }
BusFault_Handler()72 void BusFault_Handler() { while (1); }
UsageFault_Handler()73 void UsageFault_Handler() { while (1); }
SVC_Handler()74 void SVC_Handler() { }
DebugMon_Handler()75 void DebugMon_Handler() { }
PendSV_Handler()76 void PendSV_Handler() { }
77
78 }
79
80 // SysTick and 32kHz handles
81 extern "C" {
82
SysTick_Handler()83 void SysTick_Handler() {
84 IWDG_ReloadCounter();
85 ui.Poll();
86 if (!skip_factory_test) {
87 factory_test.Poll();
88 }
89 }
90
91 }
92
FillBuffer(size_t size)93 IOBuffer::Slice FillBuffer(size_t size) {
94 IOBuffer::Slice s = io_buffer.NextSlice(size);
95 gate_inputs.Read(s, size);
96 if (io_buffer.new_block()) {
97 cv_reader.Read(s.block);
98 gate_inputs.ReadNormalization(s.block);
99 }
100 return s;
101 }
102
103 SegmentGenerator::Output out[kBlockSize];
104
105 static float note_lp[kNumChannels] = { 0, 0, 0, 0, 0, 0 };
106
Process(IOBuffer::Block * block,size_t size)107 void Process(IOBuffer::Block* block, size_t size) {
108 chain_state.Update(
109 *block,
110 &settings,
111 &segment_generator[0],
112 out);
113 for (size_t channel = 0; channel < kNumChannels; ++channel) {
114 bool led_state = segment_generator[channel].Process(
115 block->input_patched[channel] ? block->input[channel] : no_gate,
116 out,
117 size);
118 ui.set_slider_led(channel, led_state, 5);
119
120 if (test_adc_noise) {
121 float note = block->cv_slider[channel];
122 ONE_POLE(note_lp[channel], note, 0.0001f);
123 float cents = (note - note_lp[channel]) * 1200.0f * 0.5f;
124 CONSTRAIN(cents, -1.0f, +1.0f)
125 for (size_t i = 0; i < size; ++i) {
126 out[i].value = cents;
127 }
128 }
129
130 for (size_t i = 0; i < size; ++i) {
131 block->output[channel][i] = settings.dac_code(channel, out[i].value);
132 }
133 }
134 }
135
136
137 float ouroboros_ratios[] = {
138 0.25f, 0.5f, 1.0f, 1.5f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 8.0f, 8.0f
139 };
140
141 float this_channel[kBlockSize];
142 float sum[kBlockSize];
143 float channel_amplitude[kNumChannels];
144 float previous_amplitude[kNumChannels];
145
ProcessOuroboros(IOBuffer::Block * block,size_t size)146 void ProcessOuroboros(IOBuffer::Block* block, size_t size) {
147 const float coarse = (block->cv_slider[0] - 0.5f) * 96.0f;
148 const float fine = block->pot[0] * 2.0f - 1.0f;
149 const float f0 = SemitonesToRatio(coarse + fine) * 261.6255f / kSampleRate;
150
151 std::fill(&sum[0], &sum[size], 0.0f);
152
153 for (int channel = kNumChannels - 1; channel >= 0; --channel) {
154
155 const float harmonic = block->pot[channel] * 9.999f;
156 MAKE_INTEGRAL_FRACTIONAL(harmonic);
157 harmonic_fractional = 8.0f * (harmonic_fractional - 0.5f) + 0.5f;
158 CONSTRAIN(harmonic_fractional, 0.0f, 1.0f);
159 const float ratio = channel == 0 ? 1.0f : Crossfade(
160 ouroboros_ratios[harmonic_integral],
161 ouroboros_ratios[harmonic_integral + 1],
162 harmonic_fractional);
163 const float amplitude = channel == 0
164 ? 1.0f
165 : std::max(block->cv_slider[channel], 0.0f);
166 bool trigger = false;
167 for (size_t i = 0; i < size; ++i) {
168 trigger = trigger || (block->input[channel][i] & GATE_FLAG_RISING);
169 }
170 if (trigger || !block->input_patched[channel]) {
171 channel_amplitude[channel] = 1.0f;
172 } else {
173 channel_amplitude[channel] *= 0.999f;
174 }
175 ui.set_slider_led(
176 channel, channel_amplitude[channel] * amplitude > 0.00001f, 1);
177 const float f = f0 * ratio;
178
179 uint8_t waveshape = settings.state().segment_configuration[channel];
180 switch (waveshape) {
181 case 0:
182 oscillator[channel].Render<OSCILLATOR_SHAPE_SINE>(
183 f, 0.5f, this_channel, size);
184 break;
185 case 1:
186 oscillator[channel].Render<OSCILLATOR_SHAPE_TRIANGLE>(
187 f, 0.5f, this_channel, size);
188 break;
189 case 2:
190 case 3:
191 oscillator[channel].Render<OSCILLATOR_SHAPE_SQUARE>(
192 f, 0.5f, this_channel, size);
193 break;
194 case 4:
195 oscillator[channel].Render<OSCILLATOR_SHAPE_SAW>(
196 f, 0.5f, this_channel, size);
197 break;
198 case 5:
199 oscillator[channel].Render<OSCILLATOR_SHAPE_SQUARE>(
200 f, 0.75f, this_channel, size);
201 break;
202 case 6:
203 case 7:
204 oscillator[channel].Render<OSCILLATOR_SHAPE_SQUARE>(
205 f, 0.9f, this_channel, size);
206 break;
207 }
208
209 ParameterInterpolator am(
210 &previous_amplitude[channel],
211 amplitude * amplitude * channel_amplitude[channel],
212 size);
213 for (size_t i = 0; i < size; ++i) {
214 sum[i] += this_channel[i] * am.Next();
215 }
216
217 const float gain = channel == 0 ? 0.2f : 0.66f;
218 const float* source = channel == 0 ? sum : this_channel;
219 for (size_t i = 0; i < size; ++i) {
220 block->output[channel][i] = settings.dac_code(channel, source[i] * gain);
221 }
222 }
223 }
224
Init()225 void Init() {
226 System sys;
227 sys.Init(true);
228 dac.Init(int(kSampleRate), 2);
229 gate_inputs.Init();
230 io_buffer.Init();
231
232 bool freshly_baked = !settings.Init();
233 for (size_t i = 0; i < kNumChannels; ++i) {
234 segment_generator[i].Init();
235 oscillator[i].Init();
236 }
237 std::fill(&no_gate[0], &no_gate[kBlockSize], GATE_FLAG_LOW);
238
239 cv_reader.Init(&settings);
240
241 ui.Init(&settings, &chain_state);
242
243 if (freshly_baked && !skip_factory_test) {
244 factory_test.Start(&settings, &cv_reader, &gate_inputs, &ui);
245 ui.set_factory_test(true);
246 } else {
247 chain_state.Init(&left_link, &right_link);
248 }
249
250 sys.StartTimers();
251 dac.Start(&FillBuffer);
252 }
253
main(void)254 int main(void) {
255 Init();
256 while (1) {
257 io_buffer.Process(factory_test.running()
258 ? &FactoryTest::ProcessFn
259 : (chain_state.ouroboros() ? &ProcessOuroboros : &Process));
260 }
261 }
262