1 // Copyright 2011 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 // -----------------------------------------------------------------------------
17 //
18 // Pattern generator.
19 //
20 // OUTPUT MODE  OUTPUT CLOCK  BIT7  BIT6  BIT5  BIT4  BIT3  BIT2  BIT1  BIT0
21 // DRUMS        FALSE          RND   CLK  HHAC  SDAC  BDAC    HH    SD    BD
22 // DRUMS        TRUE           RND   CLK   CLK   BAR   ACC    HH    SD    BD
23 // EUCLIDEAN    FALSE          RND   CLK  RST3  RST2  RST1  EUC3  EUC2  EUC1
24 // EUCLIDEAN    TRUE           RND   CLK   CLK  STEP   RST  EUC3  EUC2  EUC1
25 
26 #ifndef GRIDS_PATTERN_GENERATOR_H_
27 #define GRIDS_PATTERN_GENERATOR_H_
28 
29 #include <string.h>
30 
31 #include "avrlib/base.h"
32 #include "avrlib/random.h"
33 
34 #include "grids/hardware_config.h"
35 
36 namespace grids {
37 
38 const uint8_t kNumParts = 3;
39 const uint8_t kPulsesPerStep = 3;  // 24 ppqn ; 8 steps per quarter note.
40 const uint8_t kStepsPerPattern = 32;
41 const uint8_t kPulseDuration = 8;  // 8 ticks of the main clock.
42 
43 struct DrumsSettings {
44   uint8_t x;
45   uint8_t y;
46   uint8_t randomness;
47 };
48 
49 struct PatternGeneratorSettings {
50   union Options {
51     DrumsSettings drums;
52     uint8_t euclidean_length[kNumParts];
53   } options;
54   uint8_t density[kNumParts];
55 };
56 
57 enum OutputMode {
58   OUTPUT_MODE_EUCLIDEAN,
59   OUTPUT_MODE_DRUMS
60 };
61 
62 enum ClockResolution {
63   CLOCK_RESOLUTION_4_PPQN,
64   CLOCK_RESOLUTION_8_PPQN,
65   CLOCK_RESOLUTION_24_PPQN,
66   CLOCK_RESOLUTION_LAST
67 };
68 
69 enum OutputBits {
70   OUTPUT_BIT_COMMON = 0x08,
71   OUTPUT_BIT_CLOCK = 0x10,
72   OUTPUT_BIT_RESET = 0x20
73 };
74 
75 struct Options {
76   ClockResolution clock_resolution;
77   OutputMode output_mode;
78   bool output_clock;
79   bool tap_tempo;
80   bool gate_mode;
81   bool swing;
82 
packOptions83   uint8_t pack() const {
84     uint8_t byte = clock_resolution;
85     if (!swing) {
86       byte |= 0x08;
87     }
88     if (tap_tempo) {
89       byte |= 0x10;
90     }
91     if (output_clock) {
92       byte |= 0x20;
93     }
94     if (output_mode == OUTPUT_MODE_DRUMS) {
95       byte |= 0x40;
96     }
97     if (!gate_mode) {
98       byte |= 0x80;
99     }
100     return byte;
101   }
102 
unpackOptions103   void unpack(uint8_t byte) {
104     tap_tempo = byte & 0x10;
105     output_clock = byte & 0x20;
106     output_mode = byte & 0x40 ? OUTPUT_MODE_DRUMS : OUTPUT_MODE_EUCLIDEAN;
107     gate_mode = !(byte & 0x80);
108     swing = !(byte & 0x08);
109     clock_resolution = static_cast<ClockResolution>(byte & 0x7);
110     if (clock_resolution >= CLOCK_RESOLUTION_24_PPQN) {
111       clock_resolution = CLOCK_RESOLUTION_24_PPQN;
112     }
113   }
114 };
115 
116 class PatternGenerator {
117  public:
PatternGenerator()118   PatternGenerator() { }
~PatternGenerator()119   ~PatternGenerator() { }
120 
Init()121   static inline void Init() {
122     LoadSettings();
123     Reset();
124   }
125 
Reset()126   static inline void Reset() {
127     step_ = 0;
128     pulse_ = 0;
129     memset(euclidean_step_, 0, sizeof(euclidean_step_));
130   }
131 
Retrigger()132   static inline void Retrigger() {
133     Evaluate();
134   }
135 
TickClock(uint8_t num_pulses)136   static inline void TickClock(uint8_t num_pulses) {
137     Evaluate();
138     beat_ = (step_ & 0x7) == 0;
139     first_beat_ = step_ == 0;
140 
141     pulse_ += num_pulses;
142 
143     // Wrap into ppqn steps.
144     while (pulse_ >= kPulsesPerStep) {
145       pulse_ -= kPulsesPerStep;
146       if (!(step_ & 1)) {
147         for (uint8_t i = 0; i < kNumParts; ++i) {
148           ++euclidean_step_[i];
149         }
150       }
151       ++step_;
152     }
153 
154     // Wrap into step sequence steps.
155     if (step_ >= kStepsPerPattern) {
156       step_ -= kStepsPerPattern;
157     }
158   }
159 
state()160   static inline uint8_t state() {
161     return state_;
162   }
step()163   static inline uint8_t step() { return step_; }
164 
swing()165   static inline bool swing() { return options_.swing; }
166   static int8_t swing_amount();
output_clock()167   static inline bool output_clock() { return options_.output_clock; }
tap_tempo()168   static inline bool tap_tempo() { return options_.tap_tempo; }
gate_mode()169   static inline bool gate_mode() { return options_.gate_mode; }
output_mode()170   static inline OutputMode output_mode() { return options_.output_mode; }
clock_resolution()171   static inline ClockResolution clock_resolution() { return options_.clock_resolution; }
172 
set_swing(uint8_t value)173   static void set_swing(uint8_t value) { options_.swing = value; }
set_output_clock(uint8_t value)174   static void set_output_clock(uint8_t value) { options_.output_clock = value; }
set_tap_tempo(uint8_t value)175   static void set_tap_tempo(uint8_t value) { options_.tap_tempo = value; }
set_output_mode(uint8_t value)176   static void set_output_mode(uint8_t value) {
177     options_.output_mode = static_cast<OutputMode>(value);
178   }
set_clock_resolution(uint8_t value)179   static void set_clock_resolution(uint8_t value) {
180     if (value >= CLOCK_RESOLUTION_24_PPQN) {
181       value = CLOCK_RESOLUTION_24_PPQN;
182     }
183     options_.clock_resolution = static_cast<ClockResolution>(value);
184   }
set_gate_mode(bool gate_mode)185   static void set_gate_mode(bool gate_mode) {
186     options_.gate_mode = gate_mode;
187   }
188 
IncrementPulseCounter()189   static inline void IncrementPulseCounter() {
190     ++pulse_duration_counter_;
191     // Zero all pulses after 1ms.
192     if (pulse_duration_counter_ >= kPulseDuration && !options_.gate_mode) {
193       state_ = 0;
194       // Possible mod: the extra random pulse is not reset, and its behaviour
195       // is more similar to that of a S&H.
196       //state_ &= 0x80;
197     }
198   }
199 
ClockFallingEdge()200   static inline void ClockFallingEdge() {
201     if (options_.gate_mode) {
202       state_ = 0;
203     }
204   }
205 
mutable_settings()206   static inline PatternGeneratorSettings* mutable_settings() {
207     return &settings_;
208   }
209 
on_first_beat()210   static bool on_first_beat() { return first_beat_; }
on_beat()211   static bool on_beat() { return beat_; }
factory_testing()212   static bool factory_testing() { return factory_testing_ < 5; }
213 
214   static void SaveSettings();
215 
led_pattern()216   static inline uint8_t led_pattern() {
217     uint8_t result = 0;
218     if (state_ & 1) {
219       result |= LED_BD;
220     }
221     if (state_ & 2) {
222       result |= LED_SD;
223     }
224     if (state_ & 4) {
225       result |= LED_HH;
226     }
227     return result;
228   }
229 
230  private:
231   static void LoadSettings();
232   static void Evaluate();
233   static void EvaluateEuclidean();
234   static void EvaluateDrums();
235 
236   static uint8_t ReadDrumMap(
237       uint8_t step,
238       uint8_t instrument,
239       uint8_t x,
240       uint8_t y);
241 
242   static Options options_;
243 
244   static uint8_t pulse_;
245   static uint8_t step_;
246   static uint8_t euclidean_step_[kNumParts];
247   static bool first_beat_;
248   static bool beat_;
249 
250   static uint8_t state_;
251   static uint8_t part_perturbation_[kNumParts];
252 
253   static uint8_t pulse_duration_counter_;
254 
255   static uint8_t factory_testing_;
256 
257   static PatternGeneratorSettings settings_;
258 
259   DISALLOW_COPY_AND_ASSIGN(PatternGenerator);
260 };
261 
262 extern PatternGenerator pattern_generator;
263 
264 }  // namespace grids
265 
266 #endif // GRIDS_PATTERN_GENERATOR_H_
267