├── .gitattributes ├── .gitignore ├── DualDisplayDriver.cpp ├── DualDisplayDriver.h ├── Engine.cpp ├── Engine.h ├── GlobalScales.cpp ├── GlobalScales.h ├── GlobalTranspositionTables.cpp ├── GlobalTranspositionTables.h ├── Memory.cpp ├── Memory.h ├── MetaSequencer.ino ├── Output.cpp ├── Output.h ├── README.md ├── Rand.cpp ├── Rand.h ├── RotaryEncoder.cpp ├── RotaryEncoder.h ├── Sequencer.cpp ├── Sequencer.h ├── Snapshot.cpp ├── Snapshot.h ├── SwitchInput.cpp ├── SwitchInput.h ├── Transposer.cpp ├── Transposer.h ├── TriggerInput.cpp ├── TriggerInput.h └── defines.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | -------------------------------------------------------------------------------- /DualDisplayDriver.cpp: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include "DualDisplayDriver.h" 3 | 4 | DualDisplayDriver::DualDisplayDriver(uint8_t i2c_address, Snapshot *snapshot) 5 | { 6 | this->i2c_address = i2c_address; 7 | this->snapshot = snapshot; 8 | } 9 | 10 | void DualDisplayDriver::init() 11 | { 12 | 13 | for(uint8_t digit=0; digit<8; digit++) 14 | { 15 | digits[digit] = 0; 16 | } 17 | 18 | // Reset chip (Why? I have no idea.) 19 | Wire.beginTransmission(0x00); 20 | Wire.write(0x0C); 21 | Wire.write(0x01 | 0x01); 22 | Wire.endTransmission(); 23 | 24 | // Set display driver I2C address 25 | Wire.beginTransmission(0x00); // Default I2C address 26 | Wire.write(0x2D); // Command to set self addressing register 27 | Wire.write(i2c_address); // Value of new I2C address 28 | Wire.endTransmission(); 29 | 30 | delay(20); 31 | 32 | // Decode modes and hex codes 33 | // 34 | // 0x00 = No decode for digits 7:0 35 | // 0x01 = Code-B/HEX decode for digit 0. No decodee for digits 7:1 36 | // 0x07 = Code-B/HEX decode for digit 0:2. No decodee for digits 7:3 37 | // 0x3F = Code-B/HEX decode for digit 0:5. No decodee for digits 7:6 38 | // 0x25 = Code-B/HEX decode for digit 0,2,5. No decodee for digits 1,3,4,6,7 39 | // 40 | // Set decode mode 41 | Wire.beginTransmission(i2c_address); 42 | Wire.write(0x09); // Command to set decode mode 43 | Wire.write(0x00); // No decode for digits 7:0 44 | Wire.endTransmission(); 45 | 46 | // Set global intensity 47 | Wire.beginTransmission(i2c_address); 48 | Wire.write(0x0A); // Command to set intensity control register (globally) 49 | Wire.write(this->snapshot->display_intensity); // Intensity: range: 0x00, 0x01, 0x02... 0x0F 50 | Wire.endTransmission(); 51 | 52 | // Set scan limit (which digits should be displayed) 53 | Wire.beginTransmission(i2c_address); 54 | Wire.write(0x0B); // Command to set scan limit 55 | Wire.write(0x07); // Display digits 0:7 56 | Wire.endTransmission(); 57 | 58 | // Shutdown modes and hex codes: 59 | // 60 | // 0x00 = Shutdown Mode, Reset Feature Register to Default Settings 61 | // 0x80 = Shutdown Mode, Feature Register Unchanged 62 | // 0x01 = Normal Operation, Reset Feature Register To Default Settings 63 | // 0x81 = Normal Operation, Feature Register Unchanged 64 | // 65 | // Set shutdown mode 66 | Wire.beginTransmission(i2c_address); 67 | Wire.write(0x0C); // Command to set Shutdown Register 68 | Wire.write(0x01); // Set to normal operation, reset feature register 69 | Wire.endTransmission(); 70 | 71 | } 72 | 73 | void DualDisplayDriver::setIntensity(uint8_t intensity) // 0 - 16 74 | { 75 | if(this->snapshot->display_intensity != intensity) 76 | { 77 | this->intensity = intensity; 78 | 79 | this->snapshot->setDisplayIntensity(intensity); 80 | 81 | Wire.beginTransmission(i2c_address); 82 | Wire.write(0x0A); // Command to set intensity control register (globally) 83 | Wire.write(intensity); // Intensity: range: 0x00, 0x01, 0x02... 0x0F 84 | Wire.endTransmission(); 85 | } 86 | } 87 | 88 | void DualDisplayDriver::write(uint8_t display, uint16_t value) 89 | { 90 | if(display == DISPLAY_A) 91 | { 92 | this->writeDigit(0, value / 1000); 93 | this->writeDigit(1, (value / 100) % 10); 94 | this->writeDigit(2, (value / 10) % 10); 95 | this->writeDigit(3, value % 10); 96 | } 97 | 98 | if(display == DISPLAY_B) 99 | { 100 | this->writeDigit(4, value / 1000); 101 | this->writeDigit(5, (value / 100) % 10); 102 | this->writeDigit(6, (value / 10) % 10); 103 | this->writeDigit(7, value % 10); 104 | } 105 | } 106 | 107 | void DualDisplayDriver::writeSetting(uint8_t display, uint16_t value, byte byte_code) 108 | { 109 | if(display == DISPLAY_A) 110 | { 111 | this->writeByteCode(0, byte_code); 112 | this->writeDigit(1, (value / 100) % 10); 113 | this->writeDigit(2, (value / 10) % 10); 114 | this->writeDigit(3, value % 10); 115 | } 116 | 117 | if(display == DISPLAY_B) 118 | { 119 | this->writeByteCode(4, byte_code); 120 | this->writeDigit(5, (value / 100) % 10); 121 | this->writeDigit(6, (value / 10) % 10); 122 | this->writeDigit(7, value % 10); 123 | } 124 | } 125 | 126 | void DualDisplayDriver::writeDigit(byte digit, byte value) 127 | { 128 | byte byte_code = this->byte_codes[value]; 129 | this->writeByteCode(digit, byte_code); 130 | } 131 | 132 | void DualDisplayDriver::writeByteCode(byte digit, byte byte_code) 133 | { 134 | if(digits[digit] != byte_code) 135 | { 136 | Wire.beginTransmission(i2c_address); 137 | Wire.write(digit + 1); 138 | Wire.write(byte_code); 139 | Wire.endTransmission(); 140 | 141 | digits[digit] = byte_code; 142 | } 143 | } -------------------------------------------------------------------------------- /DualDisplayDriver.h: -------------------------------------------------------------------------------- 1 | #ifndef DualDisplayDriver_h 2 | #define DualDisplayDriver_h 3 | 4 | #define DISPLAY_A 0 5 | #define DISPLAY_B 1 6 | 7 | #include "Arduino.h" 8 | #include 9 | #include "defines.h" 10 | #include "Snapshot.h" 11 | 12 | class DualDisplayDriver 13 | { 14 | public: 15 | DualDisplayDriver(uint8_t i2c_address, Snapshot *snapshot); 16 | void init(); 17 | void write(uint8_t display, uint16_t value); 18 | void writeSetting(uint8_t display, uint16_t value, byte byte_code); 19 | void writeDigit(byte digit, byte value); 20 | void writeByteCode(byte digit, byte byte_code); 21 | void setIntensity(uint8_t intensity); // 0-16 22 | 23 | uint8_t i2c_address; 24 | uint8_t intensity = 15; 25 | 26 | Snapshot *snapshot; 27 | 28 | // The digits array is used to prevent redundant updates 29 | // of the bubble display digits. 30 | byte digits[8]; 31 | 32 | byte byte_codes[10] = { 33 | 0b01111110, // 0 34 | 0b00110000, // 1 35 | 0b01101101, // 2 36 | 0b01111001, // 3 37 | 0b00110011, // 4 38 | 0b01011011, // 5 39 | 0b01011111, // 6 40 | 0b01110000, // 7 41 | 0b01111111, // 8 42 | 0b01111011 // 9 43 | }; 44 | 45 | // 0b01110111, // A 46 | // 0b01001110, // C 47 | // 0b00001101, // c 48 | // 0b00111101, // d 49 | // 0b01000111, // F 50 | // 0b00110111, // H 51 | // 0b00010111, // h 52 | // 0b00010000, // i 53 | // 0b01001111, // E 54 | // 0b00001110, // L 55 | // 0b00011101, // o 56 | // 0b01100111, // P 57 | 58 | // 0b00000101, // r 59 | // 0b01011011, // S 60 | // 0b00001111, // t 61 | // 0b00010101, // n 62 | // 0b01111011, // g 63 | // 0b00111110, // V 64 | // 0b00011100, // v 65 | 66 | }; 67 | 68 | #endif -------------------------------------------------------------------------------- /Engine.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Engine.cpp 4 | 5 | Contains all of the sequencer logic, input handline, etc. This is the 6 | brains of the operation. All of the non-volitile variables used by this 7 | script are stored in Snapshot.php. It was originally programmed such that 8 | multiple 'snapshots' could be supported, but because of the very limited memory 9 | in the Arduino Nano, this feature was never added. 10 | 11 | */ 12 | 13 | #include "Arduino.h" 14 | #include "Engine.h" 15 | 16 | Engine::Engine() 17 | { 18 | rnd = new Rand(); 19 | rnd->seed(millis()); 20 | 21 | // Memory, and display objects (I2C devices) 22 | memory = new Memory(EEPROM_I2C_ADDRESS); 23 | 24 | snapshot = new Snapshot(memory); 25 | 26 | dual_display_driver = new DualDisplayDriver(DISPLAY_I2C_ADDRESS, snapshot); 27 | 28 | sequencer = new Sequencer(); 29 | transposer = new Transposer(snapshot); 30 | transposer2 = new Transposer(snapshot); 31 | 32 | transposer2->clock_division = 2; 33 | 34 | // Rotary encoder objects 35 | step_encoder = new RotaryEncoder(A0, A1, A2); // top encoder 36 | value_encoder = new RotaryEncoder(8, 9, 10); // bottom encoder 37 | 38 | // Trigger input objects 39 | clock_button = new TriggerInput(PIN_CLOCK_BUTTON); 40 | clock_input = new TriggerInput(PIN_CLOCK_INPUT); 41 | reset_button = new TriggerInput(PIN_RESET_BUTTON); 42 | reset_input = new TriggerInput(PIN_RESET_INPUT); 43 | 44 | // Change the reset and clock input's debounce time to a 45 | // slim 1 millilsecond. (The default is 50 milliseconds, 46 | // which is fine for pushbuttons, but too slow for other uses.) 47 | reset_input->setDebounce(1); 48 | clock_input->setDebounce(1); 49 | 50 | // Mode switch 51 | mode_switch = new SwitchInput(PIN_SWITCH_A, PIN_SWITCH_B); 52 | 53 | // Output object 54 | output = new Output(DAC_I2C_ADDRESS, snapshot, transposer, transposer2); 55 | 56 | } 57 | 58 | void Engine::init() 59 | { 60 | // I2C setup 61 | Wire.begin(); 62 | 63 | snapshot->init(); 64 | step_encoder->init(); 65 | value_encoder->init(); 66 | sequencer->init(); 67 | 68 | // Initialize display driver and set displays 69 | dual_display_driver->init(); 70 | 71 | // Test to see if the reset button is being held or 72 | // if the initialized flag is not set to "22" in memory. 73 | // If either is true, initialize the unit by setting all values to 0, 74 | // the length to 8, and the clock division to 1. 75 | 76 | uint8_t self_initialization_flag = memory->read(MEM_ADDR_SELF_INITIALIZATION); 77 | 78 | if(reset_button->read() || self_initialization_flag != 22) 79 | { 80 | this->factoryReset(); 81 | memory->write(MEM_ADDR_SELF_INITIALIZATION, 22); 82 | } 83 | 84 | // Initialize rotary encoder sensitivity values 85 | z_sequence_length = snapshot->sequence_length << 1; 86 | z_clock_division = snapshot->clock_division << 1; 87 | z_scale = snapshot->scale << 1; 88 | z_intensity = snapshot->display_intensity << 1; 89 | z_hold = snapshot->hold << 1; 90 | z_song = snapshot->song << 1; 91 | z_song2 = snapshot->song2 << 1; 92 | z_hold_offset = snapshot->hold_offset << 1; 93 | hold_threshold = snapshot->hold_threshold; // Full sensitivity! 94 | 95 | // Show a welcome message very briefly 96 | dual_display_driver->writeByteCode(0, __H__); // H 97 | dual_display_driver->writeByteCode(1, __E__); // E 98 | dual_display_driver->writeByteCode(2, __L__); // L 99 | dual_display_driver->writeByteCode(3, __O__); // O 100 | 101 | // Firmware version 102 | dual_display_driver->writeDigit(4, 1); // 1 103 | dual_display_driver->writeByteCode(5, __underscore__); // _ 104 | dual_display_driver->writeDigit(6, 0); // 0 105 | dual_display_driver->writeDigit(7, 0); // 1 106 | 107 | delay(500); 108 | 109 | value = snapshot->sequence[step]; 110 | output->write(value); 111 | } 112 | 113 | void Engine::loop() 114 | { 115 | mode_switch->poll(); 116 | 117 | // Reading the value encoder is done once, here, for efficiency. 118 | value_encoder_button_pressed = value_encoder->readButton(); 119 | 120 | switch(mode_switch->position) 121 | { 122 | case 1: 123 | mode = SETTINGS_MODE; 124 | break; 125 | case 2: 126 | if(mode != SEQUENCE_EDIT_MODE) 127 | { 128 | edit_step = step; 129 | edit_value = snapshot->sequence[step]; 130 | mode = SEQUENCE_EDIT_MODE; 131 | } 132 | break; 133 | case 3: 134 | if(mode != SEQUENCE_PLAYBACK_MODE) 135 | { 136 | value = snapshot->sequence[step]; 137 | mode = SEQUENCE_PLAYBACK_MODE; 138 | } 139 | break; 140 | } 141 | 142 | switch(mode) 143 | { 144 | case SEQUENCE_PLAYBACK_MODE: 145 | this->sequencePlaybackMode(); 146 | break; 147 | case SEQUENCE_EDIT_MODE: 148 | this->sequenceEditMode(); 149 | break; 150 | case SETTINGS_MODE: 151 | this->settingsMode(); 152 | break; 153 | } 154 | 155 | // Constantly playback when clocked, independent of the mode 156 | this->playback(); 157 | } 158 | 159 | // 160 | // Engine::playback() 161 | // 162 | // This method is called every loop cycle. It's in charge of keeping the 163 | // sequence playing. Not to be confused with playback_mode, which is the mode 164 | // where users can watch the sequence playback. 165 | // 166 | 167 | void Engine::playback() 168 | { 169 | clock_input->poll(); 170 | reset_input->poll(); 171 | 172 | if(reset_input->triggered) 173 | { 174 | if(snapshot->rst_input_assignment == RST_ASSIGNMENT_RESET) 175 | { 176 | step = 0; 177 | sequencer->resetDrift(); 178 | transposer->reset(); 179 | transposer2->reset(); 180 | value = snapshot->sequence[step]; 181 | output->write(value); 182 | } 183 | else // if(rst_input_assignment == RST_ASSIGNMENT_SAMPLE_AND_HOLD) 184 | { 185 | sample = true; 186 | } 187 | } 188 | 189 | // Step the sequencer using either the clock button or clock input 190 | if(clock_input->triggered) 191 | { 192 | // Step the internal clock variable 193 | clock_counter = clock_counter + 1; 194 | 195 | // Once the clock division has been reached, increment the step variable 196 | if(clock_counter >= snapshot->clock_division) 197 | { 198 | if(snapshot->slip == 0 || (rnd->random(100) > snapshot->slip)) // if no slip 199 | { 200 | // Step sequencer 201 | step = step + 1; 202 | 203 | if(step >= snapshot->sequence_length) 204 | { 205 | step = 0; 206 | 207 | // Step transposers 208 | transposer->clock(); 209 | transposer2->clock(); 210 | } 211 | 212 | // Apply drift 213 | if(snapshot->drift_percentage && (rnd->random(100) < snapshot->drift_percentage)) 214 | { 215 | sequencer->drift[step] = sequencer->drift[step] + ((int) rnd->random(snapshot->drift_amount << 1)) - snapshot->drift_amount; 216 | } 217 | } 218 | 219 | // 220 | // This large if-statement is saying, in English: 221 | // 222 | // "If the sequence value at the (current step + the hold offset) is greater than the hold_cutoff, 223 | // then go ahead an play the next note. Otherwise hold the current note." 224 | // 225 | 226 | if((snapshot->rst_input_assignment != RST_ASSIGNMENT_SAMPLE_AND_HOLD) && snapshot->sequence[((step + snapshot->hold_offset) % snapshot->sequence_length)] > snapshot->hold_threshold) 227 | { 228 | sample = true; 229 | } 230 | 231 | if(sample == true) 232 | { 233 | // Get the value from the sequencer 234 | value = snapshot->sequence[step]; 235 | drift = sequencer->drift[step]; 236 | 237 | // int32_t total = value + drift; 238 | // total = constrain(total, 0, 4095); 239 | 240 | if((mode == SEQUENCE_PLAYBACK_MODE) && value_encoder_button_pressed) 241 | { 242 | // do not play output while realtime recording in playback mode 243 | } 244 | else 245 | { 246 | output->write(constrain(value + drift, 0, 4095)); 247 | } 248 | 249 | sample = false; 250 | } 251 | 252 | // Reset clock_counter 253 | clock_counter = 0; 254 | } 255 | } 256 | 257 | 258 | } 259 | 260 | // 261 | // Engine::sequencePlaybackMode() 262 | // 263 | // This mode lets the user to watch the sequence playback on the bubble displays. 264 | // The user can manually reset the sequence in this mode using the reset button. 265 | // The user can manually step the sequence in this mode using the step button. 266 | // Neither of the rotary encoders do anything in this mode. 267 | // 268 | 269 | void Engine::sequencePlaybackMode() 270 | { 271 | // Poll buttons 272 | clock_button->poll(); 273 | reset_button->poll(); 274 | 275 | // Step the sequencer using the clock button 276 | if(clock_button->triggered) 277 | { 278 | step = (step + 1) % snapshot->sequence_length; 279 | 280 | transposer->step(); 281 | transposer2->step(); 282 | 283 | clock_counter = 0; 284 | 285 | // Get the value from the sequencer 286 | value = snapshot->sequence[step]; 287 | drift = sequencer->drift[step]; 288 | 289 | int32_t total = value + drift; 290 | total = constrain(total, 0, 4095); 291 | 292 | output->write(total); 293 | } 294 | 295 | if(reset_button->triggered) 296 | { 297 | step = 0; 298 | clock_counter = 0; 299 | sequencer->resetDrift(); 300 | transposer->reset(); 301 | transposer2->reset(); 302 | value = snapshot->sequence[step]; 303 | output->write(value); 304 | } 305 | 306 | // Handle realtime recording 307 | if(value_encoder_button_pressed) 308 | { 309 | // Just been pressed? 310 | if(value_encoder->pressed()) 311 | { 312 | realtime_recording_value = 0; 313 | } 314 | 315 | realtime_recording_value = (realtime_recording_value + (value_encoder->read() * 100)); 316 | realtime_recording_value = constrain(realtime_recording_value, 0, 4095); 317 | 318 | value = realtime_recording_value; 319 | 320 | // Update the sequencer with the new value 321 | snapshot->setValue(step, realtime_recording_value); 322 | 323 | output->write(realtime_recording_value); 324 | } 325 | 326 | dual_display_driver->write(TOP_DISPLAY, step + 1); 327 | dual_display_driver->write(BOTTOM_DISPLAY, value); 328 | } 329 | 330 | // 331 | // Engine::sequencePlaybackMode() 332 | // 333 | // This mode lets the user to edit the sequencer values. 334 | // The top knob selects the step. 335 | // The bottom knob selects the value. 336 | // 337 | 338 | void Engine::sequenceEditMode() 339 | { 340 | // Poll buttons 341 | clock_button->poll(); 342 | reset_button->poll(); 343 | 344 | int16_t step_acceleration = 1; 345 | int16_t value_acceleration = 1; 346 | 347 | if(step_encoder->readButton() && (snapshot->sequence_length > 16)) step_acceleration = 10; 348 | 349 | if(snapshot->press_functionality == PRESS_ASSIGNMENT_FINE) value_acceleration = 100; 350 | 351 | if(value_encoder_button_pressed) 352 | { 353 | if(snapshot->press_functionality == PRESS_ASSIGNMENT_FINE) 354 | { 355 | value_acceleration = 1; 356 | } 357 | else 358 | { 359 | value_acceleration = 100; 360 | } 361 | } 362 | 363 | z_edit_step = (z_edit_step + (step_encoder->read() * step_acceleration)); 364 | 365 | // Step the sequencer using the clock button 366 | if(clock_button->triggered) z_edit_step += 2; 367 | if(reset_button->triggered) z_edit_step -= 2; 368 | 369 | z_edit_step = constrain(z_edit_step, 0, (snapshot->sequence_length << 1) - 1); 370 | 371 | uint16_t edit_step = z_edit_step >> 1; 372 | 373 | // Get the value from the sequencer 374 | edit_value = snapshot->sequence[edit_step]; 375 | 376 | // Read value encoder and adjust value (bottom knob/display) 377 | edit_value = (edit_value + (value_encoder->read() * value_acceleration)); 378 | edit_value = constrain(edit_value, 0, 4095); 379 | 380 | // Update the sequencer with the new value 381 | snapshot->setValue(edit_step, edit_value); 382 | 383 | dual_display_driver->write(TOP_DISPLAY, edit_step + 1); 384 | dual_display_driver->write(BOTTOM_DISPLAY, edit_value); 385 | } 386 | 387 | // 388 | // Engine::settingsMode() 389 | // 390 | // This mode lets the user to edit the module's settings. 391 | // Settings are organized into pages, which are selected via the 392 | // top rotary encoder or the step button. 393 | // 394 | 395 | void Engine::settingsMode() 396 | { 397 | // Sequence length 398 | if(settings_page == 0) 399 | { 400 | int sequence_length_acceleration = 1; 401 | 402 | // Rotary encoder buttons are used for input accelleration 403 | if(value_encoder_button_pressed) sequence_length_acceleration = 20; 404 | 405 | // Set sequence length 406 | // 407 | // The variable 'z_sequence_length. is 2X the sequence length, and controls 408 | // the sensitivity of the rotary encoder, which can be too sensitive at times. 409 | 410 | z_sequence_length = z_sequence_length + (value_encoder->read() * sequence_length_acceleration); 411 | z_sequence_length = constrain(z_sequence_length, 2, MAX_SEQUENCE_LENGTH << 1); 412 | 413 | uint16_t sequence_length = z_sequence_length >> 1; 414 | 415 | snapshot->setSequenceLength(sequence_length); 416 | 417 | // Update displays 418 | dual_display_driver->writeByteCode(0, __L__); // L 419 | dual_display_driver->writeByteCode(1, __E__); // E 420 | dual_display_driver->writeByteCode(2, __n__); // n 421 | dual_display_driver->writeByteCode(3, __g__); // g 422 | 423 | dual_display_driver->write(BOTTOM_DISPLAY, sequence_length); 424 | } 425 | 426 | // Clock division settings 427 | if(settings_page == 1) 428 | { 429 | int clock_division_acceleration = 1; 430 | 431 | // Rotary encoder buttons are used for input accelleration 432 | if(value_encoder_button_pressed) clock_division_acceleration = 20; 433 | 434 | // Set clock division 435 | z_clock_division = z_clock_division + (value_encoder->read() * clock_division_acceleration); 436 | z_clock_division = constrain(z_clock_division, 2, 512 << 1); 437 | 438 | uint16_t clock_division = z_clock_division >> 1; 439 | 440 | snapshot->setClockDivision(clock_division); 441 | 442 | // Update displays 443 | dual_display_driver->writeByteCode(0, __C__); // c 444 | dual_display_driver->writeByteCode(1, __d__); // d 445 | dual_display_driver->writeByteCode(2, __i__); // i 446 | dual_display_driver->writeByteCode(3, __v__); // v 447 | 448 | dual_display_driver->write(BOTTOM_DISPLAY, clock_division); 449 | } 450 | 451 | // Scale settings 452 | if(settings_page == 2) 453 | { 454 | // Set scale 455 | z_scale = z_scale + (value_encoder->read()); 456 | z_scale = constrain(z_scale, 0, NUMBER_OF_SCALES << 1); 457 | 458 | uint16_t scale = z_scale >> 1; 459 | 460 | snapshot->setScale(scale); 461 | 462 | dual_display_driver->writeByteCode(0, __S__); // S 463 | dual_display_driver->writeByteCode(1, __C__); // C 464 | dual_display_driver->writeByteCode(2, __A__); // A 465 | dual_display_driver->writeByteCode(3, __L__); // L 466 | 467 | switch(scale) { 468 | case 0: // None 469 | dual_display_driver->writeByteCode(4, __n__); 470 | dual_display_driver->writeByteCode(5, __o__); 471 | dual_display_driver->writeByteCode(6, __n__); 472 | dual_display_driver->writeByteCode(7, __E__); 473 | break; 474 | case 1: // MAJOR 475 | dual_display_driver->writeByteCode(4, __M__); 476 | dual_display_driver->writeByteCode(5, __A__); 477 | dual_display_driver->writeByteCode(6, __j__); 478 | dual_display_driver->writeByteCode(7, __o__); 479 | break; 480 | case 2: // MINOR 481 | dual_display_driver->writeByteCode(4, __M__); 482 | dual_display_driver->writeByteCode(5, __i__); 483 | dual_display_driver->writeByteCode(6, __n__); 484 | dual_display_driver->writeByteCode(7, __o__); 485 | break; 486 | case 3: // IONIAN 487 | dual_display_driver->writeByteCode(4, __i__); 488 | dual_display_driver->writeByteCode(5, __o__); 489 | dual_display_driver->writeByteCode(6, __n__); 490 | dual_display_driver->writeByteCode(7, __i__); 491 | break; 492 | case 4: // DORIAN 493 | dual_display_driver->writeByteCode(4, __d__); 494 | dual_display_driver->writeByteCode(5, __o__); 495 | dual_display_driver->writeByteCode(6, __r__); 496 | dual_display_driver->writeByteCode(7, __i__); 497 | break; 498 | case 5: // LYDIAN 499 | dual_display_driver->writeByteCode(4, __L__); 500 | dual_display_driver->writeByteCode(5, __Y__); 501 | dual_display_driver->writeByteCode(6, __d__); 502 | dual_display_driver->writeByteCode(7, __I__); 503 | break; 504 | case 6: // PHRYGIAN 505 | dual_display_driver->writeByteCode(4, __P__); 506 | dual_display_driver->writeByteCode(5, __H__); 507 | dual_display_driver->writeByteCode(6, __r__); 508 | dual_display_driver->writeByteCode(7, __Y__); 509 | break; 510 | case 7: // MIXOLYDIAN 511 | dual_display_driver->writeByteCode(4, __M__); 512 | dual_display_driver->writeByteCode(5, __o__); 513 | dual_display_driver->writeByteCode(6, __L__); 514 | dual_display_driver->writeByteCode(7, __Y__); 515 | break; 516 | case 8: // AEOLIAN 517 | dual_display_driver->writeByteCode(4, __A__); 518 | dual_display_driver->writeByteCode(5, __E__); 519 | dual_display_driver->writeByteCode(6, __O__); 520 | dual_display_driver->writeByteCode(7, __L__); 521 | break; 522 | case 9: // LOCRIAN 523 | dual_display_driver->writeByteCode(4, __L__); 524 | dual_display_driver->writeByteCode(5, __o__); 525 | dual_display_driver->writeByteCode(6, __c__); 526 | dual_display_driver->writeByteCode(7, __r__); 527 | break; 528 | case 10: // MAJOR_PENTATONIC 529 | dual_display_driver->writeByteCode(4, __M__); 530 | dual_display_driver->writeByteCode(5, __a__); 531 | dual_display_driver->writeByteCode(6, __j__); 532 | dual_display_driver->writeByteCode(7, __P__); 533 | break; 534 | case 11: // MINOR_PENTATONIC 535 | dual_display_driver->writeByteCode(4, __M__); 536 | dual_display_driver->writeByteCode(5, __i__); 537 | dual_display_driver->writeByteCode(6, __n__); 538 | dual_display_driver->writeByteCode(7, __P__); 539 | break; 540 | case 12: // DIMINISHED 541 | dual_display_driver->writeByteCode(4, __d__); 542 | dual_display_driver->writeByteCode(5, __i__); 543 | dual_display_driver->writeByteCode(6, __m__); 544 | dual_display_driver->writeByteCode(7, __i__); 545 | break; 546 | case 13: // CHROMATIC 547 | dual_display_driver->writeByteCode(4, __c__); 548 | dual_display_driver->writeByteCode(5, __h__); 549 | dual_display_driver->writeByteCode(6, __r__); 550 | dual_display_driver->writeByteCode(7, __o__); 551 | break; 552 | case 14: // GATE 553 | dual_display_driver->writeByteCode(4, __g__); 554 | dual_display_driver->writeByteCode(5, __A__); 555 | dual_display_driver->writeByteCode(6, __t__); 556 | dual_display_driver->writeByteCode(7, __E__); 557 | break; 558 | } 559 | 560 | // dual_display_driver->write(BOTTOM_DISPLAY, scale); 561 | } 562 | 563 | // Randomize 564 | if(settings_page == 3) 565 | { 566 | dual_display_driver->writeByteCode(0, __r__); // r 567 | dual_display_driver->writeByteCode(1, __A__); // A 568 | dual_display_driver->writeByteCode(2, __n__); // n 569 | dual_display_driver->writeByteCode(3, __d__); // d 570 | 571 | dual_display_driver->writeByteCode(4, __dash__); // - 572 | dual_display_driver->writeByteCode(5, __dash__); // - 573 | dual_display_driver->writeByteCode(6, __dash__); // - 574 | dual_display_driver->writeByteCode(7, __dash__); // - 575 | 576 | if(value_encoder->pressed()) 577 | { 578 | dual_display_driver->writeByteCode(4, 0b01001110); // [ 579 | dual_display_driver->writeByteCode(5, 0b01001000); // = 580 | dual_display_driver->writeByteCode(6, 0b01001000); // = 581 | dual_display_driver->writeByteCode(7, 0b01111000); // ] 582 | 583 | for(uint8_t i=0; irandom(4096); 587 | snapshot->setValue(i, value); 588 | } 589 | 590 | dual_display_driver->writeByteCode(4, __dash__); // - 591 | dual_display_driver->writeByteCode(5, __dash__); // - 592 | dual_display_driver->writeByteCode(6, __dash__); // - 593 | dual_display_driver->writeByteCode(7, __dash__); // - 594 | } 595 | } 596 | 597 | // Clear 598 | if(settings_page == 4) 599 | { 600 | dual_display_driver->writeByteCode(0, __C__); // C 601 | dual_display_driver->writeByteCode(1, __L__); // L 602 | dual_display_driver->writeByteCode(2, __E__); // E 603 | dual_display_driver->writeByteCode(3, __r__); // r 604 | 605 | dual_display_driver->writeByteCode(4, __dash__); // - 606 | dual_display_driver->writeByteCode(5, __dash__); // - 607 | dual_display_driver->writeByteCode(6, __dash__); // - 608 | dual_display_driver->writeByteCode(7, __dash__); // - 609 | 610 | if(value_encoder->pressed()) 611 | { 612 | dual_display_driver->writeByteCode(4, 0b01001110); // [ 613 | dual_display_driver->writeByteCode(5, 0b01001000); // = 614 | dual_display_driver->writeByteCode(6, 0b01001000); // = 615 | dual_display_driver->writeByteCode(7, 0b01111000); // ] 616 | 617 | // Load sequence from non-volitile ram 618 | for(int i=0; isetValue(i, 0); 621 | } 622 | 623 | dual_display_driver->writeByteCode(4, __dash__); // - 624 | dual_display_driver->writeByteCode(5, __dash__); // - 625 | dual_display_driver->writeByteCode(6, __dash__); // - 626 | dual_display_driver->writeByteCode(7, __dash__); // - 627 | } 628 | } 629 | 630 | // Shift Left 631 | if(settings_page == 5) 632 | { 633 | dual_display_driver->writeByteCode(0, __S__); // S 634 | dual_display_driver->writeByteCode(1, __H__); // H 635 | dual_display_driver->writeByteCode(2, 0b01001110); // [ 636 | dual_display_driver->writeByteCode(3, 0b01001110); // [ 637 | 638 | dual_display_driver->writeByteCode(4, __dash__); // - 639 | dual_display_driver->writeByteCode(5, __dash__); // - 640 | dual_display_driver->writeByteCode(6, __dash__); // - 641 | dual_display_driver->writeByteCode(7, __dash__); // - 642 | 643 | if(value_encoder->pressed()) 644 | { 645 | dual_display_driver->writeByteCode(4, 0b01001110); // [ 646 | dual_display_driver->writeByteCode(5, 0b01001000); // = 647 | dual_display_driver->writeByteCode(6, 0b01001000); // = 648 | dual_display_driver->writeByteCode(7, 0b01111000); // ] 649 | 650 | int tmp = snapshot->sequence[0]; 651 | 652 | for(int i=1; i < snapshot->sequence_length; i++) 653 | { 654 | snapshot->setValue(i-1, snapshot->sequence[i]); 655 | } 656 | 657 | snapshot->setValue(snapshot->sequence_length - 1, tmp); 658 | 659 | dual_display_driver->writeByteCode(4, __dash__); // - 660 | dual_display_driver->writeByteCode(5, __dash__); // - 661 | dual_display_driver->writeByteCode(6, __dash__); // - 662 | dual_display_driver->writeByteCode(7, __dash__); // - 663 | } 664 | } 665 | 666 | // Shift right 667 | if(settings_page == 6) 668 | { 669 | dual_display_driver->writeByteCode(0, __S__); // S 670 | dual_display_driver->writeByteCode(1, __H__); // H 671 | dual_display_driver->writeByteCode(2, 0b01111000); // ] 672 | dual_display_driver->writeByteCode(3, 0b01111000); // ] 673 | 674 | dual_display_driver->writeByteCode(4, __dash__); // - 675 | dual_display_driver->writeByteCode(5, __dash__); // - 676 | dual_display_driver->writeByteCode(6, __dash__); // - 677 | dual_display_driver->writeByteCode(7, __dash__); // - 678 | 679 | if(value_encoder->pressed()) 680 | { 681 | dual_display_driver->writeByteCode(4, 0b01001110); // [ 682 | dual_display_driver->writeByteCode(5, 0b01001000); // = 683 | dual_display_driver->writeByteCode(6, 0b01001000); // = 684 | dual_display_driver->writeByteCode(7, 0b01111000); // ] 685 | 686 | int tmp = snapshot->sequence[snapshot->sequence_length - 1]; 687 | 688 | for(int i=snapshot->sequence_length - 1; i > 0; i--) 689 | { 690 | snapshot->setValue(i, snapshot->sequence[i-1]); 691 | } 692 | 693 | snapshot->setValue(0, tmp); 694 | 695 | dual_display_driver->writeByteCode(4, __dash__); // - 696 | dual_display_driver->writeByteCode(5, __dash__); // - 697 | dual_display_driver->writeByteCode(6, __dash__); // - 698 | dual_display_driver->writeByteCode(7, __dash__); // - 699 | } 700 | } 701 | 702 | // Slip 703 | if(settings_page == 7) 704 | { 705 | dual_display_driver->writeByteCode(0, __S__); // S 706 | dual_display_driver->writeByteCode(1, __L__); // L 707 | dual_display_driver->writeByteCode(2, __i__); // i 708 | dual_display_driver->writeByteCode(3, __P__); // P 709 | 710 | // Set slip 711 | int8_t slip = snapshot->slip + (value_encoder->read()); 712 | slip = constrain(slip, 0, 99); 713 | snapshot->setSlip(slip); 714 | 715 | dual_display_driver->write(BOTTOM_DISPLAY, slip); 716 | } 717 | 718 | 719 | // Drift Percentage 720 | if(settings_page == 8) 721 | { 722 | int16_t drift_percentage_acceleration = 1; 723 | if(value_encoder_button_pressed) drift_percentage_acceleration = 10; 724 | 725 | dual_display_driver->writeByteCode(0, __d__); // d 726 | dual_display_driver->writeByteCode(1, __r__); // r 727 | dual_display_driver->writeByteCode(2, __dash__); // - 728 | dual_display_driver->writeByteCode(3, __P__); // P 729 | 730 | int8_t drift_percentage = snapshot->drift_percentage + (value_encoder->read() * drift_percentage_acceleration); 731 | drift_percentage = constrain(drift_percentage, 0, 100); 732 | snapshot->setDriftPercentage(drift_percentage); 733 | 734 | dual_display_driver->write(BOTTOM_DISPLAY, drift_percentage); 735 | } 736 | 737 | // Drift Amount 738 | if(settings_page == 9) 739 | { 740 | int16_t drift_acceleration = 1; 741 | if(value_encoder_button_pressed) drift_acceleration = 100; 742 | 743 | dual_display_driver->writeByteCode(0, __d__); // d 744 | dual_display_driver->writeByteCode(1, __r__); // r 745 | dual_display_driver->writeByteCode(2, __underscore__); // _ 746 | dual_display_driver->writeByteCode(3, __A__); // A 747 | 748 | int16_t drift_amount = snapshot->drift_amount; 749 | drift_amount = drift_amount + (value_encoder->read() * drift_acceleration); 750 | drift_amount = constrain(drift_amount, 0, 300); 751 | 752 | snapshot->setDriftAmount(drift_amount); 753 | 754 | dual_display_driver->write(BOTTOM_DISPLAY, drift_amount); 755 | } 756 | 757 | // Hold offset 758 | if(settings_page == 10) 759 | { 760 | int16_t acceleration = 1; 761 | if(value_encoder_button_pressed) acceleration = 10; 762 | 763 | dual_display_driver->writeByteCode(0, __h__); // h 764 | dual_display_driver->writeByteCode(1, __d__); // d 765 | dual_display_driver->writeByteCode(2, __dash__); // - 766 | dual_display_driver->writeByteCode(3, __o__); // o 767 | 768 | z_hold_offset = z_hold_offset + (value_encoder->read() * acceleration); 769 | z_hold_offset = constrain(z_hold_offset, 0, 64 << 1); 770 | 771 | uint16_t hold_offset = z_hold_offset >> 1; 772 | 773 | snapshot->setHoldOffset(hold_offset); 774 | 775 | dual_display_driver->write(BOTTOM_DISPLAY, hold_offset); 776 | } 777 | 778 | // Hold threshold 779 | // Notice: Encoder set to full throttle 780 | if(settings_page == 11) 781 | { 782 | int16_t acceleration = 1; 783 | if(value_encoder_button_pressed) acceleration = 100; 784 | 785 | dual_display_driver->writeByteCode(0, __h__); // h 786 | dual_display_driver->writeByteCode(1, __d__); // d 787 | dual_display_driver->writeByteCode(2, __dash__); // - 788 | dual_display_driver->writeByteCode(3, __t__); // t 789 | 790 | hold_threshold = hold_threshold + (value_encoder->read() * acceleration); 791 | hold_threshold = constrain(hold_threshold, 0, 4095); 792 | 793 | snapshot->setHoldThreshold(hold_threshold); 794 | 795 | dual_display_driver->write(BOTTOM_DISPLAY, hold_threshold); 796 | } 797 | 798 | // Song pattern 799 | if(settings_page == 12) 800 | { 801 | int encoder_value = value_encoder->read(); 802 | 803 | if(encoder_value != 0) 804 | { 805 | z_song = z_song + encoder_value; 806 | z_song = constrain(z_song, 0, (NUMBER_OF_SONGS-1) << 1); // 0 == off 807 | 808 | snapshot->setSong(z_song >> 1); 809 | } 810 | 811 | dual_display_driver->writeByteCode(0, __S__); // S 812 | dual_display_driver->writeByteCode(1, __o__); // o 813 | dual_display_driver->writeByteCode(2, __n__); // n 814 | dual_display_driver->writeDigit(3, 1); // 1 815 | 816 | dual_display_driver->write(BOTTOM_DISPLAY, z_song >> 1); 817 | } 818 | 819 | // Song2 pattern 820 | if(settings_page == 13) 821 | { 822 | int encoder_value = value_encoder->read(); 823 | 824 | if(encoder_value != 0) 825 | { 826 | z_song2 = z_song2 + encoder_value; 827 | z_song2 = constrain(z_song2, 0, (NUMBER_OF_SONGS-1) << 1); // 0 == off 828 | 829 | snapshot->setSong2(z_song2 >> 1); 830 | } 831 | 832 | dual_display_driver->writeByteCode(0, __S__); // S 833 | dual_display_driver->writeByteCode(1, __o__); // o 834 | dual_display_driver->writeByteCode(2, __n__); // n 835 | dual_display_driver->writeDigit(3, 2); // 2 836 | 837 | dual_display_driver->write(BOTTOM_DISPLAY, z_song2 >> 1); 838 | } 839 | 840 | // LED Intensity 841 | if(settings_page == 14) 842 | { 843 | int encoder_value = value_encoder->read(); 844 | 845 | if(encoder_value != 0) 846 | { 847 | z_intensity = z_intensity + encoder_value; 848 | z_intensity = constrain(z_intensity, 0, 15 << 1); 849 | dual_display_driver->setIntensity(z_intensity >> 1); 850 | } 851 | 852 | dual_display_driver->writeByteCode(0, __L__); // L 853 | dual_display_driver->writeByteCode(1, __E__); // E 854 | dual_display_driver->writeByteCode(2, __d__); // d 855 | dual_display_driver->writeByteCode(3, __S__); // S 856 | 857 | dual_display_driver->write(BOTTOM_DISPLAY, z_intensity >> 1); 858 | } 859 | 860 | // Reset input assignment 861 | 862 | if(settings_page == 15) 863 | { 864 | // int16_t hold_acceleration = 1; 865 | // if(value_encoder->readButton()) hold_acceleration = 20; 866 | 867 | dual_display_driver->writeByteCode(0, __r__); // r 868 | dual_display_driver->writeByteCode(1, __S__); // S 869 | dual_display_driver->writeByteCode(2, __t__); // t 870 | dual_display_driver->writeByteCode(3, 0b00000000); // 871 | 872 | if(value_encoder->pressed()) 873 | { 874 | if(snapshot->rst_input_assignment == RST_ASSIGNMENT_SAMPLE_AND_HOLD) 875 | { 876 | snapshot->setRstInputAssignment(RST_ASSIGNMENT_RESET); 877 | } 878 | else 879 | { 880 | snapshot->setRstInputAssignment(RST_ASSIGNMENT_SAMPLE_AND_HOLD); 881 | } 882 | } 883 | 884 | if(snapshot->rst_input_assignment == RST_ASSIGNMENT_SAMPLE_AND_HOLD) 885 | { 886 | dual_display_driver->writeByteCode(4, __S__); // S 887 | dual_display_driver->writeByteCode(5, __h__); // h 888 | dual_display_driver->writeByteCode(6, 0b00000000); // 889 | dual_display_driver->writeByteCode(7, 0b00000000); // 890 | } 891 | 892 | if(snapshot->rst_input_assignment == RST_ASSIGNMENT_RESET) 893 | { 894 | dual_display_driver->writeByteCode(4, __r__); // r 895 | dual_display_driver->writeByteCode(5, __S__); // S 896 | dual_display_driver->writeByteCode(6, __t__); // t 897 | dual_display_driver->writeByteCode(7, 0b00000000); // 898 | } 899 | 900 | } 901 | 902 | if(settings_page == 16) 903 | { 904 | dual_display_driver->writeByteCode(0, __P__); 905 | dual_display_driver->writeByteCode(1, __r__); 906 | dual_display_driver->writeByteCode(2, __E__); 907 | dual_display_driver->writeByteCode(3, __S__); 908 | 909 | if(value_encoder->pressed()) 910 | { 911 | if(snapshot->press_functionality == PRESS_ASSIGNMENT_FINE) 912 | { 913 | snapshot->setPressFunctionality(PRESS_ASSIGNMENT_COARSE); 914 | } 915 | else 916 | { 917 | snapshot->setPressFunctionality(PRESS_ASSIGNMENT_FINE); 918 | } 919 | } 920 | 921 | if(snapshot->press_functionality == PRESS_ASSIGNMENT_FINE) 922 | { 923 | dual_display_driver->writeByteCode(4, __F__); 924 | dual_display_driver->writeByteCode(5, __i__); 925 | dual_display_driver->writeByteCode(6, __n__); 926 | dual_display_driver->writeByteCode(7, __E__); 927 | } 928 | 929 | if(snapshot->press_functionality == PRESS_ASSIGNMENT_COARSE) 930 | { 931 | dual_display_driver->writeByteCode(4, __c__); 932 | dual_display_driver->writeByteCode(5, __o__); 933 | dual_display_driver->writeByteCode(6, __r__); 934 | dual_display_driver->writeByteCode(7, __S__); 935 | } 936 | 937 | } 938 | 939 | // Select settings page using the clock button 940 | // Go back a page using the reset button 941 | clock_button->poll(); 942 | reset_button->poll(); 943 | 944 | if(clock_button->triggered) z_settings_page += 4; 945 | if(reset_button->triggered) z_settings_page -= 4; 946 | 947 | // You can also use the rotary top encoder to select the page 948 | z_settings_page = z_settings_page + step_encoder->read(); 949 | z_settings_page = constrain(z_settings_page, 0, (NUMBER_OF_SETTINGS_PAGES << 2) - 1); 950 | 951 | // z_settings_page is used to slow down the reaction to the rotary encoder, which 952 | // normally could be a bit sensitive. 953 | settings_page = z_settings_page >> 2; 954 | 955 | } 956 | 957 | void Engine::factoryReset() 958 | { 959 | 960 | snapshot->setClockDivision(1); 961 | snapshot->setSequenceLength(8); 962 | snapshot->setDriftPercentage(0); 963 | snapshot->setDriftAmount(0); 964 | snapshot->setSlip(0); 965 | snapshot->setScale(0); 966 | snapshot->setHoldOffset(0); 967 | snapshot->setHoldThreshold(0); 968 | snapshot->setSong(0); 969 | snapshot->setSong2(0); 970 | snapshot->setDisplayIntensity(15); 971 | snapshot->setRstInputAssignment(RST_ASSIGNMENT_RESET); 972 | snapshot->setPressFunctionality(PRESS_ASSIGNMENT_FINE); 973 | 974 | for(uint8_t i=0; isetValue(i, value); 978 | } 979 | 980 | dual_display_driver->setIntensity(15); 981 | 982 | // Animate reset message 983 | dual_display_driver->writeByteCode(0, 0b00000000); // 984 | dual_display_driver->writeByteCode(1, 0b00000000); // 985 | dual_display_driver->writeByteCode(2, 0b00000000); // 986 | dual_display_driver->writeByteCode(3, 0b00000000); // 987 | dual_display_driver->writeByteCode(4, 0b00000000); // 988 | dual_display_driver->writeByteCode(5, 0b00000000); // 989 | dual_display_driver->writeByteCode(6, 0b00000000); // 990 | dual_display_driver->writeByteCode(7, 0b00000000); // 991 | 992 | delay(400); 993 | dual_display_driver->writeByteCode(4, 0b01000110); // r 994 | delay(400); 995 | dual_display_driver->writeByteCode(5, 0b01011011); // S 996 | delay(400); 997 | dual_display_driver->writeByteCode(6, 0b01001111); // E 998 | delay(400); 999 | dual_display_driver->writeByteCode(7, 0b00001111); // t 1000 | delay(400); 1001 | 1002 | dual_display_driver->writeByteCode(4, 0b00000000); // 1003 | dual_display_driver->writeByteCode(5, 0b00000000); // 1004 | dual_display_driver->writeByteCode(6, 0b00000000); // 1005 | dual_display_driver->writeByteCode(7, 0b00000000); // 1006 | } 1007 | -------------------------------------------------------------------------------- /Engine.h: -------------------------------------------------------------------------------- 1 | #ifndef Engine_h 2 | #define Engine_h 3 | 4 | #include 5 | 6 | #include "Arduino.h" 7 | #include "defines.h" 8 | #include "DualDisplayDriver.h" 9 | #include "RotaryEncoder.h" 10 | #include "Memory.h" 11 | #include "Snapshot.h" 12 | #include "Sequencer.h" 13 | #include "TriggerInput.h" 14 | #include "SwitchInput.h" 15 | #include "Transposer.h" 16 | #include "Output.h" 17 | #include "Rand.h" 18 | 19 | class Engine 20 | { 21 | public: 22 | Engine(); 23 | void init(); 24 | void loop(); 25 | void factoryReset(); 26 | 27 | void sequencePlaybackMode(); 28 | void sequenceEditMode(); 29 | void settingsMode(); 30 | 31 | void playback(); 32 | 33 | // Global variables of the sequencer 34 | uint8_t step = 0; 35 | int16_t value = 0; 36 | int32_t output_value = 0; 37 | uint16_t old_value = 0; 38 | int8_t value_encoder_button_pressed = 0; 39 | 40 | int16_t realtime_recording_value = 0; 41 | 42 | int16_t z_sequence_length = 0; 43 | int16_t z_clock_division = 0; 44 | int8_t z_scale = 0; 45 | int8_t z_edit_step = 0; 46 | int8_t z_intensity = 0; 47 | int16_t z_hold = 0; 48 | int16_t z_hold_offset = 0; 49 | int16_t hold_threshold = 0; 50 | int8_t z_song = 0; 51 | int8_t z_song2 = 0; 52 | 53 | int16_t drift = 0; 54 | uint16_t clock_counter = 0; 55 | 56 | int8_t edit_step = 0; 57 | int16_t edit_value = 0; 58 | 59 | boolean sample = false; 60 | 61 | // Always start in playback mode 62 | uint8_t mode = SEQUENCE_PLAYBACK_MODE; 63 | uint8_t rst_input_assignment = RST_ASSIGNMENT_RESET; 64 | int8_t settings_page = 0; 65 | int8_t z_settings_page = 0; 66 | 67 | // Random number generator 68 | Rand *rnd; 69 | 70 | // Sequencer object 71 | Sequencer *sequencer; 72 | 73 | // Snapshot object 74 | Snapshot *snapshot; 75 | // Snapshot *snapshots[NUMBER_OF_SNAPSHOTS]; 76 | 77 | Transposer *transposer; 78 | Transposer *transposer2; 79 | 80 | // Memory, and display objects (I2C devices) 81 | Memory *memory; 82 | DualDisplayDriver *dual_display_driver; 83 | 84 | // Rotary encoder objects 85 | RotaryEncoder *step_encoder; // top encoder 86 | RotaryEncoder *value_encoder; // bottom encoder 87 | 88 | // Trigger input objects 89 | TriggerInput *clock_button; 90 | TriggerInput *clock_input; 91 | TriggerInput *reset_button; 92 | TriggerInput *reset_input; 93 | 94 | // Mode switch 95 | SwitchInput *mode_switch; 96 | 97 | // Output object 98 | Output *output; 99 | 100 | 101 | }; 102 | 103 | #endif -------------------------------------------------------------------------------- /GlobalScales.cpp: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include "GlobalScales.h" 3 | 4 | const uint8_t MAJOR[] = { 0,4,7,12,16,19, 24,28,31, 36,40,43, 48,52,55,60 }; 5 | const uint8_t MINOR[] = { 0,3,7, 12,15,19, 24,27,31, 36,39,43, 48,51,55,60 }; 6 | const uint8_t IONIAN[] = { 0,2,4,5,7,9,11,12,13,14, 16,17,19,21,23,24,26,28,29,31, 33,35,36,38,40,41,43,45,47,48, 50,52,53,55,57,59 }; 7 | const uint8_t DORIAN[] = { 0,2,3,5,7,9,10,12,14,15, 17,19,21,22,24,26,27,29,31,33, 34,36,38,39,41,43,45,46,48,50, 51,53,55,57,58 }; 8 | const uint8_t LYDIAN[] = { 0,2,4,6,7,9,11,12,14,16, 18,19,21,23,24,26,28,30,31,33, 35,36,38,40,42,43,45,47,48,50, 52,54,55,57,59 }; 9 | const uint8_t PHRYGIAN[] = { 0,1,3,5,7,8,10,12,13,15, 17,19,20,22,24,25,27,29,31,32, 34,36,37,39,41,43,44,46,48,49, 51,53,55,56,58 }; 10 | const uint8_t MIXOLYDIAN[] = { 0,2,4,5,7,9,10,12,14,16, 17,19,21,22,24,26,28,29,31,33, 34,36,38,40,41,43,45,46,48,50, 52,53,55,57,58,60 }; // 36 11 | const uint8_t AEOLIAN[] = { 0,2,3,5,7,8,10,12,14,15, 17,19,20,22,24,26,27,29,31,32, 34,36,38,39,41,43,44,46,48,50, 51,53,55,56,58,60 }; // 36 12 | const uint8_t LOCRIAN[] = { 0,1,3,5,6,8,10,12,13,15, 17,18,20,22,24,25,27,29,30,32, 34,36,37,39,41,42,44,46,48,49, 51,53,54,56,58,60 }; // 36 13 | const uint8_t MAJOR_PENTATONIC[] = { 0,2,4,7,9,12,14,16,19,21, 24,26,28,31,33,36,38,40,43,45, 48,50,52,55,57,60 }; // 26 14 | const uint8_t MINOR_PENTATONIC[] = { 0,3,5,7,10,12,15,17,19,22,24,27,29,31,34,36,39,41,43,46, 48,51,53,55,58,60 }; // 26 15 | const uint8_t DIMINISHED[] = { 0,2,3,5,6,8,9,11,12,14, 15,17,18,20,21,23,24,26,27,29, 30,32,33,35,36,38,39,41,42,44, 45,47,48,50,51,53,54,56,57,59,60 }; // 41 16 | const uint8_t CHROMATIC[] = { 0,1,2,3,4,5,6,7,8,9, 10,11,12,13,14,15,16,17,18,19, 20,21,22,23,24,25,26,27,28,29, 30,31,32,33,34,35,36,37,38,39, 40,41,42,43,44,45,46,47,48,49, 50,51,52,53,54,55,56,57,58,59 }; 17 | 18 | const uint16_t NOTES[] = { 19 | 0, 69, 137, 206, 274, 343, 412, 480, 549, 617, 686, 754, 20 | 823, 892, 960, 1029, 1097, 1166, 1234, 1303, 1372, 1440, 1509, 1577, 21 | 1646, 1715, 1783, 1852, 1920, 1989, 2058, 2126, 2195, 2263, 2332, 2400, 22 | 2469, 2538, 2606, 2675, 2743, 2812, 2880, 2949, 3018, 3086, 3155, 3223, 23 | 3292, 3361, 3429, 3498, 3566, 3635, 3703, 3772, 3841, 3909, 3978, 4046 24 | }; -------------------------------------------------------------------------------- /GlobalScales.h: -------------------------------------------------------------------------------- 1 | #ifndef Scales_h 2 | #define Scales_h 3 | 4 | extern const uint8_t CHROMATIC[]; 5 | extern const uint8_t IONIAN[]; 6 | extern const uint8_t DORIAN[]; 7 | extern const uint8_t LYDIAN[]; 8 | 9 | extern const uint8_t PHRYGIAN[]; 10 | extern const uint8_t MIXOLYDIAN[]; 11 | extern const uint8_t AEOLIAN[]; 12 | extern const uint8_t LOCRIAN[]; 13 | 14 | extern const uint8_t MAJOR_PENTATONIC[]; 15 | extern const uint8_t MINOR_PENTATONIC[]; 16 | extern const uint8_t BLUES[]; 17 | extern const uint8_t DIMINISHED[]; 18 | 19 | extern const uint8_t ARABIAN[]; 20 | extern const uint8_t MAJOR[]; 21 | extern const uint8_t MINOR[]; 22 | extern const uint8_t PRISM[]; 23 | 24 | extern const uint16_t NOTES[]; 25 | 26 | #endif -------------------------------------------------------------------------------- /GlobalTranspositionTables.cpp: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include "GlobalTranspositionTables.h" 3 | 4 | 5 | const int8_t TRANSPOSITION_TABLES[][16] = { 6 | // 0) None 7 | { 8 | 0,0,0,0, 9 | 0,0,0,0, 10 | 0,0,0,0, 11 | 0,0,0,0 12 | }, 13 | // 1) Subtle 14 | { 15 | 0,0,0,0, 16 | 2,2,2,2, 17 | 0,0,0,0, 18 | 2,2,2,2 19 | }, 20 | // 2) Subtle+ 21 | { 22 | 0,0,0,0, 23 | 2,2,2,2, 24 | 0,0,0,0, 25 | 9,9,9,9 26 | }, 27 | // 3) Launch 28 | { 29 | 0,0,0,0, 30 | 2,2,2,2, 31 | 36,36,36,36, 32 | 9,9,9,9 33 | }, 34 | // 4) Tadeoffs 35 | { 36 | 24,0,24,0, 37 | 12,36,36,2, 38 | 29,10,29,10, 39 | 9,9,9,9 40 | }, 41 | // 5) Return Home 42 | { 43 | 0,14,-6,14, 44 | 0,-3,-12,14, 45 | 0,-5,20,10, 46 | 0,12,7,24 47 | }, 48 | // 6) Octaves 49 | { 50 | 0,0,-12,-12, 51 | 12,12,0,0, 52 | 0,0,-12,-12, 53 | 12,12,0,0 54 | }, 55 | // 7) Down & Up 56 | { 57 | 0,0,-3,-3, 58 | -6,-6,-9,-9, 59 | -12,-12,-4,-4, 60 | 7,7,10,10 61 | }, 62 | // 8) Fast Acention 63 | { 64 | -11,-9,-7,-5, 65 | -3,-1,1,3, 66 | 5,7,9,11, 67 | 13,15,17,19 68 | }, 69 | // 9) Movement 70 | { 71 | 0,0,0,0, 72 | -7,-7,-7,-7, 73 | 4,4,4,4, 74 | -10,-10,-10,-13 75 | }, 76 | // 10) Extremes 77 | { 78 | 0,0,-48,-48, 79 | 48,48,-36,-36, 80 | 36,36,-24,-24, 81 | 24,24,-12,-12 82 | }, 83 | // 11) Fairly Random 84 | { 85 | 0,30,-4,-19, 86 | 14,5,-11,24, 87 | 22,6,-6,-12, 88 | 24,14,-12,2 89 | }, 90 | // 12) Arp up 91 | { 92 | 0,2,4,2, 93 | 4,6,4,6, 94 | 8,6,8,9, 95 | 8,9,11,8 96 | }, 97 | // 13) Arp up down 98 | { 99 | 0,4,8,4, 100 | 8,12,8,12, 101 | 16,12,8,4, 102 | 8,4,0,-4 103 | }, 104 | // 14) Wider 105 | { 106 | 0,1,-1,2 107 | -2,3,-3,4, 108 | -4,5,-5,6, 109 | -6,7,-7,-8 110 | }, 111 | // 15) down slide 112 | { 113 | 9,8,7,6, 114 | 5,4,3,2, 115 | 1,0,-1,-2, 116 | -3,-4,-5,-6 117 | }, 118 | // 16) Baby steps 119 | { 120 | 0,1,2,1, 121 | 0,-1,-2,-1, 122 | 0,1,2,1, 123 | 0,-1,-2,-1 124 | } 125 | 126 | }; 127 | 128 | 129 | /* notes 130 | 131 | 0 1 2 3 4 5 6 7 8 9 10 11 132 | 0, 69, 137, 206, 274, 343, 412, 480, 549, 617, 686, 754, 133 | 134 | 12 13 14 15 16 17 18 19 20 21 22 23 135 | 823, 892, 960, 1029, 1097, 1166, 1234, 1303, 1372, 1440, 1509, 1577, 136 | 137 | 24 25 26 27 28 29 30 31 32 33 34 35 138 | 1646, 1715, 1783, 1852, 1920, 1989, 2058, 2126, 2195, 2263, 2332, 2400, 139 | 140 | 36 37 38 39 40 41 42 43 44 45 46 47 141 | 2469, 2538, 2606, 2675, 2743, 2812, 2880, 2949, 3018, 3086, 3155, 3223, 142 | 143 | 48 49 50 51 52 53 54 55 56 57 58 59 144 | 3292, 3361, 3429, 3498, 3566, 3635, 3703, 3772, 3841, 3909, 3978, 4046 145 | 146 | */ -------------------------------------------------------------------------------- /GlobalTranspositionTables.h: -------------------------------------------------------------------------------- 1 | #ifndef TranspositionTables_h 2 | #define TranspositionTables_h 3 | 4 | extern const int8_t TRANSPOSITION_TABLES[][16]; 5 | 6 | #endif -------------------------------------------------------------------------------- /Memory.cpp: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include "Memory.h" 3 | 4 | Memory::Memory(uint8_t i2c_address) 5 | { 6 | this->i2c_address = i2c_address; 7 | } 8 | 9 | void Memory::init() 10 | { 11 | } 12 | 13 | uint8_t Memory::read(uint16_t memory_address) 14 | { 15 | 16 | uint8_t results = 0; 17 | 18 | // Send the memory address 19 | Wire.beginTransmission(this->i2c_address); 20 | Wire.write(highByte(memory_address)); 21 | Wire.write(lowByte(memory_address)); 22 | Wire.endTransmission(); 23 | 24 | // Request 1 byte 25 | Wire.requestFrom(this->i2c_address, (uint8_t) 1); 26 | 27 | // Read from the memory address 28 | if(Wire.available()) results = Wire.read(); 29 | 30 | return(results); 31 | } 32 | 33 | void Memory::write(uint16_t memory_address, uint8_t value) 34 | { 35 | Wire.beginTransmission(this->i2c_address); 36 | 37 | // Send the memory address 38 | Wire.write(highByte(memory_address)); 39 | Wire.write(lowByte(memory_address)); 40 | 41 | // Send the value to write 42 | Wire.write(value); 43 | 44 | Wire.endTransmission(); 45 | 46 | } -------------------------------------------------------------------------------- /Memory.h: -------------------------------------------------------------------------------- 1 | #ifndef Memory_h 2 | #define Memory_h 3 | 4 | #include "Arduino.h" 5 | #include 6 | 7 | class Memory 8 | { 9 | public: 10 | Memory(uint8_t i2c_address); 11 | 12 | void init(); 13 | uint8_t read(uint16_t memory_address); 14 | void write(uint16_t memory_address, uint8_t value); 15 | 16 | uint8_t i2c_address; 17 | }; 18 | 19 | #endif -------------------------------------------------------------------------------- /MetaSequencer.ino: -------------------------------------------------------------------------------- 1 | /* 2 | _ __ 3 | /\/\ ___| |_ __ _ / _\ ___ __ _ _ _ ___ _ __ ___ ___ _ __ 4 | / \ / _ \ __/ _` | \ \ / _ \/ _` | | | |/ _ \ '_ \ / __/ _ \ '__| 5 | / /\/\ \ __/ || (_| | _\ \ __/ (_| | |_| | __/ | | | (_| __/ | 6 | \/ \/\___|\__\__,_| \__/\___|\__, |\__,_|\___|_| |_|\___\___|_| 7 | |_| 8 | // by microbe modular 9 | // ============================================================================= 10 | 11 | Copyright 2014 Bret Truchan / John Staskevich 12 | 13 | The Meta Sequencer source code is free software: you can redistribute it 14 | and/or modify it under the terms of the GNU General Public License as 15 | published by the Free Software Foundation, either version 3 of the License, or 16 | (at your option) any later version. 17 | 18 | Written for the Arduino Nano 19 | 20 | Credits: 21 | Circuit/PCB design, parts selection, and manufacturing oversight by John Staskevich 22 | Front panel design by Hannes Pasqualini 23 | 24 | Parts: 25 | DAC: MCP4725 - http://www.adafruit.com/datasheets/mcp4725.pdf 26 | LED Driver: AS1115 - http://www.ams.com/eng/content/download/18430/343782 27 | 28 | Upcoming feature ideas / requests: 29 | - allow reversing of the course/fine modes via a menu settings 30 | 31 | Bugs 32 | - 33 | 34 | 35 | // =========================== - 80 column - =================================== 36 | 12345678901234567890123456789012345678901234567890123456789012345678901234567890 37 | 38 | */ 39 | 40 | #include 41 | #include "GlobalScales.h" 42 | #include "Engine.h" 43 | 44 | Engine *engine = new Engine(); 45 | 46 | void setup() 47 | { 48 | // set unused pins as outputs to prevent floating 49 | pinMode(4,OUTPUT); 50 | pinMode(7,OUTPUT); 51 | pinMode(11,OUTPUT); 52 | pinMode(12,OUTPUT); 53 | pinMode(13,OUTPUT); 54 | 55 | engine->init(); 56 | } 57 | 58 | void loop() 59 | { 60 | engine->loop(); 61 | } -------------------------------------------------------------------------------- /Output.cpp: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include "Output.h" 3 | 4 | 5 | Output::Output(uint8_t i2c_address, Snapshot *snapshot, Transposer *transposer, Transposer *transposer2) 6 | { 7 | this->i2c_address = i2c_address; 8 | this->snapshot = snapshot; 9 | this->transposer = transposer; 10 | this->transposer2 = transposer2; 11 | } 12 | 13 | void Output::write(uint16_t value) 14 | { 15 | value = transposer->transpose(value, this->snapshot->song); 16 | value = transposer2->transpose(value, this->snapshot->song2); 17 | value = quantize(value); 18 | 19 | // Send information to DAC (MCP4725) 20 | Wire.beginTransmission(i2c_address); 21 | Wire.write(0x40); // Write command 22 | Wire.write(value / 16); 23 | Wire.write((value % 16) << 4); 24 | Wire.endTransmission(); 25 | } 26 | 27 | 28 | uint16_t Output::quantize(uint16_t value) 29 | { 30 | 31 | // The NOTES array and scale arrays are defined in GlobalScales.h/GlobalScales.cpp 32 | 33 | switch(this->snapshot->scale) { 34 | case 0: 35 | return(value); // no quantization 36 | case 1: 37 | value = map(value, 0, 4095, 0, 15); 38 | return(NOTES[MAJOR[value]]); 39 | case 2: 40 | value = map(value, 0, 4095, 0, 15); 41 | return(NOTES[MINOR[value]]); 42 | case 3: 43 | value = map(value, 0, 4095, 0, 36); 44 | return(NOTES[IONIAN[value]]); 45 | case 4: 46 | value = map(value, 0, 4095, 0, 35); 47 | return(NOTES[DORIAN[value]]); 48 | case 5: 49 | value = map(value, 0, 4095, 0, 35); 50 | return(NOTES[LYDIAN[value]]); 51 | case 6: 52 | value = map(value, 0, 4095, 0, 35); 53 | return(NOTES[PHRYGIAN[value]]); 54 | case 7: 55 | value = map(value, 0, 4095, 0, 35); 56 | return(NOTES[MIXOLYDIAN[value]]); 57 | case 8: 58 | value = map(value, 0, 4095, 0, 35); 59 | return(NOTES[AEOLIAN[value]]); 60 | case 9: 61 | value = map(value, 0, 4095, 0, 35); 62 | return(NOTES[LOCRIAN[value]]); 63 | case 10: 64 | value = map(value, 0, 4095, 0, 25); 65 | return(NOTES[MAJOR_PENTATONIC[value]]); 66 | case 11: 67 | value = map(value, 0, 4095, 0, 25); 68 | return(NOTES[MINOR_PENTATONIC[value]]); 69 | case 12: 70 | value = map(value, 0, 4095, 0, 40); 71 | return(NOTES[DIMINISHED[value]]); 72 | case 13: 73 | value = map(value, 0, 4095, 0, 60); 74 | return(NOTES[CHROMATIC[value]]); 75 | case 14: 76 | if(value >= 2048) return(4095); 77 | return(0); 78 | } 79 | } -------------------------------------------------------------------------------- /Output.h: -------------------------------------------------------------------------------- 1 | #ifndef Output_h 2 | #define Output_h 3 | 4 | #include "Arduino.h" 5 | #include 6 | #include "defines.h" 7 | #include "Snapshot.h" 8 | #include "GlobalScales.h" 9 | #include "Transposer.h" 10 | 11 | class Output 12 | { 13 | public: 14 | 15 | // Methods 16 | Output(uint8_t i2c_address, Snapshot *snapshot, Transposer *transposer, Transposer *transposer2); 17 | void write(uint16_t value); 18 | uint8_t getScale(); 19 | uint16_t quantize(uint16_t value); 20 | 21 | // Variables 22 | uint8_t i2c_address; 23 | uint16_t old_value = 32768; 24 | 25 | Transposer *transposer; 26 | Transposer *transposer2; 27 | Snapshot *snapshot; 28 | }; 29 | 30 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MetaSequencer 2 | Firmware for the MetaSequencer module by Microbe Modular 3 | 4 | Programming notes: 5 | 6 | I'm using the Arduino 1.5.7 build, but I'm not sure if that matters. 7 | 8 | 1. In the Arduino IDE, under Tools, set your settings to: 9 | 10 | Board: Arduino Nano
11 | Processor: ATMega328
12 | Programmers: AVRISP mk2 (yours may differ) 13 | 14 | 2. Under File/Preferences, turn on verbose output during compilation. 15 | 16 | 3. Load the code and click the checkbox to Verify/Compile without uploading. 17 | 18 | 4. Compile the code. Look in the verbose output, near the bottom, for the location of the .elf file that was generated. My line looks like this: 19 | 20 | C:\Program Files (x86)\Arduino/hardware/tools/avr/bin/avr-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 C:\Users\Bret\AppData\Local\Temp\build2617538330943428195.tmp/MetaSequencer.cpp.elf 21 | 22 | The location and filename of the .elf file will stay the same until you restart the Arduino IDE. So be careful, in the future, not to accidentally use an outdated .elf file, otherwise you'll think to yourself, "What the heck is going on?" 23 | 24 | 5. Connect your programmer and power up the unit. If you're using the AVRISP mk2, the stripe should be on the bottom. 25 | 26 | 6. Download and open up Atmel Studio. I'm using 6.2. I'm sure that any version after 6.2 will work. 27 | 28 | 7. In Atmel Studio, under the Tools menu, select Device Programming 29 | 30 | 8. If the device is connected, Atmel Studio will automatically recognize it. Mine says: 31 | 32 | Tool: AVRISP mkII
33 | Device: ATmega328
34 | Interface ISP.
35 | 36 | Press the Apply button. 37 | 38 | 9. On the left menu that appears, select "Memories" 39 | 40 | 10. Under the Flash section, browse for the .elf file and click Program. 41 | 42 | That should do it! 43 | 44 | Cheers, 45 | Bret 46 | -------------------------------------------------------------------------------- /Rand.cpp: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include "Rand.h" 3 | 4 | Rand::Rand() 5 | { 6 | x = 132456789; 7 | y = 362436069; 8 | z = 521288629; 9 | } 10 | 11 | uint32_t Rand::xorshift96() 12 | { 13 | 14 | uint32_t t; 15 | 16 | x ^= x << 16; 17 | x ^= x >> 5; 18 | x ^= x << 1; 19 | 20 | t = x; 21 | x = y; 22 | y = z; 23 | z = t ^ x ^ y; 24 | 25 | return z; 26 | } 27 | 28 | void Rand::seed(uint32_t seed) 29 | { 30 | x = seed; 31 | y = 362436069; 32 | z = 521288629; 33 | } 34 | 35 | uint32_t Rand::random(uint32_t min, uint32_t max) 36 | { 37 | return (uint32_t) ((((xorshift96() & 0xFFFF) * (max-min))>>16) + min); 38 | } 39 | 40 | // Return a random number between 0 and max-1, inclusive 41 | uint32_t Rand::random(uint32_t max) 42 | { 43 | return (uint32_t) (((xorshift96() & 0xFFFF) * max)>>16); 44 | } 45 | 46 | // Return a random number between 0 and 4095, inclusive 47 | uint32_t Rand::random() 48 | { 49 | // Version #1: return (uint32_t) (((xorshift96() & 0xFFFF) * 4096)>>16); 50 | // Version #2: return (uint32_t) (((xorshift96() & 0xFFFF)<<12)>>16); 51 | 52 | // Version #3: 53 | return (uint32_t) ((xorshift96() & 0xFFFF)>>4); 54 | } 55 | 56 | -------------------------------------------------------------------------------- /Rand.h: -------------------------------------------------------------------------------- 1 | #ifndef Rand_h 2 | #define Rand_h 3 | 4 | // 5 | // Based on the Mozzy (http://sensorium.github.io/Mozzi/) random number code, which in 6 | // turn is based on George. (2003). Xorshift RNGs. http://www.jstatsoft.org/v08/i14/xorshift.pdf 7 | // 8 | 9 | class Rand 10 | { 11 | public: 12 | Rand(); 13 | 14 | uint32_t xorshift96(); 15 | void seed(uint32_t seed); 16 | uint32_t random(uint32_t min, uint32_t max); 17 | uint32_t random(uint32_t max); 18 | uint32_t random(); 19 | 20 | private: 21 | unsigned long x,y,z; 22 | }; 23 | 24 | #endif -------------------------------------------------------------------------------- /RotaryEncoder.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Encoder code modified from: 3 | // http://hifiduino.wordpress.com/2010/10/20/rotaryencoder-hw-sw-no-debounce/ 4 | // 5 | 6 | #include "Arduino.h" 7 | #include "RotaryEncoder.h" 8 | 9 | RotaryEncoder::RotaryEncoder(uint8_t pin_a, uint8_t pin_b, uint8_t pin_c) 10 | { 11 | this->pin_a = pin_a; 12 | this->pin_b = pin_b; 13 | this->pin_c = pin_c; 14 | 15 | pinMode(this->pin_a, INPUT_PULLUP); 16 | pinMode(this->pin_b, INPUT_PULLUP); 17 | pinMode(this->pin_c, INPUT_PULLUP); 18 | 19 | if(digitalRead(this->pin_c) == 1) 20 | { 21 | this->state |= 0b00000010; 22 | } 23 | 24 | if(digitalRead(this->pin_b) == 1) 25 | { 26 | this->state |= 0b00000001; 27 | } 28 | } 29 | 30 | void RotaryEncoder::init() 31 | { 32 | // Read the encoder and throw away the first reading. This is important, 33 | // otherwise the first reading of the rotary encoder might incorrectly 34 | // report a state change. 35 | this->read(); 36 | } 37 | 38 | int8_t RotaryEncoder::read() 39 | { 40 | state <<= 2; 41 | 42 | // add current state 43 | if(digitalRead(this->pin_c) == 1) 44 | { 45 | state |= 0b00000010; 46 | } 47 | 48 | if(digitalRead(this->pin_b) == 1) 49 | { 50 | state |= 0b00000001; 51 | } 52 | 53 | return (this->enc_states[( state & 0x0f )]); // 0x0F == 0000 1111 54 | } 55 | 56 | int8_t RotaryEncoder::readButton() 57 | { 58 | return (! digitalRead(this->pin_a)); 59 | } 60 | 61 | boolean RotaryEncoder::pressed() 62 | { 63 | if ((millis() - last_debounce_time) > debounce_delay) 64 | { 65 | boolean button_value = ! digitalRead(this->pin_a); 66 | 67 | if(old_button_value != button_value) last_debounce_time = millis(); 68 | 69 | if(old_button_value == false && button_value == true) 70 | { 71 | 72 | old_button_value = button_value; 73 | return(true); 74 | } 75 | 76 | old_button_value = button_value; 77 | return(false); 78 | } 79 | } 80 | 81 | boolean RotaryEncoder::released() 82 | { 83 | boolean button_value = ! digitalRead(this->pin_a); 84 | 85 | if(old_button_value == true && button_value == false) 86 | { 87 | old_button_value = button_value; 88 | return(true); 89 | } 90 | 91 | old_button_value = button_value; 92 | return(false); 93 | } -------------------------------------------------------------------------------- /RotaryEncoder.h: -------------------------------------------------------------------------------- 1 | #ifndef RotaryEncoder_h 2 | #define RotaryEncoder_h 3 | 4 | #include "Arduino.h" 5 | #include 6 | 7 | class RotaryEncoder 8 | { 9 | public: 10 | RotaryEncoder(uint8_t pin_a, uint8_t pin_b, uint8_t pin_c); 11 | void init(); 12 | int8_t read(); 13 | int8_t readButton(); 14 | boolean released(); 15 | boolean pressed(); 16 | 17 | uint8_t state; 18 | uint8_t pin_a; 19 | uint8_t pin_b; 20 | uint8_t pin_c; 21 | 22 | boolean old_button_value = false; 23 | 24 | int8_t enc_states[16] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0}; 25 | 26 | // Debouncing for push-in switch 27 | uint32_t last_debounce_time = 0; 28 | uint32_t debounce_delay = 50; // 50 milliseconds 29 | }; 30 | 31 | #endif -------------------------------------------------------------------------------- /Sequencer.cpp: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include "Sequencer.h" 3 | 4 | Sequencer::Sequencer() 5 | { 6 | } 7 | 8 | void Sequencer::init() 9 | { 10 | // Clear drift array 11 | memset(this->drift, 0, sizeof(this->drift)); 12 | } 13 | 14 | void Sequencer::resetDrift() 15 | { 16 | memset(this->drift, 0, sizeof(this->drift)); 17 | } -------------------------------------------------------------------------------- /Sequencer.h: -------------------------------------------------------------------------------- 1 | #ifndef Sequencer_h 2 | #define Sequencer_h 3 | 4 | #include "Arduino.h" 5 | #include "defines.h" 6 | #include 7 | #include "Memory.h" 8 | 9 | class Sequencer 10 | { 11 | public: 12 | 13 | // Methods 14 | Sequencer(); 15 | 16 | void init(); 17 | void resetDrift(); 18 | 19 | // Variables 20 | int16_t drift[MAX_SEQUENCE_LENGTH]; // stores drift values 21 | 22 | }; 23 | 24 | #endif -------------------------------------------------------------------------------- /Snapshot.cpp: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include "Snapshot.h" 3 | 4 | Snapshot::Snapshot(Memory *memory) 5 | { 6 | this->memory = memory; 7 | } 8 | 9 | void Snapshot::init() 10 | { 11 | uint8_t low_byte; 12 | uint8_t high_byte; 13 | 14 | // Load sequence from non-volitile ram 15 | for(int i=0; iread(memory_address); 20 | high_byte = memory->read(memory_address + 1); 21 | 22 | this->sequence[i] = word(high_byte, low_byte); 23 | } 24 | 25 | // Load sequence length 26 | low_byte = memory->read(MEM_ADDR_SEQUENCE_LENGTH); 27 | high_byte = memory->read(MEM_ADDR_SEQUENCE_LENGTH + 1); 28 | this->sequence_length = word(high_byte, low_byte); 29 | 30 | // Load clock division 31 | low_byte = memory->read(MEM_ADDR_CLOCK_DIVISION); 32 | high_byte = memory->read(MEM_ADDR_CLOCK_DIVISION + 1); 33 | this->clock_division = word(high_byte, low_byte); 34 | 35 | // Load slip 36 | this->slip = memory->read(MEM_ADDR_SLIP); 37 | 38 | // Load drift percentage 39 | this->drift_percentage = memory->read(MEM_ADDR_DRIFT_PERCENTAGE); 40 | 41 | // Load drift amount 42 | low_byte = memory->read(MEM_ADDR_DRIFT_AMOUNT); 43 | high_byte = memory->read(MEM_ADDR_DRIFT_AMOUNT + 1); 44 | this->drift_amount = word(high_byte, low_byte); 45 | 46 | // Load hold pattern 47 | this->hold = memory->read(MEM_ADDR_HOLD); 48 | 49 | // Load display intensity 50 | this->display_intensity = memory->read(MEM_ADDR_INTENSITY); 51 | 52 | // Load scale 53 | this->scale = memory->read(MEM_ADDR_SCALE); 54 | 55 | // Load hold 56 | this->hold = memory->read(MEM_ADDR_HOLD); 57 | 58 | // Load hold offset 59 | this->hold_offset = memory->read(MEM_ADDR_HOLD_OFFSET); 60 | 61 | // Load hold threshold 62 | low_byte = memory->read(MEM_ADDR_HOLD_THRESHOLD); 63 | high_byte = memory->read(MEM_ADDR_HOLD_THRESHOLD + 1); 64 | this->hold_threshold = word(high_byte, low_byte); 65 | 66 | // Load song1 and song2 67 | this->song = memory->read(MEM_ADDR_SONG); 68 | this->song2 = memory->read(MEM_ADDR_SONG2); 69 | 70 | // Load reset input assignment 71 | this->rst_input_assignment = memory->read(MEM_RST_INPUT_ASSIGNMENT); 72 | 73 | // Load press functionality 74 | this->press_functionality = memory->read(MEM_PRESS_FUNCTIONALITY); 75 | } 76 | 77 | 78 | 79 | // 80 | // setValue 81 | // 82 | 83 | void Snapshot::setValue(uint16_t step, uint16_t value) 84 | { 85 | if(value != this->sequence[step]) 86 | { 87 | // Write the value to the sequence array 88 | this->sequence[step] = value; 89 | 90 | // Also store the value in non-volitile memory 91 | uint16_t memory_address = step * 2; 92 | 93 | memory->write(memory_address, lowByte(value)); 94 | memory->write(memory_address + 1, highByte(value)); 95 | } 96 | } 97 | 98 | // 99 | // Sequence Length 100 | // 101 | 102 | void Snapshot::setSequenceLength(uint16_t sequence_length) 103 | { 104 | if(sequence_length != this->sequence_length) 105 | { 106 | this->sequence_length = sequence_length; 107 | memory->write(MEM_ADDR_SEQUENCE_LENGTH, lowByte(sequence_length)); 108 | memory->write(MEM_ADDR_SEQUENCE_LENGTH + 1, highByte(sequence_length)); 109 | } 110 | } 111 | 112 | // 113 | // Clock Division 114 | // 115 | 116 | void Snapshot::setClockDivision(uint16_t clock_division) 117 | { 118 | if(clock_division != this->clock_division) 119 | { 120 | this->clock_division = clock_division; 121 | memory->write(MEM_ADDR_CLOCK_DIVISION, lowByte(clock_division)); 122 | memory->write(MEM_ADDR_CLOCK_DIVISION + 1, highByte(clock_division)); 123 | } 124 | } 125 | 126 | // 127 | // Slip 128 | // 129 | 130 | void Snapshot::setSlip(uint8_t slip) 131 | { 132 | if(slip != this->slip) 133 | { 134 | this->slip = slip; 135 | memory->write(MEM_ADDR_SLIP, slip); 136 | } 137 | } 138 | 139 | // 140 | // Drift Percentage 141 | // 142 | 143 | void Snapshot::setDriftPercentage(uint8_t drift_percentage) 144 | { 145 | if(drift_percentage != this->drift_percentage) 146 | { 147 | this->drift_percentage = drift_percentage; 148 | memory->write(MEM_ADDR_DRIFT_PERCENTAGE, drift_percentage); 149 | } 150 | } 151 | 152 | // 153 | // Drift Amount 154 | // 155 | 156 | void Snapshot::setDriftAmount(uint16_t drift_amount) 157 | { 158 | if(drift_amount != this->drift_amount) 159 | { 160 | this->drift_amount = drift_amount; 161 | memory->write(MEM_ADDR_DRIFT_AMOUNT, lowByte(drift_amount)); 162 | memory->write(MEM_ADDR_DRIFT_AMOUNT + 1, highByte(drift_amount)); 163 | } 164 | } 165 | 166 | // 167 | // Hold 168 | // 169 | 170 | void Snapshot::setHold(uint8_t hold) 171 | { 172 | if(hold != this->hold) 173 | { 174 | this->hold = hold; 175 | memory->write(MEM_ADDR_HOLD, hold); 176 | } 177 | } 178 | 179 | // 180 | // Hold Offset 181 | // 182 | 183 | void Snapshot::setHoldOffset(uint16_t hold_offset) 184 | { 185 | if(hold_offset != this->hold_offset) 186 | { 187 | this->hold_offset = hold_offset; 188 | memory->write(MEM_ADDR_HOLD_OFFSET, hold_offset); 189 | } 190 | } 191 | 192 | // 193 | // Hold Threshold 194 | // 195 | 196 | void Snapshot::setHoldThreshold(uint16_t hold_threshold) 197 | { 198 | if(hold_threshold != this->hold_threshold) 199 | { 200 | this->hold_threshold = hold_threshold; 201 | memory->write(MEM_ADDR_HOLD_THRESHOLD, lowByte(hold_threshold)); 202 | memory->write(MEM_ADDR_HOLD_THRESHOLD+1, highByte(hold_threshold)); 203 | } 204 | } 205 | 206 | // 207 | // Display Intensity 208 | // 209 | 210 | void Snapshot::setDisplayIntensity(uint8_t display_intensity) 211 | { 212 | if(display_intensity != this->display_intensity) 213 | { 214 | this->display_intensity = display_intensity; 215 | memory->write(MEM_ADDR_INTENSITY, display_intensity); 216 | } 217 | } 218 | 219 | // 220 | // Scale 221 | // 222 | 223 | void Snapshot::setScale(uint8_t scale) 224 | { 225 | if(scale != this->scale) 226 | { 227 | this->scale = scale; 228 | memory->write(MEM_ADDR_SCALE, scale); 229 | } 230 | } 231 | 232 | 233 | // 234 | // Song 235 | // 236 | 237 | void Snapshot::setSong(uint16_t song) 238 | { 239 | if(song != this->song) 240 | { 241 | this->song = song; 242 | memory->write(MEM_ADDR_SONG, song); 243 | } 244 | } 245 | 246 | // 247 | // Song2 248 | // 249 | 250 | void Snapshot::setSong2(uint16_t song2) 251 | { 252 | if(song2 != this->song2) 253 | { 254 | this->song2 = song2; 255 | memory->write(MEM_ADDR_SONG2, song2); 256 | } 257 | } 258 | 259 | // 260 | // rst_input_assignment 261 | // 262 | 263 | void Snapshot::setRstInputAssignment(uint8_t rst_input_assignment) 264 | { 265 | if(rst_input_assignment != this->rst_input_assignment) 266 | { 267 | this->rst_input_assignment = rst_input_assignment; 268 | memory->write(MEM_RST_INPUT_ASSIGNMENT, rst_input_assignment); 269 | } 270 | } 271 | 272 | // 273 | // press functionality (course/fine) 274 | // 275 | 276 | void Snapshot::setPressFunctionality(uint8_t press_functionality) 277 | { 278 | if(press_functionality != this->press_functionality) 279 | { 280 | this->press_functionality = press_functionality; 281 | memory->write(MEM_PRESS_FUNCTIONALITY, press_functionality); 282 | } 283 | } -------------------------------------------------------------------------------- /Snapshot.h: -------------------------------------------------------------------------------- 1 | #ifndef Snapshot_h 2 | #define Snapshot_h 3 | 4 | #include "Arduino.h" 5 | #include "defines.h" 6 | #include 7 | #include "Memory.h" 8 | 9 | class Snapshot 10 | { 11 | public: 12 | 13 | // Methods 14 | Snapshot(Memory *memory); 15 | 16 | void init(); 17 | 18 | void setValue(uint16_t step, uint16_t value); 19 | void setStep(uint16_t step); 20 | void setSequenceLength(uint16_t length); 21 | void setClockDivision(uint16_t clock_division); 22 | void setSlip(uint8_t length); 23 | void setDriftPercentage(uint8_t length); 24 | void setDriftAmount(uint16_t length); 25 | void setDisplayIntensity(uint8_t intensity); 26 | void setScale(uint8_t scale); 27 | void setSong(uint16_t song); 28 | void setSong2(uint16_t song); 29 | void setHold(uint8_t hold); 30 | void setHoldOffset(uint16_t hold_offset); 31 | void setHoldThreshold(uint16_t hold_threshold); 32 | void setRstInputAssignment(uint8_t rst_input_assignment); 33 | void setPressFunctionality(uint8_t press_functionality); 34 | 35 | // Variables 36 | uint16_t sequence[MAX_SEQUENCE_LENGTH]; // stores sequencer values 37 | 38 | uint16_t step = 0; 39 | uint16_t sequence_length = 8; // Sequence length 40 | uint16_t clock_division = 1; // clock division 41 | uint8_t slip = 0; // Percentage chance to slip 42 | uint8_t drift_percentage = 0; // Percentage changce to drift 43 | uint16_t drift_amount = 0; // Amount to drift 44 | uint8_t hold = 0; 45 | uint16_t hold_offset = 0; 46 | uint16_t hold_threshold = 0; 47 | uint8_t display_intensity = 15; // Display brightness 48 | uint8_t scale = 0; // Quantization musical scale 49 | uint16_t song = 0; 50 | uint16_t song2 = 0; 51 | uint8_t rst_input_assignment = 0; 52 | uint8_t press_functionality = 0; 53 | 54 | private: 55 | 56 | Memory *memory; 57 | }; 58 | 59 | /* 60 | 61 | Snapshot memory consumption 62 | =========================== 63 | 64 | 16 * (64 + 5) = 1104 bits = 138 bytes = 69 uint16_t. Which should allow for 4 snapshots 65 | 66 | */ 67 | 68 | #endif -------------------------------------------------------------------------------- /SwitchInput.cpp: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include "SwitchInput.h" 3 | 4 | SwitchInput::SwitchInput(uint8_t pin1, uint8_t pin2) 5 | { 6 | this->pin1 = pin1; 7 | this->pin2 = pin2; 8 | pinMode(pin1, INPUT_PULLUP); 9 | pinMode(pin2, INPUT_PULLUP); 10 | } 11 | 12 | void SwitchInput::poll() 13 | { 14 | uint8_t p1 = ! digitalRead(this->pin1); 15 | uint8_t p2 = ! digitalRead(this->pin2); 16 | 17 | if(p1) 18 | { 19 | position = 3; 20 | } 21 | else if(p2) 22 | { 23 | position = 1; 24 | } 25 | else 26 | { 27 | position = 2; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SwitchInput.h: -------------------------------------------------------------------------------- 1 | #ifndef SwitchInput_h 2 | #define SwitchInput_h 3 | 4 | #include "Arduino.h" 5 | 6 | class SwitchInput 7 | { 8 | public: 9 | 10 | // Methods 11 | SwitchInput(uint8_t pin1, uint8_t pin2); 12 | void poll(); 13 | 14 | // Variables 15 | uint8_t position = 0; 16 | uint8_t pin1; 17 | uint8_t pin2; 18 | }; 19 | 20 | #endif -------------------------------------------------------------------------------- /Transposer.cpp: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include "Transposer.h" 3 | #include "GlobalScales.h" 4 | 5 | 6 | Transposer::Transposer(Snapshot *snapshot) 7 | { 8 | this->snapshot = snapshot; 9 | } 10 | 11 | void Transposer::clock() 12 | { 13 | this->clock_counter += 1; 14 | 15 | if(this->clock_counter == this->clock_division) 16 | { 17 | this->clock_counter = 0; 18 | this->step(); 19 | } 20 | } 21 | 22 | void Transposer::step() 23 | { 24 | this->pattern_step += 1; 25 | if(this->pattern_step == 16) this->pattern_step = 0; 26 | } 27 | 28 | void Transposer::reset() 29 | { 30 | this->pattern_step = 0; 31 | this->clock_counter = 0; 32 | } 33 | 34 | uint16_t Transposer::transpose(int16_t note_to_transpose, uint8_t song) 35 | { 36 | int table_index = TRANSPOSITION_TABLES[song][this->pattern_step]; 37 | int tranpose_amount = 0; 38 | 39 | if(table_index < 0) 40 | { 41 | tranpose_amount = (int) NOTES[abs(table_index)] * -1; 42 | } 43 | else 44 | { 45 | tranpose_amount = (int) NOTES[table_index]; 46 | } 47 | 48 | int transposed_value = (int) note_to_transpose + tranpose_amount; 49 | 50 | if(transposed_value > 4095) transposed_value = 4095 - transposed_value; 51 | if(transposed_value < 0) transposed_value = -1 * transposed_value; 52 | 53 | transposed_value = constrain(transposed_value, 0, 4095); 54 | 55 | return(transposed_value); 56 | } 57 | -------------------------------------------------------------------------------- /Transposer.h: -------------------------------------------------------------------------------- 1 | #ifndef Transposer_h 2 | #define Transposer_h 3 | 4 | #include "Arduino.h" 5 | #include 6 | #include "defines.h" 7 | #include "Snapshot.h" 8 | #include "GlobalTranspositionTables.h" 9 | 10 | class Transposer 11 | { 12 | public: 13 | 14 | // Methods 15 | Transposer(Snapshot *snapshot); 16 | void clock(); 17 | void step(); 18 | void reset(); 19 | uint16_t transpose(int16_t value, uint8_t song); 20 | 21 | // Variables 22 | uint16_t pattern_step = 0; 23 | uint16_t pattern_number = 0; 24 | uint8_t clock_division = 1; 25 | int8_t clock_counter = 0; 26 | 27 | Snapshot *snapshot; 28 | }; 29 | 30 | #endif -------------------------------------------------------------------------------- /TriggerInput.cpp: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | #include "TriggerInput.h" 3 | 4 | TriggerInput::TriggerInput(uint8_t pin) 5 | { 6 | this->pin = pin; 7 | pinMode(pin, INPUT_PULLUP); 8 | } 9 | 10 | // 11 | // void TriggerInput::poll() 12 | // 13 | // Reads the value of the trigger input and sets the class 14 | // variable 'triggered' if the input was triggered on this 15 | // polling cycle. Uses code debouncing. 16 | // 17 | 18 | void TriggerInput::poll() 19 | { 20 | if ((millis() - last_debounce_time) > debounce_delay) 21 | { 22 | boolean pin_value = ! digitalRead(this->pin); 23 | 24 | if(pin_value && (old_pin_value == false)) 25 | { 26 | this->triggered = true; 27 | } 28 | else 29 | { 30 | this->triggered = false; 31 | } 32 | 33 | if(old_pin_value != pin_value) last_debounce_time = millis(); 34 | 35 | this->old_pin_value = pin_value; 36 | } 37 | else 38 | { 39 | this->triggered = false; 40 | } 41 | } 42 | 43 | // 44 | // boolean TriggerInput::read() 45 | // 46 | // Reads the value of the trigger input and returns it. 47 | // 48 | 49 | boolean TriggerInput::read() 50 | { 51 | return(! digitalRead(this->pin)); 52 | } 53 | 54 | // 55 | // boolean TriggerInput::setDebounce() 56 | // 57 | // Sets the debounce time, in milliseconds used in TriggerInput::poll() 58 | // 59 | 60 | void TriggerInput::setDebounce(uint32_t debounce_delay) 61 | { 62 | this->debounce_delay = debounce_delay; 63 | } 64 | -------------------------------------------------------------------------------- /TriggerInput.h: -------------------------------------------------------------------------------- 1 | #ifndef TriggerInput_h 2 | #define TriggerInput_h 3 | 4 | #include "Arduino.h" 5 | 6 | class TriggerInput 7 | { 8 | public: 9 | 10 | // Methods 11 | TriggerInput(uint8_t pin); 12 | void poll(); 13 | boolean read(); 14 | void setDebounce(uint32_t debounce_delay); 15 | 16 | // Variables 17 | boolean triggered = false; 18 | boolean old_pin_value = false; 19 | uint8_t pin; 20 | 21 | uint32_t last_debounce_time = 0; 22 | uint32_t debounce_delay = 50; // 50 milliseconds 23 | }; 24 | 25 | #endif -------------------------------------------------------------------------------- /defines.h: -------------------------------------------------------------------------------- 1 | #define PIN_CLOCK_INPUT 1 2 | #define PIN_RESET_INPUT 0 3 | 4 | #define PIN_CLOCK_BUTTON 2 5 | #define PIN_RESET_BUTTON 3 6 | 7 | #define PIN_SWITCH_A 5 8 | #define PIN_SWITCH_B 6 9 | 10 | #define DISPLAY_I2C_ADDRESS 0x03 11 | #define EEPROM_I2C_ADDRESS 0x50 // 80 decimal 12 | #define DAC_I2C_ADDRESS 0x60 // 90 decimal 13 | 14 | #define TOP_DISPLAY 0 15 | #define BOTTOM_DISPLAY 1 16 | 17 | #define SEQUENCE_PLAYBACK_MODE 0 18 | #define SEQUENCE_EDIT_MODE 1 19 | #define SETTINGS_MODE 2 20 | 21 | #define RST_ASSIGNMENT_RESET 0 22 | #define RST_ASSIGNMENT_SAMPLE_AND_HOLD 1 23 | 24 | #define MAX_SEQUENCE_LENGTH 64 // max 256 to fit into 1 byte 25 | #define PRESS_ASSIGNMENT_FINE 0 26 | #define PRESS_ASSIGNMENT_COARSE 1 27 | 28 | #define MEM_ADDR_SEQUENCE_LENGTH 130 29 | #define MEM_ADDR_CLOCK_DIVISION 132 30 | #define MEM_ADDR_QUANTIZATION 134 31 | #define MEM_ADDR_SELF_INITIALIZATION 136 32 | #define MEM_ADDR_SCALE 138 33 | #define MEM_ADDR_INTENSITY 140 34 | #define MEM_ADDR_SLIP 142 35 | #define MEM_ADDR_DRIFT_PERCENTAGE 144 36 | #define MEM_ADDR_DRIFT_AMOUNT 146 37 | #define MEM_ADDR_HOLD 148 38 | #define MEM_ADDR_SONG 150 39 | #define MEM_ADDR_SONG2 152 40 | #define MEM_ADDR_HOLD_OFFSET 154 41 | #define MEM_ADDR_HOLD_THRESHOLD 156 42 | #define MEM_RST_INPUT_ASSIGNMENT 158 43 | #define MEM_PRESS_FUNCTIONALITY 160 44 | 45 | #define NUMBER_OF_SETTINGS_PAGES 17 46 | #define NUMBER_OF_SCALES 14 47 | #define NUMBER_OF_SONGS 16 48 | 49 | // 7-segment LED font 50 | 51 | #define __a__ 0b01110111 52 | #define __A__ 0b01110111 53 | #define __d__ 0b00111101 54 | #define __c__ 0b00001101 55 | #define __C__ 0b01001110 56 | #define __E__ 0b01001111 57 | #define __F__ 0b01000111 58 | #define __g__ 0b01111011 59 | #define __h__ 0b00010111 60 | #define __H__ 0b00110111 61 | #define __i__ 0b00010000 62 | #define __I__ 0b00010000 63 | #define __j__ 0b00111000 64 | #define __L__ 0b00001110 65 | #define __M__ 0b01010100 66 | #define __m__ 0b01010100 67 | #define __n__ 0b00010101 68 | #define __o__ 0b00011101 69 | #define __O__ 0b01111110 70 | #define __P__ 0b01100111 71 | #define __r__ 0b00000101 72 | #define __S__ 0b01011011 73 | #define __t__ 0b00001111 74 | #define __v__ 0b00011100 75 | #define __Y__ 0b00100111 76 | #define __space__ 0b00000000 77 | 78 | #define __dash__ 0b00000001 79 | #define __underscore__ 0b00001000 80 | 81 | 82 | 83 | --------------------------------------------------------------------------------