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