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