├── .gitattributes ├── Schematic.png ├── Front Panel.png ├── Parts List.pdf ├── KiCad - Front Panel ├── Freq - KiCad.kicad_sch ├── fp-lib-table ├── Freq - KiCad.kicad_prl └── Freq - KiCad.kicad_pro ├── Gerber Files ├── Freaq - PCB Gerber Files.zip └── Freaq -Front Panel Gerber Files.zip ├── Arduino Files └── MutantFMSynth │ ├── MutantTechnoSynth.code-workspace │ ├── avSource.cpp │ ├── MutantFMSynthOptions.h │ ├── avMidi.h │ ├── LedMatrix.h │ ├── avSequencerMultiTrack.h │ ├── avSequencer.h │ ├── mutantBitmaps.h │ ├── avSource.h │ ├── nullwaveform2048_int8.h │ ├── revsaw2048_int8.h │ ├── LedMatrix.cpp │ ├── square2048_int8.h │ ├── avSequencerMultitrack.cpp │ ├── pseudorandom2048_int8.h │ ├── avSourceFM.cpp │ ├── avSequencer.cpp │ └── MutantFMSynth.ino └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /Schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lonesoulsurfer/Freaq_FM_Synth-Modular_Synth_Version/HEAD/Schematic.png -------------------------------------------------------------------------------- /Front Panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lonesoulsurfer/Freaq_FM_Synth-Modular_Synth_Version/HEAD/Front Panel.png -------------------------------------------------------------------------------- /Parts List.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lonesoulsurfer/Freaq_FM_Synth-Modular_Synth_Version/HEAD/Parts List.pdf -------------------------------------------------------------------------------- /KiCad - Front Panel/Freq - KiCad.kicad_sch: -------------------------------------------------------------------------------- 1 | (kicad_sch (version 20211123) (generator eeschema) 2 | (paper "A4") 3 | (lib_symbols) 4 | (symbol_instances) 5 | ) 6 | -------------------------------------------------------------------------------- /Gerber Files/Freaq - PCB Gerber Files.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lonesoulsurfer/Freaq_FM_Synth-Modular_Synth_Version/HEAD/Gerber Files/Freaq - PCB Gerber Files.zip -------------------------------------------------------------------------------- /Gerber Files/Freaq -Front Panel Gerber Files.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lonesoulsurfer/Freaq_FM_Synth-Modular_Synth_Version/HEAD/Gerber Files/Freaq -Front Panel Gerber Files.zip -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/MutantTechnoSynth.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "name": "211109-210721-nanoatmega328new", 5 | "path": ".." 6 | } 7 | ], 8 | "settings": {} 9 | } -------------------------------------------------------------------------------- /KiCad - Front Panel/fp-lib-table: -------------------------------------------------------------------------------- 1 | (fp_lib_table 2 | (lib (name "Freq - Front Panel")(type "KiCad")(uri "C:/Users/marcus/Documents/Electronic Projects/Freaq/Freq - Front Panel")(options "")(descr "")) 3 | ) 4 | -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/avSource.cpp: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------------------------------------- 2 | * avSource.cpp 3 | * 4 | * Stub for base MutatingSource class 5 | * 6 | * Source Code Repository: https://github.com/Meebleeps/MeeBleeps-Freaq-FM-Synth 7 | * Youtube Channel: https://www.youtube.com/channel/UC4I1ExnOpH_GjNtm7ZdWeWA 8 | * 9 | * (C) 2021-2022 Meebleeps 10 | *----------------------------------------------------------------------------------------------------------- 11 | */ 12 | #include "avSource.h" 13 | 14 | 15 | 16 | MutatingSource::MutatingSource() 17 | { 18 | // base constructor; 19 | for (uint8_t i = 0; i < MAX_SOURCE_PARAMS; i++) 20 | { 21 | param[i] = 0; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/MutantFMSynthOptions.h: -------------------------------------------------------------------------------- 1 | #ifndef MUTANTFMSYNTHOPTION_H 2 | #define MUTANTFMSYNTHOPTION_H 3 | 4 | 5 | // 09 May 2022 6 | // added compile options for normally-open or normally-closed switches 7 | 8 | // if your switches are NORMALLY OPEN, include this line and comment out the #define below 9 | //#undef SWITCH_TYPE_NORMALLY_CLOSED 10 | 11 | // if your switches are NORMALLY CLOSED, include this line and comment out the #undef above 12 | 13 | 14 | 15 | 16 | 17 | // 09 May 2022 18 | // added compile options to reduce compiled image size to fit into boards with larger bootloaders, or using different compilers such as Arduino IDE 19 | // uncomment the below to reduce the image size by 2KB 20 | 21 | #define COMPILE_SMALLER_BINARY 22 | 23 | 24 | 25 | 26 | #endif 27 | 28 | 29 | -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/avMidi.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------------------------------------- 2 | * avMidi.h 3 | * 4 | * Stub for MIDI-out support 5 | * 6 | * Tested but disabled. 7 | * 8 | * To re-enable make sure that no other data is output from the Serial port 9 | * and uncomment the #define ENABLE_MIDI_OUTPUT 10 | * 11 | * Assumes serial port is alreay set up at 31250baud 12 | * 13 | * Source Code Repository: https://github.com/Meebleeps/MeeBleeps-Freaq-FM-Synth 14 | * Youtube Channel: https://www.youtube.com/channel/UC4I1ExnOpH_GjNtm7ZdWeWA 15 | * 16 | * (C) 2021-2022 Meebleeps 17 | *----------------------------------------------------------------------------------------------------------- 18 | */ 19 | 20 | #ifndef AVMIDI_H 21 | #define AVMIDI_H 22 | 23 | #include 24 | 25 | // uncomment this to enable midi out support 26 | //#define ENABLE_MIDI_OUTPUT 27 | 28 | 29 | // plays a MIDI note. 30 | inline void midiNoteOn(uint8_t channel, uint8_t midiNote, uint8_t velocity) 31 | { 32 | Serial.write(channel << 4); 33 | Serial.write(midiNote); 34 | Serial.write(velocity); 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /KiCad - Front Panel/Freq - KiCad.kicad_prl: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "active_layer": 0, 4 | "active_layer_preset": "All Layers", 5 | "auto_track_width": true, 6 | "hidden_nets": [], 7 | "high_contrast_mode": 0, 8 | "net_color_mode": 1, 9 | "opacity": { 10 | "pads": 1.0, 11 | "tracks": 1.0, 12 | "vias": 1.0, 13 | "zones": 0.6 14 | }, 15 | "ratsnest_display_mode": 0, 16 | "selection_filter": { 17 | "dimensions": true, 18 | "footprints": true, 19 | "graphics": true, 20 | "keepouts": true, 21 | "lockedItems": true, 22 | "otherItems": true, 23 | "pads": true, 24 | "text": true, 25 | "tracks": true, 26 | "vias": true, 27 | "zones": true 28 | }, 29 | "visible_items": [ 30 | 0, 31 | 1, 32 | 2, 33 | 3, 34 | 4, 35 | 5, 36 | 8, 37 | 9, 38 | 10, 39 | 11, 40 | 12, 41 | 13, 42 | 14, 43 | 15, 44 | 16, 45 | 17, 46 | 18, 47 | 19, 48 | 20, 49 | 21, 50 | 22, 51 | 23, 52 | 24, 53 | 25, 54 | 26, 55 | 27, 56 | 28, 57 | 29, 58 | 30, 59 | 32, 60 | 33, 61 | 34, 62 | 35, 63 | 36 64 | ], 65 | "visible_layers": "fffffff_ffffffff", 66 | "zone_display_mode": 0 67 | }, 68 | "meta": { 69 | "filename": "Freq - KiCad.kicad_prl", 70 | "version": 3 71 | }, 72 | "project": { 73 | "files": [] 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/LedMatrix.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------------------------------------- 2 | * LedMatrix.h 3 | * 4 | * Defines an interface to a MAX7219 driving an 8x8 LED matrix 5 | * 6 | * Source Code Repository: https://github.com/Meebleeps/MeeBleeps-Freaq-FM-Synth 7 | * Youtube Channel: https://www.youtube.com/channel/UC4I1ExnOpH_GjNtm7ZdWeWA 8 | * 9 | * (C) 2021-2022 Meebleeps 10 | *----------------------------------------------------------------------------------------------------------- 11 | */ 12 | #ifndef ledMatrix_h 13 | #define ledMatrix_h 14 | #include "Arduino.h" 15 | 16 | // constants for LED matrix orientation. 0 = MAX7219 driver to the right of the display 17 | #define LEDMATRIX_ORIENTATION_0 0 18 | #define LEDMATRIX_ORIENTATION_90 1 19 | #define LEDMATRIX_ORIENTATION_180 2 20 | #define LEDMATRIX_ORIENTATION_270 3 21 | 22 | #define LEDMATRIX_MAXROWS 8 23 | #define LEDMATRIX_MAXCOLS 8 24 | 25 | #define LEDMATRIX_MODIFIED_ALL 255 26 | #define LEDMATRIX_MODIFIED_NONE 0 27 | 28 | // constants for pin control 29 | #define PIN_LEDMATRIX_DIN 11 30 | #define PIN_LEDMATRIX_CS 7 31 | #define PIN_LEDMATRIX_CLK 13 32 | 33 | // constants for display 34 | #define LED_DECODE_MODE 9 35 | #define LED_INTENSITY 10 36 | #define LED_SCAN_LIMIT 11 37 | #define LED_SHUTDOWN 12 38 | #define LED_DISPLAYTEST 16 39 | 40 | class LedMatrix 41 | { 42 | public: 43 | LedMatrix(); 44 | void initialise(); 45 | 46 | void setPixel(byte x, byte y, bool value); 47 | void togglePixel(byte x, byte y); 48 | void setRowPixels(byte y, byte value); 49 | void setColPixels(byte x, byte value); 50 | 51 | void drawLineV(byte x, byte startY, byte endY, bool on); 52 | void drawLineH(byte y, byte startX, byte endX, bool on); 53 | 54 | void displayIcon(byte* bitmap); 55 | 56 | void clearScreen(); 57 | void refresh(); 58 | 59 | void setIntensity(int intensity); 60 | void setOrientation(int orientation); 61 | 62 | void sparkle(int amount); 63 | protected: 64 | 65 | void writeDisplayData(uint8_t address, uint8_t value); 66 | byte orientation; 67 | byte vRAM[8]; 68 | 69 | private: 70 | byte displayBit[8] = {1,2,4,8,16,32,64,128}; 71 | byte rowModified; 72 | 73 | }; 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![image](https://github.com/user-attachments/assets/d43b7279-5da6-433b-8786-0992f0a1a54e) 2 | 3 | # Freaq_FM_Synth-Modular_Synth_Version 4 | 5 | The awesome Freaq FM Synth by MeeBleeps - designed for Eurorack Synths 6 | 7 | Youtube Vid - https://www.youtube.com/watch?v=fAgmykZD0DI&source_ve_path=Mjg2NjY 8 | 9 | First and foremost - I need to do a huge shoutout to MeeBleeps who designed this amazing synth! - https://github.com/Meebleeps/MeeBleeps-Freaq-FM-Synth 10 | 11 | My contribution has been the design of a PCB and front panel to suit a Eurorack to suit modular synth builds. It can be run from 12V power supply via a power connector used on on Euroracks or a 9V power supply via a JST connector. 12 | 13 | It also can be used as a standalone synth and hand on heart, holds up to most mini synths you can buy. 14 | 15 | The main goal with building this module is to create my own 'simple to build' modular synth. I wanted to keep everything as easy as possble with each module built with the following aims: 16 | 17 | - Can be powered by 9V (and 12V) 18 | - Easy to build with minimum components 19 | - Use Arduino to keep it simple (plus it helps to keep the components down and everything in tune) 20 | - Can fit into any modular synth Eurorck (include the ability to power the module via normal module power sources) 21 | - Has to sound great! 22 | 23 | I've created a step by step guide on my Instructables page which you can find below. This goes through how to upload the sketch using the correct version of Mozzie (1.1.2). 24 | https://www.instructables.com/Freaq-FM-Synth/ 25 | 26 | The Freaq FM Synth features dual independent 2-operator FM voices paired with a 2-track generative sequencer. You can stack the voices so they are in unison or have them in different polymeric step-counts. This allows you to have one voice play bass and the other lead. 27 | 28 | This is one funky little machine! There are a tonne of controls and waveforms along with attack/delay envelope and LFO per voice. 29 | 30 | Full instructions can be found in the Github repository 31 | 32 | ![image](https://github.com/user-attachments/assets/2b71c2c9-46d3-4fc6-9805-e5f03454d055) 33 | 34 | NOTE - the default start-up on the Freaq has mutation and density very low which means you might only hear a couple bleeps and boops and not much else. To get the synth going just turn the mutation knob fully left then fully right. Then hold down the FUNC button and do the same thing again. This will reset the mutation & density and you'll be good to go. 35 | -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/avSequencerMultiTrack.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------------------------------------- 2 | * avSequencerMultiTrack.h 3 | * 4 | * Defines a multitrack generative sequencer with multiple generative algorithms, musical scale quantisation, 5 | * variable sequence length (up to 16 steps) and multiple parameter-lock (motion-sequencing) channels 6 | * 7 | * (C) 2021-2022 Meebleeps 8 | *----------------------------------------------------------------------------------------------------------- 9 | */ 10 | 11 | #ifndef avSequencerMultiTrack_h 12 | #define avSequencerMultiTrack_h 13 | 14 | #include "avSequencer.h" 15 | #include "Arduino.h" 16 | #include 17 | #include 18 | 19 | #define MAX_SEQUENCER_TRACKS 2 20 | 21 | class MutatingSequencerMultiTrack : MutatingSequencer 22 | { 23 | public: 24 | MutatingSequencerMultiTrack(); 25 | 26 | using MutatingSequencer::newSequence; 27 | using MutatingSequencer::outputSyncPulse; 28 | using MutatingSequencer::syncPulse; 29 | using MutatingSequencer::update; 30 | using MutatingSequencer::getNextNoteLength; 31 | using MutatingSequencer::setNextNoteLength; 32 | using MutatingSequencer::toggleStart; 33 | using MutatingSequencer::nextAlgorithm; 34 | using MutatingSequencer::getAlgorithm; 35 | using MutatingSequencer::setMutationProbability; 36 | using MutatingSequencer::setNoteProbability; 37 | using MutatingSequencer::getTonic; 38 | using MutatingSequencer::setTonic; 39 | using MutatingSequencer::getScale; 40 | using MutatingSequencer::setScale; 41 | using MutatingSequencer::setOctave; 42 | using MutatingSequencer::getOctave; 43 | using MutatingSequencer::isRunning; 44 | 45 | 46 | void setParameterLock(byte channel, int value); 47 | int getParameterLock(byte channel); 48 | void clearAllParameterLocks(byte channel); 49 | 50 | void setParameterLock(byte track, byte channel, int value); 51 | int getParameterLock(byte track, byte channel); 52 | uint16_t getParameterLock(byte channel, byte track, byte step); 53 | void clearAllParameterLocks(byte track, byte channel); 54 | 55 | byte getCurrentNote(); 56 | byte getCurrentNote(byte track); 57 | byte getCurrentStep(); 58 | byte getCurrentStep(byte track); 59 | 60 | void setOctaveOffsetTrack1(int8_t offset); 61 | int8_t getOctaveOffsetTrack1(); 62 | 63 | byte getSequenceLength(); 64 | byte getSequenceLength(byte track); 65 | 66 | void setSequenceLength(byte newLength); 67 | void setSequenceLength(byte track, byte newLength); 68 | 69 | void mutateSequence(); 70 | void mutateSequenceDefault(); 71 | void mutateSequenceArp(); 72 | void mutateSequenceDrone(); 73 | void mutateSequenceArp2(); 74 | 75 | void nextStep(bool restart); 76 | bool update(bool restart); //returns true if sequencer moved to next step 77 | 78 | protected: 79 | 80 | byte currentTrackNote[MAX_SEQUENCER_TRACKS] = {0,0}; 81 | byte currentTrackStep[MAX_SEQUENCER_TRACKS] = {0,0}; 82 | byte trackSequenceLength[MAX_SEQUENCER_TRACKS] = {16,16}; 83 | 84 | int8_t octaveOffsetTrack1; 85 | 86 | }; 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/avSequencer.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------------------------------------- 2 | * avSequencer.h 3 | * 4 | * Defines a generative sequencer with multiple generative algorithms, musical scale quantisation, 5 | * variable sequence length (up to 16 steps) and multiple parameter-lock (motion-sequencing) channels 6 | * 7 | * (C) 2021 Meebleeps 8 | *----------------------------------------------------------------------------------------------------------- 9 | */ 10 | 11 | #ifndef avSequencer_h 12 | #define avSequencer_h 13 | 14 | #include "Arduino.h" 15 | #include "avMidi.h" 16 | #include 17 | #include 18 | 19 | #ifndef CONTROL_RATE 20 | #define CONTROL_RATE 256 21 | #endif 22 | 23 | 24 | #define MAX_SEQUENCE_LENGTH 16 25 | #define MAX_SCALE_LENGTH 12 26 | 27 | #define SCALEMODE_MAJOR 0 28 | #define SCALEMODE_MINOR 1 29 | #define SCALEMODE_PENTA 2 30 | #define SCALEMODE_GOA 3 31 | #define SCALEMODE_OCTAVE 4 32 | #define SCALEMODE_FIFTHS 5 33 | #define MAX_SCALE_COUNT 6 34 | 35 | #define MUTATE_ALGO_DEFAULT 0 36 | #define MUTATE_ALGO_ARPEGGIATED 1 37 | #define MUTATE_ALGO_DRONE 2 38 | #define MUTATE_ALGO_ARP2 3 39 | #define MAX_MUTATE_ALGO_COUNT 4 40 | 41 | #define MUTATE_MAX_OCTAVE_SPREAD 3 42 | 43 | #define AUDIO_OUTPUT_LATENCY_COMPENSATION_MICROS 8000 44 | #define SYNC_STEPS_PER_PULSE 2 45 | #define SYNC_STEPS_PER_TAP 4 46 | 47 | #define MAX_PARAMETER_LOCKS 6 48 | #define PARAM_LOCK_CHANNEL_0 0 49 | #define PARAM_LOCK_CHANNEL_1 1 50 | #define PARAM_LOCK_CHANNEL_2 2 51 | #define PARAM_LOCK_CHANNEL_3 3 52 | #define PARAM_LOCK_CHANNEL_4 4 53 | #define PARAM_LOCK_CHANNEL_5 5 54 | 55 | 56 | //#define SEQUENCER_TESTMODE 57 | 58 | class MutatingSequencer 59 | { 60 | public: 61 | MutatingSequencer(); 62 | MutatingSequencer(byte stepCount, byte scaleCount); 63 | 64 | void start(); 65 | void stop(); 66 | void toggleStart(); 67 | 68 | void newSequence(byte seqLength); 69 | void testSequence(); 70 | 71 | void mutateSequence(); 72 | void mutateSequenceDefault(); 73 | void mutateSequenceArp(); 74 | void mutateNoteLength(); 75 | void mutateMutation(); 76 | 77 | void nextStep(bool restart); 78 | bool update(bool restart); //returns true if sequencer moved to next step 79 | void syncPulse(int stepsPerClick); //accepts a sync pulse to synchronise the timer 80 | int8_t outputSyncPulse(); 81 | 82 | void print(); 83 | void printParameters(); 84 | void printSequence(); 85 | 86 | void setScale(uint8_t scaleMode); 87 | uint8_t getScale(); 88 | 89 | void setTonic(int8_t newTonic); 90 | int8_t getTonic(); 91 | 92 | void setOctave(int8_t newOctave); 93 | int8_t getOctave(); 94 | 95 | void setRetrigger(bool newRetrigState); 96 | 97 | void setParameterLock(byte channel, int value); 98 | int getParameterLock(byte channel); 99 | void clearAllParameterLocks(byte channel); 100 | 101 | void setNextNoteLength(uint16_t newNoteLength); 102 | uint16_t getNextNoteLength(); 103 | 104 | void setNoteProbability(byte newProbability); 105 | byte getNoteProbability(); 106 | 107 | void setMutationProbability(byte newProbability); 108 | byte getMutationProbability(); 109 | 110 | byte getCurrentNote(); 111 | byte getCurrentStep(); 112 | 113 | byte getSequenceLength(); 114 | void setSequenceLength(byte newLength); 115 | 116 | uint8_t getAlgorithm(); 117 | void setAlgorithm(uint8_t newValue); 118 | void nextAlgorithm(); 119 | 120 | uint8_t isRunning(); 121 | 122 | protected: 123 | byte mutationProbability; 124 | byte noteProbability; 125 | byte tonicProbability; 126 | byte mutationAlgorithm; 127 | 128 | byte sequenceLength; 129 | byte scaleNoteCount; 130 | uint16_t nextStepNoteLength; 131 | 132 | bool retrigState = false; 133 | byte retrigStep = 0; 134 | 135 | byte currentNote = 0; 136 | byte currentStep = 0; 137 | 138 | //TODO: change to store these in uint8_t to halve space, then can store 2 tracks of param locks in same space (with reduced resolution) 139 | // parameter values to get compressed to 8 bits on storage and expanded back out to 10 bits on retrival 140 | int parameterLocks[MAX_PARAMETER_LOCKS][MAX_SEQUENCE_LENGTH]; 141 | 142 | //byte syncPulseSteps; 143 | byte syncPulseClockDivide; //todo allow fractional to accelerate clock 144 | 145 | uint32_t timeSinceLastSyncPulseMicros; 146 | uint32_t lastSyncPulseTimeMicros; 147 | uint32_t lastStepTimeMicros; 148 | uint32_t nextStepTimeMicros; 149 | uint32_t nextStepTimeMillis; 150 | 151 | bool running; 152 | 153 | uint8_t currentScaleMode; 154 | byte tonicNote; 155 | byte octave; 156 | 157 | byte bpm; 158 | byte notes[MAX_SEQUENCE_LENGTH]; 159 | byte scaleNotes[MAX_SCALE_LENGTH]; 160 | byte octaveSpread; 161 | 162 | byte duckingCounter; 163 | 164 | private: 165 | bool _debugOutput; 166 | void initialiseScale(int scaleMode); 167 | EventDelay stepTimer; 168 | void setNextStepTimer(); 169 | bool syncPulseLive; 170 | uint32_t syncPulseCount; 171 | 172 | 173 | bool ignoreNextSyncPulse; 174 | 175 | 176 | }; 177 | 178 | #endif 179 | -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/mutantBitmaps.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------------------------------------- 2 | * mutantBitmaps.h 3 | * 4 | * defines bitmap icons for displaying on the LED matrix 5 | * 6 | * Stored in prog mem - copy the values into RAM before using 7 | * 8 | * Source Code Repository: https://github.com/Meebleeps/MeeBleeps-Freaq-FM-Synth 9 | * Youtube Channel: https://www.youtube.com/channel/UC4I1ExnOpH_GjNtm7ZdWeWA 10 | * 11 | * (C) 2021-2022 Meebleeps 12 | *----------------------------------------------------------------------------------------------------------- 13 | */ 14 | #ifndef MUTANT_BITMAPS 15 | #define MUTANT_BITMAPS 16 | #include 17 | #include 18 | 19 | #include "MutantFMSynthOptions.h" 20 | 21 | const PROGMEM byte BITMAP_MEEBLEEPS[] = {B00011000,B01111110,B11011011,B11011011,B11011011,B11011011,B11000011,B00000110}; 22 | 23 | const PROGMEM byte BITMAP_NUMERALS[8][8] = { 24 | {B00000000,B00000000,B00000000,B11100000,B10100000,B10100000,B10100000,B11100111} 25 | ,{B00000000,B00000000,B00000000,B01000000,B01000000,B01000000,B01000111,B01000000} 26 | ,{B00000000,B00000000,B00000000,B11100000,B00100000,B11100111,B10000000,B11100000} 27 | ,{B00000000,B00000000,B00000000,B11100000,B00100111,B11100000,B00100000,B11100000} 28 | ,{B00000000,B00000000,B00000000,B10100111,B10100000,B11100000,B00100000,B00100000} 29 | ,{B00000000,B00000000,B00000111,B11100000,B10000000,B11100000,B00100000,B11100000} 30 | ,{B00000000,B00000111,B00000000,B11100000,B10000000,B11100000,B10100000,B11100000} 31 | ,{B00000000,B00000111,B00000000,B11100000,B00100000,B00100000,B00100000,B00100000} 32 | }; 33 | const PROGMEM byte BITMAP_ALGORITHMS[4][8] = { 34 | {B01000001,B10010000,B00000100,B01010000,B01000010,B01001000,B01000001,B01000100} 35 | , {B00100001,B01000010,B00000100,B11101000,B00100000,B11100001,B10000010,B11100100} 36 | , {B00000000,B01111111,B00000000,B11101111,B00100000,B11101111,B00100000,B11100111} 37 | , {B00100000,B01010000,B00001000,B10100100,B10100010,B11100001,B00101000,B00100100} 38 | }; 39 | 40 | const PROGMEM byte BITMAP_VOICES[2][8] = { 41 | {B11110000,B00000000,B00000000,B10101000,B10101000,B10101000,B01001000,B01001000} 42 | , {B00001111,B00000000,B00000000,B10101110,B10100010,B10101110,B01001000,B01001110} 43 | }; 44 | 45 | const PROGMEM byte BITMAP_ALPHA[7][8] = { 46 | {B00000000,B00000000,B00000000,B11100000,B10100000,B11100000,B10100000,B10100000} 47 | ,{B00000000,B00000000,B00000000,B11100000,B10100000,B11000000,B10100000,B11100000} 48 | ,{B00000000,B00000000,B00000000,B11100000,B10000000,B10000000,B10000000,B11100000} 49 | ,{B00000000,B00000000,B00000000,B11000000,B10100000,B10100000,B10100000,B11000000} 50 | ,{B00000000,B00000000,B00000000,B11100000,B10000000,B11100000,B10000000,B11100000} 51 | ,{B00000000,B00000000,B00000000,B11100000,B10000000,B11100000,B10000000,B10000000} 52 | ,{B00000000,B00000000,B00000000,B11100000,B10000000,B10100000,B10100000,B11100000} 53 | }; 54 | 55 | /** @brief if COMPILE_SMALLER_BINARY flag is defined, omit the definition of the pseudorandom waveform icon */ 56 | #ifdef COMPILE_SMALLER_BINARY 57 | const PROGMEM byte BITMAP_WAVEFORMS[5][8] = { 58 | #else 59 | const PROGMEM byte BITMAP_WAVEFORMS[6][8] = { 60 | #endif 61 | {B00000000,B01100000,B10010000,B10010000,B00001001,B00001001,B00000110,B00000000} 62 | , {B00000000,B10000011,B10000101,B10001001,B10010001,B10100001,B11000001,B00000000} 63 | , {B00000000,B11000001,B10100001,B10010001,B10001001,B10000101,B10000011,B00000000} 64 | , {B00000000,B11110000,B10010000,B10010000,B10010001,B00010001,B00011111,B00000000} 65 | #ifndef COMPILE_SMALLER_BINARY 66 | , {B00000000,B10010001,B00001000,B00100010,B10000100,B00010001,B01000100,B00000000} 67 | #endif 68 | , {B00000000,B00000000,B00000000,B11111111,B00000000,B00000000,B00000000,B00000000} 69 | }; 70 | 71 | 72 | const PROGMEM byte BITMAP_FMMODE[4][8] = { 73 | {B00000011,B00000010,B00001110,B00001000,B00111000,B00100000,B11100000,B10000000} 74 | ,{B00000001,B00000010,B00000100,B00001000,B00010000,B00100000,B01000000,B10000000} 75 | ,{B00000000,B00000000,B00000000,B00000001,B00000110,B00011000,B01100000,B10000000} 76 | ,{B00000000,B00000000,B00000000,B11111111,B00000000,B00000000,B00000000,B00000000} 77 | }; 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /KiCad - Front Panel/Freq - KiCad.kicad_pro: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "design_settings": { 4 | "defaults": { 5 | "board_outline_line_width": 0.09999999999999999, 6 | "copper_line_width": 0.19999999999999998, 7 | "copper_text_italic": false, 8 | "copper_text_size_h": 1.5, 9 | "copper_text_size_v": 1.5, 10 | "copper_text_thickness": 0.3, 11 | "copper_text_upright": false, 12 | "courtyard_line_width": 0.049999999999999996, 13 | "dimension_precision": 4, 14 | "dimension_units": 3, 15 | "dimensions": { 16 | "arrow_length": 1270000, 17 | "extension_offset": 500000, 18 | "keep_text_aligned": true, 19 | "suppress_zeroes": false, 20 | "text_position": 0, 21 | "units_format": 1 22 | }, 23 | "fab_line_width": 0.09999999999999999, 24 | "fab_text_italic": false, 25 | "fab_text_size_h": 1.0, 26 | "fab_text_size_v": 1.0, 27 | "fab_text_thickness": 0.15, 28 | "fab_text_upright": false, 29 | "other_line_width": 0.15, 30 | "other_text_italic": false, 31 | "other_text_size_h": 1.0, 32 | "other_text_size_v": 1.0, 33 | "other_text_thickness": 0.15, 34 | "other_text_upright": false, 35 | "pads": { 36 | "drill": 0.762, 37 | "height": 1.524, 38 | "width": 1.524 39 | }, 40 | "silk_line_width": 0.15, 41 | "silk_text_italic": false, 42 | "silk_text_size_h": 1.0, 43 | "silk_text_size_v": 1.0, 44 | "silk_text_thickness": 0.15, 45 | "silk_text_upright": false, 46 | "zones": { 47 | "45_degree_only": false, 48 | "min_clearance": 0.508 49 | } 50 | }, 51 | "diff_pair_dimensions": [], 52 | "drc_exclusions": [], 53 | "meta": { 54 | "version": 2 55 | }, 56 | "rule_severities": { 57 | "annular_width": "error", 58 | "clearance": "error", 59 | "copper_edge_clearance": "error", 60 | "courtyards_overlap": "error", 61 | "diff_pair_gap_out_of_range": "error", 62 | "diff_pair_uncoupled_length_too_long": "error", 63 | "drill_out_of_range": "error", 64 | "duplicate_footprints": "warning", 65 | "extra_footprint": "warning", 66 | "footprint_type_mismatch": "error", 67 | "hole_clearance": "error", 68 | "hole_near_hole": "error", 69 | "invalid_outline": "error", 70 | "item_on_disabled_layer": "error", 71 | "items_not_allowed": "error", 72 | "length_out_of_range": "error", 73 | "malformed_courtyard": "error", 74 | "microvia_drill_out_of_range": "error", 75 | "missing_courtyard": "ignore", 76 | "missing_footprint": "warning", 77 | "net_conflict": "warning", 78 | "npth_inside_courtyard": "ignore", 79 | "padstack": "error", 80 | "pth_inside_courtyard": "ignore", 81 | "shorting_items": "error", 82 | "silk_over_copper": "warning", 83 | "silk_overlap": "warning", 84 | "skew_out_of_range": "error", 85 | "through_hole_pad_without_hole": "error", 86 | "too_many_vias": "error", 87 | "track_dangling": "warning", 88 | "track_width": "error", 89 | "tracks_crossing": "error", 90 | "unconnected_items": "error", 91 | "unresolved_variable": "error", 92 | "via_dangling": "warning", 93 | "zone_has_empty_net": "error", 94 | "zones_intersect": "error" 95 | }, 96 | "rules": { 97 | "allow_blind_buried_vias": false, 98 | "allow_microvias": false, 99 | "max_error": 0.005, 100 | "min_clearance": 0.0, 101 | "min_copper_edge_clearance": 0.0, 102 | "min_hole_clearance": 0.25, 103 | "min_hole_to_hole": 0.25, 104 | "min_microvia_diameter": 0.19999999999999998, 105 | "min_microvia_drill": 0.09999999999999999, 106 | "min_silk_clearance": 0.0, 107 | "min_through_hole_diameter": 0.3, 108 | "min_track_width": 0.19999999999999998, 109 | "min_via_annular_width": 0.049999999999999996, 110 | "min_via_diameter": 0.39999999999999997, 111 | "solder_mask_clearance": 0.0, 112 | "solder_mask_min_width": 0.0, 113 | "use_height_for_length_calcs": true 114 | }, 115 | "track_widths": [], 116 | "via_dimensions": [], 117 | "zones_allow_external_fillets": false, 118 | "zones_use_no_outline": true 119 | }, 120 | "layer_presets": [] 121 | }, 122 | "boards": [], 123 | "cvpcb": { 124 | "equivalence_files": [] 125 | }, 126 | "libraries": { 127 | "pinned_footprint_libs": [], 128 | "pinned_symbol_libs": [] 129 | }, 130 | "meta": { 131 | "filename": "Freq - KiCad.kicad_pro", 132 | "version": 1 133 | }, 134 | "net_settings": { 135 | "classes": [ 136 | { 137 | "bus_width": 12.0, 138 | "clearance": 0.2, 139 | "diff_pair_gap": 0.25, 140 | "diff_pair_via_gap": 0.25, 141 | "diff_pair_width": 0.2, 142 | "line_style": 0, 143 | "microvia_diameter": 0.3, 144 | "microvia_drill": 0.1, 145 | "name": "Default", 146 | "pcb_color": "rgba(0, 0, 0, 0.000)", 147 | "schematic_color": "rgba(0, 0, 0, 0.000)", 148 | "track_width": 0.25, 149 | "via_diameter": 0.8, 150 | "via_drill": 0.4, 151 | "wire_width": 6.0 152 | } 153 | ], 154 | "meta": { 155 | "version": 2 156 | }, 157 | "net_colors": null 158 | }, 159 | "pcbnew": { 160 | "last_paths": { 161 | "gencad": "", 162 | "idf": "", 163 | "netlist": "", 164 | "specctra_dsn": "", 165 | "step": "", 166 | "vrml": "" 167 | }, 168 | "page_layout_descr_file": "" 169 | }, 170 | "schematic": { 171 | "legacy_lib_dir": "", 172 | "legacy_lib_list": [] 173 | }, 174 | "sheets": [], 175 | "text_variables": {} 176 | } 177 | -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/avSource.h: -------------------------------------------------------------------------------- 1 | /* 2 | avSource.h - defines a sound source using a virtual base class and a derived class which implements the particular sound source 3 | 4 | in this case, a 2-operator FM voice with envelope & lfo modulation control 5 | */ 6 | 7 | #ifndef avSource_h 8 | #define avSource_h 9 | #include "Arduino.h" 10 | 11 | #include "avMidi.h" 12 | #include "MutantFMSynthOptions.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include // sine table for oscillators & LFO 18 | #include // saw table for LFO 19 | #include "revsaw2048_int8.h" // reverse saw table for LFO 20 | #include "square2048_int8.h" // square table for LFO 21 | 22 | /** @brief if COMPILE_SMALLER_BINARY flag is defined, omit the pseudorandom waveform */ 23 | #ifndef COMPILE_SMALLER_BINARY 24 | #include "pseudorandom2048_int8.h" // noise table for LFO 25 | #endif 26 | 27 | #include "nullwaveform2048_int8.h" // zero table for LFO - used to turn carrier off 28 | #include 29 | #include 30 | 31 | #include 32 | 33 | //#define DEBUG_MODE_VERBOSE 34 | 35 | // define this here to avoid clipping the filter function 36 | #define MAX_FILTER_RESONANCE 100 37 | #define MAX_FILTER_CUTOFF 240 38 | #define MAX_FILTER_SHAPE 1023 39 | #define MAX_FILTER_ENV_ATTACK 4096 40 | #define MAX_SOURCE_PARAMS 9 41 | 42 | #define SYNTH_PARAMETER_MOD_AMOUNT 1 43 | #define SYNTH_PARAMETER_MOD_RATIO 2 44 | #define SYNTH_PARAMETER_MOD_AMOUNT_LFO 6 45 | #define SYNTH_PARAMETER_MOD_AMOUNT_LFODEPTH 3 46 | #define SYNTH_PARAMETER_ENVELOPE_SUSTAIN 4 47 | #define SYNTH_PARAMETER_ENVELOPE_SHAPE 5 48 | #define SYNTH_PARAMETER_ENVELOPE_ATTACK 7 49 | #define SYNTH_PARAMETER_ENVELOPE_DECAY 8 50 | #define SYNTH_PARAMETER_NOTE_DECAY -2 // this isn't implemented in the synth voice - it's in the sequencer, probably should be though 51 | #define SYNTH_PARAMETER_UNKNOWN -1 52 | 53 | 54 | 55 | #define SYNTH_PARAMETER_OSC2TUNE 0 56 | 57 | #define FM_MODE_EXPONENTIAL 0 58 | #define FM_MODE_LINEAR_HIGH 1 59 | #define FM_MODE_LINEAR_LOW 2 60 | #define FM_MODE_FREE 3 61 | #define MAX_FM_MODES 4 62 | 63 | /** @brief if COMPILE_SMALLER_BINARY flag is defined, omit the pseudorandom waveform */ 64 | #ifdef COMPILE_SMALLER_BINARY 65 | 66 | #define MAX_LFO_WAVEFORMS 5 67 | #define MAX_CARRIER_WAVEFORMS 5 68 | #define MAX_MODULATOR_WAVEFORMS 5 69 | 70 | #define WAVEFORM_SIN 0 71 | #define WAVEFORM_SAW 1 72 | #define WAVEFORM_REVSAW 2 73 | #define WAVEFORM_SQUARE 3 74 | #define WAVEFORM_NULL 4 75 | 76 | #else 77 | #define MAX_LFO_WAVEFORMS 6 78 | #define MAX_CARRIER_WAVEFORMS 6 79 | #define MAX_MODULATOR_WAVEFORMS 6 80 | 81 | #define WAVEFORM_SIN 0 82 | #define WAVEFORM_SAW 1 83 | #define WAVEFORM_REVSAW 2 84 | #define WAVEFORM_SQUARE 3 85 | #define WAVEFORM_PSEUDORANDOM 4 86 | #define WAVEFORM_NULL 5 87 | #endif 88 | 89 | 90 | // increase for wider LFO depth range 91 | // LFO depth will be multiplied by 2^n using a bitshift 92 | // 0 value should be optimised out by the compiler 93 | #define MOD_DEPTH_MULTIPLIER_LFO 0 94 | 95 | // increase for wider ENV depth range 96 | // ENV depth will be multiplied by 2^n using a bitshift 97 | // 0 value should be optimised out by the compiler 98 | #define MOD_DEPTH_MULTIPLIER_ENV 0 99 | 100 | // this is the shortest decay time that can be audible with the mod envelope with the given CONTROL_RATE 101 | #define MIN_MODULATION_ENV_TIME 30 102 | 103 | //#define SYNTH_MODULATION_UPDATE_DIVIDER 2 104 | 105 | class MutatingSource 106 | { 107 | public: 108 | MutatingSource(); 109 | 110 | virtual int noteOn(byte pitch, byte velocity, unsigned int length); 111 | virtual int noteOff(); 112 | virtual inline int updateAudio(); 113 | virtual inline void updateControl(); 114 | virtual int mutate(); 115 | virtual void setGain(byte gain); 116 | virtual void setParam(uint8_t paramIndex, uint16_t newValue); 117 | virtual uint16_t getParam(byte paramIndex); 118 | 119 | 120 | protected: 121 | uint16_t param[MAX_SOURCE_PARAMS]; 122 | uint16_t lastParam[MAX_SOURCE_PARAMS]; 123 | 124 | EventDelay noteOffTimer; 125 | 126 | }; 127 | 128 | class MutatingFM : public MutatingSource 129 | { 130 | public: 131 | MutatingFM(); 132 | 133 | int noteOn(uint8_t pitch, uint8_t velocity, uint16_t length); 134 | int noteOff(); 135 | int updateAudio(); 136 | void updateControl(); 137 | int mutate(); 138 | void setParam(uint8_t paramIndex, uint16_t newValue); 139 | uint16_t getParam(uint8_t paramIndex); 140 | 141 | void setGain(uint8_t gain); 142 | 143 | void setOscillator(uint8_t oscIndex); 144 | uint8_t getLFOValue(); 145 | void setLFOFrequency(float freq); 146 | void setModulationShape(uint16_t newValue); 147 | 148 | void toggleFMMode(); 149 | uint8_t getFMMode(); 150 | 151 | void toggleLFOWaveform(); 152 | uint8_t getLFOWaveform(); 153 | 154 | void toggleCarrierWaveform(); 155 | uint8_t getCarrierWaveform(); 156 | 157 | void toggleModulatorWaveform(); 158 | uint8_t getModulatorWaveform(); 159 | 160 | protected: 161 | 162 | // for FM oscillator 163 | void setFreqs(uint8_t midiNote); 164 | 165 | Q16n16 carrierFrequency; 166 | Q16n16 modulationFrequency; 167 | Q16n16 modulatorAmount; 168 | 169 | uint8_t currentGain; 170 | uint8_t masterGain; 171 | uint8_t masterGainBitShift; 172 | uint8_t lastLFOValue; 173 | uint8_t fmMode; 174 | uint8_t lfoWaveform; 175 | uint8_t carrierWaveform; 176 | uint8_t modulatorWaveform; 177 | 178 | Oscil* carrier; 179 | Oscil* modulator; 180 | ADSR * envelopeAmp; 181 | ADSR * envelopeMod; 182 | Oscil * lfo; 183 | 184 | private: 185 | uint8_t lastMidiNote; 186 | unsigned int lastNoteLength; 187 | uint8_t updateCount; 188 | 189 | 190 | }; 191 | 192 | #endif 193 | -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/nullwaveform2048_int8.h: -------------------------------------------------------------------------------- 1 | /* 2 | NULLWAVEFORM2018_int8.h - defines a table representing a zero waveform 3 | 4 | used to silence the oscillator 5 | 6 | can be replaced with any values you like, but must be 2048 cells to match the other tables 7 | */ 8 | #ifndef NULLWAVEFORM2048_H_ 9 | #define NULLWAVEFORM2048_H_ 10 | 11 | #if ARDUINO >= 100 12 | #include "Arduino.h" 13 | #else 14 | #include "WProgram.h" 15 | #endif 16 | #include "mozzi_pgmspace.h" 17 | 18 | #define NULLWAVEFORM2048_NUM_CELLS 2048 19 | #define NULLWAVEFORM2048_SAMPLERATE 2048 20 | 21 | /** @ingroup tables 22 | reverse saw table 23 | */ 24 | 25 | CONSTTABLE_STORAGE(int8_t) NULLWAVEFORM2048_DATA [2048] = 26 | { 27 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 28 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 29 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 30 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 31 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 32 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 33 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 34 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 35 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 36 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 37 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 38 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 39 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 40 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 41 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 42 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 43 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 44 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 45 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 46 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 47 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 48 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 49 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 50 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 51 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 52 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 53 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 54 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 55 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 56 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 57 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 58 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 59 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 60 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 61 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 62 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 63 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 64 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 65 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 66 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 67 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 68 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 69 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 70 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 71 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 72 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 73 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 74 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 75 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 76 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 77 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 78 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 79 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 80 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 81 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 82 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 83 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 84 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 85 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 86 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 87 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 88 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 89 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 90 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 91 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 92 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 93 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 94 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 95 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 96 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 97 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 98 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 99 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 100 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 101 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 102 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 103 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 104 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 105 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 106 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 107 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 108 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 109 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 110 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 111 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 112 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 113 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 114 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 115 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 116 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 117 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 118 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 119 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 120 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 121 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 122 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 123 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 124 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 125 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 126 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 127 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 128 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 129 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 130 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 131 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 132 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 133 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 134 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 135 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 136 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 137 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 138 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 139 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 140 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 141 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 142 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 143 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 144 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 145 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 146 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 147 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 148 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 149 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 150 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 151 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 152 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 153 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 154 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 155 | }; 156 | 157 | 158 | #endif /* NULLWAVEFORM2048_H_ */ 159 | -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/revsaw2048_int8.h: -------------------------------------------------------------------------------- 1 | /* 2 | revsaw2018_int8.h - defines a table representing a reverse-saw waveform 3 | 4 | used for the LFO/carrier/modulator 5 | 6 | can be replaced with any values you like, but must be 2048 cells to match the other tables 7 | */ 8 | #ifndef REVSAW2048_H_ 9 | #define REVSAW2048_H_ 10 | 11 | #if ARDUINO >= 100 12 | #include "Arduino.h" 13 | #else 14 | #include "WProgram.h" 15 | #endif 16 | #include "mozzi_pgmspace.h" 17 | 18 | #define REVSAW2048_NUM_CELLS 2048 19 | #define REVSAW2048_SAMPLERATE 2048 20 | 21 | /** @ingroup tables 22 | reverse saw table 23 | */ 24 | 25 | CONSTTABLE_STORAGE(int8_t) REVSAW2048_DATA [2048] = 26 | { 27 | 127,127,127,127,127,126,126,126,126,126,126,126,126,125,125,125 28 | ,125,125,125,125,125,124,124,124,124,124,124,124,124,123,123,123 29 | ,123,123,123,123,123,122,122,122,122,122,122,122,122,121,121,121 30 | ,121,121,121,121,121,120,120,120,120,120,120,120,120,119,119,119 31 | ,119,119,119,119,119,118,118,118,118,118,118,118,118,117,117,117 32 | ,117,117,117,117,117,116,116,116,116,116,116,116,116,115,115,115 33 | ,115,115,115,115,115,114,114,114,114,114,114,114,114,113,113,113 34 | ,113,113,113,113,113,112,112,112,112,112,112,112,112,111,111,111 35 | ,111,111,111,111,111,110,110,110,110,110,110,110,110,109,109,109 36 | ,109,109,109,109,109,108,108,108,108,108,108,108,108,107,107,107 37 | ,107,107,107,107,107,106,106,106,106,106,106,106,106,105,105,105 38 | ,105,105,105,105,105,104,104,104,104,104,104,104,104,103,103,103 39 | ,103,103,103,103,103,102,102,102,102,102,102,102,102,101,101,101 40 | ,101,101,101,101,101,100,100,100,100,100,100,100,100,99,99,99 41 | ,99,99,99,99,99,98,98,98,98,98,98,98,98,97,97,97 42 | ,97,97,97,97,97,96,96,96,96,96,96,96,96,95,95,95 43 | ,95,95,95,95,95,95,94,94,94,94,94,94,94,94,93,93 44 | ,93,93,93,93,93,93,92,92,92,92,92,92,92,92,91,91 45 | ,91,91,91,91,91,91,90,90,90,90,90,90,90,90,89,89 46 | ,89,89,89,89,89,89,88,88,88,88,88,88,88,88,87,87 47 | ,87,87,87,87,87,87,86,86,86,86,86,86,86,86,85,85 48 | ,85,85,85,85,85,85,84,84,84,84,84,84,84,84,83,83 49 | ,83,83,83,83,83,83,82,82,82,82,82,82,82,82,81,81 50 | ,81,81,81,81,81,81,80,80,80,80,80,80,80,80,79,79 51 | ,79,79,79,79,79,79,78,78,78,78,78,78,78,78,77,77 52 | ,77,77,77,77,77,77,76,76,76,76,76,76,76,76,75,75 53 | ,75,75,75,75,75,75,74,74,74,74,74,74,74,74,73,73 54 | ,73,73,73,73,73,73,72,72,72,72,72,72,72,72,71,71 55 | ,71,71,71,71,71,71,70,70,70,70,70,70,70,70,69,69 56 | ,69,69,69,69,69,69,68,68,68,68,68,68,68,68,67,67 57 | ,67,67,67,67,67,67,66,66,66,66,66,66,66,66,65,65 58 | ,65,65,65,65,65,65,64,64,64,64,64,64,64,64,63,63 59 | ,63,63,63,63,63,63,63,62,62,62,62,62,62,62,62,61 60 | ,61,61,61,61,61,61,61,60,60,60,60,60,60,60,60,59 61 | ,59,59,59,59,59,59,59,58,58,58,58,58,58,58,58,57 62 | ,57,57,57,57,57,57,57,56,56,56,56,56,56,56,56,55 63 | ,55,55,55,55,55,55,55,54,54,54,54,54,54,54,54,53 64 | ,53,53,53,53,53,53,53,52,52,52,52,52,52,52,52,51 65 | ,51,51,51,51,51,51,51,50,50,50,50,50,50,50,50,49 66 | ,49,49,49,49,49,49,49,48,48,48,48,48,48,48,48,47 67 | ,47,47,47,47,47,47,47,46,46,46,46,46,46,46,46,45 68 | ,45,45,45,45,45,45,45,44,44,44,44,44,44,44,44,43 69 | ,43,43,43,43,43,43,43,42,42,42,42,42,42,42,42,41 70 | ,41,41,41,41,41,41,41,40,40,40,40,40,40,40,40,39 71 | ,39,39,39,39,39,39,39,38,38,38,38,38,38,38,38,37 72 | ,37,37,37,37,37,37,37,36,36,36,36,36,36,36,36,35 73 | ,35,35,35,35,35,35,35,34,34,34,34,34,34,34,34,33 74 | ,33,33,33,33,33,33,33,32,32,32,32,32,32,32,32,31 75 | ,31,31,31,31,31,31,31,31,30,30,30,30,30,30,30,30 76 | ,29,29,29,29,29,29,29,29,28,28,28,28,28,28,28,28 77 | ,27,27,27,27,27,27,27,27,26,26,26,26,26,26,26,26 78 | ,25,25,25,25,25,25,25,25,24,24,24,24,24,24,24,24 79 | ,23,23,23,23,23,23,23,23,22,22,22,22,22,22,22,22 80 | ,21,21,21,21,21,21,21,21,20,20,20,20,20,20,20,20 81 | ,19,19,19,19,19,19,19,19,18,18,18,18,18,18,18,18 82 | ,17,17,17,17,17,17,17,17,16,16,16,16,16,16,16,16 83 | ,15,15,15,15,15,15,15,15,14,14,14,14,14,14,14,14 84 | ,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,12 85 | ,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10 86 | ,9,9,9,9,9,9,9,9,8,8,8,8,8,8,8,8 87 | ,7,7,7,7,7,7,7,7,6,6,6,6,6,6,6,6 88 | ,5,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4 89 | ,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2 90 | ,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0 91 | ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2,-2,-2 92 | ,-2,-3,-3,-3,-3,-3,-3,-3,-3,-4,-4,-4,-4,-4,-4,-4 93 | ,-4,-5,-5,-5,-5,-5,-5,-5,-5,-6,-6,-6,-6,-6,-6,-6 94 | ,-6,-7,-7,-7,-7,-7,-7,-7,-7,-8,-8,-8,-8,-8,-8,-8 95 | ,-8,-9,-9,-9,-9,-9,-9,-9,-9,-10,-10,-10,-10,-10,-10,-10 96 | ,-10,-11,-11,-11,-11,-11,-11,-11,-11,-12,-12,-12,-12,-12,-12,-12 97 | ,-12,-13,-13,-13,-13,-13,-13,-13,-13,-14,-14,-14,-14,-14,-14,-14 98 | ,-14,-15,-15,-15,-15,-15,-15,-15,-15,-16,-16,-16,-16,-16,-16,-16 99 | ,-16,-17,-17,-17,-17,-17,-17,-17,-17,-18,-18,-18,-18,-18,-18,-18 100 | ,-18,-19,-19,-19,-19,-19,-19,-19,-19,-20,-20,-20,-20,-20,-20,-20 101 | ,-20,-21,-21,-21,-21,-21,-21,-21,-21,-22,-22,-22,-22,-22,-22,-22 102 | ,-22,-23,-23,-23,-23,-23,-23,-23,-23,-24,-24,-24,-24,-24,-24,-24 103 | ,-24,-25,-25,-25,-25,-25,-25,-25,-25,-26,-26,-26,-26,-26,-26,-26 104 | ,-26,-27,-27,-27,-27,-27,-27,-27,-27,-28,-28,-28,-28,-28,-28,-28 105 | ,-28,-29,-29,-29,-29,-29,-29,-29,-29,-30,-30,-30,-30,-30,-30,-30 106 | ,-30,-31,-31,-31,-31,-31,-31,-31,-31,-32,-32,-32,-32,-32,-32,-32 107 | ,-32,-32,-33,-33,-33,-33,-33,-33,-33,-33,-34,-34,-34,-34,-34,-34 108 | ,-34,-34,-35,-35,-35,-35,-35,-35,-35,-35,-36,-36,-36,-36,-36,-36 109 | ,-36,-36,-37,-37,-37,-37,-37,-37,-37,-37,-38,-38,-38,-38,-38,-38 110 | ,-38,-38,-39,-39,-39,-39,-39,-39,-39,-39,-40,-40,-40,-40,-40,-40 111 | ,-40,-40,-41,-41,-41,-41,-41,-41,-41,-41,-42,-42,-42,-42,-42,-42 112 | ,-42,-42,-43,-43,-43,-43,-43,-43,-43,-43,-44,-44,-44,-44,-44,-44 113 | ,-44,-44,-45,-45,-45,-45,-45,-45,-45,-45,-46,-46,-46,-46,-46,-46 114 | ,-46,-46,-47,-47,-47,-47,-47,-47,-47,-47,-48,-48,-48,-48,-48,-48 115 | ,-48,-48,-49,-49,-49,-49,-49,-49,-49,-49,-50,-50,-50,-50,-50,-50 116 | ,-50,-50,-51,-51,-51,-51,-51,-51,-51,-51,-52,-52,-52,-52,-52,-52 117 | ,-52,-52,-53,-53,-53,-53,-53,-53,-53,-53,-54,-54,-54,-54,-54,-54 118 | ,-54,-54,-55,-55,-55,-55,-55,-55,-55,-55,-56,-56,-56,-56,-56,-56 119 | ,-56,-56,-57,-57,-57,-57,-57,-57,-57,-57,-58,-58,-58,-58,-58,-58 120 | ,-58,-58,-59,-59,-59,-59,-59,-59,-59,-59,-60,-60,-60,-60,-60,-60 121 | ,-60,-60,-61,-61,-61,-61,-61,-61,-61,-61,-62,-62,-62,-62,-62,-62 122 | ,-62,-62,-63,-63,-63,-63,-63,-63,-63,-63,-64,-64,-64,-64,-64,-64 123 | ,-64,-64,-64,-65,-65,-65,-65,-65,-65,-65,-65,-66,-66,-66,-66,-66 124 | ,-66,-66,-66,-67,-67,-67,-67,-67,-67,-67,-67,-68,-68,-68,-68,-68 125 | ,-68,-68,-68,-69,-69,-69,-69,-69,-69,-69,-69,-70,-70,-70,-70,-70 126 | ,-70,-70,-70,-71,-71,-71,-71,-71,-71,-71,-71,-72,-72,-72,-72,-72 127 | ,-72,-72,-72,-73,-73,-73,-73,-73,-73,-73,-73,-74,-74,-74,-74,-74 128 | ,-74,-74,-74,-75,-75,-75,-75,-75,-75,-75,-75,-76,-76,-76,-76,-76 129 | ,-76,-76,-76,-77,-77,-77,-77,-77,-77,-77,-77,-78,-78,-78,-78,-78 130 | ,-78,-78,-78,-79,-79,-79,-79,-79,-79,-79,-79,-80,-80,-80,-80,-80 131 | ,-80,-80,-80,-81,-81,-81,-81,-81,-81,-81,-81,-82,-82,-82,-82,-82 132 | ,-82,-82,-82,-83,-83,-83,-83,-83,-83,-83,-83,-84,-84,-84,-84,-84 133 | ,-84,-84,-84,-85,-85,-85,-85,-85,-85,-85,-85,-86,-86,-86,-86,-86 134 | ,-86,-86,-86,-87,-87,-87,-87,-87,-87,-87,-87,-88,-88,-88,-88,-88 135 | ,-88,-88,-88,-89,-89,-89,-89,-89,-89,-89,-89,-90,-90,-90,-90,-90 136 | ,-90,-90,-90,-91,-91,-91,-91,-91,-91,-91,-91,-92,-92,-92,-92,-92 137 | ,-92,-92,-92,-93,-93,-93,-93,-93,-93,-93,-93,-94,-94,-94,-94,-94 138 | ,-94,-94,-94,-95,-95,-95,-95,-95,-95,-95,-95,-96,-96,-96,-96,-96 139 | ,-96,-96,-96,-96,-97,-97,-97,-97,-97,-97,-97,-97,-98,-98,-98,-98 140 | ,-98,-98,-98,-98,-99,-99,-99,-99,-99,-99,-99,-99,-100,-100,-100,-100 141 | ,-100,-100,-100,-100,-101,-101,-101,-101,-101,-101,-101,-101,-102,-102,-102,-102 142 | ,-102,-102,-102,-102,-103,-103,-103,-103,-103,-103,-103,-103,-104,-104,-104,-104 143 | ,-104,-104,-104,-104,-105,-105,-105,-105,-105,-105,-105,-105,-106,-106,-106,-106 144 | ,-106,-106,-106,-106,-107,-107,-107,-107,-107,-107,-107,-107,-108,-108,-108,-108 145 | ,-108,-108,-108,-108,-109,-109,-109,-109,-109,-109,-109,-109,-110,-110,-110,-110 146 | ,-110,-110,-110,-110,-111,-111,-111,-111,-111,-111,-111,-111,-112,-112,-112,-112 147 | ,-112,-112,-112,-112,-113,-113,-113,-113,-113,-113,-113,-113,-114,-114,-114,-114 148 | ,-114,-114,-114,-114,-115,-115,-115,-115,-115,-115,-115,-115,-116,-116,-116,-116 149 | ,-116,-116,-116,-116,-117,-117,-117,-117,-117,-117,-117,-117,-118,-118,-118,-118 150 | ,-118,-118,-118,-118,-119,-119,-119,-119,-119,-119,-119,-119,-120,-120,-120,-120 151 | ,-120,-120,-120,-120,-121,-121,-121,-121,-121,-121,-121,-121,-122,-122,-122,-122 152 | ,-122,-122,-122,-122,-123,-123,-123,-123,-123,-123,-123,-123,-124,-124,-124,-124 153 | ,-124,-124,-124,-124,-125,-125,-125,-125,-125,-125,-125,-125,-126,-126,-126,-126 154 | ,-126,-126,-126,-126,-127,-127,-127,-127,-127,-127,-127,-127,-128,-128,-128,-128 155 | }; 156 | 157 | 158 | #endif /* REVSAW2048_H_ */ 159 | -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/LedMatrix.cpp: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------------------------------------- 2 | * LedMatrix.cpp 3 | * 4 | * Implements an interface to a MAX7219 driving an 8x8 LED matrix 5 | * 6 | * Source Code Repository: https://github.com/Meebleeps/MeeBleeps-Freaq-FM-Synth 7 | * Youtube Channel: https://www.youtube.com/channel/UC4I1ExnOpH_GjNtm7ZdWeWA 8 | * 9 | * (C) 2021-2022 Meebleeps 10 | *----------------------------------------------------------------------------------------------------------- 11 | */ 12 | #include "LedMatrix.h" 13 | #include 14 | #include 15 | 16 | 17 | 18 | 19 | /*---------------------------------------------------------------------------------------------------------- 20 | * LedMatrix::LedMatrix() 21 | * initialises the vRAM and sets modified flag to all so that all rows will be updated on first refresh 22 | *---------------------------------------------------------------------------------------------------------- 23 | */ 24 | LedMatrix::LedMatrix() 25 | { 26 | for (uint8_t y = 0; y < 8; y++) 27 | { 28 | vRAM[y] = 0; 29 | } 30 | rowModified = LEDMATRIX_MODIFIED_ALL; 31 | } 32 | 33 | 34 | /*---------------------------------------------------------------------------------------------------------- 35 | * LedMatrix::initialise() 36 | *---------------------------------------------------------------------------------------------------------- 37 | */ 38 | void LedMatrix::initialise() 39 | { 40 | pinMode(PIN_LEDMATRIX_DIN, OUTPUT); 41 | pinMode(PIN_LEDMATRIX_CS, OUTPUT); 42 | pinMode(PIN_LEDMATRIX_CLK, OUTPUT); 43 | pinMode(2, OUTPUT); 44 | 45 | SPI.setBitOrder(MSBFIRST); 46 | SPI.begin(); 47 | 48 | setOrientation(LEDMATRIX_ORIENTATION_0); 49 | 50 | 51 | writeDisplayData(LED_DISPLAYTEST, 0x01); 52 | 53 | delay(250); // todo find out if this is necessary 54 | 55 | writeDisplayData(LED_DISPLAYTEST, 0x00); 56 | writeDisplayData(LED_DECODE_MODE, 0x00); 57 | writeDisplayData(LED_INTENSITY, 0x00); 58 | writeDisplayData(LED_SCAN_LIMIT, 0x0f); 59 | writeDisplayData(LED_SHUTDOWN, 0x01); 60 | writeDisplayData(LED_INTENSITY, 0x0f); 61 | 62 | } 63 | 64 | 65 | 66 | /*---------------------------------------------------------------------------------------------------------- 67 | * setPixel 68 | *---------------------------------------------------------------------------------------------------------- 69 | */ 70 | void LedMatrix::setPixel(byte x, byte y, bool value) 71 | { 72 | if (x < LEDMATRIX_MAXCOLS && y < LEDMATRIX_MAXROWS) 73 | { 74 | if (value) 75 | { 76 | vRAM[y] = vRAM[y] | displayBit[x]; 77 | } 78 | else 79 | { 80 | vRAM[y] = vRAM[y] & ~displayBit[x]; 81 | } 82 | 83 | rowModified |= 1 << y; 84 | } 85 | 86 | 87 | } 88 | 89 | 90 | /*---------------------------------------------------------------------------------------------------------- 91 | * togglePixel 92 | * 93 | *---------------------------------------------------------------------------------------------------------- 94 | */ 95 | void LedMatrix::togglePixel(byte x, byte y) 96 | { 97 | if (y < LEDMATRIX_MAXROWS && x < LEDMATRIX_MAXCOLS) 98 | { 99 | // if pixel is on, switch off 100 | if (vRAM[y] & displayBit[x]) 101 | { 102 | vRAM[y] = vRAM[y] & ~displayBit[x]; 103 | } 104 | else 105 | { 106 | vRAM[y] = vRAM[y] | displayBit[x]; 107 | } 108 | 109 | rowModified |= 1 << y; 110 | } 111 | } 112 | 113 | 114 | 115 | /*---------------------------------------------------------------------------------------------------------- 116 | * setRowPixels 117 | * 118 | *---------------------------------------------------------------------------------------------------------- 119 | */ 120 | void LedMatrix::setRowPixels(byte y, byte value) 121 | { 122 | if (y < LEDMATRIX_MAXROWS) 123 | { 124 | vRAM[y] = value; 125 | rowModified |= 1 << y; 126 | } 127 | 128 | } 129 | 130 | 131 | 132 | /*---------------------------------------------------------------------------------------------------------- 133 | * setColPixels 134 | * 135 | *---------------------------------------------------------------------------------------------------------- 136 | */ 137 | void LedMatrix::setColPixels(byte x, byte value) 138 | { 139 | if (x < LEDMATRIX_MAXCOLS) 140 | { 141 | if (value) 142 | { 143 | for (uint8_t y = 0; y < 7; y++) 144 | { 145 | vRAM[y] = vRAM[y] | displayBit[x]; 146 | rowModified |= 1 << y; 147 | } 148 | } 149 | else 150 | { 151 | for (uint8_t y = 0; y < 7; y++) 152 | { 153 | vRAM[y] = vRAM[y] & (~displayBit[x]); 154 | rowModified |= 1 << y; 155 | } 156 | } 157 | } 158 | } 159 | 160 | 161 | /*---------------------------------------------------------------------------------------------------------- 162 | * DrawLineV 163 | * 164 | *---------------------------------------------------------------------------------------------------------- 165 | */ 166 | void LedMatrix::drawLineV(byte x, byte startY, byte endY, bool on) 167 | { 168 | if (x < LEDMATRIX_MAXCOLS && startY <= endY) 169 | { 170 | for (byte y = startY; y < endY; y++) 171 | { 172 | setPixel(x, y, on); 173 | } 174 | } 175 | } 176 | 177 | 178 | /*---------------------------------------------------------------------------------------------------------- 179 | * DrawLineH 180 | * 181 | *---------------------------------------------------------------------------------------------------------- 182 | */ 183 | void LedMatrix::drawLineH(byte y, byte startX, byte endX, bool on) 184 | { 185 | if (y < LEDMATRIX_MAXROWS && startX <= endX) 186 | { 187 | for (byte x = startX; x < endX; x++) 188 | { 189 | setPixel(x, y, on); 190 | } 191 | } 192 | } 193 | 194 | 195 | /*---------------------------------------------------------------------------------------------------------- 196 | * displayIcon 197 | * takes a pointer to a 8-byte array and displays an icon 198 | * HIGH RISK OF BUFFER OVERFLOWS! :( 199 | *---------------------------------------------------------------------------------------------------------- 200 | */ 201 | void LedMatrix::displayIcon(byte* bitmap) 202 | { 203 | for (uint8_t y = 0; y < LEDMATRIX_MAXROWS; y++) 204 | { 205 | setRowPixels(y, bitmap[y]); 206 | } 207 | 208 | refresh(); 209 | } 210 | 211 | 212 | /*---------------------------------------------------------------------------------------------------------- 213 | * sparkle 214 | *---------------------------------------------------------------------------------------------------------- 215 | */ 216 | void LedMatrix::sparkle(int amount) 217 | { 218 | int x, y; 219 | 220 | for (uint8_t i = 0; i < amount; i++) 221 | { 222 | x = rand(LEDMATRIX_MAXCOLS); 223 | y = rand(LEDMATRIX_MAXROWS); 224 | togglePixel(x,y); 225 | refresh(); 226 | delay(10); 227 | togglePixel(x,y); 228 | } 229 | 230 | refresh(); 231 | } 232 | 233 | 234 | 235 | /*---------------------------------------------------------------------------------------------------------- 236 | * refresh 237 | * updates the matrix with the current vram contents 238 | *---------------------------------------------------------------------------------------------------------- 239 | */ 240 | void LedMatrix::refresh() 241 | { 242 | //Serial.println(F("--------")); 243 | for (uint8_t y = 0; y < 8; y++) 244 | { 245 | if (rowModified & (1 << y)) 246 | { 247 | writeDisplayData(y+1, vRAM[y]); 248 | } 249 | else 250 | { 251 | 252 | } 253 | } 254 | 255 | rowModified = LEDMATRIX_MODIFIED_NONE; 256 | 257 | } 258 | 259 | 260 | 261 | /*---------------------------------------------------------------------------------------------------------- 262 | * clearScreen 263 | * clears the VRAM and updates the matrix 264 | *---------------------------------------------------------------------------------------------------------- 265 | */ 266 | void LedMatrix::clearScreen() 267 | { 268 | for (uint8_t y = 0; y < 8; y++) 269 | { 270 | vRAM[y] = 0; 271 | } 272 | 273 | rowModified = LEDMATRIX_MODIFIED_ALL; 274 | 275 | refresh(); 276 | } 277 | 278 | 279 | /*---------------------------------------------------------------------------------------------------------- 280 | * setIntensity 281 | * 282 | *---------------------------------------------------------------------------------------------------------- 283 | */ 284 | void LedMatrix::setIntensity(int intensity) 285 | { 286 | if (intensity > 15) 287 | { 288 | intensity = 15; 289 | } 290 | else if (intensity < 0) 291 | { 292 | intensity = 0; 293 | } 294 | 295 | writeDisplayData(LED_INTENSITY, intensity); 296 | } 297 | 298 | 299 | 300 | /*---------------------------------------------------------------------------------------------------------- 301 | * setOrientation 302 | * sets the orientation of the matrix depending on installation 303 | *---------------------------------------------------------------------------------------------------------- 304 | */ 305 | void LedMatrix::setOrientation(int newOrientate) 306 | { 307 | orientation = newOrientate; 308 | //Serial.print(orientation); 309 | 310 | switch (orientation) 311 | { 312 | case LEDMATRIX_ORIENTATION_0: 313 | 314 | displayBit[0] = 128; 315 | displayBit[1] = 64; 316 | displayBit[2] = 32; 317 | displayBit[3] = 16; 318 | displayBit[4] = 8; 319 | displayBit[5] = 4; 320 | displayBit[6] = 2; 321 | displayBit[7] = 1; 322 | break; 323 | 324 | case LEDMATRIX_ORIENTATION_90: 325 | 326 | //? 327 | break; 328 | 329 | case LEDMATRIX_ORIENTATION_180: 330 | 331 | displayBit[0] = 1; 332 | displayBit[1] = 2; 333 | displayBit[2] = 4; 334 | displayBit[3] = 8; 335 | displayBit[4] = 16; 336 | displayBit[5] = 32; 337 | displayBit[6] = 64; 338 | displayBit[7] = 128; 339 | break; 340 | 341 | case LEDMATRIX_ORIENTATION_270: 342 | 343 | //? 344 | break; 345 | 346 | default: 347 | displayBit[0] = 1; 348 | displayBit[1] = 2; 349 | displayBit[2] = 4; 350 | displayBit[3] = 8; 351 | displayBit[4] = 16; 352 | displayBit[5] = 32; 353 | displayBit[6] = 64; 354 | displayBit[7] = 128; 355 | break; 356 | 357 | } 358 | } 359 | 360 | 361 | /*---------------------------------------------------------------------------------------------------------- 362 | * writeDisplayData 363 | * writes a single line of data to the LED matrix 364 | *---------------------------------------------------------------------------------------------------------- 365 | */ 366 | void LedMatrix::writeDisplayData(uint8_t address, uint8_t value) 367 | { 368 | digitalWrite(PIN_LEDMATRIX_CS, LOW); 369 | SPI.transfer(address); 370 | SPI.transfer(value); 371 | digitalWrite(PIN_LEDMATRIX_CS, HIGH); 372 | } 373 | -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/square2048_int8.h: -------------------------------------------------------------------------------- 1 | /* 2 | SQUARE2018_int8.h - defines a table representing a square waveform 3 | 4 | used for the LFO/carrier/modulator 5 | 6 | can be replaced with any values you like, but must be 2048 cells to match the other tables 7 | */ 8 | #ifndef SQUARE2048_H_ 9 | #define SQUARE2048_H_ 10 | 11 | #if ARDUINO >= 100 12 | #include "Arduino.h" 13 | #else 14 | #include "WProgram.h" 15 | #endif 16 | #include "mozzi_pgmspace.h" 17 | 18 | #define SQUARE2048_NUM_CELLS 2048 19 | #define SQUARE2048_SAMPLERATE 2048 20 | 21 | /** @ingroup tables 22 | reverse saw table 23 | */ 24 | 25 | CONSTTABLE_STORAGE(int8_t) SQUARE2048_DATA [2048] = 26 | { 27 | 127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 28 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 29 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 30 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 31 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 32 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 33 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 34 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 35 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 36 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 37 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 38 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 39 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 40 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 41 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 42 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 43 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 44 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 45 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 46 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 47 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 48 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 49 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 50 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 51 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 52 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 53 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 54 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 55 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 56 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 57 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 58 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 59 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 60 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 61 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 62 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 63 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 64 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 65 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 66 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 67 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 68 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 69 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 70 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 71 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 72 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 73 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 74 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 75 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 76 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 77 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 78 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 79 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 80 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 81 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 82 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 83 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 84 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 85 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 86 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 87 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 88 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 89 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 90 | ,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127 91 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 92 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 93 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 94 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 95 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 96 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 97 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 98 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 99 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 100 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 101 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 102 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 103 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 104 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 105 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 106 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 107 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 108 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 109 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 110 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 111 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 112 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 113 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 114 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 115 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 116 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 117 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 118 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 119 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 120 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 121 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 122 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 123 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 124 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 125 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 126 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 127 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 128 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 129 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 130 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 131 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 132 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 133 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 134 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 135 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 136 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 137 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 138 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 139 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 140 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 141 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 142 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 143 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 144 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 145 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 146 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 147 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 148 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 149 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 150 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 151 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 152 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 153 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 154 | ,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128,-128 155 | }; 156 | 157 | 158 | #endif /* SQUARE2048_H_ */ 159 | -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/avSequencerMultitrack.cpp: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------------------------------------- 2 | * avSequencerMultiTrack.h 3 | * 4 | * Implements a multitrack generative sequencer with multiple generative algorithms, musical scale quantisation, 5 | * variable sequence length (up to 16 steps) and multiple parameter-lock (motion-sequencing) channels 6 | * 7 | * (C) 2021 Meebleeps 8 | *----------------------------------------------------------------------------------------------------------- 9 | */ 10 | #include 11 | #include 12 | 13 | #include "Arduino.h" 14 | #include "avSequencerMultiTrack.h" 15 | 16 | 17 | 18 | /*---------------------------------------------------------------------------------------------------------- 19 | * MutatingSequencerMultiTrack::MutatingSequencerMultiTrack() 20 | * initialises the sequencer 21 | *---------------------------------------------------------------------------------------------------------- 22 | */ 23 | MutatingSequencerMultiTrack::MutatingSequencerMultiTrack() 24 | { 25 | // all other settings 26 | 27 | for (uint8_t i=0; i 0 && newLength <= MAX_SEQUENCE_LENGTH && trackSequenceLength[track] != newLength) 465 | { 466 | trackSequenceLength[track] = newLength; 467 | #ifndef ENABLE_MIDI_OUTPUT 468 | Serial.print(F("sequenceLength=")); 469 | Serial.println(trackSequenceLength[track]); 470 | #endif 471 | } 472 | } 473 | 474 | 475 | -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/pseudorandom2048_int8.h: -------------------------------------------------------------------------------- 1 | /* 2 | pseudorandom2048_int8.h - defines a table to semi-random values with a slight smoothing between them 3 | 4 | used for the LFO/carrier/modulator 5 | 6 | can be replaced with any values you like, but must be 2048 cells to match the other tables 7 | */ 8 | 9 | #ifndef PSEUDORANDOM2048_H_ 10 | #define PSEUDORANDOM2048_H_ 11 | 12 | #if ARDUINO >= 100 13 | #include "Arduino.h" 14 | #else 15 | #include "WProgram.h" 16 | #endif 17 | #include "mozzi_pgmspace.h" 18 | 19 | #define PSEUDORANDOM2048_NUM_CELLS 2048 20 | #define PSEUDORANDOM2048_SAMPLERATE 2048 21 | 22 | /** @ingroup tables 23 | random table. smoothed 24 | */ 25 | CONSTTABLE_STORAGE(int8_t) PSEUDORANDOM2048_DATA [2048] = 26 | { 27 | 41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41 28 | ,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41 29 | ,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41 30 | ,35,29,24,18,12,6,0,-6,-11,-17,-23,-29,-35,-40,-46,-52 31 | ,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52 32 | ,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52 33 | ,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52 34 | ,-52,-51,-51,-51,-50,-50,-50,-50,-49,-49,-49,-48,-48,-48,-47,-47 35 | ,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47 36 | ,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47 37 | ,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47 38 | ,-47,-48,-48,-49,-49,-50,-50,-51,-51,-51,-52,-52,-53,-53,-54,-54 39 | ,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54 40 | ,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54 41 | ,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54 42 | ,-55,-56,-56,-57,-58,-59,-59,-60,-61,-62,-62,-63,-64,-65,-65,-66 43 | ,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66 44 | ,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66 45 | ,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66 46 | ,-61,-57,-52,-47,-42,-38,-33,-28,-23,-19,-14,-9,-4,1,5,10 47 | ,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10 48 | ,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10 49 | ,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10 50 | ,10,9,9,9,8,8,8,8,7,7,7,6,6,6,5,5 51 | ,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 52 | ,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 53 | ,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 54 | ,11,17,23,29,35,41,47,54,60,66,72,78,84,90,96,102 55 | ,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102 56 | ,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102 57 | ,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102 58 | ,95,89,82,76,69,63,56,50,43,36,30,23,17,10,4,-3 59 | ,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3 60 | ,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3 61 | ,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3 62 | ,-2,-1,0,1,1,2,3,4,5,6,7,8,8,9,10,11 63 | ,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11 64 | ,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11 65 | ,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11 66 | ,14,17,19,22,25,28,31,34,36,39,42,45,48,50,53,56 67 | ,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56 68 | ,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56 69 | ,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56 70 | ,60,64,67,71,75,79,83,87,90,94,98,102,106,109,113,117 71 | ,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117 72 | ,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117 73 | ,112,107,102,97,92,87,82,77,71,66,61,56,51,46,41,36 74 | ,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36 75 | ,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36 76 | ,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36 77 | ,28,20,12,4,-4,-12,-20,-28,-35,-43,-51,-59,-67,-75,-83,-91 78 | ,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91 79 | ,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91 80 | ,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91 81 | ,-78,-65,-51,-38,-25,-12,1,15,28,41,54,67,80,94,107,120 82 | ,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120 83 | ,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120 84 | ,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120 85 | ,117,114,110,107,104,101,98,95,91,88,85,82,79,75,72,69 86 | ,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69 87 | ,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69 88 | ,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69 89 | ,61,53,46,38,30,22,14,7,-1,-9,-17,-25,-33,-40,-48,-56 90 | ,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56 91 | ,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56 92 | ,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56 93 | ,-45,-33,-22,-11,1,12,24,35,46,58,69,81,92,103,115,126 94 | ,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126 95 | ,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126 96 | ,123,120,116,113,110,107,104,101,97,94,91,88,85,81,78,75 97 | ,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75 98 | ,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75 99 | ,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75 100 | ,66,57,48,39,30,21,12,3,-7,-16,-25,-34,-43,-52,-61,-70 101 | ,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70 102 | ,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70 103 | ,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70 104 | ,-61,-51,-42,-32,-23,-13,-4,6,15,24,34,43,53,62,72,81 105 | ,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81 106 | ,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81 107 | ,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81 108 | ,68,56,43,31,18,5,-7,-20,-33,-45,-58,-71,-83,-96,-108,-121 109 | ,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121 110 | ,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121 111 | ,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121 112 | ,-115,-108,-102,-96,-89,-83,-76,-70,-64,-57,-51,-45,-38,-32,-25,-19 113 | ,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19 114 | ,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19 115 | ,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19 116 | ,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19 117 | ,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19 118 | ,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19 119 | ,-15,-12,-8,-4,-1,3,7,11,14,18,22,25,29,33,36,40 120 | ,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40 121 | ,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40 122 | ,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40 123 | ,38,35,33,30,28,25,23,20,18,15,13,10,8,5,3,0 124 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 125 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 126 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 127 | ,7,15,22,30,37,44,52,59,66,74,81,89,96,103,111,118 128 | ,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118 129 | ,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118 130 | ,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118 131 | ,114,110,107,103,99,95,91,88,84,80,76,72,68,65,61,57 132 | ,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57 133 | ,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57 134 | ,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57 135 | ,60,63,66,69,72,75,78,81,84,87,90,93,96,99,102,105 136 | ,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105 137 | ,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105 138 | ,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105 139 | ,101,97,94,90,86,82,78,75,71,67,63,59,55,52,48,44 140 | ,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44 141 | ,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44 142 | ,40,36,32,28,24,20,16,12,7,3,-1,-5,-9,-13,-17,-21 143 | ,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21 144 | ,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21 145 | ,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21 146 | ,-18,-16,-13,-11,-8,-5,-3,0,3,5,8,11,13,16,18,21 147 | ,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21 148 | ,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21 149 | ,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21 150 | ,15,9,4,-2,-8,-14,-20,-26,-31,-37,-43,-49,-55,-60,-66,-72 151 | ,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72 152 | ,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72 153 | ,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72 154 | ,-72,-65,-58,-51,-44,-37,-30,-23,-16,-9,-2,5,12,19,26,33 155 | 156 | }; 157 | /* 158 | 159 | // random table. not smoothed 160 | 161 | CONSTTABLE_STORAGE(int8_t) PSEUDORANDOM2048_DATA [2048] = 162 | { 163 | 41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41 164 | ,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41 165 | ,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41 166 | ,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41 167 | ,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52 168 | ,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52 169 | ,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52 170 | ,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52,-52 171 | ,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47 172 | ,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47 173 | ,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47 174 | ,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47,-47 175 | ,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54 176 | ,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54 177 | ,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54 178 | ,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54,-54 179 | ,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66 180 | ,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66 181 | ,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66 182 | ,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66,-66 183 | ,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10 184 | ,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10 185 | ,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10 186 | ,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 187 | ,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 188 | ,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 189 | ,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 190 | ,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102 191 | ,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102 192 | ,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102 193 | ,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102 194 | ,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3 195 | ,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3 196 | ,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3 197 | ,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3,-3 198 | ,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11 199 | ,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11 200 | ,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11 201 | ,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11 202 | ,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56 203 | ,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56 204 | ,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56 205 | ,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56 206 | ,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117 207 | ,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117 208 | ,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117 209 | ,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36 210 | ,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36 211 | ,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36 212 | ,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36 213 | ,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91 214 | ,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91 215 | ,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91 216 | ,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91,-91 217 | ,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120 218 | ,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120 219 | ,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120 220 | ,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120 221 | ,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69 222 | ,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69 223 | ,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69 224 | ,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69 225 | ,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56 226 | ,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56 227 | ,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56 228 | ,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56,-56 229 | ,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126 230 | ,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126 231 | ,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126 232 | ,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75 233 | ,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75 234 | ,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75 235 | ,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75 236 | ,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70 237 | ,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70 238 | ,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70 239 | ,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70,-70 240 | ,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81 241 | ,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81 242 | ,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81 243 | ,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81 244 | ,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121 245 | ,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121 246 | ,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121 247 | ,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121,-121 248 | ,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19 249 | ,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19 250 | ,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19 251 | ,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19 252 | ,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19 253 | ,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19 254 | ,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19,-19 255 | ,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40 256 | ,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40 257 | ,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40 258 | ,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40 259 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 260 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 261 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 262 | ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 263 | ,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118 264 | ,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118 265 | ,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118 266 | ,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118 267 | ,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57 268 | ,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57 269 | ,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57 270 | ,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57 271 | ,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105 272 | ,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105 273 | ,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105 274 | ,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105 275 | ,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44 276 | ,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44 277 | ,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44 278 | ,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21 279 | ,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21 280 | ,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21 281 | ,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21 282 | ,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21 283 | ,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21 284 | ,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21 285 | ,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21 286 | ,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72 287 | ,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72 288 | ,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72 289 | ,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72,-72 290 | ,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19 291 | 292 | 293 | }; 294 | */ 295 | 296 | #endif /* PSEUDORANDOM2048_H_ */ 297 | -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/avSourceFM.cpp: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------------------------------------- 2 | * avSourceFM.cpp 3 | * 4 | * Implements a 2-operator FM voice with 5 | * Attack-Release envelope for modulation level 6 | * multiple carrier and modulator waveforms 7 | * LFO for modulation level with multi-waveform 8 | * multiple FM ratio modes (quantised, high/low linear and fixed) 9 | * 10 | * Source Code Repository: https://github.com/Meebleeps/MeeBleeps-Freaq-FM-Synth 11 | * Youtube Channel: https://www.youtube.com/channel/UC4I1ExnOpH_GjNtm7ZdWeWA 12 | * 13 | * (C) 2021-2022 Meebleeps 14 | *----------------------------------------------------------------------------------------------------------- 15 | */ 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include // a template for an oscillator 22 | #include 23 | #include 24 | #include "avSource.h" 25 | #include "MutantFMSynthOptions.h" 26 | 27 | //making LFO update rate lower than control rate to save processing. places upper limit on LFO frequency 28 | #define LFO_OSCILLATOR_UPDATE_RATE 64 29 | 30 | // voice 1 31 | Oscil carrier1(SIN2048_DATA); 32 | Oscil modulator1(SIN2048_DATA); 33 | ADSR envelopeAmp1; 34 | ADSR envelopeMod1; 35 | Oscil lfo1(SIN2048_DATA); 36 | 37 | // voice 2 38 | Oscil carrier2(SIN2048_DATA); 39 | Oscil modulator2(SIN2048_DATA); 40 | ADSR envelopeAmp2; 41 | ADSR envelopeMod2; 42 | Oscil lfo2(SIN2048_DATA); 43 | 44 | 45 | 46 | /*---------------------------------------------------------------------------------------------------------- 47 | * MutatingFM::MutatingFM() 48 | * create a new instance 49 | *---------------------------------------------------------------------------------------------------------- 50 | */ 51 | MutatingFM::MutatingFM() 52 | { 53 | masterGain = 255; 54 | masterGainBitShift = 8; 55 | setOscillator(0); 56 | setFreqs(33); 57 | updateCount = 0; 58 | envelopeMod->setADLevels(255,0); 59 | param[SYNTH_PARAMETER_MOD_AMOUNT_LFODEPTH] = 0; 60 | } 61 | 62 | 63 | 64 | /*---------------------------------------------------------------------------------------------------------- 65 | * MutatingFM::setOscillator() 66 | * links this object instance to a given statically defined oscillator, envelope etc 67 | * terrible design pattern but I had compilation issues when these variables were declared in the class def where they belong 68 | *---------------------------------------------------------------------------------------------------------- 69 | */ 70 | void MutatingFM::setOscillator(uint8_t oscIndex) 71 | { 72 | switch (oscIndex) 73 | { 74 | case 1: 75 | carrier = &carrier2; 76 | modulator = &modulator2; 77 | envelopeAmp = &envelopeAmp2; 78 | envelopeMod = &envelopeMod2; 79 | lfo = &lfo2; 80 | break; 81 | 82 | case 0: 83 | default: 84 | carrier = &carrier1; 85 | modulator = &modulator1; 86 | envelopeAmp = &envelopeAmp1; 87 | envelopeMod = &envelopeMod1; 88 | lfo = &lfo1; 89 | break; 90 | } 91 | 92 | lfo->setFreq((float)0.02); 93 | } 94 | 95 | 96 | 97 | /*---------------------------------------------------------------------------------------------------------- 98 | * MutatingFM::noteOff() 99 | * turns the note on 100 | * currently velocity is ignored 101 | *---------------------------------------------------------------------------------------------------------- 102 | */ 103 | int MutatingFM::noteOn(byte pitch, byte velocity, unsigned int length) 104 | { 105 | #ifndef ENABLE_MIDI_OUTPUT 106 | 107 | //Serial.print(F("MutatingFM::noteOn(")); 108 | //Serial.print(pitch); 109 | //Serial.println(F(")")); 110 | #endif 111 | 112 | 113 | if (velocity > 0 && pitch > 0) 114 | { 115 | if (length != lastNoteLength) 116 | { 117 | envelopeAmp->setTimes(0,length,0,50); 118 | envelopeAmp->setADLevels(255,200); 119 | } 120 | envelopeAmp->noteOn(false); 121 | 122 | // setup modulation envelope attack, decay time based on parameters 123 | if (param[SYNTH_PARAMETER_ENVELOPE_ATTACK] < MIN_MODULATION_ENV_TIME) 124 | { 125 | envelopeMod->setTimes(0,param[SYNTH_PARAMETER_ENVELOPE_DECAY]+MIN_MODULATION_ENV_TIME,length,50); 126 | } 127 | else 128 | { 129 | envelopeMod->setTimes(param[SYNTH_PARAMETER_ENVELOPE_ATTACK],param[SYNTH_PARAMETER_ENVELOPE_DECAY]+MIN_MODULATION_ENV_TIME,length,50); 130 | } 131 | 132 | setFreqs(pitch); 133 | envelopeMod->noteOn(true); 134 | 135 | #ifndef ENABLE_MIDI_OUTPUT 136 | 137 | /* 138 | Serial.print(F("note on: envelopeMod ADSR=(")); 139 | Serial.print(param[SYNTH_PARAMETER_ENVELOPE_ATTACK]); 140 | Serial.print(F(", " )); 141 | Serial.print(param[SYNTH_PARAMETER_ENVELOPE_DECAY]); 142 | Serial.print(F(", Sustain Level=" )); 143 | Serial.print(param[SYNTH_PARAMETER_ENVELOPE_SUSTAIN] >> 2); 144 | Serial.print(F(", 50)" )); 145 | Serial.println(); 146 | */ 147 | #endif 148 | 149 | lastNoteLength = length; 150 | } 151 | else 152 | { 153 | noteOff(); 154 | } 155 | return 0; 156 | } 157 | 158 | 159 | /*---------------------------------------------------------------------------------------------------------- 160 | * MutatingFM::noteOff() 161 | * turns the note off 162 | *---------------------------------------------------------------------------------------------------------- 163 | */ 164 | int MutatingFM::noteOff() 165 | { 166 | envelopeAmp->noteOff(); 167 | return 0; 168 | 169 | } 170 | 171 | 172 | /*---------------------------------------------------------------------------------------------------------- 173 | * MutatingFM::updateAudio() 174 | * returns the next audio sample 175 | *---------------------------------------------------------------------------------------------------------- 176 | */ 177 | inline int MutatingFM::updateAudio() 178 | { 179 | // TODO: ignores master gain due to audio glitches when shifting by a variable rather than a constant 180 | // optimise and reinstate 181 | //return MonoOutput::fromNBit(9, (((int16_t)carrier->phMod(modulatorAmount * modulator->next() >> 8) * currentGain) >> masterGainBitShift)); 182 | 183 | // return audio without master gain 184 | return MonoOutput::fromNBit(9, (((int16_t)carrier->phMod(modulatorAmount * modulator->next() >> 8) * currentGain) >> 8)); 185 | } 186 | 187 | 188 | 189 | 190 | 191 | /*---------------------------------------------------------------------------------------------------------- 192 | * MutatingFM::updateControl() 193 | * updates the envelopes and modulation control 194 | *---------------------------------------------------------------------------------------------------------- 195 | */ 196 | inline void MutatingFM::updateControl() 197 | { 198 | #ifdef SYNTH_MODULATION_UPDATE_DIVIDER 199 | // CONTROL_RATE has to be high to reduce jitter in the sequencer but running these calcs at 128hz seems to be too high, so only do it every 2nd call 200 | if (++updateCount % SYNTH_MODULATION_UPDATE_DIVIDER == 0) 201 | { 202 | #endif 203 | 204 | // update amplitude & modulation envelopes 205 | // 20-30 micros 206 | envelopeAmp->update(); 207 | envelopeMod->update(); 208 | 209 | #ifdef SYNTH_MODULATION_UPDATE_DIVIDER 210 | } 211 | #endif 212 | 213 | // store gain for use in updateAudio 214 | currentGain = envelopeAmp->next(); 215 | 216 | // store LFO value for use in displaying the lfo position onscreen. 217 | lastLFOValue = lfo->next()+128; 218 | 219 | modulatorAmount = ((((uint32_t)param[SYNTH_PARAMETER_MOD_AMOUNT]) * (uint32_t)envelopeMod->next()) 220 | + (((uint32_t)param[SYNTH_PARAMETER_MOD_AMOUNT_LFODEPTH]) * (uint32_t)lastLFOValue) 221 | ); 222 | #ifndef ENABLE_MIDI_OUTPUT 223 | 224 | //Serial.println(Q16n16_to_float(modulatorAmount)); 225 | #endif 226 | 227 | } 228 | 229 | 230 | 231 | /*---------------------------------------------------------------------------------------------------------- 232 | * MutatingFM::setGain() 233 | * sets the gain 234 | * stores it as a 0-255 byte and also as a bitshift value of gain reduction 8 (max volume) - 17 (off) 235 | *---------------------------------------------------------------------------------------------------------- 236 | */ 237 | void MutatingFM::setGain(byte gain) 238 | { 239 | masterGain = gain; 240 | 241 | if (masterGain == 0) 242 | { 243 | masterGainBitShift = 17; 244 | } 245 | else 246 | { 247 | masterGainBitShift = 8 + (((uint16_t)264 - (uint16_t)masterGain) >> 5); 248 | } 249 | } 250 | 251 | 252 | 253 | 254 | /*---------------------------------------------------------------------------------------------------------- 255 | * MutatingFM::setFreqs() 256 | * calculates the frequencies based on the current parameters 257 | *---------------------------------------------------------------------------------------------------------- 258 | */ 259 | void MutatingFM::setFreqs(uint8_t midiNote) 260 | { 261 | uint8_t multIndex; 262 | float freqshift[17] = {0,0.03125,0.0625,0.125,0.25,0.5,1,1.5,2,2.5,3,3.5,4,5,6,7,8}; 263 | 264 | 265 | if(midiNote != lastMidiNote && midiNote != 0) 266 | { 267 | carrierFrequency = Q16n16_mtof(Q8n0_to_Q16n16(midiNote)); 268 | carrier->setFreq_Q16n16(carrierFrequency); 269 | lastMidiNote = midiNote; 270 | } 271 | 272 | // added EXPONENTIAL & LINEAR FM modes - exponential is fixed to defined multiples 273 | // LINEAR is carrier * value with two ranges 274 | switch(fmMode) 275 | { 276 | case FM_MODE_EXPONENTIAL: 277 | lastParam[SYNTH_PARAMETER_MOD_RATIO] = param[SYNTH_PARAMETER_MOD_RATIO]; 278 | 279 | multIndex = param[SYNTH_PARAMETER_MOD_RATIO]/61;//(1023/17); 280 | 281 | if (multIndex>0) 282 | { 283 | modulationFrequency = carrierFrequency * freqshift[multIndex]; 284 | } 285 | else 286 | { 287 | modulationFrequency = carrierFrequency*((float)1.0 / ((512-param[SYNTH_PARAMETER_MOD_RATIO])+1)); 288 | } 289 | break; 290 | 291 | case FM_MODE_LINEAR_HIGH: 292 | modulationFrequency = carrierFrequency*(float)param[SYNTH_PARAMETER_MOD_RATIO]/100;// carrierFrequency*((float)1.0 / ((512-param[SYNTH_PARAMETER_MOD_RATIO])+1)); 293 | break; 294 | 295 | case FM_MODE_LINEAR_LOW: 296 | modulationFrequency = carrierFrequency*(float)param[SYNTH_PARAMETER_MOD_RATIO]/10000;// carrierFrequency*((float)1.0 / ((512-param[SYNTH_PARAMETER_MOD_RATIO])+1)); 297 | break; 298 | 299 | case FM_MODE_FREE: 300 | modulationFrequency = (uint32_t)param[SYNTH_PARAMETER_MOD_RATIO] << 17; //0-1023 << 17 into a Q16n16 value = 0-2000hz 301 | break; 302 | } 303 | 304 | modulator->setFreq_Q16n16(modulationFrequency); 305 | 306 | 307 | 308 | /* 309 | #ifndef ENABLE_MIDI_OUTPUT 310 | 311 | if (midiNote != 0) 312 | { 313 | if (carrier == &carrier1) 314 | { 315 | Serial.print(F("OSC1: ")); 316 | } 317 | else 318 | { 319 | Serial.print(F("OSC2: ")); 320 | } 321 | 322 | 323 | Serial.print(F("set frequency note=")); 324 | Serial.print(midiNote); 325 | Serial.print(F(", carrier=")); 326 | Serial.print(Q16n16_to_float(carrierFrequency)); 327 | Serial.print(F(", modfreq=")); 328 | Serial.print(Q16n16_to_float(modulationFrequency)); 329 | Serial.println(); 330 | } 331 | #endif 332 | 333 | */ 334 | } 335 | 336 | 337 | 338 | /*---------------------------------------------------------------------------------------------------------- 339 | * MutatingPhasor::setFilterShape() 340 | * 341 | * adjusts attack, decay and sustain level for the filter to provide 1-knob control of filter envelope 342 | *---------------------------------------------------------------------------------------------------------- 343 | */ 344 | void MutatingFM::setModulationShape(uint16_t newValue) 345 | { 346 | #ifndef ENABLE_MIDI_OUTPUT 347 | 348 | Serial.print(F("setModulationShape(")); 349 | Serial.print(newValue); 350 | Serial.print(F(") ")); 351 | #endif 352 | if (newValue >= 0 && newValue < MAX_FILTER_SHAPE) 353 | { 354 | #ifndef ENABLE_MIDI_OUTPUT 355 | Serial.print(F(" settiing ATTACK ")); 356 | #endif 357 | 358 | // for first 60% of range, attack = 0 359 | // for second part of range, attack is linear 360 | if (newValue < 600) 361 | { 362 | param[SYNTH_PARAMETER_ENVELOPE_ATTACK] = 0; 363 | } 364 | else 365 | { 366 | param[SYNTH_PARAMETER_ENVELOPE_ATTACK] = (newValue - 600)*2; 367 | } 368 | 369 | // set decay 370 | #ifndef ENABLE_MIDI_OUTPUT 371 | Serial.print(F(" settiing DECAY")); 372 | #endif 373 | 374 | param[SYNTH_PARAMETER_ENVELOPE_DECAY] = newValue; 375 | 376 | // set sustain volume 377 | // for first 1/2 of range, sustain is cubic 378 | // for second 3/4 of range, sustain is maxxed 379 | // for last part sustain decreases from 255 to 128 380 | #ifndef ENABLE_MIDI_OUTPUT 381 | Serial.print(F(" settiing SUSTAIN")); 382 | #endif 383 | 384 | if (newValue < 512) 385 | { 386 | uint32_t p = pow(newValue,3) / 262144; 387 | param[SYNTH_PARAMETER_ENVELOPE_SUSTAIN] = min(p,255);// (255.0 * (float)newValue) / 512; 388 | } 389 | else if (newValue < 768) 390 | { 391 | param[SYNTH_PARAMETER_ENVELOPE_SUSTAIN] = 255; 392 | } 393 | else 394 | { 395 | param[SYNTH_PARAMETER_ENVELOPE_SUSTAIN] = 255 + ((768 - newValue)/2); 396 | } 397 | 398 | param[SYNTH_PARAMETER_ENVELOPE_SHAPE] = newValue; 399 | } 400 | #ifndef ENABLE_MIDI_OUTPUT 401 | 402 | Serial.println(F(")")); 403 | #endif 404 | } 405 | 406 | 407 | 408 | 409 | 410 | 411 | void MutatingFM::setParam(uint8_t paramIndex, uint16_t newValue) 412 | { 413 | if (param[paramIndex] != newValue) 414 | { 415 | param[paramIndex] = newValue; 416 | 417 | switch(paramIndex) 418 | { 419 | case SYNTH_PARAMETER_MOD_RATIO: 420 | setFreqs(0); 421 | break; 422 | 423 | case SYNTH_PARAMETER_MOD_AMOUNT: 424 | envelopeMod->setADLevels(param[SYNTH_PARAMETER_MOD_AMOUNT] >> 2,0); 425 | break; 426 | 427 | case SYNTH_PARAMETER_ENVELOPE_SHAPE: 428 | setModulationShape(newValue); 429 | envelopeMod->setTimes(param[SYNTH_PARAMETER_ENVELOPE_ATTACK],param[SYNTH_PARAMETER_ENVELOPE_DECAY]+MIN_MODULATION_ENV_TIME,lastNoteLength,50); 430 | break; 431 | 432 | case SYNTH_PARAMETER_ENVELOPE_ATTACK: 433 | envelopeMod->setTimes(param[SYNTH_PARAMETER_ENVELOPE_ATTACK],param[SYNTH_PARAMETER_ENVELOPE_DECAY]+MIN_MODULATION_ENV_TIME,lastNoteLength,50); 434 | break; 435 | 436 | case SYNTH_PARAMETER_ENVELOPE_DECAY: 437 | envelopeMod->setTimes(param[SYNTH_PARAMETER_ENVELOPE_ATTACK],param[SYNTH_PARAMETER_ENVELOPE_DECAY]+MIN_MODULATION_ENV_TIME,lastNoteLength,50); 438 | break; 439 | 440 | case SYNTH_PARAMETER_ENVELOPE_SUSTAIN: 441 | envelopeMod->setSustainLevel(param[SYNTH_PARAMETER_ENVELOPE_SUSTAIN] >> 2); 442 | break; 443 | 444 | } 445 | } 446 | } 447 | 448 | 449 | uint16_t MutatingFM::getParam(uint8_t paramIndex) 450 | { 451 | return param[paramIndex]; 452 | } 453 | 454 | 455 | 456 | /*---------------------------------------------------------------------------------------------------------- 457 | * toggleFMMode 458 | * Sets the FM ratio mode 459 | * 460 | * FM_MODE_EXPONENTIAL modulator is a quantized multiple of the carrier, 461 | * FM_MODE_LINEAR_HIGH modulator is a multiple of the carrier, with high scale 462 | * FM_MODE_LINEAR_LOW modulator is a multiple of the carrier, with low scale 463 | * FM_MODE_FREE modulator is not related to the the carrier 464 | *---------------------------------------------------------------------------------------------------------- 465 | */ 466 | void MutatingFM::toggleFMMode() 467 | { 468 | fmMode = (fmMode + 1) % MAX_FM_MODES; 469 | setFreqs(0); 470 | } 471 | 472 | 473 | /*---------------------------------------------------------------------------------------------------------- 474 | * getFMMode 475 | * Gets the FM ratio mode 476 | *---------------------------------------------------------------------------------------------------------- 477 | */ 478 | uint8_t MutatingFM::getFMMode() 479 | { 480 | return fmMode; 481 | } 482 | 483 | 484 | /*---------------------------------------------------------------------------------------------------------- 485 | * toggleCarrierWaveform 486 | * Sets the carrier waveform 487 | * 488 | * set to WAVEFORM_NULL to switch the carrier off 489 | *---------------------------------------------------------------------------------------------------------- 490 | */ 491 | void MutatingFM::toggleCarrierWaveform() 492 | { 493 | carrierWaveform = (carrierWaveform + 1) % MAX_CARRIER_WAVEFORMS; 494 | 495 | switch (carrierWaveform) 496 | { 497 | case WAVEFORM_SIN: 498 | carrier->setTable(SIN2048_DATA); 499 | break; 500 | 501 | case WAVEFORM_SAW: 502 | carrier->setTable(SAW2048_DATA); 503 | break; 504 | 505 | case WAVEFORM_REVSAW: 506 | carrier->setTable(REVSAW2048_DATA); 507 | break; 508 | 509 | case WAVEFORM_SQUARE: 510 | carrier->setTable(SQUARE2048_DATA); 511 | break; 512 | 513 | /** @brief if COMPILE_SMALLER_BINARY flag is defined, omit the pseudorandom waveform */ 514 | #ifndef COMPILE_SMALLER_BINARY 515 | case WAVEFORM_PSEUDORANDOM: 516 | carrier->setTable(PSEUDORANDOM2048_DATA); 517 | break; 518 | #endif 519 | 520 | case WAVEFORM_NULL: 521 | carrier->setTable(NULLWAVEFORM2048_DATA); 522 | break; 523 | 524 | default: 525 | carrier->setTable(SIN2048_DATA); 526 | } 527 | } 528 | 529 | 530 | /*---------------------------------------------------------------------------------------------------------- 531 | * getCarrierWaveform 532 | * Gets the carrier waveform 533 | *---------------------------------------------------------------------------------------------------------- 534 | */ 535 | uint8_t MutatingFM::getCarrierWaveform() 536 | { 537 | return carrierWaveform; 538 | } 539 | 540 | 541 | 542 | 543 | /*---------------------------------------------------------------------------------------------------------- 544 | * toggleCarrierWaveform 545 | * Sets the carrier waveform 546 | * 547 | * set to WAVEFORM_NULL to switch the carrier off 548 | *---------------------------------------------------------------------------------------------------------- 549 | */ 550 | void MutatingFM::toggleModulatorWaveform() 551 | { 552 | modulatorWaveform = (modulatorWaveform + 1) % MAX_MODULATOR_WAVEFORMS; 553 | 554 | switch (modulatorWaveform) 555 | { 556 | case WAVEFORM_SIN: 557 | modulator->setTable(SIN2048_DATA); 558 | break; 559 | 560 | case WAVEFORM_SAW: 561 | modulator->setTable(SAW2048_DATA); 562 | break; 563 | 564 | case WAVEFORM_REVSAW: 565 | modulator->setTable(REVSAW2048_DATA); 566 | break; 567 | 568 | case WAVEFORM_SQUARE: 569 | modulator->setTable(SQUARE2048_DATA); 570 | break; 571 | 572 | /** @brief if COMPILE_SMALLER_BINARY flag is defined, omit the pseudorandom waveform */ 573 | #ifndef COMPILE_SMALLER_BINARY 574 | case WAVEFORM_PSEUDORANDOM: 575 | modulator->setTable(PSEUDORANDOM2048_DATA); 576 | break; 577 | #endif 578 | 579 | case WAVEFORM_NULL: 580 | modulator->setTable(NULLWAVEFORM2048_DATA); 581 | break; 582 | 583 | default: 584 | modulator->setTable(SIN2048_DATA); 585 | } 586 | } 587 | 588 | 589 | /*---------------------------------------------------------------------------------------------------------- 590 | * getModulatorWaveform 591 | * Gets the Modulator waveform 592 | *---------------------------------------------------------------------------------------------------------- 593 | */ 594 | uint8_t MutatingFM::getModulatorWaveform() 595 | { 596 | return modulatorWaveform; 597 | } 598 | 599 | 600 | 601 | 602 | 603 | /*---------------------------------------------------------------------------------------------------------- 604 | * toggleLFOWaveform 605 | * Sets the LFO waveform 606 | *---------------------------------------------------------------------------------------------------------- 607 | */ 608 | void MutatingFM::toggleLFOWaveform() 609 | { 610 | lfoWaveform = (lfoWaveform + 1) % MAX_LFO_WAVEFORMS; 611 | 612 | switch (lfoWaveform) 613 | { 614 | case WAVEFORM_SIN: 615 | lfo->setTable(SIN2048_DATA); 616 | break; 617 | 618 | case WAVEFORM_SAW: 619 | lfo->setTable(SAW2048_DATA); 620 | break; 621 | 622 | case WAVEFORM_REVSAW: 623 | lfo->setTable(REVSAW2048_DATA); 624 | break; 625 | 626 | case WAVEFORM_SQUARE: 627 | lfo->setTable(SQUARE2048_DATA); 628 | break; 629 | 630 | /** @brief if COMPILE_SMALLER_BINARY flag is defined, omit the pseudorandom waveform */ 631 | #ifndef COMPILE_SMALLER_BINARY 632 | case WAVEFORM_PSEUDORANDOM: 633 | lfo->setTable(PSEUDORANDOM2048_DATA); 634 | break; 635 | #endif 636 | 637 | case WAVEFORM_NULL: 638 | lfo->setTable(NULLWAVEFORM2048_DATA); 639 | break; 640 | 641 | default: 642 | lfo->setTable(SIN2048_DATA); 643 | } 644 | } 645 | 646 | 647 | /*---------------------------------------------------------------------------------------------------------- 648 | * getLFOWaveform 649 | * Gets the LFO waveform 650 | *---------------------------------------------------------------------------------------------------------- 651 | */ 652 | uint8_t MutatingFM::getLFOWaveform() 653 | { 654 | return lfoWaveform; 655 | } 656 | 657 | 658 | 659 | /*---------------------------------------------------------------------------------------------------------- 660 | * mutate 661 | * used to generate randomness in the parameters - not used 662 | *---------------------------------------------------------------------------------------------------------- 663 | */ 664 | int MutatingFM::mutate() 665 | { 666 | // 667 | return 0; 668 | 669 | } 670 | 671 | 672 | 673 | /*---------------------------------------------------------------------------------------------------------- 674 | * getLFOValue 675 | * gets the current LFO value 676 | *---------------------------------------------------------------------------------------------------------- 677 | */ 678 | uint8_t MutatingFM::getLFOValue() 679 | { 680 | return lastLFOValue; 681 | } 682 | 683 | 684 | 685 | /*---------------------------------------------------------------------------------------------------------- 686 | * setLFOFrequency 687 | * sets the current LFO frequency 688 | *---------------------------------------------------------------------------------------------------------- 689 | */ 690 | void MutatingFM::setLFOFrequency(float freq) 691 | { 692 | lfo->setFreq_Q16n16(float_to_Q16n16(freq)); 693 | } 694 | 695 | 696 | -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/avSequencer.cpp: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------------------------------------- 2 | * avSequencer.cpp 3 | * 4 | * Implements a generative sequencer with multiple generative algorithms, musical scale quantisation, 5 | * variable sequence length (up to 16 steps) and multiple parameter-lock (motion-sequencing) channels 6 | * 7 | * (C) 2021-2022 Meebleeps 8 | *----------------------------------------------------------------------------------------------------------- 9 | */ 10 | #include 11 | #include 12 | 13 | #include "Arduino.h" 14 | #include "avSequencer.h" 15 | 16 | 17 | /*---------------------------------------------------------------------------------------------------------- 18 | * MutatingSequencer::MutatingSequencer() 19 | * initialises the sequencer 20 | *---------------------------------------------------------------------------------------------------------- 21 | */ 22 | MutatingSequencer::MutatingSequencer() 23 | { 24 | running = false; 25 | mutationAlgorithm = MUTATE_ALGO_DEFAULT; 26 | 27 | // initialise sequence 28 | for (uint8_t i = 0; i < MAX_SEQUENCE_LENGTH; i++) 29 | { 30 | notes[i] = 0; 31 | } 32 | 33 | for (uint8_t i = 0; i < MAX_SCALE_LENGTH; i++) 34 | { 35 | scaleNotes[i] = 0; 36 | } 37 | 38 | for (uint8_t i = 0; i < MAX_SEQUENCE_LENGTH; i++) 39 | { 40 | for (uint8_t m = 0; m < MAX_PARAMETER_LOCKS; m++) 41 | { 42 | parameterLocks[m][i] = 0; 43 | } 44 | } 45 | 46 | currentStep = 0; 47 | retrigStep = 0; 48 | retrigState = false; 49 | tonicNote = 9; // default to A 50 | octave = 1; 51 | mutationProbability = 0; 52 | noteProbability = 70; 53 | tonicProbability = 30; 54 | sequenceLength = 16; 55 | bpm = 130; 56 | currentNote = tonicNote; 57 | nextStepNoteLength = 80; 58 | octaveSpread = 3; 59 | scaleNoteCount = 7; 60 | 61 | // deleted this to allow for different pulse steps defined by the UI layer 62 | //syncPulseSteps = 2; // standard 2 steps per sync pulse as per volca 63 | syncPulseClockDivide = 1; // divide the clock by this many steps 64 | 65 | nextStepTimeMillis = (15000 / bpm); // 16th note length for given BPM 66 | 67 | lastSyncPulseTimeMicros = 0; 68 | 69 | initialiseScale(SCALEMODE_PENTA); 70 | newSequence(sequenceLength); 71 | 72 | _debugOutput = true; 73 | printParameters(); 74 | } 75 | 76 | 77 | 78 | /*---------------------------------------------------------------------------------------------------------- 79 | * MutatingSequencer::start() 80 | * starts the sequencer at step 0 81 | *---------------------------------------------------------------------------------------------------------- 82 | */ 83 | void MutatingSequencer::start() 84 | { 85 | #ifndef ENABLE_MIDI_OUTPUT 86 | Serial.println(F("Sequencer.Start()")); 87 | #endif 88 | running = true; 89 | ignoreNextSyncPulse = true; 90 | //nextStep(true); 91 | } 92 | 93 | 94 | 95 | 96 | /*---------------------------------------------------------------------------------------------------------- 97 | * MutatingSequencer::stop() 98 | * stops the sequencer 99 | *---------------------------------------------------------------------------------------------------------- 100 | */ 101 | void MutatingSequencer::stop() 102 | { 103 | #ifndef ENABLE_MIDI_OUTPUT 104 | Serial.println(F("Sequencer.Stop()")); 105 | #endif 106 | running = false; 107 | } 108 | 109 | 110 | /*---------------------------------------------------------------------------------------------------------- 111 | * MutatingSequencer::toggleStart() 112 | * starts the sequencer if it is stopped, otherwise stops it 113 | *---------------------------------------------------------------------------------------------------------- 114 | */ 115 | void MutatingSequencer::toggleStart() 116 | { 117 | if (!running) 118 | { 119 | start(); 120 | } 121 | else 122 | { 123 | stop(); 124 | } 125 | } 126 | 127 | 128 | 129 | /*---------------------------------------------------------------------------------------------------------- 130 | * MutatingSequencer::setScale() 131 | * sets the scale and generates a new sequence according to the new scale 132 | *---------------------------------------------------------------------------------------------------------- 133 | */ 134 | void MutatingSequencer::setScale(uint8_t scaleMode) 135 | { 136 | initialiseScale(scaleMode); 137 | newSequence(sequenceLength); 138 | #ifndef ENABLE_MIDI_OUTPUT 139 | Serial.print(F("NEW SCALE: ")); 140 | Serial.println(scaleMode); 141 | #endif 142 | } 143 | 144 | 145 | /*---------------------------------------------------------------------------------------------------------- 146 | * MutatingSequencer::getScale() 147 | * returns the current scale mode 148 | *---------------------------------------------------------------------------------------------------------- 149 | */ 150 | uint8_t MutatingSequencer::getScale() 151 | { 152 | return currentScaleMode; 153 | } 154 | 155 | 156 | /*---------------------------------------------------------------------------------------------------------- 157 | * MutatingSequencer::getAlgorithm() 158 | * returns the current mutation algorithm 159 | *---------------------------------------------------------------------------------------------------------- 160 | */ 161 | uint8_t MutatingSequencer::getAlgorithm() 162 | { 163 | return mutationAlgorithm; 164 | } 165 | 166 | 167 | /*---------------------------------------------------------------------------------------------------------- 168 | * MutatingSequencer::setAlgorithm() 169 | * sets the current mutation algorithm 170 | *---------------------------------------------------------------------------------------------------------- 171 | */ 172 | void MutatingSequencer::setAlgorithm(uint8_t newValue) 173 | { 174 | mutationAlgorithm = newValue % MAX_MUTATE_ALGO_COUNT; 175 | } 176 | 177 | /*---------------------------------------------------------------------------------------------------------- 178 | * MutatingSequencer::incrAlgorithm() 179 | * moves to the next algorithm 180 | *---------------------------------------------------------------------------------------------------------- 181 | */ 182 | void MutatingSequencer::nextAlgorithm() 183 | { 184 | mutationAlgorithm = (mutationAlgorithm + 1) % MAX_MUTATE_ALGO_COUNT; 185 | #ifndef ENABLE_MIDI_OUTPUT 186 | Serial.print(F("New Algorithm = ")); 187 | Serial.println(mutationAlgorithm); 188 | #endif 189 | } 190 | 191 | 192 | 193 | 194 | /*---------------------------------------------------------------------------------------------------------- 195 | * MutatingSequencer::getCurrentNote() 196 | * gets the note value for the current step 197 | *---------------------------------------------------------------------------------------------------------- 198 | */ 199 | byte MutatingSequencer::getCurrentNote() 200 | { 201 | if (!retrigState) 202 | { 203 | return notes[currentStep]; 204 | } 205 | else 206 | { 207 | return notes[retrigStep]; 208 | } 209 | } 210 | 211 | 212 | /*---------------------------------------------------------------------------------------------------------- 213 | * MutatingSequencer::getCurrentStep() 214 | * gets the current playing step 215 | *---------------------------------------------------------------------------------------------------------- 216 | */ 217 | byte MutatingSequencer::getCurrentStep() 218 | { 219 | if(!retrigState) 220 | { 221 | return currentStep; 222 | } 223 | else 224 | { 225 | return retrigStep; 226 | } 227 | 228 | } 229 | 230 | 231 | /*---------------------------------------------------------------------------------------------------------- 232 | * MutatingSequencer::setRetrigger() 233 | * sets retrig on or off 234 | *---------------------------------------------------------------------------------------------------------- 235 | */ 236 | void MutatingSequencer::setRetrigger(bool newRetrigState) 237 | { 238 | if (newRetrigState != retrigState) 239 | { 240 | if(newRetrigState) 241 | { 242 | retrigState = true; 243 | retrigStep = currentStep; 244 | } 245 | else 246 | { 247 | retrigState = false; 248 | } 249 | } 250 | } 251 | 252 | 253 | /*---------------------------------------------------------------------------------------------------------- 254 | * MutatingSequencer::setparameterLocks() 255 | * records the given value as a parameter lock on the given channel 256 | *---------------------------------------------------------------------------------------------------------- 257 | */ 258 | void MutatingSequencer::setParameterLock(byte channel, int value) 259 | { 260 | parameterLocks[channel][currentStep] = value; 261 | } 262 | 263 | 264 | /*---------------------------------------------------------------------------------------------------------- 265 | * MutatingSequencer::getparameterLocks() 266 | * returns the parameter lock on the given channel for the current step 267 | *---------------------------------------------------------------------------------------------------------- 268 | */ 269 | int MutatingSequencer::getParameterLock(byte channel) 270 | { 271 | return parameterLocks[channel][currentStep]; 272 | } 273 | 274 | 275 | /*---------------------------------------------------------------------------------------------------------- 276 | * MutatingSequencer::clearAllParameterLocks() 277 | * clears all parameter locks for the given channel 278 | *---------------------------------------------------------------------------------------------------------- 279 | */ 280 | void MutatingSequencer::clearAllParameterLocks(byte channel) 281 | { 282 | for (uint8_t i = 0; i < MAX_SEQUENCE_LENGTH; i++) 283 | { 284 | parameterLocks[channel][i] = 0; 285 | } 286 | } 287 | 288 | 289 | 290 | /*---------------------------------------------------------------------------------------------------------- 291 | * MutatingSequencer::setTonic() 292 | * sets a new tonic 293 | *---------------------------------------------------------------------------------------------------------- 294 | */ 295 | void MutatingSequencer::setTonic(int8_t newTonic) 296 | { 297 | int8_t noteShift; 298 | 299 | if (newTonic != tonicNote) 300 | { 301 | #ifndef ENABLE_MIDI_OUTPUT 302 | Serial.print(F("OLD TONIC: ")); 303 | Serial.print(tonicNote); 304 | Serial.print(F(", NEW TONIC: ")); 305 | Serial.println(newTonic); 306 | #endif 307 | 308 | noteShift = newTonic - tonicNote; 309 | tonicNote = newTonic; 310 | 311 | // update the whole sequence to the new tonic 312 | for(int i=0; i< MAX_SEQUENCE_LENGTH; i++) 313 | { 314 | if(notes[i] > 0) notes[i] += noteShift; 315 | } 316 | printSequence(); 317 | } 318 | } 319 | 320 | /*---------------------------------------------------------------------------------------------------------- 321 | * MutatingSequencer::setTonic() 322 | * sets a new tonic 323 | *---------------------------------------------------------------------------------------------------------- 324 | */ 325 | int8_t MutatingSequencer::getTonic() 326 | { 327 | return tonicNote; 328 | } 329 | 330 | 331 | 332 | /*---------------------------------------------------------------------------------------------------------- 333 | * MutatingSequencer::setOctave() 334 | * sets a new octave 335 | *---------------------------------------------------------------------------------------------------------- 336 | */ 337 | void MutatingSequencer::setOctave(int8_t newOctave) 338 | { 339 | int8_t noteShift; 340 | 341 | if (newOctave != octave) 342 | { 343 | noteShift = (newOctave - octave) * 12; 344 | octave = newOctave; 345 | 346 | // update the whole sequence to the new tonic 347 | for(int i=0; i< MAX_SEQUENCE_LENGTH; i++) 348 | { 349 | if(notes[i] > 0) notes[i] += noteShift; 350 | } 351 | 352 | printSequence(); 353 | } 354 | 355 | } 356 | 357 | /*---------------------------------------------------------------------------------------------------------- 358 | * MutatingSequencer::getOctave() 359 | * returns the current octave 360 | *---------------------------------------------------------------------------------------------------------- 361 | */ 362 | int8_t MutatingSequencer::getOctave() 363 | { 364 | return octave; 365 | } 366 | 367 | 368 | 369 | /*---------------------------------------------------------------------------------------------------------- 370 | * MutatingSequencer::initialiseScale() 371 | * sets up the notes of each scale 372 | *---------------------------------------------------------------------------------------------------------- 373 | */ 374 | void MutatingSequencer::initialiseScale(int scaleMode) 375 | { 376 | currentScaleMode = scaleMode % MAX_SCALE_COUNT; 377 | 378 | switch(scaleMode) 379 | { 380 | case SCALEMODE_MINOR: 381 | scaleNotes[0] = 0; 382 | scaleNotes[1] = 2; 383 | scaleNotes[2] = 3; 384 | scaleNotes[3] = 5; 385 | scaleNotes[4] = 7; 386 | scaleNotes[5] = 8; 387 | scaleNotes[6] = 10; 388 | scaleNoteCount = 7; 389 | break; 390 | 391 | case SCALEMODE_MAJOR: 392 | scaleNotes[0] = 0; 393 | scaleNotes[1] = 2; 394 | scaleNotes[2] = 4; 395 | scaleNotes[3] = 5; 396 | scaleNotes[4] = 7; 397 | scaleNotes[5] = 9; 398 | scaleNotes[6] = 11; 399 | scaleNoteCount = 7; 400 | break; 401 | 402 | case SCALEMODE_PENTA: 403 | scaleNotes[0] = 0; 404 | scaleNotes[1] = 3; 405 | scaleNotes[2] = 5; 406 | scaleNotes[3] = 7; 407 | scaleNotes[4] = 10; 408 | scaleNoteCount = 5; 409 | break; 410 | 411 | case SCALEMODE_GOA: 412 | scaleNotes[0] = -2; 413 | scaleNotes[1] = 0; 414 | scaleNotes[2] = 1; 415 | scaleNotes[3] = 13; 416 | scaleNotes[4] = 0; 417 | scaleNotes[5] = 7; 418 | scaleNotes[6] = 8; 419 | scaleNotes[7] = 8; 420 | scaleNoteCount = 8; 421 | break; 422 | 423 | case SCALEMODE_OCTAVE: 424 | scaleNotes[0] = 0; 425 | scaleNotes[1] = 12; 426 | scaleNoteCount = 2; 427 | break; 428 | 429 | case SCALEMODE_FIFTHS: 430 | scaleNotes[0] = 0; 431 | scaleNotes[1] = 7; 432 | scaleNotes[2] = 12; 433 | scaleNoteCount = 3; 434 | break; 435 | 436 | 437 | } 438 | } 439 | 440 | 441 | 442 | /*--------------------------------------------------------------------------------------------------------------- 443 | * MutatingSequencer::update() 444 | * Call this function every time Mozzi updates controls at CONTROL_RATE 445 | * if stepTimer is ready, advance to next step and return true 446 | *--------------------------------------------------------------------------------------------------------------- 447 | */ 448 | bool MutatingSequencer::update(bool restart) 449 | { 450 | bool processStep = false; 451 | 452 | if (running) 453 | { 454 | if (restart || (stepTimer.ready() || syncPulseLive)) 455 | { 456 | nextStep(restart); 457 | processStep = true; 458 | } 459 | } 460 | 461 | return processStep; 462 | } 463 | 464 | 465 | 466 | /*--------------------------------------------------------------------------------------------------------------- 467 | * MutatingSequencer::nextStep() 468 | * Move ths sequencer to the next step 469 | *--------------------------------------------------------------------------------------------------------------- 470 | */ 471 | void MutatingSequencer::nextStep(bool restart) 472 | { 473 | if (restart) 474 | { 475 | currentStep = 0; 476 | duckingCounter = 0; 477 | } 478 | else 479 | { 480 | currentStep = (currentStep + 1) % sequenceLength; 481 | duckingCounter++; 482 | } 483 | #ifndef ENABLE_MIDI_OUTPUT 484 | //Serial.print(F("nextStep() step=")); 485 | //Serial.println(currentStep); 486 | #endif 487 | 488 | 489 | currentNote = notes[currentStep]; 490 | 491 | 492 | 493 | setNextStepTimer(); 494 | 495 | } 496 | 497 | 498 | /*--------------------------------------------------------------------------------------------------------------- 499 | * MutatingSequencer::setNextStepTimer() 500 | * Move ths sequencer to the next step 501 | *--------------------------------------------------------------------------------------------------------------- 502 | */ 503 | void MutatingSequencer::setNextStepTimer() 504 | { 505 | uint32_t currentStepTimeMicros; 506 | uint32_t timeElapsedSincePulseMicros; 507 | uint32_t forecastTimeToNextStepMicros; 508 | 509 | currentStepTimeMicros = mozziMicros(); 510 | 511 | #ifndef ENABLE_MIDI_OUTPUT 512 | Serial.print(F("step time micros=")); 513 | Serial.println(currentStepTimeMicros - lastStepTimeMicros); 514 | #endif 515 | 516 | if(syncPulseLive) 517 | { 518 | // this step is the first one after a sync pulse 519 | // adjust the next step 520 | 521 | timeElapsedSincePulseMicros = currentStepTimeMicros - lastSyncPulseTimeMicros; 522 | 523 | if(nextStepTimeMillis*1000 > timeElapsedSincePulseMicros) 524 | { 525 | forecastTimeToNextStepMicros = nextStepTimeMillis*1000 - timeElapsedSincePulseMicros; 526 | } 527 | else 528 | { 529 | forecastTimeToNextStepMicros = nextStepTimeMillis*1000; 530 | } 531 | #ifndef ENABLE_MIDI_OUTPUT 532 | //Serial.print(F(" adjusted=")); 533 | //Serial.println(forecastTimeToNextStepMicros); 534 | #endif 535 | 536 | stepTimer.start(forecastTimeToNextStepMicros/1000 + 3); 537 | 538 | syncPulseLive = false; 539 | } 540 | else 541 | { 542 | stepTimer.start(nextStepTimeMillis + 3); 543 | } 544 | 545 | lastStepTimeMicros = currentStepTimeMicros; 546 | 547 | } 548 | 549 | 550 | /*--------------------------------------------------------------------------------------------------------------- 551 | * returns true if the sequencer should output a sync pulse 552 | * will immediately reset the timer so that next call to update will trigger nextStep() 553 | * this allows for resyncing the sequence if the trigger tempo changes. 554 | * then sets the timer for the next step to 555 | *--------------------------------------------------------------------------------------------------------------- 556 | */ 557 | int8_t MutatingSequencer::outputSyncPulse() 558 | { 559 | return (duckingCounter % SYNC_STEPS_PER_PULSE) == 0; 560 | } 561 | 562 | 563 | 564 | /*--------------------------------------------------------------------------------------------------------------- 565 | * Call this function whenever a sync pulse is detected. 566 | * will immediately reset the timer so that next call to update will trigger nextStep() 567 | * this allows for resyncing the sequence if the trigger tempo changes. 568 | * then sets the timer for the next step to 569 | *--------------------------------------------------------------------------------------------------------------- 570 | */ 571 | void MutatingSequencer::syncPulse(int stepsPerClick) 572 | { 573 | uint32_t thisSyncPulseMicros; 574 | 575 | if (ignoreNextSyncPulse) 576 | { 577 | // reset the flag 578 | ignoreNextSyncPulse = false; 579 | } 580 | else 581 | { 582 | syncPulseLive = true; 583 | syncPulseCount++; 584 | 585 | thisSyncPulseMicros = mozziMicros(); 586 | 587 | timeSinceLastSyncPulseMicros = thisSyncPulseMicros - lastSyncPulseTimeMicros; 588 | lastSyncPulseTimeMicros = thisSyncPulseMicros; 589 | 590 | nextStepTimeMillis = timeSinceLastSyncPulseMicros / (1000 * stepsPerClick) * syncPulseClockDivide; 591 | 592 | // immediately make the timer ready, so next call to update will trigger next step 593 | stepTimer.start(0); 594 | 595 | } 596 | //Serial.print(F("timeSinceLastSyncPulseMicros = ")); 597 | //Serial.println(timeSinceLastSyncPulseMicros); 598 | } 599 | 600 | 601 | /*---------------------------------------------------------------------------------------------------------- 602 | * MutatingSequencer::testSequence() 603 | * initialises the sequencer with a new test sequence 604 | *---------------------------------------------------------------------------------------------------------- 605 | */ 606 | void MutatingSequencer::testSequence() 607 | { 608 | for (uint8_t i = 0; i < MAX_SEQUENCE_LENGTH; i++) 609 | { 610 | notes[i] = tonicNote + i; 611 | } 612 | } 613 | 614 | 615 | 616 | /*---------------------------------------------------------------------------------------------------------- 617 | * MutatingSequencer::newSequence() 618 | * initialises the sequencer with a new random sequence 619 | *---------------------------------------------------------------------------------------------------------- 620 | */ 621 | void MutatingSequencer::newSequence(byte seqLength) 622 | { 623 | if (seqLength > 0 && seqLength < MAX_SEQUENCE_LENGTH) 624 | { 625 | sequenceLength = seqLength; 626 | } 627 | 628 | for(int i=0; i < sequenceLength; i++) 629 | { 630 | //root //scale note //octave 631 | notes[i] = tonicNote + (12*octave) + scaleNotes[rand(scaleNoteCount)] + (12*rand(octaveSpread)); 632 | 633 | //sprinkle the tonic in there with a bit more frequency 634 | if (rand(100) < tonicProbability) 635 | { 636 | notes[i] = tonicNote + (12*octave) + (12*rand(octaveSpread)); 637 | } 638 | 639 | // sprinkle some rests 640 | if (rand(100) > noteProbability) 641 | { 642 | notes[i] = 0; 643 | } 644 | } 645 | } 646 | 647 | 648 | /*--------------------------------------------------------------------------------------------------------------- 649 | * mutateSequence 650 | * mutate the current sequence according to the selected mutation algorithm 651 | *--------------------------------------------------------------------------------------------------------------- 652 | */ 653 | void MutatingSequencer::mutateSequence() 654 | { 655 | switch(mutationAlgorithm) 656 | { 657 | case MUTATE_ALGO_DEFAULT: 658 | mutateSequenceDefault(); 659 | break; 660 | 661 | case MUTATE_ALGO_ARPEGGIATED: 662 | mutateSequenceArp(); 663 | break; 664 | } 665 | } 666 | 667 | 668 | /*--------------------------------------------------------------------------------------------------------------- 669 | * mutateSequenceDefault 670 | * default mutation algorithm 671 | *--------------------------------------------------------------------------------------------------------------- 672 | */ 673 | void MutatingSequencer::mutateSequenceDefault() 674 | { 675 | int seqStep; 676 | 677 | if(rand(100) < mutationProbability) 678 | { 679 | 680 | seqStep = rand(MAX_SEQUENCE_LENGTH); 681 | 682 | // don't mutate the retrig step if the sequencer is currently retriggering 683 | // allows the rest of the sequence to mutate while the retrigged step is held 684 | if (!retrigState || seqStep != retrigStep) 685 | { 686 | 687 | if (rand(100) < noteProbability) 688 | { 689 | if (rand(100) < tonicProbability) 690 | { 691 | notes[seqStep] = tonicNote + (12*octave) + (12*rand(octaveSpread)); 692 | } 693 | else 694 | { 695 | //root //scale note //octave 696 | notes[seqStep] = tonicNote + (12*octave) + scaleNotes[rand(scaleNoteCount)] + (12*rand(octaveSpread)); 697 | } 698 | 699 | } 700 | else 701 | { 702 | notes[seqStep] = 0; 703 | } 704 | } 705 | } 706 | } 707 | 708 | 709 | /*--------------------------------------------------------------------------------------------------------------- 710 | * mutateSequenceArp 711 | * arpegiated mutation algorithm 712 | *--------------------------------------------------------------------------------------------------------------- 713 | */ 714 | void MutatingSequencer::mutateSequenceArp() 715 | { 716 | int8_t startStep; 717 | int8_t startOctave; 718 | uint8_t startNote; 719 | 720 | int8_t seqStep; 721 | uint8_t seqNote; 722 | uint8_t stepSize; 723 | uint8_t runLength; 724 | int8_t runDirection; 725 | 726 | 727 | // include the default mutation 728 | mutateSequenceDefault(); 729 | 730 | if(rand(100) < mutationProbability) 731 | { 732 | runLength = 3; 733 | runDirection = 1;//rand(2) - 1; 734 | 735 | // put in a run of scale notes starting at a random step on a random scalenote in a random octave 736 | startStep = rand(MAX_SEQUENCE_LENGTH); 737 | startNote = rand(scaleNoteCount); 738 | startOctave = octave + rand(octaveSpread); 739 | stepSize = rand(2) + 1; 740 | 741 | if (rand(100) < noteProbability) 742 | { 743 | #ifndef ENABLE_MIDI_OUTPUT 744 | Serial.print(F("new arpeggio run: ")); 745 | #endif 746 | 747 | for (uint8_t i = 0; i < runLength; i++) 748 | { 749 | seqStep = (startStep + i) % MAX_SEQUENCE_LENGTH; 750 | seqNote = scaleNotes[(startNote + (i*stepSize*runDirection) ) % scaleNoteCount]; 751 | notes[seqStep] = tonicNote + seqNote + (12*(startOctave + (startNote + i < scaleNoteCount ? 0 : 1))); 752 | #ifndef ENABLE_MIDI_OUTPUT 753 | Serial.print(notes[seqStep]); 754 | Serial.print(F(",")); 755 | #endif 756 | 757 | } 758 | #ifndef ENABLE_MIDI_OUTPUT 759 | Serial.println(); 760 | #endif 761 | } 762 | } 763 | 764 | } 765 | 766 | /*---------------------------------------------------------------------------------------------------------- 767 | * MutatingSequencer::mutateMutation() 768 | * not used 769 | *---------------------------------------------------------------------------------------------------------- 770 | */ 771 | void MutatingSequencer::mutateMutation() 772 | { 773 | noteProbability = 50 + rand(50); 774 | mutationProbability = 10 + rand(20); 775 | } 776 | 777 | 778 | /*---------------------------------------------------------------------------------------------------------- 779 | * MutatingSequencer::mutateNoteLength() 780 | * not used 781 | *---------------------------------------------------------------------------------------------------------- 782 | */ 783 | void MutatingSequencer::mutateNoteLength() 784 | { 785 | setNextNoteLength(rand(500)); 786 | } 787 | 788 | 789 | /*---------------------------------------------------------------------------------------------------------- 790 | * MutatingSequencer::setNextNoteLength() 791 | * set the next note length 792 | *---------------------------------------------------------------------------------------------------------- 793 | */ 794 | void MutatingSequencer::setNextNoteLength(uint16_t newNoteLength) 795 | { 796 | if (newNoteLength > 0 and newNoteLength <= 65000 && newNoteLength != nextStepNoteLength) 797 | { 798 | nextStepNoteLength = newNoteLength; 799 | #ifndef ENABLE_MIDI_OUTPUT 800 | Serial.print(F("nextStepNoteLength=")); 801 | Serial.println(nextStepNoteLength); 802 | #endif 803 | 804 | } 805 | } 806 | 807 | 808 | /*---------------------------------------------------------------------------------------------------------- 809 | * MutatingSequencer::getNextNoteLength() 810 | * return the next note length 811 | *---------------------------------------------------------------------------------------------------------- 812 | */ 813 | uint16_t MutatingSequencer::getNextNoteLength() 814 | { 815 | return nextStepNoteLength; 816 | } 817 | 818 | 819 | /*---------------------------------------------------------------------------------------------------------- 820 | * MutatingSequencer::isRunning() 821 | * return true if the sequencer is running 822 | *---------------------------------------------------------------------------------------------------------- 823 | */ 824 | uint8_t MutatingSequencer::isRunning() 825 | { 826 | return running; 827 | } 828 | 829 | 830 | /*---------------------------------------------------------------------------------------------------------- 831 | * MutatingSequencer::getSequenceLength() 832 | * return the sequence length 833 | *---------------------------------------------------------------------------------------------------------- 834 | */ 835 | byte MutatingSequencer::getSequenceLength() 836 | { 837 | return sequenceLength; 838 | } 839 | 840 | 841 | /*---------------------------------------------------------------------------------------------------------- 842 | * MutatingSequencer::setSequenceLength() 843 | * set the sequence length 844 | *---------------------------------------------------------------------------------------------------------- 845 | */ 846 | void MutatingSequencer::setSequenceLength(byte newLength) 847 | { 848 | if(newLength > 0 && newLength <= MAX_SEQUENCE_LENGTH && sequenceLength != newLength) 849 | { 850 | sequenceLength = newLength; 851 | #ifndef ENABLE_MIDI_OUTPUT 852 | Serial.print(F("sequenceLength=")); 853 | Serial.println(sequenceLength); 854 | #endif 855 | } 856 | } 857 | 858 | 859 | 860 | /*---------------------------------------------------------------------------------------------------------- 861 | * MutatingSequencer::setNoteProbability() 862 | * set the note probability 863 | *---------------------------------------------------------------------------------------------------------- 864 | */ 865 | void MutatingSequencer::setNoteProbability(byte newProbability) 866 | { 867 | if (newProbability >= 0 && newProbability <= 100 && newProbability != noteProbability) 868 | { 869 | noteProbability = newProbability; 870 | #ifndef ENABLE_MIDI_OUTPUT 871 | Serial.print(F("noteProbability=")); 872 | Serial.println(noteProbability); 873 | #endif 874 | } 875 | } 876 | 877 | /*---------------------------------------------------------------------------------------------------------- 878 | * MutatingSequencer::getNoteProbability() 879 | * gets the note probability 880 | *---------------------------------------------------------------------------------------------------------- 881 | */ 882 | byte MutatingSequencer::getNoteProbability() 883 | { 884 | return noteProbability; 885 | } 886 | 887 | /*---------------------------------------------------------------------------------------------------------- 888 | * MutatingSequencer::setMutationProbability() 889 | * gets the mutation probability 890 | *---------------------------------------------------------------------------------------------------------- 891 | */ 892 | void MutatingSequencer::setMutationProbability(byte newProbability) 893 | { 894 | if (newProbability >= 0 && newProbability <= 100 && newProbability != mutationProbability) 895 | { 896 | mutationProbability = newProbability; 897 | #ifndef ENABLE_MIDI_OUTPUT 898 | Serial.print(F("mutationProbability=")); 899 | Serial.println(mutationProbability); 900 | #endif 901 | 902 | } 903 | } 904 | 905 | /*---------------------------------------------------------------------------------------------------------- 906 | * MutatingSequencer::getMutationProbability() 907 | * gets the mutation probability 908 | *---------------------------------------------------------------------------------------------------------- 909 | */ 910 | byte MutatingSequencer::getMutationProbability() 911 | { 912 | return mutationProbability; 913 | } 914 | 915 | 916 | 917 | void MutatingSequencer::printParameters() 918 | { 919 | #ifndef ENABLE_MIDI_OUTPUT 920 | 921 | /* 922 | Serial.print(F("Parameters: note prob=")); 923 | Serial.print(noteProbability); 924 | Serial.print(F(", mutate=")); 925 | Serial.print(mutationProbability); 926 | 927 | Serial.print(F(", skip=")); 928 | Serial.print(skipProbability); 929 | Serial.print(F(", tonic=")); 930 | Serial.print(tonicProbability); 931 | Serial.print(F(", rachet=")); 932 | Serial.print(rachetProbability); 933 | Serial.print(F(", shuffle=")); 934 | Serial.print(shufflePct); 935 | 936 | 937 | 938 | Serial.print(F("\n")); 939 | */ 940 | #endif 941 | 942 | } 943 | 944 | 945 | 946 | 947 | 948 | void MutatingSequencer::print() 949 | { 950 | printSequence(); 951 | } 952 | 953 | 954 | void MutatingSequencer::printSequence() 955 | { 956 | #ifndef ENABLE_MIDI_OUTPUT 957 | 958 | for(int i=0; i < sequenceLength; i++) 959 | { 960 | Serial.print(notes[i]); 961 | Serial.print(F(" ")); 962 | } 963 | Serial.print(F("}\n")); 964 | #endif 965 | 966 | } 967 | -------------------------------------------------------------------------------- /Arduino Files/MutantFMSynth/MutantFMSynth.ino: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------------------------------------- 2 | * MutantFMSynth.ino 3 | * 4 | * Main project file for the Mutant FM Synth. 5 | * 6 | * Instantiates all mutant class objects 7 | * Calls the Mozzi audio hook functions 8 | * manages the user interface 9 | * 10 | * Source Code Repository: https://github.com/Meebleeps/MeeBleeps-Freaq-FM-Synth 11 | * Youtube Channel: https://www.youtube.com/channel/UC4I1ExnOpH_GjNtm7ZdWeWA 12 | * 13 | * (C) 2021-2022 Meebleeps 14 | *----------------------------------------------------------------------------------------------------------- 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | 23 | #include "avSource.h" 24 | #include "avSequencerMultiTrack.h" 25 | #include "avMidi.h" 26 | #include "LedMatrix.h" 27 | #include "mutantBitmaps.h" 28 | #include 29 | 30 | #include "MutantFMSynthOptions.h" 31 | 32 | // define the pins 33 | #define PIN_SYNC_IN 8 34 | #define PIN_SYNC_OUT 2 35 | #define TIMER_SYNC_PULSE_OUTPUT_MILLIS 15 36 | 37 | #define PIN_AUDIO_OUT 9 38 | #define PIN_BUTTON0 4 39 | #define PIN_BUTTON1 5 40 | #define PIN_BUTTON2 6 41 | #define PIN_BUTTON3 3 42 | #define PIN_BUTTON4 10 43 | #define PIN_BUTTON5 12 44 | #define MAX_BUTTON_INPUTS 6 45 | 46 | #define SEQUENCER_TRACK_0 0 47 | #define SEQUENCER_TRACK_1 1 48 | #define SEQUENCER_TRACK_0_DISPLAY_ROW_0 4 49 | #define SEQUENCER_TRACK_0_DISPLAY_ROW_1 5 50 | #define SEQUENCER_TRACK_1_DISPLAY_ROW_0 6 51 | #define SEQUENCER_TRACK_1_DISPLAY_ROW_1 7 52 | #define LFO_TRACK_0_DISPLAY_ROW 2 53 | #define LFO_TRACK_1_DISPLAY_ROW 2 54 | #define TRIGGER_DISPLAY_ROW 0 55 | #define TRIGGER_DISPLAY_COL 7 56 | #define CURRENT_VOICE_DISPLAY_ROW 1 57 | 58 | #define MAX_ANALOG_INPUTS 8 59 | #define MAX_ANALOG_VALUE 1023 60 | 61 | #define ANALOG_INPUT_MOD_AMOUNT 7 62 | #define ANALOG_INPUT_DECAY 4 63 | #define ANALOG_INPUT_MUTATION 0 64 | #define ANALOG_INPUT_LFO 1 65 | #define ANALOG_INPUT_MOD_RATIO 6 66 | #define ANALOG_INPUT_STEPCOUNT 2 67 | #define ANALOG_INPUT_MOD_ENVELOPE1 5 68 | #define ANALOG_INPUT_MOD_ENVELOPE2 3 69 | 70 | #define ANALOG_INPUT_MOVEMENT_THRESHOLD 5 71 | 72 | // listed in order of left to right. 73 | #define BUTTON_INPUT_FUNC 4 74 | #define BUTTON_INPUT_TONIC 5 75 | #define BUTTON_INPUT_SCALE 2 76 | #define BUTTON_INPUT_START 3 77 | #define BUTTON_INPUT_REC 1 78 | #define BUTTON_INPUT_VOICE 0 79 | #define MAX_OSCILLATOR_MODES 1 80 | 81 | #define INTERFACE_MODE_NORMAL 0 82 | #define INTERFACE_MODE_SHIFT 1 83 | 84 | #define DISPLAY_SETTING_CHANGE_PERSIST_MILLIS 350 85 | #define DISPLAY_SETTING_INTENSITY 4 86 | 87 | #define MOTION_RECORD_NONE 0 88 | #define MOTION_RECORD_REC 1 89 | #define MOTION_RECORD_CLEAR 2 90 | 91 | // MOZZI variables 92 | // original had at 256 but as CPU got tight had to reduce it 93 | // needs to be at least 128. 64Hz means incoming sync pulses are regularly missed between updates. 94 | #define CONTROL_RATE 128 95 | 96 | // todo: decrease INTERFACE_UPDATE_DIVIDER if controls are externally modulated via CV voltage inputs 97 | #define INTERFACE_UPDATE_DIVIDER_ANALOG 5 98 | #define INTERFACE_UPDATE_DIVIDER_DIGITAL 7 99 | #define INTERFACE_UPDATE_DIVIDER_LFO 2 100 | #define INTERFACE_UPDATE_DIVIDER_DISPLAY 32 101 | 102 | 103 | byte firstTimeStart = true; 104 | byte iTrigger = 1; 105 | byte iLastTrigger = 0; 106 | byte interfaceMode = INTERFACE_MODE_NORMAL; 107 | byte controlSynthVoice = 0; 108 | byte motionRecordMode = MOTION_RECORD_NONE; 109 | 110 | int iLastAnalogValue[MAX_ANALOG_INPUTS] = {0,0,0,0,0,0,0,0}; 111 | int iCurrentAnalogValue[MAX_ANALOG_INPUTS] = {0,0,0,0,0,0,0,0}; 112 | 113 | // save space for digital inputs - use a bit rather than a byte per button 114 | uint8_t bitsLastButton; 115 | 116 | // save space for digital inputs - use a bit rather than a byte per button 117 | uint8_t bitsCurrentButton; 118 | 119 | // save space for param lock flags - use a bit rather than a byte per param 120 | uint8_t bitsLastParamLock; 121 | 122 | // time since the last updateAudio() 123 | uint32_t lastUpdateMicros; 124 | 125 | // used to divide the calls to updateControl to spread out control reads and save cpu cycles 126 | uint8_t updateCounter = 0; 127 | 128 | 129 | 130 | 131 | // voice 1 instance 132 | MutatingFM voice0; 133 | 134 | // voice 2 instance 135 | MutatingFM voice1; 136 | 137 | // array of pointers to the MutatingFM instances to simplfy the code 138 | MutatingFM* voices[2]; 139 | 140 | // MAX7219 display matrix interface class 141 | LedMatrix ledDisplay; 142 | 143 | // timer to pull sync output low at end of pulse 144 | EventDelay syncOutputTimer; 145 | 146 | // timer to prevent update of the display while a settings icon is being displayed 147 | EventDelay settingDisplayTimer; 148 | 149 | // the sequencer 150 | MutatingSequencerMultiTrack sequencer; 151 | 152 | 153 | 154 | 155 | 156 | /*---------------------------------------------------------------------------------------------------------- 157 | * setup() 158 | *---------------------------------------------------------------------------------------------------------- 159 | */ 160 | void setup() 161 | { 162 | #ifdef ENABLE_MIDI_OUTPUT 163 | Serial.begin(31250); 164 | #else 165 | Serial.begin(115200); 166 | Serial.print(F("\n\n\n\n\n-----------------------------------------------------------------------\n")); 167 | Serial.print(F("Freaq - Mozzi-based Mutating FM Synth. Build ")); 168 | Serial.print (__DATE__); 169 | Serial.print (F(" ")); 170 | Serial.println (__TIME__); 171 | #endif 172 | 173 | initialisePins(); 174 | initialiseDisplay(); 175 | initialiseSources(); 176 | initialiseSequencer(); 177 | 178 | startMozzi(CONTROL_RATE); 179 | } 180 | 181 | 182 | /*---------------------------------------------------------------------------------------------------------- 183 | * debugPrintMemoryUsage 184 | * does nothing now. used while optimising memory usage 185 | *---------------------------------------------------------------------------------------------------------- 186 | */ 187 | void debugPrintMemoryUsage() 188 | { 189 | /* 190 | debugWriteValue("sizeof(synthVoice)", sizeof(synthVoice)); 191 | debugWriteValue("sizeof(sequencer)", sizeof(sequencer)); 192 | */ 193 | 194 | } 195 | 196 | 197 | /*---------------------------------------------------------------------------------------------------------- 198 | * initialiseDisplay 199 | *---------------------------------------------------------------------------------------------------------- 200 | */ 201 | void initialiseDisplay() 202 | { 203 | ledDisplay.initialise(); 204 | ledDisplay.setOrientation(LEDMATRIX_ORIENTATION_0); 205 | 206 | settingDisplayTimer.start(0); 207 | 208 | 209 | // display logo 210 | for (uint8_t i = 10; i < 100; i += 10) 211 | { 212 | ledDisplay.clearScreen(); 213 | delay(i); 214 | displaySettingIcon(BITMAP_MEEBLEEPS); 215 | delay(i); 216 | } 217 | 218 | //fade logo to target intensity 219 | for(int i = 15; i>= DISPLAY_SETTING_INTENSITY; i--) 220 | { 221 | ledDisplay.setIntensity(i); 222 | 223 | delay(20); 224 | } 225 | 226 | // ledDisplay.setIntensity(DISPLAY_SETTING_INTENSITY); 227 | // displaySettingIcon(BITMAP_MEEBLEEPS); 228 | 229 | #ifndef ENABLE_MIDI_OUTPUT 230 | Serial.println(F("initialiseDisplay() complete")); 231 | #endif 232 | } 233 | 234 | 235 | 236 | 237 | /*---------------------------------------------------------------------------------------------------------- 238 | * initialisePins 239 | *---------------------------------------------------------------------------------------------------------- 240 | */ 241 | void initialisePins() 242 | { 243 | #ifndef ENABLE_MIDI_OUTPUT 244 | Serial.println(F("initialisePins()")); 245 | #endif 246 | 247 | pinMode(PIN_SYNC_IN, INPUT); // sync is pulled down by external pulldown resistor 248 | pinMode(PIN_SYNC_OUT, OUTPUT); 249 | pinMode(PIN_BUTTON0, INPUT_PULLUP); // all other buttons are pulled up by internal pullup resistor 250 | pinMode(PIN_BUTTON1, INPUT_PULLUP); 251 | pinMode(PIN_BUTTON2, INPUT_PULLUP); 252 | pinMode(PIN_BUTTON3, INPUT_PULLUP); 253 | pinMode(PIN_BUTTON4, INPUT_PULLUP); 254 | pinMode(PIN_BUTTON5, INPUT_PULLUP); 255 | 256 | pinMode(A0, INPUT); 257 | pinMode(A1, INPUT); 258 | pinMode(A2, INPUT); 259 | pinMode(A3, INPUT); 260 | pinMode(A4, INPUT); 261 | pinMode(A5, INPUT); 262 | pinMode(A6, INPUT); 263 | pinMode(A7, INPUT); 264 | 265 | // initialise 266 | bitsLastButton = 0; 267 | bitsCurrentButton = 0; 268 | 269 | for (uint8_t i = 0; i < MAX_ANALOG_INPUTS; i++) 270 | { 271 | iLastAnalogValue[i] = 0; 272 | } 273 | } 274 | 275 | 276 | 277 | /*---------------------------------------------------------------------------------------------------------- 278 | * initialiseSources 279 | *---------------------------------------------------------------------------------------------------------- 280 | */ 281 | void initialiseSources() 282 | { 283 | voice0.setOscillator(0); 284 | voice1.setOscillator(1); 285 | 286 | voices[0] = &voice0; 287 | voices[1] = &voice1; 288 | } 289 | 290 | 291 | 292 | /*---------------------------------------------------------------------------------------------------------- 293 | * initialiseSequencer 294 | *---------------------------------------------------------------------------------------------------------- 295 | */ 296 | void initialiseSequencer() 297 | { 298 | sequencer.setScale(SCALEMODE_MINOR); 299 | sequencer.newSequence(16); 300 | } 301 | 302 | 303 | 304 | 305 | /*---------------------------------------------------------------------------------------------------------- 306 | * updateControl 307 | * called by Mozzi Library on CONTROL_RATE frequency 308 | * spreads out control logic updates so that we don't bog down the CPU 309 | * 310 | * every step - check for sync trigger and update sequencer 311 | * if this gets delayed, note on/off commands will drift 312 | *---------------------------------------------------------------------------------------------------------- 313 | */ 314 | void updateControl() 315 | { 316 | uint8_t doDisplayUpdate = false; 317 | 318 | lastUpdateMicros = micros(); 319 | updateCounter++; 320 | 321 | 322 | 323 | // check for incoming sync trigger and if necessary update output sync 324 | // do every update to ensure minimum sync jitter 325 | updateSyncTrigger(); 326 | 327 | // update sequencer returns true if the sequencer has moved to next step 328 | if (updateSequencer()) 329 | { 330 | 331 | // check to see if sequencer should update the output sync pulse 332 | if (sequencer.outputSyncPulse()) 333 | { 334 | outputSyncPulse(); 335 | } 336 | 337 | //update the display once per sequencer step 338 | // but do the display update at the end of updateControl so that any latency is introduced after all critical functions are processed 339 | 340 | doDisplayUpdate = true; 341 | } 342 | // check controls once every INTERFACE_UPDATE_DIVIDER steps for efficiency 343 | // don't update these if the sequencer has updated as that is expensive 344 | else if(updateCounter % INTERFACE_UPDATE_DIVIDER_ANALOG == 0) 345 | { 346 | // now check analog controls 347 | updateAnalogControls(); 348 | 349 | } 350 | // never check both analog and digital controls in the same step to causing buffer underflows 351 | else if(updateCounter % INTERFACE_UPDATE_DIVIDER_DIGITAL == 0) 352 | { 353 | // check button controls first to ensure interface mode is correctly set 354 | updateButtonControls(); 355 | 356 | } 357 | else if(updateCounter % INTERFACE_UPDATE_DIVIDER_LFO == 0) 358 | { 359 | //update display of LFO modulation at higher rate than rest of display 360 | updateLFOModulationDisplay(); 361 | } 362 | else 363 | { 364 | doDisplayUpdate = (updateCounter % INTERFACE_UPDATE_DIVIDER_DISPLAY == 0); 365 | } 366 | 367 | #ifndef ENABLE_MIDI_OUTPUT 368 | //Serial.print(micros() - lastUpdateMicros); 369 | //Serial.print(F(",")); 370 | #endif 371 | 372 | // now that all controls are updated, update the source. 373 | 374 | voices[0]->updateControl(); 375 | voices[1]->updateControl(); 376 | 377 | #ifndef ENABLE_MIDI_OUTPUT 378 | /* 379 | Serial.print(micros() - lastUpdateMicros); 380 | Serial.print(F(",")); 381 | Serial.print(updateCounter % INTERFACE_UPDATE_DIVIDER_DIGITAL); 382 | Serial.print(F(",")); 383 | Serial.print(updateCounter % INTERFACE_UPDATE_DIVIDER_ANALOG); 384 | Serial.print(F(",")); 385 | Serial.print(sequenceUpdated); 386 | Serial.println(); 387 | */ 388 | #endif 389 | 390 | // do the display update last so that any latency is introduced after the notes are updated 391 | if (doDisplayUpdate) 392 | { 393 | updateDisplay(); 394 | } 395 | 396 | } 397 | 398 | 399 | 400 | /*---------------------------------------------------------------------------------------------------------- 401 | * updateLFOModulationDisplay 402 | * displays the current position of the 2 LFOs using 4 LEDs each 403 | *---------------------------------------------------------------------------------------------------------- 404 | */ 405 | void updateLFOModulationDisplay() 406 | { 407 | if (!firstTimeStart && settingDisplayTimer.ready()) 408 | { 409 | // divide LFO value of 0-255 to range 0-3 by right-shift 6 bits, then right-shift 128 by that value to get the correct pixel bitfield 410 | // originally used floating point maths - very slow. 411 | ledDisplay.setRowPixels(LFO_TRACK_0_DISPLAY_ROW, (128 >> (voice0.getLFOValue() >> 6)) | (8 >> (voice1.getLFOValue() >> 6))); 412 | 413 | ledDisplay.refresh(); 414 | } 415 | } 416 | 417 | 418 | 419 | /*---------------------------------------------------------------------------------------------------------- 420 | * updateSequencer 421 | * updates sequencer 422 | * returns true if the sequencer advances a step 423 | *---------------------------------------------------------------------------------------------------------- 424 | */ 425 | int updateSequencer() 426 | { 427 | byte nextNote[MAX_SEQUENCER_TRACKS]; 428 | uint16_t nextNoteLength; 429 | 430 | // if the sequencer is due to make a new step, 431 | if (sequencer.update(false)) 432 | { 433 | nextNoteLength = sequencer.getNextNoteLength(); 434 | 435 | for (uint8_t i=0; i 0) 440 | { 441 | //todo: find way to extend param locks to channel 2? 442 | if (i==0) 443 | { 444 | getParameterLocks(); 445 | } 446 | 447 | voices[i]->noteOn(nextNote[i], 255, nextNoteLength); 448 | 449 | } 450 | } 451 | #ifdef ENABLE_MIDI_OUTPUT 452 | //midiNoteOn(1,nextNote[0],127); 453 | if (nextNote[0]) 454 | { 455 | Serial.write(0x90); 456 | Serial.write(nextNote[0]-24); 457 | Serial.write(0x45); 458 | } 459 | #else 460 | 461 | #endif 462 | 463 | 464 | return true; 465 | } 466 | else 467 | { 468 | return false; 469 | } 470 | 471 | 472 | } 473 | 474 | 475 | 476 | /*---------------------------------------------------------------------------------------------------------- 477 | * outputSyncPulse 478 | * sends a digital signal to the output pin and sets the timer to pull it low after TIMER_SYNC_PULSE_OUTPUT_MILLIS 479 | *---------------------------------------------------------------------------------------------------------- 480 | */ 481 | void outputSyncPulse() 482 | { 483 | /* 484 | DEBUG only 485 | static uint32_t lastSyncOutTimeMicros; 486 | static uint32_t thisSyncOutTimeMicros; 487 | 488 | thisSyncOutTimeMicros = mozziMicros(); 489 | Serial.print(F("lastSyncOutTimeMicros = ")); 490 | Serial.println(thisSyncOutTimeMicros - lastSyncOutTimeMicros); 491 | lastSyncOutTimeMicros = thisSyncOutTimeMicros; 492 | */ 493 | 494 | syncOutputTimer.start(TIMER_SYNC_PULSE_OUTPUT_MILLIS); 495 | digitalWrite(PIN_SYNC_OUT, HIGH); 496 | } 497 | 498 | 499 | /*---------------------------------------------------------------------------------------------------------- 500 | * getParameterLocks 501 | * updates source parameters based on stored modulation sequence 502 | * parameter locks are only available for first track only. 503 | *---------------------------------------------------------------------------------------------------------- 504 | */ 505 | void getParameterLocks() 506 | { 507 | uint16_t thisParamLock; 508 | uint8_t thisStep; 509 | int8_t synthParamIndex; 510 | 511 | // parameters are recorded on the longest sequence but only applied to track 1 voice 512 | // this way if track 1 is 5 steps but track 2 is 16 steps, the automation will be 16 steps long 513 | if (sequencer.getSequenceLength(SEQUENCER_TRACK_1) > sequencer.getSequenceLength(SEQUENCER_TRACK_0)) 514 | { 515 | thisStep = sequencer.getCurrentStep(SEQUENCER_TRACK_1); 516 | } 517 | else 518 | { 519 | thisStep = sequencer.getCurrentStep(SEQUENCER_TRACK_0); 520 | } 521 | 522 | for (uint8_t paramIndex = 0; paramIndex < MAX_PARAMETER_LOCKS; paramIndex++) 523 | { 524 | thisParamLock = sequencer.getParameterLock(paramIndex, SEQUENCER_TRACK_0, thisStep); 525 | 526 | if (thisParamLock != 0) 527 | { 528 | #ifndef ENABLE_MIDI_OUTPUT 529 | 530 | /* 531 | Serial.print(F("parameter lock for channel ")); 532 | Serial.print(SEQUENCER_TRACK_0); 533 | Serial.print(F(" parameter ")); 534 | Serial.print(paramIndex); 535 | Serial.print(F(" value ")); 536 | Serial.println(thisParamLock); 537 | */ 538 | #endif 539 | 540 | // set the flag for this input - last parameter was a lock 541 | bitsLastParamLock |= 1 << paramIndex; 542 | } 543 | else 544 | { 545 | // if the last step was a parameter lock but this step doesn't have one, set the parameter lock to the current knob position 546 | if ((bitsLastParamLock >> paramIndex) & 1) 547 | { 548 | #ifndef ENABLE_MIDI_OUTPUT 549 | 550 | /* 551 | Serial.print(F("clearing last parameter lock for channel ")); 552 | Serial.print(SEQUENCER_TRACK_0); 553 | Serial.print(F(" parameter ")); 554 | Serial.print(paramIndex); 555 | Serial.print(F(" knob value ")); 556 | Serial.println(iCurrentAnalogValue[getParameterLockControl(paramIndex)]); 557 | */ 558 | #endif 559 | thisParamLock = iCurrentAnalogValue[getParameterLockControl(paramIndex)]; 560 | } 561 | 562 | // reset the lock bitflag for this parameter 563 | bitsLastParamLock &= ~(1 << paramIndex); 564 | 565 | } 566 | 567 | // if there is a parameter lock or we are recovering from a previous step parameter lock 568 | if (thisParamLock != 0) 569 | { 570 | synthParamIndex = getParameterLockSynthParam(paramIndex); 571 | 572 | if (synthParamIndex == -2) 573 | { 574 | sequencer.setNextNoteLength(thisParamLock); 575 | } 576 | else if (synthParamIndex >= 0) 577 | { 578 | voices[SEQUENCER_TRACK_0]->setParam(synthParamIndex, thisParamLock); 579 | } 580 | } 581 | //} 582 | } 583 | 584 | } 585 | 586 | 587 | 588 | /*---------------------------------------------------------------------------------------------------------- 589 | * setParameterLock 590 | * saves the given parameter value onto a modulation channel 591 | *---------------------------------------------------------------------------------------------------------- 592 | */ 593 | inline void setParameterLock(int8_t paramChannel, uint16_t value) 594 | { 595 | switch (motionRecordMode) 596 | { 597 | // 14/02/22: moved this here as is the most common case, assuming no branch prediction on arduion platforms 598 | case MOTION_RECORD_NONE: 599 | // do nothing 600 | break; 601 | 602 | case MOTION_RECORD_REC: 603 | sequencer.setParameterLock(paramChannel, value); 604 | #ifndef ENABLE_MIDI_OUTPUT 605 | //Serial.println(F("setParameterLock(0)")); 606 | #endif 607 | break; 608 | 609 | case MOTION_RECORD_CLEAR: 610 | sequencer.clearAllParameterLocks(paramChannel); 611 | #ifndef ENABLE_MIDI_OUTPUT 612 | //Serial.println(F("Clear ParameterLock(0)")); 613 | #endif 614 | break; 615 | 616 | } 617 | } 618 | 619 | 620 | 621 | /*---------------------------------------------------------------------------------------------------------- 622 | * getParameterLockChannel 623 | * returns the sequencer modulation channel for a given analog control index 624 | * 625 | * These are a bit of a kludge - would be better as a lookup table. 626 | *---------------------------------------------------------------------------------------------------------- 627 | */ 628 | inline int8_t getParameterLockChannel(uint8_t analogControlIndex) 629 | { 630 | switch(analogControlIndex) 631 | { 632 | case ANALOG_INPUT_MOD_AMOUNT: return PARAM_LOCK_CHANNEL_0; 633 | case ANALOG_INPUT_DECAY: return PARAM_LOCK_CHANNEL_1; 634 | case ANALOG_INPUT_MOD_RATIO: return PARAM_LOCK_CHANNEL_2; 635 | case ANALOG_INPUT_MOD_ENVELOPE1: return PARAM_LOCK_CHANNEL_3; 636 | case ANALOG_INPUT_MOD_ENVELOPE2: return PARAM_LOCK_CHANNEL_4; 637 | case ANALOG_INPUT_LFO: return PARAM_LOCK_CHANNEL_5; 638 | default: return -1; 639 | } 640 | } 641 | 642 | 643 | /*---------------------------------------------------------------------------------------------------------- 644 | * getParameterLockControl 645 | * returns the analog control index for a given sequencer modulation channel 646 | *---------------------------------------------------------------------------------------------------------- 647 | */ 648 | inline int8_t getParameterLockControl(uint8_t paramChannelIndex) 649 | { 650 | switch(paramChannelIndex) 651 | { 652 | case PARAM_LOCK_CHANNEL_0: return ANALOG_INPUT_MOD_AMOUNT; 653 | case PARAM_LOCK_CHANNEL_1: return ANALOG_INPUT_DECAY; 654 | case PARAM_LOCK_CHANNEL_2: return ANALOG_INPUT_MOD_RATIO; 655 | case PARAM_LOCK_CHANNEL_3: return ANALOG_INPUT_MOD_ENVELOPE1; 656 | case PARAM_LOCK_CHANNEL_4: return ANALOG_INPUT_MOD_ENVELOPE2; 657 | case PARAM_LOCK_CHANNEL_5: return ANALOG_INPUT_LFO; 658 | default: return -1; 659 | } 660 | } 661 | 662 | 663 | /*---------------------------------------------------------------------------------------------------------- 664 | * getParameterLockSynthParam 665 | * returns the sytnh parameter for a given sequencer modulation channel 666 | *---------------------------------------------------------------------------------------------------------- 667 | */ 668 | inline int8_t getParameterLockSynthParam(uint8_t paramChannelIndex) 669 | { 670 | switch(paramChannelIndex) 671 | { 672 | case PARAM_LOCK_CHANNEL_0: return SYNTH_PARAMETER_MOD_AMOUNT; 673 | case PARAM_LOCK_CHANNEL_1: return SYNTH_PARAMETER_NOTE_DECAY; 674 | case PARAM_LOCK_CHANNEL_2: return SYNTH_PARAMETER_MOD_RATIO; 675 | case PARAM_LOCK_CHANNEL_3: return SYNTH_PARAMETER_ENVELOPE_DECAY; 676 | case PARAM_LOCK_CHANNEL_4: return SYNTH_PARAMETER_ENVELOPE_ATTACK; 677 | case PARAM_LOCK_CHANNEL_5: return SYNTH_PARAMETER_MOD_AMOUNT_LFODEPTH; 678 | default: return SYNTH_PARAMETER_UNKNOWN; 679 | } 680 | } 681 | 682 | 683 | 684 | 685 | 686 | 687 | /*---------------------------------------------------------------------------------------------------------- 688 | * updateSyncTrigger 689 | * check for incoming sync trigger and update sequencer 690 | * also check to see if output sync trigger needs to be pulled low 691 | *---------------------------------------------------------------------------------------------------------- 692 | */ 693 | void updateSyncTrigger() 694 | { 695 | iTrigger = digitalRead(PIN_SYNC_IN); // read the sync pin 696 | if (iTrigger != iLastTrigger) 697 | { 698 | digitalWrite(PIN_SYNC_OUT, iTrigger); 699 | 700 | //trigger note on or off 701 | if (iTrigger == HIGH) 702 | { 703 | #ifndef ENABLE_MIDI_OUTPUT 704 | //Serial.println("sync!"); 705 | #endif 706 | sequencer.syncPulse(SYNC_STEPS_PER_PULSE); 707 | } 708 | 709 | iLastTrigger = iTrigger; 710 | } 711 | 712 | // check to see if the output sync pulse needs to be pulled low 713 | if (syncOutputTimer.ready()) 714 | { 715 | digitalWrite(PIN_SYNC_OUT, LOW); 716 | } 717 | 718 | } 719 | 720 | 721 | /*---------------------------------------------------------------------------------------------------------- 722 | * getLastButtonState 723 | * returns the last state for the given button 724 | * uses a bitfield to compress 725 | *---------------------------------------------------------------------------------------------------------- 726 | */ 727 | inline uint8_t getLastButtonState(uint8_t buttonIndex) 728 | { 729 | return (bitsLastButton >> buttonIndex) & 1; 730 | } 731 | 732 | /*---------------------------------------------------------------------------------------------------------- 733 | * getCurrentButtonState 734 | * returns the current state for the given button 735 | *---------------------------------------------------------------------------------------------------------- 736 | */ 737 | inline uint8_t getCurrentButtonState(uint8_t buttonIndex) 738 | { 739 | return (bitsCurrentButton >> buttonIndex) & 1; 740 | } 741 | 742 | /*---------------------------------------------------------------------------------------------------------- 743 | * setLastButtonState 744 | * sets the last state for the given button 745 | *---------------------------------------------------------------------------------------------------------- 746 | */ 747 | inline void setLastButtonState(uint8_t buttonIndex, uint8_t value) 748 | { 749 | if (value) 750 | { 751 | bitsLastButton |= 1 << buttonIndex; 752 | } 753 | else 754 | { 755 | bitsLastButton &= ~(1 << buttonIndex); 756 | } 757 | } 758 | 759 | 760 | /*---------------------------------------------------------------------------------------------------------- 761 | * setCurrentButtonState 762 | * sets the current state for the given button 763 | *---------------------------------------------------------------------------------------------------------- 764 | */ 765 | inline void setCurrentButtonState(uint8_t buttonIndex, uint8_t value) 766 | { 767 | if (value) 768 | { 769 | bitsCurrentButton |= 1 << buttonIndex; 770 | } 771 | else 772 | { 773 | bitsCurrentButton &= ~(1 << buttonIndex); 774 | } 775 | } 776 | 777 | 778 | /*---------------------------------------------------------------------------------------------------------- 779 | * updateButtonControls 780 | * check for button presses 781 | *---------------------------------------------------------------------------------------------------------- 782 | */ 783 | void updateButtonControls() 784 | { 785 | // IMPORTANT: 786 | // These calls assume you are using NORMALLY CLOSED switches, which is what I used in the build 787 | // if your switches are NORMALLY OPEN delete the definition of SWITCH_TYPE_NORMALLY_CLOSED in MutantFMSynthOptions.h 788 | 789 | #ifdef SWITCH_TYPE_NORMALLY_CLOSED 790 | setCurrentButtonState(0,digitalRead(PIN_BUTTON0)); 791 | setCurrentButtonState(1,digitalRead(PIN_BUTTON1)); 792 | setCurrentButtonState(2,digitalRead(PIN_BUTTON2)); 793 | setCurrentButtonState(3,digitalRead(PIN_BUTTON3)); 794 | setCurrentButtonState(4,digitalRead(PIN_BUTTON4)); 795 | setCurrentButtonState(5,digitalRead(PIN_BUTTON5)); 796 | #else 797 | setCurrentButtonState(0, !digitalRead(PIN_BUTTON0)); 798 | setCurrentButtonState(1, !digitalRead(PIN_BUTTON1)); 799 | setCurrentButtonState(2, !digitalRead(PIN_BUTTON2)); 800 | setCurrentButtonState(3, !digitalRead(PIN_BUTTON3)); 801 | setCurrentButtonState(4, !digitalRead(PIN_BUTTON4)); 802 | setCurrentButtonState(5, !digitalRead(PIN_BUTTON5)); 803 | #endif 804 | 805 | // TODO: increase efficiency - only execute this entire block if at least one button is pressed, which is bitsCurrentButton != 0 806 | 807 | // if func button is not pressed, all UI controls are normal 808 | if (getCurrentButtonState(BUTTON_INPUT_FUNC) != getLastButtonState(BUTTON_INPUT_FUNC)) 809 | { 810 | if(getCurrentButtonState(BUTTON_INPUT_FUNC) == LOW) 811 | { 812 | interfaceMode = INTERFACE_MODE_NORMAL; 813 | } 814 | else 815 | { 816 | interfaceMode = INTERFACE_MODE_SHIFT; 817 | } 818 | #ifndef ENABLE_MIDI_OUTPUT 819 | Serial.print(interfaceMode); 820 | #endif 821 | } 822 | 823 | 824 | if (getCurrentButtonState(BUTTON_INPUT_REC) != getLastButtonState(BUTTON_INPUT_REC)) 825 | { 826 | if (getCurrentButtonState(BUTTON_INPUT_REC) == LOW) 827 | { 828 | motionRecordMode = MOTION_RECORD_NONE; 829 | } 830 | else 831 | { 832 | switch(interfaceMode) 833 | { 834 | case INTERFACE_MODE_NORMAL: 835 | motionRecordMode = MOTION_RECORD_REC; 836 | break; 837 | 838 | case INTERFACE_MODE_SHIFT: 839 | motionRecordMode = MOTION_RECORD_CLEAR; 840 | break; 841 | } 842 | } 843 | #ifndef ENABLE_MIDI_OUTPUT 844 | Serial.print(F("motionRecordMode=")); 845 | Serial.println(motionRecordMode); 846 | #endif 847 | } 848 | 849 | if (getCurrentButtonState(BUTTON_INPUT_VOICE) != getLastButtonState(BUTTON_INPUT_VOICE)) 850 | { 851 | switch(interfaceMode) 852 | { 853 | case INTERFACE_MODE_NORMAL: 854 | if (getCurrentButtonState(BUTTON_INPUT_VOICE) == HIGH) 855 | { 856 | updateSynthControl(); 857 | } 858 | break; 859 | 860 | case INTERFACE_MODE_SHIFT: 861 | if (getCurrentButtonState(BUTTON_INPUT_VOICE) == HIGH) 862 | { 863 | if (getCurrentButtonState(BUTTON_INPUT_REC) == HIGH) 864 | { 865 | // if user if holding down FUNC & REC when they hit VOICE, then change the waveform type for the current voice carrier 866 | voices[controlSynthVoice]->toggleCarrierWaveform(); 867 | displaySettingIcon(BITMAP_WAVEFORMS[voices[controlSynthVoice]->getCarrierWaveform()]); 868 | } 869 | else 870 | { 871 | voices[controlSynthVoice]->toggleFMMode(); 872 | //todo: display icon for current FM mode 873 | displaySettingIcon(BITMAP_FMMODE[voices[controlSynthVoice]->getFMMode()]); 874 | } 875 | } 876 | 877 | break; 878 | } 879 | } 880 | 881 | if (getCurrentButtonState(BUTTON_INPUT_START) != getLastButtonState(BUTTON_INPUT_START) && getCurrentButtonState(BUTTON_INPUT_START) == HIGH) 882 | { 883 | switch(interfaceMode) 884 | { 885 | case INTERFACE_MODE_NORMAL: 886 | startStopSequencer(); 887 | break; 888 | case INTERFACE_MODE_SHIFT: 889 | if (getCurrentButtonState(BUTTON_INPUT_REC) == HIGH) 890 | { 891 | // if user if holding down FUNC & REC when they hit START, then change the waveform type for the current voice MODULATOR 892 | voices[controlSynthVoice]->toggleModulatorWaveform(); 893 | displaySettingIcon(BITMAP_WAVEFORMS[voices[controlSynthVoice]->getModulatorWaveform()]); 894 | } 895 | else 896 | { 897 | // send tap tempo message to the sequencer 898 | sequencer.syncPulse(SYNC_STEPS_PER_TAP); 899 | } 900 | break; 901 | } 902 | } 903 | 904 | if (getCurrentButtonState(BUTTON_INPUT_TONIC) != getLastButtonState(BUTTON_INPUT_TONIC) && getCurrentButtonState(BUTTON_INPUT_TONIC) == HIGH) 905 | { 906 | switch(interfaceMode) 907 | { 908 | case INTERFACE_MODE_NORMAL: 909 | updateTonic(1); 910 | break; 911 | 912 | case INTERFACE_MODE_SHIFT: 913 | if (getCurrentButtonState(BUTTON_INPUT_REC) == HIGH) 914 | { 915 | // TODO: if user if holding down FUNC & REC when they hit TONIC, then change the octave of the current voice only 916 | sequencer.setOctaveOffsetTrack1((sequencer.getOctaveOffsetTrack1() + 1 ) % 4); 917 | displaySettingIcon(BITMAP_NUMERALS[sequencer.getOctaveOffsetTrack1()] ); 918 | } 919 | else 920 | { 921 | sequencer.setOctave((sequencer.getOctave() + 1) % 7); 922 | displayTonicIcon(); 923 | } 924 | break; 925 | } 926 | } 927 | 928 | if (getCurrentButtonState(BUTTON_INPUT_SCALE) != getLastButtonState(BUTTON_INPUT_SCALE) && getCurrentButtonState(BUTTON_INPUT_SCALE) == HIGH) 929 | { 930 | switch(interfaceMode) 931 | { 932 | case INTERFACE_MODE_NORMAL: 933 | updateScale(); 934 | break; 935 | 936 | case INTERFACE_MODE_SHIFT: 937 | if (getCurrentButtonState(BUTTON_INPUT_REC) == HIGH) 938 | { 939 | // if user if holding down FUNC & REC when they hit SCALE, then change LFO mode 940 | voices[controlSynthVoice]->toggleLFOWaveform(); 941 | displaySettingIcon(BITMAP_WAVEFORMS[voices[controlSynthVoice]->getLFOWaveform()]); 942 | 943 | } 944 | else 945 | { 946 | updateAlgorithm(); 947 | } 948 | break; 949 | } 950 | } 951 | 952 | /* 953 | DEBUG ONLY 954 | for (uint8_t i=0; isetGain(iCurrentAnalogValue[ANALOG_INPUT_DECAY] >> 2); 1097 | 1098 | } 1099 | // 14/02/22 - moved this from above switch statement as it meant that decay parameter locks weren't getting cleared 1100 | setParameterLock(getParameterLockChannel(ANALOG_INPUT_DECAY), iCurrentAnalogValue[ANALOG_INPUT_DECAY]); 1101 | break; 1102 | 1103 | case ANALOG_INPUT_MOD_AMOUNT: 1104 | 1105 | switch (interfaceMode) 1106 | { 1107 | case INTERFACE_MODE_NORMAL: 1108 | voices[controlSynthVoice]->setParam(SYNTH_PARAMETER_MOD_AMOUNT, iCurrentAnalogValue[ANALOG_INPUT_MOD_AMOUNT]); 1109 | break; 1110 | case INTERFACE_MODE_SHIFT: 1111 | voices[controlSynthVoice]->setParam(SYNTH_PARAMETER_MOD_AMOUNT, iCurrentAnalogValue[ANALOG_INPUT_MOD_AMOUNT]); 1112 | break; 1113 | } 1114 | setParameterLock(getParameterLockChannel(ANALOG_INPUT_MOD_AMOUNT), iCurrentAnalogValue[ANALOG_INPUT_MOD_AMOUNT]); 1115 | 1116 | break; 1117 | 1118 | 1119 | case ANALOG_INPUT_MOD_RATIO: 1120 | 1121 | switch (interfaceMode) 1122 | { 1123 | case INTERFACE_MODE_NORMAL: 1124 | voices[controlSynthVoice]->setParam(SYNTH_PARAMETER_MOD_RATIO, iCurrentAnalogValue[ANALOG_INPUT_MOD_RATIO]); 1125 | break; 1126 | 1127 | case INTERFACE_MODE_SHIFT: 1128 | voices[controlSynthVoice]->setParam(SYNTH_PARAMETER_MOD_RATIO, iCurrentAnalogValue[ANALOG_INPUT_MOD_RATIO]); 1129 | break; 1130 | } 1131 | setParameterLock(getParameterLockChannel(ANALOG_INPUT_MOD_RATIO), iCurrentAnalogValue[ANALOG_INPUT_MOD_RATIO]); 1132 | 1133 | break; 1134 | 1135 | case ANALOG_INPUT_MUTATION: 1136 | 1137 | switch (interfaceMode) 1138 | { 1139 | case INTERFACE_MODE_NORMAL: 1140 | sequencer.setMutationProbability(scaleAnalogInputNonLinear(iCurrentAnalogValue[ANALOG_INPUT_MUTATION],512,20,100)); 1141 | break; 1142 | case INTERFACE_MODE_SHIFT: 1143 | sequencer.setNoteProbability(scaleAnalogInput(iCurrentAnalogValue[ANALOG_INPUT_MUTATION],100)); 1144 | break; 1145 | } 1146 | 1147 | break; 1148 | 1149 | case ANALOG_INPUT_STEPCOUNT: 1150 | switch (interfaceMode) 1151 | { 1152 | case INTERFACE_MODE_NORMAL: 1153 | sequencer.setSequenceLength(controlSynthVoice, scaleAnalogInput(iCurrentAnalogValue[ANALOG_INPUT_STEPCOUNT],16) + 1); 1154 | break; 1155 | 1156 | // if shift, change both sequences to the current knob setting to keep them in sync 1157 | case INTERFACE_MODE_SHIFT: 1158 | sequencer.setSequenceLength(SEQUENCER_TRACK_0, scaleAnalogInput(iCurrentAnalogValue[ANALOG_INPUT_STEPCOUNT],16) + 1); 1159 | sequencer.setSequenceLength(SEQUENCER_TRACK_1, scaleAnalogInput(iCurrentAnalogValue[ANALOG_INPUT_STEPCOUNT],16) + 1); 1160 | break; 1161 | } 1162 | 1163 | 1164 | break; 1165 | 1166 | case ANALOG_INPUT_LFO: 1167 | switch (interfaceMode) 1168 | { 1169 | case INTERFACE_MODE_NORMAL: 1170 | voices[controlSynthVoice]->setParam(SYNTH_PARAMETER_MOD_AMOUNT_LFODEPTH,iCurrentAnalogValue[ANALOG_INPUT_LFO]); 1171 | break; 1172 | case INTERFACE_MODE_SHIFT: 1173 | // set LFO frequency between 0 - 1000Hz 1174 | voices[controlSynthVoice]->setLFOFrequency((float)scaleAnalogInputNonLinear(iCurrentAnalogValue[ANALOG_INPUT_LFO]+1,512,300,3000)/(float)300.0); 1175 | break; 1176 | } 1177 | setParameterLock(getParameterLockChannel(ANALOG_INPUT_LFO), iCurrentAnalogValue[ANALOG_INPUT_LFO]); 1178 | 1179 | break; 1180 | 1181 | 1182 | case ANALOG_INPUT_MOD_ENVELOPE1: 1183 | 1184 | switch (interfaceMode) 1185 | { 1186 | case INTERFACE_MODE_NORMAL: 1187 | voices[controlSynthVoice]->setParam(SYNTH_PARAMETER_ENVELOPE_DECAY, iCurrentAnalogValue[ANALOG_INPUT_MOD_ENVELOPE1]); 1188 | break; 1189 | case INTERFACE_MODE_SHIFT: 1190 | //todo: shift function for decay knob 1191 | break; 1192 | } 1193 | setParameterLock(getParameterLockChannel(ANALOG_INPUT_MOD_ENVELOPE1), iCurrentAnalogValue[ANALOG_INPUT_MOD_ENVELOPE1]); 1194 | 1195 | break; 1196 | 1197 | 1198 | case ANALOG_INPUT_MOD_ENVELOPE2: 1199 | 1200 | switch (interfaceMode) 1201 | { 1202 | case INTERFACE_MODE_NORMAL: 1203 | voices[controlSynthVoice]->setParam(SYNTH_PARAMETER_ENVELOPE_ATTACK, iCurrentAnalogValue[ANALOG_INPUT_MOD_ENVELOPE2]); 1204 | break; 1205 | case INTERFACE_MODE_SHIFT: 1206 | //todo: shift function for attack knob 1207 | break; 1208 | } 1209 | setParameterLock(getParameterLockChannel(ANALOG_INPUT_MOD_ENVELOPE2), iCurrentAnalogValue[ANALOG_INPUT_MOD_ENVELOPE2]); 1210 | 1211 | break; 1212 | 1213 | } 1214 | 1215 | iLastAnalogValue[i] = iCurrentAnalogValue[i]; 1216 | } 1217 | } 1218 | 1219 | } 1220 | 1221 | 1222 | 1223 | /*---------------------------------------------------------------------------------------------------------- 1224 | * updateNoteDecay 1225 | * sets the length of the notes 1226 | *---------------------------------------------------------------------------------------------------------- 1227 | */ 1228 | void updateNoteDecay(bool ignoreRecordMode) 1229 | { 1230 | uint16_t nextNoteLength; 1231 | 1232 | nextNoteLength = scaleAnalogInputNonLinear(iCurrentAnalogValue[ANALOG_INPUT_DECAY], 512, 512, 16384); 1233 | sequencer.setNextNoteLength(nextNoteLength); 1234 | 1235 | } 1236 | 1237 | 1238 | 1239 | /*---------------------------------------------------------------------------------------------------------- 1240 | * updateTonic 1241 | * sets the tonic to one of the natural notes 1242 | *---------------------------------------------------------------------------------------------------------- 1243 | */ 1244 | void updateTonic(int incr) 1245 | { 1246 | int8_t tonicNotes[7] = { 0, 2, 4, 5, 7, 9, 11}; 1247 | byte tonicIndex; 1248 | 1249 | for (uint8_t i = 0; i < 7; i++) 1250 | { 1251 | if(tonicNotes[i] == sequencer.getTonic()) 1252 | { 1253 | tonicIndex = i; 1254 | } 1255 | } 1256 | tonicIndex = (tonicIndex + incr) % 7; 1257 | 1258 | sequencer.setTonic(tonicNotes[tonicIndex]); 1259 | displayTonicIcon(); 1260 | 1261 | } 1262 | 1263 | 1264 | 1265 | /*---------------------------------------------------------------------------------------------------------- 1266 | * getMidiNoteIconIndex 1267 | * returns the icon index for the given midi note (represented as A, B C, etc...) 1268 | *---------------------------------------------------------------------------------------------------------- 1269 | */ 1270 | uint8_t getMidiNoteIconIndex(uint8_t midinote) 1271 | { 1272 | uint8_t basenote; 1273 | basenote = (midinote) % 12; 1274 | 1275 | // todo: fix this 1276 | switch(basenote) 1277 | { 1278 | case 0: return 2; //C 1279 | case 2: return 3; //D 1280 | case 4: return 4; //E 1281 | case 5: return 5; //F 1282 | case 7: return 6; //G 1283 | case 9: return 0; //A 1284 | case 11: return 1; //B 1285 | default: return 0; //A 1286 | } 1287 | } 1288 | 1289 | 1290 | 1291 | 1292 | 1293 | 1294 | 1295 | /*---------------------------------------------------------------------------------------------------------- 1296 | * updateAudio 1297 | * returns the current source audio to be output on pin 9 1298 | * mixes the two voices together with simple addition 1299 | *---------------------------------------------------------------------------------------------------------- 1300 | */ 1301 | int updateAudio() 1302 | { 1303 | return MonoOutput::fromNBit(9, voices[0]->updateAudio() + voices[1]->updateAudio()); 1304 | } 1305 | 1306 | 1307 | 1308 | 1309 | 1310 | /*---------------------------------------------------------------------------------------------------------- 1311 | * updateDisplay 1312 | * updates the matrix display 1313 | *---------------------------------------------------------------------------------------------------------- 1314 | */ 1315 | void updateDisplay() 1316 | { 1317 | byte currentNote[MAX_SEQUENCER_TRACKS]; 1318 | byte currentStep[MAX_SEQUENCER_TRACKS]; 1319 | 1320 | 1321 | if (settingDisplayTimer.ready()) 1322 | { 1323 | currentNote[SEQUENCER_TRACK_0] = sequencer.getCurrentNote(SEQUENCER_TRACK_0); 1324 | currentStep[SEQUENCER_TRACK_0] = sequencer.getCurrentStep(SEQUENCER_TRACK_0); 1325 | currentNote[SEQUENCER_TRACK_1] = sequencer.getCurrentNote(SEQUENCER_TRACK_1); 1326 | currentStep[SEQUENCER_TRACK_1] = sequencer.getCurrentStep(SEQUENCER_TRACK_1); 1327 | 1328 | // set current voice display 1329 | ledDisplay.setRowPixels(CURRENT_VOICE_DISPLAY_ROW,controlSynthVoice == SEQUENCER_TRACK_0 ? 240 : 15); 1330 | 1331 | //blank out row 0 & 3 to clear any old icons - these rows are currently otherwise unused 1332 | ledDisplay.setRowPixels(0, 0); 1333 | ledDisplay.setRowPixels(3, 0); 1334 | 1335 | 1336 | // clear sequencer step rows 1337 | ledDisplay.setRowPixels(SEQUENCER_TRACK_0_DISPLAY_ROW_0, 0); 1338 | ledDisplay.setRowPixels(SEQUENCER_TRACK_0_DISPLAY_ROW_1, 0); 1339 | ledDisplay.setRowPixels(SEQUENCER_TRACK_1_DISPLAY_ROW_0, 0); 1340 | ledDisplay.setRowPixels(SEQUENCER_TRACK_1_DISPLAY_ROW_1, 0); 1341 | 1342 | if(currentStep[SEQUENCER_TRACK_0] < 8) 1343 | { 1344 | ledDisplay.setPixel(currentStep[SEQUENCER_TRACK_0]%8, SEQUENCER_TRACK_0_DISPLAY_ROW_0, (currentNote[SEQUENCER_TRACK_0] > 0)); 1345 | } 1346 | else 1347 | { 1348 | ledDisplay.setPixel(currentStep[SEQUENCER_TRACK_0]%8, SEQUENCER_TRACK_0_DISPLAY_ROW_1, (currentNote[SEQUENCER_TRACK_0] > 0)); 1349 | } 1350 | 1351 | if(currentStep[SEQUENCER_TRACK_1] < 8) 1352 | { 1353 | ledDisplay.setPixel(currentStep[SEQUENCER_TRACK_1]%8, SEQUENCER_TRACK_1_DISPLAY_ROW_0, (currentNote[SEQUENCER_TRACK_1] > 0)); 1354 | } 1355 | else 1356 | { 1357 | ledDisplay.setPixel(currentStep[SEQUENCER_TRACK_1]%8, SEQUENCER_TRACK_1_DISPLAY_ROW_1, (currentNote[SEQUENCER_TRACK_1] > 0)); 1358 | } 1359 | 1360 | //display trigger 1361 | ledDisplay.setPixel(TRIGGER_DISPLAY_COL, TRIGGER_DISPLAY_ROW, iTrigger == HIGH); 1362 | 1363 | displaySequenceLength(); 1364 | 1365 | ledDisplay.refresh(); 1366 | } 1367 | 1368 | } 1369 | 1370 | 1371 | /*---------------------------------------------------------------------------------------------------------- 1372 | * displaySequenceLength 1373 | * displays a pixel indicating the length of each sequence 1374 | *---------------------------------------------------------------------------------------------------------- 1375 | */ 1376 | void displaySequenceLength() 1377 | { 1378 | byte sequenceLength[MAX_SEQUENCER_TRACKS]; 1379 | 1380 | sequenceLength[SEQUENCER_TRACK_0] = sequencer.getSequenceLength(SEQUENCER_TRACK_0); 1381 | sequenceLength[SEQUENCER_TRACK_1] = sequencer.getSequenceLength(SEQUENCER_TRACK_1); 1382 | 1383 | // invert last step in sequence so user can see how long the sequence is 1384 | if(sequenceLength[SEQUENCER_TRACK_0] <= 8) 1385 | { 1386 | ledDisplay.togglePixel((sequenceLength[SEQUENCER_TRACK_0]-1)%8, SEQUENCER_TRACK_0_DISPLAY_ROW_0); 1387 | } 1388 | else if (sequenceLength[SEQUENCER_TRACK_0] > 1) 1389 | { 1390 | ledDisplay.togglePixel((sequenceLength[SEQUENCER_TRACK_0]-1)%8, SEQUENCER_TRACK_0_DISPLAY_ROW_1); 1391 | } 1392 | else 1393 | { 1394 | // if sequence length = 1 then just light step 1 1395 | ledDisplay.setPixel(0, SEQUENCER_TRACK_0_DISPLAY_ROW_0, 1); 1396 | } 1397 | 1398 | // invert last step in sequence so user can see how long the sequence is 1399 | if(sequenceLength[SEQUENCER_TRACK_1] <= 8) 1400 | { 1401 | ledDisplay.togglePixel((sequenceLength[SEQUENCER_TRACK_1]-1)%8, SEQUENCER_TRACK_1_DISPLAY_ROW_0); 1402 | } 1403 | else if (sequenceLength[1] > 1) 1404 | { 1405 | ledDisplay.togglePixel((sequenceLength[SEQUENCER_TRACK_1]-1)%8, SEQUENCER_TRACK_1_DISPLAY_ROW_1); 1406 | } 1407 | else 1408 | { 1409 | // if sequence length = 1 then just light step 1 1410 | ledDisplay.setPixel(0, SEQUENCER_TRACK_1_DISPLAY_ROW_0, 1); 1411 | } 1412 | //ledDisplay.refresh(); 1413 | } 1414 | 1415 | /*---------------------------------------------------------------------------------------------------------- 1416 | * displaySettingIcon 1417 | * copies the bitmap values from program memory then displays the given icon on the screen 1418 | * and sets a timer and a flag for it to be cleared after a set time 1419 | *---------------------------------------------------------------------------------------------------------- 1420 | */ 1421 | void displaySettingIcon(const byte* bitmap) 1422 | { 1423 | byte bitmapRAM[8]; 1424 | 1425 | for (byte i = 0; i < 8; i++) 1426 | { 1427 | bitmapRAM[i] = pgm_read_byte_near(bitmap + i); 1428 | } 1429 | 1430 | ledDisplay.displayIcon(&bitmapRAM[0]); 1431 | settingDisplayTimer.start(DISPLAY_SETTING_CHANGE_PERSIST_MILLIS); 1432 | } 1433 | 1434 | 1435 | 1436 | /*---------------------------------------------------------------------------------------------------------- 1437 | * displayTonicIcon 1438 | * OR's the alpha note name with the numeric octave to create a tonic icon eg G3 1439 | *---------------------------------------------------------------------------------------------------------- 1440 | */ 1441 | void displayTonicIcon() 1442 | { 1443 | byte bitmapRAM[8]; 1444 | const byte* alphaBitmap; 1445 | const byte* octaveBitmap; 1446 | 1447 | octaveBitmap = BITMAP_NUMERALS[sequencer.getOctave()]; 1448 | alphaBitmap = BITMAP_ALPHA[getMidiNoteIconIndex(sequencer.getTonic())]; 1449 | 1450 | for (byte i = 0; i < 8; i++) 1451 | { 1452 | bitmapRAM[i] = pgm_read_byte_near(alphaBitmap + i) | (pgm_read_byte_near(octaveBitmap + i) >> 4); 1453 | } 1454 | 1455 | ledDisplay.displayIcon(&bitmapRAM[0]); 1456 | settingDisplayTimer.start(DISPLAY_SETTING_CHANGE_PERSIST_MILLIS); 1457 | } 1458 | 1459 | 1460 | /*---------------------------------------------------------------------------------------------------------- 1461 | * debugWriteValue 1462 | *---------------------------------------------------------------------------------------------------------- 1463 | */ 1464 | void debugWriteValue(char* valueName, int value) 1465 | { 1466 | #ifndef ENABLE_MIDI_OUTPUT 1467 | Serial.print(valueName); 1468 | Serial.print(F("=")); 1469 | Serial.println(value); 1470 | #endif 1471 | } 1472 | 1473 | 1474 | 1475 | 1476 | 1477 | 1478 | /*---------------------------------------------------------------------------------------------------------- 1479 | * scaleAnalogInput 1480 | * scales an analog input from 0-1023 to 0-maxScale 1481 | * also trims off bottom and top end of range to saturate signal at high and low values 1482 | *---------------------------------------------------------------------------------------------------------- 1483 | */ 1484 | int scaleAnalogInput(int rawValue, int maxScale) 1485 | { 1486 | if (rawValue < 3) 1487 | { 1488 | return 0; 1489 | } 1490 | else if (rawValue > MAX_ANALOG_VALUE) 1491 | { 1492 | return maxScale; 1493 | } 1494 | else 1495 | { 1496 | return ((float)rawValue / MAX_ANALOG_VALUE) * maxScale; 1497 | } 1498 | } 1499 | 1500 | 1501 | 1502 | 1503 | /*---------------------------------------------------------------------------------------------------------- 1504 | * scaleAnalogInput 1505 | * scales an analog input from 0-1023 to 0-maxScale with a non-linear kink at kneeX,kneeY 1506 | * assumes 1000 = max 1507 | * todo: very inefficient - either don't use it or work out a better way to do it. 1508 | *---------------------------------------------------------------------------------------------------------- 1509 | */ 1510 | long scaleAnalogInputNonLinear(long rawValue, long kneeX, long kneeY, long maxScale) 1511 | { 1512 | if (rawValue<=kneeX) 1513 | { 1514 | return rawValue * kneeY / kneeX; 1515 | } 1516 | else 1517 | { 1518 | 1519 | return rawValue * (maxScale-kneeY) / (MAX_ANALOG_VALUE-kneeX) 1520 | - (maxScale-kneeY)*kneeX/(MAX_ANALOG_VALUE-kneeX) + kneeY; 1521 | } 1522 | 1523 | } 1524 | 1525 | 1526 | 1527 | /*---------------------------------------------------------------------------------------------------------- 1528 | * analogInputHasChanged 1529 | * returns true if the given analog input channel has moved by more than the noise threshold 1530 | *---------------------------------------------------------------------------------------------------------- 1531 | */ 1532 | bool analogInputHasChanged(byte inputChannel) 1533 | { 1534 | return abs(iCurrentAnalogValue[inputChannel] - iLastAnalogValue[inputChannel]) > ANALOG_INPUT_MOVEMENT_THRESHOLD; 1535 | } 1536 | 1537 | 1538 | /*---------------------------------------------------------------------------------------------------------- 1539 | * loop 1540 | * calls Mozzi's audioHook() function 1541 | * all other control code moved to updateControls() 1542 | *---------------------------------------------------------------------------------------------------------- 1543 | */ 1544 | 1545 | void loop() 1546 | { 1547 | //required for Mozzi 1548 | audioHook(); 1549 | } 1550 | --------------------------------------------------------------------------------