1 // Copyright 2012 Emilie Gillet.
2 //
3 // Author: Emilie Gillet (emilie.o.gillet@gmail.com)
4 //
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16 #include <avr/eeprom.h>
17
18 #include "avrlib/adc.h"
19 #include "avrlib/boot.h"
20 #include "avrlib/op.h"
21 #include "avrlib/watchdog_timer.h"
22
23 #include "grids/clock.h"
24 #include "grids/hardware_config.h"
25 #include "grids/pattern_generator.h"
26
27 using namespace avrlib;
28 using namespace grids;
29
30 Leds leds;
31 Inputs inputs;
32 AdcInputScanner adc;
33 ShiftRegister shift_register;
34 MidiInput midi;
35
36 enum Parameter {
37 PARAMETER_NONE,
38 PARAMETER_WAITING,
39 PARAMETER_CLOCK_RESOLUTION,
40 PARAMETER_TAP_TEMPO,
41 PARAMETER_SWING,
42 PARAMETER_GATE_MODE,
43 PARAMETER_OUTPUT_MODE,
44 PARAMETER_CLOCK_OUTPUT
45 };
46
47 uint32_t tap_duration = 0;
48 uint8_t led_pattern ;
49 uint8_t led_off_timer;
50
51 int8_t swing_amount;
52
53 volatile Parameter parameter = PARAMETER_NONE;
54 volatile bool long_press_detected = false;
55 const uint8_t kUpdatePeriod = F_CPU / 32 / 8000;
56
UpdateLeds()57 inline void UpdateLeds() {
58 uint8_t pattern;
59 if (parameter == PARAMETER_NONE) {
60 if (led_off_timer) {
61 --led_off_timer;
62 if (!led_off_timer) {
63 led_pattern = 0;
64 }
65 }
66 pattern = led_pattern;
67 if (pattern_generator.tap_tempo()) {
68 if (pattern_generator.on_beat()) {
69 pattern |= LED_CLOCK;
70 }
71 } else {
72 if (pattern_generator.on_first_beat()) {
73 pattern |= LED_CLOCK;
74 }
75 }
76 } else {
77 pattern = LED_CLOCK;
78 switch (parameter) {
79 case PARAMETER_CLOCK_RESOLUTION:
80 pattern |= LED_BD >> pattern_generator.clock_resolution();
81 break;
82
83 case PARAMETER_CLOCK_OUTPUT:
84 if (pattern_generator.output_clock()) {
85 pattern |= LED_ALL;
86 }
87 break;
88
89 case PARAMETER_SWING:
90 if (pattern_generator.swing()) {
91 pattern |= LED_ALL;
92 }
93 break;
94
95 case PARAMETER_OUTPUT_MODE:
96 if (pattern_generator.output_mode() == OUTPUT_MODE_DRUMS) {
97 pattern |= LED_ALL;
98 }
99 break;
100
101 case PARAMETER_TAP_TEMPO:
102 if (pattern_generator.tap_tempo()) {
103 pattern |= LED_ALL;
104 }
105 break;
106
107 case PARAMETER_GATE_MODE:
108 if (pattern_generator.gate_mode()) {
109 pattern |= LED_ALL;
110 }
111 }
112 }
113 leds.Write(pattern);
114 }
115
UpdateShiftRegister()116 inline void UpdateShiftRegister() {
117 static uint8_t previous_state = 0;
118 if (pattern_generator.state() != previous_state) {
119 previous_state = pattern_generator.state();
120 shift_register.Write(previous_state);
121 if (!previous_state) {
122 // Switch off the LEDs, but not now.
123 led_off_timer = 200;
124 } else {
125 // Switch on the LEDs with a new pattern.
126 led_pattern = pattern_generator.led_pattern();
127 led_off_timer = 0;
128 }
129 }
130 }
131
132 uint8_t ticks_granularity[] = { 6, 3, 1 };
133
HandleClockResetInputs()134 inline void HandleClockResetInputs() {
135 static uint8_t previous_inputs;
136
137 uint8_t inputs_value = ~inputs.Read();
138 uint8_t num_ticks = 0;
139 uint8_t increment = ticks_granularity[pattern_generator.clock_resolution()];
140
141 // CLOCK
142 if (clock.bpm() < 40 && !clock.locked()) {
143 if ((inputs_value & INPUT_CLOCK) && !(previous_inputs & INPUT_CLOCK)) {
144 num_ticks = increment;
145 }
146 if (!(inputs_value & INPUT_CLOCK) && (previous_inputs & INPUT_CLOCK)) {
147 pattern_generator.ClockFallingEdge();
148 }
149 if (midi.readable()) {
150 uint8_t byte = midi.ImmediateRead();
151 if (byte == 0xf8) {
152 num_ticks = 1;
153 } else if (byte == 0xfa) {
154 pattern_generator.Reset();
155 }
156 }
157 } else {
158 clock.Tick();
159 clock.Wrap(swing_amount);
160 if (clock.raising_edge()) {
161 num_ticks = increment;
162 }
163 if (clock.past_falling_edge()) {
164 pattern_generator.ClockFallingEdge();
165 }
166 }
167
168 // RESET
169 if ((inputs_value & INPUT_RESET) && !(previous_inputs & INPUT_RESET)) {
170 pattern_generator.Reset();
171
172 // !! HACK AHEAD !!
173 //
174 // Earlier versions of the firmware retriggered the outputs whenever a
175 // RESET signal was received. This allowed for nice drill'n'bass effects,
176 // but made synchronization with another sequencer a bit glitchy (risk of
177 // double notes at the beginning of a pattern). It was later decided
178 // to remove this behaviour and make the RESET transparent (just set the
179 // step index without producing any trigger) - similar to the MIDI START
180 // message. However, the factory testing script relies on the old behaviour.
181 // To solve this problem, we reproduce this behaviour the first 5 times the
182 // module is powered. After the 5th power-on (or settings change) cycle,
183 // this odd behaviour disappears.
184 if (pattern_generator.factory_testing() ||
185 clock.bpm() >= 40 ||
186 clock.locked()) {
187 pattern_generator.Retrigger();
188 clock.Reset();
189 }
190 }
191 previous_inputs = inputs_value;
192
193 if (num_ticks) {
194 swing_amount = pattern_generator.swing_amount();
195 pattern_generator.TickClock(num_ticks);
196 }
197 }
198
199 enum SwitchState {
200 SWITCH_STATE_JUST_PRESSED = 0xfe,
201 SWITCH_STATE_PRESSED = 0x00,
202 SWITCH_STATE_JUST_RELEASED = 0x01,
203 SWITCH_STATE_RELEASED = 0xff
204 };
205
HandleTapButton()206 inline void HandleTapButton() {
207 static uint8_t switch_state = 0xff;
208 static uint16_t switch_hold_time = 0;
209
210 switch_state = switch_state << 1;
211 if (inputs.Read() & INPUT_SW_RESET) {
212 switch_state |= 1;
213 }
214
215 if (switch_state == SWITCH_STATE_JUST_PRESSED) {
216 if (parameter == PARAMETER_NONE) {
217 if (!pattern_generator.tap_tempo()) {
218 pattern_generator.Reset();
219 if (pattern_generator.factory_testing() ||
220 clock.bpm() >= 40 ||
221 clock.locked()) {
222 clock.Reset();
223 }
224 } else {
225 uint32_t new_bpm = (F_CPU * 60L) / (32L * kUpdatePeriod * tap_duration);
226 if (new_bpm >= 30 && new_bpm <= 480) {
227 clock.Update(new_bpm, pattern_generator.clock_resolution());
228 clock.Reset();
229 clock.Lock();
230 } else {
231 clock.Unlock();
232 }
233 tap_duration = 0;
234 }
235 }
236 switch_hold_time = 0;
237 } else if (switch_state == SWITCH_STATE_PRESSED) {
238 ++switch_hold_time;
239 if (switch_hold_time == 500) {
240 long_press_detected = true;
241 }
242 }
243 }
244
ISR(TIMER2_COMPA_vect,ISR_NOBLOCK)245 ISR(TIMER2_COMPA_vect, ISR_NOBLOCK) {
246 static uint8_t switch_debounce_prescaler;
247
248 ++tap_duration;
249 ++switch_debounce_prescaler;
250 if (switch_debounce_prescaler >= 10) {
251 // Debounce RESET/TAP switch and perform switch action.
252 HandleTapButton();
253 switch_debounce_prescaler = 0;
254 }
255
256 HandleClockResetInputs();
257 adc.Scan();
258
259 pattern_generator.IncrementPulseCounter();
260 UpdateShiftRegister();
261 UpdateLeds();
262 }
263
264 static int16_t pot_values[8];
265
ScanPots()266 void ScanPots() {
267 if (long_press_detected) {
268 if (parameter == PARAMETER_NONE) {
269 // Freeze pot values
270 for (uint8_t i = 0; i < 8; ++i) {
271 pot_values[i] = adc.Read8(i);
272 }
273 parameter = PARAMETER_WAITING;
274 } else {
275 parameter = PARAMETER_NONE;
276 pattern_generator.SaveSettings();
277 }
278 long_press_detected = false;
279 }
280
281 if (parameter == PARAMETER_NONE) {
282 uint8_t bpm = adc.Read8(ADC_CHANNEL_TEMPO);
283 bpm = U8U8MulShift8(bpm, 220) + 20;
284 if (bpm != clock.bpm() && !clock.locked()) {
285 clock.Update(bpm, pattern_generator.clock_resolution());
286 }
287 PatternGeneratorSettings* settings = pattern_generator.mutable_settings();
288 settings->options.drums.x = ~adc.Read8(ADC_CHANNEL_X_CV);
289 settings->options.drums.y = ~adc.Read8(ADC_CHANNEL_Y_CV);
290 settings->options.drums.randomness = ~adc.Read8(ADC_CHANNEL_RANDOMNESS_CV);
291 settings->density[0] = ~adc.Read8(ADC_CHANNEL_BD_DENSITY_CV);
292 settings->density[1] = ~adc.Read8(ADC_CHANNEL_SD_DENSITY_CV);
293 settings->density[2] = ~adc.Read8(ADC_CHANNEL_HH_DENSITY_CV);
294 } else {
295 for (uint8_t i = 0; i < 8; ++i) {
296 int16_t value = adc.Read8(i);
297 int16_t delta = value - pot_values[i];
298 if (delta < 0) {
299 delta = -delta;
300 }
301 if (delta > 32) {
302 pot_values[i] = value;
303 switch (i) {
304 case ADC_CHANNEL_BD_DENSITY_CV:
305 parameter = PARAMETER_CLOCK_RESOLUTION;
306 pattern_generator.set_clock_resolution((255 - value) >> 6);
307 clock.Update(clock.bpm(), pattern_generator.clock_resolution());
308 pattern_generator.Reset();
309 break;
310
311 case ADC_CHANNEL_SD_DENSITY_CV:
312 parameter = PARAMETER_TAP_TEMPO;
313 pattern_generator.set_tap_tempo(!(value & 0x80));
314 if (!pattern_generator.tap_tempo()) {
315 clock.Unlock();
316 }
317 break;
318
319 case ADC_CHANNEL_HH_DENSITY_CV:
320 parameter = PARAMETER_SWING;
321 pattern_generator.set_swing(!(value & 0x80));
322 break;
323
324 case ADC_CHANNEL_X_CV:
325 parameter = PARAMETER_OUTPUT_MODE;
326 pattern_generator.set_output_mode(!(value & 0x80) ? 1 : 0);
327 break;
328
329 case ADC_CHANNEL_Y_CV:
330 parameter = PARAMETER_GATE_MODE;
331 pattern_generator.set_gate_mode(!(value & 0x80));
332 break;
333
334 case ADC_CHANNEL_RANDOMNESS_CV:
335 parameter = PARAMETER_CLOCK_OUTPUT;
336 pattern_generator.set_output_clock(!(value & 0x80));
337 break;
338 }
339 }
340 }
341 }
342 }
343
Init()344 void Init() {
345 sei();
346 UCSR0B = 0;
347
348 leds.set_mode(DIGITAL_OUTPUT);
349 inputs.set_mode(DIGITAL_INPUT);
350 inputs.EnablePullUpResistors();
351
352 clock.Init();
353 adc.Init();
354 adc.set_num_inputs(ADC_CHANNEL_LAST);
355 Adc::set_reference(ADC_DEFAULT);
356 Adc::set_alignment(ADC_LEFT_ALIGNED);
357 pattern_generator.Init();
358 shift_register.Init();
359 midi.Init();
360
361 TCCR2A = _BV(WGM21);
362 TCCR2B = 3;
363 OCR2A = kUpdatePeriod - 1;
364 TIMSK2 |= _BV(1);
365 }
366
main(void)367 int main(void) {
368 ResetWatchdog();
369 Init();
370 clock.Update(120, pattern_generator.clock_resolution());
371 while (1) {
372 // Use any spare cycles to read the CVs and update the potentiometers
373 ScanPots();
374 }
375 }
376