├── 3D Models ├── 240x320 TFT Standoff.stl ├── 3mm Bicolour LED Standoff.stl ├── Encoder Spacer.stl └── Momentum Case USB C Brass Inserts.stl ├── LICENSE ├── Manual ├── Momentum Schematic V1_1.pdf └── Momentum User Manual V1_2.pdf ├── Momentum ├── Audio.h ├── AudioPatching.h ├── ButtonTool │ ├── Button.h │ ├── ButtonBase.cpp │ ├── ButtonBase.h │ ├── ButtonConfig.h │ ├── ButtonPlex74165.h │ ├── ButtonPlexBase.cpp │ ├── ButtonPlexBase.h │ └── ButtonTool.h ├── Constants.cpp ├── Constants.h ├── Detune.cpp ├── Detune.h ├── Display.h ├── EepromMgr.h ├── EncoderMapping.h ├── EncoderTool │ ├── EncoderBase.cpp │ ├── EncoderBase.h │ ├── EncoderButton.h │ ├── EncoderTool.h │ ├── Multiplexed │ │ ├── EncPlex74165.h │ │ ├── EncPlexBase.cpp │ │ └── EncPlexBase.h │ └── config.h ├── HWControls.h ├── Keyboard.cpp ├── Keyboard.h ├── MidiCC.h ├── Momentum.ino ├── Momentum20pt7b.h ├── MonoNoteHistory.cpp ├── MonoNoteHistory.h ├── Oscilloscope.h ├── Parameters.cpp ├── Parameters.h ├── PatchMgr.h ├── PerformanceMgr.h ├── SequenceMgr.h ├── Sequencer.h ├── Settings.h ├── SettingsService.cpp ├── SettingsService.h ├── StringMapping.h ├── Velocity.cpp ├── Velocity.h ├── Voice.h ├── VoiceGroup.h ├── Yeysk12pt7b.h ├── Yeysk16pt7b.h ├── effect_combine.h ├── effect_ensemble.cpp ├── effect_ensemble.h ├── effect_envelope.cpp ├── effect_envelope.h ├── filter_dcblock.cpp ├── filter_dcblock.h ├── filter_variable.cpp ├── filter_variable.h ├── main.cpp ├── name.c ├── synth_dc.cpp ├── synth_dc.h ├── synth_waveform.cpp ├── synth_waveform.h └── utils.h ├── README.md ├── SDCard ├── Bank1 │ ├── 256978124 │ ├── 916744880 │ ├── 1504780501 │ ├── 2173298836 │ ├── 2275129409 │ ├── 2991689649 │ ├── 3078337974 │ ├── 3421571788 │ ├── 4044366186 │ └── Patchindex ├── Bank2 │ ├── 304633332 │ ├── 885943129 │ ├── 1022321240 │ ├── 1231019462 │ ├── 1337423881 │ ├── 2803543883 │ ├── 2829671085 │ ├── 3053187522 │ ├── 3390698083 │ ├── 3796215573 │ └── Patchindex ├── Bank3 │ ├── 47066540 │ ├── 1519828906 │ ├── 1555103360 │ ├── 2266998631 │ ├── 3426240329 │ ├── 3733337278 │ ├── 3826079193 │ ├── 3851442546 │ └── Patchindex ├── Bank4 │ ├── 1126472567 │ ├── 1361350319 │ ├── 2010595689 │ ├── 2255545869 │ ├── 2343874542 │ ├── 2479572785 │ ├── 3723771264 │ └── Patchindex ├── Bank5 │ ├── 676151029 │ ├── 3373092806 │ ├── 3794887208 │ ├── 3959255724 │ ├── 3989574602 │ └── Patchindex ├── Banknames └── Performances │ └── 1 └── platformio.ini /3D Models/240x320 TFT Standoff.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Electrotechnique/Momentum/3a84c3e65f7249cb1fc10a58568f6c78b335ba4f/3D Models/240x320 TFT Standoff.stl -------------------------------------------------------------------------------- /3D Models/3mm Bicolour LED Standoff.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Electrotechnique/Momentum/3a84c3e65f7249cb1fc10a58568f6c78b335ba4f/3D Models/3mm Bicolour LED Standoff.stl -------------------------------------------------------------------------------- /3D Models/Encoder Spacer.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Electrotechnique/Momentum/3a84c3e65f7249cb1fc10a58568f6c78b335ba4f/3D Models/Encoder Spacer.stl -------------------------------------------------------------------------------- /3D Models/Momentum Case USB C Brass Inserts.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Electrotechnique/Momentum/3a84c3e65f7249cb1fc10a58568f6c78b335ba4f/3D Models/Momentum Case USB C Brass Inserts.stl -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 ElectroTechnique 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Manual/Momentum Schematic V1_1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Electrotechnique/Momentum/3a84c3e65f7249cb1fc10a58568f6c78b335ba4f/Manual/Momentum Schematic V1_1.pdf -------------------------------------------------------------------------------- /Manual/Momentum User Manual V1_2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Electrotechnique/Momentum/3a84c3e65f7249cb1fc10a58568f6c78b335ba4f/Manual/Momentum User Manual V1_2.pdf -------------------------------------------------------------------------------- /Momentum/Audio.h: -------------------------------------------------------------------------------- 1 | /* Audio Library for Teensy 3.X 2 | * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com 3 | * 4 | * Development of this audio library was funded by PJRC.COM, LLC by sales of 5 | * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop 6 | * open source software by purchasing Teensy or other PJRC products. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice, development funding notice, and this permission 16 | * notice shall be included in all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | 27 | #ifndef Audio_h_ 28 | #define Audio_h_ 29 | 30 | #if TEENSYDUINO < 120 31 | #error "Teensyduino version 1.20 or later is required to compile the Audio library." 32 | #endif 33 | #ifdef __AVR__ 34 | #error "The Audio Library only works with Teensy 3.X. Teensy 2.0 is unsupported." 35 | #endif 36 | 37 | #include "DMAChannel.h" 38 | #if !defined(DMACHANNEL_HAS_BEGIN) || !defined(DMACHANNEL_HAS_BOOLEAN_CTOR) 39 | #error "You need to update DMAChannel.h & DMAChannel.cpp" 40 | #error "https://github.com/PaulStoffregen/cores/blob/master/teensy3/DMAChannel.h" 41 | #error "https://github.com/PaulStoffregen/cores/blob/master/teensy3/DMAChannel.cpp" 42 | #endif 43 | 44 | // When changing multiple audio object settings that must update at 45 | // the same time, these functions allow the audio library interrupt 46 | // to be disabled. For example, you may wish to begin playing a note 47 | // in response to reading an analog sensor. If you have "velocity" 48 | // information, you might start the sample playing and also adjust 49 | // the gain of a mixer channel. Use AudioNoInterrupts() first, then 50 | // make both changes to the 2 separate objects. Then allow the audio 51 | // library to update with AudioInterrupts(). Both changes will happen 52 | // at the same time, because AudioNoInterrupts() prevents any updates 53 | // while you make changes. 54 | // 55 | // ElectroTechnique Note: I don't use these as I found they introduced noise(!) 56 | #define AudioNoInterrupts() (NVIC_DISABLE_IRQ(IRQ_SOFTWARE)) 57 | #define AudioInterrupts() (NVIC_ENABLE_IRQ(IRQ_SOFTWARE)) 58 | 59 | #include "output_dacs.h" 60 | #include "effect_ensemble.h" //Electrotechnique exclusive stereo emsemble effect 61 | #include "effect_freeverb.h" 62 | #include "effect_envelope.h" //Local version 63 | #include "effect_combine.h" //Local version 64 | #include "filter_variable.h" //Local version 65 | #include "filter_dcblock.h" //Local version 66 | #include "mixer.h" 67 | #include "output_i2s.h" 68 | #include "synth_waveform.h" //Local version 69 | #include "synth_dc.h" 70 | #include "synth_whitenoise.h" 71 | #include "synth_pinknoise.h" 72 | #include "Oscilloscope.h" 73 | #include "analyze_peak.h" 74 | #endif 75 | -------------------------------------------------------------------------------- /Momentum/ButtonTool/Button.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Bounce2.h" 4 | 5 | #define HELD 2 6 | #define HELD_REPEAT 3 7 | #define HIGH_AFTER_HELD 4 8 | 9 | namespace ButtonTool 10 | { 11 | class Button : public Bounce 12 | { 13 | public: 14 | Button() : Bounce() {} 15 | 16 | bool update(bool state) 17 | { 18 | curState = state; 19 | return Bounce::update(); 20 | } 21 | 22 | protected: 23 | bool readCurrentState() override { return curState; } 24 | bool curState; 25 | }; 26 | } -------------------------------------------------------------------------------- /Momentum/ButtonTool/ButtonBase.cpp: -------------------------------------------------------------------------------- 1 | #include "ButtonBase.h" 2 | 3 | namespace ButtonTool 4 | { 5 | 6 | ButtonBase &ButtonBase::attachButtonCallback(btnCallback_t cb) 7 | { 8 | btnCallback = cb; 9 | return *this; 10 | } 11 | 12 | void ButtonBase::update(uint32_t btn) 13 | { 14 | if (button.update(btn)) 15 | { 16 | btnChanged = true; 17 | if (btnCallback != nullptr) 18 | { 19 | btnCallback(button.read()); 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Momentum/ButtonTool/ButtonBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Button.h" 3 | #include "ButtonConfig.h" 4 | 5 | namespace ButtonTool 6 | { 7 | class ButtonBase 8 | { 9 | public: 10 | void begin(); 11 | 12 | ButtonBase &attachButtonCallback(btnCallback_t); 13 | 14 | int32_t getButton() { 15 | return button.read(); 16 | } 17 | bool buttonChanged() 18 | { 19 | bool ret = btnChanged; 20 | btnChanged = false; 21 | return ret; 22 | } 23 | 24 | void update(uint32_t btn = 0); 25 | 26 | protected: 27 | ButtonBase() = default; 28 | 29 | Button button; 30 | bool btnChanged = false; 31 | btnCallback_t btnCallback = nullptr; 32 | 33 | ButtonBase &operator=(ButtonBase const &) = delete; 34 | ButtonBase(ButtonBase const &) = delete; 35 | 36 | friend class ButtonPlexBase; 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /Momentum/ButtonTool/ButtonConfig.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace ButtonTool 7 | { 8 | using btnCallback_t = std::function; 9 | using allBtnCallback_t = std::function; 10 | } 11 | -------------------------------------------------------------------------------- /Momentum/ButtonTool/ButtonPlex74165.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ButtonPlexBase.h" 4 | 5 | /* 6 | Modified from https://github.com/luni64/EncoderTool to support buttons on 74HC595 parallel shift registers 7 | The tick() code has been written specifically for Momentum due to the three parallel shift registers 8 | This is mostly Momentum specific and includes references to Button numbers 9 | */ 10 | 11 | namespace ButtonTool 12 | { 13 | class ButtonPlex74165 : public ButtonPlexBase 14 | { 15 | public: 16 | inline ButtonPlex74165(unsigned nrOfButtons, unsigned pinLD, unsigned pinCLK, unsigned pinA = UINT32_MAX, unsigned pinB = UINT32_MAX, unsigned pinC = UINT32_MAX); 17 | inline ~ButtonPlex74165(); 18 | 19 | inline void begin(); 20 | inline void begin(allBtnCallback_t callback); 21 | inline void read(); // call as often as possible 22 | 23 | protected: 24 | const unsigned BtnA, BtnB, BtnC, LD, CLK; 25 | int32_t previousState[8] = {LOW}; 26 | uint32_t WINDOWTIME[7] = {500, 390, 330, 220, 140, 60, 15}; 27 | uint16_t TWOBUTTONWINDOWTIME = 250; // Maximum time to detect two buttons pressed/held 28 | int8_t buttonPairNo = -1; 29 | uint32_t starttime[24] = {0}; 30 | boolean buttonHeld[24] = {false}; 31 | boolean buttonWasHeld[24] = {false}; 32 | boolean twoButtonCall = true; // Must be initally true to prevent callbacks during startup 33 | inline void readButton(unsigned i); 34 | uint8_t w = 0; 35 | }; 36 | 37 | // IMPLEMENTATION ============================================ 38 | 39 | ButtonPlex74165::ButtonPlex74165(unsigned nrOfButtons, unsigned pinLD, unsigned pinCLK, unsigned pinA, unsigned pinB, unsigned pinC) 40 | : ButtonPlexBase(nrOfButtons), BtnA(pinA), BtnB(pinB), BtnC(pinC), LD(pinLD), CLK(pinCLK) 41 | { 42 | } 43 | 44 | ButtonPlex74165::~ButtonPlex74165() 45 | { 46 | for (unsigned pin : {BtnA, BtnB, BtnC, LD, CLK}) 47 | { 48 | pinMode(pin, INPUT_DISABLE); 49 | }; 50 | } 51 | 52 | void ButtonPlex74165::begin(allBtnCallback_t cb) 53 | { 54 | begin(); 55 | attachCallback(cb); 56 | } 57 | 58 | void ButtonPlex74165::begin() 59 | { 60 | ButtonPlexBase::begin(); 61 | 62 | for (uint8_t pin : {BtnA, BtnB, BtnC}) 63 | { 64 | pinMode(pin, INPUT); 65 | } 66 | for (uint8_t pin : {LD, CLK}) 67 | { 68 | pinMode(pin, OUTPUT); 69 | } 70 | } 71 | 72 | void ButtonPlex74165::read() 73 | /* 74 | Button1 SR1 D4 75 | Button2 SR2 D4 76 | Button3 SR3 D4 77 | Button4 SR1 D5 78 | Button5 SR2 D5 79 | Button6 SR3 D5 80 | Button7 SR1 D6 81 | Button8 SR2 D6 82 | ButtonUp SR1 D7 83 | ButtonDown SR2 D7 84 | 85 | Read in Parallel 86 | Buttons 1,2,3 code for 2&3: 33 87 | Buttons 4,5,6 88 | Buttons 7,8 89 | Buttons Up, Down code: 22 90 | */ 91 | { 92 | // load current values to shift register 93 | digitalWriteFast(LD, LOW); 94 | delayNanoseconds(50); 95 | delayNanoseconds(50); 96 | delayNanoseconds(50); 97 | digitalWriteFast(LD, HIGH); 98 | 99 | // Read three buttons in parallel in each shift 100 | unsigned i = 0; 101 | while (i < buttonCount) 102 | { 103 | if (i > 0) 104 | { 105 | digitalWriteFast(CLK, HIGH); 106 | delayNanoseconds(50); 107 | } 108 | buttons[i].update(digitalReadFast(BtnA)); 109 | readButton(i); 110 | i++; 111 | buttons[i].update(digitalReadFast(BtnB)); 112 | readButton(i); 113 | i++; 114 | buttons[i].update(digitalReadFast(BtnC)); 115 | readButton(i); 116 | i++; 117 | if (i > 0) 118 | { 119 | digitalWriteFast(CLK, LOW); 120 | delayNanoseconds(50); 121 | } 122 | } 123 | } 124 | 125 | void ButtonPlex74165::readButton(unsigned i) 126 | { 127 | // Ignore unconnected shift register inputs ***** This is Momentum specific ***** 128 | if (i == 2 || i == 5 || i > 11) 129 | return; 130 | 131 | if (buttons[i].buttonChanged()) 132 | { 133 | if (buttons[i].getButton() == LOW) 134 | { 135 | callback(i, LOW); 136 | starttime[i] = millis(); 137 | w = 0; 138 | } 139 | else 140 | { 141 | twoButtonCall = false; 142 | if (!buttonHeld[i]) 143 | { 144 | callback(i, HIGH); 145 | } 146 | if (buttonHeld[i] && buttonWasHeld[i] && w < 127) 147 | { 148 | callback(i, HIGH_AFTER_HELD); 149 | buttonWasHeld[i] = false; 150 | } 151 | buttonHeld[i] = false; 152 | w = 0; 153 | } 154 | } 155 | 156 | // Two button press 157 | if (buttons[i].getButton() == LOW && !twoButtonCall) 158 | { 159 | switch (i) 160 | { 161 | case VOL_UP: // UP 162 | if (buttonPairNo == VOL_DOWN && (starttime[VOL_DOWN] - starttime[VOL_UP]) < TWOBUTTONWINDOWTIME) 163 | { 164 | callback(22, HELD); 165 | buttonPairNo = -1; // Reset 166 | twoButtonCall = true; 167 | starttime[VOL_DOWN] = millis() + 1000; 168 | starttime[VOL_UP] = millis() + 1000; 169 | buttonWasHeld[VOL_DOWN] = false; 170 | buttonWasHeld[VOL_UP] = false; 171 | w = 127; 172 | return; 173 | } 174 | buttonPairNo = VOL_UP; 175 | break; 176 | case VOL_DOWN: 177 | 178 | if (buttonPairNo == VOL_UP && (starttime[VOL_UP] - starttime[VOL_DOWN]) < TWOBUTTONWINDOWTIME) 179 | { 180 | callback(22, HELD); 181 | buttonPairNo = -1; // Reset 182 | twoButtonCall = true; 183 | starttime[VOL_DOWN] = millis() + 1000; 184 | starttime[VOL_UP] = millis() + 1000; 185 | buttonWasHeld[VOL_DOWN] = false; 186 | buttonWasHeld[VOL_UP] = false; 187 | w = 127; 188 | return; 189 | } 190 | buttonPairNo = VOL_DOWN; 191 | break; 192 | case BUTTON_2: 193 | if (keyboardActive) 194 | return; 195 | if (buttonPairNo == BUTTON_3 && (starttime[BUTTON_3] - starttime[BUTTON_2]) < TWOBUTTONWINDOWTIME) 196 | { 197 | callback(33, HELD); 198 | buttonPairNo = -1; // Reset 199 | twoButtonCall = true; 200 | starttime[BUTTON_2] = millis() + 1000; 201 | starttime[BUTTON_3] = millis() + 1000; 202 | buttonWasHeld[BUTTON_3] = false; 203 | buttonWasHeld[BUTTON_2] = false; 204 | w = 127; 205 | return; 206 | } 207 | buttonPairNo = BUTTON_2; 208 | break; 209 | case BUTTON_3: 210 | if (keyboardActive) 211 | return; 212 | if (buttonPairNo == BUTTON_2 && (starttime[BUTTON_2] - starttime[BUTTON_3]) < TWOBUTTONWINDOWTIME) 213 | { 214 | callback(33, HELD); 215 | buttonPairNo = -1; // Reset 216 | twoButtonCall = true; 217 | starttime[BUTTON_2] = millis() + 1000; 218 | starttime[BUTTON_3] = millis() + 1000; 219 | buttonWasHeld[BUTTON_3] = false; 220 | buttonWasHeld[BUTTON_2] = false; 221 | w = 127; 222 | return; 223 | } 224 | buttonPairNo = BUTTON_3; 225 | break; 226 | } 227 | } 228 | 229 | if (buttons[i].getButton() == LOW && (millis() - starttime[i]) > WINDOWTIME[w]) 230 | { 231 | buttonHeld[i] = true; 232 | buttonWasHeld[i] = true; 233 | starttime[i] = millis(); 234 | if (w == 127) // prevent HELD calbacks after two button press 235 | return; 236 | // Acceleration of callbacks when button is held down 237 | if (w < 6) 238 | w++; 239 | if (w > 1) 240 | { 241 | callback(i, HELD_REPEAT); // HELD REPEAT 242 | } 243 | else 244 | { 245 | callback(i, HELD); // HELD ONCE 246 | } 247 | } 248 | } 249 | } -------------------------------------------------------------------------------- /Momentum/ButtonTool/ButtonPlexBase.cpp: -------------------------------------------------------------------------------- 1 | #include "ButtonPlexBase.h" 2 | 3 | namespace ButtonTool 4 | { 5 | ButtonPlexBase::ButtonPlexBase(unsigned eCnt) : buttonCount(eCnt) 6 | { 7 | buttons = new ButtonBase[eCnt]; 8 | } 9 | 10 | void ButtonPlexBase::begin() 11 | { 12 | } 13 | 14 | ButtonPlexBase::~ButtonPlexBase() 15 | { 16 | delete[] buttons; 17 | } 18 | 19 | ButtonBase &ButtonPlexBase::operator[](std::size_t idx) 20 | { 21 | return idx < buttonCount ? buttons[idx] : buttons[buttonCount - 1]; 22 | } 23 | 24 | void ButtonPlexBase::attachCallback(allBtnCallback_t _callback) 25 | { 26 | callback = _callback; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Momentum/ButtonTool/ButtonPlexBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ButtonConfig.h" 4 | #include "ButtonBase.h" 5 | 6 | /* 7 | Modified from https://github.com/luni64/EncoderTool to support buttons on 74HC595 parallel shift registers 8 | This is mostly Momentum specific and includes references to Button numbers 9 | */ 10 | // Button numbers as they are connected to the shift registers 11 | #define VOL_DOWN 0 12 | #define VOL_UP 1 13 | #define BUTTON_8 3 14 | #define BUTTON_7 4 15 | #define BUTTON_5 6 16 | #define BUTTON_4 7 17 | #define BUTTON_6 8 18 | #define BUTTON_2 9 19 | #define BUTTON_1 10 20 | #define BUTTON_3 11 21 | 22 | namespace ButtonTool 23 | { 24 | class ButtonPlexBase 25 | { 26 | public: 27 | void attachCallback(allBtnCallback_t callback); 28 | ButtonBase &operator[](std::size_t idx); 29 | 30 | protected: 31 | ButtonPlexBase(unsigned ButtonCount); 32 | ~ButtonPlexBase(); 33 | 34 | void begin(); 35 | void begin(allBtnCallback_t); 36 | 37 | const uint32_t buttonCount; 38 | ButtonBase *buttons; 39 | 40 | allBtnCallback_t callback = nullptr; 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /Momentum/ButtonTool/ButtonTool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ButtonPlex74165.h" 4 | #include "Button.h" 5 | 6 | /* 7 | Modified from https://github.com/luni64/EncoderTool 8 | to act as a 74HC165 wired in parallel, button reader. 9 | */ -------------------------------------------------------------------------------- /Momentum/Detune.cpp: -------------------------------------------------------------------------------- 1 | #include "Detune.h" 2 | #include "Arduino.h" 3 | 4 | const float DETUNE[4][24] PROGMEM = { 5 | {0.0f, 0.04f, 0.09f, 0.13f, 0.17f, 0.22f, 0.26f, 0.30f, 0.35f, 0.39f, 0.43f, 0.49f, 0.52f, 0.57f, 0.61f, 0.65f, 0.70f, 0.74f, 0.78f, 0.83f, 0.87f, 0.91f, 0.96f, 1.0f}, 6 | {0.0f, 0.09f, 0.18f, 0.27f, 0.36f, 0.45f, 0.55f, 0.63f, 0.73f, 0.82f, 0.91f, 1.0f, 0.0f, 0.09f, 0.18f, 0.27f, 0.36f, 0.45f, 0.55f, 0.63f, 0.73f, 0.82f, 0.91f, 1.0f}, 7 | {0.0f, 0.14f, 0.29f, 0.43, 0.57f, 0.71f, 0.86f, 1.0f, 0.0f, 0.14f, 0.29f, 0.43, 0.57f, 0.71f, 0.86f, 1.0f, 0.0f, 0.14f, 0.29f, 0.43, 0.57f, 0.71f, 0.86f, 1.0f}, 8 | {0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f, 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f, 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f, 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f} 9 | }; 10 | 11 | const uint32_t CHORD_DETUNE[12][128] PROGMEM = { 12 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 13 | {4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 1, 1}, 14 | {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 2, 2}, 15 | {12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10, 10, 10, 3, 3}, 16 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 14, 14, 14, 14, 14, 14, 14, 4, 4}, 17 | {4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 5, 5}, 18 | {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 6, 6}, 19 | {12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 7, 7, 7, 7, 7, 7, 7, 11, 11, 11, 11, 11, 11, 11, 7, 7, 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 4, 4, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7}, 20 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8}, 21 | {4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 14, 14, 14, 14, 14, 14, 14, 4, 4, 4, 4, 4, 4, 4, 14, 14, 14, 14, 14, 14, 11, 11, 11, 11, 11, 11, 11, 11, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9}, 22 | {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 10, 10}, 23 | {12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 6, 6, 6, 6, 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 5, 5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, 11, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 11, 11} 24 | }; -------------------------------------------------------------------------------- /Momentum/Detune.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define MAXDETUNE 0.06f // 6% 1semitone 6 | #define CDT_DETUNE 0.992f 7 | 8 | extern const float DETUNE[4][24]; 9 | extern const char* CDT_STR[128]; 10 | extern const uint32_t CHORD_DETUNE[12][128]; 11 | -------------------------------------------------------------------------------- /Momentum/EepromMgr.h: -------------------------------------------------------------------------------- 1 | #include 2 | #define FIRSTRUN 111 3 | #define EEPROM_MIDI_CH 0 4 | #define EEPROM_MIDI_OUT_CH 1 5 | #define EEPROM_MIDI_THRU 2 6 | #define EEPROM_SCOPE_ENABLE 3 7 | #define EEPROM_VU_ENABLE 4 8 | #define EEPROM_VOLUME 5 9 | #define EEPROM_LAST_BANK 6 10 | #define EEPROM_LAST_PATCH 7 11 | #define EEPROM_TUNING 8 12 | #define EEPROM_FIRST_RUN 9 13 | #define EEPROM_ARP_TEMPO 10 14 | #define EEPROM_ARP_STYLE 11 15 | #define EEPROM_ARP_RANGE 12 16 | #define EEPROM_ARP_DIVISION 13 17 | #define EEPROM_ARP_CYCLES 14 18 | #define EEPROM_ARP_BASIS 15 19 | #define EEPROM_KEYBOARD_SCALE 16 20 | #define EEPROM_KEYBOARD_BASIS 17 21 | #define EEPROM_SEND_CC 18 22 | #define EEPROM_LAST_SEQUENCE 19 23 | #define EEPROM_SYNC_TO_MIDI_CLK 20 24 | 25 | FLASHMEM int8_t getFirstRun() 26 | { 27 | return EEPROM.read(EEPROM_FIRST_RUN) == FIRSTRUN; // Assuming it's never this from the factory 28 | } 29 | 30 | FLASHMEM void storeFirstRun() 31 | { 32 | EEPROM.update(EEPROM_FIRST_RUN, FIRSTRUN); 33 | } 34 | 35 | FLASHMEM int8_t getSendCC() 36 | { 37 | return EEPROM.read(EEPROM_SEND_CC); 38 | } 39 | 40 | FLASHMEM int8_t getSyncToMIDIClk() 41 | { 42 | return EEPROM.read(EEPROM_SYNC_TO_MIDI_CLK); 43 | } 44 | 45 | FLASHMEM void storeSendCCToEEPROM(byte cc) 46 | { 47 | EEPROM.update(EEPROM_SEND_CC, cc); 48 | } 49 | 50 | FLASHMEM void storeSyncToMIDIClkToEEPROM(byte cc) 51 | { 52 | EEPROM.update(EEPROM_SYNC_TO_MIDI_CLK, cc); 53 | } 54 | 55 | 56 | FLASHMEM int8_t getLastBank() 57 | { 58 | byte b = EEPROM.read(EEPROM_LAST_BANK); 59 | if (b < 0 || b > 7) 60 | return 0; 61 | return b; 62 | } 63 | 64 | FLASHMEM int8_t getLastSequence() 65 | { 66 | byte b = EEPROM.read(EEPROM_LAST_SEQUENCE); 67 | if (b < 0 || b > 127) 68 | return 0; 69 | return b; 70 | } 71 | 72 | FLASHMEM void storeLastBankToEEPROM(byte type) 73 | { 74 | EEPROM.update(EEPROM_LAST_BANK, type); 75 | } 76 | 77 | FLASHMEM int8_t getLastPatch() 78 | { 79 | byte p = EEPROM.read(EEPROM_LAST_PATCH); 80 | if (p < 0 || p > 127) 81 | return 0; 82 | return p; 83 | } 84 | 85 | FLASHMEM void storeLastPatchToEEPROM(byte type) 86 | { 87 | EEPROM.update(EEPROM_LAST_PATCH, type); 88 | } 89 | 90 | FLASHMEM void storeLastSequenceToEEPROM(byte type) 91 | { 92 | EEPROM.update(EEPROM_LAST_SEQUENCE, type); 93 | } 94 | 95 | FLASHMEM void loadLastPatchUsed() 96 | { 97 | currentBankIndex = getLastBank(); 98 | currentPatchIndex = getLastPatch(); 99 | } 100 | 101 | FLASHMEM int8_t getVolume() 102 | { 103 | byte v = EEPROM.read(EEPROM_VOLUME); 104 | if (v < 0 || v > 127) 105 | return currentVolume; 106 | return v; 107 | } 108 | 109 | FLASHMEM void storeVolumeToEEPROM(byte type) 110 | { 111 | EEPROM.update(EEPROM_VOLUME, type); 112 | } 113 | 114 | FLASHMEM int getMIDIChannel() 115 | { 116 | byte midiChannel = EEPROM.read(EEPROM_MIDI_CH); 117 | if (midiChannel < 0 || midiChannel > 16) 118 | midiChannel = MIDI_CHANNEL_OMNI; // If EEPROM has no MIDI channel stored 119 | return midiChannel; 120 | } 121 | 122 | FLASHMEM void storeMidiChannel(byte channel) 123 | { 124 | EEPROM.update(EEPROM_MIDI_CH, channel); 125 | } 126 | 127 | FLASHMEM int getMIDIOutCh() 128 | { 129 | byte mc = EEPROM.read(EEPROM_MIDI_OUT_CH); 130 | if (mc < 0 || midiOutCh > 16) 131 | mc = 0; // If EEPROM has no MIDI channel stored 132 | return mc; 133 | } 134 | 135 | FLASHMEM void storeMidiOutCh(byte channel) 136 | { 137 | EEPROM.update(EEPROM_MIDI_OUT_CH, channel); 138 | } 139 | 140 | FLASHMEM midi::Thru::Mode getMidiThru() 141 | { 142 | byte midiThruMode = EEPROM.read(EEPROM_MIDI_THRU); 143 | if (midiThruMode < midi::Thru::Off || midiThruMode > midi::Thru::DifferentChannel) 144 | return midi::Thru::Full; // If EEPROM has no MIDI Thru stored 145 | return (midi::Thru::Mode)midiThruMode; 146 | } 147 | 148 | FLASHMEM void storeMidiThru(byte thru) 149 | { 150 | EEPROM.update(EEPROM_MIDI_THRU, thru); 151 | } 152 | 153 | FLASHMEM boolean getScopeEnable() 154 | { 155 | byte sc = EEPROM.read(EEPROM_SCOPE_ENABLE); 156 | if (sc < 0 || sc > 1) 157 | return false; // If EEPROM has no scope enable stored 158 | return sc == 1 ? true : false; 159 | } 160 | 161 | FLASHMEM void storeScopeEnable(byte ScopeEnable) 162 | { 163 | EEPROM.update(EEPROM_SCOPE_ENABLE, ScopeEnable); 164 | } 165 | 166 | FLASHMEM boolean getVUEnable() 167 | { 168 | byte vu = EEPROM.read(EEPROM_VU_ENABLE); 169 | if (vu < 0 || vu > 1) 170 | return false; // If EEPROM has no VU enable stored 171 | return vu == 1 ? true : false; 172 | } 173 | 174 | FLASHMEM void storeVUEnable(byte VUEnable) 175 | { 176 | EEPROM.update(EEPROM_VU_ENABLE, VUEnable); 177 | } 178 | 179 | FLASHMEM int8_t getTuningCents() 180 | { 181 | byte t = EEPROM.read(EEPROM_TUNING); 182 | if (t < 0 || t > 100) 183 | return 0; // If EEPROM has no value stored 184 | return t - 50; // zero is stored as 50, +/-50cents 185 | } 186 | 187 | FLASHMEM void storeTuning(byte tuning) 188 | { 189 | EEPROM.update(EEPROM_TUNING, tuning + 50); // zero is stored as 50, +/-50cents 190 | } 191 | 192 | FLASHMEM int8_t getArpStyle() 193 | { 194 | byte p = EEPROM.read(EEPROM_ARP_STYLE); 195 | if (p < 0 || p > 127) 196 | return 0; 197 | return p; 198 | } 199 | 200 | FLASHMEM void storeArpRangeToEEPROM(byte range) 201 | { 202 | EEPROM.update(EEPROM_ARP_RANGE, range); 203 | } 204 | 205 | FLASHMEM int8_t getArpRange() 206 | { 207 | byte p = EEPROM.read(EEPROM_ARP_RANGE); 208 | if (p < 0 || p > 127) 209 | return 0; 210 | return p; 211 | } 212 | 213 | FLASHMEM void storeArpDivisionToEEPROM(byte div) 214 | { 215 | EEPROM.update(EEPROM_ARP_DIVISION, div); 216 | } 217 | 218 | FLASHMEM int8_t getArpDivision() 219 | { 220 | byte p = EEPROM.read(EEPROM_ARP_DIVISION); 221 | if (p < 0 || p > 127) 222 | return 0; 223 | return p; 224 | } 225 | 226 | FLASHMEM void storeArpCyclesToEEPROM(byte c) 227 | { 228 | EEPROM.update(EEPROM_ARP_CYCLES, c); 229 | } 230 | 231 | FLASHMEM int8_t getArpCycles() 232 | { 233 | byte p = EEPROM.read(EEPROM_ARP_CYCLES); 234 | if (p < 0 || p > 127) 235 | return 0; 236 | return p; 237 | } 238 | 239 | FLASHMEM void storeArpBasisToEEPROM(byte c) 240 | { 241 | EEPROM.update(EEPROM_ARP_BASIS, c); 242 | } 243 | 244 | FLASHMEM int8_t getArpBasis() 245 | { 246 | byte p = EEPROM.read(EEPROM_ARP_BASIS); 247 | if (p < 0 || p > 127) 248 | return 0; 249 | return p; 250 | } 251 | 252 | FLASHMEM void storeKeyboardBasisToEEPROM(byte c) 253 | { 254 | EEPROM.update(EEPROM_KEYBOARD_BASIS, c); 255 | } 256 | 257 | FLASHMEM int8_t getKeyboardBasis() 258 | { 259 | byte p = EEPROM.read(EEPROM_KEYBOARD_BASIS); 260 | if (p < 0 || p > 127) 261 | return 0; 262 | return p; 263 | } 264 | 265 | FLASHMEM void storeKeyboardScaleToEEPROM(byte c) 266 | { 267 | EEPROM.update(EEPROM_KEYBOARD_SCALE, c); 268 | } 269 | 270 | FLASHMEM int8_t getKeyboardScale() 271 | { 272 | byte p = EEPROM.read(EEPROM_KEYBOARD_SCALE); 273 | if (p < 0 || p > 127) 274 | return 0; 275 | return p; 276 | } 277 | 278 | FLASHMEM void storeArpStyleToEEPROM(byte style) 279 | { 280 | EEPROM.update(EEPROM_ARP_STYLE, style); 281 | } 282 | 283 | FLASHMEM void checkFirstRun() 284 | { 285 | if (!getFirstRun()) 286 | { 287 | if (DEBUG) 288 | Serial.println(F("First Run")); 289 | // Default the EEPROM contents 290 | storeMidiChannel(0); 291 | storeMidiOutCh(0); 292 | storeMidiThru(midi::Thru::Full); 293 | storeLastBankToEEPROM(0); 294 | storeLastPatchToEEPROM(0); 295 | storeLastSequenceToEEPROM(0); 296 | storeTuning(0); 297 | storeVUEnable(0); 298 | storeVolumeToEEPROM(currentVolume); 299 | storeScopeEnable(0); 300 | storeArpDivisionToEEPROM(1); 301 | storeArpCyclesToEEPROM(0); 302 | storeArpRangeToEEPROM(3); 303 | storeArpStyleToEEPROM(0); 304 | storeArpBasisToEEPROM(2); 305 | storeKeyboardScaleToEEPROM(0); 306 | storeKeyboardBasisToEEPROM(4); 307 | storeSendCCToEEPROM(0); 308 | storeSyncToMIDIClkToEEPROM(0); 309 | storeFirstRun(); 310 | } 311 | } 312 | -------------------------------------------------------------------------------- /Momentum/EncoderTool/EncoderBase.cpp: -------------------------------------------------------------------------------- 1 | #include "EncoderBase.h" 2 | #include "Arduino.h" 3 | #include "core_pins.h" 4 | #include 5 | 6 | namespace EncoderTool 7 | { 8 | EncoderBase &EncoderBase::setCountMode(CountMode mode) 9 | { 10 | switch (mode) 11 | { 12 | case CountMode::quarter: 13 | stateMachine = &stateMachineQtr; 14 | invert = 0b11; 15 | break; 16 | case CountMode::quarterInv: 17 | stateMachine = &stateMachineQtr; 18 | invert = 0b00; 19 | break; 20 | case CountMode::half: 21 | stateMachine = &stateMachineHalf; 22 | invert = 0b00; 23 | break; 24 | case CountMode::halfAlt: 25 | stateMachine = &stateMachineHalf; 26 | invert = 0b01; 27 | break; 28 | default: 29 | stateMachine = &stateMachineFull; 30 | invert = 0b00; 31 | } 32 | return *this; 33 | } 34 | 35 | EncoderBase &EncoderBase::attachCallback(encCallback_t cb) 36 | { 37 | callback = cb; 38 | return *this; 39 | } 40 | 41 | EncoderBase &EncoderBase::attachButtonCallback(encBtnCallback_t cb) 42 | { 43 | btnCallback = cb; 44 | return *this; 45 | } 46 | 47 | EncoderBase &EncoderBase::setLimits(int32_t min, int32_t max, bool periodic) 48 | { 49 | if (min < max) 50 | { 51 | this->minVal = min; 52 | this->maxVal = max; 53 | this->periodic = periodic; 54 | } 55 | else 56 | { 57 | this->minVal = INT32_MIN; 58 | this->maxVal = INT32_MAX; 59 | } 60 | return *this; 61 | } 62 | 63 | enum states : uint8_t 64 | { 65 | A = 0x00, 66 | B_cw = 0x01, 67 | C_cw = 0x03, 68 | D_cw = 0x02, 69 | B_ccw = 0x04, 70 | C_ccw = 0x06, 71 | D_ccw = 0x05, 72 | 73 | UP = 0x10, 74 | DOWN = 0x20, 75 | ERR = 0x30, 76 | }; 77 | 78 | void EncoderBase::begin(uint32_t phaseA, uint32_t phaseB) 79 | { 80 | curState = (phaseA << 1 | phaseB) ^ invert; 81 | } 82 | 83 | int EncoderBase::update(uint32_t phaseA, uint32_t phaseB, uint32_t btn) 84 | { 85 | if (button.update(btn)) 86 | { 87 | btnChanged = true; 88 | if (btnCallback != nullptr) 89 | { 90 | btnCallback(button.read()); 91 | } 92 | } 93 | unsigned input = (phaseA << 1 | phaseB) ^ invert; // invert signals if necessary 94 | if (stateMachine == nullptr) 95 | return 0; // tick might get called from yield before class is initialized 96 | 97 | curState = (*stateMachine)[curState][input]; // get next state depending on new input 98 | uint8_t direction = curState & 0xF0; // direction is set if we need to count up / down or got an error 99 | curState &= 0x0F; // remove the direction info from state 100 | 101 | if (direction == UP) 102 | { 103 | if (value < maxVal) // maxVal = INT_MAX if no limits set 104 | { 105 | value++; 106 | valChanged = true; 107 | if (callback != nullptr) 108 | callback(value, +1); 109 | return +1; 110 | } 111 | if (periodic) // if periodic, wrap to minVal, else stop counting 112 | { 113 | value = minVal; 114 | valChanged = true; 115 | 116 | if (callback != nullptr) 117 | callback(value, +1); 118 | return +1; 119 | } 120 | value = maxVal; 121 | return false; 122 | } 123 | 124 | if (direction == DOWN) 125 | { 126 | if (value > minVal) // minVal = INT_MIN if no limits set 127 | { 128 | value--; 129 | valChanged = true; 130 | if (callback != nullptr) 131 | callback(value, -1); 132 | return -1; 133 | } 134 | if (periodic) // if periodic, wrap to maxVal, else stop counting 135 | { 136 | valChanged = true; 137 | value = maxVal; 138 | if (callback != nullptr) 139 | callback(value, -1); 140 | return -1; 141 | } 142 | value = minVal; 143 | return 0; 144 | } 145 | 146 | #if defined(USE_ERROR_CALLBACKS) 147 | if (direction == ERR) 148 | { 149 | if (errCallback != nullptr) 150 | errCallback(value); 151 | } 152 | #endif 153 | return false; 154 | } 155 | 156 | const uint8_t EncoderBase::stateMachineQtr[7][4]{ 157 | // 00 01 10 11 158 | /*0 A */ {A, B_cw, D_ccw, A | ERR}, 159 | /*1 B_cw*/ {A, B_cw, B_cw | ERR, C_cw}, 160 | /*2 D_cw*/ {A | UP, D_cw | ERR, D_cw, C_cw}, 161 | /*3 C_cw*/ {C_cw | ERR, B_cw, D_cw, C_cw}, 162 | 163 | /*4 B_ccw*/ {A | DOWN, B_ccw, B_ccw | ERR, C_ccw}, 164 | /*5 D_ccw*/ {A, D_ccw | ERR, D_ccw, C_ccw}, 165 | /*6 C_ccw*/ {C_ccw | ERR, B_ccw, D_ccw, C_ccw}, 166 | }; 167 | 168 | const uint8_t EncoderBase::stateMachineHalf[7][4]{ 169 | // 00 01 10 11 170 | /*0 A */ {A, B_cw, D_ccw, A | ERR}, 171 | /*1 B_cw*/ {A, B_cw, B_cw | ERR, C_cw | UP}, 172 | /*2 D_cw*/ {A | UP, D_cw | ERR, D_cw, C_cw}, 173 | /*3 C_cw*/ {C_cw | ERR, B_ccw, D_cw, C_cw}, // C_ccw = C_cw 174 | 175 | /*4 B_ccw*/ {A | DOWN, B_ccw, B_ccw | ERR, C_cw}, 176 | /*5 D_ccw*/ {A, B_ccw | ERR, D_ccw, C_cw | DOWN}, 177 | /*6 C_ccw*/ {C_ccw | ERR, C_ccw | ERR, C_ccw | ERR, C_ccw | ERR}, // should never be in this state... 178 | }; 179 | 180 | const uint8_t EncoderBase::stateMachineFull[7][4]{ 181 | // 00 01 10 11 182 | /*0 A */ {A, B_cw | UP, D_cw | DOWN, A | ERR}, 183 | /*1 B_cw*/ {A | DOWN, B_cw, B_cw | ERR, C_cw | UP}, 184 | /*2 D_cw*/ {A | UP, D_cw | ERR, D_cw, C_cw | DOWN}, 185 | /*3 C_cw*/ {C_cw | ERR, B_cw | DOWN, D_cw | UP, C_cw}, 186 | }; 187 | } // namespace EncoderTool 188 | 189 | // the linker currently (<=td1.54) does not always link in _write 190 | // this is a ugly workaround to fix it for T3.x boards 191 | // T4.x don't show the issue. 192 | 193 | #if defined(KINETISK) 194 | extern "C" 195 | { 196 | int _write(int handle, char *buf, int count) 197 | { 198 | return 0; // just ignore the call 199 | } 200 | } 201 | #endif -------------------------------------------------------------------------------- /Momentum/EncoderTool/EncoderBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "EncoderButton.h" 3 | #include "config.h" 4 | 5 | namespace EncoderTool 6 | { 7 | enum class CountMode { // cnt per quad period | input at detents | remark 8 | quarter, // 1 | 0/0 | standard for mech encoders 9 | quarterInv, // 1 | 1/1 | 10 | half, // 2 | 0/0 and 1/1 | seldom used 11 | halfAlt, // 2 | 1/0 and 0/1 | seldom used 12 | full // 4 | n.a. | standard for optical encoders w/o detents 13 | }; 14 | 15 | class EncoderBase 16 | { 17 | public: 18 | void begin(uint32_t phaseA, uint32_t phaseB); 19 | 20 | EncoderBase& setCountMode(CountMode); 21 | EncoderBase& attachCallback(encCallback_t); 22 | EncoderBase& attachButtonCallback(encBtnCallback_t); 23 | EncoderBase& setLimits(int32_t min, int32_t max, bool periodic = false); 24 | 25 | void setValue(int32_t val) { value = val; } 26 | 27 | int32_t getValue() const { return value; } 28 | bool valueChanged() 29 | { 30 | bool ret = valChanged; 31 | valChanged = false; 32 | return ret; 33 | } 34 | 35 | int32_t getButton() { return button.read(); } 36 | bool buttonChanged() 37 | { 38 | bool ret = btnChanged; 39 | btnChanged = false; 40 | return ret; 41 | } 42 | 43 | int update(uint32_t phaseA, uint32_t phaseB, uint32_t btn = 0); 44 | 45 | protected: 46 | EncoderBase() = default; 47 | int32_t value = 0; 48 | bool valChanged = false; 49 | 50 | EncoderButton button; 51 | bool btnChanged = false; 52 | 53 | int32_t minVal = INT32_MIN, maxVal = INT32_MAX; 54 | bool periodic = false; 55 | unsigned invert = 0x00; 56 | uint8_t curState = 0; 57 | 58 | encCallback_t callback = nullptr; 59 | encBtnCallback_t btnCallback = nullptr; 60 | 61 | static const uint8_t stateMachineQtr[7][4]; 62 | static const uint8_t stateMachineHalf[7][4]; 63 | static const uint8_t stateMachineFull[7][4]; 64 | const uint8_t (*stateMachine)[7][4] = &stateMachineFull; 65 | 66 | EncoderBase& operator=(EncoderBase const&) = delete; 67 | EncoderBase(EncoderBase const&) = delete; 68 | 69 | friend class EncPlexBase; 70 | 71 | #if defined(USE_ERROR_CALLBACKS) 72 | protected: 73 | encCallback_t errCallback = nullptr; 74 | 75 | public: 76 | void attachErrorCallback(encCallback_t cb) { errCallback = cb; } 77 | #endif 78 | }; 79 | } -------------------------------------------------------------------------------- /Momentum/EncoderTool/EncoderButton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Bounce2.h" 4 | 5 | namespace EncoderTool 6 | { 7 | class EncoderButton : public Bounce 8 | { 9 | public: 10 | EncoderButton() : Bounce() {} 11 | 12 | bool update(bool state) 13 | { 14 | curState = state; 15 | return Bounce::update(); 16 | } 17 | 18 | // bool longPress() 19 | // { 20 | // return durationOfPreviousState() > 100; 21 | // } 22 | 23 | protected: 24 | bool readCurrentState() override { return curState; } 25 | bool curState; 26 | }; 27 | } -------------------------------------------------------------------------------- /Momentum/EncoderTool/EncoderTool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Multiplexed/EncPlex74165.h" 4 | 5 | /* 6 | Modified from https://github.com/luni64/EncoderTool 7 | This has encoder acceleration and an all button callback added. 8 | Some parts of this library have been removed. 9 | */ -------------------------------------------------------------------------------- /Momentum/EncoderTool/Multiplexed/EncPlex74165.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Bounce2.h" 4 | #include "EncPlexBase.h" 5 | 6 | /* 7 | Modified from https://github.com/luni64/EncoderTool 8 | This has encoder acceleration and an all button callback added. 9 | Some parts of this library have been removed. 10 | The tick() code has been rewritten specifically for Momentum 11 | */ 12 | 13 | namespace EncoderTool 14 | { 15 | class EncPlex74165 : public EncPlexBase 16 | { 17 | public: 18 | inline EncPlex74165(unsigned nrOfEncoders, unsigned pinLD, unsigned pinCLK, unsigned pinA, unsigned pinB, unsigned pinBtn = UINT32_MAX); 19 | inline ~EncPlex74165(); 20 | 21 | inline void begin(CountMode mode = CountMode::quarter); 22 | inline void begin(allCallback_t callback, allBtnCallback_t btnCallback, CountMode m = CountMode::quarter); 23 | inline void read(); // call as often as possible 24 | 25 | protected: 26 | const unsigned A, B, Btn, LD, CLK; 27 | uint32_t now = 0; 28 | int32_t previousState[8] = {LOW}; 29 | uint32_t WINDOWTIME[7] = {500, 390, 330, 220, 140, 80, 20}; 30 | uint32_t btnStarttime[8] = {0}; 31 | boolean buttonHeld[8] = {false}; 32 | uint8_t w = 0; 33 | boolean encRotationBlocked = false; 34 | }; 35 | 36 | // IMPLEMENTATION ============================================ 37 | 38 | EncPlex74165::EncPlex74165(unsigned nrOfEncoders, unsigned pinLD, unsigned pinCLK, unsigned pinA, unsigned pinB, unsigned pinBtn) 39 | : EncPlexBase(nrOfEncoders), A(pinA), B(pinB), Btn(pinBtn), LD(pinLD), CLK(pinCLK) 40 | { 41 | } 42 | 43 | EncPlex74165::~EncPlex74165() 44 | { 45 | for (unsigned pin : {A, B, Btn, LD, CLK}) 46 | { 47 | pinMode(pin, INPUT_DISABLE); 48 | }; 49 | } 50 | 51 | void EncPlex74165::begin(allCallback_t cb, allBtnCallback_t bcb, CountMode mode) 52 | { 53 | begin(mode); 54 | attachCallback(cb); 55 | attachBtnCallback(bcb); 56 | } 57 | 58 | void EncPlex74165::begin(CountMode mode) 59 | { 60 | EncPlexBase::begin(mode); 61 | 62 | for (uint8_t pin : {A, B, Btn}) 63 | { 64 | pinMode(pin, INPUT); 65 | } 66 | for (uint8_t pin : {LD, CLK}) 67 | { 68 | pinMode(pin, OUTPUT); 69 | } 70 | 71 | digitalWriteFast(LD, HIGH); // active low 72 | delayMicroseconds(1); 73 | } 74 | 75 | void EncPlex74165::read() 76 | { 77 | // load current values to shift register 78 | digitalWriteFast(LD, LOW); 79 | delayNanoseconds(50); 80 | delayNanoseconds(50); 81 | delayNanoseconds(50); 82 | digitalWriteFast(LD, HIGH); 83 | 84 | now = millis(); 85 | 86 | for (unsigned i = 0; i < encoderCount; i++) 87 | { 88 | if (i > 0) 89 | { 90 | digitalWriteFast(CLK, HIGH); 91 | delayNanoseconds(50); 92 | } 93 | // Don't read first four because encoders are on last four positions. 94 | if (i > 3) 95 | { 96 | int delta = encoders[i].update(digitalReadFast(A), digitalReadFast(B), digitalReadFast(Btn)); 97 | if (encoders[i].buttonChanged()) 98 | { 99 | if (encoders[i].getButton() == LOW) 100 | { 101 | btnStarttime[i] = millis(); 102 | w = 0; 103 | encRotationBlocked = true; // Prevent rotation of encoder when pressing button 104 | } 105 | else 106 | { 107 | if (!buttonHeld[i]) 108 | btnCallback(i, encoders[i].getButton()); 109 | buttonHeld[i] = false; 110 | w = 0; 111 | encRotationBlocked = false; 112 | } 113 | } 114 | 115 | else if (delta != 0 && !encRotationBlocked) 116 | { 117 | if ((now - last[i]) < ACC_TIME) // Accelerate 1 118 | { 119 | callback(i, encoders[i].getValue(), delta * 3); 120 | } 121 | else if ((now - last[i]) < ACC_TIME2) // Accelerate 2 122 | { 123 | callback(i, encoders[i].getValue(), delta * 10); 124 | } 125 | else 126 | { 127 | callback(i, encoders[i].getValue(), delta); 128 | } 129 | last[i] = now; 130 | } 131 | 132 | if (encoders[i].getButton() == LOW && (millis() - btnStarttime[i]) > WINDOWTIME[w]) 133 | { 134 | buttonHeld[i] = true; 135 | btnStarttime[i] = millis(); 136 | // Acceleration of callbacks when button is held down 137 | if (w < 6) 138 | w++; 139 | if (w > 1) 140 | { 141 | btnCallback(i, HELD_REPEAT); // HELD REPEAT 142 | } 143 | else 144 | { 145 | btnCallback(i, HELD); // HELD ONCE 146 | } 147 | } 148 | } 149 | // Clock after first is read 150 | if (i > 0) 151 | { 152 | digitalWriteFast(CLK, LOW); 153 | delayNanoseconds(50); 154 | } 155 | } 156 | } 157 | 158 | } // namespace EncoderTool -------------------------------------------------------------------------------- /Momentum/EncoderTool/Multiplexed/EncPlexBase.cpp: -------------------------------------------------------------------------------- 1 | #include "EncPlexBase.h" 2 | 3 | namespace EncoderTool 4 | { 5 | EncPlexBase::EncPlexBase(unsigned eCnt) 6 | : encoderCount(eCnt) 7 | { 8 | encoders = new EncoderBase[eCnt]; 9 | } 10 | 11 | void EncPlexBase::begin(CountMode mode) 12 | { 13 | for (unsigned i = 0; i < encoderCount; i++) 14 | { 15 | encoders[i].setCountMode(mode); 16 | } 17 | } 18 | 19 | EncPlexBase::~EncPlexBase() 20 | { 21 | delete[] encoders; 22 | } 23 | 24 | EncoderBase &EncPlexBase::operator[](std::size_t idx) 25 | { 26 | return idx < encoderCount ? encoders[idx] : encoders[encoderCount - 1]; 27 | } 28 | 29 | void EncPlexBase::attachCallback(allCallback_t _callback) 30 | { 31 | callback = _callback; 32 | } 33 | 34 | void EncPlexBase::attachBtnCallback(allBtnCallback_t _btnCallback) 35 | { 36 | btnCallback = _btnCallback; 37 | } 38 | } // namespace EncoderTool -------------------------------------------------------------------------------- /Momentum/EncoderTool/Multiplexed/EncPlexBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../config.h" 4 | #include "../EncoderBase.h" 5 | 6 | namespace EncoderTool 7 | { 8 | class EncPlexBase 9 | { 10 | public: 11 | void attachCallback(allCallback_t callback); 12 | void attachBtnCallback(allBtnCallback_t btnCallback); 13 | EncoderBase &operator[](std::size_t idx); 14 | 15 | protected: 16 | EncPlexBase(unsigned EncoderCount); 17 | ~EncPlexBase(); 18 | 19 | void begin(CountMode mode = CountMode::quarter); 20 | void begin(allCallback_t, allBtnCallback_t, CountMode mode = CountMode::quarter); 21 | 22 | const uint32_t encoderCount; 23 | EncoderBase *encoders; 24 | 25 | allCallback_t callback = nullptr; 26 | allBtnCallback_t btnCallback = nullptr; 27 | 28 | // Encoder acceleration in millis 29 | uint32_t ACC_TIME = 15; 30 | uint32_t ACC_TIME2 = 7; 31 | uint32_t last[8] = {0}; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /Momentum/EncoderTool/config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // un-comment the following line if you prefer plain function pointers for callbacks 4 | // #define PLAIN_ENC_CALLBACK 5 | 6 | //================================================================================================================ 7 | 8 | #include 9 | 10 | #if not defined(PLAIN_ENC_CALLBACK) 11 | #include 12 | #endif 13 | 14 | namespace EncoderTool 15 | { 16 | #if defined(PLAIN_ENC_CALLBACK) 17 | using encCallback_t = void (*)(int32_t value, int32_t delta); 18 | using encBtnCallback_t = void (*)(int32_t state); 19 | 20 | using allCallback_t = void (*)(uint32_t channel, int32_t value, int32_t delta); 21 | using allBtnCallback_t = void (*)(int32_t state); 22 | #else 23 | using encCallback_t = std::function; // encoder value 24 | using encBtnCallback_t = std::function; // encoder button 25 | 26 | using allCallback_t = std::function; // all encoder values 27 | using allBtnCallback_t = std::function; // all encoder buttons 28 | #endif 29 | } -------------------------------------------------------------------------------- /Momentum/HWControls.h: -------------------------------------------------------------------------------- 1 | #include "ButtonTool/ButtonTool.h" 2 | using namespace ButtonTool; 3 | #include "EncoderTool/EncoderTool.h" 4 | using namespace EncoderTool; 5 | 6 | #include 7 | #include 8 | 9 | // Encoder Shift Register numbering 10 | #define ENC_TL 2 11 | #define ENC_BL 3 12 | #define ENC_TR 0 13 | #define ENC_BR 1 14 | 15 | // Because of the way the four encoders and ten buttons are arranged on three 74HC595 shift registers in parallel, these counts are not the same 16 | constexpr unsigned encoderCount = 8; // There are four arranged over three Shift Registers on the last four positions, hence all eight positions must be shifted to reach them. 17 | constexpr unsigned buttonCount = 12; // There are ten buttons, but arranged over three Shift Registers on the first four positions. The last four are skipped. 18 | 19 | // These are Teensy numbering on https://learn.sparkfun.com/tutorials/micromod-teensy-processor-hookup-guide/all 20 | constexpr unsigned srA = 40; // output pin QH of shift register Enc pin A 21 | constexpr unsigned srB = 41; // output pin QH of shift register Enc pin B 22 | constexpr unsigned srC = 42; // output pin QH of shift register Button 23 | constexpr unsigned pinLD = 45; // load pin for all shift registers 24 | constexpr unsigned pinCLK = 6; // clock pin for all shift registers 25 | 26 | constexpr unsigned latchPin = 26; // LEDs SR2 27 | constexpr unsigned clockPin = 9; // LEDs CLK2 28 | constexpr unsigned dataPinG = 44; // Green LEDs data 29 | constexpr unsigned dataPinR = 43; // Red LEDs data 30 | 31 | constexpr unsigned pinCD = 27; // Card detect 32 | 33 | uint8_t currentRLEDs = 0; 34 | uint8_t currentGLEDs = 0; 35 | 36 | EncPlex74165 encoders(encoderCount, pinLD, pinCLK, srB, srA, srC); 37 | ButtonPlex74165 buttons(buttonCount, pinLD, pinCLK, srB, srA, srC); 38 | 39 | void ledAnimation(long millis); 40 | 41 | constexpr unsigned BACKLIGHT = 24; // A10/I2C_SCL1 42 | 43 | typedef enum ledColour 44 | { 45 | RED, 46 | GREEN, 47 | OFF, 48 | } ledColour; 49 | 50 | // typedef enum controlParameter 51 | // { 52 | // control_noiseLevel, 53 | // control_pitchLfoRate, 54 | // control_pitchLfoWaveform, 55 | // control_pitchLfoAmount, 56 | // control_detune, 57 | // control_oscMix, 58 | // control_filterAttack, 59 | // control_filterDecay, 60 | // control_pwmAmountA, 61 | // control_waveformA, 62 | // control_pitchA, 63 | // control_pwmAmountB, 64 | // control_waveformB, 65 | // control_pitchB, 66 | // control_pwmRate, 67 | // control_pitchEnv, 68 | // control_attack, 69 | // control_decay, 70 | // control_sustain, 71 | // control_release, 72 | // control_filterLFOAmount, 73 | // control_FXMix, 74 | // control_FXAmount, 75 | // control_glide, 76 | // control_filterEnv, 77 | // control_filterRelease, 78 | // control_filterSustain, 79 | // control_filterType, 80 | // control_resonance, 81 | // control_cutoff, 82 | // control_filterLFORate, 83 | // control_filterLFOWaveform, 84 | // control_volume, 85 | // control_unison, 86 | // control_oscFX, 87 | // control_filterLFORetrig, 88 | // control_filterLFOMidiClkSync, 89 | // } controlParameter; 90 | 91 | const int16_t LED_TO_BIN[9] = {0, 1, 2, 4, 8, 16, 32, 64, 128}; // First value is dummy, LEDs are indexed 1-8 92 | 93 | // Shift both red and green LEDs - FOR 595s IN PARALLEL 94 | /* 95 | Red: 2.1V 9mA 96 | Green: 2.8V 1.5mA 97 | */ 98 | FLASHMEM void shiftOutParallel(uint8_t dataPinR, uint8_t dataPinG, uint8_t clockPin, uint8_t bitOrder, uint8_t valR, uint8_t valG) 99 | { 100 | for (uint8_t i = 0; i < 8; i++) 101 | { 102 | if (bitOrder == LSBFIRST) 103 | { 104 | digitalWrite(dataPinR, valR & 1); 105 | valR >>= 1; 106 | digitalWrite(dataPinG, valG & 1); 107 | valG >>= 1; 108 | } 109 | else 110 | { 111 | digitalWrite(dataPinR, (valR & 128) != 0); 112 | valR <<= 1; 113 | digitalWrite(dataPinG, (valG & 128) != 0); 114 | valG <<= 1; 115 | } 116 | 117 | digitalWrite(clockPin, HIGH); 118 | digitalWrite(clockPin, LOW); 119 | } 120 | } 121 | 122 | // ledNo starts at 1 123 | FLASHMEM void singleLED(ledColour color, int8_t ledNo) 124 | { 125 | digitalWrite(latchPin, LOW); 126 | switch (color) 127 | { 128 | case RED: 129 | shiftOutParallel(dataPinR, dataPinG, clockPin, MSBFIRST, LED_TO_BIN[ledNo], 0); 130 | currentRLEDs = ledNo; 131 | currentGLEDs = 0; 132 | break; 133 | case GREEN: 134 | shiftOutParallel(dataPinR, dataPinG, clockPin, MSBFIRST, 0, LED_TO_BIN[ledNo]); 135 | currentGLEDs = ledNo; 136 | currentRLEDs = 0; 137 | break; 138 | case OFF: 139 | shiftOutParallel(dataPinR, dataPinG, clockPin, MSBFIRST, 0, 0); 140 | currentRLEDs = 0; 141 | currentGLEDs = 0; 142 | break; 143 | } 144 | digitalWrite(latchPin, HIGH); 145 | } 146 | 147 | FLASHMEM void lightRGLEDs(int8_t ledRNos, int8_t ledGNos) 148 | { 149 | digitalWrite(latchPin, LOW); 150 | shiftOutParallel(dataPinR, dataPinG, clockPin, MSBFIRST, ledRNos, ledGNos); 151 | digitalWrite(latchPin, HIGH); 152 | } 153 | 154 | FLASHMEM void ledsOff() 155 | { 156 | lightRGLEDs(0, 0); 157 | currentRLEDs = 0; 158 | currentGLEDs = 0; 159 | } 160 | 161 | // ledNo starts at 1 162 | FLASHMEM void seqLED(ledColour color, int8_t ledNo) 163 | { 164 | if (color == RED) 165 | lightRGLEDs(LED_TO_BIN[ledNo] + LED_TO_BIN[currentRLEDs], LED_TO_BIN[currentGLEDs]); 166 | else 167 | lightRGLEDs(LED_TO_BIN[currentRLEDs], LED_TO_BIN[ledNo] + LED_TO_BIN[currentGLEDs]); 168 | } 169 | 170 | FLASHMEM void flashLED(ledColour color, int8_t ledNo, int duration) 171 | { 172 | if (color == RED) 173 | lightRGLEDs(LED_TO_BIN[ledNo] + LED_TO_BIN[currentRLEDs], LED_TO_BIN[currentGLEDs]); 174 | else 175 | lightRGLEDs(LED_TO_BIN[currentRLEDs], LED_TO_BIN[ledNo] + LED_TO_BIN[currentGLEDs]); 176 | delay(duration); 177 | lightRGLEDs(LED_TO_BIN[currentRLEDs], LED_TO_BIN[currentGLEDs]); 178 | } 179 | 180 | FLASHMEM void ledAnimation(long millis) 181 | { 182 | lightRGLEDs(24, 0); 183 | delay(millis); 184 | lightRGLEDs(36, 0); 185 | delay(millis); 186 | lightRGLEDs(66, 0); 187 | delay(millis); 188 | lightRGLEDs(129, 0); 189 | delay(millis); 190 | lightRGLEDs(0, 0); 191 | delay(millis); 192 | lightRGLEDs(0, 129); 193 | delay(millis); 194 | lightRGLEDs(0, 66); 195 | delay(millis); 196 | lightRGLEDs(0, 36); 197 | delay(millis); 198 | lightRGLEDs(0, 24); 199 | delay(millis); 200 | lightRGLEDs(0, 0); 201 | } 202 | 203 | FLASHMEM void sdCardInteruptRoutine() 204 | { 205 | detachInterrupt(pinCD); 206 | sdCardInterrupt = true; 207 | } 208 | 209 | FLASHMEM void setupHardware(EncoderTool::allCallback_t ec, EncoderTool::allBtnCallback_t ebc, ButtonTool::allBtnCallback_t bc) 210 | { 211 | pinMode(latchPin, OUTPUT); 212 | pinMode(clockPin, OUTPUT); 213 | pinMode(dataPinG, OUTPUT); 214 | pinMode(dataPinR, OUTPUT); 215 | 216 | encoders.begin(CountMode::full); 217 | encoders.attachCallback(ec); 218 | encoders.attachBtnCallback(ebc); 219 | 220 | buttons.begin(bc); 221 | 222 | ledAnimation(50); 223 | 224 | pinMode(pinCD, INPUT_PULLUP); 225 | attachInterrupt(digitalPinToInterrupt(pinCD), sdCardInteruptRoutine, CHANGE); 226 | 227 | // Display backlight - Can be used to turn off or dim using PWM 228 | // Not used but you never know 229 | // pinMode(BACKLIGHT, OUTPUT); 230 | } -------------------------------------------------------------------------------- /Momentum/Keyboard.cpp: -------------------------------------------------------------------------------- 1 | #include "Keyboard.h" 2 | #include "Arduino.h" 3 | 4 | const char *SCALE_STR[24] PROGMEM = {"C maj", "C min", "C# maj", "C# min", 5 | "D maj", "D min", "D# maj", "D# min", 6 | "E maj", "E min", 7 | "F maj", "F min", "F# maj", "F# min", 8 | "G maj", "G min", "G# maj", "G# min", 9 | "A maj", "A min", "A# maj", "A# min", 10 | "B maj", "B min"}; 11 | 12 | const uint8_t SCALE_STEPS[2][8] = {{0, 2, 4, 5, 7, 9, 11, 12}, // Maj 13 | {0, 2, 3, 5, 7, 8, 10, 12}}; // Min 14 | 15 | const char *KEYBOARD_OCT_STR[7] = {"3 Below", "2 Below", "1 Below", "Middle Oct", "1 Above", "2 Above", "3 Above"}; -------------------------------------------------------------------------------- /Momentum/Keyboard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef enum MajMin 6 | { 7 | MAJOR = 0, 8 | MINOR = 1 9 | } MajMin; 10 | 11 | extern const char *SCALE_STR[24]; 12 | extern const uint8_t SCALE_STEPS[2][8]; 13 | 14 | extern const char *KEYBOARD_OCT_STR[7]; -------------------------------------------------------------------------------- /Momentum/MidiCC.h: -------------------------------------------------------------------------------- 1 | // MIDI CC control numbers 2 | // These broadly follow standard CC assignments 3 | #define CCbankselectMSB 0 4 | #define CCmodwheel 1 // pitch LFO amount and filter mod amount 5 | #define CCosclfoamt 3 // pitch LFO amount - panel control 6 | #define CCglide 5 7 | #define CCvolume 7 8 | #define CCoscwaveformA 14 9 | #define CCoscwaveformB 15 10 | #define CCfilterenv 16 11 | #define CCfiltermixer 19 12 | #define CCoscLevelA 20 13 | #define CCoscLevelB 21 14 | #define CCnoiseLevel 23 15 | #define CCoscfx 24 16 | #define CCpitchA 26 17 | #define CCpitchB 27 18 | #define CCpitchenv 28 19 | #define CCosclforetrig 30 // Off/On 20 | #define CCfilterlforetrig 31 // Off/On 21 | #define CCbankselectLSB 32 22 | #define CCfilterres 71 23 | #define CCamprelease 72 24 | #define CCampattack 73 25 | #define CCfilterfreq 74 26 | #define CCampdecay 75 27 | #define CCfilterlforate 76 28 | #define CCfilterlfoamt 77 29 | #define CCampsustain 79 30 | #define CCfilterattack 80 31 | #define CCfilterdecay 81 32 | #define CCfiltersustain 82 33 | #define CCfilterrelease 83 34 | #define CCpwA 85 35 | #define CCpwB 86 36 | #define CCpwmRateA 87 37 | #define CCpwmAmtA 88 38 | #define CCkeytracking 89 39 | #define CCfilterlfowaveform 90 40 | #define CCensemblefxamt 91 41 | #define CCensemblefxmix 93 42 | #define CCdetune 94 43 | #define CCpwmAmtB 95 44 | #define CCpwmRateB 96 45 | #define CCreverbfxtime 97 46 | #define CCreverbfxmix 98 47 | #define CCoscLfoRate 102 48 | #define CCoscLfoWaveform 103 49 | #define CCfilterLFOMidiClkSync 104 // Off/On 50 | #define CCoscLFOMidiClkSync 105 // Off/On 51 | #define CCpwmSourceA 106 // Osc1 LFO/Filter Env 52 | #define CCunison 107 53 | #define CCpwmSourceB 108 // Osc2 LFO/Filter Env 54 | #define CCvelocitySens 109 // Velocity sensitivity 55 | #define CCFilterVelocitySens 110 // Filter Velocity sensitivity 56 | #define CCallnotesoff 123 // Panic button includes sound off 57 | #define CCmonomode 126 58 | 59 | /* 60 | 0 Bank Select (MSB) 61 | 1 Modulation Wheel 62 | 2 Breath controller 63 | 3 = Undefined 64 | 4 Foot Pedal (MSB) 65 | 5 Portamento Time (MSB) 66 | 6 Data Entry (MSB) 67 | 7 Volume (MSB) 68 | 8 Balance (MSB 69 | 9 = Undefined 70 | 10 Pan position (MSB) 71 | 11 Expression (MSB) 72 | 12 Effect Control 1 (MSB) 73 | 13 Effect Control 2 (MSB) 74 | 14 = Undefined 75 | 15 = Undefined 76 | 16-19 = General Purpose 77 | 20-31 = Undefined 78 | 32-63 = Controller 0-31 79 | 64 Hold Pedal (on/off) 80 | 65 Portamento (on/off) 81 | 66 Sostenuto Pedal (on/off) 82 | 67 Soft Pedal (on/off) 83 | 68 Legato Pedal (on/off) 84 | 69 Hold 2 Pedal (on/off) 85 | 70 Sound Variation 86 | 71 Resonance (Timbre) 87 | 72 Sound Release Time 88 | 73 Sound Attack Time 89 | 74 Frequency Cutoff (Brightness) 90 | 75 Sound Control 6 91 | 76 Sound Control 7 92 | 77 Sound Control 8 93 | 78 Sound Control 9 94 | 79 Sound Control 10 95 | 80 Decay or General Purpose Button 1 (on/off) Roland Tone level 1 96 | 81 Hi Pass Filter Frequency or General Purpose Button 2 (on/off) Roland Tone level 2 97 | 82 General Purpose Button 3 (on/off) Roland Tone level 3 98 | 83 General Purpose Button 4 (on/off) Roland Tone level 4 99 | 84 Portamento Amount 100 | 85-90 = Undefined 101 | 91 Reverb Level 102 | 92 Tremolo Level 103 | 93 Chorus Level 104 | 94 Detune Level 105 | 95 Phaser Level 106 | 96 Data Button increment 107 | 97 Data Button decrement 108 | 98 Non-registered Parameter (LSB) 109 | 99 Non-registered Parameter (MSB) 110 | 100 Registered Parameter (LSB) 111 | 101 Registered Parameter (MSB) 112 | 102-119 = Undefined 113 | 120 All Sound Off 114 | 121 All Controllers Off 115 | 122 Local Keyboard (on/off) 116 | 123 All Notes Off 117 | 124 Omni Mode Off 118 | 125 Omni Mode On 119 | 126 Mono Operation 120 | 127 Poly Mode 121 | 122 | */ -------------------------------------------------------------------------------- /Momentum/Momentum.ino: -------------------------------------------------------------------------------- 1 | /* 2 | For Arduino IDE 3 | */ -------------------------------------------------------------------------------- /Momentum/MonoNoteHistory.cpp: -------------------------------------------------------------------------------- 1 | #include "MonoNoteHistory.h" 2 | 3 | MonoNoteHistory::MonoNoteHistory(): 4 | numElements(0){ 5 | } 6 | 7 | // Drop element at index, shift everything else down. 8 | void shiftDataFrom(uint8_t index, uint8_t numElements, MonoNoteHistory::Element data[MAX_NOTE_HISTORY]) { 9 | for(uint8_t cur = index; (cur+1) < numElements; cur++) { 10 | data[cur] = data[cur+1]; 11 | } 12 | } 13 | 14 | void MonoNoteHistory::push(uint8_t note, uint8_t velocity) { 15 | if (numElements == MAX_NOTE_HISTORY) { 16 | shiftDataFrom(0, numElements, data); 17 | numElements--; 18 | } 19 | data[numElements++] = Element{note, velocity}; 20 | } 21 | 22 | void MonoNoteHistory::clear() { 23 | numElements = 0; 24 | } 25 | 26 | MonoNoteHistory::Element MonoNoteHistory::getLast() { 27 | Element result = data[numElements-1]; 28 | return result; 29 | } 30 | 31 | MonoNoteHistory::Element MonoNoteHistory::getFirst() { 32 | Element result = data[0]; 33 | return result; 34 | } 35 | 36 | MonoNoteHistory::Element MonoNoteHistory::getHighest() { 37 | uint8_t highest = 0; 38 | for (int cur = 1; cur < size(); cur++) { 39 | if (data[cur].note > data[highest].note) { 40 | highest = cur; 41 | } 42 | } 43 | return data[highest]; 44 | } 45 | 46 | MonoNoteHistory::Element MonoNoteHistory::getLowest() { 47 | uint8_t highest = 0; 48 | for (uint8_t cur = 1; cur < size(); cur++) { 49 | if (data[cur].note < data[highest].note) { 50 | highest = cur; 51 | } 52 | } 53 | return data[highest]; 54 | } 55 | 56 | int MonoNoteHistory::size() { 57 | return numElements; 58 | } 59 | 60 | void MonoNoteHistory::erase(uint8_t note) { 61 | for (uint8_t cur = 0; cur < size(); cur++) { 62 | if (data[cur].note == note) { 63 | shiftDataFrom(cur, size(), data); 64 | numElements--; 65 | cur--; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Momentum/MonoNoteHistory.h: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a special data structure that stores notes for monophonic access. 3 | * It maintains a stack/queue for LIFO/FIFO access, and also provides getters 4 | * for access by highest/lowest note. Finally, notes at any index can be 5 | * removed. 6 | */ 7 | #ifndef MONONOTEHISTORY_H 8 | #define MONONOTEHISTORY_H 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #define MAX_NOTE_HISTORY 20 15 | 16 | class MonoNoteHistory { 17 | public: 18 | struct Element { 19 | uint8_t note; 20 | uint8_t velocity; 21 | }; 22 | 23 | MonoNoteHistory(); 24 | 25 | // Remove everything from the note stack. 26 | void clear(); 27 | 28 | // Number of notes in history. 29 | int size(); 30 | 31 | // Add notes to history. 32 | void push(uint8_t note, uint8_t velocity); 33 | 34 | // Erase note from history. 35 | void erase(uint8_t note); 36 | 37 | // Get the last note (most recently played). 38 | Element getLast(); 39 | // Get the first note (oldest played). 40 | Element getFirst(); 41 | // Get the highest note. 42 | Element getHighest(); 43 | // Get the loweset note. 44 | Element getLowest(); 45 | 46 | private: 47 | uint8_t numElements; 48 | Element data[MAX_NOTE_HISTORY]; 49 | }; 50 | 51 | #endif -------------------------------------------------------------------------------- /Momentum/Oscilloscope.h: -------------------------------------------------------------------------------- 1 | #ifndef Oscilloscope_h_ 2 | #define Oscilloscope_h_ 3 | #include "AudioStream.h" 4 | #include "ILI9341_t3n.h" 5 | 6 | uint8_t bufferBlock = 0; 7 | uint8_t bufcount = 0; 8 | uint8_t pixel_x = 0; 9 | int16_t pixel_y = 0; 10 | int16_t prev_pixel_y = 0; 11 | 12 | class Oscilloscope : public AudioStream { 13 | public: 14 | Oscilloscope(void) : AudioStream(1, inputQueueArray) { 15 | } 16 | virtual void update(void); 17 | void ScreenSetup(ILI9341_t3n*); 18 | void Display(void); 19 | void AddtoBuffer(int16_t*); 20 | 21 | private: 22 | audio_block_t *inputQueueArray[1]; 23 | ILI9341_t3n *display; 24 | int16_t buffer[AUDIO_BLOCK_SAMPLES]; 25 | }; 26 | #endif 27 | 28 | FLASHMEM void Oscilloscope::ScreenSetup(ILI9341_t3n *screen) 29 | { 30 | display = screen; 31 | } 32 | 33 | void Oscilloscope::Display() 34 | { 35 | pixel_x = 0; 36 | prev_pixel_y = map(buffer[0], 32767, -32768, -120, 120) + 200; 37 | if (prev_pixel_y < 167) 38 | prev_pixel_y = 167; 39 | if (prev_pixel_y > 237) 40 | prev_pixel_y = 237; 41 | 42 | for (uint8_t i = 0; i < AUDIO_BLOCK_SAMPLES - 1; i++) 43 | { 44 | pixel_y = map(buffer[i], 32767, -32768, -120, 120) + 200; 45 | if (pixel_y < 167) 46 | pixel_y = 167; 47 | if (pixel_y > 237) 48 | pixel_y = 237; 49 | display->drawLine(pixel_x + 96, prev_pixel_y, pixel_x + 97, pixel_y, 0x07B0);//Orange 50 | prev_pixel_y = pixel_y; 51 | pixel_x++; 52 | } 53 | } 54 | 55 | void Oscilloscope::AddtoBuffer(int16_t *audio) 56 | { 57 | audio++; 58 | if (bufferBlock == 0) 59 | { 60 | if (*(audio - 1) > -16 && *(audio + 3) < 16) 61 | { 62 | bufferBlock = 1; 63 | bufcount = 0; 64 | } 65 | } 66 | else 67 | { 68 | for (uint16_t i = 0; i < 32; i++) 69 | { 70 | buffer[bufcount++] = *audio; 71 | audio += 4; 72 | } 73 | bufferBlock++; 74 | if (bufferBlock >= 5) 75 | { 76 | bufferBlock = 0; 77 | } 78 | } 79 | } 80 | 81 | void Oscilloscope::update(void) 82 | { 83 | if (!display) 84 | return; 85 | audio_block_t *block; 86 | block = receiveReadOnly(0); 87 | if (block) 88 | { 89 | AddtoBuffer(block->data); 90 | release(block); 91 | if (bufferBlock == 0) 92 | { 93 | Display(); 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /Momentum/Parameters.cpp: -------------------------------------------------------------------------------- 1 | #include "Parameters.h" 2 | #include "Constants.h" 3 | 4 | // Values below are just for initialising and will be changed when synth is initialised to current panel controls & EEPROM settings 5 | 6 | // Globals used for Settings 7 | byte midiChannel = MIDI_CHANNEL_OMNI; //(EEPROM) 8 | byte midiOutCh = 0; //(EEPROM) 9 | midi::Thru::Mode MIDIThru = midi::Thru::Off; //(EEPROM) 10 | String patchName = INITPATCHNAME; 11 | boolean encCW = true; // This is to set the encoder to increment when turned CW - Settings Option 12 | boolean vuMeter = false; 13 | boolean sendCC = false; 14 | int8_t tuningCents = 0; 15 | float tuningCentsFrac = 1.0f; 16 | boolean syncToMIDIClk = false; 17 | 18 | float lfoSyncFreq = 1.0f; 19 | float lfoFilterTempoValue = 1.0f; 20 | float lfoPitchTempoValue = 1.0f; 21 | 22 | // Exponential envelopes 23 | int8_t envTypeAmp = -128; // Linear 24 | int8_t envTypeFilt = -128; // Linear 25 | // Glide shape 26 | int8_t glideShape = 1; // Exp 27 | 28 | uint8_t currentVolume = 63; 29 | 30 | int8_t charCursor = 0; 31 | int8_t nameCursor = 0; -------------------------------------------------------------------------------- /Momentum/Parameters.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | // Globals used for Settings 7 | extern byte midiChannel; 8 | extern byte midiOutCh; 9 | extern midi::Thru::Mode MIDIThru; 10 | extern String patchName; 11 | extern boolean encCW; 12 | extern boolean vuMeter; 13 | extern boolean sendCC; 14 | extern boolean syncToMIDIClk; 15 | extern int8_t tuningCents; 16 | extern float tuningCentsFrac; 17 | 18 | // Global patch modifiers 19 | extern float lfoSyncFreq; 20 | extern float lfoFilterTempoValue; 21 | extern float lfoPitchTempoValue; 22 | 23 | // Exponential envelopes 24 | extern int8_t envTypeAmp; 25 | extern int8_t envTypeFilt; 26 | // Glide shape 27 | extern int8_t glideShape; 28 | 29 | extern uint8_t currentVolume; 30 | 31 | extern int8_t charCursor; 32 | extern int8_t nameCursor; 33 | 34 | // extern uint8_t currentSettingsOption; 35 | // extern uint8_t currentSettingsValue; 36 | 37 | // *** Patch parameters to store the relative 7-bit values (Cutoff freq 8-bit) for patch store and modification by the encoders *** 38 | // *** Initialised with a default patch to store when there are no patches on SD card *** 39 | typedef struct PatchStruct 40 | { 41 | uint32_t UID = 0; 42 | char PatchName[64] = "Init"; // INITPATCHNAME; 43 | uint8_t OscLevelA = 127; 44 | uint8_t OscLevelB = 127; 45 | uint8_t NoiseLevel = 63; // Centre off 46 | uint8_t Unison = 0; 47 | uint8_t OscFX = 0; 48 | uint8_t Detune = 20; // 0.15% 49 | uint8_t KeyTracking = 63; // Half tracking, 0.5 50 | uint8_t Glide = 0; 51 | uint8_t PitchA = 0; //-24 52 | uint8_t PitchB = 8; //-12 53 | uint8_t WaveformA = 75; // Pulse 54 | uint8_t WaveformB = 75; // Pulse 55 | uint8_t PWMSourceA = 0; 56 | uint8_t PWMSourceB = 0; 57 | uint8_t PWMA_Amount = 63; // 0.50 58 | uint8_t PWMB_Amount = 63; // 0.50 59 | uint8_t PWMRateA = 10; // 0.18Hz 60 | uint8_t PWMRateB = 10; // 0.18Hz 61 | uint8_t PWA_Amount = 63; 62 | uint8_t PWB_Amount = 63; 63 | uint8_t FilterRes = 0; // 0.71 64 | uint8_t FilterFreq = 255; // 12000Hz 65 | uint8_t FilterMixer = 0; 66 | uint8_t FilterEnv = 63; 67 | uint8_t PitchLFOAmt = 0; 68 | uint8_t PitchLFORate = 10; 69 | uint8_t PitchLFOWaveform = 0; 70 | uint8_t PitchLFORetrig = 0; 71 | uint8_t PitchLFOMidiClkSync = 0; 72 | uint8_t FilterLFORate = 10; 73 | uint8_t FilterLFORetrig = 0; 74 | uint8_t FilterLFOMidiClkSync = 0; 75 | uint8_t FilterLfoAmt = 0; 76 | uint8_t FilterLFOWaveform = 0; 77 | uint8_t FilterAttack = 0; 78 | uint8_t FilterDecay = 20; 79 | uint8_t FilterSustain = 80; 80 | uint8_t FilterRelease = 25; 81 | uint8_t Attack = 0; 82 | uint8_t Decay = 20; 83 | uint8_t Sustain = 80; 84 | uint8_t Release = 25; 85 | uint8_t EnsembleEffectAmt = 8; 86 | uint8_t EnsembleEffectMix = 31; 87 | uint8_t ReverbEffectTime = 8; 88 | uint8_t ReverbEffectMix = 0; 89 | uint8_t PitchEnv = 63; // Centre off 90 | uint8_t VelocitySensitivity = 0; 91 | uint8_t FilterVelocitySensitivity = 0; 92 | uint8_t ChordDetune = 0; 93 | uint8_t MonophonicMode = 0; 94 | uint8_t FilterEnvShape = 9; // Exp 0 95 | uint8_t AmpEnvShape = 9; // Exp 0 96 | uint8_t GlideShape = 1; // Exp 97 | uint8_t PitchBend = 7; 98 | uint8_t PitchModWheelDepth = 1; 99 | uint8_t FilterModWheelDepth = 0; 100 | } PatchStruct; -------------------------------------------------------------------------------- /Momentum/PerformanceMgr.h: -------------------------------------------------------------------------------- 1 | // Janelia Array available in libraries manager 2 | #include 3 | #include "Constants.h" 4 | #include "Utils.h" 5 | #include 6 | 7 | uint8_t currentPerformanceIndex = 0; 8 | 9 | typedef struct PatchesInPerfStruct 10 | { 11 | uint8_t bankIndex = 0; 12 | uint32_t UID = 0; 13 | String patchName = ""; 14 | uint8_t midiCh = 0; 15 | uint8_t midiChOut = 0; 16 | midi::Thru::Mode midiThru = midi::Thru::Off; 17 | uint8_t min = 0; 18 | uint8_t max = 127; 19 | } PatchesInPerfStruct; 20 | 21 | typedef enum PerformanceMode 22 | { 23 | Single, 24 | Layer, // NOT USED - Requires multitimbral functionality to be finished 25 | Split // NOT USED - Requires multitimbral functionality to be finished 26 | } PerformanceMode; 27 | 28 | typedef struct PerformanceStruct 29 | { 30 | String performanceName = EMPTYNAME; 31 | PerformanceMode mode = PerformanceMode::Single; 32 | Array patches; 33 | uint8_t TL = noencoder; 34 | uint8_t TR = noencoder; 35 | uint8_t BL = noencoder; 36 | uint8_t BR = noencoder; 37 | } PerformanceStruct; 38 | 39 | PerformanceStruct currentPerformance; 40 | 41 | String performances[PERFORMANCES_LIMIT]; 42 | 43 | FLASHMEM void concatPerformanceFolderAndFilename(uint32_t filename, char *result) 44 | { 45 | char buf[20]; 46 | strcpy(result, PERFORMANCE_FOLDER_NAME_SLASH); // copy string one into the result. 47 | strcat(result, utoa(filename, buf, 10)); // append string two to the result 48 | } 49 | 50 | // Performancename from a files and return it 51 | FLASHMEM char *getPerformanceName(File file) 52 | { 53 | // Allocate a temporary JsonDocument 54 | // Don't forget to change the capacity to match your requirements. 55 | // Use https://arduinojson.org/v6/assistant to compute the capacity. 56 | StaticJsonDocument<2048> doc; 57 | 58 | // Deserialize the JSON document 59 | DeserializationError error = deserializeJson(doc, file); 60 | if (error) 61 | { 62 | if (DEBUG) 63 | Serial.println(F("getPerformanceName() - Failed to read file")); 64 | return "Failed to read file"; 65 | } 66 | // Copy values from the JsonDocument to the PerformanceStruct 67 | return doc["PerformanceName"]; 68 | } 69 | 70 | FLASHMEM void loadPerformanceNames() 71 | { 72 | if (!cardStatus) 73 | return; 74 | File performanceDir = SD.open(PERFORMANCE_FOLDER_NAME_SLASH); 75 | File performanceFile; 76 | for (uint8_t i = 0; i < PERFORMANCES_LIMIT; i++) 77 | { 78 | performances[i] = {EMPTYNAME}; 79 | } 80 | 81 | while (performanceFile = performanceDir.openNextFile()) 82 | { 83 | if (!performanceFile) 84 | break; 85 | uint8_t number = strtoul(performanceFile.name(), NULL, 0); 86 | if (number < 1 || number > 128) 87 | { 88 | if (DEBUG) 89 | Serial.print(F("Performance number is outside 1-128:")); 90 | if (DEBUG) 91 | Serial.println(number); 92 | } 93 | else 94 | { 95 | performances[number - 1] = getPerformanceName(performanceFile); 96 | } 97 | } 98 | performanceFile.close(); 99 | } 100 | 101 | // Filename is index +1 (1-128) 102 | FLASHMEM boolean loadPerformance(uint8_t filename) 103 | { 104 | // Initial empty 105 | PerformanceStruct ps; 106 | currentPerformance = ps; 107 | if (!cardStatus) 108 | return false; 109 | 110 | // Open file for reading - Filename is index +1 (1-128) 111 | char result[30]; 112 | concatPerformanceFolderAndFilename(filename, result); 113 | File file = SD.open(result); 114 | 115 | if (!file) 116 | { 117 | if (DEBUG) 118 | Serial.println(F("Performance file not found:") + String(filename)); 119 | file.close(); 120 | return false; 121 | } 122 | 123 | // Allocate a temporary JsonDocument 124 | // Don't forget to change the capacity to match your requirements. 125 | // Use https://arduinojson.org/v6/assistant to compute the capacity. 126 | StaticJsonDocument<512> doc; 127 | 128 | // Deserialize the JSON document 129 | DeserializationError error = deserializeJson(doc, file); 130 | if (error) 131 | { 132 | if (DEBUG) 133 | Serial.print(F("loadPerformance() - Failed to read file:")); 134 | if (DEBUG) 135 | Serial.println(filename); 136 | return false; 137 | } 138 | // Copy values from the JsonDocument to the PerformanceStruct 139 | currentPerformance.performanceName = doc["PerformanceName"].as(); 140 | currentPerformance.mode = doc["Mode"]; 141 | JsonObject Encoders = doc["Encoders"]; 142 | currentPerformance.TL = Encoders["TL"]; 143 | currentPerformance.TR = Encoders["TR"]; 144 | currentPerformance.BL = Encoders["BL"]; 145 | currentPerformance.BR = Encoders["BR"]; 146 | 147 | uint8_t i = 0; 148 | for (JsonObject P : doc["Patches"].as()) 149 | { 150 | currentPerformance.patches[i].bankIndex = P["Bank"]; 151 | currentPerformance.patches[i].UID = P["UID"]; 152 | currentPerformance.patches[i].patchName = getPatchName(currentPerformance.patches[i].bankIndex, currentPerformance.patches[i].UID); 153 | currentPerformance.patches[i].midiCh = P["MidiChIn"]; 154 | currentPerformance.patches[i].midiChOut = P["MidiChOut"]; 155 | currentPerformance.patches[i].midiThru = P["MidiThru"]; 156 | currentPerformance.patches[i].min = P["Min"]; 157 | currentPerformance.patches[i].max = P["Max"]; 158 | i++; 159 | } 160 | file.close(); 161 | return true; 162 | } 163 | 164 | FLASHMEM void savePerformance() 165 | { 166 | if (!cardStatus) 167 | return; 168 | // Delete existing performance 169 | char resultdel[30]; 170 | concatPerformanceFolderAndFilename(currentPerformanceIndex + 1, resultdel); 171 | SD.remove(resultdel); 172 | 173 | StaticJsonDocument<1024> doc; 174 | doc["PerformanceName"] = currentPerformance.performanceName; 175 | doc["Mode"] = currentPerformance.mode; 176 | 177 | JsonArray Patches = doc.createNestedArray("Patches"); 178 | 179 | JsonObject Patches_0 = Patches.createNestedObject(); 180 | Patches_0["Bank"] = currentPerformance.patches[0].bankIndex; 181 | Patches_0["UID"] = currentPerformance.patches[0].UID; 182 | Patches_0["MidiChIn"] = currentPerformance.patches[0].midiCh; 183 | Patches_0["MidiChOut"] = currentPerformance.patches[0].midiChOut; 184 | Patches_0["MidiThru"] = currentPerformance.patches[0].midiThru; 185 | Patches_0["Min"] = currentPerformance.patches[0].min; 186 | Patches_0["Max"] = currentPerformance.patches[0].max; 187 | 188 | // NOT USED Multimbrality isn't supported yet 189 | JsonObject Patches_1 = Patches.createNestedObject(); 190 | Patches_1["Bank"] = currentPerformance.patches[1].bankIndex; 191 | Patches_1["UID"] = currentPerformance.patches[1].UID; 192 | Patches_1["MidiChIn"] = currentPerformance.patches[1].midiCh; 193 | Patches_1["MidiChOut"] = currentPerformance.patches[1].midiChOut; 194 | Patches_1["MidiThru"] = currentPerformance.patches[1].midiThru; 195 | Patches_1["Min"] = currentPerformance.patches[1].min; 196 | Patches_1["Max"] = currentPerformance.patches[1].max; 197 | 198 | JsonObject Encoders = doc.createNestedObject("Encoders"); 199 | Encoders["TL"] = currentPerformance.TL; 200 | Encoders["TR"] = currentPerformance.TR; 201 | Encoders["BL"] = currentPerformance.BL; 202 | Encoders["BR"] = currentPerformance.BR; 203 | 204 | // Need to generate a new UID as the performance settings may have changed if overwriting an existing performance 205 | String output; 206 | serializeJson(doc, output); // Generate JSON without UID 207 | 208 | char result[30]; 209 | concatPerformanceFolderAndFilename(currentPerformanceIndex + 1, result); 210 | SD.remove(result); // Delete Performance file 211 | File file = SD.open(result, FILE_WRITE); 212 | if (!file) 213 | { 214 | if (DEBUG) 215 | Serial.println(F("Failed to create file")); 216 | return; 217 | } 218 | if (serializeJson(doc, file) == 0) 219 | { 220 | if (DEBUG) 221 | Serial.println(F("Failed to write to file")); 222 | return; 223 | } 224 | if (DEBUG) 225 | Serial.println(F("Save Performance:") + String(currentPerformanceIndex + 1)); 226 | } 227 | 228 | FLASHMEM void deletePerformance(uint8_t filename) 229 | { 230 | if (!cardStatus) 231 | return; 232 | char result[30]; 233 | concatPerformanceFolderAndFilename(filename, result); 234 | if (!SD.remove(result)) 235 | { 236 | // Performance missing 237 | if (DEBUG) 238 | Serial.print(F("Performance Missing:")); 239 | if (DEBUG) 240 | Serial.println(filename); 241 | } 242 | loadPerformanceNames(); 243 | } 244 | 245 | FLASHMEM uint8_t incPerformanceIndex() 246 | { 247 | if (currentPerformanceIndex < PERFORMANCES_LIMIT - 1) 248 | { 249 | return ++currentPerformanceIndex; 250 | } 251 | else 252 | { 253 | // Go back to Start from front of array 254 | currentPerformanceIndex = 0; 255 | return currentPerformanceIndex; 256 | } 257 | } 258 | 259 | FLASHMEM uint8_t decPerformanceIndex() 260 | { 261 | if (currentPerformanceIndex > 0) 262 | { 263 | return --currentPerformanceIndex; 264 | } 265 | else 266 | { 267 | // Go to back of array 268 | currentPerformanceIndex = PERFORMANCES_LIMIT - 1; 269 | return currentPerformanceIndex; 270 | } 271 | } -------------------------------------------------------------------------------- /Momentum/Sequencer.h: -------------------------------------------------------------------------------- 1 | /* 2 | This code is taken from: 3 | 4 | MicroDexed - https://codeberg.org/positionhigh/MicroDexed-touch 5 | 6 | MicroDexed is a port of the Dexed sound engine 7 | (https://github.com/asb2m10/dexed) for the Teensy-3.5/3.6/4.x with audio shield. 8 | Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android 9 | 10 | (c)2018-2022 H. Wirtz 11 | (c)2021-2022 H. Wirtz , M. Koslowski 12 | 13 | This program is free software; you can redistribute it and/or modify 14 | it under the terms of the GNU General Public License as published by 15 | (at your option) any later version. 16 | 17 | This program is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU General Public License for more details. 21 | 22 | You should have received a copy of the GNU General Public License 23 | along with this program; if not, write to the Free Software Foundation, 24 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 25 | */ 26 | #ifndef Sequencer_h_ 27 | #define Sequencer_h_ 28 | #include "Parameters.h" 29 | 30 | #define NUM_SEQ_TRACKS 6 31 | #define NUM_SEQ_PATTERN 10 32 | #define FILENAME_LEN 20 33 | 34 | // 1 = Instrumenttrack, 2 = Chord, 3 = Arp 35 | typedef enum TrackType 36 | { 37 | INSTRUMENT = 1, 38 | CHORD = 2, 39 | ARP = 3 40 | } TrackType; 41 | 42 | typedef struct sequencer_t 43 | { 44 | bool midi_learn_active = false; 45 | uint8_t active_track = 0; 46 | uint8_t menu; 47 | bool noteoffsent[NUM_SEQ_TRACKS] = {false, false, false, false, false, false}; 48 | uint8_t inst_dexed[NUM_SEQ_TRACKS] = {0, 0, 1, 1, 1, 1}; 49 | uint8_t step = 0; 50 | bool running = false; 51 | bool recording = false; 52 | bool smartfilter = true; 53 | uint8_t state_last_loadsave = 200; 54 | char name[FILENAME_LEN]; 55 | char name_temp[FILENAME_LEN]; 56 | uint8_t note_in; 57 | uint8_t note_in_velocity; 58 | int transpose; 59 | 60 | uint8_t chord_dexed_inst = 0; 61 | uint8_t chord_velocity = 60; 62 | uint8_t chord_key_ammount = 4; 63 | uint8_t element_shift = 0; 64 | int oct_shift = 0; 65 | uint8_t arp_style = 0; // up, down, up&down, random 66 | 67 | const uint8_t arps[6][23] = { 68 | {0, 4, 7, 12, 16, 19, 24, 28, 31, 36, 40, 43, 48, 52, 55, 60, 64, 67, 72, 76, 79, 84, 0}, // major 69 | {0, 3, 7, 12, 15, 19, 24, 27, 31, 36, 39, 43, 48, 51, 55, 60, 63, 67, 72, 75, 79, 84, 0}, // minor 70 | {0, 4, 7, 10, 12, 16, 19, 22, 24, 28, 31, 34, 36, 40, 43, 46, 48, 52, 55, 58, 60, 64, 0}, // seventh 71 | {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 0}, // augmented 72 | {0, 3, 6, 12, 15, 18, 24, 27, 30, 36, 39, 42, 48, 51, 54, 60, 63, 66, 72, 75, 78, 84, 0}, // dim 73 | {0, 4, 7, 11, 12, 16, 19, 23, 24, 28, 31, 35, 36, 40, 43, 47, 48, 52, 55, 59, 60, 64, 0} // maj7 74 | }; 75 | 76 | const char chord_names[7][4] = { 77 | {'M', 'a', 'j', ' '}, // major 78 | {'M', 'i', 'n', ' '}, 79 | {'s', 'e', 'v', ' '}, 80 | {'a', 'u', 'g', ' '}, 81 | {'d', 'i', 'm', ' '}, 82 | {'M', 'a', 'j', '7'}, 83 | {'N', 'o', 'C', 'd'}}; 84 | 85 | const char arp_style_names[4][3] = { 86 | {'u', 'p', ' '}, 87 | {'d', 'w', 'n'}, 88 | {'u', '&', 'd'}, 89 | {'R', 'N', 'D'}}; 90 | int tempo_ms = 180000; 91 | int bpm = 120; 92 | uint8_t temp_select_menu; 93 | uint8_t temp_active_menu = 99; 94 | uint8_t chain_active_chainstep; 95 | uint8_t chain_length = 3; // 0 = 16 steps, 1 = 32 Steps, 2 = 46 Steps, 3 = 64 Steps 96 | uint8_t chain_active_step = 0; 97 | uint8_t prev_note[NUM_SEQ_TRACKS]; // note_offs for every (instr.) track 98 | uint8_t prev_vel[NUM_SEQ_TRACKS]; 99 | uint8_t arp_step; 100 | uint8_t arp_note; 101 | uint8_t arp_chord = 6; 102 | bool arp_play_basenote = true; 103 | uint8_t arp_note_prev; 104 | uint8_t arp_octave; 105 | uint8_t arp_prev_oct; 106 | uint8_t arp_speed = 0; 107 | uint8_t arp_counter = 0; 108 | uint8_t arp_length = 8; 109 | uint8_t data_buffer[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 110 | uint8_t note_data[NUM_SEQ_PATTERN][16] = { 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 | uint8_t vel[NUM_SEQ_PATTERN][16] = { 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 | 133 | uint8_t patternchain[4][NUM_SEQ_TRACKS] = { 134 | {0, 2, 6, 9, 99, 99}, 135 | {1, 2, 5, 8, 99, 99}, 136 | {0, 2, 6, 9, 99, 99}, 137 | {1, 2, 5, 7, 99, 99}}; 138 | uint8_t track_type[NUM_SEQ_TRACKS] = {INSTRUMENT, INSTRUMENT, INSTRUMENT, INSTRUMENT, INSTRUMENT, INSTRUMENT}; // 1 = Instrumenttrack, 2 = Chord, 3 = Arp 139 | } sequencer_t; 140 | #endif -------------------------------------------------------------------------------- /Momentum/Settings.h: -------------------------------------------------------------------------------- 1 | #include "VoiceGroup.h" 2 | #include "SettingsService.h" 3 | 4 | FLASHMEM void settingsMIDICh(int index, const char *value); 5 | FLASHMEM void settingsMIDIOutCh(int index, const char *value); 6 | FLASHMEM void settingsMIDIThru(int index, const char *value); 7 | FLASHMEM void settingsScopeEnable(int index, const char *value); 8 | FLASHMEM void settingsVUEnable(int index, const char *value); 9 | FLASHMEM void settingsTuning(int index, const char *value); 10 | FLASHMEM void settingsSendCCEnable(int index, const char *value); 11 | 12 | FLASHMEM int currentIndexMIDICh(); 13 | FLASHMEM int currentIndexMIDIOutCh(); 14 | FLASHMEM int currentIndexMIDIThru(); 15 | FLASHMEM int currentIndexScopeEnable(); 16 | FLASHMEM int currentIndexVUEnable(); 17 | FLASHMEM int currentIndexTuning(); 18 | FLASHMEM int currentIndexSendCCEnable(); 19 | 20 | FLASHMEM void settingsMIDICh(int index, const char *value) 21 | { 22 | if (strcmp(value, "ALL") == 0) 23 | { 24 | midiChannel = MIDI_CHANNEL_OMNI; 25 | } 26 | else 27 | { 28 | midiChannel = atoi(value); 29 | } 30 | storeMidiChannel(midiChannel); 31 | } 32 | 33 | FLASHMEM void settingsMIDIOutCh(int index, const char *value) 34 | { 35 | if (strcmp(value, "Off") == 0) 36 | { 37 | midiOutCh = 0; 38 | } 39 | else 40 | { 41 | midiOutCh = atoi(value); 42 | } 43 | storeMidiOutCh(midiOutCh); 44 | } 45 | 46 | FLASHMEM void settingsMIDIThru(int index, const char *value) 47 | { 48 | if (strcmp(value, "Off") == 0) 49 | MIDIThru = midi::Thru::Off; 50 | if (strcmp(value, "Full") == 0) 51 | MIDIThru = midi::Thru::Full; 52 | if (strcmp(value, "Same Ch.") == 0) 53 | MIDIThru = midi::Thru::SameChannel; 54 | if (strcmp(value, "Diff. Ch.") == 0) 55 | MIDIThru = midi::Thru::DifferentChannel; 56 | changeMIDIThruMode(); 57 | storeMidiThru(MIDIThru); 58 | } 59 | 60 | FLASHMEM void settingsScopeEnable(int index, const char *value) 61 | { 62 | if (strcmp(value, "Off") == 0) 63 | { 64 | enableScope(false); 65 | storeScopeEnable(0); 66 | } 67 | else 68 | { 69 | enableScope(true); 70 | storeScopeEnable(1); 71 | } 72 | } 73 | 74 | FLASHMEM void settingsVUEnable(int index, const char *value) 75 | { 76 | if (strcmp(value, "Off") == 0) 77 | { 78 | vuMeter = false; 79 | storeVUEnable(0); 80 | } 81 | else 82 | { 83 | vuMeter = true; 84 | storeVUEnable(1); 85 | } 86 | } 87 | 88 | FLASHMEM void settingsSendCCEnable(int index, const char *value) 89 | { 90 | if (strcmp(value, "Off") == 0) 91 | { 92 | sendCC = false; 93 | storeSendCCToEEPROM(0); 94 | } 95 | else 96 | { 97 | sendCC = true; 98 | storeSendCCToEEPROM(1); 99 | } 100 | } 101 | 102 | FLASHMEM void settingsSyncToMIDIClkEnable(int index, const char *value) 103 | { 104 | if (strcmp(value, "Off") == 0) 105 | { 106 | syncToMIDIClk = false; 107 | storeSyncToMIDIClkToEEPROM(0); 108 | } 109 | else 110 | { 111 | syncToMIDIClk = true; 112 | storeSyncToMIDIClkToEEPROM(1); 113 | } 114 | } 115 | 116 | FLASHMEM void settingsTuning(int index, const char *value) 117 | { 118 | tuningCents = atoi(value); 119 | tuningCentsFrac = 1.0f + (tuningCents * CENTSFRAC); 120 | storeTuning(tuningCents); 121 | } 122 | 123 | FLASHMEM int currentIndexMIDICh() 124 | { 125 | return getMIDIChannel(); 126 | } 127 | 128 | FLASHMEM int currentIndexMIDIOutCh() 129 | { 130 | return getMIDIOutCh(); 131 | } 132 | 133 | FLASHMEM int currentIndexMIDIThru() 134 | { 135 | if (MIDIThru == midi::Thru::Off) 136 | return 0; 137 | if (MIDIThru == midi::Thru::Full) 138 | return 1; 139 | if (MIDIThru == midi::Thru::SameChannel) 140 | return 2; 141 | if (MIDIThru == midi::Thru::DifferentChannel) 142 | return 3; 143 | return 0; 144 | } 145 | 146 | FLASHMEM int currentIndexScopeEnable() 147 | { 148 | return getScopeEnable() ? 1 : 0; 149 | } 150 | 151 | FLASHMEM int currentIndexVUEnable() 152 | { 153 | return getVUEnable() ? 1 : 0; 154 | } 155 | 156 | FLASHMEM int currentIndexTuning() 157 | { 158 | return getTuningCents() + 50; 159 | } 160 | 161 | FLASHMEM int currentIndexSendCCEnable() 162 | { 163 | return getSendCC() ? 1 : 0; 164 | } 165 | 166 | FLASHMEM int currentIndexSyncToMIDIClkEnable() 167 | { 168 | return getSyncToMIDIClk() ? 1 : 0; 169 | } 170 | 171 | // add settings to the circular buffer 172 | FLASHMEM void setUpSettings() 173 | { 174 | settings::append(settings::SettingsOption{"Oscilloscope", {"Off", "On", "\0"}, settingsScopeEnable, currentIndexScopeEnable}); 175 | settings::append(settings::SettingsOption{"VU Meter", {"Off", "On", "\0"}, settingsVUEnable, currentIndexVUEnable}); 176 | settings::append(settings::SettingsOption{"Global Tuning (cents)", {"-50", "-49", "-48", "-47", "-46", "-45", "-44", "-43", "-42", "-41", "-40", "-39", "-38", "-37", "-36", "-35", "-34", "-33", "-32", "-31", "-30", "-29", "-28", "-27", "-26", "-25", "-24", "-23", "-22", "-21", "-20", "-19", "-18", "-17", "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9", "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "\0"}, settingsTuning, currentIndexTuning}); 177 | settings::append(settings::SettingsOption{"Patch MIDI CC Out", {"Off", "On", "\0"}, settingsSendCCEnable, currentIndexSendCCEnable}); 178 | settings::append(settings::SettingsOption{"Sync to MIDI Clk", {"Off", "On", "\0"}, settingsSyncToMIDIClkEnable, currentIndexSyncToMIDIClkEnable}); 179 | } 180 | -------------------------------------------------------------------------------- /Momentum/SettingsService.cpp: -------------------------------------------------------------------------------- 1 | #include "SettingsService.h" 2 | #include 3 | 4 | // global settings buffer 5 | std::vector settingsOptions; 6 | 7 | // currently selected settings option value index 8 | int selectedSettingIndex = 0; 9 | int selectedSettingValueIndex = 0; 10 | 11 | // Helpers 12 | int currentSettingIndex() 13 | { 14 | return selectedSettingIndex; 15 | } 16 | 17 | int nextSettingIndex() 18 | { 19 | return (selectedSettingIndex + 1) % settingsOptions.size(); 20 | } 21 | 22 | int prevSettingIndex() 23 | { 24 | if (selectedSettingIndex == 0) 25 | { 26 | return settingsOptions.size() - 1; 27 | } 28 | return selectedSettingIndex - 1; 29 | } 30 | 31 | void refresh_current_value_index() 32 | { 33 | selectedSettingValueIndex = settingsOptions[currentSettingIndex()].currentIndex(); 34 | } 35 | 36 | // Add new option 37 | 38 | void settings::append(SettingsOption option) 39 | { 40 | settingsOptions.push_back(option); 41 | 42 | if (settingsOptions.size() == 1) 43 | { 44 | selectedSettingIndex = 0; 45 | refresh_current_value_index(); 46 | } 47 | } 48 | 49 | void settings::reset() 50 | { 51 | settingsOptions.clear(); 52 | } 53 | 54 | int settings::getSettingsOptionsSize() 55 | { 56 | return settingsOptions.size(); 57 | } 58 | 59 | int settings::current_setting_size() 60 | { 61 | int i = 0; 62 | while (settingsOptions[currentSettingIndex()].value[i][0] != '\0') 63 | { 64 | i++; 65 | } 66 | return i; 67 | } 68 | 69 | // Setting names 70 | 71 | const char *settings::current_setting() 72 | { 73 | return settingsOptions[currentSettingIndex()].option; 74 | } 75 | 76 | const char *settings::previous_setting() 77 | { 78 | return settingsOptions[prevSettingIndex()].option; 79 | } 80 | 81 | const char *settings::next_setting() 82 | { 83 | return settingsOptions[nextSettingIndex()].option; 84 | } 85 | 86 | // Values 87 | 88 | const char *settings::previous_setting_value() 89 | { 90 | return settingsOptions[prevSettingIndex()].value[settingsOptions[prevSettingIndex()].currentIndex()]; 91 | } 92 | const char *settings::next_setting_value() 93 | { 94 | return settingsOptions[nextSettingIndex()].value[settingsOptions[nextSettingIndex()].currentIndex()]; 95 | } 96 | 97 | const char *settings::current_setting_value() 98 | { 99 | return settingsOptions[currentSettingIndex()].value[selectedSettingValueIndex]; 100 | } 101 | 102 | const char *settings::current_setting_previous_value() 103 | { 104 | if (selectedSettingValueIndex == 0) 105 | { 106 | return ""; 107 | } 108 | return settingsOptions[currentSettingIndex()].value[selectedSettingValueIndex - 1]; 109 | } 110 | 111 | const char *settings::current_setting_next_value() 112 | { 113 | if (settingsOptions[currentSettingIndex()].value[selectedSettingValueIndex + 1][0] == '\0') 114 | { 115 | return ""; 116 | } 117 | return settingsOptions[currentSettingIndex()].value[selectedSettingValueIndex - 1]; 118 | } 119 | 120 | // Change settings 121 | 122 | void settings::increment_setting() 123 | { 124 | selectedSettingIndex = nextSettingIndex(); 125 | refresh_current_value_index(); 126 | } 127 | 128 | void settings::decrement_setting() 129 | { 130 | selectedSettingIndex = prevSettingIndex(); 131 | refresh_current_value_index(); 132 | } 133 | 134 | // Change setting values 135 | 136 | void settings::increment_setting_value() 137 | { 138 | if (settingsOptions[currentSettingIndex()].value[selectedSettingValueIndex + 1][0] == '\0') 139 | { 140 | return; 141 | } 142 | selectedSettingValueIndex++; 143 | } 144 | 145 | void settings::decrement_setting_value() 146 | { 147 | if (selectedSettingValueIndex == 0) 148 | { 149 | return; 150 | } 151 | selectedSettingValueIndex--; 152 | } 153 | 154 | void settings::save_current_value() 155 | { 156 | settingsOptions[currentSettingIndex()].updateHandler(selectedSettingValueIndex, current_setting_value()); 157 | } -------------------------------------------------------------------------------- /Momentum/SettingsService.h: -------------------------------------------------------------------------------- 1 | // Global settings service. 2 | // 3 | // Settings can be appended from anywhere in the code and they are displayed 4 | // as part of the menu system. Callbacks are used to manage initializing and 5 | // setting values. 6 | // 7 | // Some features which are currently planned: 8 | // - Different types of SettingsOptions. Currently there is a single "Array" 9 | // option. It would be nice to have a "text" input type which allowed for 10 | // editing text instead of selecting a value. 11 | // - Multiple menus. For example "settings" opens the current menu, the encoder 12 | // opens the patch menu, holding the encoder opens the timbre menu. 13 | 14 | #pragma once 15 | 16 | namespace settings 17 | { 18 | 19 | // Function to handle the values for this settings option 20 | typedef void (*updater)(int index, const char *value); 21 | 22 | // Function to array index of current value for this settings option 23 | typedef int (*index)(); 24 | 25 | struct SettingsOption 26 | { 27 | const char *option; // Settings option string 28 | const char *value[102]; // Array of strings of settings option values 29 | updater updateHandler; 30 | index currentIndex; 31 | }; 32 | 33 | // setting names 34 | const char *current_setting(); 35 | const char *previous_setting(); 36 | const char *next_setting(); 37 | 38 | const char *previous_setting_value(); 39 | const char *next_setting_value(); 40 | 41 | const char *current_setting_value(); 42 | const char *current_setting_previous_value(); 43 | const char *current_setting_next_value(); 44 | 45 | void increment_setting(); 46 | void decrement_setting(); 47 | 48 | void increment_setting_value(); 49 | void decrement_setting_value(); 50 | 51 | void save_current_value(); 52 | 53 | void append(SettingsOption option); 54 | void reset(); 55 | 56 | int getSettingsOptionsSize(); 57 | int current_setting_size(); 58 | } -------------------------------------------------------------------------------- /Momentum/Velocity.cpp: -------------------------------------------------------------------------------- 1 | #include "Velocity.h" 2 | #include "Arduino.h" 3 | 4 | // 0 - Off, maximum velocity 5 | // 1 - Linear (0-127) 6 | // 2 - Curve up - (0-127)^2 7 | // 3 - Curve to flatten at 127 - (0-127)^0.5 8 | // 4 - Curve to flatten at 70, then maximum to 127 - - (0-70)^0.5 9 | // 10 | const float VELOCITY[5][128] PROGMEM = { 11 | {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}, 12 | {0.00f, 0.01f, 0.02f, 0.02f, 0.03f, 0.04f, 0.05f, 0.06f, 0.06f, 0.07f, 0.08f, 0.09f, 0.09f, 0.10f, 0.11f, 0.12f, 0.13f, 0.13f, 0.14f, 0.15f, 0.16f, 0.17f, 0.17f, 0.18f, 0.19f, 0.20f, 0.20f, 0.21f, 0.22f, 0.23f, 0.24f, 0.24f, 0.25f, 0.26f, 0.27f, 0.28f, 0.28f, 0.29f, 0.30f, 0.31f, 0.31f, 0.32f, 0.33f, 0.34f, 0.35f, 0.35f, 0.36f, 0.37f, 0.38f, 0.39f, 0.39f, 0.40f, 0.41f, 0.42f, 0.43f, 0.43f, 0.44f, 0.45f, 0.46f, 0.46f, 0.47f, 0.48f, 0.49f, 0.50f, 0.50f, 0.51f, 0.52f, 0.53f, 0.54f, 0.54f, 0.55f, 0.56f, 0.57f, 0.57f, 0.58f, 0.59f, 0.60f, 0.61f, 0.61f, 0.62f, 0.63f, 0.64f, 0.65f, 0.65f, 0.66f, 0.67f, 0.68f, 0.69f, 0.69f, 0.70f, 0.71f, 0.72f, 0.72f, 0.73f, 0.74f, 0.75f, 0.76f, 0.76f, 0.77f, 0.78f, 0.79f, 0.80f, 0.80f, 0.81f, 0.82f, 0.83f, 0.83f, 0.84f, 0.85f, 0.86f, 0.87f, 0.87f, 0.88f, 0.89f, 0.90f, 0.91f, 0.91f, 0.92f, 0.93f, 0.94f, 0.94f, 0.95f, 0.96f, 0.97f, 0.98f, 0.98f, 0.99f, 1.00}, 13 | {0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.00f, 0.01f, 0.01f, 0.01f, 0.01f, 0.01f, 0.01f, 0.01f, 0.02f, 0.02f, 0.02f, 0.02f, 0.02f, 0.03f, 0.03f, 0.03f, 0.04f, 0.04f, 0.04f, 0.05f, 0.05f, 0.05f, 0.06f, 0.06f, 0.06f, 0.07f, 0.07f, 0.08f, 0.08f, 0.08f, 0.09f, 0.09f, 0.10f, 0.10f, 0.11f, 0.11f, 0.12f, 0.13f, 0.13f, 0.14f, 0.14f, 0.15f, 0.16f, 0.16f, 0.17f, 0.17f, 0.18f, 0.19f, 0.19f, 0.20f, 0.21f, 0.22f, 0.22f, 0.23f, 0.24f, 0.25f, 0.25f, 0.26f, 0.27f, 0.28f, 0.29f, 0.30f, 0.30f, 0.31f, 0.32f, 0.33f, 0.34f, 0.35f, 0.36f, 0.37f, 0.38f, 0.39f, 0.40f, 0.41f, 0.42f, 0.43f, 0.44f, 0.45f, 0.46f, 0.47f, 0.48f, 0.49f, 0.50f, 0.51f, 0.52f, 0.54f, 0.55f, 0.56f, 0.57f, 0.58f, 0.60f, 0.61f, 0.62f, 0.63f, 0.65f, 0.66f, 0.67f, 0.68f, 0.70f, 0.71f, 0.72f, 0.74f, 0.75f, 0.76f, 0.78f, 0.79f, 0.81f, 0.82f, 0.83f, 0.85f, 0.86f, 0.88f, 0.89f, 0.91f, 0.92f, 0.94f, 0.95f, 0.97f, 0.98f, 1.00}, 14 | {0.00f, 0.09f, 0.13f, 0.15f, 0.18f, 0.20f, 0.22f, 0.23f, 0.25f, 0.27f, 0.28f, 0.29f, 0.31f, 0.32f, 0.33f, 0.34f, 0.35f, 0.37f, 0.38f, 0.39f, 0.40f, 0.41f, 0.42f, 0.43f, 0.43f, 0.44f, 0.45f, 0.46f, 0.47f, 0.48f, 0.49f, 0.49f, 0.50f, 0.51f, 0.52f, 0.52f, 0.53f, 0.54f, 0.55f, 0.55f, 0.56f, 0.57f, 0.58f, 0.58f, 0.59f, 0.60f, 0.60f, 0.61f, 0.61f, 0.62f, 0.63f, 0.63f, 0.64f, 0.65f, 0.65f, 0.66f, 0.66f, 0.67f, 0.68f, 0.68f, 0.69f, 0.69f, 0.70f, 0.70f, 0.71f, 0.72f, 0.72f, 0.73f, 0.73f, 0.74f, 0.74f, 0.75f, 0.75f, 0.76f, 0.76f, 0.77f, 0.77f, 0.78f, 0.78f, 0.79f, 0.79f, 0.80f, 0.80f, 0.81f, 0.81f, 0.82f, 0.82f, 0.83f, 0.83f, 0.84f, 0.84f, 0.85f, 0.85f, 0.86f, 0.86f, 0.86f, 0.87f, 0.87f, 0.88f, 0.88f, 0.89f, 0.89f, 0.90f, 0.90f, 0.90f, 0.91f, 0.91f, 0.92f, 0.92f, 0.93f, 0.93f, 0.93f, 0.94f, 0.94f, 0.95f, 0.95f, 0.96f, 0.96f, 0.96f, 0.97f, 0.97f, 0.98f, 0.98f, 0.98f, 0.99f, 0.99f, 1.00f, 1.00}, 15 | {0.00f, 0.03f, 0.06f, 0.08f, 0.10f, 0.12f, 0.14f, 0.16f, 0.18f, 0.19f, 0.21f, 0.23f, 0.24f, 0.26f, 0.28f, 0.29f, 0.31f, 0.32f, 0.34f, 0.35f, 0.37f, 0.38f, 0.40f, 0.41f, 0.42f, 0.44f, 0.45f, 0.47f, 0.48f, 0.49f, 0.51f, 0.52f, 0.53f, 0.55f, 0.56f, 0.57f, 0.59f, 0.60f, 0.61f, 0.63f, 0.64f, 0.65f, 0.66f, 0.68f, 0.69f, 0.70f, 0.71f, 0.73f, 0.74f, 0.75f, 0.76f, 0.78f, 0.79f, 0.80f, 0.81f, 0.82f, 0.84f, 0.85f, 0.86f, 0.87f, 0.88f, 0.90f, 0.91f, 0.92f, 0.93f, 0.95f, 0.96f, 0.97f, 0.98f, 0.99f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00}}; 16 | 17 | const char *velocityStr[5] = {"None", "Linear", "Curve up", "Curve flat 1", "Curve flat 2"}; -------------------------------------------------------------------------------- /Momentum/Velocity.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 0 - Off, maximum velocity 4 | // 1 - Linear (0-127) 5 | // 2 - Curve up - (0-127)^2 6 | // 3 - Curve to flatten at 127 - (0-127)^0.5 7 | // 4 - Curve to flatten at 70, then maximum to 127 - - (0-70)^0.5 8 | // 9 | extern const float VELOCITY[5][128]; 10 | 11 | extern const char *velocityStr[5]; -------------------------------------------------------------------------------- /Momentum/Voice.h: -------------------------------------------------------------------------------- 1 | #ifndef MOMENTUM_VOICE_H 2 | #define MOMENTUM_VOICE_H 3 | 4 | #include 5 | #include 6 | #include "AudioPatching.h" 7 | #include "Constants.h" 8 | #include "Detune.h" 9 | #include "Velocity.h" 10 | 11 | // TODO: Store / update these in the VoiceGroup instead of re-initializing for each noteOn. 12 | struct VoiceParams 13 | { 14 | float keytrackingAmount; 15 | float mixerLevel; 16 | int prevNote; 17 | float glideSpeed; 18 | int unisonMode; 19 | uint8_t chordDetune; 20 | float detune; 21 | int oscPitchA; 22 | int oscPitchB; 23 | }; 24 | 25 | class Voice 26 | { 27 | private: 28 | Patch &_oscillator; 29 | long _timeOn; 30 | uint8_t _note; 31 | float _velocity; 32 | bool _voiceOn; 33 | uint8_t _idx; 34 | uint8_t _noteId; 35 | Mixer *mixer = nullptr; 36 | 37 | public: 38 | Voice(Patch &p, uint8_t i) : _oscillator(p), _timeOn(-1), _note(0), _velocity(0), _voiceOn(false), _idx(i), _noteId(0) 39 | { 40 | p.waveformMod_a.frequencyModulation(PITCHLFOOCTAVERANGE); 41 | p.waveformMod_a.begin(WAVEFORMLEVEL, 440.0f, WAVEFORM_SQUARE); 42 | p.waveformMod_b.frequencyModulation(PITCHLFOOCTAVERANGE); 43 | p.waveformMod_b.begin(WAVEFORMLEVEL, 440.0f, WAVEFORM_SQUARE); 44 | 45 | // Arbitary waveform needs initializing to something 46 | p.waveformMod_a.arbitraryWaveform(PARABOLIC_WAVE, AWFREQ); 47 | p.waveformMod_b.arbitraryWaveform(PARABOLIC_WAVE, AWFREQ); 48 | 49 | // Gain controls to signal input of the filter from a AudioMixer4 object are limited to +/-1 50 | //Key tracking needs +/-5, so divide it by 5 and multiply using the octavecontrol 51 | p.filter_.octaveControl(5.0f); 52 | } 53 | 54 | inline void setMixer(Mixer *mixer_) 55 | { 56 | delete mixer; 57 | mixer = mixer_; 58 | } 59 | 60 | inline uint8_t index() 61 | { 62 | return this->_idx; 63 | } 64 | 65 | inline bool on() 66 | { 67 | return this->_voiceOn; 68 | } 69 | 70 | inline uint8_t note() 71 | { 72 | return this->_note; 73 | } 74 | 75 | inline uint8_t noteId() 76 | { 77 | return this->_noteId; 78 | } 79 | 80 | inline uint8_t velocity() 81 | { 82 | return this->_velocity; 83 | } 84 | 85 | inline long timeOn() 86 | { 87 | return this->_timeOn; 88 | } 89 | 90 | inline Patch &patch() 91 | { 92 | return this->_oscillator; 93 | } 94 | 95 | void updateVoice(VoiceParams ¶ms, uint8_t notesOn) 96 | { 97 | Patch &osc = this->patch(); 98 | 99 | if (params.unisonMode == 1) 100 | { 101 | int offset = 2 * this->index(); 102 | osc.waveformMod_a.frequency(NOTEFREQS[this->_note + params.oscPitchA] * tuningCentsFrac * (params.detune + ((1 - params.detune) * DETUNE[notesOn - 1][offset]))); 103 | osc.waveformMod_b.frequency(NOTEFREQS[this->_note + params.oscPitchB] * tuningCentsFrac * (params.detune + ((1 - params.detune) * DETUNE[notesOn - 1][offset + 1]))); 104 | } 105 | else if (params.unisonMode == 2) 106 | { 107 | // TODO: This approach doesn't make sense with voices spread across multiple timbres. 108 | osc.waveformMod_a.frequency(NOTEFREQS[this->_note + params.oscPitchA + CHORD_DETUNE[this->index()][params.chordDetune]] * tuningCentsFrac); 109 | osc.waveformMod_b.frequency(NOTEFREQS[this->_note + params.oscPitchB + CHORD_DETUNE[this->index()][params.chordDetune]] * CDT_DETUNE * tuningCentsFrac); 110 | } 111 | else 112 | { 113 | osc.waveformMod_a.frequency(NOTEFREQS[this->_note + params.oscPitchA] * tuningCentsFrac); 114 | osc.waveformMod_b.frequency(NOTEFREQS[this->_note + params.oscPitchB] * params.detune * tuningCentsFrac); 115 | } 116 | } 117 | 118 | void noteOn(uint8_t note, int velocity, VoiceParams ¶ms, uint8_t notesOn, uint8_t id) 119 | { 120 | Patch &osc = this->patch(); 121 | 122 | mixer->gain(VELOCITY[currentPatch.VelocitySensitivity][velocity] * params.mixerLevel); 123 | if (currentPatch.FilterVelocitySensitivity != 0) 124 | { 125 | osc.filterVelocity_.amplitude(2.0f * (VELOCITY[currentPatch.FilterVelocitySensitivity][velocity]) - 1.0f); //-1 to 1 (63=0) 126 | } 127 | else 128 | { 129 | osc.filterVelocity_.amplitude(0.0f); 130 | } 131 | 132 | // C3 261Hz is the pivot key which is unaffected by keytracking. Divide by 5 as the AudioMixer4 is limited to +/-1 output. OctaveControl on filter multiplies this by 5 133 | osc.filterModMixer_.gain(2, KEYTRACKINGFACTOR[note] * params.keytrackingAmount / 5.0f); 134 | osc.filterEnvelope_.noteOn(); 135 | osc.ampEnvelope_.noteOn(); 136 | if (params.glideSpeed > 0 && note != params.prevNote) 137 | { 138 | osc.glide_.amplitude((params.prevNote - note) * DIV24); // Set glide to previous note frequency (limited to 1 octave max) 139 | osc.glide_.amplitude(0, params.glideSpeed * GLIDEFACTOR); // Glide to current note 140 | } 141 | 142 | this->_noteId = id; 143 | this->_voiceOn = true; 144 | this->_note = note; 145 | this->_velocity = velocity; 146 | this->_timeOn = millis(); 147 | 148 | this->updateVoice(params, notesOn); 149 | } 150 | 151 | void noteOff() 152 | { 153 | if (!this->_voiceOn) 154 | return; 155 | this->_voiceOn = false; 156 | this->_noteId = 0; 157 | this->patch().filterEnvelope_.noteOff(); 158 | this->patch().ampEnvelope_.noteOff(); 159 | } 160 | }; 161 | 162 | #endif 163 | -------------------------------------------------------------------------------- /Momentum/effect_combine.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2018 John-Michael Reed 2 | * bleeplabs.com 3 | * 4 | * Development of this audio library was funded by PJRC.COM, LLC by sales of 5 | * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop 6 | * open source software by purchasing Teensy or other PJRC products. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice, development funding notice, and this permission 16 | * notice shall be included in all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | * 26 | * Combine analog signals with bitwise expressions like XOR. 27 | * Combining two simple oscillators results in interesting new waveforms, 28 | * Combining white noise or dynamic incoming audio results in aggressive digital distortion. 29 | */ 30 | 31 | //ElectroTechnique 2020 - Added OFF mode to stop module running programmically 32 | 33 | #ifndef effect_digital_combine_h_ 34 | #define effect_digital_combine_h_ 35 | #include 36 | #include "AudioStream.h" 37 | 38 | class AudioEffectDigitalCombine : public AudioStream 39 | { 40 | public: 41 | enum combineMode { 42 | OR = 0, 43 | XOR = 1, 44 | AND = 2, 45 | MODULO = 3, 46 | OFF = 4, 47 | }; 48 | AudioEffectDigitalCombine() : AudioStream(2, inputQueueArray), mode_sel(OR) { } 49 | void setCombineMode(int mode_in) { 50 | if (mode_in > OFF) { 51 | mode_in = OFF; 52 | } 53 | mode_sel = mode_in; 54 | } 55 | virtual void update(void); 56 | private: 57 | short mode_sel; 58 | audio_block_t *inputQueueArray[2]; 59 | }; 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /Momentum/effect_ensemble.h: -------------------------------------------------------------------------------- 1 | /* Audio Library for Teensy 3.X 2 | Portions Copyright (c) 2019, Alexander Davis info@matrixwide.com 3 | Portions Copyright (c) 2021, Vince R. Pearson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice, development funding notice, and this permission 13 | notice shall be included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | */ 23 | 24 | // V. Pearson: Implemented delay buffer interpolation with floating point fractional indices and using a larger table 25 | // to reduce audible delay sweep quantization noise. 26 | // The fractional indices are stored in flash memory instead of being calculated at runtime and stored in RAM. 27 | // #define LARGE_ENSEMBLE_LFO_TABLE uses a larger lfo table with only delay buffer interpolation. 28 | // This is more precise and is slightly faster but takes more flash memory. 29 | // With it undefined, lfo table and delay buffer interpolation are implemented with some extra processing and a smaller lfo table. 30 | 31 | #define LARGE_ENSEMBLE_LFO_TABLE 32 | 33 | #ifndef effect_ensemble_h_ 34 | #define effect_ensemble_h_ 35 | 36 | #include 37 | #include "AudioStream.h" 38 | #define ENSEMBLE_BUFFER_SIZE 1024 39 | // to put a channel 90 degrees out of LFO phase for stereo spread 40 | #define PHASE_90 367 41 | 42 | // LFO wavetable parameters 43 | #ifdef LARGE_ENSEMBLE_LFO_TABLE 44 | #define LFO_SAMPLES (1470*4) // number of samples in tablle 45 | #define LFO_SIZE (1470*4) // number of effective values (no interpolation so same as table size). 46 | #define COUNTS_PER_LFO (200/4) // Adjust for larger table so the rate is the same. 47 | #else 48 | #define LFO_SAMPLES 1470 // number of samples in table 49 | #define LFO_SIZE (1470*4) // number of effective values interpolated from table 50 | #define COUNTS_PER_LFO (200/4) // Adjust for larger effective table so the rate is the same. 51 | #endif 52 | 53 | #define LFO_RANGE 110 54 | 55 | class AudioEffectEnsemble : public AudioStream 56 | { 57 | public: 58 | AudioEffectEnsemble(void); 59 | virtual void update(void); 60 | void lfoRate(float rate); 61 | 62 | private: 63 | audio_block_t *inputQueueArray[1]; 64 | // buffers 65 | int16_t delayBuffer[ENSEMBLE_BUFFER_SIZE]; 66 | 67 | // LFO wavetable 68 | const static float PROGMEM lfoTable[]; 69 | 70 | // input index 71 | int16_t inIndex; 72 | // output indexes 73 | // default to csenter of buffer 74 | int16_t outIndex1; 75 | int16_t outIndex2; 76 | int16_t outIndex3; 77 | int16_t outIndex4; 78 | int16_t outIndex5; 79 | int16_t outIndex6; 80 | // lfo index 81 | // seprated by thirds to approximate 120 degree phase relationship 82 | int16_t lfoIndex1; 83 | int16_t lfoIndex2; 84 | int16_t lfoIndex3; 85 | int16_t lfoIndex4; 86 | int16_t lfoIndex5; 87 | int16_t lfoIndex6; 88 | // lfo rate counter 89 | int16_t lfoCount; 90 | // output index offset 91 | float offset1; 92 | float offset2; 93 | float offset3; 94 | float offset4; 95 | float offset5; 96 | float offset6; 97 | //Default countsPerLfo 98 | int countsPerLfo = COUNTS_PER_LFO; 99 | int16_t interpBuffer(float findex); 100 | 101 | #ifndef LARGE_ENSEMBLE_LFO_TABLE 102 | float lfoLookup(int16_t lfoIndex); 103 | #endif 104 | 105 | }; 106 | 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /Momentum/filter_dcblock.cpp: -------------------------------------------------------------------------------- 1 | /* Audio Library for Teensy, DC Block 2 | * Copyright (c) 2023, Matt Kuebrich 3 | * 4 | * This was adapted from "Tim's Quicker DC Blocker" by Tim Wescott. 5 | * 6 | * I can't find where the code first originated (maybe on the defunct comp.dsp Google group), 7 | * but it's been reposted here by Robert Bristow-Johnson, about halfway down the page. 8 | * https://www.dsprelated.com/showthread/comp.dsp/172787-1.php 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice, development funding notice, and this permission 18 | * notice shall be included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #include "filter_dcblock.h" 30 | 31 | void AudioFilterDCBlock::update(void) 32 | { 33 | 34 | audio_block_t *block = receiveReadOnly(); 35 | if (!block) 36 | return; 37 | 38 | A = (long)(32768.0f * (1.0 - pole)); 39 | 40 | for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) 41 | { 42 | int16_t input = block->data[i]; 43 | curr_y = long(input) - (w >> 15); 44 | // error = w - (curr_y<<15); 45 | w += (A * curr_y); 46 | block->data[i] = saturate16(curr_y); 47 | } 48 | 49 | transmit(block); 50 | release(block); 51 | } 52 | -------------------------------------------------------------------------------- /Momentum/filter_dcblock.h: -------------------------------------------------------------------------------- 1 | /* Audio Library for Teensy, DC Block 2 | * Copyright (c) 2023, Matt Kuebrich 3 | * 4 | * This was adapted from "Tim's Quicker DC Blocker" by Tim Wescott. 5 | * 6 | * I can't find where the code first originated (maybe on the defunct comp.dsp Google group), 7 | * but it's been reposted here by Robert Bristow-Johnson, about halfway down the page. 8 | * https://www.dsprelated.com/showthread/comp.dsp/172787-1.php 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice, development funding notice, and this permission 18 | * notice shall be included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | 30 | #ifndef filter_dcblock_h_ 31 | #define filter_dcblock_h_ 32 | 33 | #include 34 | #include "AudioStream.h" 35 | #include "utility/dspinst.h" 36 | 37 | class AudioFilterDCBlock : public AudioStream 38 | { 39 | public: 40 | AudioFilterDCBlock() : AudioStream(1, inputQueueArray) { 41 | pole = 0.995; // 30 Hz 42 | //pole = 0.9999; // original value from Tim's Quicker DC Blocker, 7 Hz? 43 | w = 0; 44 | } 45 | 46 | virtual void update(void); 47 | void frequency(float freq) { 48 | pole = 1.0 - (2.0f * 3.141592654f * freq) / AUDIO_SAMPLE_RATE_EXACT; 49 | } 50 | 51 | private: 52 | audio_block_t *inputQueueArray[1]; 53 | long w, A, curr_y, error; 54 | double pole; 55 | }; 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /Momentum/filter_variable.cpp: -------------------------------------------------------------------------------- 1 | /* Audio Library for Teensy 3.X 2 | * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com 3 | * 4 | * Development of this audio library was funded by PJRC.COM, LLC by sales of 5 | * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop 6 | * open source software by purchasing Teensy or other PJRC products. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice, development funding notice, and this permission 16 | * notice shall be included in all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | 27 | #include 28 | #include "filter_variable.h" 29 | #include "utility/dspinst.h" 30 | 31 | // State Variable Filter (Chamberlin) with 2X oversampling 32 | // http://www.musicdsp.org/showArchiveComment.php?ArchiveID=92 33 | 34 | // The fast 32x32 with rshift32 discards 2 bits, which probably 35 | // never matter. 36 | //#define MULT(a, b) (int32_t)(((int64_t)(a) * (b)) >> 30) 37 | #define MULT(a, b) (multiply_32x32_rshift32_rounded(a, b) << 2) 38 | 39 | // It's very unlikely anyone could hear any difference, but if you 40 | // care deeply about numerical precision in seldom-used cases, 41 | // uncomment this to improve the control signal accuracy 42 | //#define IMPROVE_HIGH_FREQUENCY_ACCURACY 43 | 44 | // This increases the exponential approximation accuracy from 45 | // about 0.341% error to only 0.012% error, which probably makes 46 | // no audible difference. 47 | //#define IMPROVE_EXPONENTIAL_ACCURACY 48 | 49 | #if defined(__ARM_ARCH_7EM__) 50 | 51 | void AudioFilterStateVariableTS::update_fixed(const int16_t *in, 52 | int16_t *lp, int16_t *bp, int16_t *hp) 53 | { 54 | const int16_t *end = in + AUDIO_BLOCK_SAMPLES; 55 | int32_t input, inputprev; 56 | int32_t lowpass, bandpass, highpass; 57 | int32_t lowpasstmp, bandpasstmp, highpasstmp; 58 | int32_t fmult, damp; 59 | 60 | fmult = setting_fmult; 61 | damp = setting_damp; 62 | inputprev = state_inputprev; 63 | lowpass = state_lowpass; 64 | bandpass = state_bandpass; 65 | do { 66 | input = (*in++) << 12; 67 | lowpass = lowpass + MULT(fmult, bandpass); 68 | highpass = ((input + inputprev)>>1) - lowpass - MULT(damp, bandpass); 69 | inputprev = input; 70 | bandpass = bandpass + MULT(fmult, highpass); 71 | lowpasstmp = lowpass; 72 | bandpasstmp = bandpass; 73 | highpasstmp = highpass; 74 | lowpass = lowpass + MULT(fmult, bandpass); 75 | highpass = input - lowpass - MULT(damp, bandpass); 76 | bandpass = bandpass + MULT(fmult, highpass); 77 | lowpasstmp = signed_saturate_rshift(lowpass+lowpasstmp, 16, 13); 78 | bandpasstmp = signed_saturate_rshift(bandpass+bandpasstmp, 16, 13); 79 | highpasstmp = signed_saturate_rshift(highpass+highpasstmp, 16, 13); 80 | *lp++ = lowpasstmp; 81 | *bp++ = bandpasstmp; 82 | *hp++ = highpasstmp; 83 | } while (in < end); 84 | state_inputprev = inputprev; 85 | state_lowpass = lowpass; 86 | state_bandpass = bandpass; 87 | } 88 | 89 | 90 | void AudioFilterStateVariableTS::update_variable(const int16_t *in, 91 | const int16_t *ctl, int16_t *lp, int16_t *bp, int16_t *hp) 92 | { 93 | const int16_t *end = in + AUDIO_BLOCK_SAMPLES; 94 | int32_t input, inputprev, control; 95 | int32_t lowpass, bandpass, highpass; 96 | int32_t lowpasstmp, bandpasstmp, highpasstmp; 97 | int32_t fcenter, fmult, damp, octavemult; 98 | int32_t n; 99 | 100 | fcenter = setting_fcenter; 101 | octavemult = setting_octavemult; 102 | damp = setting_damp; 103 | inputprev = state_inputprev; 104 | lowpass = state_lowpass; 105 | bandpass = state_bandpass; 106 | do { 107 | // compute fmult using control input, fcenter and octavemult 108 | control = *ctl++; // signal is always 15 fractional bits 109 | control *= octavemult; // octavemult range: 0 to 28671 (12 frac bits) 110 | n = control & 0x7FFFFFF; // 27 fractional control bits 111 | #ifdef IMPROVE_EXPONENTIAL_ACCURACY 112 | // exp2 polynomial suggested by Stefan Stenzel on "music-dsp" 113 | // mail list, Wed, 3 Sep 2014 10:08:55 +0200 114 | int32_t x = n << 3; 115 | n = multiply_accumulate_32x32_rshift32_rounded(536870912, x, 1494202713); 116 | int32_t sq = multiply_32x32_rshift32_rounded(x, x); 117 | n = multiply_accumulate_32x32_rshift32_rounded(n, sq, 1934101615); 118 | n = n + (multiply_32x32_rshift32_rounded(sq, 119 | multiply_32x32_rshift32_rounded(x, 1358044250)) << 1); 120 | n = n << 1; 121 | #else 122 | // exp2 algorithm by Laurent de Soras 123 | // https://www.musicdsp.org/en/latest/Other/106-fast-exp2-approximation.html 124 | n = (n + 134217728) << 3; 125 | n = multiply_32x32_rshift32_rounded(n, n); 126 | n = multiply_32x32_rshift32_rounded(n, 715827883) << 3; 127 | n = n + 715827882; 128 | #endif 129 | n = n >> (6 - (control >> 27)); // 4 integer control bits 130 | fmult = multiply_32x32_rshift32_rounded(fcenter, n); 131 | //if (fmult > 5378279) fmult = 5378279; 132 | if (fmult > 4205728) fmult = 4205728; 133 | fmult = fmult << 8; 134 | // fmult is within 0.4% accuracy for all but the top 2 octaves 135 | // of the audio band. This math improves accuracy above 5 kHz. 136 | // Without this, the filter still works fine for processing 137 | // high frequencies, but the filter's corner frequency response 138 | // can end up about 6% higher than requested. 139 | #ifdef IMPROVE_HIGH_FREQUENCY_ACCURACY 140 | // From "Fast Polynomial Approximations to Sine and Cosine" 141 | // Charles K Garrett, http://krisgarrett.net/ 142 | fmult = (multiply_32x32_rshift32_rounded(fmult, 2145892402) + 143 | multiply_32x32_rshift32_rounded( 144 | multiply_32x32_rshift32_rounded(fmult, fmult), 145 | multiply_32x32_rshift32_rounded(fmult, -1383276101))) << 1; 146 | #endif 147 | // now do the state variable filter as normal, using fmult 148 | input = (*in++) << 12; 149 | lowpass = lowpass + MULT(fmult, bandpass); 150 | highpass = ((input + inputprev)>>1) - lowpass - MULT(damp, bandpass); 151 | inputprev = input; 152 | bandpass = bandpass + MULT(fmult, highpass); 153 | lowpasstmp = lowpass; 154 | bandpasstmp = bandpass; 155 | highpasstmp = highpass; 156 | lowpass = lowpass + MULT(fmult, bandpass); 157 | highpass = input - lowpass - MULT(damp, bandpass); 158 | bandpass = bandpass + MULT(fmult, highpass); 159 | lowpasstmp = signed_saturate_rshift(lowpass+lowpasstmp, 16, 13); 160 | bandpasstmp = signed_saturate_rshift(bandpass+bandpasstmp, 16, 13); 161 | highpasstmp = signed_saturate_rshift(highpass+highpasstmp, 16, 13); 162 | *lp++ = lowpasstmp; 163 | *bp++ = bandpasstmp; 164 | *hp++ = highpasstmp; 165 | } while (in < end); 166 | state_inputprev = inputprev; 167 | state_lowpass = lowpass; 168 | state_bandpass = bandpass; 169 | } 170 | 171 | 172 | void AudioFilterStateVariableTS::update(void) 173 | { 174 | audio_block_t *input_block=NULL, *control_block=NULL; 175 | audio_block_t *lowpass_block=NULL, *bandpass_block=NULL, *highpass_block=NULL; 176 | 177 | input_block = receiveReadOnly(0); 178 | control_block = receiveReadOnly(1); 179 | if (!input_block) { 180 | if (control_block) release(control_block); 181 | return; 182 | } 183 | lowpass_block = allocate(); 184 | if (!lowpass_block) { 185 | release(input_block); 186 | if (control_block) release(control_block); 187 | return; 188 | } 189 | bandpass_block = allocate(); 190 | if (!bandpass_block) { 191 | release(input_block); 192 | release(lowpass_block); 193 | if (control_block) release(control_block); 194 | return; 195 | } 196 | highpass_block = allocate(); 197 | if (!highpass_block) { 198 | release(input_block); 199 | release(lowpass_block); 200 | release(bandpass_block); 201 | if (control_block) release(control_block); 202 | return; 203 | } 204 | 205 | if (control_block) { 206 | update_variable(input_block->data, 207 | control_block->data, 208 | lowpass_block->data, 209 | bandpass_block->data, 210 | highpass_block->data); 211 | release(control_block); 212 | } else { 213 | update_fixed(input_block->data, 214 | lowpass_block->data, 215 | bandpass_block->data, 216 | highpass_block->data); 217 | } 218 | release(input_block); 219 | transmit(lowpass_block, 0); 220 | release(lowpass_block); 221 | transmit(bandpass_block, 1); 222 | release(bandpass_block); 223 | transmit(highpass_block, 2); 224 | release(highpass_block); 225 | return; 226 | } 227 | 228 | #elif defined(KINETISL) 229 | 230 | void AudioFilterStateVariableTS::update(void) 231 | { 232 | audio_block_t *block; 233 | 234 | block = receiveReadOnly(0); 235 | if (block) release(block); 236 | block = receiveReadOnly(1); 237 | if (block) release(block); 238 | } 239 | 240 | #endif 241 | -------------------------------------------------------------------------------- /Momentum/filter_variable.h: -------------------------------------------------------------------------------- 1 | /* Audio Library for Teensy 3.X 2 | * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com 3 | * 4 | * Development of this audio library was funded by PJRC.COM, LLC by sales of 5 | * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop 6 | * open source software by purchasing Teensy or other PJRC products. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice, development funding notice, and this permission 16 | * notice shall be included in all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | 26 | ElectroTechnique 2020 27 | Increased resonance max to 15.0 28 | */ 29 | 30 | #ifndef filter_variable_h_ 31 | #define filter_variable_h_ 32 | 33 | #include "Arduino.h" 34 | #include "AudioStream.h" 35 | 36 | class AudioFilterStateVariableTS: public AudioStream 37 | { 38 | public: 39 | AudioFilterStateVariableTS() : AudioStream(2, inputQueueArray) { 40 | frequency(1000); 41 | octaveControl(1.0); // default values 42 | resonance(0.707); 43 | state_inputprev = 0; 44 | state_lowpass = 0; 45 | state_bandpass = 0; 46 | } 47 | void frequency(float freq) { 48 | if (freq < 1.0) freq = 1.0;//ElectroTechnique changed from 20.0 to make dc offset filter 49 | else if (freq > AUDIO_SAMPLE_RATE_EXACT/2.5) freq = AUDIO_SAMPLE_RATE_EXACT/2.5; 50 | setting_fcenter = (freq * (3.141592654/(AUDIO_SAMPLE_RATE_EXACT*2.0))) 51 | * 2147483647.0; 52 | // TODO: should we use an approximation when freq is not a const, 53 | // so the sinf() function isn't linked? 54 | setting_fmult = sinf(freq * (3.141592654/(AUDIO_SAMPLE_RATE_EXACT*2.0))) 55 | * 2147483647.0; 56 | } 57 | void resonance(float q) { 58 | if (q < 0.7) q = 0.7; 59 | else if (q > 15.0) q = 15.0;//ElectroTechnique changed from 5.0 60 | // TODO: allow lower Q when frequency is lower 61 | setting_damp = (1.0 / q) * 1073741824.0; 62 | } 63 | void octaveControl(float n) { 64 | // filter's corner frequency is Fcenter * 2^(control * N) 65 | // where "control" ranges from -1.0 to +1.0 66 | // and "N" allows the frequency to change from 0 to 7 octaves 67 | if (n < 0.0) n = 0.0; 68 | else if (n > 6.9999) n = 6.9999; 69 | setting_octavemult = n * 4096.0; 70 | } 71 | virtual void update(void); 72 | private: 73 | void update_fixed(const int16_t *in, 74 | int16_t *lp, int16_t *bp, int16_t *hp); 75 | void update_variable(const int16_t *in, const int16_t *ctl, 76 | int16_t *lp, int16_t *bp, int16_t *hp); 77 | int32_t setting_fcenter; 78 | int32_t setting_fmult; 79 | int32_t setting_octavemult; 80 | int32_t setting_damp; 81 | int32_t state_inputprev; 82 | int32_t state_lowpass; 83 | int32_t state_bandpass; 84 | audio_block_t *inputQueueArray[2]; 85 | }; 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /Momentum/name.c: -------------------------------------------------------------------------------- 1 | #include "usb_names.h" 2 | 3 | #define MIDI_NAME {'M','o','m','e','n','t','u','m'} 4 | #define MIDI_NAME_LEN 8 5 | 6 | #define MANUFACTURER_NAME {'E','l','e','c','t','r','o','t','e','c','h','n','i','q','u','e'} 7 | #define MANUFACTURER_NAME_LEN 16 8 | 9 | struct usb_string_descriptor_struct usb_string_product_name = { 10 | 2 + MIDI_NAME_LEN * 2, 11 | 3, 12 | MIDI_NAME 13 | }; 14 | 15 | struct usb_string_descriptor_struct usb_string_manufacturer_name = { 16 | 2 + MANUFACTURER_NAME_LEN * 2, 17 | 3, 18 | MANUFACTURER_NAME 19 | }; 20 | -------------------------------------------------------------------------------- /Momentum/synth_dc.cpp: -------------------------------------------------------------------------------- 1 | /* Audio Library for Teensy 3.X 2 | * Portions Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com 3 | * Portions Copyright (c) 2021, Vince R. Pearson (exponential glide functionality) 4 | * 5 | * Development of this audio library was funded by PJRC.COM, LLC by sales of 6 | * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop 7 | * open source software by purchasing Teensy or other PJRC products. 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice, development funding notice, and this permission 17 | * notice shall be included in all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | #include 29 | #include "synth_dc.h" 30 | 31 | void AudioSynthWaveformDcTS::update(void) 32 | { 33 | audio_block_t *block; 34 | uint32_t *p, *end, val; 35 | int32_t count, t1, t2, t3, t4; 36 | 37 | block = allocate(); 38 | if (!block) return; 39 | p = (uint32_t *)(block->data); 40 | end = p + AUDIO_BLOCK_SAMPLES/2; 41 | 42 | if (state == 0) { 43 | mode=modePending; 44 | // steady DC output, simply fill the buffer with fixed value 45 | if(mode!=GLIDE_EXP) 46 | val = pack_16t_16t(magnitude, magnitude); 47 | else 48 | val=pack_16t_16t(expMagnitude<<2,expMagnitude<<2); 49 | 50 | do { 51 | *p++ = val; 52 | *p++ = val; 53 | *p++ = val; 54 | *p++ = val; 55 | *p++ = val; 56 | *p++ = val; 57 | *p++ = val; 58 | *p++ = val; 59 | } while (p < end); 60 | } else if(mode!=GLIDE_EXP) 61 | { 62 | // transitioning to a new DC level 63 | //count = (target - magnitude) / increment; 64 | count = substract_int32_then_divide_int32(target, magnitude, increment); 65 | if (count >= AUDIO_BLOCK_SAMPLES) { 66 | // this update will not reach the target 67 | do { 68 | magnitude += increment; 69 | t1 = magnitude; 70 | magnitude += increment; 71 | t1 = pack_16t_16t(magnitude, t1); 72 | magnitude += increment; 73 | t2 = magnitude; 74 | magnitude += increment; 75 | t2 = pack_16t_16t(magnitude, t2); 76 | magnitude += increment; 77 | t3 = magnitude; 78 | magnitude += increment; 79 | t3 = pack_16t_16t(magnitude, t3); 80 | magnitude += increment; 81 | t4 = magnitude; 82 | magnitude += increment; 83 | t4 = pack_16t_16t(magnitude, t4); 84 | *p++ = t1; 85 | *p++ = t2; 86 | *p++ = t3; 87 | *p++ = t4; 88 | } while (p < end); 89 | } else { 90 | // this update reaches the target 91 | while (count >= 2) { 92 | count -= 2; 93 | magnitude += increment; 94 | t1 = magnitude; 95 | magnitude += increment; 96 | t1 = pack_16t_16t(magnitude, t1); 97 | *p++ = t1; 98 | } 99 | if (count) { 100 | t1 = pack_16t_16t(target, magnitude + increment); 101 | *p++ = t1; 102 | } 103 | magnitude = target; 104 | state = 0; 105 | mode=modePending; 106 | val = pack_16t_16t(magnitude, magnitude); 107 | while (p < end) { 108 | *p++ = val; 109 | } 110 | } 111 | } 112 | else // Exponential glide. Vince R. Pearson 113 | do 114 | { 115 | 116 | ysum=ysum+(int64_t)kf*(expTargetB-expMagnitude); 117 | t1=ysum>>32; 118 | 119 | ysum=ysum+(int64_t)kf*(expTargetB-t1); 120 | t2=ysum>>32; 121 | 122 | ysum=ysum+(int64_t)kf*(expTargetB-t2); 123 | t3=ysum>>32; 124 | 125 | ysum=ysum+(int64_t)kf*(expTargetB-t3); 126 | t4=ysum>>32; 127 | expMagnitude=t4; 128 | 129 | // Check for target crossing starting with last sample. If a sample has not hit target 130 | // all previous samples have not either so skip further checks. 131 | if((target-t4)*stepDirection<0) 132 | { 133 | t4=expTarget; 134 | state=0; 135 | expMagnitude=expTargetB=expTarget; 136 | if((expTarget-t3)*stepDirection<0) 137 | { 138 | t3=expTarget; 139 | if((expTarget-t2)*stepDirection<0) 140 | { 141 | t2=expTarget; 142 | if((expTarget-t1)*stepDirection<0) 143 | t1=expTarget; 144 | } 145 | } 146 | } 147 | t1= pack_16t_16t(t1<<2, t2<<2); 148 | t2= pack_16t_16t(t3<<2, t4<<2); 149 | 150 | *p++ = t1; 151 | *p++ = t2; 152 | } while(p= 0) 64 | { 65 | if (b >= 0) 66 | { 67 | return (a - b) / c; // no overflow if both a & b are positive 68 | } 69 | else 70 | { 71 | diff = a + (b * -1); // assumes 0x80000000 * -1 == 0x80000000 72 | negative = 0; 73 | } 74 | } 75 | else 76 | { 77 | if (b >= 0) 78 | { 79 | diff = (a * -1) + b; // assumes 0x80000000 * -1 == 0x80000000 80 | negative = 1; 81 | } 82 | else 83 | { 84 | return (a - b) / c; // no overflow if both a & b are negative 85 | } 86 | } 87 | if (c >= 0) 88 | { 89 | diff = diff / (uint32_t)c; 90 | } 91 | else 92 | { 93 | diff = diff / (uint32_t)(c * -1); 94 | negative ^= 1; 95 | } 96 | if (negative) 97 | { 98 | if (diff > 0x7FFFFFFF) 99 | return 0x80000000; 100 | return (int32_t)diff * -1; 101 | } 102 | else 103 | { 104 | if (diff > 0x7FFFFFFF) 105 | return 0x7FFFFFFF; 106 | return (int32_t)diff; 107 | } 108 | } 109 | 110 | #endif 111 | 112 | class AudioSynthWaveformDcTS : public AudioStream 113 | { 114 | public: 115 | AudioSynthWaveformDcTS() : AudioStream(0, NULL) 116 | { 117 | mode = modePending = GLIDE_EXP; 118 | state = 0; 119 | magnitude = expMagnitude = 0; 120 | stepDirection = 1; 121 | target = expTarget = 0; 122 | expTargetB = 0; 123 | kf = 0x7ff00000; // Arbitrary positive coefficient until set. 124 | } 125 | // immediately jump to the new DC level 126 | FLASHMEM void amplitude(float n) 127 | { 128 | if (n > 1.0f) 129 | n = 1.0f; 130 | else if (n < -1.0f) 131 | n = -1.0f; 132 | int32_t m = (int32_t)(n * 2147418112.0f); // 0x7fff0000 133 | __disable_irq(); 134 | magnitude = m; 135 | expMagnitude = m >> 2; 136 | ysum = (int64_t)expMagnitude << 32; 137 | state = 0; 138 | __enable_irq(); 139 | } 140 | // slowly transition to the new DC level 141 | FLASHMEM void amplitude(float n, float milliseconds) 142 | { 143 | if (milliseconds <= 0.0f) 144 | { 145 | amplitude(n); 146 | return; 147 | } 148 | if (n > 1.0f) 149 | n = 1.0f; 150 | else if (n < -1.0f) 151 | n = -1.0f; 152 | int32_t c = (int32_t)(milliseconds * (AUDIO_SAMPLE_RATE_EXACT / 1000.0f)); 153 | if (c == 0) 154 | { 155 | amplitude(n); 156 | return; 157 | } 158 | int32_t t = (int32_t)(n * 2147418112.0f); 159 | // 160 | int32_t k = (0x80000000UL) * (1.0f - exp(-2.0f / (milliseconds * AUDIO_SAMPLE_RATE_EXACT / 1000.0f))); 161 | // Create 162 | int32_t et = t >> 2; 163 | int32_t bt = et + EXP_TARGET_MARGIN * ((int64_t)expTarget - (int64_t)expMagnitude); 164 | // Need to keep track of step direction for threshold crossing detection 165 | int8_t sd; 166 | if (expTarget > expMagnitude) 167 | sd = 1; 168 | else 169 | sd = -1; 170 | 171 | int8_t st; 172 | if (((target == magnitude) && (mode == GLIDE_LIN)) || ((expTarget == expMagnitude) && (mode == GLIDE_EXP))) 173 | st = 0; 174 | else 175 | st = 1; 176 | 177 | __disable_irq(); 178 | target = t; 179 | expTarget = et; 180 | expTargetB = bt; 181 | ysum = (int64_t)expMagnitude << 32; 182 | kf = k; 183 | stepDirection = sd; 184 | 185 | if (st == 0) 186 | { 187 | state = 0; 188 | __enable_irq(); 189 | return; 190 | } 191 | 192 | increment = substract_int32_then_divide_int32(target, magnitude, c); 193 | if (increment == 0) 194 | { 195 | increment = (target > magnitude) ? 1 : -1; 196 | } 197 | state = 1; 198 | __enable_irq(); 199 | } 200 | FLASHMEM float read(void) 201 | { 202 | int32_t m = magnitude; 203 | if (mode != GLIDE_EXP) 204 | m = magnitude; 205 | else 206 | m = expMagnitude << 2; 207 | return (float)m * (float)(1.0 / 2147418112.0); 208 | } 209 | enum 210 | { 211 | GLIDE_LIN = 0, 212 | GLIDE_EXP = 1 213 | }; 214 | FLASHMEM void setMode(uint8_t mode) 215 | { 216 | // For now the mode should only change when the state is zero so set it to pending. 217 | // Changing mode from GLIDE_EXP to GLIDE_LIN may mess up the calculations. 218 | if (mode != GLIDE_EXP) 219 | this->modePending = GLIDE_LIN; // default to linear for all other values. 220 | else 221 | this->modePending = GLIDE_EXP; // may have to wait until next state==0 for this to be set. 222 | } 223 | uint8_t getMode() { return mode; }; 224 | 225 | virtual void update(void); 226 | 227 | private: 228 | uint8_t state; // 0=steady output, 1=transitioning 229 | int32_t magnitude; // current output 230 | int32_t target; // designed output (while transitiong) 231 | int32_t increment; // adjustment per sample (while transitiong) 232 | 233 | // Exponential glide variables 234 | uint8_t mode, modePending; // Linear or exponential mode. Pending allows a glide to finish with the mode it started with. 235 | int8_t stepDirection; // Used to track step direction for target threshold detection. 236 | int64_t ysum; // filter accumulator 237 | int32_t expMagnitude; // Magnitude value. This is scaled down by 4 from the linear case. 238 | int32_t expTarget; // Target value. This is scaled down by 4 from the linear case. 239 | int32_t expTargetB; // Biased target value. This is set just beyond the target so the target can be hit earlier. 240 | int32_t kf; // FIlter coefficient. 241 | }; 242 | 243 | #endif 244 | -------------------------------------------------------------------------------- /Momentum/synth_waveform.h: -------------------------------------------------------------------------------- 1 | /* Audio Library for Teensy 3.X 2 | * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com 3 | * 4 | * Development of this audio library was funded by PJRC.COM, LLC by sales of 5 | * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop 6 | * open source software by purchasing Teensy or other PJRC products. 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice, development funding notice, and this permission 16 | * notice shall be included in all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | 26 | ElectroTechnique 2020 27 | Added WAVEFORM_SILENT, sync() 28 | */ 29 | 30 | #ifndef synth_waveform_h_ 31 | #define synth_waveform_h_ 32 | 33 | #include 34 | #include "AudioStream.h" 35 | #include "arm_math.h" 36 | 37 | // waveforms.c 38 | extern "C" { 39 | extern const int16_t AudioWaveformSine[257]; 40 | } 41 | 42 | 43 | #define WAVEFORM_SINE 0 44 | #define WAVEFORM_SAWTOOTH 1 45 | #define WAVEFORM_SQUARE 2 46 | #define WAVEFORM_TRIANGLE 3 47 | #define WAVEFORM_ARBITRARY 4 48 | #define WAVEFORM_PULSE 5 49 | #define WAVEFORM_SAWTOOTH_REVERSE 6 50 | #define WAVEFORM_SAMPLE_HOLD 7 51 | #define WAVEFORM_TRIANGLE_VARIABLE 8 52 | #define WAVEFORM_BANDLIMIT_SAWTOOTH 9 53 | #define WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE 10 54 | #define WAVEFORM_BANDLIMIT_SQUARE 11 55 | #define WAVEFORM_BANDLIMIT_PULSE 12 56 | #define WAVEFORM_SILENT 19 57 | 58 | typedef struct step_state 59 | { 60 | int offset ; 61 | bool positive ; 62 | } step_state ; 63 | 64 | 65 | class BandLimitedWaveformTS 66 | { 67 | public: 68 | BandLimitedWaveformTS (void) ; 69 | int16_t generate_sawtooth (uint32_t new_phase, int i) ; 70 | int16_t generate_square (uint32_t new_phase, int i) ; 71 | int16_t generate_pulse (uint32_t new_phase, uint32_t pulse_width, int i) ; 72 | void init_sawtooth (uint32_t freq_word) ; 73 | void init_square (uint32_t freq_word) ; 74 | void init_pulse (uint32_t freq_word, uint32_t pulse_width) ; 75 | 76 | 77 | private: 78 | int32_t lookup (int offset) ; 79 | void insert_step (int offset, bool rising, int i) ; 80 | int32_t process_step (int i) ; 81 | int32_t process_active_steps (uint32_t new_phase) ; 82 | int32_t process_active_steps_saw (uint32_t new_phase) ; 83 | int32_t process_active_steps_pulse (uint32_t new_phase, uint32_t pulse_width) ; 84 | void new_step_check_square (uint32_t new_phase, int i) ; 85 | void new_step_check_pulse (uint32_t new_phase, uint32_t pulse_width, int i) ; 86 | void new_step_check_saw (uint32_t new_phase, int i) ; 87 | 88 | 89 | uint32_t phase_word ; 90 | int32_t dc_offset ; 91 | step_state states [32] ; // circular buffer of active steps 92 | int newptr ; // buffer pointers into states, AND'd with PTRMASK to keep in buffer range. 93 | int delptr ; 94 | int32_t cyclic[16] ; // circular buffer of output samples 95 | bool pulse_state ; 96 | uint32_t sampled_width ; // pulse width is sampled once per waveform 97 | }; 98 | 99 | 100 | class AudioSynthWaveformTS : public AudioStream 101 | { 102 | public: 103 | AudioSynthWaveformTS(void) : AudioStream(0,NULL), 104 | phase_accumulator(0), phase_increment(0), phase_offset(0), 105 | magnitude(0), pulse_width(0x40000000), 106 | arbdata(NULL), sample(0), tone_type(WAVEFORM_SINE), 107 | tone_offset(0),syncFlag(0) { 108 | } 109 | 110 | void frequency(float freq) { 111 | if (freq < 0.0) { 112 | freq = 0.0; 113 | } else if (freq > AUDIO_SAMPLE_RATE_EXACT / 2) { 114 | freq = AUDIO_SAMPLE_RATE_EXACT / 2; 115 | } 116 | phase_increment = freq * (4294967296.0 / AUDIO_SAMPLE_RATE_EXACT); 117 | if (phase_increment > 0x7FFE0000u) phase_increment = 0x7FFE0000; 118 | } 119 | void phase(float angle) { 120 | if (angle < 0.0) { 121 | angle = 0.0; 122 | } else if (angle > 360.0) { 123 | angle = angle - 360.0; 124 | if (angle >= 360.0) return; 125 | } 126 | phase_offset = angle * (4294967296.0 / 360.0); 127 | } 128 | void sync() { 129 | syncFlag = 1; 130 | } 131 | void amplitude(float n) { // 0 to 1.0 132 | if (n < 0) { 133 | n = 0; 134 | } else if (n > 1.0) { 135 | n = 1.0; 136 | } 137 | magnitude = n * 65536.0; 138 | } 139 | void offset(float n) { 140 | if (n < -1.0) { 141 | n = -1.0; 142 | } else if (n > 1.0) { 143 | n = 1.0; 144 | } 145 | tone_offset = n * 32767.0; 146 | } 147 | void pulseWidth(float n) { // 0.0 to 1.0 148 | if (n < 0) { 149 | n = 0; 150 | } else if (n > 1.0) { 151 | n = 1.0; 152 | } 153 | pulse_width = n * 4294967296.0; 154 | } 155 | void begin(short t_type) { 156 | phase_offset = 0; 157 | tone_type = t_type; 158 | if (t_type == WAVEFORM_BANDLIMIT_SQUARE) 159 | band_limit_waveform.init_square (phase_increment) ; 160 | else if (t_type == WAVEFORM_BANDLIMIT_PULSE) 161 | band_limit_waveform.init_pulse (phase_increment, pulse_width) ; 162 | else if (t_type == WAVEFORM_BANDLIMIT_SAWTOOTH || t_type == WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE) 163 | band_limit_waveform.init_sawtooth (phase_increment) ; 164 | } 165 | void begin(float t_amp, float t_freq, short t_type) { 166 | amplitude(t_amp); 167 | frequency(t_freq); 168 | phase_offset = 0; 169 | begin (t_type); 170 | } 171 | void arbitraryWaveform(const int16_t *data, float maxFreq) { 172 | arbdata = data; 173 | } 174 | virtual void update(void); 175 | 176 | private: 177 | uint32_t phase_accumulator; 178 | uint32_t phase_increment; 179 | uint32_t phase_offset; 180 | int32_t magnitude; 181 | uint32_t pulse_width; 182 | const int16_t *arbdata; 183 | int16_t sample; // for WAVEFORM_SAMPLE_HOLD 184 | short tone_type; 185 | int16_t tone_offset; 186 | int16_t syncFlag; 187 | BandLimitedWaveformTS band_limit_waveform ; 188 | }; 189 | 190 | 191 | class AudioSynthWaveformModulatedTS : public AudioStream 192 | { 193 | public: 194 | AudioSynthWaveformModulatedTS(void) : AudioStream(2, inputQueueArray), 195 | phase_accumulator(0), phase_increment(0), modulation_factor(32768), 196 | magnitude(0), arbdata(NULL), sample(0), tone_offset(0), 197 | tone_type(WAVEFORM_SINE), modulation_type(0), syncFlag(0) { 198 | } 199 | 200 | void frequency(float freq) { 201 | if (freq < 0.0) { 202 | freq = 0.0; 203 | } else if (freq > AUDIO_SAMPLE_RATE_EXACT / 2) { 204 | freq = AUDIO_SAMPLE_RATE_EXACT / 2; 205 | } 206 | phase_increment = freq * (4294967296.0 / AUDIO_SAMPLE_RATE_EXACT); 207 | if (phase_increment > 0x7FFE0000u) phase_increment = 0x7FFE0000; 208 | } 209 | void amplitude(float n) { // 0 to 1.0 210 | if (n < 0) { 211 | n = 0; 212 | } else if (n > 1.0) { 213 | n = 1.0; 214 | } 215 | magnitude = n * 65536.0; 216 | } 217 | void sync() { 218 | syncFlag = 1; 219 | } 220 | void offset(float n) { 221 | if (n < -1.0) { 222 | n = -1.0; 223 | } else if (n > 1.0) { 224 | n = 1.0; 225 | } 226 | tone_offset = n * 32767.0; 227 | } 228 | void begin(short t_type) { 229 | tone_type = t_type; 230 | if (t_type == WAVEFORM_BANDLIMIT_SQUARE) 231 | band_limit_waveform.init_square (phase_increment) ; 232 | else if (t_type == WAVEFORM_BANDLIMIT_PULSE) 233 | band_limit_waveform.init_pulse (phase_increment, 0x80000000u) ; 234 | else if (t_type == WAVEFORM_BANDLIMIT_SAWTOOTH || t_type == WAVEFORM_BANDLIMIT_SAWTOOTH_REVERSE) 235 | band_limit_waveform.init_sawtooth (phase_increment) ; 236 | } 237 | void begin(float t_amp, float t_freq, short t_type) { 238 | amplitude(t_amp); 239 | frequency(t_freq); 240 | begin (t_type) ; 241 | } 242 | void arbitraryWaveform(const int16_t *data, float maxFreq) { 243 | arbdata = data; 244 | } 245 | void frequencyModulation(float octaves) { 246 | if (octaves > 12.0) { 247 | octaves = 12.0; 248 | } else if (octaves < 0.1) { 249 | octaves = 0.1; 250 | } 251 | modulation_factor = octaves * 4096.0; 252 | modulation_type = 0; 253 | } 254 | void phaseModulation(float degrees) { 255 | if (degrees > 9000.0) { 256 | degrees = 9000.0; 257 | } else if (degrees < 30.0) { 258 | degrees = 30.0; 259 | } 260 | modulation_factor = degrees * (65536.0 / 180.0); 261 | modulation_type = 1; 262 | } 263 | virtual void update(void); 264 | 265 | private: 266 | audio_block_t *inputQueueArray[2]; 267 | uint32_t phase_accumulator; 268 | uint32_t phase_increment; 269 | uint32_t modulation_factor; 270 | int32_t magnitude; 271 | const int16_t *arbdata; 272 | uint32_t phasedata[AUDIO_BLOCK_SAMPLES]; 273 | int16_t sample; // for WAVEFORM_SAMPLE_HOLD 274 | int16_t tone_offset; 275 | uint8_t tone_type; 276 | uint8_t modulation_type; 277 | int16_t syncFlag; 278 | BandLimitedWaveformTS band_limit_waveform ; 279 | }; 280 | 281 | 282 | #endif 283 | -------------------------------------------------------------------------------- /Momentum/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef MOMENTUM_UTILS_H 2 | #define MOMENTUM_UTILS_H 3 | 4 | #include 5 | #include 6 | 7 | // Clamp a value to the given range. 8 | template 9 | NumericType inRangeOrDefault(NumericType value, NumericType defaultValue, NumericType min, NumericType max) 10 | { 11 | static_assert(std::is_arithmetic::value, "NumericType must be numeric"); 12 | if (value < min || value > max) 13 | return defaultValue; 14 | return value; 15 | } 16 | 17 | // Set new value and clamp it to the given range. 18 | template 19 | NumericType clampToRange(NumericType value, NumericType delta, NumericType min, NumericType max) 20 | { 21 | static_assert(std::is_arithmetic::value, "NumericType must be numeric"); 22 | if ((value + delta) < min) 23 | { 24 | value = min; 25 | } 26 | else if ((value + delta) > max) 27 | { 28 | value = max; 29 | } 30 | else 31 | { 32 | value += delta; 33 | } 34 | return value; 35 | } 36 | 37 | FLASHMEM String milliToString(float milli) 38 | { 39 | if (milli < 1000) 40 | return String(int(milli)) + " ms"; 41 | return String(milli / 1000) + " s"; 42 | } 43 | 44 | // Computes a hash of the parameter values to create a UID for each patch/sequence/peformance that is stored with it. 45 | // This can also be used to identify identical patches. Hash takes about 2.8us on TeensyMM 46 | FLASHMEM uint32_t getHash(String tohash) 47 | { 48 | return rokkit(tohash.c_str(), strlen(tohash.c_str())); 49 | } 50 | 51 | // For debug purposes, prints string of parameter values 52 | // FLASHMEM String getCurrentPatchDataWithoutPatchname() 53 | // { 54 | // auto p = groupvec[activeGroupIndex]->params(); 55 | // return String(groupvec[activeGroupIndex]->getOscLevelA()) + "," + String(groupvec[activeGroupIndex]->getOscLevelB()) + "," + String(groupvec[activeGroupIndex]->getPinkNoiseLevel() - groupvec[activeGroupIndex]->getWhiteNoiseLevel()) + "," + 56 | // String(p.unisonMode) + "," + String(groupvec[activeGroupIndex]->getOscFX()) + "," + String(p.detune, 5) + "," + String(lfoSyncFreq) + "," + String(midiClkTimeInterval) + "," + String(lfoTempoValue) + "," + 57 | // String(groupvec[activeGroupIndex]->getKeytrackingAmount()) + "," + String(p.glideSpeed, 5) + "," + String(p.oscPitchA) + "," + String(p.oscPitchB) + "," + String(groupvec[activeGroupIndex]->getWaveformA()) + "," + String(groupvec[activeGroupIndex]->getWaveformB()) + "," + 58 | // String(groupvec[activeGroupIndex]->getPwmSourceA()) + "," + String(groupvec[activeGroupIndex]->getPwmSourceB()) + "," + String(groupvec[activeGroupIndex]->getPwmAmtA()) + "," + String(groupvec[activeGroupIndex]->getPwmAmtB()) + "," + String(groupvec[activeGroupIndex]->getPwmRateA()) + "," + String(groupvec[activeGroupIndex]->getPwmRateB()) + "," + 59 | // String(groupvec[activeGroupIndex]->getPwA()) + "," + String(groupvec[activeGroupIndex]->getPwB()) + "," + String(groupvec[activeGroupIndex]->getResonance()) + "," + String(groupvec[activeGroupIndex]->getCutoff()) + "," + 60 | // String(groupvec[activeGroupIndex]->getFilterMixer()) + "," + String(groupvec[activeGroupIndex]->getFilterEnvelope()) + "," + String(groupvec[activeGroupIndex]->getPitchLfoAmount(), 5) + "," + 61 | // String(groupvec[activeGroupIndex]->getPitchLfoRate(), 5) + "," + String(groupvec[activeGroupIndex]->getPitchLfoWaveform()) + "," + String(int(groupvec[activeGroupIndex]->getPitchLfoRetrig())) + "," + 62 | // String(int(groupvec[activeGroupIndex]->getPitchLfoMidiClockSync())) + "," + String(groupvec[activeGroupIndex]->getFilterLfoRate(), 5) + "," + 63 | // groupvec[activeGroupIndex]->getFilterLfoRetrig() + "," + groupvec[activeGroupIndex]->getFilterLfoMidiClockSync() + "," + groupvec[activeGroupIndex]->getFilterLfoAmt() + "," + groupvec[activeGroupIndex]->getFilterLfoWaveform() + "," + groupvec[activeGroupIndex]->getFilterAttack() + "," + 64 | // groupvec[activeGroupIndex]->getFilterDecay() + "," + groupvec[activeGroupIndex]->getFilterSustain() + "," + groupvec[activeGroupIndex]->getFilterRelease() + "," + groupvec[activeGroupIndex]->getAmpAttack() + "," + groupvec[activeGroupIndex]->getAmpDecay() + "," + groupvec[activeGroupIndex]->getAmpSustain() + "," + groupvec[activeGroupIndex]->getAmpRelease() + "," + 65 | // String(groupvec[activeGroupIndex]->getEnsebleEffectAmount()) + "," + String(groupvec[activeGroupIndex]->getEnsembleEffectMix()) + "," + String(groupvec[activeGroupIndex]->getPitchEnvelope()) + "," + String(velocitySens) + "," + 66 | // String(p.chordDetune) + "," + String(groupvec[activeGroupIndex]->getMonophonicMode()) + "," + String(0.0f); 67 | // } 68 | 69 | // ONLY WORKS WITH TD1.58? 70 | 71 | // https://forum.pjrc.com/threads/33443-How-to-display-free-ram 72 | // void memInfo() 73 | // { 74 | // constexpr auto RAM_BASE = 0x2020'0000; 75 | // constexpr auto RAM_SIZE = 512 << 10; 76 | // constexpr auto FLASH_BASE = 0x6000'0000; 77 | // #if ARDUINO_TEENSY40 78 | // constexpr auto FLASH_SIZE = 2 << 20; 79 | // #elif ARDUINO_TEENSY41 80 | // constexpr auto FLASH_SIZE = 8 << 20; 81 | // #elif ARDUINO_TEENSY_MICROMOD 82 | // constexpr auto FLASH_SIZE = 16 << 20; 83 | // #endif 84 | 85 | // // note: these values are defined by the linker, they are not valid memory 86 | // // locations in all cases - by defining them as arrays, the C++ compiler 87 | // // will use the address of these definitions - it's a big hack, but there's 88 | // // really no clean way to get at linker-defined symbols from the .ld file 89 | 90 | // extern char _stext[], _etext[], _sbss[], _ebss[], _sdata[], _edata[], 91 | // _estack[], _heap_start[], _heap_end[], _itcm_block_count[], *__brkval; 92 | 93 | // auto sp = (char *)__builtin_frame_address(0); 94 | 95 | // printf("_stext %08x\n", _stext); 96 | // printf("_etext %08x +%db\n", _etext, _etext - _stext); 97 | // printf("_sdata %08x\n", _sdata); 98 | // printf("_edata %08x +%db\n", _edata, _edata - _sdata); 99 | // printf("_sbss %08x\n", _sbss); 100 | // printf("_ebss %08x +%db\n", _ebss, _ebss - _sbss); 101 | // printf("curr stack %08x +%db\n", sp, sp - _ebss); 102 | // printf("_estack %08x +%db\n", _estack, _estack - sp); 103 | // printf("_heap_start %08x\n", _heap_start); 104 | // printf("__brkval %08x +%db\n", __brkval, __brkval - _heap_start); 105 | // printf("_heap_end %08x +%db\n", _heap_end, _heap_end - __brkval); 106 | // #if ARDUINO_TEENSY41 107 | // extern char _extram_start[], _extram_end[], *__brkval; 108 | // printf("_extram_start %08x\n", _extram_start); 109 | // printf("_extram_end %08x +%db\n", _extram_end, 110 | // _extram_end - _extram_start); 111 | // #endif 112 | // printf("\n"); 113 | 114 | // printf(" %08x .. %08x\n", 115 | // _stext, _stext + ((int)_itcm_block_count << 15) - 1); 116 | // printf(" %08x .. %08x\n", 117 | // _sdata, _estack - 1); 118 | // printf(" %08x .. %08x\n", 119 | // RAM_BASE, RAM_BASE + RAM_SIZE - 1); 120 | // printf(" %08x .. %08x\n", 121 | // FLASH_BASE, FLASH_BASE + FLASH_SIZE - 1); 122 | // #if ARDUINO_TEENSY41 123 | // extern uint8_t external_psram_size; 124 | // if (external_psram_size > 0) 125 | // printf(" %08x .. %08x\n", 126 | // _extram_start, _extram_start + (external_psram_size << 20) - 1); 127 | // #endif 128 | // printf("\n"); 129 | 130 | // auto stack = sp - _ebss; 131 | // printf("avail STACK %8d b %5d kb\n", stack, stack >> 10); 132 | 133 | // auto heap = _heap_end - __brkval; 134 | // printf("avail HEAP %8d b %5d kb\n", heap, heap >> 10); 135 | 136 | // #if ARDUINO_TEENSY41 137 | // auto psram = _extram_start + (external_psram_size << 20) - _extram_end; 138 | // printf("avail PSRAM %8d b %5d kb\n", psram, psram >> 10); 139 | // #endif 140 | // } 141 | 142 | // uint32_t *ptrFreeITCM; // Set to Usable ITCM free RAM 143 | // uint32_t sizeofFreeITCM; // sizeof free RAM in uint32_t units. 144 | // uint32_t SizeLeft_etext; 145 | // // extern uint32_t _stext; 146 | // // extern uint32_t _etext; 147 | // extern char _stext[], _etext[]; 148 | 149 | // FLASHMEM void getFreeITCM() 150 | // { // end of CODE ITCM, skip full 32 bits 151 | // if(DEBUG) Serial.println("\n\n++++++++++++++++++++++"); 152 | // SizeLeft_etext = (32 * 1024) - (((uint32_t)&_etext - (uint32_t)&_stext) % (32 * 1024)); 153 | // sizeofFreeITCM = SizeLeft_etext - 4; 154 | // sizeofFreeITCM /= sizeof(ptrFreeITCM[0]); 155 | // ptrFreeITCM = (uint32_t *)((uint32_t)&_stext + (uint32_t)&_etext + 4); 156 | // printf("Size of Free ITCM in Bytes = %u\n", sizeofFreeITCM * sizeof(ptrFreeITCM[0])); 157 | // printf("Start of Free ITCM = %u [%X] \n", ptrFreeITCM, ptrFreeITCM); 158 | // printf("End of Free ITCM = %u [%X] \n", ptrFreeITCM + sizeofFreeITCM, ptrFreeITCM + sizeofFreeITCM); 159 | // for (uint32_t ii = 0; ii < sizeofFreeITCM; ii++) 160 | // ptrFreeITCM[ii] = 1; 161 | // uint32_t jj = 0; 162 | // for (uint32_t ii = 0; ii < sizeofFreeITCM; ii++) 163 | // jj += ptrFreeITCM[ii]; 164 | // printf("ITCM DWORD cnt = %u [#bytes=%u] \n", jj, jj * 4); 165 | // } 166 | 167 | #endif 168 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Momentum 2 | Electrotechnique Momentum Synthesizer 3 | 4 | 3D Models - STL models of 3D printed components 5 | 6 | Manual - User Manual including build guide 7 | 8 | Momentum - Folder with source code, set-up for PlatformIO 9 | 10 | SDCard - Folder with 'factory presets'. Copy the contents of the SDCard folder straight onto a formatted micro SD card 11 | 12 | # Flashing firmware 13 | Get the firmware hex file from [RELEASES](https://github.com/ElectroTechnique/Momentum/releases) on the right 14 | See the User Manual sections on Flashing Firmware - use either TyUploader (recommended) or Teensy Loader. 15 | TyUploader is in [TyTools Releases](https://github.com/Koromix/tytools/releases) 16 | Teensy Loader is at [PJRC](https://www.pjrc.com/teensy/loader.html) 17 | -------------------------------------------------------------------------------- /SDCard/Bank1/1504780501: -------------------------------------------------------------------------------- 1 | {"PatchName":"Sciew","OSC1":{"Pitch":120,"Waveform":84,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":121,"Waveform":69,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":37,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":5,"PitchLFORate":0,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":254,"Res":14,"Mixer":0,"FilterEnv":112,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":1},"Amp":{"Attack":24,"Decay":20,"Sustain":127,"Release":59},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":9,"EnsembleEffectAmt":51,"EnsembleEffectMix":111,"ReverbEffectTime":0,"ReverbEffectMix":0,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":1504780501} -------------------------------------------------------------------------------- /SDCard/Bank1/2173298836: -------------------------------------------------------------------------------- 1 | {"PatchName":"Fizzy Brass","OSC1":{"Pitch":118,"Waveform":40,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":118,"Waveform":64,"Level":127,"PWAmount":63,"PWMAmount":124,"PWMSource":0,"PWMRate":26},"Detune":43,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":39,"Res":10,"Mixer":118,"FilterEnv":124,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":18,"Decay":38,"Sustain":64,"Release":69,"FilterVelocitySensitivity":0},"Amp":{"Attack":18,"Decay":20,"Sustain":74,"Release":59},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":8,"EnsembleEffectMix":31,"ReverbEffectTime":47,"ReverbEffectMix":40,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":2173298836} -------------------------------------------------------------------------------- /SDCard/Bank1/2275129409: -------------------------------------------------------------------------------- 1 | {"PatchName":"Swell","OSC1":{"Pitch":7,"Waveform":76,"Level":127,"PWAmount":63,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"OSC2":{"Pitch":0,"Waveform":76,"Level":127,"PWAmount":63,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"Detune":52,"NoiseLevel":63,"Unison":1,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":65,"Res":31,"Mixer":0,"FilterEnv":125,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":34,"Decay":29,"Sustain":111,"Release":87,"FilterVelocitySensitivity":0},"Amp":{"Attack":12,"Decay":20,"Sustain":111,"Release":66},"KeyTracking":0,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":8,"EnsembleEffectMix":38,"ReverbEffectTime":27,"ReverbEffectMix":51,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":2275129409} -------------------------------------------------------------------------------- /SDCard/Bank1/256978124: -------------------------------------------------------------------------------- 1 | {"PatchName":"Power Brass","OSC1":{"Pitch":7,"Waveform":81,"Level":127,"PWAmount":63,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"OSC2":{"Pitch":0,"Waveform":82,"Level":127,"PWAmount":63,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"Detune":42,"NoiseLevel":63,"Unison":1,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":65,"Res":31,"Mixer":0,"FilterEnv":127,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":12,"Decay":29,"Sustain":126,"Release":26,"FilterVelocitySensitivity":0},"Amp":{"Attack":12,"Decay":20,"Sustain":111,"Release":40},"KeyTracking":0,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":8,"EnsembleEffectMix":38,"ReverbEffectTime":27,"ReverbEffectMix":51,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":256978124} -------------------------------------------------------------------------------- /SDCard/Bank1/2991689649: -------------------------------------------------------------------------------- 1 | {"PatchName":"Hi Strings","OSC1":{"Pitch":119,"Waveform":63,"Level":123,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"OSC2":{"Pitch":122,"Waveform":62,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"Detune":55,"NoiseLevel":64,"Unison":0,"OscFX":0,"PitchEnv":66,"PitchLFOAmt":0,"PitchLFORate":0,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":41,"Res":27,"Mixer":71,"FilterEnv":63,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":3,"Decay":92,"Sustain":7,"Release":77,"FilterVelocitySensitivity":0},"Amp":{"Attack":6,"Decay":48,"Sustain":127,"Release":45},"KeyTracking":0,"VelocitySensitivity":0,"ChordDetune":127,"MonophonicMode":0,"Glide":9,"EnsembleEffectAmt":3,"EnsembleEffectMix":127,"ReverbEffectTime":79,"ReverbEffectMix":40,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":2991689649} -------------------------------------------------------------------------------- /SDCard/Bank1/3078337974: -------------------------------------------------------------------------------- 1 | {"PatchName":"AFX Strings","OSC1":{"Pitch":119,"Waveform":45,"Level":127,"PWAmount":63,"PWMAmount":127,"PWMSource":0,"PWMRate":15},"OSC2":{"Pitch":119,"Waveform":41,"Level":127,"PWAmount":63,"PWMAmount":127,"PWMSource":0,"PWMRate":12},"Detune":48,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":1,"Res":39,"Mixer":79,"FilterEnv":62,"LFORate":19,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":49,"LFOWaveform":0,"Attack":42,"Decay":4,"Sustain":127,"Release":21,"FilterVelocitySensitivity":0},"Amp":{"Attack":27,"Decay":13,"Sustain":80,"Release":71},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":62,"EnsembleEffectMix":91,"ReverbEffectTime":113,"ReverbEffectMix":75,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":3078337974} -------------------------------------------------------------------------------- /SDCard/Bank1/3421571788: -------------------------------------------------------------------------------- 1 | {"PatchName":"Synth Brass","OSC1":{"Pitch":0,"Waveform":82,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":4},"OSC2":{"Pitch":7,"Waveform":93,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"Detune":36,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":5,"PitchLFORate":0,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":174,"Res":24,"Mixer":0,"FilterEnv":64,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":17,"Decay":90,"Sustain":39,"Release":39,"FilterVelocitySensitivity":1},"Amp":{"Attack":0,"Decay":21,"Sustain":127,"Release":15},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":0,"EnsembleEffectMix":0,"ReverbEffectTime":0,"ReverbEffectMix":0,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":3421571788} -------------------------------------------------------------------------------- /SDCard/Bank1/4044366186: -------------------------------------------------------------------------------- 1 | {"PatchName":"Ensemble Strings","OSC1":{"Pitch":63,"Waveform":47,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":64,"Waveform":49,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":27,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":234,"Res":27,"Mixer":0,"FilterEnv":89,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":8,"Decay":20,"Sustain":80,"Release":25},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":19,"EnsembleEffectMix":88,"ReverbEffectTime":42,"ReverbEffectMix":21,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":4044366186}{"PatchName":"Ensemble Strings","OSC1":{"Pitch":63,"Waveform":47,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":64,"Waveform":49,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":27,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":234,"Res":27,"Mixer":0,"FilterEnv":89,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":8,"Decay":20,"Sustain":80,"Release":25},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":19,"EnsembleEffectMix":88,"ReverbEffectTime":42,"ReverbEffectMix":21,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":4044366186}{"PatchName":"Ensemble Strings","OSC1":{"Pitch":63,"Waveform":47,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":64,"Waveform":49,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":27,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":234,"Res":27,"Mixer":0,"FilterEnv":89,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":8,"Decay":20,"Sustain":80,"Release":25},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":19,"EnsembleEffectMix":88,"ReverbEffectTime":42,"ReverbEffectMix":21,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":4044366186}{"PatchName":"Ensemble Strings","OSC1":{"Pitch":63,"Waveform":47,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":64,"Waveform":49,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":27,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":234,"Res":27,"Mixer":0,"FilterEnv":89,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":8,"Decay":20,"Sustain":80,"Release":25},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":19,"EnsembleEffectMix":88,"ReverbEffectTime":42,"ReverbEffectMix":21,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":4044366186}{"PatchName":"Ensemble Strings","OSC1":{"Pitch":63,"Waveform":47,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":64,"Waveform":49,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":27,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":234,"Res":27,"Mixer":0,"FilterEnv":89,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":8,"Decay":20,"Sustain":80,"Release":25},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":19,"EnsembleEffectMix":88,"ReverbEffectTime":42,"ReverbEffectMix":21,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":4044366186}{"PatchName":"Ensemble Strings","OSC1":{"Pitch":63,"Waveform":47,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":64,"Waveform":49,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":27,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":234,"Res":27,"Mixer":0,"FilterEnv":89,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":8,"Decay":20,"Sustain":80,"Release":25},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":19,"EnsembleEffectMix":88,"ReverbEffectTime":42,"ReverbEffectMix":21,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":4044366186}{"PatchName":"Ensemble Strings","OSC1":{"Pitch":63,"Waveform":47,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":64,"Waveform":49,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":27,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":234,"Res":27,"Mixer":0,"FilterEnv":89,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":8,"Decay":20,"Sustain":80,"Release":25},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":19,"EnsembleEffectMix":88,"ReverbEffectTime":42,"ReverbEffectMix":21,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":4044366186} -------------------------------------------------------------------------------- /SDCard/Bank1/916744880: -------------------------------------------------------------------------------- 1 | {"PatchName":"Syn Brass","OSC1":{"Pitch":6,"Waveform":90,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":5},"OSC2":{"Pitch":9,"Waveform":84,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"Detune":54,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":74,"Res":28,"Mixer":0,"FilterEnv":112,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":15,"Decay":22,"Sustain":61,"Release":26,"FilterVelocitySensitivity":0},"Amp":{"Attack":10,"Decay":35,"Sustain":122,"Release":26},"KeyTracking":0,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":0,"EnsembleEffectMix":0,"ReverbEffectTime":8,"ReverbEffectMix":0,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":916744880}{"PatchName":"Syn Brass","OSC1":{"Pitch":6,"Waveform":90,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":5},"OSC2":{"Pitch":9,"Waveform":84,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"Detune":54,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":74,"Res":28,"Mixer":0,"FilterEnv":112,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":15,"Decay":22,"Sustain":61,"Release":26,"FilterVelocitySensitivity":0},"Amp":{"Attack":10,"Decay":35,"Sustain":122,"Release":26},"KeyTracking":0,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":0,"EnsembleEffectMix":0,"ReverbEffectTime":8,"ReverbEffectMix":0,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":916744880} -------------------------------------------------------------------------------- /SDCard/Bank1/Patchindex: -------------------------------------------------------------------------------- 1 | {"1":4044366186,"2":1504780501,"3":3421571788,"4":3078337974,"5":916744880,"6":2991689649,"7":2173298836,"8":256978124,"9":2275129409,"10":916744880} -------------------------------------------------------------------------------- /SDCard/Bank2/1022321240: -------------------------------------------------------------------------------- 1 | {"PatchName":"Square Bass","OSC1":{"Pitch":0,"Waveform":33,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":1,"Waveform":36,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":42,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":40,"Res":19,"Mixer":0,"FilterEnv":112,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":20,"Sustain":127,"Release":35},"KeyTracking":127,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":8,"EnsembleEffectMix":45,"ReverbEffectTime":24,"ReverbEffectMix":0,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":1022321240} -------------------------------------------------------------------------------- /SDCard/Bank2/1231019462: -------------------------------------------------------------------------------- 1 | {"PatchName":"Simplex","OSC1":{"Pitch":0,"Waveform":75,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":8,"Waveform":75,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":10,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":52,"Res":10,"Mixer":0,"FilterEnv":89,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":1},"Amp":{"Attack":0,"Decay":20,"Sustain":80,"Release":25},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":8,"EnsembleEffectMix":0,"ReverbEffectTime":0,"ReverbEffectMix":0,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":1231019462} -------------------------------------------------------------------------------- /SDCard/Bank2/1337423881: -------------------------------------------------------------------------------- 1 | {"PatchName":"Mod Bass","OSC1":{"Pitch":0,"Waveform":75,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":1,"Waveform":75,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":42,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":42,"Res":36,"Mixer":0,"FilterEnv":112,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":1},"Amp":{"Attack":0,"Decay":20,"Sustain":127,"Release":35},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":8,"EnsembleEffectMix":45,"ReverbEffectTime":24,"ReverbEffectMix":0,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":1337423881} -------------------------------------------------------------------------------- /SDCard/Bank2/2803543883: -------------------------------------------------------------------------------- 1 | {"PatchName":"PWM Unison","OSC1":{"Pitch":0,"Waveform":76,"Level":127,"PWAmount":63,"PWMAmount":124,"PWMSource":0,"PWMRate":11},"OSC2":{"Pitch":1,"Waveform":75,"Level":127,"PWAmount":63,"PWMAmount":122,"PWMSource":0,"PWMRate":12},"Detune":77,"NoiseLevel":63,"Unison":1,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":114,"Res":23,"Mixer":0,"FilterEnv":118,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":20,"Sustain":127,"Release":35},"KeyTracking":1,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":8,"EnsembleEffectMix":92,"ReverbEffectTime":0,"ReverbEffectMix":0,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":2803543883} -------------------------------------------------------------------------------- /SDCard/Bank2/2829671085: -------------------------------------------------------------------------------- 1 | {"PatchName":"Solid Bass","OSC1":{"Pitch":0,"Waveform":81,"Level":127,"PWAmount":64,"PWMAmount":123,"PWMSource":1,"PWMRate":23},"OSC2":{"Pitch":0,"Waveform":87,"Level":127,"PWAmount":63,"PWMAmount":124,"PWMSource":1,"PWMRate":10},"Detune":45,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":230,"Res":10,"Mixer":0,"FilterEnv":106,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":73,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":20,"Sustain":80,"Release":25},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":8,"EnsembleEffectMix":31,"ReverbEffectTime":8,"ReverbEffectMix":0,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":2829671085} -------------------------------------------------------------------------------- /SDCard/Bank2/304633332: -------------------------------------------------------------------------------- 1 | {"PatchName":"Elec Bass","OSC1":{"Pitch":0,"Waveform":83,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"OSC2":{"Pitch":0,"Waveform":84,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"Detune":47,"NoiseLevel":63,"Unison":1,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":200,"Res":26,"Mixer":0,"FilterEnv":127,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":51,"Sustain":22,"Release":77,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":48,"Sustain":84,"Release":45},"KeyTracking":0,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":45,"EnsembleEffectMix":63,"ReverbEffectTime":8,"ReverbEffectMix":0,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":304633332} -------------------------------------------------------------------------------- /SDCard/Bank2/3053187522: -------------------------------------------------------------------------------- 1 | {"PatchName":"Acid Dream","OSC1":{"Pitch":0,"Waveform":42,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":1,"Waveform":0,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":0,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":85,"Res":127,"Mixer":0,"FilterEnv":116,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":9,"Decay":6,"Sustain":0,"Release":26,"FilterVelocitySensitivity":2},"Amp":{"Attack":0,"Decay":20,"Sustain":127,"Release":35},"KeyTracking":20,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":8,"EnsembleEffectMix":45,"ReverbEffectTime":24,"ReverbEffectMix":0,"FilterEnvShape":8,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":3053187522} -------------------------------------------------------------------------------- /SDCard/Bank2/3390698083: -------------------------------------------------------------------------------- 1 | {"PatchName":"Hook Bass","OSC1":{"Pitch":0,"Waveform":75,"Level":127,"PWAmount":115,"PWMAmount":63,"PWMSource":2,"PWMRate":10},"OSC2":{"Pitch":0,"Waveform":75,"Level":127,"PWAmount":24,"PWMAmount":63,"PWMSource":2,"PWMRate":10},"Detune":69,"NoiseLevel":63,"Unison":1,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":126,"Res":18,"Mixer":40,"FilterEnv":116,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":25,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":16,"Sustain":57,"Release":35},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":6,"EnsembleEffectMix":80,"ReverbEffectTime":61,"ReverbEffectMix":34,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":7,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":3390698083} -------------------------------------------------------------------------------- /SDCard/Bank2/3796215573: -------------------------------------------------------------------------------- 1 | {"PatchName":"Expensive Sound","OSC1":{"Pitch":0,"Waveform":46,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":0,"Waveform":42,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":77,"NoiseLevel":63,"Unison":1,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":68,"Res":63,"Mixer":0,"FilterEnv":127,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":84,"Decay":87,"Sustain":8,"Release":87,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":20,"Sustain":127,"Release":53},"KeyTracking":72,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":8,"EnsembleEffectMix":61,"ReverbEffectTime":8,"ReverbEffectMix":0,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":3796215573} -------------------------------------------------------------------------------- /SDCard/Bank2/885943129: -------------------------------------------------------------------------------- 1 | {"PatchName":"Birdland Bass","OSC1":{"Pitch":0,"Waveform":91,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":0},"OSC2":{"Pitch":0,"Waveform":89,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"Detune":70,"NoiseLevel":63,"Unison":1,"OscFX":1,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":56,"Res":40,"Mixer":0,"FilterEnv":115,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":7,"Decay":15,"Sustain":31,"Release":27,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":0,"Sustain":80,"Release":12},"KeyTracking":0,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":0,"EnsembleEffectMix":0,"ReverbEffectTime":8,"ReverbEffectMix":0,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":885943129} -------------------------------------------------------------------------------- /SDCard/Bank2/Patchindex: -------------------------------------------------------------------------------- 1 | {"1":2803543883,"2":1231019462,"3":1337423881,"4":1022321240,"5":3053187522,"6":3796215573,"7":304633332,"8":885943129,"9":2829671085,"10":3390698083}} -------------------------------------------------------------------------------- /SDCard/Bank3/1519828906: -------------------------------------------------------------------------------- 1 | {"PatchName":"SQ Lead","OSC1":{"Pitch":118,"Waveform":7,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"OSC2":{"Pitch":122,"Waveform":35,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"Detune":55,"NoiseLevel":64,"Unison":0,"OscFX":0,"PitchEnv":66,"PitchLFOAmt":0,"PitchLFORate":0,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":50,"Res":27,"Mixer":66,"FilterEnv":58,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":92,"Sustain":7,"Release":77,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":48,"Sustain":127,"Release":45},"KeyTracking":0,"VelocitySensitivity":0,"ChordDetune":127,"MonophonicMode":1,"Glide":9,"EnsembleEffectAmt":3,"EnsembleEffectMix":97,"ReverbEffectTime":74,"ReverbEffectMix":110,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":1519828906} -------------------------------------------------------------------------------- /SDCard/Bank3/1555103360: -------------------------------------------------------------------------------- 1 | {"PatchName":"Marimbaphone","OSC1":{"Pitch":0,"Waveform":17,"Level":111,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":62,"Waveform":127,"Level":127,"PWAmount":63,"PWMAmount":28,"PWMSource":0,"PWMRate":10},"Detune":42,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":40,"Res":19,"Mixer":0,"FilterEnv":112,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":20,"Sustain":127,"Release":35},"KeyTracking":127,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":8,"EnsembleEffectMix":0,"ReverbEffectTime":66,"ReverbEffectMix":50,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":1555103360} -------------------------------------------------------------------------------- /SDCard/Bank3/2266998631: -------------------------------------------------------------------------------- 1 | {"PatchName":"E Piano","OSC1":{"Pitch":6,"Waveform":84,"Level":63,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":64,"Waveform":115,"Level":127,"PWAmount":63,"PWMAmount":28,"PWMSource":0,"PWMRate":10},"Detune":7,"NoiseLevel":63,"Unison":0,"OscFX":1,"PitchEnv":63,"PitchLFOAmt":6,"PitchLFORate":38,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":60,"Res":19,"Mixer":0,"FilterEnv":112,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":24,"Sustain":54,"Release":34},"KeyTracking":127,"VelocitySensitivity":2,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":8,"EnsembleEffectMix":0,"ReverbEffectTime":47,"ReverbEffectMix":71,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":2,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":2266998631} -------------------------------------------------------------------------------- /SDCard/Bank3/3426240329: -------------------------------------------------------------------------------- 1 | {"PatchName":"Exit","OSC1":{"Pitch":63,"Waveform":8,"Level":20,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":62,"Waveform":121,"Level":127,"PWAmount":63,"PWMAmount":28,"PWMSource":0,"PWMRate":10},"Detune":36,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":255,"Res":0,"Mixer":0,"FilterEnv":63,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":20,"Sustain":127,"Release":35},"KeyTracking":0,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":2,"EnsembleEffectMix":64,"ReverbEffectTime":61,"ReverbEffectMix":16,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":3426240329} -------------------------------------------------------------------------------- /SDCard/Bank3/3733337278: -------------------------------------------------------------------------------- 1 | {"PatchName":"LFO Time!","OSC1":{"Pitch":0,"Waveform":75,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":8,"Waveform":75,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":20,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":11,"PitchLFORate":50,"PitchLFOWaveform":43,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":61,"Res":53,"Mixer":0,"FilterEnv":105,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":1,"LfoAmt":29,"LFOWaveform":20,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":20,"Sustain":80,"Release":38},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":8,"EnsembleEffectMix":44,"ReverbEffectTime":8,"ReverbEffectMix":0,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":2,"FilterModWheelDepth":0,"UID":3733337278} -------------------------------------------------------------------------------- /SDCard/Bank3/3826079193: -------------------------------------------------------------------------------- 1 | {"PatchName":"Vibrations","OSC1":{"Pitch":121,"Waveform":83,"Level":127,"PWAmount":4,"PWMAmount":63,"PWMSource":2,"PWMRate":10},"OSC2":{"Pitch":124,"Waveform":43,"Level":106,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":25,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":7,"PitchLFORate":49,"PitchLFOWaveform":1,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":102,"Res":24,"Mixer":0,"FilterEnv":90,"LFORate":48,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":22,"LFOWaveform":2,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":2,"Decay":15,"Sustain":72,"Release":80},"KeyTracking":127,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":17,"EnsembleEffectMix":70,"ReverbEffectTime":53,"ReverbEffectMix":104,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":3826079193} -------------------------------------------------------------------------------- /SDCard/Bank3/3851442546: -------------------------------------------------------------------------------- 1 | {"PatchName":"Simply","OSC1":{"Pitch":121,"Waveform":36,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":127,"Waveform":38,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":43,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":32,"Res":4,"Mixer":0,"FilterEnv":119,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":17,"Sustain":0,"Release":14,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":18,"Sustain":15,"Release":28},"KeyTracking":96,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":0,"EnsembleEffectMix":0,"ReverbEffectTime":0,"ReverbEffectMix":0,"FilterEnvShape":8,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":3851442546} -------------------------------------------------------------------------------- /SDCard/Bank3/47066540: -------------------------------------------------------------------------------- 1 | {"PatchName":"HPF Lead","OSC1":{"Pitch":6,"Waveform":63,"Level":127,"PWAmount":63,"PWMAmount":81,"PWMSource":0,"PWMRate":12},"OSC2":{"Pitch":7,"Waveform":60,"Level":127,"PWAmount":63,"PWMAmount":88,"PWMSource":0,"PWMRate":27},"Detune":28,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":64,"Res":91,"Mixer":82,"FilterEnv":97,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":20,"Sustain":80,"Release":25},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":8,"EnsembleEffectMix":31,"ReverbEffectTime":8,"ReverbEffectMix":0,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":47066540} -------------------------------------------------------------------------------- /SDCard/Bank3/Patchindex: -------------------------------------------------------------------------------- 1 | {"1":47066540,"2":1555103360,"3":3733337278,"4":2266998631,"5":3851442546,"6":1519828906,"7":3426240329,"8":3826079193} -------------------------------------------------------------------------------- /SDCard/Bank4/1126472567: -------------------------------------------------------------------------------- 1 | {"PatchName":"UFO","OSC1":{"Pitch":0,"Waveform":10,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"OSC2":{"Pitch":127,"Waveform":35,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"Detune":127,"NoiseLevel":63,"Unison":2,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":0,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":254,"Res":27,"Mixer":0,"FilterEnv":58,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":51,"Sustain":127,"Release":77,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":48,"Sustain":127,"Release":45},"KeyTracking":0,"VelocitySensitivity":0,"ChordDetune":127,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":3,"EnsembleEffectMix":127,"ReverbEffectTime":8,"ReverbEffectMix":0,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":1126472567} -------------------------------------------------------------------------------- /SDCard/Bank4/1361350319: -------------------------------------------------------------------------------- 1 | {"PatchName":"Tunnel","OSC1":{"Pitch":0,"Waveform":0,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":127,"Waveform":17,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":20,"NoiseLevel":0,"Unison":1,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":90,"Res":125,"Mixer":127,"FilterEnv":52,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":13,"Sustain":11,"Release":6,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":14,"Sustain":0,"Release":6},"KeyTracking":85,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":0,"EnsembleEffectMix":0,"ReverbEffectTime":114,"ReverbEffectMix":40,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":1361350319} -------------------------------------------------------------------------------- /SDCard/Bank4/2010595689: -------------------------------------------------------------------------------- 1 | {"PatchName":"Jet Stream","OSC1":{"Pitch":6,"Waveform":0,"Level":63,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":126,"Waveform":14,"Level":127,"PWAmount":63,"PWMAmount":28,"PWMSource":0,"PWMRate":10},"Detune":40,"NoiseLevel":127,"Unison":1,"OscFX":1,"PitchEnv":63,"PitchLFOAmt":6,"PitchLFORate":38,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":59,"Res":16,"Mixer":127,"FilterEnv":112,"LFORate":6,"LFORetrig":1,"LFOMidiClkSync":0,"LfoAmt":70,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":23,"Sustain":127,"Release":34},"KeyTracking":127,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":0,"EnsembleEffectMix":46,"ReverbEffectTime":39,"ReverbEffectMix":21,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":2,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":2010595689} -------------------------------------------------------------------------------- /SDCard/Bank4/2255545869: -------------------------------------------------------------------------------- 1 | {"PatchName":"Autobell","OSC1":{"Pitch":110,"Waveform":107,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":119,"Waveform":34,"Level":0,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":0,"NoiseLevel":64,"Unison":0,"OscFX":2,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":200,"Res":29,"Mixer":0,"FilterEnv":127,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":78,"Decay":89,"Sustain":17,"Release":81,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":51,"Sustain":86,"Release":51},"KeyTracking":72,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":8,"EnsembleEffectMix":115,"ReverbEffectTime":20,"ReverbEffectMix":30,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":2255545869} -------------------------------------------------------------------------------- /SDCard/Bank4/2343874542: -------------------------------------------------------------------------------- 1 | {"PatchName":"Desert Dream","OSC1":{"Pitch":127,"Waveform":84,"Level":76,"PWAmount":63,"PWMAmount":127,"PWMSource":0,"PWMRate":15},"OSC2":{"Pitch":37,"Waveform":87,"Level":2,"PWAmount":63,"PWMAmount":127,"PWMSource":0,"PWMRate":12},"Detune":28,"NoiseLevel":63,"Unison":0,"OscFX":2,"PitchEnv":63,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":59,"Res":17,"Mixer":0,"FilterEnv":97,"LFORate":19,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":49,"LFOWaveform":0,"Attack":9,"Decay":38,"Sustain":111,"Release":99,"FilterVelocitySensitivity":0},"Amp":{"Attack":6,"Decay":30,"Sustain":91,"Release":73},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":1,"Glide":0,"EnsembleEffectAmt":19,"EnsembleEffectMix":74,"ReverbEffectTime":79,"ReverbEffectMix":77,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":2343874542} -------------------------------------------------------------------------------- /SDCard/Bank4/2479572785: -------------------------------------------------------------------------------- 1 | {"PatchName":"Complex","OSC1":{"Pitch":119,"Waveform":45,"Level":127,"PWAmount":63,"PWMAmount":127,"PWMSource":0,"PWMRate":15},"OSC2":{"Pitch":119,"Waveform":41,"Level":127,"PWAmount":63,"PWMAmount":127,"PWMSource":0,"PWMRate":12},"Detune":48,"NoiseLevel":63,"Unison":0,"OscFX":0,"PitchEnv":127,"PitchLFOAmt":0,"PitchLFORate":10,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":119,"Res":92,"Mixer":80,"FilterEnv":111,"LFORate":19,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":49,"LFOWaveform":0,"Attack":21,"Decay":3,"Sustain":0,"Release":22,"FilterVelocitySensitivity":0},"Amp":{"Attack":27,"Decay":0,"Sustain":64,"Release":10},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":62,"EnsembleEffectMix":67,"ReverbEffectTime":102,"ReverbEffectMix":41,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":2479572785} -------------------------------------------------------------------------------- /SDCard/Bank4/3723771264: -------------------------------------------------------------------------------- 1 | {"PatchName":"Rumble","OSC1":{"Pitch":63,"Waveform":0,"Level":0,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"OSC2":{"Pitch":64,"Waveform":14,"Level":127,"PWAmount":63,"PWMAmount":63,"PWMSource":0,"PWMRate":10},"Detune":27,"NoiseLevel":127,"Unison":1,"OscFX":0,"PitchEnv":63,"PitchLFOAmt":41,"PitchLFORate":120,"PitchLFOWaveform":127,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":40,"Res":13,"Mixer":0,"FilterEnv":64,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":20,"Sustain":80,"Release":50,"FilterVelocitySensitivity":0},"Amp":{"Attack":8,"Decay":20,"Sustain":127,"Release":25},"KeyTracking":63,"VelocitySensitivity":0,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":3,"EnsembleEffectMix":54,"ReverbEffectTime":0,"ReverbEffectMix":0,"FilterEnvShape":9,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":3723771264} -------------------------------------------------------------------------------- /SDCard/Bank4/Patchindex: -------------------------------------------------------------------------------- 1 | {"1":2343874542,"2":1361350319,"3":3723771264,"4":2010595689,"5":2255545869,"6":1126472567,"7":2479572785} -------------------------------------------------------------------------------- /SDCard/Bank5/3373092806: -------------------------------------------------------------------------------- 1 | {"PatchName":"Snare","OSC1":{"Pitch":0,"Waveform":0,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":4},"OSC2":{"Pitch":127,"Waveform":9,"Level":27,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"Detune":3,"NoiseLevel":22,"Unison":1,"OscFX":1,"PitchEnv":63,"PitchLFOAmt":5,"PitchLFORate":0,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":14,"Res":127,"Mixer":125,"FilterEnv":127,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":9,"Sustain":0,"Release":0,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":13,"Sustain":0,"Release":12},"KeyTracking":127,"VelocitySensitivity":3,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":0,"EnsembleEffectMix":0,"ReverbEffectTime":0,"ReverbEffectMix":0,"FilterEnvShape":11,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":3373092806} -------------------------------------------------------------------------------- /SDCard/Bank5/3794887208: -------------------------------------------------------------------------------- 1 | {"PatchName":"Bass Drum 2","OSC1":{"Pitch":0,"Waveform":0,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":4},"OSC2":{"Pitch":127,"Waveform":11,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"Detune":3,"NoiseLevel":0,"Unison":1,"OscFX":1,"PitchEnv":31,"PitchLFOAmt":5,"PitchLFORate":0,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":31,"Res":127,"Mixer":127,"FilterEnv":127,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":5,"Sustain":0,"Release":6,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":20,"Sustain":0,"Release":17},"KeyTracking":127,"VelocitySensitivity":3,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":0,"EnsembleEffectMix":0,"ReverbEffectTime":0,"ReverbEffectMix":0,"FilterEnvShape":11,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":3794887208} -------------------------------------------------------------------------------- /SDCard/Bank5/3959255724: -------------------------------------------------------------------------------- 1 | {"PatchName":"Snare 2","OSC1":{"Pitch":0,"Waveform":0,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":4},"OSC2":{"Pitch":127,"Waveform":0,"Level":27,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"Detune":3,"NoiseLevel":0,"Unison":1,"OscFX":1,"PitchEnv":63,"PitchLFOAmt":5,"PitchLFORate":0,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":88,"Res":127,"Mixer":125,"FilterEnv":127,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":0,"Sustain":0,"Release":0,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":13,"Sustain":0,"Release":12},"KeyTracking":127,"VelocitySensitivity":3,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":0,"EnsembleEffectMix":0,"ReverbEffectTime":0,"ReverbEffectMix":0,"FilterEnvShape":11,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":3959255724} -------------------------------------------------------------------------------- /SDCard/Bank5/3989574602: -------------------------------------------------------------------------------- 1 | {"PatchName":"Tub Drum","OSC1":{"Pitch":0,"Waveform":0,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":4},"OSC2":{"Pitch":127,"Waveform":11,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"Detune":3,"NoiseLevel":0,"Unison":1,"OscFX":1,"PitchEnv":63,"PitchLFOAmt":5,"PitchLFORate":0,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":31,"Res":127,"Mixer":127,"FilterEnv":127,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":0,"Sustain":0,"Release":0,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":13,"Sustain":0,"Release":12},"KeyTracking":127,"VelocitySensitivity":3,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":0,"EnsembleEffectMix":0,"ReverbEffectTime":0,"ReverbEffectMix":0,"FilterEnvShape":11,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":3989574602} -------------------------------------------------------------------------------- /SDCard/Bank5/676151029: -------------------------------------------------------------------------------- 1 | {"PatchName":"Bass Drum","OSC1":{"Pitch":0,"Waveform":0,"Level":127,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":4},"OSC2":{"Pitch":0,"Waveform":0,"Level":27,"PWAmount":127,"PWMAmount":127,"PWMSource":1,"PWMRate":10},"Detune":3,"NoiseLevel":0,"Unison":1,"OscFX":1,"PitchEnv":63,"PitchLFOAmt":5,"PitchLFORate":0,"PitchLFOWaveform":0,"PitchLFORetrig":0,"PitchLFOMidiClkSync":0,"Filter":{"Freq":58,"Res":127,"Mixer":127,"FilterEnv":127,"LFORate":10,"LFORetrig":0,"LFOMidiClkSync":0,"LfoAmt":0,"LFOWaveform":0,"Attack":0,"Decay":0,"Sustain":0,"Release":0,"FilterVelocitySensitivity":0},"Amp":{"Attack":0,"Decay":13,"Sustain":0,"Release":12},"KeyTracking":127,"VelocitySensitivity":3,"ChordDetune":0,"MonophonicMode":0,"Glide":0,"EnsembleEffectAmt":0,"EnsembleEffectMix":0,"ReverbEffectTime":0,"ReverbEffectMix":0,"FilterEnvShape":11,"AmpEnvShape":9,"GlideShape":1,"PitchBend":12,"PitchModWheelDepth":1,"FilterModWheelDepth":0,"UID":676151029} -------------------------------------------------------------------------------- /SDCard/Bank5/Patchindex: -------------------------------------------------------------------------------- 1 | {"1":3989574602,"2":3373092806,"3":3959255724,"4":676151029,"5":3794887208} -------------------------------------------------------------------------------- /SDCard/Banknames: -------------------------------------------------------------------------------- 1 | {"Bank1":"Strings and Brass","Bank2":"Basses","Bank3":"Keys","Bank4":"FX","Bank5":"Perc","Bank6":"User 1","Bank7":"User 2","Bank8":"User 3"} -------------------------------------------------------------------------------- /SDCard/Performances/1: -------------------------------------------------------------------------------- 1 | {"PerformanceName":"Ensemble","Mode":0,"Patches":[{"Bank":0,"UID":4044366186,"MidiChIn":0,"MidiChOut":0,"MidiThru":0,"Min":0,"Max":127},{"Bank":0,"UID":0,"MidiChIn":0,"MidiChOut":0,"MidiThru":0,"Min":0,"Max":127}],"Encoders":{"TL":91,"TR":93,"BL":97,"BR":98}} -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [platformio] 12 | src_dir = Momentum 13 | 14 | [env:teensymm] 15 | platform = teensy 16 | board = teensymm 17 | framework = arduino 18 | build_flags = -D USB_MIDI_AUDIO_SERIAL 19 | lib_deps = 20 | rlogiacco/CircularBuffer@^1.3.3 21 | adafruit/Adafruit GFX Library@^1.10.7 22 | ftrias/TeensyThreads@^1.0.1 23 | adafruit/Adafruit BusIO@^1.7.3 24 | kurte/ILI9341_t3n@0.0.0-alpha+sha.f1bfb81825 25 | sukkopera/RokkitHash@0.0.0-alpha+sha.20151212 26 | janelia-arduino/Array@^1.2.1 27 | luni64/TeensyTimerTool@^1.2.0 28 | bblanchon/ArduinoJson@6.19.4 29 | --------------------------------------------------------------------------------