diff --git a/Changelog b/Changelog index c5920005e..8a056aa38 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,65 @@ +MCL 4.60 21/09/2024 + +Please upgrade to Machinedrum OS X.11 & Monomachine OS X.01 before using MCL 4.60. + +- Sequencer: + + The MD's in-built MIDI machines are now supported via the MCL sequencer. + MIDI data is transmitted on MegaCommand's MIDI Port 2. + +- Grid Page: + + It's now possible to reconfigure the Grid Page Encoders to act as the four + Performance Controllers. Via option: Config -> Page Setup -> Grid Encod + + When selecting multiple rows for copy/clear/paste operations the corresponding Bank/Pattern id is now displayed on the left. + +- Mixer Page: + + Performance States (formerly Mute Sets): + + As previously, there are 4 Performance States, each mapped to an individual [Up/Down/Left/Right] key. + Each Performance State contains Mute settings for the MD and External MIDI tracks, and 4 Performance Controller Locks. + + Press [Scale] to toggle the Mixer's active device between MD and External MIDI. + + The Mutes in a Performance State can be deactivated for the active device by holding an [Up/Down/Left/Right] key and pressing [Mute/BankA] + + Apply Performance States: + - To apply a Performance State during a performance, hold down an [Up/Down/Left/Right] Key and press [YES] + + Performance State Autoload: + A chosen Performance State can now be made to auto-load when the Perf Slot in Grid Y is loaded: + - From the Mixer Page, Hold an [ Arrow ] key to visually preview the Performance State and then press [Accent/BANKB] to enable auto "LOAD". + - Then save the Perf Slot, in Grid Y. + + Performance Controller AutoFill ( Kit Morph ): + - A Perf Controller's assigned left + right scenes can be cleared of paramater locks by holding down the MCL and pressing the MC's < Shift > button. + - A Perf Controller's assigned right scenes can be auto-filled altered Kit parameters by holding down the MCL + and pressing the MC's button. + +- Misc: + + The Port 1 MIDI driver can now be optionally changed to Generic. + + Performance optimizations and improvements. + +- Bug Fixes: + + Fixed device selection in Chromatic Page + + Route and Perf track types would not load correctly during transitions + + WavDesigner sample transfer was broken. + + GUI fixes for SampleBrowser and text input related pages. + + MD's random LFO shape was broken when loading with MCL. + + MCL LFO could transmit bogus MIDI data. + + MCL would crash when loading tracks at very slow tempo 30BPM. + MCL 4.51a 20/12/2023 Fixed [ Func ] + [ Clear ] regression in PianoRoll. diff --git a/avr/cores/megacommand/A4/A4.cpp b/avr/cores/megacommand/A4/A4.cpp index 4e9460c1d..0342a5cb4 100644 --- a/avr/cores/megacommand/A4/A4.cpp +++ b/avr/cores/megacommand/A4/A4.cpp @@ -152,83 +152,50 @@ void A4Class::requestGlobalX(uint8_t global) { sendRequest(A4_GLOBALX_REQUEST_ID, global); } -bool A4Class::getBlockingSound(uint8_t sound, uint16_t timeout) { - SysexCallback cb; - A4SysexListener.addOnSoundMessageCallback( - &cb, (sysex_callback_ptr_t)&SysexCallback::onSysexReceived); - requestSound(sound); - connected = cb.waitBlocking(timeout); - A4SysexListener.removeOnSoundMessageCallback(&cb); +bool A4Class::getBlockingGeneric(uint16_t timeout) { + SysexCallback cb; + A4SysexListener.addOnMessageCallback(&cb, (sysex_callback_ptr_t)&SysexCallback::onSysexReceived); + bool connected = cb.waitBlocking(timeout); + A4SysexListener.removeOnMessageCallback(&cb); + return connected; +} - return connected; +bool A4Class::getBlockingSound(uint8_t sound, uint16_t timeout) { + requestSound(sound); + return getBlockingGeneric(timeout); } bool A4Class::getBlockingSettings(uint8_t settings, uint16_t timeout) { - SysexCallback cb; - A4SysexListener.addOnSettingsMessageCallback( - &cb, (sysex_callback_ptr_t)&SysexCallback::onSysexReceived); - requestSettings(settings); - connected = cb.waitBlocking(timeout); - A4SysexListener.removeOnSettingsMessageCallback(&cb); - - return connected; + requestSettings(settings); + return getBlockingGeneric(timeout); } bool A4Class::getBlockingKitX(uint8_t kit, uint16_t timeout) { - SysexCallback cb; - A4SysexListener.addOnKitMessageCallback( - &cb, (sysex_callback_ptr_t)&SysexCallback::onSysexReceived); - requestKitX(kit); - connected = cb.waitBlocking(timeout); - A4SysexListener.removeOnKitMessageCallback(&cb); - - return connected; + requestKitX(kit); + return getBlockingGeneric(timeout); } bool A4Class::getBlockingPatternX(uint8_t pattern, uint16_t timeout) { - SysexCallback cb; - A4SysexListener.addOnPatternMessageCallback( - &cb, (sysex_callback_ptr_t)&SysexCallback::onSysexReceived); - requestPatternX(pattern); - connected = cb.waitBlocking(timeout); - A4SysexListener.removeOnPatternMessageCallback(&cb); - - return connected; + requestPatternX(pattern); + return getBlockingGeneric(timeout); } bool A4Class::getBlockingGlobalX(uint8_t global, uint16_t timeout) { - SysexCallback cb; - A4SysexListener.addOnGlobalMessageCallback( - &cb, (sysex_callback_ptr_t)&SysexCallback::onSysexReceived); - requestGlobalX(global); - connected = cb.waitBlocking(timeout); - A4SysexListener.removeOnGlobalMessageCallback(&cb); - - return connected; + requestGlobalX(global); + return getBlockingGeneric(timeout); } bool A4Class::getBlockingSoundX(uint8_t sound, uint16_t timeout) { - SysexCallback cb; - A4SysexListener.addOnSoundMessageCallback( - &cb, (sysex_callback_ptr_t)&SysexCallback::onSysexReceived); - requestSoundX(sound); - connected = cb.waitBlocking(timeout); - A4SysexListener.removeOnSoundMessageCallback(&cb); - - return connected; + requestSoundX(sound); + return getBlockingGeneric(timeout); } bool A4Class::getBlockingSettingsX(uint8_t settings, uint16_t timeout) { - SysexCallback cb; - A4SysexListener.addOnSettingsMessageCallback( - &cb, (sysex_callback_ptr_t)&SysexCallback::onSysexReceived); - requestSettingsX(settings); - connected = cb.waitBlocking(timeout); - A4SysexListener.removeOnSettingsMessageCallback(&cb); - - return connected; + requestSettingsX(settings); + return getBlockingGeneric(timeout); } -void A4Class::muteTrack(uint8_t track, bool mute = true, MidiUartParent *uart_ = nullptr) { + +void A4Class::muteTrack(uint8_t track, bool mute, MidiUartParent *uart_) { if (uart_ == nullptr) { uart_ = uart; } uart->sendCC(track, 94, mute); } diff --git a/avr/cores/megacommand/A4/A4.h b/avr/cores/megacommand/A4/A4.h index eefb5ab58..e458fadbd 100644 --- a/avr/cores/megacommand/A4/A4.h +++ b/avr/cores/megacommand/A4/A4.h @@ -84,7 +84,7 @@ class A4Class : public ElektronDevice { } virtual uint8_t get_mute_cc() { return 0x5E; } - + bool getBlockingGeneric(uint16_t timeout); /*X denotes get from RAM/unsaved */ bool getBlockingKitX(uint8_t kit, uint16_t timeout = 3000); bool getBlockingPatternX(uint8_t pattern, uint16_t timeout = 3000); diff --git a/avr/cores/megacommand/A4/A4Sysex.cpp b/avr/cores/megacommand/A4/A4Sysex.cpp index 02956634a..dd09a214f 100644 --- a/avr/cores/megacommand/A4/A4Sysex.cpp +++ b/avr/cores/megacommand/A4/A4Sysex.cpp @@ -52,51 +52,18 @@ void A4SysexListenerClass::end() { // break; case A4_GLOBAL_MESSAGE_ID: - onGlobalMessageCallbacks.call(); - break; - case A4_GLOBALX_MESSAGE_ID: - onGlobalMessageCallbacks.call(); - break; - case A4_KIT_MESSAGE_ID: - onKitMessageCallbacks.call(); - break; - case A4_KITX_MESSAGE_ID: - onKitMessageCallbacks.call(); - break; - case A4_SOUND_MESSAGE_ID: - onSoundMessageCallbacks.call(); - break; - case A4_SOUNDX_MESSAGE_ID: - onSoundMessageCallbacks.call(); - break; - case A4_PATTERN_MESSAGE_ID: - onPatternMessageCallbacks.call(); - break; - case A4_PATTERNX_MESSAGE_ID: - onPatternMessageCallbacks.call(); - break; - case A4_SONG_MESSAGE_ID: - onSongMessageCallbacks.call(); - break; - case A4_SONGX_MESSAGE_ID: - onSongMessageCallbacks.call(); - break; - case A4_SETTINGS_MESSAGE_ID: - onSettingsMessageCallbacks.call(); - break; - case A4_SETTINGSX_MESSAGE_ID: - onSettingsMessageCallbacks.call(); + onMessageCallbacks.call(); break; } diff --git a/avr/cores/megacommand/A4/A4Sysex.h b/avr/cores/megacommand/A4/A4Sysex.h index 883cde1a0..966c046d2 100644 --- a/avr/cores/megacommand/A4/A4Sysex.h +++ b/avr/cores/megacommand/A4/A4Sysex.h @@ -17,10 +17,6 @@ class A4SysexListenerClass : public ElektronSysexListenerClass { **/ public: - CallbackVector onSoundMessageCallbacks; - - CallbackVector onSettingsMessageCallbacks; - /** Stores if the currently received message is a MachineDrum sysex message. * **/ bool isA4Message; @@ -40,28 +36,6 @@ class A4SysexListenerClass : public ElektronSysexListenerClass { * automatically by the A4Task subsystem though). **/ void setup(MidiClass *_midi); - - void addOnSoundMessageCallback(SysexCallback *obj, sysex_callback_ptr_t func) { - onSoundMessageCallbacks.add(obj, func); - } - void removeOnSoundMessageCallback(SysexCallback *obj, sysex_callback_ptr_t func) { - onSoundMessageCallbacks.remove(obj, func); - } - void removeOnSoundMessageCallback(SysexCallback *obj) { - onSoundMessageCallbacks.remove(obj); - } - - void addOnSettingsMessageCallback(SysexCallback *obj, sysex_callback_ptr_t func) { - onSettingsMessageCallbacks.add(obj, func); - } - void removeOnSettingsMessageCallback(SysexCallback *obj, - sysex_callback_ptr_t func) { - onSettingsMessageCallbacks.remove(obj, func); - } - void removeOnSettingsMessageCallback(SysexCallback *obj) { - onSettingsMessageCallbacks.remove(obj); - } - /* @} */ }; diff --git a/avr/cores/megacommand/Adafruit-GFX-Library/Adafruit_GFX.cpp b/avr/cores/megacommand/Adafruit-GFX-Library/Adafruit_GFX.cpp index 94e4f8a54..844b07093 100755 --- a/avr/cores/megacommand/Adafruit-GFX-Library/Adafruit_GFX.cpp +++ b/avr/cores/megacommand/Adafruit-GFX-Library/Adafruit_GFX.cpp @@ -169,14 +169,15 @@ void Adafruit_GFX::endWrite() { // (x,y) is topmost point; if unsure, calling function // should sort endpoints or call drawLine() instead -void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y, int16_t h, - uint16_t color) { +/* +void Adafruit_GFX::drawFastVLine(uint8_t x, uint8_t y, uint8_t h, + uint8_t color) { // Update in subclasses if desired! startWrite(); writeLine(x, y, x, y + h - 1, color); endWrite(); } - +*/ // (x,y) is leftmost point; if unsure, calling function // should sort endpoints or call drawLine() instead void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y, int16_t w, @@ -187,8 +188,8 @@ void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y, int16_t w, endWrite(); } -void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color) { +void Adafruit_GFX::fillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, + uint8_t color) { // Update in subclasses if desired! startWrite(); for (int16_t i = x; i < x + w; i++) { @@ -829,8 +830,11 @@ void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c, ((y + 8 * size - 1) < 0)) // Clip top return; - if (!_cp437 && (c >= 176)) - c++; // Handle 'classic' charset behavior + + c -= 0x20; //Classic font is reduced in lengthand shifted. + if (c > 126) { c = 0; } + //if (!_cp437 && (c >= 176)) + // c++; // Handle 'classic' charset behavior startWrite(); for (int8_t i = 0; i < 5; i++) { // Char bitmap = 5 columns diff --git a/avr/cores/megacommand/Adafruit-GFX-Library/Adafruit_GFX.h b/avr/cores/megacommand/Adafruit-GFX-Library/Adafruit_GFX.h index 3dff2ad1f..894b895d4 100755 --- a/avr/cores/megacommand/Adafruit-GFX-Library/Adafruit_GFX.h +++ b/avr/cores/megacommand/Adafruit-GFX-Library/Adafruit_GFX.h @@ -22,9 +22,9 @@ class Adafruit_GFX : public Print { // These MAY be overridden by the subclass to provide device-specific // optimized code. Otherwise 'generic' versions are used. virtual void startWrite(void); - virtual void writePixel(int16_t x, int16_t y, uint16_t color); - virtual void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - virtual void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + void writePixel(int16_t x, int16_t y, uint16_t color); + void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); virtual void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); virtual void writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color); virtual void endWrite(void); @@ -39,15 +39,15 @@ class Adafruit_GFX : public Print { // BASIC DRAW API // These MAY be overridden by the subclass to provide device-specific // optimized code. Otherwise 'generic' versions are used. - virtual void - // It's good to implement those, even if using transaction API - drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color), - drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color), - fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color), - fillScreen(uint16_t color), + + void fillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color); + void fillScreen(uint16_t color); + virtual void drawFastVLine(uint8_t x, uint8_t y, uint8_t h, uint8_t color) = 0; + void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color); + + void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); // Optional and probably not necessary to change - drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color), - drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); // These exist only with Adafruit_GFX (no subclass overrides) void diff --git a/avr/cores/megacommand/Adafruit-GFX-Library/glcdfont.c b/avr/cores/megacommand/Adafruit-GFX-Library/glcdfont.c index 659c85f43..5bfc7a2f0 100755 --- a/avr/cores/megacommand/Adafruit-GFX-Library/glcdfont.c +++ b/avr/cores/megacommand/Adafruit-GFX-Library/glcdfont.c @@ -14,7 +14,201 @@ #endif // Standard ASCII 5x7 font +// Shifted to begin at 0x32, and limited to +static const unsigned char font[] PROGMEM = { + // Space + 0x00, 0x00, 0x00, 0x00, 0x00, + // Exclamation mark + 0x00, 0x00, 0x5F, 0x00, 0x00, + // Double quote + 0x00, 0x07, 0x00, 0x07, 0x00, + // Hash + 0x14, 0x7F, 0x14, 0x7F, 0x14, + // Dollar sign + 0x24, 0x2A, 0x7F, 0x2A, 0x12, + // Percent sign + 0x23, 0x13, 0x08, 0x64, 0x62, + // Ampersand + 0x36, 0x49, 0x56, 0x20, 0x50, + // Single quote + 0x00, 0x08, 0x07, 0x03, 0x00, + // Open parenthesis + 0x00, 0x1C, 0x22, 0x41, 0x00, + // Close parenthesis + 0x00, 0x41, 0x22, 0x1C, 0x00, + // Asterisk + 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, + // Plus + 0x08, 0x08, 0x3E, 0x08, 0x08, + // Comma + 0x00, 0x80, 0x70, 0x30, 0x00, + // Dash + 0x08, 0x08, 0x08, 0x08, 0x08, + // Period + 0x00, 0x00, 0x60, 0x60, 0x00, + // Slash + 0x20, 0x10, 0x08, 0x04, 0x02, + // Digit '0' + 0x3E, 0x51, 0x49, 0x45, 0x3E, + // Digit '1' + 0x00, 0x42, 0x7F, 0x40, 0x00, + // Digit '2' + 0x72, 0x49, 0x49, 0x49, 0x46, + // Digit '3' + 0x21, 0x41, 0x49, 0x4D, 0x33, + // Digit '4' + 0x18, 0x14, 0x12, 0x7F, 0x10, + // Digit '5' + 0x27, 0x45, 0x45, 0x45, 0x39, + // Digit '6' + 0x3C, 0x4A, 0x49, 0x49, 0x31, + // Digit '7' + 0x41, 0x21, 0x11, 0x09, 0x07, + // Digit '8' + 0x36, 0x49, 0x49, 0x49, 0x36, + // Digit '9' + 0x46, 0x49, 0x49, 0x29, 0x1E, + // Colon + 0x00, 0x00, 0x14, 0x00, 0x00, + // Semicolon + 0x00, 0x40, 0x34, 0x00, 0x00, + // Less than + 0x08, 0x14, 0x22, 0x41, 0x00, + // Equal + 0x14, 0x14, 0x14, 0x14, 0x14, + // Greater than + 0x00, 0x41, 0x22, 0x14, 0x08, + // Question mark + 0x02, 0x01, 0x59, 0x09, 0x06, + // At symbol + 0x3E, 0x41, 0x5D, 0x59, 0x4E, + // Uppercase 'A' + 0x7C, 0x12, 0x11, 0x12, 0x7C, + // Uppercase 'B' + 0x7F, 0x49, 0x49, 0x49, 0x36, + // Uppercase 'C' + 0x3E, 0x41, 0x41, 0x41, 0x22, + // Uppercase 'D' + 0x7F, 0x41, 0x41, 0x41, 0x3E, + // Uppercase 'E' + 0x7F, 0x49, 0x49, 0x49, 0x41, + // Uppercase 'F' + 0x7F, 0x09, 0x09, 0x09, 0x01, + // Uppercase 'G' + 0x3E, 0x41, 0x49, 0x49, 0x7A, + // Uppercase 'H' + 0x7F, 0x08, 0x08, 0x08, 0x7F, + // Uppercase 'I' + 0x00, 0x41, 0x7F, 0x41, 0x00, + // Uppercase 'J' + 0x20, 0x40, 0x41, 0x3F, 0x01, + // Uppercase 'K' + 0x7F, 0x08, 0x14, 0x22, 0x41, + // Uppercase 'L' + 0x7F, 0x40, 0x40, 0x40, 0x40, + // Uppercase 'M' + 0x7F, 0x02, 0x0C, 0x02, 0x7F, + // Uppercase 'N' + 0x7F, 0x04, 0x08, 0x10, 0x7F, + // Uppercase 'O' + 0x3E, 0x41, 0x41, 0x41, 0x3E, + // Uppercase 'P' + 0x7F, 0x09, 0x09, 0x09, 0x06, + // Uppercase 'Q' + 0x3E, 0x41, 0x51, 0x21, 0x5E, + // Uppercase 'R' + 0x7F, 0x09, 0x19, 0x29, 0x46, + // Uppercase 'S' + 0x46, 0x49, 0x49, 0x49, 0x31, + // Uppercase 'T' + 0x01, 0x01, 0x7F, 0x01, 0x01, + // Uppercase 'U' + 0x3F, 0x40, 0x40, 0x40, 0x3F, + // Uppercase 'V' + 0x1F, 0x20, 0x40, 0x20, 0x1F, + // Uppercase 'W' + 0x7F, 0x20, 0x18, 0x20, 0x7F, + // Uppercase 'X' + 0x63, 0x14, 0x08, 0x14, 0x63, + // Uppercase 'Y' + 0x03, 0x04, 0x78, 0x04, 0x03, + // Uppercase 'Z' + 0x61, 0x51, 0x49, 0x45, 0x43, + // Open square bracket + 0x00, 0x7F, 0x41, 0x41, 0x00, + // Backslash + 0x02, 0x04, 0x08, 0x10, 0x20, + // Close square bracket + 0x00, 0x41, 0x41, 0x7F, 0x00, + // Caret + 0x04, 0x02, 0x01, 0x02, 0x04, + // Underscore + 0x40, 0x40, 0x40, 0x40, 0x40, + // Grave accent + 0x00, 0x03, 0x07, 0x08, 0x00, + // Lowercase 'a' + 0x20, 0x54, 0x54, 0x54, 0x78, + // Lowercase 'b' + 0x7F, 0x48, 0x44, 0x44, 0x38, + // Lowercase 'c' + 0x38, 0x44, 0x44, 0x44, 0x28, + // Lowercase 'd' + 0x38, 0x44, 0x44, 0x48, 0x7F, + // Lowercase 'e' + 0x38, 0x54, 0x54, 0x54, 0x18, + // Lowercase 'f' + 0x08, 0x7E, 0x09, 0x01, 0x02, + // Lowercase 'g' + 0x0C, 0x52, 0x52, 0x52, 0x3E, + // Lowercase 'h' + 0x7F, 0x08, 0x04, 0x04, 0x78, + // Lowercase 'i' + 0x00, 0x44, 0x7D, 0x40, 0x00, + // Lowercase 'j' + 0x20, 0x40, 0x44, 0x3D, 0x00, + // Lowercase 'k' + 0x7F, 0x10, 0x28, 0x44, 0x00, + // Lowercase 'l' + 0x00, 0x41, 0x7F, 0x40, 0x00, + // Lowercase 'm' + 0x7C, 0x04, 0x18, 0x04, 0x78, + // Lowercase 'n' + 0x7C, 0x08, 0x04, 0x04, 0x78, + // Lowercase 'o' + 0x38, 0x44, 0x44, 0x44, 0x38, + // Lowercase 'p' + 0x7C, 0x14, 0x14, 0x14, 0x08, + // Lowercase 'q' + 0x08, 0x14, 0x14, 0x18, 0x7C, + // Lowercase 'r' + 0x7C, 0x08, 0x04, 0x04, 0x08, + // Lowercase 's' + 0x48, 0x54, 0x54, 0x54, 0x24, + // Lowercase 't' + 0x04, 0x3F, 0x44, 0x40, 0x20, + // Lowercase 'u' + 0x3C, 0x40, 0x40, 0x20, 0x7C, + // Lowercase 'v' + 0x1C, 0x20, 0x40, 0x20, 0x1C, + // Lowercase 'w' + 0x3C, 0x40, 0x30, 0x40, 0x3C, + // Lowercase 'x' + 0x44, 0x28, 0x10, 0x28, 0x44, + // Lowercase 'y' + 0x0C, 0x50, 0x50, 0x50, 0x3C, + // Lowercase 'z' + 0x44, 0x64, 0x54, 0x4C, 0x44, + // Open curly brace + 0x00, 0x08, 0x36, 0x41, 0x00, + // Vertical bar + 0x00, 0x00, 0x7F, 0x00, 0x00, + // Close curly brace + 0x00, 0x41, 0x36, 0x08, 0x00, + // Tilde + 0x08, 0x08, 0x2A, 0x1C, 0x08, + }; +/* static const unsigned char font[] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, @@ -273,4 +467,5 @@ static const unsigned char font[] PROGMEM = { 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00 // #255 NBSP }; +*/ #endif // FONT5X7_H diff --git a/avr/cores/megacommand/Adafruit_SSD1305_Library/Adafruit_SSD1305.cpp b/avr/cores/megacommand/Adafruit_SSD1305_Library/Adafruit_SSD1305.cpp index 2c2867448..f4883bd05 100644 --- a/avr/cores/megacommand/Adafruit_SSD1305_Library/Adafruit_SSD1305.cpp +++ b/avr/cores/megacommand/Adafruit_SSD1305_Library/Adafruit_SSD1305.cpp @@ -53,20 +53,17 @@ static uint8_t buffer[SSD1305_LCDHEIGHT * SSD1305_LCDWIDTH / 8] = {}; // the most basic function, set a single pixel void Adafruit_SSD1305::drawPixel(uint8_t x, uint8_t y, uint8_t color) { - if ((x >= width()) || (y >= height())) - return; - + if (x >= width() || y >= height()) + return; uint16_t index = x + (y / 8) * SSD1305_LCDWIDTH; - draw_pixel: - // x is which column + uint8_t bit = _BV(y & 7); + if (color == WHITE) - SET_BIT(buffer[index],y % 8); - else if (color == INVERT) { - color = - (IS_BIT_SET(buffer[index],y % 8)) ? BLACK : WHITE; - goto draw_pixel; - } else // BLACK - CLEAR_BIT(buffer[index],(y % 8)); + buffer[index] |= bit; + else if (color == BLACK) + buffer[index] &= ~bit; + else // INVERT + buffer[index] ^= bit; } void Adafruit_SSD1305::drawFastVLine(uint8_t x, uint8_t y, uint8_t h, diff --git a/avr/cores/megacommand/Adafruit_SSD1305_Library/Adafruit_SSD1305.h b/avr/cores/megacommand/Adafruit_SSD1305_Library/Adafruit_SSD1305.h index ec84fe9a5..c6e55312e 100644 --- a/avr/cores/megacommand/Adafruit_SSD1305_Library/Adafruit_SSD1305.h +++ b/avr/cores/megacommand/Adafruit_SSD1305_Library/Adafruit_SSD1305.h @@ -103,7 +103,7 @@ All text above, and the splash screen must be included in any redistribution #define SSD1305_SETVCOMLEVEL 0xDB -class Adafruit_SSD1305 : public Adafruit_GFX { +class Adafruit_SSD1305 final : public Adafruit_GFX { private: bool screen_saver_active = false; @@ -132,11 +132,11 @@ class Adafruit_SSD1305 : public Adafruit_GFX { void textbox(const char *text, const char *text2, uint16_t delay = 800); void display(); - void drawPixel(uint8_t x, uint8_t y, uint8_t color); + virtual void drawPixel(uint8_t x, uint8_t y, uint8_t color); virtual void drawFastVLine(uint8_t x, uint8_t y, uint8_t h, uint8_t color); - virtual void fillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color); - virtual void fillScreen(uint8_t color); + void fillRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color); + void fillScreen(uint8_t color); bool textbox_enabled = false; private: diff --git a/avr/cores/megacommand/CommonTools/RingBuffer.h b/avr/cores/megacommand/CommonTools/RingBuffer.h index 897408741..b6a482d98 100644 --- a/avr/cores/megacommand/CommonTools/RingBuffer.h +++ b/avr/cores/megacommand/CommonTools/RingBuffer.h @@ -163,7 +163,7 @@ void CRingBuffer::put_h_isr(C *src, T n) volatile { if constexpr (N == 0) { memcpy_bank1(ptr + wr, src, s * sizeof(C)); } else { - memcpy(buf + wr, src, s * sizeof(C)); + memcpy((void*)(buf + wr), src, s * sizeof(C)); } wr += s; n -= s; @@ -171,7 +171,7 @@ void CRingBuffer::put_h_isr(C *src, T n) volatile { if constexpr (N == 0) { memcpy_bank1(ptr, src + s, n * sizeof(C)); } else { - memcpy(buf ,src + s, n * sizeof(C)); + memcpy((void*)buf ,src + s, n * sizeof(C)); } wr = n; } diff --git a/avr/cores/megacommand/Elektron/Elektron.cpp b/avr/cores/megacommand/Elektron/Elektron.cpp index 64d59e62d..c7be07475 100644 --- a/avr/cores/megacommand/Elektron/Elektron.cpp +++ b/avr/cores/megacommand/Elektron/Elektron.cpp @@ -17,6 +17,29 @@ uint8_t *MidiDevice::gif_data() { return R.icons_logo->midi_gif_data; } MCLGIF *MidiDevice::gif() { return R.icons_logo->midi_gif; } uint16_t ElektronDevice::sendRequest(uint8_t *data, uint8_t len, bool send, MidiUartParent *uart_) { + if (!send) { + return len + sysex_protocol.header_size + 2; + } + + uart_ = uart_ ? uart_ : uart; + + uint8_t buf[256]; + uint8_t i = 0; + + buf[i++] = 0xF0; + memcpy(buf + i, sysex_protocol.header, sysex_protocol.header_size); + i += sysex_protocol.header_size; + + for (uint8_t n = 0; n < len; n++) { + buf[i++] = data[n] & 0x7F; + } + buf[i++] = 0xF7; + + uart_->m_putc(buf, i); + + return i; +} +/* if (uart_ == nullptr) { uart_ = uart; } uint8_t buf[256]; @@ -37,7 +60,7 @@ uint16_t ElektronDevice::sendRequest(uint8_t *data, uint8_t len, bool send, Midi } return len + sysex_protocol.header_size + 2; } - +*/ uint16_t ElektronDevice::sendRequest(uint8_t type, uint8_t param, bool send) { uint8_t data[] = {type, param}; return sendRequest(data, 2, send); @@ -112,7 +135,6 @@ bool ElektronDevice::get_fw_caps() { void ElektronDevice::activate_encoder_interface(uint8_t *params) { encoder_interface = true; uint8_t data[3 + 4 + 24] = {0x70, 0x36, 0x01}; - uint8_t mod7 = 0; uint8_t cnt = 0; @@ -131,53 +153,88 @@ void ElektronDevice::activate_encoder_interface(uint8_t *params) { //waitBlocking(); } -void ElektronDevice::deactivate_encoder_interface() { - uint8_t data[3] = {0x70, 0x36, 0x00}; - sendRequest(data, sizeof(data)); - encoder_interface = false; - //waitBlocking(); -} - -void ElektronDevice::activate_enhanced_midi() { - uint8_t data[3] = {0x70, 0x3E, 0x01}; - sendRequest(data, sizeof(data)); - // waitBlocking(); -} -void ElektronDevice::deactivate_enhanced_midi() { - uint8_t data[3] = {0x70, 0x3E, 0x00}; - sendRequest(data, sizeof(data)); - // waitBlocking(); -} +void ElektronDevice::deactivate_encoder_interface() { sendCommand(ElektronCommand::ActivateEncoderInterface, 0); } + +void ElektronDevice::sendCommand(ElektronCommand command, uint8_t param) { + uint8_t data[3] = {0x70, 0x00, 0x00}; + bool needsWait = false; + uint8_t l = 3; + switch (command) { + case ElektronCommand::ActivateEncoderInterface: + data[1] = 0x36; + data[2] = param;; + encoder_interface = param; + break; + case ElektronCommand::ActivateEnhancedMidi: + data[1] = 0x3E; + data[2] = param; + break; + case ElektronCommand::ActivateEnhancedGui: + data[1] = 0x37; + data[2] = param; + break; + case ElektronCommand::SetSeqPage: + data[1] = 0x38; + data[2] = param; + break; + case ElektronCommand::SetRecMode: + data[1] = 0x3A; + data[2] = param; + break; + case ElektronCommand::SetKeyRepeat: + data[1] = 0x4E; + data[2] = param; + break; + case ElektronCommand::ActivateTrigInterface: + data[1] = 0x31; + data[2] = param; + break; + case ElektronCommand::ActivateTrackSelect: + data[1] = 0x32; + data[2] = param; + needsWait = true; + break; + case ElektronCommand::UndokitSync: + data[1] = 0x42; + l = 2; + break; + case ElektronCommand::ResetDspParams: + data[1] = 0x43; + l = 2; + break; + case ElektronCommand::DrawCloseBank: + data[1] = 0x3C; + data[2] = 0x23; + break; + case ElektronCommand::DrawCloseMicrotiming: + data[1] = 0x3C; + data[2] = 0x21; + break; + default: + return; // Invalid command + } -void ElektronDevice::activate_enhanced_gui() { - uint8_t data[3] = {0x70, 0x37, 0x01}; - sendRequest(data, sizeof(data)); - // waitBlocking(); + sendRequest(data, l); + if (needsWait) { + waitBlocking(); + } } -void ElektronDevice::deactivate_enhanced_gui() { - uint8_t data[3] = {0x70, 0x37, 0x00}; - sendRequest(data, sizeof(data)); - // waitBlocking(); -} -void ElektronDevice::set_seq_page(uint8_t page) { - uint8_t data[3] = {0x70, 0x38, page}; - sendRequest(data, sizeof(data)); +void ElektronDevice::draw_microtiming(uint8_t speed, uint8_t timing) { + uint8_t a = timing >> 7; + uint8_t b = timing & 0x7F; + uint8_t data[6] = {0x70, 0x3C, 0x20, speed, a, b}; + sendRequest(data, 6); // waitBlocking(); } -void ElektronDevice::set_rec_mode(uint8_t mode) { - uint8_t data[3] = {0x70, 0x3A, mode}; - sendRequest(data, sizeof(data)); +void ElektronDevice::draw_pattern_idx(uint8_t idx, uint8_t idx_other, uint8_t chain_mask) { + uint8_t data[6] = {0x70, 0x3C, 0x24, idx, idx_other, chain_mask }; + sendRequest(data, 6); // waitBlocking(); } -void ElektronDevice::set_key_repeat(uint8_t mode) { - uint8_t data[3] = {0x70, 0x4E, mode}; - sendRequest(data, sizeof(data)); - // waitBlocking(); -} void ElektronDevice::popup_text(uint8_t action_string, uint8_t persistent) { uint8_t data[4] = {0x70, 0x3B, persistent, action_string}; @@ -198,66 +255,23 @@ void ElektronDevice::draw_bank(uint8_t bank) { sendRequest(data, 5); // waitBlocking(); } -void ElektronDevice::draw_close_bank() { - uint8_t data[3] = {0x70, 0x3C, 0x23}; - sendRequest(data, 3); - // waitBlocking(); -} - -void ElektronDevice::draw_microtiming(uint8_t speed, uint8_t timing) { - uint8_t a = timing >> 7; - uint8_t b = timing & 0x7F; - uint8_t data[6] = {0x70, 0x3C, 0x20, speed, a, b}; - sendRequest(data, 6); - // waitBlocking(); -} -void ElektronDevice::draw_close_microtiming() { - uint8_t data[3] = {0x70, 0x3C, 0x21}; - sendRequest(data, 3); - // waitBlocking(); -} - -void ElektronDevice::draw_pattern_idx(uint8_t idx, uint8_t idx_other, uint8_t chain_mask) { - uint8_t data[6] = {0x70, 0x3C, 0x24, idx, idx_other, chain_mask }; - sendRequest(data, 6); - // waitBlocking(); -} - - -void ElektronDevice::activate_trig_interface() { - uint8_t data[3] = {0x70, 0x31, 0x01}; - sendRequest(data, sizeof(data)); - // waitBlocking(); -} - -void ElektronDevice::deactivate_trig_interface() { - uint8_t data[3] = {0x70, 0x31, 0x00}; - sendRequest(data, sizeof(data)); - // waitBlocking(); -} - -void ElektronDevice::activate_track_select() { - uint8_t data[3] = {0x70, 0x32, 0x01}; - sendRequest(data, sizeof(data)); - waitBlocking(); -} - -void ElektronDevice::deactivate_track_select() { - uint8_t data[3] = {0x70, 0x32, 0x00}; - sendRequest(data, sizeof(data)); - waitBlocking(); -} - -void ElektronDevice::undokit_sync() { - uint8_t data[2] = { 0x70, 0x42 }; - sendRequest(data, sizeof(data)); -} - -void ElektronDevice::reset_dsp_params() { - uint8_t data[2] = { 0x70, 0x43 }; - sendRequest(data, sizeof(data)); -} +// Implement the individual functions using the central sendCommand function +void ElektronDevice::activate_enhanced_midi() { sendCommand(ElektronCommand::ActivateEnhancedMidi, 1); } +void ElektronDevice::deactivate_enhanced_midi() { sendCommand(ElektronCommand::ActivateEnhancedMidi, 0); } +void ElektronDevice::activate_enhanced_gui() { sendCommand(ElektronCommand::ActivateEnhancedGui, 1); } +void ElektronDevice::deactivate_enhanced_gui() { sendCommand(ElektronCommand::ActivateEnhancedGui, 0); } +void ElektronDevice::set_seq_page(uint8_t page) { sendCommand(ElektronCommand::SetSeqPage, page); } +void ElektronDevice::set_rec_mode(uint8_t mode) { sendCommand(ElektronCommand::SetRecMode, mode); } +void ElektronDevice::set_key_repeat(uint8_t mode) { sendCommand(ElektronCommand::SetKeyRepeat, mode); } +void ElektronDevice::activate_trig_interface() { sendCommand(ElektronCommand::ActivateTrigInterface, 1); } +void ElektronDevice::deactivate_trig_interface() { sendCommand(ElektronCommand::ActivateTrigInterface, 0); } +void ElektronDevice::activate_track_select() { sendCommand(ElektronCommand::ActivateTrackSelect, 1); } +void ElektronDevice::deactivate_track_select() { sendCommand(ElektronCommand::ActivateTrackSelect, 0); } +void ElektronDevice::undokit_sync() { sendCommand(ElektronCommand::UndokitSync, 0); } +void ElektronDevice::reset_dsp_params() { sendCommand(ElektronCommand::ResetDspParams, 0); } +void ElektronDevice::draw_close_bank() { sendCommand(ElektronCommand::DrawCloseBank, 0); } +void ElektronDevice::draw_close_microtiming() { sendCommand(ElektronCommand::DrawCloseMicrotiming, 0); } void ElektronDevice::set_trigleds(uint16_t bitmask, TrigLEDMode mode, @@ -318,78 +332,69 @@ uint8_t ElektronDevice::getBlockingStatus(uint8_t type, uint16_t timeout) { return connected ? cb.value : 255; } -bool ElektronDevice::getBlockingKit(uint8_t kit, uint16_t timeout) { - SysexCallback cb; - uint8_t count = SYSEX_RETRIES; - auto listener = getSysexListener(); - bool ret; - while ((MidiClock.state == 2) && - ((MidiClock.mod12_counter > 6) || (MidiClock.mod12_counter == 0))) - ; - while (count) { - listener->addOnKitMessageCallback( - &cb, (sysex_callback_ptr_t)&SysexCallback::onSysexReceived); - requestKit(kit); - DEBUG_PRINTLN("get blocking kit"); - ret = cb.waitBlocking(timeout); - listener->removeOnKitMessageCallback(&cb); - if (ret) { - midi->midiSysex.rd_cur = listener->msg_rd; - auto kit = getKit(); - if (kit != nullptr && kit->fromSysex(midi)) { - DEBUG_PRINTLN("finished"); - return true; - } +bool ElektronDevice::getBlockingData(DataType type, uint8_t index, uint16_t timeout) { + SysexCallback cb; + uint8_t count = (type == DataType::Global) ? 1 : SYSEX_RETRIES; + auto listener = getSysexListener(); + bool ret = false; + + while ((MidiClock.state == 2) && + ((MidiClock.mod12_counter > 6) || (MidiClock.mod12_counter == 0))) + ; + + while (count--) { + + listener->addOnMessageCallback(&cb, (sysex_callback_ptr_t)&SysexCallback::onSysexReceived); + switch (type) { + case DataType::Kit: + requestKit(index); + break; + case DataType::Pattern: + requestPattern(index); + break; + case DataType::Global: + requestGlobal(index); + break; + } + + ret = cb.waitBlocking(timeout); + + listener->removeOnMessageCallback(&cb); + + if (ret) { + midi->midiSysex.rd_cur = listener->msg_rd; + void* data = nullptr; + switch (type) { + case DataType::Kit: + data = getKit(); + break; + case DataType::Pattern: + data = getPattern(); + break; + case DataType::Global: + data = getGlobal(); + break; + } + if (data != nullptr && ((ElektronSysexObject*)data)->fromSysex(midi)) { + if (type == DataType::Global) connected = true; + return true; + } + } } - count--; - } - return false; + return false; } -bool ElektronDevice::getBlockingPattern(uint8_t pattern, uint16_t timeout) { - SysexCallback cb; - uint8_t count = SYSEX_RETRIES; - auto listener = getSysexListener(); - bool ret; - while ((MidiClock.state == 2) && - ((MidiClock.mod12_counter > 6) || (MidiClock.mod12_counter == 0))) - ; - while (count) { - listener->addOnPatternMessageCallback( - &cb, (sysex_callback_ptr_t)&SysexCallback::onSysexReceived); - requestPattern(pattern); - ret = cb.waitBlocking(timeout); - listener->removeOnPatternMessageCallback(&cb); - - if (ret) { - midi->midiSysex.rd_cur = listener->msg_rd; - auto pattern = getPattern(); - if (pattern != nullptr && pattern->fromSysex(midi)) { - return true; - } - } - count--; - } - return false; +bool ElektronDevice::getBlockingKit(uint8_t kit, uint16_t timeout) { + return getBlockingData(DataType::Kit, kit, timeout);; +} + +bool ElektronDevice::getBlockingPattern(uint8_t pattern, uint16_t timeout) { + return getBlockingData(DataType::Pattern, pattern, timeout);; } bool ElektronDevice::getBlockingGlobal(uint8_t global, uint16_t timeout) { - SysexCallback cb; - auto listener = getSysexListener(); - listener->addOnGlobalMessageCallback( - &cb, (sysex_callback_ptr_t)&SysexCallback::onSysexReceived); - requestGlobal(global); - connected = cb.waitBlocking(timeout); - listener->removeOnGlobalMessageCallback(&cb); - if (connected) { - auto global = getGlobal(); - midi->midiSysex.rd_cur = listener->msg_rd; - if (global != nullptr && global->fromSysex(midi)) { - return true; - } - } - return connected; + return getBlockingData(DataType::Global, global, timeout); } uint8_t ElektronDevice::getCurrentTrack(uint16_t timeout) { diff --git a/avr/cores/megacommand/Elektron/Elektron.h b/avr/cores/megacommand/Elektron/Elektron.h index 34036a4db..af6796f1b 100644 --- a/avr/cores/megacommand/Elektron/Elektron.h +++ b/avr/cores/megacommand/Elektron/Elektron.h @@ -41,6 +41,8 @@ typedef struct short_machine_name_s { uint8_t id; } short_machine_name_t; +enum class DataType { Kit, Pattern, Global }; + /** * Class grouping various helper functions to convert elektron sysex * data. These are deprecated and should be replaced by the elektron @@ -141,7 +143,7 @@ class MidiDevice { public: bool connected; MidiClass* midi; - MidiUartParent* uart; + MidiUartClass* uart; const char* const name; const uint8_t id; // Device identifier const bool isElektronDevice; @@ -183,18 +185,9 @@ class ElektronSysexListenerClass : public MidiSysexListenerClass { public: /** Vector storing the onGlobalMessage callbacks (called when a global message * is received). **/ - CallbackVector onGlobalMessageCallbacks; + CallbackVector onMessageCallbacks; /** Vector storing the onKitMessage callbacks (called when a kit message is * received). **/ - CallbackVector onKitMessageCallbacks; - /** Vector storing the onSongMessage callbacks (called when a song messages is - * received). **/ - CallbackVector onSongMessageCallbacks; - /** Vector storing the onPatternMessage callbacks (called when a pattern - * message is received). **/ - CallbackVector onPatternMessageCallbacks; - /** Vector storing the onStatusResponse callbacks (when a status response is - * received). **/ CallbackVector2 onStatusResponseCallbacks; void addOnStatusResponseCallback(SysexCallback *obj, @@ -209,44 +202,14 @@ class ElektronSysexListenerClass : public MidiSysexListenerClass { onStatusResponseCallbacks.remove(obj); } - void addOnGlobalMessageCallback(SysexCallback *obj, sysex_callback_ptr_t func) { - onGlobalMessageCallbacks.add(obj, func); - } - void removeOnGlobalMessageCallback(SysexCallback *obj, sysex_callback_ptr_t func) { - onGlobalMessageCallbacks.remove(obj, func); - } - void removeOnGlobalMessageCallback(SysexCallback *obj) { - onGlobalMessageCallbacks.remove(obj); - } - - void addOnKitMessageCallback(SysexCallback *obj, sysex_callback_ptr_t func) { - onKitMessageCallbacks.add(obj, func); + void addOnMessageCallback(SysexCallback *obj, sysex_callback_ptr_t func) { + onMessageCallbacks.add(obj, func); } - void removeOnKitMessageCallback(SysexCallback *obj, sysex_callback_ptr_t func) { - onKitMessageCallbacks.remove(obj, func); + void removeOnMessageCallback(SysexCallback *obj, sysex_callback_ptr_t func) { + onMessageCallbacks.remove(obj, func); } - void removeOnKitMessageCallback(SysexCallback *obj) { - onKitMessageCallbacks.remove(obj); - } - - void addOnPatternMessageCallback(SysexCallback *obj, sysex_callback_ptr_t func) { - onPatternMessageCallbacks.add(obj, func); - } - void removeOnPatternMessageCallback(SysexCallback *obj, sysex_callback_ptr_t func) { - onPatternMessageCallbacks.remove(obj, func); - } - void removeOnPatternMessageCallback(SysexCallback *obj) { - onPatternMessageCallbacks.remove(obj); - } - - void addOnSongMessageCallback(SysexCallback *obj, sysex_callback_ptr_t func) { - onSongMessageCallbacks.add(obj, func); - } - void removeOnSongMessageCallback(SysexCallback *obj, sysex_callback_ptr_t func) { - onSongMessageCallbacks.remove(obj, func); - } - void removeOnSongMessageCallback(SysexCallback *obj) { - onSongMessageCallbacks.remove(obj); + void removeOnMessageCallback(SysexCallback *obj) { + onMessageCallbacks.remove(obj); } }; @@ -259,6 +222,21 @@ enum TrigLEDMode { TRIGLED_MUTE = 4 }; +enum class ElektronCommand { + ActivateEncoderInterface, + ActivateEnhancedMidi, + ActivateEnhancedGui, + SetSeqPage, + SetRecMode, + SetKeyRepeat, + ActivateTrigInterface, + ActivateTrackSelect, + UndokitSync, + ResetDspParams, + DrawCloseBank, + DrawCloseMicrotiming +}; + /// sysex constants for constructing data frames class ElektronSysexProtocol { public: @@ -316,7 +294,7 @@ class ElektronSysexObject { #define FW_CAP_ENHANCED_MIDI FW_CAP_HIGH(3) #define FW_CAP_MACHINE_CACHE FW_CAP_HIGH(4) #define FW_CAP_UNDO_CACHE FW_CAP_HIGH(5) - +#define FW_CAP_MID_MACHINE FW_CAP_HIGH(6) /// Base class for Elektron MidiDevice class ElektronDevice : public MidiDevice { public: @@ -335,10 +313,7 @@ class ElektronDevice : public MidiDevice { uint8_t currentBank; /** Stores the current pattern of the MD, usually set by the MDTask. **/ uint8_t currentPattern; - /** Set to true if the kit was loaded (usually set by MDTask). **/ - bool loadedKit; /** Set to true if the global was loaded (usually set by MDTask). **/ - bool loadedGlobal; bool encoder_interface; ElektronDevice( MidiClass* _midi, const char* _name, const uint8_t _id, @@ -349,9 +324,6 @@ class ElektronDevice : public MidiDevice { currentKit = -1; currentPattern = -1; - loadedKit = false; - loadedGlobal = false; - encoder_interface = false; } @@ -438,6 +410,7 @@ class ElektronDevice : public MidiDevice { * are wrapped in appropriate methods like requestKit, * requestPattern, etc... **/ + void sendCommand(ElektronCommand command, uint8_t param); virtual uint16_t sendRequest(uint8_t *data, uint8_t len, bool send = true, MidiUartParent *uart_ = nullptr); virtual uint16_t sendRequest(uint8_t type, uint8_t param, bool send = true); /** @@ -471,6 +444,7 @@ class ElektronDevice : public MidiDevice { **/ void requestGlobal(uint8_t global); + bool getBlockingData(DataType type, uint8_t index, uint16_t timeout); /** * Get the status answer from the device, blocking until either * a message is received or the timeout has run out. diff --git a/avr/cores/megacommand/GUI/GUI.cpp b/avr/cores/megacommand/GUI/GUI.cpp index 7502338a0..a5ed8488b 100644 --- a/avr/cores/megacommand/GUI/GUI.cpp +++ b/avr/cores/megacommand/GUI/GUI.cpp @@ -120,6 +120,7 @@ void GuiClass::display() { if (sketch != NULL) { page = sketch->currentPage(); if (page != NULL) { + oled_display.setFont(); page->display(); } } diff --git a/avr/cores/megacommand/GUI_private.h b/avr/cores/megacommand/GUI_private.h index 9d4042758..66443f088 100644 --- a/avr/cores/megacommand/GUI_private.h +++ b/avr/cores/megacommand/GUI_private.h @@ -39,11 +39,7 @@ class EncodersClass { ALWAYS_INLINE() int8_t getButton(uint8_t i) { return encoders[i].button; } ALWAYS_INLINE() int8_t limitValue(int8_t value, int8_t min, int8_t max) { - if (value > max) - return max; - if (value < min) - return min; - return value; + return (value > max) ? max : (value < min ? min : value); } }; diff --git a/avr/cores/megacommand/MCL/ArpPage.cpp b/avr/cores/megacommand/MCL/ArpPage.cpp index a39ba0bb1..8d544ba13 100644 --- a/avr/cores/megacommand/MCL/ArpPage.cpp +++ b/avr/cores/megacommand/MCL/ArpPage.cpp @@ -11,7 +11,6 @@ void ArpPage::setup() { void ArpPage::init() { DEBUG_PRINT_FN(); - oled_display.setFont(); // seq_ptc_page.display(); track_update(); trig_interface.send_md_leds(TRIGLED_EXCLUSIVE); @@ -57,7 +56,7 @@ void ArpPage::track_update(uint8_t n, bool re_render) { last_arp_track = arp_track; } -void ArpPage::cleanup() { oled_display.clearDisplay(); } +void ArpPage::cleanup() {} void ArpPage::loop() { uint8_t n = current_track; @@ -88,7 +87,6 @@ const arp_name_t arp_names[] PROGMEM = { void ArpPage::display() { - auto oldfont = oled_display.getFont(); oled_display.setFont(&TomThumb); oled_display.fillRect(8, 2, 128 - 16, 32 - 2, BLACK); @@ -133,8 +131,6 @@ void ArpPage::display() { mcl_gui.put_value_at(encoders[3]->cur, str); mcl_gui.draw_text_encoder(x + 3 * mcl_gui.knob_w, y, "RANGE", str, param_select == 3); - oled_display.display(); - oled_display.setFont(oldfont); } bool ArpPage::handleEvent(gui_event_t *event) { diff --git a/avr/cores/megacommand/MCL/ArpSeqTrack.cpp b/avr/cores/megacommand/MCL/ArpSeqTrack.cpp index e05d180c2..f68b27bea 100644 --- a/avr/cores/megacommand/MCL/ArpSeqTrack.cpp +++ b/avr/cores/megacommand/MCL/ArpSeqTrack.cpp @@ -19,9 +19,11 @@ void ArpSeqTrack::set_length(uint8_t length_) { } } -void ArpSeqTrack::seq(MidiUartParent *uart_) { +void ArpSeqTrack::seq(MidiUartParent *uart_, MidiUartParent *uart2_) { MidiUartParent *uart_old = uart; + MidiUartParent *uart2_old = uart2; uart = uart_; + uart2 = uart2_; uint8_t timing_mid = get_timing_mid_inline(); @@ -29,12 +31,13 @@ void ArpSeqTrack::seq(MidiUartParent *uart_) { if (mod12_counter == timing_mid) { step_count_inc(); if (active == EXT_ARP_TRACK_TYPE && last_note_on != 255 && step_count == length / 2) { - seq_ptc_page.note_off_ext(last_note_on, 0, track_number, uart); + seq_ptc_page.note_off_ext(last_note_on, 0, track_number, uart2_); last_note_on = 255; } mod12_counter = 0; } - + bool is_midi_model = + ((MD.kit.models[track_number] & 0xF0) == MID_01_MODEL); if (mod12_counter == 0 && enabled && mute_state == SEQ_MUTE_OFF) { if (step_count == 0) { if (len > 0) { @@ -42,10 +45,15 @@ void ArpSeqTrack::seq(MidiUartParent *uart_) { note += oct*12; switch (active) { case MD_ARP_TRACK_TYPE: - seq_ptc_page.trig_md(note, track_number, CTRL_EVENT, fine_tune, uart); + if (is_midi_model) { + mcl_seq.md_tracks[track_number].send_notes(note, uart2_); + seq_ptc_page.record(note, track_number); + } else { + seq_ptc_page.trig_md(note, track_number, CTRL_EVENT, fine_tune, uart_); + } break; case EXT_ARP_TRACK_TYPE: - seq_ptc_page.note_on_ext(note, 127, track_number, uart); + seq_ptc_page.note_on_ext(note, 127, track_number, uart2_); last_note_on = note; break; } @@ -57,6 +65,7 @@ void ArpSeqTrack::seq(MidiUartParent *uart_) { } } uart = uart_old; + uart2 = uart2_old; } #define NOTE_RANGE 128 @@ -127,7 +136,7 @@ void ArpSeqTrack::render(uint8_t mode_, uint8_t oct_, uint8_t fine_tune_, uint8_ for (uint8_t i = 0; i < num_of_notes; i++) { switch (mode) { case ARP_RND: - note = sort_up[get_random(num_of_notes)] + 12 * random(range); + note = sort_up[get_random(num_of_notes)] + 12 * get_random(range); break; case ARP_UP2: case ARP_UPP: diff --git a/avr/cores/megacommand/MCL/ArpSeqTrack.h b/avr/cores/megacommand/MCL/ArpSeqTrack.h index 28679fc67..ce16bc03b 100644 --- a/avr/cores/megacommand/MCL/ArpSeqTrack.h +++ b/avr/cores/megacommand/MCL/ArpSeqTrack.h @@ -80,7 +80,7 @@ class ArpSeqTrack : public ArpSeqData, public SeqTrackBase { SeqTrackBase::reset(); } - ALWAYS_INLINE() void seq(MidiUartParent *uart_); + ALWAYS_INLINE() void seq(MidiUartParent *uart_, MidiUartParent *uart2_); void clear_track(); void re_sync(); void set_speed(uint8_t speed_); diff --git a/avr/cores/megacommand/MCL/DeviceTrack.cpp b/avr/cores/megacommand/MCL/DeviceTrack.cpp index eca00204f..32106f787 100644 --- a/avr/cores/megacommand/MCL/DeviceTrack.cpp +++ b/avr/cores/megacommand/MCL/DeviceTrack.cpp @@ -31,9 +31,9 @@ DeviceTrack *DeviceTrack::init_track_type(uint8_t track_type) { case MNM_TRACK_TYPE: ::new (this) MNMTrack; break; - case GRIDCHAIN_TRACK_TYPE: - ::new (this) GridChainTrack; - break; +// case GRIDCHAIN_TRACK_TYPE: +// ::new (this) GridChainTrack; +// break; case PERF_TRACK_TYPE: ::new (this) PerfTrack; break; @@ -126,7 +126,7 @@ bool DeviceTrackChunk::load_chunk(volatile void *ptr, uint8_t chunk) { if (chunk == get_chunk_count() - 1) { chunk_size = get_seq_data_size() - sizeof(seq_data_chunk) * chunk; } - memcpy(ptr + sizeof(seq_data_chunk) * chunk, seq_data_chunk, chunk_size); + memcpy((uint8_t*) ptr + sizeof(seq_data_chunk) * chunk, seq_data_chunk, chunk_size); return true; } diff --git a/avr/cores/megacommand/MCL/ExtSeqTrack.cpp b/avr/cores/megacommand/MCL/ExtSeqTrack.cpp index e9e0ec586..32ff7813c 100644 --- a/avr/cores/megacommand/MCL/ExtSeqTrack.cpp +++ b/avr/cores/megacommand/MCL/ExtSeqTrack.cpp @@ -678,6 +678,12 @@ void ExtSeqTrack::seq(MidiUartParent *uart_) { SET_BIT128_P(mute_mask, s); } + if (mute_state_pending) { + mute_state = SEQ_MUTE_ON; + mute_state_pending = false; + buffer_notesoff(); + } + if ((is_generic_midi || (!is_generic_midi && count_down == 0)) && (mute_state == SEQ_MUTE_OFF)) { // SEQ_MUTE_OFF)) { @@ -1213,10 +1219,6 @@ void ExtSeqTrack::toggle_mute() { if (mute_state == SEQ_MUTE_ON) { mute_state = SEQ_MUTE_OFF; } else { - mute_state = SEQ_MUTE_ON; - uint8_t mod12_counter_ = MidiClock.mod12_counter; - while (MidiClock.state == 2 && mod12_counter_ == MidiClock.mod12_counter) { - }; - buffer_notesoff(); + mute_state_pending = true; } } diff --git a/avr/cores/megacommand/MCL/ExtSeqTrack.h b/avr/cores/megacommand/MCL/ExtSeqTrack.h index 3975859f1..b19bed45a 100644 --- a/avr/cores/megacommand/MCL/ExtSeqTrack.h +++ b/avr/cores/megacommand/MCL/ExtSeqTrack.h @@ -158,6 +158,7 @@ class ExtSeqTrack : public ExtSeqTrackData, public SeqSlideTrack { static uint8_t epoch; NoteVector notes_on[NUM_NOTES_ON]; uint8_t notes_on_count; + bool mute_state_pending; uint8_t locks_slide_next_lock_utiming[NUM_LOCKS]; @@ -168,6 +169,7 @@ class ExtSeqTrack : public ExtSeqTrackData, public SeqSlideTrack { memset(oneshot_mask,0,sizeof(oneshot_mask)); memset(ignore_notes,0, sizeof(ignore_notes)); pgm_oneshot = 0; + mute_state_pending = false; } void seq(MidiUartParent *uart_); diff --git a/avr/cores/megacommand/MCL/ExtTrack.h b/avr/cores/megacommand/MCL/ExtTrack.h index 840883470..f626c4ae8 100644 --- a/avr/cores/megacommand/MCL/ExtTrack.h +++ b/avr/cores/megacommand/MCL/ExtTrack.h @@ -37,7 +37,7 @@ class ExtTrack : public DeviceTrack { } virtual void load_immediate(uint8_t tracknumber, SeqTrack *seq_track); - bool virtual convert(ExtTrack_270 *old) { + bool convert(ExtTrack_270 *old) { link.row = old->link.row; link.loops = old->link.loops; if (link.row >= GRID_LENGTH) { diff --git a/avr/cores/megacommand/MCL/FXPage.cpp b/avr/cores/megacommand/MCL/FXPage.cpp index 545eda603..944c25035 100644 --- a/avr/cores/megacommand/MCL/FXPage.cpp +++ b/avr/cores/megacommand/MCL/FXPage.cpp @@ -10,8 +10,6 @@ void FXPage::setup() { DEBUG_PRINT_FN(); } void FXPage::init() { DEBUG_PRINT_FN(); - oled_display.clearDisplay(); - oled_display.setFont(); trig_interface.off(); update_encoders(); MD.set_key_repeat(0); @@ -24,26 +22,12 @@ void FXPage::init() { void FXPage::update_encoders() { for (uint8_t n = 0; n < GUI_NUM_ENCODERS; n++) { - MCLEncoder * enc = encoders[n]; + MCLEncoder *enc = (MCLEncoder*) encoders[n]; enc->max = 127; uint8_t a = ((uint8_t)page_mode * GUI_NUM_ENCODERS) + n; uint8_t fx_param = params[a].param; - - switch (params[a].type) { - case MD_FX_ECHO: - enc->cur = MD.kit.delay[fx_param]; - break; - case MD_FX_REV: - enc->cur = MD.kit.reverb[fx_param]; - break; - case MD_FX_EQ: - enc->cur = MD.kit.eq[fx_param]; - break; - case MD_FX_DYN: - enc->cur = MD.kit.dynamics[fx_param]; - break; - } + enc->cur = MD.kit.get_fx_param(params[a].type, fx_param); enc->old = enc->cur; } @@ -53,14 +37,13 @@ void FXPage::update_encoders() { void FXPage::cleanup() { // md_exploit.off(); MD.set_key_repeat(1); - oled_display.clearDisplay(); } void FXPage::loop() { for (uint8_t i = 0; i < GUI_NUM_ENCODERS; i++) { uint8_t n = i + (page_mode * GUI_NUM_ENCODERS); - MCLEncoder *enc = encoders[i]; + MCLEncoder *enc = (MCLEncoder *) encoders[i]; if (enc->hasChanged()) { uint8_t fx_param = params[n].param; uint8_t fx_type = params[n].type; @@ -75,7 +58,6 @@ void FXPage::display() { char str[4]; PGM_P param_name = NULL; oled_display.clearDisplay(); - auto oldfont = oled_display.getFont(); uint8_t *icon = R.icons_page->icon_rhytmecho; if (page_id == 1) { @@ -106,8 +88,6 @@ void FXPage::display() { } info2 = &fx_page_title[0]; mcl_gui.draw_panel_labels(info1, info2); - oled_display.display(); - oled_display.setFont(oldfont); } bool FXPage::handleEvent(gui_event_t *event) { @@ -164,15 +144,5 @@ bool FXPage::handleEvent(gui_event_t *event) { return true; } - if (EVENT_PRESSED(event, Buttons.BUTTON3)) { - } - - if (EVENT_PRESSED(event, Buttons.BUTTON4)) { - } - if (EVENT_PRESSED(event, Buttons.BUTTON2)) { - mcl.setPage(PAGE_SELECT_PAGE); - return true; - } - return false; } diff --git a/avr/cores/megacommand/MCL/FileBrowserPage.cpp b/avr/cores/megacommand/MCL/FileBrowserPage.cpp index f3684e832..729f65977 100644 --- a/avr/cores/megacommand/MCL/FileBrowserPage.cpp +++ b/avr/cores/megacommand/MCL/FileBrowserPage.cpp @@ -47,12 +47,12 @@ void FileBrowserPage::setup() { encoders[2]->cur = 1; } -void FileBrowserPage::get_entry(uint16_t n, const char *entry) { +void FileBrowserPage::get_entry(uint16_t n, char *entry) { uint8_t discard_type; get_entry(n, entry, discard_type); } -void FileBrowserPage::get_entry(uint16_t n, const char *entry, uint8_t &type) { +void FileBrowserPage::get_entry(uint16_t n, char *entry, uint8_t &type) { volatile uint8_t *ptr = (uint8_t *)BANK3_FILE_ENTRIES_START + n * FILE_ENTRY_SIZE; char buf[FILE_ENTRY_SIZE]; @@ -172,7 +172,6 @@ void FileBrowserPage::draw_menu() { void FileBrowserPage::draw_sidebar() { constexpr uint8_t x_offset = 43; oled_display.clearDisplay(); - oled_display.setFont(&TomThumb); oled_display.setCursor(0, 8); oled_display.setTextColor(WHITE, BLACK); oled_display.println(title); @@ -220,13 +219,13 @@ void FileBrowserPage::draw_filebrowser() { } void FileBrowserPage::display() { + oled_display.setFont(&TomThumb); if (filemenu_active) { draw_menu(); return; } draw_sidebar(); draw_filebrowser(); - oled_display.display(); return; } @@ -260,7 +259,7 @@ void FileBrowserPage::loop() { bool FileBrowserPage::create_folder() { char new_dir[17] = "new_folder "; - if (mcl_gui.wait_for_input(new_dir, "Create Folder", 8)) { + if (mcl_gui.wait_for_input(new_dir, "Create Folder", NAME_LENGTH)) { SD.mkdir(new_dir); init(); } @@ -366,7 +365,7 @@ bool FileBrowserPage::_handle_filemenu() { for (uint8_t n = 1; n < 32; n++) { buf2[n] = ' '; } - uint8_t name_length = 8; + uint8_t name_length = NAME_LENGTH; switch (file_menu_page.menu.get_item_index(file_menu_encoder.cur)) { case FM_NEW_FOLDER: // new folder @@ -386,8 +385,8 @@ bool FileBrowserPage::_handle_filemenu() { if (suffix_pos != nullptr) { buf2[suffix_pos - buf1] = '\0'; } - // default max length = 8, can extend if buf2 without suffix - // is longer than 8. + // default max length = NAME_LENGTH, can extend if buf2 without suffix + // is longer than NAME_LENGTH. name_length = max(name_length, strlen(buf2)); if (mcl_gui.wait_for_input(buf2, "RENAME TO:", name_length)) { if (suffix_pos != nullptr) { diff --git a/avr/cores/megacommand/MCL/FileBrowserPage.h b/avr/cores/megacommand/MCL/FileBrowserPage.h index 3c3500716..a77e95145 100644 --- a/avr/cores/megacommand/MCL/FileBrowserPage.h +++ b/avr/cores/megacommand/MCL/FileBrowserPage.h @@ -30,12 +30,14 @@ #define FM_RECVALL 4 #define FM_SENDALL 5 +#define NAME_LENGTH 14 + class FileBrowserFileTypes { constexpr static uint8_t size = 2; char types[size][5]; uint8_t count = 0; public: - void add(char *str) { + void add(const char *str) { if (count < size) { strcpy(types[count], str); count++; @@ -140,8 +142,8 @@ class FileBrowserPage : public LightPage { static constexpr uint8_t DIR_TYPE = 1; bool add_entry(const char *entry, uint8_t type = FILE_TYPE); - void get_entry(uint16_t n, const char *entry); - void get_entry(uint16_t n, const char *entry, uint8_t &type); + void get_entry(uint16_t n, char *entry); + void get_entry(uint16_t n, char *entry, uint8_t &type); void draw_scrollbar(uint8_t x_offset); bool create_folder(); diff --git a/avr/cores/megacommand/MCL/Grid.cpp b/avr/cores/megacommand/MCL/Grid.cpp index 34841eba2..e40514ab9 100644 --- a/avr/cores/megacommand/MCL/Grid.cpp +++ b/avr/cores/megacommand/MCL/Grid.cpp @@ -65,7 +65,7 @@ bool Grid::new_file(const char *gridname) { bool Grid::new_grid(const char *gridname) { bool ret = false; - + uint8_t ledstatus = 0; DEBUG_PRINT_FN(); DEBUG_PRINTLN(F("Creating new grid")); if (!new_file(gridname)) { @@ -79,7 +79,6 @@ bool Grid::new_grid(const char *gridname) { oled_display.drawRect(15, 23, 98, 6, WHITE); #endif // Initialise the project file by filling the grid with blank data. - uint8_t ledstatus = 0; for (uint16_t i = 0; i < GRID_LENGTH; i++) { #ifdef OLED_DISPLAY diff --git a/avr/cores/megacommand/MCL/GridIOPage.cpp b/avr/cores/megacommand/MCL/GridIOPage.cpp index 3c65a1574..505fa6dd6 100644 --- a/avr/cores/megacommand/MCL/GridIOPage.cpp +++ b/avr/cores/megacommand/MCL/GridIOPage.cpp @@ -12,6 +12,7 @@ void GridIOPage::cleanup() { trig_interface.send_md_leds(); MD.popup_text(127, 2); proj.select_grid(old_grid); + offset = 255; } void GridIOPage::init() { diff --git a/avr/cores/megacommand/MCL/GridLoadPage.cpp b/avr/cores/megacommand/MCL/GridLoadPage.cpp index 4806a4851..32ce56381 100644 --- a/avr/cores/megacommand/MCL/GridLoadPage.cpp +++ b/avr/cores/megacommand/MCL/GridLoadPage.cpp @@ -108,8 +108,6 @@ void GridLoadPage::display() { const uint64_t mute_mask = 0, slide_mask = 0; - auto oldfont = oled_display.getFont(); - if (show_track_type) { mcl_gui.draw_track_type_select(mcl_cfg.track_type_select); } @@ -118,7 +116,6 @@ void GridLoadPage::display() { // mcl_gui.draw_text_encoder(MCLGUI::s_menu_x + 4, MCLGUI::s_menu_y + 8, // "STEP", K); if (show_offset) { - oled_display.setFont(); oled_display.setCursor(MCLGUI::s_menu_x + 18, 12); oled_display.print("DESTINATION"); trig_mask = 0; @@ -193,8 +190,6 @@ void GridLoadPage::display() { oled_display.print(F("SEQ")); */ } - oled_display.display(); - oled_display.setFont(oldfont); } void GridLoadPage::load() { @@ -211,10 +206,8 @@ void GridLoadPage::load() { track_select_array[n] = 1; } } - mcl.setPage(GRID_PAGE); - trig_interface.off(); - grid_task.load_queue.put(mcl_cfg.load_mode, grid_page.getRow(), track_select_array, offset); + mcl.setPage(GRID_PAGE); } void GridLoadPage::group_select() { diff --git a/avr/cores/megacommand/MCL/GridPage.cpp b/avr/cores/megacommand/MCL/GridPage.cpp index c4aefef8f..b18a0d181 100644 --- a/avr/cores/megacommand/MCL/GridPage.cpp +++ b/avr/cores/megacommand/MCL/GridPage.cpp @@ -1,28 +1,42 @@ #include "MCL_impl.h" #include "ResourceManager.h" +#define PERF_ENC 1 +#define GRID_ENC 0 + void GridPage::init() { DEBUG_PRINTLN("Grid page init"); - encoders[0] = ¶m1; - encoders[1] = ¶m2; - ((MCLEncoder *)encoders[0])->max = getWidth() - 1; + if (mcl_cfg.grid_page_mode == PERF_ENC) { + encoders[0] = &perf_param1; + encoders[1] = &perf_param2; + encoders[2] = &perf_param3; + encoders[3] = &perf_param4; + } + else { + encoders[0] = ¶m1; + encoders[1] = ¶m2; + encoders[2] = ¶m3; + encoders[3] = ¶m4; + } + param1.max = getWidth() - 1; show_slot_menu = false; reload_slot_models = false; + draw_encoders = false; // Edge case, prevent R.Clear being called if we're outside of GridPage if (mcl.currentPage() != GRID_PAGE) { return; } trig_interface.off(); //load_slot_models(); - oled_display.clearDisplay(); R.Clear(); R.use_machine_names_short(); + R.use_icons_knob(); } void GridPage::setup() { - encoders[0]->cur = encoders[0]->old = mcl_cfg.col; - encoders[1]->cur = encoders[1]->old = mcl_cfg.row; - encoders[2]->cur = 1; + param1.cur = param1.old = mcl_cfg.col; + param2.cur = param2.old = mcl_cfg.row; + param3.cur = 1; cur_col = mcl_cfg.cur_col; cur_row = mcl_cfg.cur_row; memset(active_slots, SLOT_DISABLED, sizeof(active_slots)); @@ -83,7 +97,7 @@ void GridPage::close_bank_popup() { DEBUG_PRINTLN("setting page"); mcl.setPage(last_page); } - last_page = 255; + last_page = NULL_PAGE; bank_popup = 0; note_interface.init_notes(); // Clear blink leds @@ -94,39 +108,48 @@ void GridPage::load_old_col() { cur_col = old_col; param1.cur = cur_col; param1.old = cur_col; - encoders[2]->cur = GRID_WIDTH - cur_col; - encoders[2]->old = encoders[2]->cur; + param3.cur = GRID_WIDTH - cur_col; + param3.old = param3.cur; grid_page.grid_select_apply = 0; proj.grid_select = 0; - ((MCLEncoder *)encoders[2])->max = getWidth() + 1; + param3.max = getWidth() + 1; } void GridPage::loop() { + if (mcl_cfg.grid_page_mode == PERF_ENC) { + //need to limit range of the alternate encoders + encoder_t *enc = nullptr; + perf_page.func_enc_check(); + param1.update(enc); + param2.update(enc); + param3.update(enc); + param4.update(enc); + } int8_t diff, new_val; if (show_slot_menu) { - if (encoders[2]->hasChanged()) { - if ((proj.get_grid() == 0) && (getCol() + encoders[2]->cur > GRID_WIDTH)) { + if (param3.hasChanged()) { + if ((proj.get_grid() == 0) && (getCol() + param3.cur > GRID_WIDTH)) { old_col = getCol(); cur_col = 0; param1.cur = 0; param1.old = 0; - encoders[2]->cur = 1; - encoders[2]->old = 1; + param3.cur = 1; + param3.old = 1; grid_page.grid_select_apply = 1; proj.grid_select = 1; - ((MCLEncoder *)encoders[2])->max = getWidth(); + param3.max = getWidth(); load_slot_models(); reload_slot_models = true; } - else if ((proj.get_grid() == 1) && (encoders[2]->cur == 0) && (old_col != 255)) { + else if ((proj.get_grid() == 1) && (param3.cur == 0) && (old_col != 255)) { load_old_col(); load_slot_models(); reload_slot_models = true; } - if (encoders[2]->cur == 0) { encoders[2]->cur = 1; encoders[2]->old = 1; } + if (param3.cur == 0) { param3.cur = 1; param3.old = 1; } } - if (encoders[3]->hasChanged()) { - if (cur_row + encoders[3]->cur > MAX_VISIBLE_ROWS - 1) { + if (param4.hasChanged()) { + if (cur_row + param4.cur > MAX_VISIBLE_ROWS - 1) { load_slot_models(); reload_slot_models = true; } @@ -134,21 +157,22 @@ void GridPage::loop() { grid_slot_page.loop(); return; } else { - } - /* - if (encoders[2]->hasChanged()) { - diff = encoders[2]->cur - encoders[2]->old; - if (cur_col + encoders[2]->cur > MAX_VISIBLE_COLS - 1) { - encoders[0]->cur += diff; - encoders[0]->old = encoders[0]->cur; + if (mcl_cfg.grid_page_mode == PERF_ENC) { + if (encoders[0]->hasChanged() || encoders[1]->hasChanged() || encoders[2]->hasChanged() || encoders[3]->hasChanged()) { + //mcl.setPage(MIXER_PAGE); + draw_encoders_lastclock = slowclock; + draw_encoders = true; + //return; + perf_page.encoder_send(); + } } - } -*/ - if (encoders[2]->hasChanged()) { - if (encoders[2]->cur == 0) { encoders[2]->cur = 1; encoders[2]->old = 1; } } - if (encoders[0]->hasChanged()) { - diff = encoders[0]->cur - encoders[0]->old; + + if (param3.hasChanged()) { + if (param3.cur == 0) { param3.cur = 1; param3.old = 1; } + } + if (param1.hasChanged()) { + diff = param1.cur - param1.old; new_val = cur_col + diff; if (new_val > MAX_VISIBLE_COLS - 1) { new_val = MAX_VISIBLE_COLS - 1; @@ -159,8 +183,8 @@ void GridPage::loop() { cur_col = new_val; } - if (encoders[1]->hasChanged()) { - diff = encoders[1]->cur - encoders[1]->old; + if (param2.hasChanged()) { + diff = param2.cur - param2.old; new_val = cur_row + diff; if (new_val > MAX_VISIBLE_ROWS - 1) { @@ -169,7 +193,6 @@ void GridPage::loop() { if (new_val < 0) { new_val = 0; } - // MD.assignMachine(0, encoders[1]->cur); cur_row = new_val; if ((cur_row == MAX_VISIBLE_ROWS - 1) || (cur_row == 0)) { load_slot_models(); @@ -180,10 +203,9 @@ void GridPage::loop() { volatile uint8_t *ptr; write_cfg = true; } - encoders[2]->cur = 1; - encoders[3]->cur = 1; - //((MCLEncoder *)encoders[2])->max = getWidth() + 1 - getCol(); - ((MCLEncoder *)encoders[3])->max = GRID_LENGTH - getRow(); + param3.cur = 1; + param4.cur = 1; + param4.max = GRID_LENGTH - getRow(); if (!reload_slot_models) { load_slot_models(); @@ -202,8 +224,8 @@ void GridPage::loop() { mcl_cfg.cur_col = cur_col; mcl_cfg.cur_row = cur_row; - mcl_cfg.col = encoders[0]->cur; - mcl_cfg.row = encoders[1]->cur; + mcl_cfg.col = param1.cur; + mcl_cfg.row = param2.cur; mcl_cfg.tempo = MidiClock.get_tempo(); DEBUG_PRINTLN(F("write cfg")); @@ -216,6 +238,13 @@ void GridPage::loop() { row_state_scan(); } + if (mcl_cfg.grid_page_mode == PERF_ENC) { + param1.checkHandle(); + param2.checkHandle(); + param3.checkHandle(); + param4.checkHandle(); + } + if (bank_popup == 2 && clock_diff(bank_popup_lastclock, slowclock) > 800) { close_bank_popup(); return; @@ -262,8 +291,8 @@ uint8_t GridPage::getWidth() { return GRID_WIDTH; } void GridPage::load_slot_models() { DEBUG_PRINTLN("load slot models"); uint8_t row_shift = 0; - if ((cur_row + encoders[3]->cur > MAX_VISIBLE_ROWS - 1)) { - row_shift = cur_row + encoders[3]->cur - MAX_VISIBLE_ROWS; + if ((cur_row + param4.cur > MAX_VISIBLE_ROWS - 1)) { + row_shift = cur_row + param4.cur - MAX_VISIBLE_ROWS; } for (uint8_t n = 0; n < MAX_VISIBLE_ROWS; n++) { @@ -357,13 +386,13 @@ void GridPage::display_grid_info() { oled_display.print(':'); char val[4]; - mcl_gui.put_value_at2(encoders[0]->cur + 1, val); + mcl_gui.put_value_at2(param1.cur + 1, val); val[2] = '\0'; oled_display.print(val); oled_display.print(F(" ")); - uint8_t b = encoders[1]->cur / 16; + uint8_t b = param2.cur / 16; oled_display.print((char)('A' + b)); - mcl_gui.put_value_at2(encoders[1]->cur - b * 16 + 1, val); + mcl_gui.put_value_at2(param2.cur - b * 16 + 1, val); oled_display.print(val); oled_display.setCursor(1, y_offset + 2 * 8); @@ -401,19 +430,21 @@ void GridPage::display_grid() { char str[3]; PGM_P tmp; - encoders[1]->handler = NULL; + +// encoders[1]->handler = NULL; + uint8_t row_shift = 0; uint8_t col_shift = 0; auto grid_id = proj.get_grid(); auto *device = midi_active_peering.get_device(grid_id + 1); if (show_slot_menu) { - if (cur_col + encoders[2]->cur > MAX_VISIBLE_COLS - 1) { + if (cur_col + param3.cur > MAX_VISIBLE_COLS - 1) { - col_shift = cur_col + encoders[2]->cur - MAX_VISIBLE_COLS; + col_shift = cur_col + param3.cur - MAX_VISIBLE_COLS; } - if (cur_row + encoders[3]->cur > MAX_VISIBLE_ROWS - 1) { - row_shift = cur_row + encoders[3]->cur - MAX_VISIBLE_ROWS; + if (cur_row + param4.cur > MAX_VISIBLE_ROWS - 1) { + row_shift = cur_row + param4.cur - MAX_VISIBLE_ROWS; } } for (uint8_t y = 0; y < MAX_VISIBLE_ROWS; y++) { @@ -484,8 +515,8 @@ void GridPage::display_grid() { break; } // Highlight the current cursor position + slot menu apply range - bool a = in_area(x, y + row_shift, cur_col, cur_row, encoders[2]->cur - 1, - encoders[3]->cur - 1); + bool a = in_area(x, y + row_shift, cur_col, cur_row, param3.cur - 1, + param4.cur - 1); bool b = is_slot_queue(track_idx, row_idx); if (a ^ b) { @@ -534,6 +565,24 @@ void GridPage::display_slot_menu() { // grid_slot_page.draw_scrollbar(36); } +void GridPage::display_row_info() { + uint8_t row_shift = 0; + if ((cur_row + param4.cur > MAX_VISIBLE_ROWS - 1)) { + row_shift = cur_row + param4.cur - MAX_VISIBLE_ROWS; + } + char val[4]; + val[2] = '\0'; + + for (uint8_t n = 0; n < MAX_VISIBLE_ROWS; n++) { + uint8_t row = getRow() - cur_row + n + row_shift; + if (row >= GRID_LENGTH) { return; } + uint8_t b = row / 16; + oled_display.setCursor(27, (n + 1) * 8); + oled_display.print((char)('A' + b)); + mcl_gui.put_value_at2(row - b * 16 + 1, val); + oled_display.print(val); + } +} #ifdef FPS int frames; int frameclock; @@ -554,26 +603,26 @@ void GridPage::display() { if (!show_slot_menu) { display_grid_info(); } else { - display_slot_menu(); + if (param4.cur > 4) { + display_row_info(); + } + else{ + display_slot_menu(); + } } display_grid(); + if (draw_encoders && clock_diff(draw_encoders_lastclock, slowclock) < 750) { + oled_display.setFont(); + mixer_page.draw_encs(); + } + else { + draw_encoders = false; + } /* if (row_scan) { mcl_gui.draw_progress_bar(8, 8, false, 18, 2, 9, 7, false); } */ - oled_display.display(); -} - -void GridPage::prepare() { - if (MD.connected) { - MD.getCurrentTrack(CALLBACK_TIMEOUT); - MD.currentKit = MD.getCurrentKit(CALLBACK_TIMEOUT); - MD.getBlockingKit(0x7F); - if (MidiClock.state == 2) { - mcl_seq.update_kit_params(); - } - } } void rename_row() { @@ -609,10 +658,11 @@ void apply_slot_changes_cb() { grid_page.apply_slot_changes(); } bool GridPage::swap_grids() { if (grid_select_apply != proj.grid_select) { proj.grid_select = grid_select_apply; - ((MCLEncoder *)encoders[0])->max = getWidth() - 1; + param1.max = getWidth() - 1; //load_slot_models(); - return; + return true; } + return false; } void GridPage::apply_slot_changes(bool ignore_undo, bool ignore_func) { @@ -621,6 +671,7 @@ void GridPage::apply_slot_changes(bool ignore_undo, bool ignore_func) { uint8_t _col = getCol();; + bool activate_header = false; //old_col != 255 indicates that the grid selection spans grids x and y. if (old_col != 255) { _col = old_col; @@ -630,6 +681,11 @@ void GridPage::apply_slot_changes(bool ignore_undo, bool ignore_func) { GridTrack temp_slot; temp_slot.load_from_grid(_col, getRow()); + uint8_t track_select_array[NUM_SLOTS] = {0}; + SeqTrack seq_track; + uint16_t target_length = slot.link.length * seq_track.get_speed_multiplier(slot.link.speed) * slot.link.loops; + + if (old_col == 255) { if (swap_grids()) { return; } } @@ -649,8 +705,8 @@ void GridPage::apply_slot_changes(bool ignore_undo, bool ignore_func) { return; } } - width = old_col != 255 ? GRID_WIDTH - _col : encoders[2]->cur; - height = encoders[3]->cur; + width = old_col != 255 ? GRID_WIDTH - _col : param3.cur; + height = param4.cur; uint8_t slot_update = 0; @@ -687,7 +743,7 @@ void GridPage::apply_slot_changes(bool ignore_undo, bool ignore_func) { } mcl_clipboard.copy(_col + 16 * proj.get_grid(), getRow(), width, height); if (old_col != 255 && proj.get_grid() == 0) { - mcl_clipboard.copy(16, getRow(), encoders[2]->cur, height); + mcl_clipboard.copy(16, getRow(), param3.cur, height); mcl_clipboard.t_col = _col; mcl_clipboard.t_w += GRID_WIDTH - cur_col; DEBUG_PRINTLN("copy grid 1+2"); @@ -722,16 +778,12 @@ void GridPage::apply_slot_changes(bool ignore_undo, bool ignore_func) { oled_display.display(); - bool activate_header = false; - uint8_t track_select_array[NUM_SLOTS] = {0}; GridRowHeader header; - SeqTrack seq_track; - uint16_t target_length = slot.link.length * seq_track.get_speed_multiplier(slot.link.speed) * slot.link.loops; - again: + for (uint8_t y = 0; y < height && y + getRow() < GRID_LENGTH; y++) { uint8_t ypos = y + getRow(); proj.read_grid_row_header(&header, y + getRow()); @@ -796,7 +848,7 @@ void GridPage::apply_slot_changes(bool ignore_undo, bool ignore_func) { if (old_col != 255) { if (proj.get_grid() == 0) { proj.select_grid(1); - width = encoders[2]->cur; + width = param3.cur; _col = 0; goto again; } @@ -908,6 +960,7 @@ bool GridPage::handleEvent(gui_event_t *event) { } next: if (event->mask == EVENT_BUTTON_PRESSED) { + if (key != MDX_KEY_FUNC) { draw_encoders = false; } uint8_t inc = 1; if (trig_interface.is_key_down(MDX_KEY_FUNC)) { inc = 4; @@ -1086,8 +1139,10 @@ bool GridPage::handleEvent(gui_event_t *event) { DEBUG_DUMP(slot.link.row); encoders[0] = &grid_slot_param1; encoders[1] = &grid_slot_param2; - encoders[2]->cur = 1; - encoders[3]->cur = 1; + encoders[2] = ¶m3; + encoders[3] = ¶m4; + param3.cur = 1; + param4.cur = 1; slot_apply = 0; old_col = 255; if (!slot.is_ext_track()) { @@ -1132,10 +1187,6 @@ bool GridPage::handleEvent(gui_event_t *event) { mcl.pushPage(SYSTEM_PAGE); return true; } - if (EVENT_PRESSED(event, Buttons.BUTTON2)) { - mcl.setPage(PAGE_SELECT_PAGE); - return true; - } return false; } diff --git a/avr/cores/megacommand/MCL/GridPage.h b/avr/cores/megacommand/MCL/GridPage.h index 3b07b6ca1..f89a279cb 100644 --- a/avr/cores/megacommand/MCL/GridPage.h +++ b/avr/cores/megacommand/MCL/GridPage.h @@ -15,6 +15,8 @@ #define SLOT_RAM_RECORD 252 #define SLOT_RAM_PLAY 251 +class GridTrack; + class GridPage : public LightPage { public: GridRowHeader row_headers[MAX_VISIBLE_ROWS]; @@ -59,6 +61,8 @@ class GridPage : public LightPage { uint16_t bank_popup_lastclock; uint16_t bank_popup_loadmask; + bool draw_encoders; + uint16_t draw_encoders_lastclock; GridPage(Encoder *e1 = NULL, Encoder *e2 = NULL, Encoder *e3 = NULL, Encoder *e4 = NULL) : LightPage(e1, e2, e3, e4) {} @@ -81,14 +85,15 @@ class GridPage : public LightPage { void display_counters(); void display_grid_info(); void display_grid(); + void display_row_info(); void display(); void display_oled(); void setup(); void cleanup(); void init(); - void prepare(); bool swap_grids(); void apply_slot_changes(bool ignore_undo = false, bool ignore_func = false); + void load_old_col(); void close_bank_popup(); diff --git a/avr/cores/megacommand/MCL/GridSavePage.cpp b/avr/cores/megacommand/MCL/GridSavePage.cpp index 9fcb6fdc7..19ac02637 100644 --- a/avr/cores/megacommand/MCL/GridSavePage.cpp +++ b/avr/cores/megacommand/MCL/GridSavePage.cpp @@ -28,8 +28,6 @@ void GridSavePage::display() { draw_popup(); - auto oldfont = oled_display.getFont(); - const uint64_t slide_mask = 0; const uint64_t mute_mask = 0; if (show_track_type) { @@ -73,8 +71,6 @@ void GridSavePage::display() { oled_display.setCursor(data_x + 24 + 9, MCLGUI::s_menu_y + 18); oled_display.print(F("GRID")); } - oled_display.display(); - oled_display.setFont(oldfont); } void GridSavePage::save() { @@ -96,9 +92,8 @@ void GridSavePage::save() { } } - mcl.setPage(GRID_PAGE); - trig_interface.off(); mcl_actions.save_tracks(grid_page.getRow(), track_select_array, save_mode); + mcl.setPage(GRID_PAGE); } void GridSavePage::group_select() { diff --git a/avr/cores/megacommand/MCL/GridTask.cpp b/avr/cores/megacommand/MCL/GridTask.cpp index 1c08d1b48..070d60988 100644 --- a/avr/cores/megacommand/MCL/GridTask.cpp +++ b/avr/cores/megacommand/MCL/GridTask.cpp @@ -118,7 +118,7 @@ void GridTask::transition_handler() { // = 0.032 * MidiClock.get_tempo() // while (MidiClock.clock_less_than( - MidiClock.div32th_counter + 0.032 * MidiClock.get_tempo(), + MidiClock.div32th_counter + 0.032 * max(60.0,MidiClock.get_tempo()), (uint32_t)mcl_actions.next_transition * 2) <= 0) { float div32th_per_second = MidiClock.get_tempo() * 0.133333333333f; diff --git a/avr/cores/megacommand/MCL/GridTrack.cpp b/avr/cores/megacommand/MCL/GridTrack.cpp index c00ffce17..80a7bfd49 100644 --- a/avr/cores/megacommand/MCL/GridTrack.cpp +++ b/avr/cores/megacommand/MCL/GridTrack.cpp @@ -1,7 +1,7 @@ #include "MCL_impl.h" -bool GridTrack::write_grid(void *data, size_t len, uint8_t column, uint16_t row, Grid *grid = nullptr) { +bool GridTrack::write_grid(void *data, size_t len, uint8_t column, uint16_t row, Grid *grid) { if (grid == nullptr) { return proj.write_grid((uint8_t *)(this), len, column, row); } diff --git a/avr/cores/megacommand/MCL/GridTrack.h b/avr/cores/megacommand/MCL/GridTrack.h index a37515258..e504867ef 100644 --- a/avr/cores/megacommand/MCL/GridTrack.h +++ b/avr/cores/megacommand/MCL/GridTrack.h @@ -70,7 +70,7 @@ class GridTrack { /// caller guarantees that the type is reconstructed correctly /// downloads from BANK1 to the runtime object bool load_from_mem(uint8_t column, size_t size = 0) { - uint32_t bytes = size ? size : get_track_size(); + uint16_t bytes = size ? size : get_track_size(); uint32_t pos = get_region() + get_region_size() * (uint32_t)(column); volatile uint8_t *ptr = reinterpret_cast(pos); memcpy_bank1(this, ptr, bytes); diff --git a/avr/cores/megacommand/MCL/LFOPage.cpp b/avr/cores/megacommand/MCL/LFOPage.cpp index cf77d307d..935ee2a1d 100644 --- a/avr/cores/megacommand/MCL/LFOPage.cpp +++ b/avr/cores/megacommand/MCL/LFOPage.cpp @@ -31,7 +31,6 @@ void LFOPage::init() { void LFOPage::cleanup() { PerfPageParent::cleanup(); trig_interface.off(); - oled_display.clearDisplay(); } void LFOPage::config_encoder_range(uint8_t i) { @@ -150,7 +149,6 @@ void LFOPage::loop() { void LFOPage::display() { oled_display.clearDisplay(); - auto oldfont = oled_display.getFont(); uint8_t lfo_track_num = lfo_track->track_number; mcl_gui.draw_panel_number(lfo_track_num); mcl_gui.draw_panel_toggle("ON", "OFF", lfo_track->enable); @@ -238,8 +236,6 @@ void LFOPage::display() { mcl_gui.draw_panel_labels(info1, info2); - oled_display.display(); - oled_display.setFont(oldfont); } void LFOPage::learn_param(uint8_t track, uint8_t param, uint8_t value) { diff --git a/avr/cores/megacommand/MCL/LFOSeqTrack.cpp b/avr/cores/megacommand/MCL/LFOSeqTrack.cpp index 7c6afa94f..741bc96a3 100644 --- a/avr/cores/megacommand/MCL/LFOSeqTrack.cpp +++ b/avr/cores/megacommand/MCL/LFOSeqTrack.cpp @@ -1,6 +1,6 @@ #include "MCL_impl.h" -static uint8_t LFOSeqTrack::wav_tables[4][WAV_LENGTH]; +uint8_t LFOSeqTrack::wav_tables[4][WAV_LENGTH]; void LFOSeqTrack::load_tables() { SinLFO sin_lfo; diff --git a/avr/cores/megacommand/MCL/LoadProjectPage.cpp b/avr/cores/megacommand/MCL/LoadProjectPage.cpp index 215ce4fe3..4802cadc9 100644 --- a/avr/cores/megacommand/MCL/LoadProjectPage.cpp +++ b/avr/cores/megacommand/MCL/LoadProjectPage.cpp @@ -72,38 +72,31 @@ void LoadProjectPage::on_rename(const char *from, const char *to) { return; } + char grid_filename[f_len] = {'\0'}; + char to_grid_filename[f_len] = {'\0'}; + char proj_filename[f_len] = {'\0'}; + + char to_proj_filename[f_len] = {'\0'}; + bool reload_current = false; + uint8_t l, l2 = 0; if (!SD.chdir(from)) { goto error; } - bool reload_current = false; if (strcmp(mcl_cfg.project, from) == 0) { DEBUG_PRINTLN("reload current"); reload_current = true; } - char grid_filename[f_len] = {'\0'}; - char to_grid_filename[f_len] = {'\0'}; - char proj_filename[f_len] = {'\0'}; - strncpy(proj_filename, from, f_len); strcat(proj_filename, ".mcl"); - char to_proj_filename[f_len] = {'\0'}; strncpy(to_proj_filename, to, f_len); strcat(to_proj_filename, ".mcl"); strncpy(to_grid_filename, to, f_len); strncpy(grid_filename, from, f_len); - uint8_t l = strlen(grid_filename); - uint8_t l2 = strlen(to_grid_filename); - - DEBUG_PRINTLN("check"); - DEBUG_PRINTLN(from); - DEBUG_PRINTLN(to); - DEBUG_PRINTLN(grid_filename); - DEBUG_PRINTLN(to_grid_filename); - DEBUG_PRINTLN(proj_filename); - DEBUG_PRINTLN(to_proj_filename); + l = strlen(grid_filename); + l2 = strlen(to_grid_filename); for (uint8_t i = 0; i < NUM_GRIDS; i++) { grid_filename[l] = '.'; @@ -114,32 +107,22 @@ void LoadProjectPage::on_rename(const char *from, const char *to) { to_grid_filename[l2 + 1] = i + '0'; to_grid_filename[l2 + 2] = '\0'; - DEBUG_PRINTLN("from to grid filenames"); - DEBUG_PRINTLN(grid_filename); - DEBUG_PRINTLN(to_grid_filename); if (!SD.rename(grid_filename, to_grid_filename)) { DEBUG_PRINTLN("Rename failed"); goto error; } } - DEBUG_PRINTLN("from to project filename"); - DEBUG_PRINTLN(proj_filename); - DEBUG_PRINTLN(to_proj_filename); - if (!SD.rename(proj_filename, to_proj_filename)) { goto error; } SD.chdir(lwd); - DEBUG_PRINTLN("rename from to"); - DEBUG_PRINTLN(from); - DEBUG_PRINTLN(to); if (SD.rename(from, to)) { if (reload_current) { proj.load_project(to); } gfx.alert("SUCCESS", "Project renamed."); - return true; + return; } error: DEBUG_PRINTLN("error"); diff --git a/avr/cores/megacommand/MCL/MCL.cpp b/avr/cores/megacommand/MCL/MCL.cpp index ed2467d82..db54b5df4 100644 --- a/avr/cores/megacommand/MCL/MCL.cpp +++ b/avr/cores/megacommand/MCL/MCL.cpp @@ -2,6 +2,49 @@ #include "MCL_impl.h" #include "ResourceManager.h" + +uint32_t read_bytes_progmem(uint32_t address, uint8_t n) { + uint32_t value = 0; + for (uint8_t i = 0; i < n; i++) { + uint8_t byte = pgm_read_byte_far(address + i); // Read a byte from program memory + value |= (uint32_t)byte << (8 * i); // Combine bytes into a 32-bit value + } + return value; +} + + +bool health_check() { + uint32_t memoryAddress = 256 * 1024 - 16 * 1024 - 6; + uint32_t length = read_bytes_progmem(memoryAddress, 4); + uint16_t checksum = (uint16_t) read_bytes_progmem(memoryAddress + 4, 2); + DEBUG_PRINTLN(length); + DEBUG_PRINTLN(checksum); + + uint16_t calc_checksum = 0; + uint32_t n = 0; + uint8_t byte = 0; + + for (uint32_t n = 0; n < length; n++) { + uint8_t last_byte = byte; + byte = pgm_read_byte_far(n); + if (n % 2 == 0) { + calc_checksum ^= (byte << 8) | last_byte; + } + } + + DEBUG_PRINTLN(calc_checksum); + +#ifdef DEBUGMODE + if (calc_checksum != checksum) { + DEBUG_PRINTLN("checksum error"); + } +#endif + + return calc_checksum == checksum; + +} + + void sdcard_bench() { EmptyTrack empty_track; @@ -34,7 +77,7 @@ void sdcard_bench() { void mcl_setup() { mcl.setup(); } -static LightPage *const MCL::pages_table[NUM_PAGES] PROGMEM = { +LightPage *const MCL::pages_table[NUM_PAGES] PROGMEM = { &grid_page, // Index: 0 &page_select_page, // Index: 1 &system_page, // Index: 2 @@ -70,17 +113,16 @@ static LightPage *const MCL::pages_table[NUM_PAGES] PROGMEM = { &chain_config_page, // Index: 28 &aux_config_page, // Index: 29 &mcl_config_page, // Index: 30 - &ram_config_page, // Index: 31 - &arp_page, // Index: 32 - &md_import_page, // Index: 33 - &midiport_menu_page, // Index: 34 - &midiprogram_menu_page, // Index: 35 - &midiclock_menu_page, // Index: 36 - &midiroute_menu_page, // Index: 37 - &midimachinedrum_menu_page,// Index: 38 - &midigeneric_menu_page, // Index: 39 - &sound_browser, // Index: 40 - &perf_page // Index: 41 + &arp_page, // Index: 31 + &md_import_page, // Index: 32 + &midiport_menu_page, // Index: 33 + &midiprogram_menu_page, // Index: 34 + &midiclock_menu_page, // Index: 35 + &midiroute_menu_page, // Index: 36 + &midimachinedrum_menu_page,// Index: 37 + &midigeneric_menu_page, // Index: 38 + &sound_browser, // Index: 39 + &perf_page // Index: 40 }; void MCL::setup() { @@ -103,10 +145,21 @@ void MCL::setup() { DEBUG_PRINTLN(BANK3_FILE_ENTRIES_END); bool ret = false; - delay(100); - + delay(50); +#ifdef CHECKSUM + bool health = health_check(); +#endif ret = mcl_sd.sd_init(); gfx.init_oled(); + +#ifdef CHECKSUM + if (!health) { + oled_display.textbox("CHECKSUM ", "ERROR"); + oled_display.display(); + while (1); + } +#endif + R.Clear(); R.use_icons_boot(); @@ -225,7 +278,8 @@ bool mcl_handleEvent(gui_event_t *event) { case MDX_KEY_BANKD: { if (mcl.currentPage() == GRID_LOAD_PAGE || mcl.currentPage() == GRID_SAVE_PAGE || - (mcl.currentPage() == GRID_PAGE && grid_page.show_slot_menu)) { + (mcl.currentPage() == GRID_PAGE && grid_page.show_slot_menu)) { // || +// (mcl.currentPage() == MIXER_PAGE && mixer_page.preview_mute_set != 255)) { return false; } if (trig_interface.is_key_down(MDX_KEY_FUNC)) { @@ -381,6 +435,12 @@ bool mcl_handleEvent(gui_event_t *event) { } } } + + if (EVENT_PRESSED(event, Buttons.BUTTON2)) { + mcl.setPage(PAGE_SELECT_PAGE); + return true; + } + return false; } diff --git a/avr/cores/megacommand/MCL/MCL.h b/avr/cores/megacommand/MCL/MCL.h index 4a86d4256..1173c7864 100644 --- a/avr/cores/megacommand/MCL/MCL.h +++ b/avr/cores/megacommand/MCL/MCL.h @@ -16,8 +16,8 @@ #include "Fonts/Elektrothic.h" #include "Fonts/TomThumb.h" -#define VERSION 4051 -#define VERSION_STR "4.51" +#define VERSION 4060 +#define VERSION_STR "4.60" #define CALLBACK_TIMEOUT 500 #define GUI_NAME_TIMEOUT 800 @@ -63,24 +63,23 @@ enum PageIndex { CHAIN_CONFIG_PAGE, // Index: 28 AUX_CONFIG_PAGE, // Index: 29 MCL_CONFIG_PAGE, // Index: 30 - RAM_CONFIG_PAGE, // Index: 31 - ARP_PAGE, // Index: 32 - MD_IMPORT_PAGE, // Index: 33 - MIDIPORT_MENU_PAGE, // Index: 34 - MIDIPROGRAM_MENU_PAGE, // Index: 35 - MIDICLOCK_MENU_PAGE, // Index: 36 - MIDIROUTE_MENU_PAGE, // Index: 37 - MIDIMACHINEDRUM_MENU_PAGE,// Index: 38 - MIDIGENERIC_MENU_PAGE, // Index: 39 - SOUND_BROWSER, // Index: 40 - PERF_PAGE_0, // Index: 41 + ARP_PAGE, // Index: 31 + MD_IMPORT_PAGE, // Index: 32 + MIDIPORT_MENU_PAGE, // Index: 33 + MIDIPROGRAM_MENU_PAGE, // Index: 34 + MIDICLOCK_MENU_PAGE, // Index: 35 + MIDIROUTE_MENU_PAGE, // Index: 36 + MIDIMACHINEDRUM_MENU_PAGE,// Index: 37 + MIDIGENERIC_MENU_PAGE, // Index: 38 + SOUND_BROWSER, // Index: 39 + PERF_PAGE_0, // Index: 40 NULL_PAGE = 255 }; class MCL { public: - static constexpr uint8_t NUM_PAGES = 42; + static constexpr uint8_t NUM_PAGES = static_cast(PageIndex::PERF_PAGE_0) + 1; static LightPage *const pages_table[NUM_PAGES] PROGMEM; diff --git a/avr/cores/megacommand/MCL/MCLActions.cpp b/avr/cores/megacommand/MCL/MCLActions.cpp index 415a64bc9..0981a1980 100644 --- a/avr/cores/megacommand/MCL/MCLActions.cpp +++ b/avr/cores/megacommand/MCL/MCLActions.cpp @@ -30,12 +30,6 @@ void MCLActions::setup() { // DEBUG_PRINTLN(F("mcl actions setup")); mcl_actions_callbacks.setup_callbacks(); mcl_actions_midievents.setup_callbacks(); - for (uint8_t i = 0; i < NUM_SLOTS; i++) { - next_transitions[i] = 0; - transition_offsets[i] = 0; - send_machine[i] = 0; - transition_level[i] = 0; - } } void MCLActions::init_chains() { @@ -170,7 +164,7 @@ void MCLActions::save_tracks(int row, uint8_t *slot_select_array, uint8_t merge, save_dev_tracks[i] = false; continue; } - ElektronPattern *p = elektron_devs[i]->getPattern(); + ElektronPattern *p = (ElektronPattern*) elektron_devs[i]->getPattern(); if (p->isEmpty()) { save_dev_tracks[i] = false; continue; @@ -563,7 +557,6 @@ void MCLActions::send_tracks_to_devices(uint8_t *slot_select_array, midi_active_peering.get_device(UART2_PORT), }; - uint8_t mute_states[NUM_SLOTS]; uint8_t send_masks[NUM_SLOTS] = {0}; uint8_t row = 0; uint8_t old_grid = proj.get_grid(); @@ -591,9 +584,6 @@ void MCLActions::send_tracks_to_devices(uint8_t *slot_select_array, proj.select_grid(grid_idx); - mute_states[dst] = gdt_dst->seq_track->mute_state; - gdt_dst->seq_track->mute_state = SEQ_MUTE_ON; - row = grid_page.getRow(); if (row_array) { row = row_array[i]; @@ -643,7 +633,6 @@ void MCLActions::send_tracks_to_devices(uint8_t *slot_select_array, } } - // switch back to old grid before driving the GUI loop // note, do not re-enter grid_task -- stackoverflow GUI.removeTask(&grid_task); @@ -651,14 +640,7 @@ void MCLActions::send_tracks_to_devices(uint8_t *slot_select_array, // GUI.loop(); } GUI.addTask(&grid_task); - for (uint8_t i = 0; i < NUM_SLOTS; ++i) { - if (select_array[i] == 0) { continue; } - uint8_t dst = load_offset == 255 ? i : (i - first_slot) + load_offset; - GridDeviceTrack *gdt_dst = get_grid_dev_track(dst); - if (gdt_dst != nullptr) { - gdt_dst->seq_track->mute_state = mute_states[dst]; - } - } + /*All the tracks have been sent so clear the write queue*/ write_original = 0; @@ -760,7 +742,11 @@ void MCLActions::cache_next_tracks(uint8_t *slot_select_array, links[n].loops = 1; links[n].length = (float)chains[n].get_length() / (float)gdt->seq_track->get_speed_multiplier(); + while (links[n].loops * links[n].length < 8) { + links[n].loops++; + } } + //if (links[n].length == 0) { links[n].length = 16; } chains[n].inc(); links[n].row = chains[n].get_row(); if (links[n].row == 255) { @@ -915,11 +901,7 @@ void MCLActions::calc_latency() { midi_active_peering.get_device(UART2_PORT), }; - for (uint8_t a = 0; a < NUM_DEVS; a++) { - dev_latency[a].latency = 0; - dev_latency[a].div32th_latency = 0; - dev_latency[a].div192th_latency = 0; - } + memset(dev_latency,0,sizeof(dev_latency)); bool send_dev[NUM_DEVS] = {0}; diff --git a/avr/cores/megacommand/MCL/MCLActionsEvents.cpp b/avr/cores/megacommand/MCL/MCLActionsEvents.cpp index e400572f1..abb46e98f 100644 --- a/avr/cores/megacommand/MCL/MCLActionsEvents.cpp +++ b/avr/cores/megacommand/MCL/MCLActionsEvents.cpp @@ -89,6 +89,12 @@ void MCLActionsCallbacks::StopHardCallback() { bool proceed = false; for (uint8_t n = 0; n < NUM_SLOTS; n++) { + GridDeviceTrack *gdt = + mcl_actions.get_grid_dev_track(n); + + if (gdt == nullptr) + continue; + if (mcl_actions.chains[n].is_mode_queue()) { slot_select_array[n] = 1; row_array[n] = mcl_actions.chains[n].rows[0]; @@ -134,6 +140,12 @@ void MCLActionsCallbacks::onMidiStartCallback() { mcl_actions.start_clock32th = 0; mcl_actions.start_clock16th = 0; for (uint8_t n = 0; n < NUM_SLOTS; n++) { + GridDeviceTrack *gdt = + mcl_actions.get_grid_dev_track(n); + + if (gdt == nullptr) + continue; + if (grid_page.active_slots[n] != SLOT_DISABLED) { mcl_actions.next_transitions[n] = 0; mcl_actions.transition_offsets[n] = 0; diff --git a/avr/cores/megacommand/MCL/MCLEncoder.cpp b/avr/cores/megacommand/MCL/MCLEncoder.cpp index 440336829..e9808bbaa 100644 --- a/avr/cores/megacommand/MCL/MCLEncoder.cpp +++ b/avr/cores/megacommand/MCL/MCLEncoder.cpp @@ -2,8 +2,11 @@ int MCLEncoder::update(encoder_t *enc) { - int inc = update_rotations(enc); - inc = inc + (fastmode ? 4 * enc->button : enc->button); + int inc = 0; + if (enc) { + inc = update_rotations(enc); + inc = inc + (fastmode ? 4 * enc->button : enc->button); + } cur = limit_value(cur, inc, min, max); return cur; } diff --git a/avr/cores/megacommand/MCL/MCLGUI.cpp b/avr/cores/megacommand/MCL/MCLGUI.cpp index a4e7bfd47..c32c104e1 100644 --- a/avr/cores/megacommand/MCL/MCLGUI.cpp +++ b/avr/cores/megacommand/MCL/MCLGUI.cpp @@ -11,19 +11,17 @@ void MCLGUI::put_value_at(uint8_t value, char *str) { str[0] = value + '0'; str[1] = '\0'; } else if (value < 100) { - str[0] = (value % 100) / 10 + '0'; - str[1] = (value % 10) + '0'; + str[0] = value / 10 + '0'; + str[1] = value % 10 + '0'; str[2] = '\0'; - } else if (value < 1000) { - str[0] = (value % 1000) / 100 + '0'; - str[1] = (value % 100) / 10 + '0'; - str[2] = (value % 10) + '0'; + str[0] = value / 100 + '0'; + str[1] = (value / 10) % 10 + '0'; + str[2] = value % 10 + '0'; str[3] = '\0'; } } - void MCLGUI::draw_textbox(const char *text, const char *text2) { auto oldfont = oled_display.getFont(); oled_display.setFont(); diff --git a/avr/cores/megacommand/MCL/MCLMemory.h b/avr/cores/megacommand/MCL/MCLMemory.h index 847d142d0..e29b2c644 100644 --- a/avr/cores/megacommand/MCL/MCLMemory.h +++ b/avr/cores/megacommand/MCL/MCLMemory.h @@ -35,7 +35,7 @@ constexpr size_t NUM_EXT_TRACKS = 0; constexpr size_t NUM_INSTRUMENT_TRACKS = (NUM_MD_TRACKS + NUM_EXT_TRACKS); -constexpr size_t NUM_AUX_TRACKS = 4; +constexpr size_t NUM_AUX_TRACKS = 3; constexpr size_t GRIDCHAIN_TRACK_NUM = 10; constexpr size_t PERF_TRACK_NUM = 11; diff --git a/avr/cores/megacommand/MCL/MCLMenus.cpp b/avr/cores/megacommand/MCL/MCLMenus.cpp index 870fd74c4..3b2e84c22 100644 --- a/avr/cores/megacommand/MCL/MCLMenus.cpp +++ b/avr/cores/megacommand/MCL/MCLMenus.cpp @@ -102,6 +102,10 @@ const uint8_t *const menu_target_param[] PROGMEM = { &perf_page.perf_id, // 60 &mcl_cfg.uart2_cc_mute, + // 61 + &mcl_cfg.uart1_device, + // 62 + &mcl_cfg.grid_page_mode, }; const menu_function_t menu_target_functions[] PROGMEM = { @@ -171,7 +175,6 @@ MenuPage midi_config_page(&config_param1, &config_param3); MenuPage md_config_page(&config_param1, &config_param4); MenuPage chain_config_page(&config_param1, &config_param6); MenuPage mcl_config_page(&config_param1, &config_param5); -MenuPage ram_config_page(&config_param1, &config_param7); MenuPage md_import_page(&config_param1, &config_param8); MenuPage midiport_menu_page(&config_param1, &config_param9); diff --git a/avr/cores/megacommand/MCL/MCLMenus.h b/avr/cores/megacommand/MCL/MCLMenus.h index 5c62ae2df..3f314c4eb 100644 --- a/avr/cores/megacommand/MCL/MCLMenus.h +++ b/avr/cores/megacommand/MCL/MCLMenus.h @@ -55,16 +55,13 @@ extern MenuPage mcl_config_page; constexpr size_t chain_config_page_N = 3; extern MenuPage chain_config_page; -constexpr size_t aux_config_page_N = 1; +constexpr size_t aux_config_page_N = 2; extern MenuPage aux_config_page; -constexpr size_t ram_config_page_N = 1; -extern MenuPage ram_config_page; - constexpr size_t md_import_page_N = 4; extern MenuPage md_import_page; -constexpr size_t midiport_menu_page_N = 5; +constexpr size_t midiport_menu_page_N = 6; extern MenuPage midiport_menu_page; constexpr size_t midiprogram_menu_page_N = 3; diff --git a/avr/cores/megacommand/MCL/MCLSeq.cpp b/avr/cores/megacommand/MCL/MCLSeq.cpp index 723429206..31febba64 100644 --- a/avr/cores/megacommand/MCL/MCLSeq.cpp +++ b/avr/cores/megacommand/MCL/MCLSeq.cpp @@ -39,6 +39,9 @@ void MCLSeq::setup() { mdfx_track.length = 16; mdfx_track.speed = SEQ_SPEED_1X; + perf_track.length = 16; + perf_track.speed = SEQ_SPEED_1X; + enable(); MidiClock.addOnMidiStopCallback( @@ -108,7 +111,7 @@ void MCLSeq::onMidiStartImmediateCallback() { aux_tracks[i].reset(); } mdfx_track.reset(); - + perf_track.reset(); #ifdef LFO_TRACKS for (uint8_t i = 0; i < num_lfo_tracks; i++) { lfo_tracks[i].sample_hold = 0; @@ -148,6 +151,7 @@ void MCLSeq::onMidiStopCallback() { for (uint8_t i = 0; i < num_md_tracks; i++) { md_tracks[i].reset_params(); + md_tracks[i].send_notes_off(); md_tracks[i].locks_slides_recalc = 255; for (uint8_t c = 0; c < NUM_LOCKS; c++) { md_tracks[i].locks_slide_data[c].init(); @@ -231,13 +235,9 @@ void MCLSeq::seq() { MDSeqTrack::md_trig_mask = 0; MDSeqTrack::load_machine_cache = 0; for (uint8_t i = 0; i < num_md_tracks; i++) { - md_tracks[i].seq(uart); + md_tracks[i].seq(uart,uart2); md_arp_tracks[i].mute_state = md_tracks[i].mute_state; - md_arp_tracks[i].seq(uart); - } - - if (MDSeqTrack::md_trig_mask > 0) { - MD.parallelTrig(MDSeqTrack::md_trig_mask, uart); + md_arp_tracks[i].seq(uart,uart2); } mdfx_track.seq(); @@ -250,7 +250,6 @@ void MCLSeq::seq() { for (uint8_t i = 0; i < NUM_AUX_TRACKS; i++) { aux_tracks[i].seq(); } - // Arp #ifdef LFO_TRACKS for (uint8_t i = 0; i < num_lfo_tracks; i++) { @@ -258,11 +257,17 @@ void MCLSeq::seq() { } #endif + perf_track.seq(uart, uart2); + + if (MDSeqTrack::md_trig_mask > 0) { + MD.parallelTrig(MDSeqTrack::md_trig_mask, uart); + } + #ifdef EXT_TRACKS for (uint8_t i = 0; i < num_ext_tracks; i++) { ext_tracks[i].seq(uart2); ext_arp_tracks[i].mute_state = ext_tracks[i].mute_state; - ext_arp_tracks[i].seq(uart2); + ext_arp_tracks[i].seq(uart,uart2); } #endif @@ -281,12 +286,25 @@ void MCLSeq::seq() { } } -void MCLSeqMidiEvents::onNoteOnCallback_Midi(uint8_t *msg) { - mixer_page.onNoteOnCallback_Midi(msg); -} +void MCLSeqMidiEvents::onNoteCallback_Midi(uint8_t *msg) { + uint8_t note_num = msg[1]; + uint8_t channel = MIDI_VOICE_CHANNEL(msg[0]); + uint8_t n = MD.noteToTrack(msg[1]); + if (n < 16) { + bool is_midi_machine = ((MD.kit.models[n] & 0xF0) == MID_01_MODEL); + if (is_midi_machine) { + if (msg[2]) {mcl_seq.md_tracks[n].send_notes(255); } + //velocity 0 == NoteOff + //Only send note off if the sequener is not running, otherwise defer to note length + else if (MidiClock.state != 2) { mcl_seq.md_tracks[n].send_notes_off(); } -void MCLSeqMidiEvents::onNoteOffCallback_Midi(uint8_t *msg) {} + } + if (msg[0] != 153 && msg[2]) { + mixer_page.disp_levels[n] = MD.kit.levels[n]; + } + } +} void MCLSeqMidiEvents::onControlChangeCallback_Midi(uint8_t *msg) { uint8_t channel = MIDI_VOICE_CHANNEL(msg[0]); uint8_t param = msg[1]; @@ -299,6 +317,8 @@ void MCLSeqMidiEvents::onControlChangeCallback_Midi(uint8_t *msg) { return; } + mcl_seq.md_tracks[track].onControlChangeCallback_Midi(track_param, value); + if (mcl.currentPage() == MIXER_PAGE) { mixer_page.onControlChangeCallback_Midi(track, track_param, value); } @@ -365,11 +385,10 @@ void MCLSeqMidiEvents::setup_callbacks() { } Midi.addOnNoteOnCallback( - this, (midi_callback_ptr_t)&MCLSeqMidiEvents::onNoteOnCallback_Midi); - /* - Midi.addOnNoteOffCallback( - this, (midi_callback_ptr_t)&MCLSeqMidiEvents::onNoteOffCallback_Midi); - */ + this, (midi_callback_ptr_t)&MCLSeqMidiEvents::onNoteCallback_Midi); + Midi.addOnNoteOffCallback( + this, (midi_callback_ptr_t)&MCLSeqMidiEvents::onNoteCallback_Midi); + update_params = true; Midi.addOnControlChangeCallback( this, @@ -389,11 +408,9 @@ void MCLSeqMidiEvents::remove_callbacks() { } Midi.removeOnNoteOnCallback( - this, (midi_callback_ptr_t)&MCLSeqMidiEvents::onNoteOnCallback_Midi); - /* + this, (midi_callback_ptr_t)&MCLSeqMidiEvents::onNoteCallback_Midi); Midi.removeOnNoteOffCallback( - this, (midi_callback_ptr_t)&MCLSeqMidiEvents::onNoteOffCallback_Midi); - */ + this, (midi_callback_ptr_t)&MCLSeqMidiEvents::onNoteCallback_Midi); Midi.removeOnControlChangeCallback( this, (midi_callback_ptr_t)&MCLSeqMidiEvents::onControlChangeCallback_Midi); diff --git a/avr/cores/megacommand/MCL/MCLSeq.h b/avr/cores/megacommand/MCL/MCLSeq.h index 869441711..f09ba8538 100644 --- a/avr/cores/megacommand/MCL/MCLSeq.h +++ b/avr/cores/megacommand/MCL/MCLSeq.h @@ -11,6 +11,7 @@ #include "ArpSeqTrack.h" #include "ExtSeqTrack.h" #include "MDFXseqTrack.h" +#include "PerfSeqTrack.h" #define SEQ_MUTE_ON 1 #define SEQ_MUTE_OFF 0 @@ -33,7 +34,8 @@ class MCLSeqMidiEvents : public MidiCallback { void remove_callbacks(); uint8_t note_to_trig(uint8_t); - void onNoteOnCallback_Midi(uint8_t *msg); + void onNoteCallback_Midi(uint8_t *msg); + void onNoteOffCallback_Midi(uint8_t *msg); void onControlChangeCallback_Midi(uint8_t *msg); void onControlChangeCallback_Midi2(uint8_t *msg); @@ -62,6 +64,7 @@ class MCLSeq : public ClockCallback { SeqTrackBase aux_tracks[NUM_AUX_TRACKS]; + PerfSeqTrack perf_track; MDFXSeqTrack mdfx_track; MCLSeqMidiEvents midi_events; diff --git a/avr/cores/megacommand/MCL/MCLSysConfig.cpp b/avr/cores/megacommand/MCL/MCLSysConfig.cpp index bb03de681..c3cc3fca3 100644 --- a/avr/cores/megacommand/MCL/MCLSysConfig.cpp +++ b/avr/cores/megacommand/MCL/MCLSysConfig.cpp @@ -1,59 +1,56 @@ #include "MCL_impl.h" - -void usb_wait() { +// Consolidated display function to reduce code duplication +static void show_message(const char* line1) { oled_display.clearDisplay(); - oled_display.textbox("PLEASE WAIT", ""); + oled_display.textbox(line1, ""); oled_display.display(); +} + +// Common wait routine +static inline void usb_wait() { + show_message("PLEASE WAIT"); delay(4000); } -bool megacmd_check() { +// Simplified megacmd check +static inline bool megacmd_check() { if (!IS_MEGACMD()) { - oled_display.textbox("MODE ", "N/A"); - oled_display.display(); + show_message("MODE N/A"); return false; } return true; } -void usb_os_update() { +// Combined USB mode change function +static void enter_usb_mode(uint8_t mode, const char* line1) { usb_wait(); - change_usb_mode(USB_SERIAL); - oled_display.clearDisplay(); - oled_display.textbox("OS UPDATE", ""); - oled_display.display(); - while (1) - ; + show_message(line1); + + if (mode == USB_STORAGE) { + LOCAL_SPI_DISABLE(); + EXTERNAL_SPI_ENABLE(); + } + + change_usb_mode(mode); + while (1); // Infinite loop +} + +// Optimized public functions +void usb_os_update() { + enter_usb_mode(USB_SERIAL, "OS UPDATE"); } void usb_dfu_mode() { - usb_wait(); - oled_display.clearDisplay(); - oled_display.textbox("DFU ", "MODE"); - oled_display.display(); - //DFU mode is activated via datalines between CPUs - SET_USB_MODE(USB_DFU); - while (1) - ; + enter_usb_mode(USB_DFU, "DFU MODE"); } void usb_disk_mode() { - if (!megacmd_check()) { - return; + if (megacmd_check()) { + enter_usb_mode(USB_STORAGE, "USB DISK"); } - usb_wait(); - oled_display.clearDisplay(); - - oled_display.textbox("USB ", "DISK"); - oled_display.display(); - - LOCAL_SPI_DISABLE(); - EXTERNAL_SPI_ENABLE(); - change_usb_mode(USB_STORAGE); - while (1) - ; } + void mclsys_apply_config() { DEBUG_PRINT_FN(); GUI.display_mirror = mcl_cfg.display_mirror; @@ -144,6 +141,7 @@ bool MCLSysConfig::cfg_init() { //ram_page_mode = 0; track_select = 1; track_type_select = 0b00000011; + uart1_device = 1; //uart2_device = 0; //uart_cc_loopback = 0; //uart2_prg_mode = 0; @@ -155,6 +153,7 @@ bool MCLSysConfig::cfg_init() { //seq_dev = 0; uart2_cc_mute = 128; uart2_cc_level = 128; + //grid_page_mode = 0; cfgfile.close(); ret = write_cfg(); if (!ret) { diff --git a/avr/cores/megacommand/MCL/MCLSysConfig.h b/avr/cores/megacommand/MCL/MCLSysConfig.h index 65ab7e1a0..157acc9da 100644 --- a/avr/cores/megacommand/MCL/MCLSysConfig.h +++ b/avr/cores/megacommand/MCL/MCLSysConfig.h @@ -4,7 +4,7 @@ #define MCLSYSCONFIG_H__ #include "SdFat.h" -#define CONFIG_VERSION 4010 +#define CONFIG_VERSION 4011 #define MIDI_OMNI_MODE 17 #define MIDI_LOCAL_MODE 0 @@ -67,6 +67,8 @@ class MCLSysConfigData { uint8_t seq_dev; uint8_t uart2_cc_mute; uint8_t uart2_cc_level; + uint8_t uart1_device; + uint8_t grid_page_mode; }; class MCLSysConfig : public MCLSysConfigData { diff --git a/avr/cores/megacommand/MCL/MCL_impl.h b/avr/cores/megacommand/MCL/MCL_impl.h index c8182f87e..024c28f5c 100644 --- a/avr/cores/megacommand/MCL/MCL_impl.h +++ b/avr/cores/megacommand/MCL/MCL_impl.h @@ -82,6 +82,7 @@ #include "ArpSeqTrack.h" #include "EmptyTrack.h" #include "LFOSeqTrack.h" +#include "PerfSeqTrack.h" #include "MNMTrack.h" #include "MCLActions.h" diff --git a/avr/cores/megacommand/MCL/MDFXTrack.cpp b/avr/cores/megacommand/MCL/MDFXTrack.cpp index a2fed0350..691aba0a3 100644 --- a/avr/cores/megacommand/MCL/MDFXTrack.cpp +++ b/avr/cores/megacommand/MCL/MDFXTrack.cpp @@ -60,6 +60,7 @@ void MDFXTrack::load_immediate_cleared(uint8_t tracknumber, SeqTrack *seq_track) void MDFXTrack::place_fx_in_kit() { DEBUG_PRINTLN("place"); memcpy(MD.kit.reverb, reverb, sizeof(reverb) * 4); + memcpy(MD.kit.fx_orig, reverb, sizeof(reverb) * 4); /* if (enable_reverb) { memcpy(&MD.kit.reverb, &reverb, sizeof(reverb)); diff --git a/avr/cores/megacommand/MCL/MDRouteTrack.cpp b/avr/cores/megacommand/MCL/MDRouteTrack.cpp index 6797a46a7..7878c012c 100644 --- a/avr/cores/megacommand/MCL/MDRouteTrack.cpp +++ b/avr/cores/megacommand/MCL/MDRouteTrack.cpp @@ -5,9 +5,11 @@ void MDRouteTrack::transition_send(uint8_t tracknumber, uint8_t slotnumber) { void MDRouteTrack::transition_load(uint8_t tracknumber, SeqTrack *seq_track, uint8_t slotnumber) { GridTrack::transition_load(tracknumber, seq_track, slotnumber); - load_routes(); - //Send routes regardless - send_routes(); + if (mcl_actions.send_machine[slotnumber]) { + load_routes(); + //Send routes regardless + send_routes(); + } } uint16_t MDRouteTrack::calc_latency(uint8_t tracknumber) { diff --git a/avr/cores/megacommand/MCL/MDRouteTrack.h b/avr/cores/megacommand/MCL/MDRouteTrack.h index 08f08fd60..089489aef 100644 --- a/avr/cores/megacommand/MCL/MDRouteTrack.h +++ b/avr/cores/megacommand/MCL/MDRouteTrack.h @@ -42,5 +42,5 @@ class MDRouteTrack : public AUXTrack, public RouteData { virtual uint8_t get_device_type() { return MDROUTE_TRACK_TYPE; } virtual void *get_sound_data_ptr() { return &routing; } - virtual size_t get_sound_data_size() { return sizeof(routing); } + virtual size_t get_sound_data_size() { return sizeof(RouteData); } }; diff --git a/avr/cores/megacommand/MCL/MDSeqTrack.cpp b/avr/cores/megacommand/MCL/MDSeqTrack.cpp index fe8348c1d..b9d243bd5 100644 --- a/avr/cores/megacommand/MCL/MDSeqTrack.cpp +++ b/avr/cores/megacommand/MCL/MDSeqTrack.cpp @@ -34,20 +34,25 @@ void MDSeqTrack::set_length(uint8_t len, bool expand) { return; } } - MDSeqStep empty_step; - memset(&empty_step, 0, sizeof(empty_step)); - uint8_t a = 0; - for (uint8_t n = old_length; n < 64; n++) { - copy_step(a++, &empty_step); - paste_step(n, &empty_step); - if (a == old_length) { a = 0; } + MDSeqStep empty_step; + memset(&empty_step, 0, sizeof(empty_step)); + uint8_t a = 0; + for (uint8_t n = old_length; n < 64; n++) { + copy_step(a++, &empty_step); + paste_step(n, &empty_step); + if (a == old_length) { + a = 0; } + } } } void MDSeqTrack::store_mute_state() { for (uint8_t n = 0; n < NUM_MD_STEPS; n++) { - if (IS_BIT_SET64(mute_mask, n)) { set_step(n,MASK_PATTERN, 0); set_step(n,MASK_LOCK, 0); } + if (IS_BIT_SET64(mute_mask, n)) { + set_step(n, MASK_PATTERN, 0); + set_step(n, MASK_LOCK, 0); + } } clear_mutes(); } @@ -79,28 +84,31 @@ void MDSeqTrack::re_sync() { } void MDSeqTrack::load_cache() { -/* MDTrackChunk t; - DEBUG_PRINTLN("lc"); - for (uint8_t n = 0; n < t.get_chunk_count(); n++) { - t.load_from_mem_chunk(track_number, n); - t.load_chunk(data(), n); - }*/ + /* MDTrackChunk t; + DEBUG_PRINTLN("lc"); + for (uint8_t n = 0; n < t.get_chunk_count(); n++) { + t.load_from_mem_chunk(track_number, n); + t.load_chunk(data(), n); + }*/ MDTrack t; t.load_from_mem(track_number, MD_TRACK_TYPE); t.load_seq_data((SeqTrack *)this); if (load_sound) { - MD.insertMachineInKit(track_number, &(t.machine),false); + MD.insertMachineInKit(track_number, &(t.machine), false); SET_BIT32(load_machine_cache, track_number); load_sound = 0; } } -void MDSeqTrack::seq(MidiUartParent *uart_) { +void MDSeqTrack::seq(MidiUartParent *uart_, MidiUartParent *uart2_) { MidiUartParent *uart_old = uart; + MidiUartParent *uart2_old = uart2; + uart = uart_; + uart2 = uart2_; - uint8_t timing_mid = get_timing_mid_inline(); + uint8_t timing_mid = get_timing_mid(); mod12_counter++; @@ -117,9 +125,8 @@ void MDSeqTrack::seq(MidiUartParent *uart_) { if (count_down == 0) { reset(); mod12_counter = 0; - SET_BIT16(gui_update,track_number); - } - else if (count_down <= track_number / 4 + 1) { + SET_BIT16(gui_update, track_number); + } else if (count_down <= track_number / 4 + 1) { if (!cache_loaded) { load_cache(); cache_loaded = true; @@ -128,6 +135,13 @@ void MDSeqTrack::seq(MidiUartParent *uart_) { } } + if (notes.count_down) { + notes.count_down--; + if (notes.count_down == 0) { + send_notes_off(); + } + } + if (record_mutes) { uint8_t u = 0; uint8_t q = 0; @@ -135,8 +149,7 @@ void MDSeqTrack::seq(MidiUartParent *uart_) { SET_BIT64(mute_mask, s); } - if ((mute_state == SEQ_MUTE_OFF) && - (ignore_step != step_count)) { + if ((mute_state == SEQ_MUTE_OFF) && (ignore_step != step_count)) { uint8_t next_step = 0; if (step_count == (length - 1)) { @@ -161,16 +174,26 @@ void MDSeqTrack::seq(MidiUartParent *uart_) { lock_idx += popcount(steps[step_count].locks); } } - auto &step = steps[current_step]; uint8_t send_trig = trig_conditional(step.cond_id); - if (send_trig == TRIG_TRUE || (!step.cond_plock && send_trig != TRIG_ONESHOT)) { + bool is_midi_model = + ((MD.kit.models[track_number] & 0xF0) == MID_01_MODEL); + if (send_trig == TRIG_TRUE || + (!step.cond_plock && send_trig != TRIG_ONESHOT)) { + if (is_midi_model && send_trig == TRIG_TRUE && step.trig) { + send_notes_off(); + init_notes(); + } send_parameter_locks_inline(current_step, step.trig, lock_idx); if (step.slide) { locks_slides_recalc = current_step; locks_slides_idx = lock_idx; } if (send_trig == TRIG_TRUE && step.trig) { + if (is_midi_model) { + notes.count_down = notes.len == 0 ? timing_mid / 4 : (notes.len * timing_mid / 2); + send_notes_on(); + } send_trig_inline(); } } @@ -178,6 +201,7 @@ void MDSeqTrack::seq(MidiUartParent *uart_) { } end: uart = uart_old; + uart2 = uart2_old; } bool MDSeqTrack::is_param(uint8_t param_id) { @@ -199,7 +223,7 @@ void MDSeqTrack::recalc_slides() { int16_t x0, x1; int8_t y0, y1; uint8_t step = locks_slides_recalc; - uint8_t timing_mid = get_timing_mid_inline(); + uint8_t timing_mid = get_timing_mid(); uint8_t find_mask = 0; uint8_t cur_mask = 1; @@ -211,7 +235,9 @@ void MDSeqTrack::recalc_slides() { } auto lockidx = locks_slides_idx; - if (find_mask == 0) { goto end; } + if (find_mask == 0) { + goto end; + } find_next_locks(lockidx, step, find_mask); for (uint8_t c = 0; c < NUM_LOCKS; c++) { @@ -240,7 +266,7 @@ void MDSeqTrack::recalc_slides() { y1 = locks_slide_next_lock_val[c]; prepare_slide(c, x0, x1, y0, y1); } - end: +end: locks_slides_recalc = 255; } @@ -265,7 +291,8 @@ void MDSeqTrack::find_next_locks(uint8_t curidx, uint8_t step, uint8_t mask) { mask &= ~cur_mask; // all targets hit? } else if (steps[next_step].trig) { - locks_slide_next_lock_val[i] = MD.kit.params[track_number][locks_params[i] - 1]; + locks_slide_next_lock_val[i] = + MD.kit.params[track_number][locks_params[i] - 1]; locks_slide_next_lock_step[i] = next_step; mask &= ~cur_mask; } @@ -371,40 +398,154 @@ void MDSeqTrack::send_parameter_locks(uint8_t step, bool trig, send_parameter_locks_inline(step, trig, idx); } +void MDSeqTrack::send_notes_ccs(uint8_t *ccs, bool send_ccs) { + uint8_t channel = MD.kit.models[track_number] - MID_01_MODEL; + if (send_ccs) { + for (uint8_t n = 0; n < number_midi_cc; n++) { + if (ccs[n] == 255) continue; + switch (n) { + case 1: + uart2->sendPitchBend(channel, ccs[1] << 7); + break; + case 2: + uart2->sendCC(channel, 0x1, ccs[2]); + break; + case 3: + uart2->sendChannelPressure(channel, ccs[3]); + break; + case 0: + notes.prog = ccs[0]; + uart2->sendProgramChange(channel, ccs[0]); + break; + default: + if (!(n & 1)) continue; + uint8_t a = ccs[n - 1]; + if (a > 0 && a != 255) { + uint8_t v = ccs[n]; + // 0 = off + // 1 = bank (0) + // 2 = 2 + if (a == 1) { + a = 0; + }; + uart2->sendCC(channel, a, v); + break; + } + } + } + } +} + +void MDSeqTrack::process_note_locks(uint8_t param, uint8_t val, uint8_t *ccs, + bool is_lock) { + uint8_t channel = MD.kit.models[track_number] - MID_01_MODEL; + + uint8_t i = param - 5; + switch (param) { + case 0: + case 1: + case 2: + case 3: + case 4: + //note values are set via init_notes initially. + ((uint8_t *)¬es)[param] = val; + //ccs[param] = val; not required. + break; + case 5: + case 6: + case 7: + ccs[i + 1] = val; + break; + case 20: + if (notes.prog != val || is_lock) { + ccs[0] = val; + } + else { + ccs[0] = 255; + } + break; + default: + i = param - 8 + 4; + if (param < 20) { + // If the parameter is CC value and the CC dest is not yet set, use the + // kit value for CC dest + uint8_t j = i - 1; + if ((param & 1) && ccs[j] == 255) { + ccs[j] = MD.kit.params[track_number][param - 1]; + } + ccs[i] = val; + } + break; + } +} + void MDSeqTrack::send_parameter_locks_inline(uint8_t step, bool trig, uint16_t lock_idx) { + + uint8_t ccs[midi_cc_array_size]; + bool send_ccs = false; + bool is_midi_model = (MD.kit.models[track_number] & 0xF0) == MID_01_MODEL; + + if (is_midi_model) { + if (notes.first_trig) { + // first note, we want to send all CCs regardless if they dont have locks. + memcpy(ccs + 1, &MD.kit.params[track_number][5], sizeof(ccs) - 1); + //prevent re-transmission of program change. + //process_note_locks(20, MD.kit.params[track_number][20],ccs); + send_ccs = true; + notes.first_trig = false; + } else { + memset(ccs, 255, sizeof(ccs)); + } + } for (uint8_t c = 0; c < NUM_LOCKS; c++) { bool lock_bit = steps[step].is_lock_bit(c); bool lock_present = steps[step].is_lock(c); bool send = false; - uint8_t send_param; + uint8_t val; uint8_t p = locks_params[c] - 1; if (locks_params[c]) { if (lock_present) { - send_param = locks[lock_idx]; + val = locks[lock_idx]; send = true; } else if (trig) { - send_param = MD.kit.params[track_number][p]; + val = MD.kit.params[track_number][p]; send = true; } } lock_idx += lock_bit; if (send) { - bool update_kit = false; - MD.setTrackParam_inline(track_number, p, send_param, uart, update_kit); + if (is_midi_model && p < 21) { + process_note_locks(p, val, ccs, true); + send_ccs |= (p > 4 && p < 8) | (p > 8) && (p & 1) | (p == 20); + } + + else { + bool update_kit = false; + MD.setTrackParam_inline(track_number, p, val, uart, update_kit); + } } } + if (is_midi_model) { + send_notes_ccs(ccs, send_ccs); + } } void MDSeqTrack::reset_params() { bool re_assign = false; - for (uint8_t c = 0; c < NUM_LOCKS; c++) { - if (locks_params[c] > 0) { - MDTrack md_track; - md_track.get_machine_from_kit(track_number); - MD.assignMachineBulk(track_number, &md_track.machine, 255, 1, true); - return; - } + bool is_midi_model = ((MD.kit.models[track_number] & 0xF0) == MID_01_MODEL); + if (is_midi_model) { + uint8_t ccs[midi_cc_array_size]; + bool send_ccs = true; + memcpy(ccs + 1, &MD.kit.params[track_number][5], sizeof(ccs) - 1); + ccs[0] = 255; //disable program change + //notes.prog = MD.kit.params[track_number][20]; + //process_note_locks(20, MD.kit.params[track_number][20],ccs); + send_notes_ccs(ccs, send_ccs); + } else { + MDTrack md_track; + md_track.get_machine_from_kit(track_number); + MD.assignMachineBulk(track_number, &md_track.machine, 255, 1, true); } /* @@ -438,18 +579,88 @@ void MDSeqTrack::get_step_locks(uint8_t step, uint8_t *params, } } +void MDSeqTrack::send_notes(uint8_t note1, MidiUartParent *uart2_) { + if (!uart2_) { uart2_ = uart2; } + if (notes.count_down) { + send_notes_off(uart2_); + } + init_notes(); + if (note1 != 255) { notes.note1 = note1; } + if (notes.first_trig) { reset_params(); notes.first_trig = false; } + uint8_t timing_mid = get_timing_mid(); + notes.count_down = notes.len == 0 ? timing_mid / 4 : (notes.len * timing_mid / 2); + send_notes_on(uart2_); +} + +void MDSeqTrack::send_notes_on(MidiUartParent *uart2_) { + if (!uart2_) { uart2_ = uart2; } + TrigNotes *n = ¬es; + uint8_t channel = MD.kit.models[track_number] - MID_01_MODEL; + + if (n->note1 != 255) { + mixer_page.trig(track_number); + uart2_->sendNoteOn(channel, n->note1, n->vel); + if (n->note2 != 64) { + uart2_->sendNoteOn(channel, n->note1 + n->note2 - 64, n->vel); + } + if (n->note3 != 64) { + uart2_->sendNoteOn(channel, n->note1 + n->note3 - 64, n->vel); + } + } +} + +void MDSeqTrack::send_notes_off(MidiUartParent *uart2_) { + if (!uart2_) { uart2_ = uart2; } + TrigNotes *n = ¬es; + uint8_t channel = MD.kit.models[track_number] - MID_01_MODEL; + + if (n->note1 != 255) { + uart2_->sendNoteOff(channel, n->note1); + if (n->note2 != 64) { + uart2_->sendNoteOff(channel, n->note1 + n->note2 - 64); + } + if (n->note3 != 64) { + uart2_->sendNoteOff(channel, n->note1 + n->note3 - 64); + } + n->note1 = 255; + } + n->count_down = 0; +} + +void MDSeqTrack::onControlChangeCallback_Midi(uint8_t track_param, + uint8_t value) { + bool is_midi_model = ((MD.kit.models[track_number] & 0xF0) == MID_01_MODEL); + if (!is_midi_model || MD.encoder_interface) { + return; + } + uint8_t ccs[midi_cc_array_size]; + // memset(ccs, 0, sizeof(ccs)); + // Ignore notes, len and vel (those will be obtained from kit upon init_notes + if (track_param > 4 && track_param < 21) { + if (!(track_param & 1) && track_param > 7 && track_param < 20) { + return; + } // ignore cc destination + // memcpy(ccs, &MD.kit.params[track_number][8], sizeof(ccs)); + memset(ccs, 255, sizeof(ccs)); + process_note_locks(track_param, value, ccs); + send_notes_ccs(ccs, true); + } +} + void MDSeqTrack::send_trig() { send_trig_inline(); } void MDSeqTrack::send_trig_inline() { mixer_page.trig(track_number); - // MD.triggerTrack(track_number, 127, uart); + // MD.triggerTrack(track_number, 127, uart); + // Parallel trig: SET_BIT16(MDSeqTrack::md_trig_mask, track_number); } uint8_t MDSeqTrack::trig_conditional(uint8_t condition) { bool send_trig = TRIG_FALSE; - if (IS_BIT_SET64(oneshot_mask, step_count) || IS_BIT_SET64(mute_mask, step_count)) { + if (IS_BIT_SET64(oneshot_mask, step_count) || + IS_BIT_SET64(mute_mask, step_count)) { return TRIG_ONESHOT; } if (condition == 14) { @@ -457,11 +668,10 @@ uint8_t MDSeqTrack::trig_conditional(uint8_t condition) { SET_BIT64(oneshot_mask, step_count); send_trig = TRIG_TRUE; } - } - else { + } else { send_trig = SeqTrack::conditional(condition); } - return send_trig; + return send_trig; } uint8_t MDSeqTrack::get_track_lock_implicit(uint8_t step, uint8_t param) { @@ -665,10 +875,10 @@ void MDSeqTrack::clear_param_locks(uint8_t param_id) { } } - MD.setTrackParam(track_number, param_id, MD.kit.params[track_number][locks_params[match] - 1]); + MD.setTrackParam(track_number, param_id, + MD.kit.params[track_number][locks_params[match] - 1]); } - void MDSeqTrack::clear_step_locks(uint8_t step) { uint8_t idx = get_lockidx(step); uint8_t cnt = popcount(steps[step].locks); @@ -680,7 +890,6 @@ void MDSeqTrack::clear_step_locks(uint8_t step) { } steps[step].locks = 0; steps[step].locks_enabled = false; - } void MDSeqTrack::disable_step_locks(uint8_t step) { @@ -695,9 +904,7 @@ uint8_t MDSeqTrack::get_step_locks(uint8_t step) { return steps[step].locks_enabled ? steps[step].locks : 0; } -void MDSeqTrack::clear_mute() { - mute_mask = 0; -} +void MDSeqTrack::clear_mute() { mute_mask = 0; } void MDSeqTrack::clear_mutes() { oneshot_mask = 0; @@ -724,6 +931,7 @@ void MDSeqTrack::clear_locks() { memset(locks, 0, sizeof(locks)); cur_event_idx = 0; + notes.first_trig = true; } void MDSeqTrack::clear_track(bool locks) { @@ -733,6 +941,7 @@ void MDSeqTrack::clear_track(bool locks) { clear_locks(); } memset(steps, 0, sizeof(steps)); + notes.first_trig = true; } void MDSeqTrack::merge_from_md(uint8_t track_number, MDPattern *pattern) { @@ -836,15 +1045,15 @@ void MDSeqTrack::modify_track(uint8_t dir) { memmove(timing + 1, timing, length - 1); steps[0] = step_buf; timing[0] = timing_buf; - ROTATE_RIGHT(mute_mask,length); + ROTATE_RIGHT(mute_mask, length); break; } case DIR_REVERSE: { uint8_t rev_locks[NUM_MD_LOCK_SLOTS]; memcpy(rev_locks, locks, sizeof(locks)); uint16_t l = 0, r = 0; - //mute_mask = 0; //unimplemented - // reverse steps & locks + // mute_mask = 0; //unimplemented + // reverse steps & locks for (uint8_t i = 0; i <= length / 2; ++i) { int j = length - i - 1; if (j < i) { @@ -864,10 +1073,16 @@ void MDSeqTrack::modify_track(uint8_t dir) { timing[j] = timing_buf; bool a = IS_BIT_SET64(mute_mask, i); bool b = IS_BIT_SET64(mute_mask, j); - if (a) { SET_BIT64(mute_mask, j); } - else { CLEAR_BIT64(mute_mask,j); } - if (b) { SET_BIT64(mute_mask, i); } - else { CLEAR_BIT64(mute_mask,i); } + if (a) { + SET_BIT64(mute_mask, j); + } else { + CLEAR_BIT64(mute_mask, j); + } + if (b) { + SET_BIT64(mute_mask, i); + } else { + CLEAR_BIT64(mute_mask, i); + } } break; } diff --git a/avr/cores/megacommand/MCL/MDSeqTrack.h b/avr/cores/megacommand/MCL/MDSeqTrack.h index c9ce470f1..94a53e83c 100644 --- a/avr/cores/megacommand/MCL/MDSeqTrack.h +++ b/avr/cores/megacommand/MCL/MDSeqTrack.h @@ -3,10 +3,10 @@ #ifndef MDSEQTRACK_H__ #define MDSEQTRACK_H__ +#include "DeviceTrack.h" #include "MD.h" -#include "SeqTrack.h" #include "MDSeqTrackData.h" -#include "DeviceTrack.h" +#include "SeqTrack.h" #define UART1_PORT 1 @@ -16,10 +16,22 @@ class MDTrack; +class TrigNotes { +public: + uint8_t note1; + uint8_t note2; + uint8_t note3; + uint8_t len; + uint8_t vel; + uint8_t prog = 255; + + uint16_t count_down; + bool first_trig = false; +}; + class MDSeqTrack : public MDSeqTrackData, public SeqSlideTrack { public: - uint64_t oneshot_mask; uint64_t mute_mask; @@ -27,11 +39,17 @@ class MDSeqTrack : public MDSeqTrackData, public SeqSlideTrack { static uint16_t md_trig_mask; static uint32_t load_machine_cache; + TrigNotes notes; + + const uint8_t number_midi_cc = 6 * 2 + 4; + const uint8_t midi_cc_array_size = 6 * 2 + 4; + MDSeqTrack() : SeqSlideTrack() { active = MD_TRACK_TYPE; } ALWAYS_INLINE() void reset() { SeqSlideTrack::reset(); oneshot_mask = 0; record_mutes = false; + send_notes_off(); } void get_mask(uint64_t *_pmask, uint8_t mask_type) const; @@ -39,7 +57,7 @@ class MDSeqTrack : public MDSeqTrackData, public SeqSlideTrack { bool get_step(uint8_t step, uint8_t mask_type) const; void set_step(uint8_t step, uint8_t mask_type, bool val); - void seq(MidiUartParent *uart_); + void seq(MidiUartParent *uart_, MidiUartParent *uart2_); void mute() { mute_state = SEQ_MUTE_ON; } void unmute() { mute_state = SEQ_MUTE_OFF; } @@ -47,20 +65,24 @@ class MDSeqTrack : public MDSeqTrackData, public SeqSlideTrack { void send_trig(); void send_trig_inline(); uint8_t trig_conditional(uint8_t condition); - void send_parameter_locks(uint8_t step, bool trig, uint16_t lock_idx = 0xFFFF); + void send_parameter_locks(uint8_t step, bool trig, + uint16_t lock_idx = 0xFFFF); void send_parameter_locks_inline(uint8_t step, bool trig, uint16_t lock_idx); void reset_params(); - void get_step_locks(uint8_t step, uint8_t *params, bool ignore_locks_disabled = false); + void get_step_locks(uint8_t step, uint8_t *params, + bool ignore_locks_disabled = false); void recalc_slides(); void find_next_locks(uint8_t curidx, uint8_t step, uint8_t mask); void set_track_pitch(uint8_t step, uint8_t pitch); - void set_track_step(uint8_t step, uint8_t utiming, uint8_t velocity = 127); + void set_track_step(uint8_t step, uint8_t utiming, + uint8_t velocity = 127); // !! Note lockidx is lock index, not param id bool set_track_locks_i(uint8_t step, uint8_t lockidx, uint8_t velocity); // !! Note track_param is param_id, not lock index - bool set_track_locks(uint8_t step, uint8_t track_param, uint8_t velocity); + bool set_track_locks(uint8_t step, uint8_t track_param, + uint8_t velocity); // !! Note lockidx is lock index, not param_id uint8_t get_track_lock(uint8_t step, uint8_t lockidx); @@ -96,13 +118,27 @@ class MDSeqTrack : public MDSeqTrackData, public SeqSlideTrack { void modify_track(uint8_t dir); - void set_speed(uint8_t new_speed, uint8_t old_speed = 255, bool timing_adjust = true); + void set_speed(uint8_t new_speed, uint8_t old_speed = 255, + bool timing_adjust = true); void store_mute_state(); void copy_step(uint8_t n, MDSeqStep *step); void paste_step(uint8_t n, MDSeqStep *step); void load_cache(); + + void init_notes() { + // Copy 3 notes, len and vel from kit to notes structure; + memcpy(¬es.note1, MD.kit.params[track_number], 5); + notes.count_down = 0; + } + void process_note_locks(uint8_t param, uint8_t val, uint8_t *ccs, bool is_lock = false); + void send_notes_ccs(uint8_t *ccs, bool send_ccs); + void send_notes(uint8_t first_note = 255, MidiUartParent *uart2_ = nullptr); + void send_notes_on(MidiUartParent *uart2_ = nullptr); + void send_notes_off(MidiUartParent *uart2_ = nullptr); + + void onControlChangeCallback_Midi(uint8_t track_param,uint8_t value); }; #endif /* MDSEQTRACK_H__ */ diff --git a/avr/cores/megacommand/MCL/MDTrack.cpp b/avr/cores/megacommand/MCL/MDTrack.cpp index 7004dde62..7e3a50d13 100644 --- a/avr/cores/megacommand/MCL/MDTrack.cpp +++ b/avr/cores/megacommand/MCL/MDTrack.cpp @@ -120,6 +120,7 @@ void MDTrack::load_seq_data(SeqTrack *seq_track) { load_link_data(seq_track); md_seq_track->clear_mutes(); md_seq_track->set_length(md_seq_track->length); + md_seq_track->notes.first_trig = true; } void MDTrack::scale_seq_vol(float scale) { diff --git a/avr/cores/megacommand/MCL/MenuPage.cpp b/avr/cores/megacommand/MCL/MenuPage.cpp index 0cf961d30..d053b4091 100644 --- a/avr/cores/megacommand/MCL/MenuPage.cpp +++ b/avr/cores/megacommand/MCL/MenuPage.cpp @@ -5,6 +5,7 @@ void MenuPageBase::init() { DEBUG_PRINTLN("MenuPageBase::init"); R.Clear(); R.use_machine_names_short(); // for grid page + R.use_icons_knob(); // for grid page R.use_menu_options(); R.use_menu_layouts(); DEBUG_PRINT("R.Size() = "); @@ -34,36 +35,38 @@ void MenuPageBase::init() { void MenuPageBase::gen_menu_device_names() { MenuBase *m = get_menu(); - menu_option_t *p = (menu_option_t *)R.Allocate(sizeof(menu_option_t) * NUM_DEVS); + menu_option_t *p = + (menu_option_t *)R.Allocate(sizeof(menu_option_t) * NUM_DEVS); m->set_custom_options(p); for (uint8_t n = 0; n < NUM_DEVS; n++) { p->pos = n + 1; - strcpy(p->name,midi_active_peering.get_device(n + 1)->name); + strcpy(p->name, midi_active_peering.get_device(n + 1)->name); p++; } - } void MenuPageBase::gen_menu_row_names() { MenuBase *m = get_menu(); menu_option_t *p = (menu_option_t *)R.Allocate(sizeof(menu_option_t) * 128); m->set_custom_options(p); - uint8_t row_id = 0; - for (char bank = 'A'; bank <= 'H'; ++bank) { - for (uint8_t i = 1; i <= 16; ++i) { - p->pos = row_id++; - p->name[0] = bank; - if (i < 10) { - p->name[1] = '0'; - p->name[2] = '0' + i; - } else { - p->name[1] = '1'; - p->name[2] = '0' + i - 10; - } - p->name[3] = '\0'; - ++p; + for (uint8_t row_id = 0; row_id < 128; ++row_id) { + char bank = 'A' + row_id / 16; + uint8_t i = row_id % 16 + 1; + + p->pos = row_id; + p->name[0] = bank; + + if (i < 10) { + p->name[1] = '0'; + p->name[2] = '0' + i; + } else { + p->name[1] = '1'; + p->name[2] = '0' + i - 10; } + + p->name[3] = '\0'; + ++p; } } @@ -152,8 +155,9 @@ void MenuPageBase::draw_menu(uint8_t x_offset, uint8_t y_offset, oled_display.setCursor(x_offset, y_offset + 8 * n); if (n == cur_row) { oled_display.setTextColor(BLACK, WHITE); - oled_display.fillRect(max(0,oled_display.getCursorX() - 3), - max(0,oled_display.getCursorY() - 6), width, 7, WHITE); + oled_display.fillRect(max(0, oled_display.getCursorX() - 3), + max(0, oled_display.getCursorY() - 6), width, 7, + WHITE); } else { oled_display.setTextColor(WHITE, BLACK); } @@ -181,7 +185,6 @@ void MenuPageBase::display() { if (number_of_items > visible_rows) { draw_scrollbar(120); } - oled_display.display(); } bool MenuPageBase::enter() { @@ -202,11 +205,13 @@ bool MenuPageBase::enter() { return false; } -bool MenuPageBase::exit() { - if (GUI.currentPage() != this) { return; } +void MenuPageBase::exit() { + if (GUI.currentPage() != this) { + return; + } void (*exit_func)() = get_menu()->get_exit_function(); if (exit_func != NULL) { - (*exit_func)(); + (*exit_func)(); } mcl.popPage(); } @@ -231,16 +236,16 @@ bool MenuPageBase::handleEvent(gui_event_t *event) { trig_interface.ignoreNextEvent(MDX_KEY_NO); goto NO; case MDX_KEY_UP: - encoders[1]->cur -= inc; + encoders[1]->cur -= inc; break; case MDX_KEY_DOWN: - encoders[1]->cur += inc; + encoders[1]->cur += inc; break; case MDX_KEY_LEFT: - encoders[0]->cur -= inc; + encoders[0]->cur -= inc; break; case MDX_KEY_RIGHT: - encoders[0]->cur += inc; + encoders[0]->cur += inc; break; } } diff --git a/avr/cores/megacommand/MCL/MenuPage.h b/avr/cores/megacommand/MCL/MenuPage.h index 656fdebd8..78b269e59 100644 --- a/avr/cores/megacommand/MCL/MenuPage.h +++ b/avr/cores/megacommand/MCL/MenuPage.h @@ -39,7 +39,7 @@ class MenuPageBase : public LightPage { void setup(); void init(); bool enter(); - bool exit(); + void exit(); void cleanup(); void gen_menu_device_names(); void gen_menu_row_names(); diff --git a/avr/cores/megacommand/MCL/MidiActivePeering.cpp b/avr/cores/megacommand/MCL/MidiActivePeering.cpp index 1ab6fa5d6..abe4eb4e9 100644 --- a/avr/cores/megacommand/MCL/MidiActivePeering.cpp +++ b/avr/cores/megacommand/MCL/MidiActivePeering.cpp @@ -17,8 +17,8 @@ uint8_t GenericMidiDevice::get_mute_cc() { return mcl_cfg.uart2_cc_mute > 127 ? 255 : mcl_cfg.uart2_cc_mute; } -void GenericMidiDevice::muteTrack(uint8_t track, bool mute = true, - MidiUartParent *uart_ = nullptr) { +void GenericMidiDevice::muteTrack(uint8_t track, bool mute, + MidiUartClass *uart_) { if (track >= NUM_EXT_TRACKS || mcl_cfg.uart2_cc_mute > 127) { return; } @@ -30,7 +30,7 @@ void GenericMidiDevice::muteTrack(uint8_t track, bool mute = true, }; void GenericMidiDevice::setLevel(uint8_t track, uint8_t value, - MidiUartParent *uart_ = nullptr) { + MidiUartClass *uart_) { if (track >= NUM_EXT_TRACKS || mcl_cfg.uart2_cc_level > 127) { return; } @@ -52,8 +52,8 @@ void GenericMidiDevice::init_grid_devices(uint8_t device_idx) { } /// It is the caller's responsibility to check for null MidiUart device -static MidiUartParent *_getMidiUart(uint8_t port) { - MidiUartParent *ret = nullptr; +static MidiUartClass *_getMidiUart(uint8_t port) { + MidiUartClass *ret = nullptr; if (port == UART1_PORT) ret = &MidiUart; #ifdef EXT_TRACKS @@ -92,7 +92,7 @@ static void prepare_display(uint8_t *buf) { // the general probe accept whatever devices. static bool midi_device_setup(uint8_t port) { return true; } -static MidiDevice *port1_drivers[] = {&MD}; +static MidiDevice *port1_drivers[] = { &MD }; static MidiDevice *port2_drivers[] = { &MNM, @@ -243,17 +243,21 @@ void MidiActivePeering::run() { } #endif - probePort(UART1_PORT, port1_drivers, countof(port1_drivers), - &connected_midi_devices[0], resource_buf); + MidiDevice **drivers = port1_drivers; + uint8_t nr_drivers = countof(port1_drivers); + if (!mcl_cfg.uart1_device) { + nr_drivers = 1; + drivers = generic_drivers; + } + probePort(UART1_PORT, drivers, nr_drivers, &connected_midi_devices[0], resource_buf); #ifdef EXT_TRACKS - uint8_t nr_drivers = countof(port2_drivers); - MidiDevice **drivers = port2_drivers; + drivers = port2_drivers; + nr_drivers = countof(port2_drivers); if (!mcl_cfg.uart2_device) { nr_drivers = 1; drivers = generic_drivers; } - probePort(UART2_PORT, drivers, nr_drivers, &connected_midi_devices[1], - resource_buf); + probePort(UART2_PORT, drivers, nr_drivers, &connected_midi_devices[1], resource_buf); if (resource_loaded) { // XXX doesn't work yet // R.Restore(resource_buf, resource_size); diff --git a/avr/cores/megacommand/MCL/MidiActivePeering.h b/avr/cores/megacommand/MCL/MidiActivePeering.h index 50942c45c..59d6ee4dd 100644 --- a/avr/cores/megacommand/MCL/MidiActivePeering.h +++ b/avr/cores/megacommand/MCL/MidiActivePeering.h @@ -40,8 +40,8 @@ class GenericMidiDevice : public MidiDevice { void init_grid_devices(uint8_t device_idx); virtual uint8_t get_mute_cc(); - virtual void muteTrack(uint8_t track, bool mute = true, MidiUartParent *uart_ = nullptr); - virtual void setLevel(uint8_t track, uint8_t value, MidiUartParent *uart_ = nullptr); + virtual void muteTrack(uint8_t track, bool mute = true, MidiUartClass *uart_ = nullptr); + virtual void setLevel(uint8_t track, uint8_t value, MidiUartClass *uart_ = nullptr); }; class NullMidiDevice : public MidiDevice { diff --git a/avr/cores/megacommand/MCL/MidiSetup.cpp b/avr/cores/megacommand/MCL/MidiSetup.cpp index 630f53882..972f3c764 100644 --- a/avr/cores/megacommand/MCL/MidiSetup.cpp +++ b/avr/cores/megacommand/MCL/MidiSetup.cpp @@ -130,22 +130,31 @@ void MidiSetup::cfg_ports(bool boot) { MidiUSB.uart); } - if (elektron_devs[0]) { - turbo_light.set_speed(turbo_light.lookup_speed(mcl_cfg.uart1_turbo_speed), + if (mcl_cfg.uart1_device == 0) { + midi_active_peering.disconnect(UART1_PORT); + midi_active_peering.force_connect(UART1_PORT, &generic_midi_device); + turbo_light.set_speed(turbo_light.lookup_speed(mcl_cfg.uart1_turbo_speed), + Midi.uart); + } else if (elektron_devs[0]) { + turbo_light.set_speed(turbo_light.lookup_speed(mcl_cfg.uart1_turbo_speed), Midi.uart); - delay(100); - elektron_devs[0]->setup(); + delay(100); + elektron_devs[0]->setup(); + } else { + midi_active_peering.force_connect(UART1_PORT, &null_midi_device); } + if (mcl_cfg.uart2_device == 0) { - midi_active_peering.force_connect(UART2_PORT, &generic_midi_device); - if (mcl_cfg.uart2_turbo_speed) { + midi_active_peering.disconnect(UART2_PORT); + midi_active_peering.force_connect(UART2_PORT, &generic_midi_device); turbo_light.set_speed(turbo_light.lookup_speed(mcl_cfg.uart2_turbo_speed), Midi2.uart); - } } else if (elektron_devs[1]) { - elektron_devs[1]->setup(); turbo_light.set_speed(turbo_light.lookup_speed(mcl_cfg.uart2_turbo_speed), - Midi2.uart); + Midi2.uart); + delay(100); + elektron_devs[1]->setup(); + } else { midi_active_peering.force_connect(UART2_PORT, &null_midi_device); } diff --git a/avr/cores/megacommand/MCL/MixerPage.cpp b/avr/cores/megacommand/MCL/MixerPage.cpp index 6711340c5..ecceb7d44 100644 --- a/avr/cores/megacommand/MCL/MixerPage.cpp +++ b/avr/cores/megacommand/MCL/MixerPage.cpp @@ -12,11 +12,14 @@ void MixerPage::set_display_mode(uint8_t param) { } void MixerPage::oled_draw_mutes() { + bool is_md_device = (midi_device == &MD); uint8_t len = is_md_device ? mcl_seq.num_md_tracks : mcl_seq.num_ext_tracks; uint8_t fader_x = 0; + bool draw = true; + if (preview_mute_set != 255 && load_types[preview_mute_set][!is_md_device] == 0) { draw = false; } for (uint8_t i = 0; i < len; ++i) { // draw routing SeqTrack *seq_track = is_md_device ? (SeqTrack *)&mcl_seq.md_tracks[i] @@ -32,10 +35,12 @@ void MixerPage::oled_draw_mutes() { // } else if (mute_state) { // No Mute (SEQ_MUTE_OFF) oled_display.fillRect(fader_x, 2, 6, 6, BLACK); - if (mute_state) { - oled_display.drawRect(fader_x, 2, 6, 6, WHITE); - } else { - oled_display.drawLine(fader_x, 5, 5 + (i * 8), 5, WHITE); + if (draw) { + if (mute_state) { + oled_display.drawRect(fader_x, 2, 6, 6, WHITE); + } else { + oled_display.drawLine(fader_x, 5, 5 + (i * 8), 5, WHITE); + } } fader_x += 8; } @@ -71,7 +76,6 @@ void MixerPage::init() { redraw_mask = -1; seq_step_page.mute_mask++; show_mixer_menu = 0; - memset(perf_locks_temp, 255, sizeof(perf_locks_temp)); // populate_mute_set(); draw_encoders = false; redraw_mutes = true; @@ -82,7 +86,6 @@ void MixerPage::init() { void MixerPage::cleanup() { // md_exploit.off(); - oled_display.clearDisplay(); MD.set_key_repeat(1); disable_record_mutes(); trig_interface.off(); @@ -102,13 +105,12 @@ void MixerPage::load_perf_locks(uint8_t state) { uint8_t val = perf_locks[state][n]; if (val < 128) { enc->cur = val; - enc->old = val; - enc->send(); + enc->resend = true; } } } void MixerPage::loop() { - constexpr int timeout = 1500; + constexpr int timeout = 750; perf_page.func_enc_check(); bool old_draw_encoders = draw_encoders; @@ -216,6 +218,23 @@ void encoder_lastparam_handle(EncoderParent *enc) { } */ +void MixerPage::draw_encs() { + constexpr uint8_t fader_y = 11; + oled_display.fillRect(0, fader_y, 128, 21, BLACK); + for (uint8_t n = 0; n < 4; n++) { + char str1[] = "A"; + str1[0] = 'A' + n; + uint8_t pos = n * 24; + bool highlight = + (preview_mute_set != 255) && (perf_locks[preview_mute_set][n] != 255); // && (trig_interface.is_key_down(MDX_KEY_NO)); + uint8_t val = + highlight ? perf_locks[preview_mute_set][n] : encoders[n]->cur; + mcl_gui.draw_encoder(24 + pos, fader_y + 4, val, highlight); + oled_display.setCursor(16 + pos, fader_y + 6); + oled_display.print(str1); + } +} + void MixerPage::adjust_param(EncoderParent *enc, uint8_t param) { if (midi_device != &MD) { @@ -240,11 +259,8 @@ void MixerPage::adjust_param(EncoderParent *enc, uint8_t param) { void MixerPage::display() { - auto oldfont = oled_display.getFont(); if (oled_display.textbox_enabled) { - oled_display.clearDisplay(); - oled_draw_mutes(); - redraw_mask = -1; + redraw(); } if (redraw_mutes) { @@ -261,7 +277,9 @@ void MixerPage::display() { oled_draw_mutes(); } else if (mute_set != 255 && mute_sets[!is_md_device].mutes[mute_set] != seq_step_page.mute_mask) { + uint16_t mask = mute_sets[!is_md_device].mutes[mute_set]; + if (load_types[mute_set][!is_md_device] == 0) { mask = 0; } if (!is_md_device) { mask &= 0b111111; } @@ -271,20 +289,13 @@ void MixerPage::display() { } if (draw_encoders || preview_mute_set != 255) { // oled_display.clearDisplay(); - oled_display.fillRect(0, fader_y, 128, 21, BLACK); - for (uint8_t n = 0; n < 4; n++) { - char str1[] = "A"; - str1[0] = 'A' + n; - uint8_t pos = n * 24; - bool highlight = - (preview_mute_set != 255) && (perf_locks[preview_mute_set][n] != 255); // && (trig_interface.is_key_down(MDX_KEY_NO)); - uint8_t val = - highlight ? perf_locks[preview_mute_set][n] : encoders[n]->cur; - mcl_gui.draw_encoder(24 + pos, fader_y + 4, val, highlight); - oled_display.setCursor(16 + pos, fader_y + 6); - oled_display.print(str1); + draw_encs(); + oled_display.setFont(&TomThumb); + if (load_mute_set != 255 && load_mute_set == preview_mute_set) { + oled_display.setCursor(111, 31); + oled_display.print("LOAD"); } - oled_display.display(); + oled_display.setFont(); } else { uint8_t fader_level; @@ -308,8 +319,8 @@ void MixerPage::display() { fader_level = 127; } - fader_level = ((fader_level * 0.00787) * FADER_LEN) + 0; - meter_level = ((levels[i] * 0.00787) * FADER_LEN) + 0; + fader_level = (((uint16_t) fader_level * FADER_LEN) / 127) + 0; + meter_level = (((uint16_t) levels[i] * FADER_LEN) / 127) + 0; meter_level = min(fader_level, meter_level); if (IS_BIT_SET16(redraw_mask, i)) { @@ -341,12 +352,7 @@ void MixerPage::display() { } } - if (!redraw_mask) { - oled_display.display(); - } else { - redraw_mask = -1; - } - oled_display.setFont(oldfont); + redraw_mask = -1; } void MixerPage::record_mutes_set(bool state) { @@ -404,41 +410,42 @@ void MixerPage::populate_mute_set() { } } -void MixerPage::switch_mute_set(uint8_t state) { +void MixerPage::switch_mute_set(uint8_t state, bool load_perf, bool *load_type) { MidiDevice *devs[2] = { midi_active_peering.get_device(UART1_PORT), midi_active_peering.get_device(UART2_PORT), }; + if (load_type != nullptr && state < 255) { + for (uint8_t dev = 0; dev < 2; dev++) { + bool is_md_device = dev == 0; - for (uint8_t dev = 0; dev < 2; dev++) { - - bool is_md_device = dev == 0; - uint8_t len = + if (!load_type[dev]) continue; + uint8_t len = (is_md_device) ? mcl_seq.num_md_tracks : mcl_seq.num_ext_tracks; - for (uint8_t n = 0; n < len; n++) { - SeqTrack *seq_track = (is_md_device) ? (SeqTrack *)&mcl_seq.md_tracks[n] + for (uint8_t n = 0; n < len; n++) { + SeqTrack *seq_track = (is_md_device) ? (SeqTrack *)&mcl_seq.md_tracks[n] : (SeqTrack *)&mcl_seq.ext_tracks[n]; - uint8_t mute_set = state; - bool mute_state = IS_BIT_CLEAR16(mute_sets[dev].mutes[state], n); - // Flip - if (state == 4 && devs[dev] == midi_device) { - mute_state = !seq_track->mute_state; - } - // Switch - if (mute_state != seq_track->mute_state) { - devs[dev]->muteTrack(n, mute_state); - if (is_md_device) { - mcl_seq.md_tracks[n].toggle_mute(); - } else { - mcl_seq.ext_tracks[n].toggle_mute(); + bool mute_state = IS_BIT_CLEAR16(mute_sets[dev].mutes[state], n); + // Flip + if (state == 4 && devs[dev] == midi_device) { + mute_state = !seq_track->mute_state; + } + // Switch + if (mute_state != seq_track->mute_state) { + devs[dev]->muteTrack(n, mute_state); + if (is_md_device) { + mcl_seq.md_tracks[n].toggle_mute(); + } else { + mcl_seq.ext_tracks[n].toggle_mute(); + } } } } } - if (state < 4) { + if (state < 4 && load_perf) { load_perf_locks(state); } oled_draw_mutes(); @@ -519,7 +526,7 @@ bool MixerPage::handleEvent(gui_event_t *event) { uint8_t len = is_md_device ? mcl_seq.num_md_tracks : mcl_seq.num_ext_tracks; if (event->mask == EVENT_BUTTON_PRESSED && track < len) { if (note_interface.is_note(track)) { - if (show_mixer_menu || preview_mute_set != 255 || ext_key_down) { + if (show_mixer_menu || preview_mute_set != 255 && load_types[preview_mute_set][!is_md_device] || ext_key_down) { if (ext_key_down) { mute_toggle = 1; } SeqTrack *seq_track = is_md_device ? (SeqTrack *)&mcl_seq.md_tracks[track] @@ -535,7 +542,7 @@ bool MixerPage::handleEvent(gui_event_t *event) { mcl_seq.ext_tracks[track].toggle_mute(); } midi_device->muteTrack(track, seq_track->mute_state); - return; + return true; } // Toggle preview mutes @@ -620,26 +627,51 @@ bool MixerPage::handleEvent(gui_event_t *event) { } break; } + case MDX_KEY_BANKA: { + if (preview_mute_set != 255) { + load_types[preview_mute_set][!is_md_device] = !load_types[preview_mute_set][!is_md_device]; + if (load_types[preview_mute_set][!is_md_device] == 0) { seq_step_page.mute_mask = 0; } + redraw_mutes = true; + return true; + } + break; + } + case MDX_KEY_BANKB: { + if (preview_mute_set != 255) { + if (load_mute_set == preview_mute_set) { load_mute_set = 255; } + else { load_mute_set = preview_mute_set; } + return true; + } + break; + } case MDX_KEY_YES: { - if (preview_mute_set == 255 && + if (preview_mute_set == 255 && trig_interface.is_key_down(MDX_KEY_FUNC) && note_interface.notes_on == 0) { - switch_mute_set(4); //---> Flip mutes + bool load_t[2] = { 0, 0 }; + load_t[!is_md_device] = 1; + switch_mute_set(4,false,load_t); //---> Flip mutes break; } + uint8_t set = 255; + if (trig_interface.is_key_down(MDX_KEY_LEFT)) { - switch_mute_set(1); - break; + set = 1; } else if (trig_interface.is_key_down(MDX_KEY_UP)) { - switch_mute_set(2); - break; + set = 2; } else if (trig_interface.is_key_down(MDX_KEY_RIGHT)) { - switch_mute_set(3); - break; + set = 3; } else if (trig_interface.is_key_down(MDX_KEY_DOWN)) { - switch_mute_set(0); - break; - } else { + set = 0; + } + if (set != 255) { + //bool load_t[2]; + //load_t[0] = load_types[key][0]; + //load_t[1] = load_types[key][1]; + //load_t[is_md_device] = 0; + switch_mute_set(set,true,load_types[set]); + } + else { if (!note_interface.notes_on) { seq_step_page.mute_mask = 0; show_mixer_menu = true; @@ -649,22 +681,16 @@ bool MixerPage::handleEvent(gui_event_t *event) { } break; } - case MDX_KEY_LEFT: case MDX_KEY_UP: case MDX_KEY_RIGHT: case MDX_KEY_DOWN: { + if (trig_interface.is_key_down(MDX_KEY_NO)) { return true; } uint8_t set = get_mute_set(key); if (trig_interface.is_key_down(MDX_KEY_YES)) { - switch_mute_set(set); + switch_mute_set(set,true,load_types[set]); } else { - preview_mute_set = set; - for (uint8_t n = 0; n < 4; n++) { - if (perf_locks_temp[n] == 255 && (trig_interface.is_key_down(MDX_KEY_NO))) { - perf_locks_temp[n] = encoders[n]->cur; - encoders[n]->old = encoders[n]->cur; - } - } + preview_mute_set = set; // force redraw in display() seq_step_page.mute_mask++; } @@ -715,31 +741,13 @@ bool MixerPage::handleEvent(gui_event_t *event) { trig_interface.send_md_leds(is_md_device ? TRIGLED_OVERLAY : TRIGLED_EXCLUSIVE); preview_mute_set = 255; redraw(); - for (uint8_t n = 0; n < 4; n++) { - MCLEncoder *enc = (MCLEncoder*) &encoders[n]; - if (perf_locks_temp[n] != 255 && (trig_interface.is_key_down(MDX_KEY_NO))) { - enc->cur = perf_locks_temp[n]; - enc->old = enc->cur; - } - perf_locks_temp[n] = 255; - } } break; } } } } - if (EVENT_PRESSED(event, Buttons.BUTTON3) && !BUTTON_DOWN(Buttons.BUTTON4)) { - // show_mixer_menu = true; - if (note_interface.notes_on) { - setLed2(); - record_mutes_set(true); - } - return true; - } - if (EVENT_RELEASED(event, Buttons.BUTTON3)) { - global_release: preview_mute_set = 255; show_mixer_menu = false; @@ -748,10 +756,44 @@ bool MixerPage::handleEvent(gui_event_t *event) { redraw(); return true; } + if (EVENT_PRESSED(event,Buttons.BUTTON3)) { + // show_mixer_menu = true; + if (note_interface.notes_on) { + setLed2(); + record_mutes_set(true); + return true; + } + if (BUTTON_DOWN(Buttons.ENCODER1)) { + perf_param1.clear_scenes(); + } + if (BUTTON_DOWN(Buttons.ENCODER2)) { + perf_param2.clear_scenes(); + } + if (BUTTON_DOWN(Buttons.ENCODER3)) { + perf_param3.clear_scenes(); + } + if (BUTTON_DOWN(Buttons.ENCODER4)) { + perf_param4.clear_scenes(); + } + redraw_mask = -1; + return true; + } - if (EVENT_PRESSED(event, Buttons.BUTTON2)) { - mcl.setPage(PAGE_SELECT_PAGE); - return true; + if (EVENT_PRESSED(event, Buttons.BUTTON4)) { + if (BUTTON_DOWN(Buttons.ENCODER1)) { + perf_param1.scene_autofill(); + } + if (BUTTON_DOWN(Buttons.ENCODER2)) { + perf_param2.scene_autofill(); + } + if (BUTTON_DOWN(Buttons.ENCODER3)) { + perf_param3.scene_autofill(); + } + if (BUTTON_DOWN(Buttons.ENCODER4)) { + perf_param4.scene_autofill(); + } + redraw_mask = -1; + return true; } if (preview_mute_set != 255 && (trig_interface.is_key_down(MDX_KEY_NO))) { @@ -840,22 +882,3 @@ void MixerPage::onControlChangeCallback_Midi(uint8_t track, uint8_t track_param, mixer_page.set_display_mode(track_param); } -uint8_t MixerPage::note_to_trig(uint8_t note_num) { - uint8_t trig_num = 0; - for (uint8_t i = 0; i < sizeof(MD.global.drumMapping); i++) { - if (note_num == MD.global.drumMapping[i]) { - trig_num = i; - } - } - return trig_num; -} - -void MixerPage::onNoteOnCallback_Midi(uint8_t *msg) { - uint8_t note_num = msg[1]; - uint8_t channel = MIDI_VOICE_CHANNEL(msg[0]); - - uint8_t n = note_to_trig(msg[1]); - if (msg[0] != 153) { - mixer_page.disp_levels[n] = MD.kit.levels[n]; - } -} diff --git a/avr/cores/megacommand/MCL/MixerPage.h b/avr/cores/megacommand/MCL/MixerPage.h index 98480c6d4..9c5cae454 100644 --- a/avr/cores/megacommand/MCL/MixerPage.h +++ b/avr/cores/megacommand/MCL/MixerPage.h @@ -31,8 +31,8 @@ void encoder_lastparam_handle(EncoderParent *enc); class MixerPage : public LightPage { public: uint8_t level_pressmode = 0; - int8_t disp_levels[16]; - int8_t ext_disp_levels[6]; + uint8_t disp_levels[16]; + uint8_t ext_disp_levels[6]; bool mute_toggle = 0; uint8_t ext_key_down; MidiDevice *midi_device; @@ -49,26 +49,29 @@ class MixerPage : public LightPage { uint8_t current_mute_set = 255; uint8_t preview_mute_set = 255; + uint8_t load_mute_set = 255; + void send_fx(uint8_t param, Encoder *enc, uint8_t type); // Don't change order MuteSet mute_sets[2]; uint8_t perf_locks[4][4]; + bool load_types[4][2]; // - uint8_t perf_locks_temp[4]; - uint8_t get_mute_set(uint8_t key); MixerPage(Encoder *e1 = NULL, Encoder *e2 = NULL, Encoder *e3 = NULL, Encoder *e4 = NULL) : LightPage(e1, e2, e3, e4) { midi_device = &MD; - memset(mute_sets, 0xFF, sizeof(mute_sets)); - memset(perf_locks, 0xFF, sizeof(perf_locks)); + memset(mute_sets, 0xFF, sizeof(mute_sets) + sizeof(perf_locks)); + //memset(perf_locks, 0xFF, sizeof(perf_locks)); + memset(load_types, 1, sizeof(load_types)); } void adjust_param(EncoderParent *enc, uint8_t param); void draw_levels(); + void draw_encs(); void redraw(); void set_level(int curtrack, int value); void set_display_mode(uint8_t param); @@ -76,13 +79,12 @@ class MixerPage : public LightPage { void record_mutes_set(bool state); void disable_record_mutes(bool clear = false); void oled_draw_mutes(); - void switch_mute_set(uint8_t state); + void switch_mute_set(uint8_t state, bool load_perf = false, bool *load_types = nullptr); void populate_mute_set(); void load_perf_locks(uint8_t state); void toggle_or_solo(bool solo = false); // Handled in MCLSeq - void onNoteOnCallback_Midi(uint8_t *msg); void onControlChangeCallback_Midi(uint8_t track, uint8_t track_param, uint8_t value); diff --git a/avr/cores/megacommand/MCL/NoteInterface.cpp b/avr/cores/megacommand/MCL/NoteInterface.cpp index 152b75703..2fde94dd2 100644 --- a/avr/cores/megacommand/MCL/NoteInterface.cpp +++ b/avr/cores/megacommand/MCL/NoteInterface.cpp @@ -124,7 +124,7 @@ void NoteInterfaceMidiEvents::onNoteOnCallback_Midi2(uint8_t *msg) { } void NoteInterfaceMidiEvents::onNoteOffCallback_Midi(uint8_t *msg) { // only accept input if device is not a MD - // MD input is handled by the NoteInterface object + // MD input is handled by the TrigInterface object if (midi_active_peering.get_device(UART1_PORT) == &MD) { return; } @@ -150,12 +150,14 @@ void NoteInterfaceMidiEvents::setup_callbacks() { if (state) { return; } +/* Midi.addOnNoteOnCallback( this, (midi_callback_ptr_t)&NoteInterfaceMidiEvents::onNoteOnCallback_Midi); Midi.addOnNoteOffCallback( this, (midi_callback_ptr_t)&NoteInterfaceMidiEvents::onNoteOffCallback_Midi); +*/ Midi2.addOnNoteOnCallback( this, (midi_callback_ptr_t)&NoteInterfaceMidiEvents::onNoteOnCallback_Midi2); @@ -170,12 +172,14 @@ void NoteInterfaceMidiEvents::remove_callbacks() { if (!state) { return; } +/* Midi.removeOnNoteOnCallback( this, (midi_callback_ptr_t)&NoteInterfaceMidiEvents::onNoteOnCallback_Midi); Midi.removeOnNoteOffCallback( this, (midi_callback_ptr_t)&NoteInterfaceMidiEvents::onNoteOffCallback_Midi); +*/ Midi2.removeOnNoteOnCallback( this, (midi_callback_ptr_t)&NoteInterfaceMidiEvents::onNoteOnCallback_Midi2); diff --git a/avr/cores/megacommand/MCL/OscMixerPage.cpp b/avr/cores/megacommand/MCL/OscMixerPage.cpp index 128e49cf8..c93b0fbc6 100644 --- a/avr/cores/megacommand/MCL/OscMixerPage.cpp +++ b/avr/cores/megacommand/MCL/OscMixerPage.cpp @@ -28,8 +28,6 @@ bool OscMixerPage::handleEvent(gui_event_t *event) { void OscMixerPage::loop() { WavDesignerPage::loop(); } void OscMixerPage::display() { - // oled_display.clearDisplay(); - auto oldfont = oled_display.getFont(); if (show_menu) { WavDesignerPage::display(); } else { @@ -42,8 +40,6 @@ void OscMixerPage::display() { scanline_width = 4; draw_wav(); } - oled_display.display(); - oled_display.setFont(oldfont); } float OscMixerPage::get_max_gain() { diff --git a/avr/cores/megacommand/MCL/OscPage.cpp b/avr/cores/megacommand/MCL/OscPage.cpp index ecd2a1cd0..8680922fd 100644 --- a/avr/cores/megacommand/MCL/OscPage.cpp +++ b/avr/cores/megacommand/MCL/OscPage.cpp @@ -61,10 +61,10 @@ bool OscPage::handleEvent(gui_event_t *event) { } void OscPage::calc_largest_sine_peak() { - float max_sine_gain = ((float)1 / (float)16); + float max_sine_gain = 0.0004921259843f; // ((float)1 / (float)16) / 127; largest_sine_peak = 0; for (uint8_t f = 0; f < 16; f++) { - largest_sine_peak += max_sine_gain * ((float)sine_levels[f] / (float)127); + largest_sine_peak += max_sine_gain * (float)sine_levels[f]; } } @@ -122,6 +122,9 @@ void OscPage::loop() { trig_interface.off(); } } + +const char wave_names[][4] PROGMEM = {"--", "SIN", "TRI", "PUL", "SAW", "USR"}; + void OscPage::display() { // oled_display.clearDisplay(); oled_display.fillRect(0, 0, 64, 32, BLACK); @@ -130,17 +133,13 @@ void OscPage::display() { uint8_t c = 1; uint8_t i = 0; - auto oldfont = oled_display.getFont(); - oled_display.setFont(); oled_display.setCursor(0, 0); switch (osc_waveform) { - case 0: - draw_wav(0); - oled_display.print(F("--")); + default: + sample_number = 0; break; case SIN_OSC: - oled_display.print(F("SIN")); draw_levels(); for (i = 0; i < 16; i++) { if (sine_levels[i] > 0) { @@ -148,30 +147,12 @@ void OscPage::display() { } } scanline_width = 64 / c; - draw_wav(SIN_OSC); - break; - case TRI_OSC: - oled_display.print(F("TRI")); - sample_number = 0; - draw_wav(TRI_OSC); - break; - case PUL_OSC: - oled_display.print(F("PUL")); - sample_number = 0; - draw_wav(PUL_OSC); - break; - case SAW_OSC: - oled_display.print(F("SAW")); - sample_number = 0; - draw_wav(SAW_OSC); - break; - case USR_OSC: - oled_display.print(F("USR")); - draw_wav(USR_OSC); - sample_number = 0; - draw_usr(); break; } + char buf1[4]; + draw_wav(osc_waveform); + strncpy_P(buf1, wave_names[osc_waveform], 4); + oled_display.print(buf1); oled_display.print(F(" ")); char str[] = " "; @@ -194,8 +175,6 @@ void OscPage::display() { } // GUI.put_string_at(0, my_str); WavDesignerPage::display(); - oled_display.display(); - oled_display.setFont(oldfont); } void OscPage::draw_wav(uint8_t wav_type) { uint8_t x = 64; @@ -208,8 +187,8 @@ void OscPage::draw_wav(uint8_t wav_type) { SawOsc saw_osc(w, osc_width); SineOsc sine_osc(w); UsrOsc usr_osc(w); - float sample; - float max_sine_gain = (float)1 / (float)16; + float sample = 0; + float max_sine_gain = 0.0004921259843f; // (float)1 / (float)16 / 127; uint8_t n = sample_number; // for (uint8_t n = 0; n < 128 - x; n++) { @@ -223,9 +202,8 @@ void OscPage::draw_wav(uint8_t wav_type) { sample = 0; for (uint8_t f = 1; f <= 16; f++) { if (sine_levels[f - 1] != 0) { - float sine_gain = ((float)sine_levels[f - 1] / (float)127); - sample += sine_osc.get_sample((uint32_t)n, 1 * (float)f) * sine_gain * - max_sine_gain; + float sine_gain = (float)sine_levels[f - 1] * max_sine_gain; + sample += sine_osc.get_sample((uint32_t)n, 1 * (float)f) * sine_gain; } } if (largest_sine_peak == 0) { @@ -264,6 +242,10 @@ void OscPage::draw_wav(uint8_t wav_type) { if (sample_number > 127 - x) { sample_number = 0; } + if (wav_type == USR_OSC) { + draw_usr(); + } + } void OscPage::draw_usr() { diff --git a/avr/cores/megacommand/MCL/PageSelectPage.cpp b/avr/cores/megacommand/MCL/PageSelectPage.cpp index 8091e642a..a3048511c 100644 --- a/avr/cores/megacommand/MCL/PageSelectPage.cpp +++ b/avr/cores/megacommand/MCL/PageSelectPage.cpp @@ -18,7 +18,7 @@ static uint8_t get_pageidx(uint8_t page_number) { return i; } } - return 255; + return NULL_PAGE; } static PageIndex get_page(uint8_t pageidx, char *str) { @@ -31,7 +31,7 @@ static PageIndex get_page(uint8_t pageidx, char *str) { if (str) { strcpy(str, "----"); } - return 255; + return NULL_PAGE; } } @@ -110,7 +110,7 @@ void PageSelectPage::draw_popup() { void PageSelectPage::md_prepare() { kit_cb.init(); auto listener = MD.getSysexListener(); - listener->addOnKitMessageCallback( + listener->addOnMessageCallback( &kit_cb, (sysex_callback_ptr_t)&MDCallback::onReceived); MD.requestKit(0x7F); } @@ -123,7 +123,7 @@ void PageSelectPage::cleanup() { uint8_t PageSelectPage::get_nextpage_down() { for (int8_t i = page_select - 1; i >= 0; i--) { - if (get_page(get_pageidx(i), nullptr) != 255) { + if (get_page(get_pageidx(i), nullptr) != NULL_PAGE) { return i; } } @@ -132,7 +132,7 @@ uint8_t PageSelectPage::get_nextpage_down() { uint8_t PageSelectPage::get_nextpage_up() { for (uint8_t i = page_select + 1; i < 16; i++) { - if (get_page(get_pageidx(i), nullptr) != 255) { + if (get_page(get_pageidx(i), nullptr) != NULL_PAGE) { return i; } } @@ -279,7 +279,6 @@ void PageSelectPage::display() { WHITE); } - oled_display.display(); uint16_t led_mask = 1 << page_select; if (trigled_mask != led_mask) { trigled_mask = led_mask; @@ -353,7 +352,7 @@ bool PageSelectPage::handleEvent(gui_event_t *event) { release: PageIndex p; p = get_page(get_pageidx(page_select), nullptr); - if (BUTTON_DOWN(Buttons.BUTTON1) || (p == 255)) { + if (BUTTON_DOWN(Buttons.BUTTON1) || (p == NULL_PAGE)) { GUI.ignoreNextEvent(Buttons.BUTTON1); // md_exploit.off(); mcl.setPage(GRID_PAGE); diff --git a/avr/cores/megacommand/MCL/PageSelectPage.h b/avr/cores/megacommand/MCL/PageSelectPage.h index a83cc5391..645a5f522 100644 --- a/avr/cores/megacommand/MCL/PageSelectPage.h +++ b/avr/cores/megacommand/MCL/PageSelectPage.h @@ -34,7 +34,7 @@ class MDCallback : public SysexCallback { mcl_seq.update_kit_params(); } auto listener = MD.getSysexListener(); - listener->removeOnKitMessageCallback(this); + listener->removeOnMessageCallback(this); state = false; } }; diff --git a/avr/cores/megacommand/MCL/PerfData.h b/avr/cores/megacommand/MCL/PerfData.h index 467d42420..06fb0473e 100644 --- a/avr/cores/megacommand/MCL/PerfData.h +++ b/avr/cores/megacommand/MCL/PerfData.h @@ -12,27 +12,11 @@ static uint8_t get_param_device(uint8_t dest, uint8_t param) { if (dest <= NUM_MD_TRACKS) { return MD.kit.params[dest - 1][param]; } else { - switch (dest - NUM_MD_TRACKS - 1) { - case MD_FX_ECHO - MD_FX_ECHO: - return MD.kit.delay[param]; - break; - case MD_FX_DYN - MD_FX_ECHO: - return MD.kit.dynamics[param]; - break; - - case MD_FX_REV - MD_FX_ECHO: - return MD.kit.reverb[param]; - break; - case MD_FX_EQ - MD_FX_ECHO: - return MD.kit.eq[param]; - break; - } + return MD.kit.get_fx_param(dest - NUM_MD_TRACKS - 1 + MD_FX_ECHO, param); } return 255; } - - class PerfParam { public: uint8_t dest; @@ -197,8 +181,10 @@ class PerfData { } void clear_scene(uint8_t scene) { - PerfScene *s = &scenes[scene]; - s->init(); + if (scene < NUM_SCENES) { + PerfScene *s = &scenes[scene]; + s->init(); + } } void init_params() { @@ -207,6 +193,45 @@ class PerfData { } } + void scene_autofill(uint8_t scene) { + oled_display.textbox("FILL SCENES", ""); + if (scene >= NUM_SCENES) { return; } + + uint8_t *params = (uint8_t *) &MD.kit.params; + uint8_t *params_orig = (uint8_t *) &MD.kit.params_orig; + + for (uint8_t track = 0; track < 16; track++) { + for (uint8_t param = 0; param < 24; param++) { + if (MD.kit.params[track][param] != MD.kit.params_orig[track][param]) { + if (add_param(track,param,scene,MD.kit.params[track][param]) != 255) { + //Kit encoders go back to normal, for save. + uint8_t val = MD.kit.params[track][param]; + MD.setTrackParam(track, param, MD.kit.params_orig[track][param], nullptr, + true); + MD.setTrackParam(track, param, val, nullptr, + false); + } + } + + } + } + for (uint8_t n = 0; n < 8 * 4; n++) { + uint8_t fx = n / 8; + uint8_t param = n - fx * 8; + //delay and reverb are flipped in memory + if (fx == 0) { fx = 1; } + else if (fx == 1) { fx = 0; } + uint8_t *fxs = (uint8_t *) &MD.kit.reverb; + uint8_t *fxs_orig = (uint8_t *) &MD.kit.fx_orig; + if (fxs[n] != fxs_orig[n]) { + if (add_param(fx + NUM_MD_TRACKS,param,scene,fxs[n]) != 255) { + uint8_t val = fxs[n]; + MD.setFXParam(param, fxs_orig[n], fx + MD_FX_ECHO, true); + MD.setFXParam(param, val, fx + MD_FX_ECHO, false); + } + } + } + } }; diff --git a/avr/cores/megacommand/MCL/PerfEncoder.cpp b/avr/cores/megacommand/MCL/PerfEncoder.cpp index f636fb2d9..bb7818f7d 100644 --- a/avr/cores/megacommand/MCL/PerfEncoder.cpp +++ b/avr/cores/megacommand/MCL/PerfEncoder.cpp @@ -7,20 +7,23 @@ PerfScene PerfData::scenes[NUM_SCENES]; -void PerfEncoder::send_param(uint8_t dest, uint8_t param, uint8_t val) { +void PerfEncoder::send_param(uint8_t dest, uint8_t param, uint8_t val, MidiUartParent *uart_,MidiUartParent *uart2_) { + if (uart_ == nullptr) { uart_ = &MidiUart; } + if (uart2_ == nullptr) { uart2_ = &MidiUart2; } + if (dest >= NUM_MD_TRACKS + 4) { uint8_t channel = dest - NUM_MD_TRACKS - 4; DEBUG_PRINTLN("send cc"); DEBUG_PRINT(channel); DEBUG_PRINT(" "); DEBUG_PRINT(param); DEBUG_PRINT(" "); DEBUG_PRINTLN(val); - MidiUart2.sendCC(channel, param, val); + uart2_->sendCC(channel, param, val); } else if (dest >= NUM_MD_TRACKS) { - MD.setFXParam(param, val, MD_FX_ECHO + dest - NUM_MD_TRACKS); + MD.setFXParam(param, val, MD_FX_ECHO + dest - NUM_MD_TRACKS, false, uart_); } else { - MD.setTrackParam(dest, param, val); + MD.setTrackParam(dest, param, val, uart_, false); } } -void PerfEncoder::send_params(uint8_t cur_, PerfScene *s1, PerfScene *s2) { +void PerfEncoder::send_params(uint8_t cur_, PerfScene *s1, PerfScene *s2, MidiUartParent *uart_,MidiUartParent *uart2_) { PerfMorph morph; morph.populate(s1, s2); @@ -46,13 +49,14 @@ void PerfEncoder::send_params(uint8_t cur_, PerfScene *s1, PerfScene *s2) { continue; } DEBUG_PRINTLN(val); - send_param(f->dest - 1, f->param, val); + send_param(f->dest - 1, f->param, val, uart_, uart2_); } } -void PerfEncoder::send() { +void PerfEncoder::send(MidiUartParent *uart_,MidiUartParent *uart2_) { PerfScene *s1 = active_scene_a == 255 ? nullptr : &perf_data.scenes[active_scene_a]; PerfScene *s2 = active_scene_b == 255 ? nullptr : &perf_data.scenes[active_scene_b]; - send_params(cur, s1, s2); + send_params(cur, s1, s2, uart_, uart2_); + resend = false; } int PerfEncoder::update(encoder_t *enc) { @@ -60,4 +64,14 @@ int PerfEncoder::update(encoder_t *enc) { // Update all params return cur; } +void PerfEncoder::scene_autofill() { + perf_data.scene_autofill(active_scene_b); + cur = 127; + old = 127; +} +void PerfEncoder::clear_scenes() { + oled_display.textbox("CLEAR SCENES", ""); + perf_data.clear_scene(active_scene_a); + perf_data.clear_scene(active_scene_b); +} diff --git a/avr/cores/megacommand/MCL/PerfEncoder.h b/avr/cores/megacommand/MCL/PerfEncoder.h index 8e7051fb0..402cd2721 100644 --- a/avr/cores/megacommand/MCL/PerfEncoder.h +++ b/avr/cores/megacommand/MCL/PerfEncoder.h @@ -22,10 +22,14 @@ class PerfEncoder : public MCLEncoder { uint8_t active_scene_a = 0; uint8_t active_scene_b = 1; + bool resend = false; + void init() { perf_data.init(); } - void send(); - void send_param(uint8_t dest, uint8_t param, uint8_t val); - void send_params(uint8_t cur_, PerfScene *s1, PerfScene *s2); + void send(MidiUartParent *uart_ = nullptr,MidiUartParent *uart2_ = nullptr); + void send_param(uint8_t dest, uint8_t param, uint8_t val, MidiUartParent *uart_ = nullptr, MidiUartParent *uart2_ = nullptr); + void send_params(uint8_t cur_, PerfScene *s1, PerfScene *s2, MidiUartParent *uart_ = nullptr,MidiUartParent *uart2_ = nullptr); + void scene_autofill(); + void clear_scenes(); /** Create a new range-limited encoder with max and min value, short name, initial value, and handling function. The initRangeEncoder diff --git a/avr/cores/megacommand/MCL/PerfPage.cpp b/avr/cores/megacommand/MCL/PerfPage.cpp index 5ce310ce1..0e00a6f41 100644 --- a/avr/cores/megacommand/MCL/PerfPage.cpp +++ b/avr/cores/megacommand/MCL/PerfPage.cpp @@ -213,6 +213,7 @@ void PerfPage::loop() { } void PerfPage::display() { + oled_display.setFont(&TomThumb); if (show_menu) { constexpr uint8_t width = 52; oled_display.fillRect(128 - width - 2, 0, width + 2, 32, BLACK); @@ -222,8 +223,6 @@ void PerfPage::display() { oled_display.clearDisplay(); - auto oldfont = oled_display.getFont(); - uint8_t x = mcl_gui.knob_x0 + 5; uint8_t y = 8; uint8_t lfo_height = 7; @@ -232,8 +231,8 @@ void PerfPage::display() { // mcl_gui.draw_vertical_dashline(x, 0, knob_y); mcl_gui.draw_knob_frame(); - const char *info1 = ""; - const char *info2 = "PARAMETER"; + char *info1 = ""; + char *info2 = "PARAMETER"; uint8_t scene = learn - 1; @@ -285,7 +284,6 @@ void PerfPage::display() { mcl_gui.draw_panel_number(scene + 1); } oled_display.setTextColor(WHITE, BLACK); - oled_display.setFont(oldfont); mcl_gui.draw_panel_labels(info1, info2); if (trig_interface.is_key_down(MDX_KEY_LEFT) || @@ -302,7 +300,6 @@ void PerfPage::display() { oled_display.writeFastHLine(109, MCLGUI::pane_info2_y + 1, 5, WHITE); oled_display.writeFastVLine(109 + ((e->cur * 5) / 128), MCLGUI::pane_info2_y, 3, WHITE); - oled_display.display(); } @@ -313,7 +310,7 @@ void PerfPage::encoder_check() { void PerfPage::encoder_send() { for (uint8_t i = 0; i < 4; i++) { - if (perf_encoders[i]->hasChanged()) { perf_encoders[i]->send(); } + if (perf_encoders[i]->hasChanged() || perf_encoders[i]->resend) { perf_encoders[i]->send(); } } } @@ -513,7 +510,7 @@ bool PerfPage::handleEvent(gui_event_t *event) { } case MDX_KEY_PASTE: { if (undo < NUM_SCENES) { - return; + return true; } if (mcl_clipboard.paste_scene( &perf_encoders[perf_id]->perf_data.scenes[t])) { @@ -526,6 +523,7 @@ bool PerfPage::handleEvent(gui_event_t *event) { return true; } case MDX_KEY_CLEAR: { + char str[] = "CLEAR SCENE"; if (t == undo) { if (mcl_clipboard.paste_scene( &perf_encoders[perf_id]->perf_data.scenes[undo])) { @@ -542,7 +540,6 @@ bool PerfPage::handleEvent(gui_event_t *event) { mcl_clipboard.copy_scene( &perf_encoders[perf_id]->perf_data.scenes[t]); } - char str[] = "CLEAR SCENE"; oled_display.textbox(str, ""); MD.popup_text(str); perf_encoders[perf_id]->perf_data.clear_scene(t); diff --git a/avr/cores/megacommand/MCL/PerfPageParent.cpp b/avr/cores/megacommand/MCL/PerfPageParent.cpp index 0d291bbfd..3f05911e2 100644 --- a/avr/cores/megacommand/MCL/PerfPageParent.cpp +++ b/avr/cores/megacommand/MCL/PerfPageParent.cpp @@ -8,8 +8,6 @@ void PerfPageParent::setup() { DEBUG_PRINT_FN(); } void PerfPageParent::init() { DEBUG_PRINT_FN(); MD.set_key_repeat(0); - oled_display.clearDisplay(); - oled_display.setFont(); config_encoders(); R.Clear(); R.use_machine_param_names(); @@ -94,10 +92,5 @@ bool PerfPageParent::handleEvent(gui_event_t *event) { } } */ - if (EVENT_PRESSED(event, Buttons.BUTTON2)) { - mcl.setPage(PAGE_SELECT_PAGE); - return true; - } - return false; } diff --git a/avr/cores/megacommand/MCL/PerfSeqTrack.cpp b/avr/cores/megacommand/MCL/PerfSeqTrack.cpp new file mode 100644 index 000000000..dd99c91cd --- /dev/null +++ b/avr/cores/megacommand/MCL/PerfSeqTrack.cpp @@ -0,0 +1,29 @@ +#include "MCL_impl.h" + +void PerfSeqTrack::seq(MidiUartParent *uart_, MidiUartParent *uart2_) { + uint8_t timing_mid = get_timing_mid(); + mod12_counter++; + if (mod12_counter == timing_mid) { + mod12_counter = 0; + step_count_inc(); + } + if (count_down) { + count_down--; + if (count_down == 0) { + if (load_sound) { + for (uint8_t n = 0; n < 4; n++) { + if (perf_locks[n] != 255) { + perf_page.perf_encoders[n]->cur = perf_locks[n]; + perf_page.perf_encoders[n]->old = perf_locks[n]; + perf_page.perf_encoders[n]->send(uart_,uart2_); + //perf_page.perf_encoders[n]->resend = true; + } + perf_locks[n] = 255; + } + load_sound = 0; + } + reset(); + mod12_counter = 0; + } + } +} diff --git a/avr/cores/megacommand/MCL/PerfSeqTrack.h b/avr/cores/megacommand/MCL/PerfSeqTrack.h new file mode 100644 index 000000000..d59dd4a75 --- /dev/null +++ b/avr/cores/megacommand/MCL/PerfSeqTrack.h @@ -0,0 +1,28 @@ +/* Justin Mammarella jmamma@gmail.com 2021 */ + +#pragma once + +#include "MidiUartParent.h" +#include "SeqTrack.h" +#include "WProgram.h" +#include "GridTrack.h" + +//Ephemeral +class PerfSeqTrack : public SeqTrackBase { + +public: + + uint8_t perf_locks[4]; + + PerfSeqTrack() : SeqTrackBase() { + active = PERF_TRACK_TYPE; + init(); + } + void reset() { + memset(perf_locks,255,sizeof(perf_locks)); + SeqTrackBase::reset(); + } + + void seq(MidiUartParent *uart_, MidiUartParent *uart2_); + +}; diff --git a/avr/cores/megacommand/MCL/PerfTrack.cpp b/avr/cores/megacommand/MCL/PerfTrack.cpp index 29cb24622..6b6732219 100644 --- a/avr/cores/megacommand/MCL/PerfTrack.cpp +++ b/avr/cores/megacommand/MCL/PerfTrack.cpp @@ -8,15 +8,26 @@ void PerfTrack::transition_load(uint8_t tracknumber, SeqTrack *seq_track, uint8_t slotnumber) { DEBUG_PRINTLN("transition send"); GridTrack::transition_load(tracknumber, seq_track, slotnumber); - load_perf(); + if (mcl_actions.send_machine[slotnumber]) { + load_perf(false, seq_track); + } } uint16_t PerfTrack::calc_latency(uint8_t tracknumber) { - return 0; + uint8_t load_mute_set = 255; + + for (uint8_t n = 0; n < 4; n++) { + if ((mute_sets[1].mutes[n] & 0b1000000000000000) == 0) { + load_mute_set = n; + } + } + + return load_mute_set == 255 ? 0 : 32 * 3 * 4; // Worst case estimate, 32 parameters, 3 bytes each, 4 perf controllers. } void PerfTrack::get_perf() { - + memcpy(scenes, PerfData::scenes, sizeof(PerfScene) * NUM_SCENES); + memcpy(mute_sets,mixer_page.mute_sets, sizeof(mute_sets) + sizeof(perf_locks)); for (uint8_t n = 0; n < 4; n++) { PerfEncoder *e = perf_page.perf_encoders[n]; PerfData *d = &e->perf_data; @@ -27,17 +38,29 @@ void PerfTrack::get_perf() { encs[n].active_scene_b = e->active_scene_b; encs[n].cur = e->cur; memcpy(encs[n].name,e->name, PERF_NAME_LENGTH); + + if (!mixer_page.load_types[n][0]) { + CLEAR_BIT16(mute_sets[1].mutes[n],13); + } + if (!mixer_page.load_types[n][1]) { + CLEAR_BIT16(mute_sets[1].mutes[n],14); + } + } DEBUG_PRINTLN("get perf"); DEBUG_PRINTLN(sizeof(scenes)); - memcpy(scenes, PerfData::scenes, sizeof(PerfScene) * NUM_SCENES); - memcpy(mute_sets,mixer_page.mute_sets, sizeof(mute_sets) + sizeof(perf_locks)); + //Encode the load_mute_set value into the high bit of the corresponding ext mutes. + if (mixer_page.load_mute_set < 4) { + mute_sets[1].mutes[mixer_page.load_mute_set] &= 0b0111111111111111; + } } -void PerfTrack::load_perf() { +void PerfTrack::load_perf(bool immediate, SeqTrack *seq_track) { DEBUG_PRINTLN("load perf"); DEBUG_PRINTLN( sizeof(scenes)); + mixer_page.load_mute_set = 255; + for (uint8_t n = 0; n < 4; n++) { PerfEncoder *e = perf_page.perf_encoders[n]; PerfData *d = &e->perf_data; @@ -49,15 +72,31 @@ void PerfTrack::load_perf() { e->cur = encs[n].cur; e->old = encs[n].cur; memcpy(e->name,encs[n].name, PERF_NAME_LENGTH); + + if ((mute_sets[1].mutes[n] & 0b1000000000000000) == 0) { + mixer_page.load_mute_set = n; + } + mixer_page.load_types[n][0] = mute_sets[1].mutes[n] & 0b0010000000000000; + mixer_page.load_types[n][1] = mute_sets[1].mutes[n] & 0b0100000000000000; + mute_sets[1].mutes[n] |= 0b1110000000000000; + } memcpy(PerfData::scenes, scenes, sizeof(PerfScene) * NUM_SCENES); + memcpy(mixer_page.mute_sets, mute_sets, sizeof(mute_sets) + sizeof(perf_locks)); + if (mixer_page.load_mute_set < 4) { + mixer_page.switch_mute_set(mixer_page.load_mute_set, immediate, mixer_page.load_types[mixer_page.load_mute_set]); //Mute change is applied outside of sequencer runtime. + if (!immediate) { + PerfSeqTrack *p = (PerfSeqTrack*) seq_track; + memcpy(p->perf_locks, &perf_locks[mixer_page.load_mute_set],4); //Perf change is pre-empted at sequencer runtime. + } + } } void PerfTrack::load_immediate(uint8_t tracknumber, SeqTrack *seq_track) { DEBUG_PRINTLN("load immediate"); load_link_data(seq_track); - load_perf(); + load_perf(true, seq_track); } bool PerfTrack::store_in_grid(uint8_t column, uint16_t row, diff --git a/avr/cores/megacommand/MCL/PerfTrack.h b/avr/cores/megacommand/MCL/PerfTrack.h index e86a916b0..ce7300dcc 100644 --- a/avr/cores/megacommand/MCL/PerfTrack.h +++ b/avr/cores/megacommand/MCL/PerfTrack.h @@ -55,11 +55,12 @@ class PerfTrack : public AUXTrack, public PerfTrackData { } scenes[n].init(); } - memset(mute_sets, 0xFF, sizeof(mute_sets)); - memset(perf_locks, 255, sizeof(perf_locks)); + //memset(mute_sets, 0xFF, sizeof(mute_sets)); + //memset(perf_locks, 255, sizeof(perf_locks)); + memset(mute_sets, 0xFF, sizeof(mute_sets) + sizeof(perf_locks)); } - void load_perf(); + void load_perf(bool immediate, SeqTrack *seq_track); void get_perf(); uint16_t calc_latency(uint8_t tracknumber); diff --git a/avr/cores/megacommand/MCL/PolyPage.cpp b/avr/cores/megacommand/MCL/PolyPage.cpp index ee612006d..efaf2f5d3 100644 --- a/avr/cores/megacommand/MCL/PolyPage.cpp +++ b/avr/cores/megacommand/MCL/PolyPage.cpp @@ -8,14 +8,11 @@ void PolyPage::init() { DEBUG_PRINT_FN(); trig_interface.on(); note_interface.init_notes(); - oled_display.clearDisplay(); - oled_display.setFont(); MD.set_trigleds(mcl_cfg.poly_mask, TRIGLED_EXCLUSIVE); } void PolyPage::cleanup() { seq_ptc_page.init_poly(); - oled_display.clearDisplay(); trig_interface.off(); } @@ -47,12 +44,8 @@ void PolyPage::toggle_mask(uint8_t i) { } void PolyPage::display() { - auto oldfont = oled_display.getFont(); - oled_display.clearDisplay(); - oled_display.setFont(); - oled_display.setCursor(0, 15); oled_display.println("VOICE SELECT "); @@ -63,8 +56,6 @@ void PolyPage::display() { MD.set_trigleds(mcl_cfg.poly_mask, TRIGLED_EXCLUSIVE); } - oled_display.setFont(oldfont); - oled_display.display(); } bool PolyPage::handleEvent(gui_event_t *event) { diff --git a/avr/cores/megacommand/MCL/QuestionDialogPage.cpp b/avr/cores/megacommand/MCL/QuestionDialogPage.cpp index 6b488a804..a6a99431e 100644 --- a/avr/cores/megacommand/MCL/QuestionDialogPage.cpp +++ b/avr/cores/megacommand/MCL/QuestionDialogPage.cpp @@ -4,8 +4,6 @@ void QuestionDialogPage::init(const char* title_, const char* text_) { mcl_gui.draw_infobox(title_, text_, -1); oled_display.drawFastHLine(MCLGUI::dlg_info_x1 + 1, MCLGUI::dlg_info_y2, MCLGUI::dlg_info_w - 2, BLACK); - auto oldfont = oled_display.getFont(); - oled_display.setFont(&TomThumb); oled_display.setTextColor(WHITE); @@ -18,8 +16,6 @@ void QuestionDialogPage::init(const char* title_, const char* text_) { oled_display.drawRect(MCLGUI::dlg_info_x2 - 88, MCLGUI::dlg_info_y1 + 16, 18, 9, WHITE); oled_display.drawRect(MCLGUI::dlg_info_x2 - 57, MCLGUI::dlg_info_y1 + 16, 18, 9, WHITE); - oled_display.setFont(oldfont); - oled_display.display(); } void QuestionDialogPage::display() { diff --git a/avr/cores/megacommand/MCL/RAMPage.cpp b/avr/cores/megacommand/MCL/RAMPage.cpp index 128cca79c..c60d823c0 100644 --- a/avr/cores/megacommand/MCL/RAMPage.cpp +++ b/avr/cores/megacommand/MCL/RAMPage.cpp @@ -25,8 +25,6 @@ void RAMPage::setup() { void RAMPage::init() { DEBUG_PRINT_FN(); - oled_display.clearDisplay(); - oled_display.setFont(); trig_interface.off(); cc_link_enable = true; if (mcl_cfg.ram_page_mode == MONO) { @@ -50,7 +48,7 @@ void RAMPage::init() { R.use_icons_knob(); } -void RAMPage::cleanup() { oled_display.clearDisplay(); } +void RAMPage::cleanup() { } void RAMPage::setup_sequencer(uint8_t track) { USE_LOCK(); @@ -448,8 +446,6 @@ void RAMPage::display() { oled_display.clearDisplay(); float remain; - auto oldfont = oled_display.getFont(); - oled_display.setFont(); oled_display.setCursor(28, 24); switch (RAMPage::rec_states[page_id]) { case STATE_QUEUE: @@ -539,7 +535,8 @@ void RAMPage::display() { uint8_t w_x = 0, w_y = 2; oled_display.drawPixel(w_x + 24, w_y + 0, WHITE); - oled_display.drawCircle(w_x + 24, w_y + 0, 2, WHITE); + //oled_display.drawCircle(w_x + 24, w_y + 0, 2, WHITE); + oled_display.drawRoundRect(w_x + 22, w_y - 2, 5, 5, 1, WHITE); oled_display.drawLine(w_x + 12, w_y - 1, w_x + 24, w_y - 3, WHITE); oled_display.drawLine(w_x + 17, w_y + 15, w_x + 26, w_y + 2, WHITE); @@ -611,8 +608,6 @@ void RAMPage::display() { } wheel_spin_last_clock = MidiClock.div16th_counter; } - oled_display.display(); - oled_display.setFont(oldfont); } void RAMPage::onControlChangeCallback_Midi(uint8_t track, uint8_t track_param, uint8_t value) { @@ -752,11 +747,6 @@ bool RAMPage::handleEvent(gui_event_t *event) { } } - if (EVENT_PRESSED(event, Buttons.BUTTON2)) { - mcl.setPage(PAGE_SELECT_PAGE); - return true; - } - return false; } diff --git a/avr/cores/megacommand/MCL/RoutePage.cpp b/avr/cores/megacommand/MCL/RoutePage.cpp index adc59edb5..93e131f7f 100644 --- a/avr/cores/megacommand/MCL/RoutePage.cpp +++ b/avr/cores/megacommand/MCL/RoutePage.cpp @@ -97,7 +97,6 @@ void RoutePage::toggle_routes_batch(bool solo) { void RoutePage::display() { uint8_t x; - auto *oldfont = oled_display.getFont(); oled_display.clearDisplay(); oled_display.drawBitmap(0, 0, R.icons_page->icon_route, 24, 14, WHITE); @@ -127,8 +126,6 @@ void RoutePage::display() { mcl_gui.draw_panel_labels("ROUTE", info_line2); draw_routes(); - oled_display.display(); - oled_display.setFont(oldfont); } bool RoutePage::handleEvent(gui_event_t *event) { @@ -163,10 +160,6 @@ bool RoutePage::handleEvent(gui_event_t *event) { // mcl.setPage(MIXER_PAGE); // return true; //} - if (EVENT_PRESSED(event, Buttons.BUTTON2)) { - mcl.setPage(PAGE_SELECT_PAGE); - return true; - } /* if (EVENT_PRESSED(event, Buttons.ENCODER1) || EVENT_PRESSED(event, Buttons.ENCODER2) || diff --git a/avr/cores/megacommand/MCL/SampleBrowserPage.cpp b/avr/cores/megacommand/MCL/SampleBrowserPage.cpp index 16f8c8d3c..a3ab78017 100644 --- a/avr/cores/megacommand/MCL/SampleBrowserPage.cpp +++ b/avr/cores/megacommand/MCL/SampleBrowserPage.cpp @@ -20,6 +20,7 @@ void SampleBrowserPage::setup() { } void SampleBrowserPage::display() { + oled_display.setFont(&TomThumb); if (filemenu_active) { draw_menu(); return; @@ -71,7 +72,7 @@ void SampleBrowserPage::display() { oled_display.print(F(":")); oled_display.print(ms); */ - uint32_t size = wav_file.file.size(); + size = wav_file.file.size(); wav_file.close(); } else if (is_syx) { @@ -95,7 +96,6 @@ void SampleBrowserPage::display() { FileBrowserPage::selection_change = false; end: draw_filebrowser(); - oled_display.display(); } void SampleBrowserPage::init(uint8_t show_samplemgr_) { @@ -267,11 +267,6 @@ bool SampleBrowserPage::handleEvent(gui_event_t *event) { return true; } - if (EVENT_PRESSED(event, Buttons.BUTTON1)) { - mcl.setPage(PAGE_SELECT_PAGE); - return true; - } - return FileBrowserPage::handleEvent(event); } @@ -351,7 +346,7 @@ bool SampleBrowserPage::_handle_filemenu() { return true; case FM_SENDALL: if (!mcl_gui.wait_for_confirm("Send all", "Overwrite?")) { - return; + return true; } char wav_name[FILE_ENTRY_SIZE] = ""; for (uint8_t n = 0; n < numEntries && !trig_interface.is_key_down(MDX_KEY_NO); n++) { diff --git a/avr/cores/megacommand/MCL/SeqExtStepPage.cpp b/avr/cores/megacommand/MCL/SeqExtStepPage.cpp index 80326ea33..0644d2e33 100644 --- a/avr/cores/megacommand/MCL/SeqExtStepPage.cpp +++ b/avr/cores/megacommand/MCL/SeqExtStepPage.cpp @@ -804,7 +804,6 @@ void SeqExtStepPage::display() { } // oled_display.fillRect(draw_x, 0, 1 , fov_h, WHITE); - oled_display.display(); #endif } diff --git a/avr/cores/megacommand/MCL/SeqExtStepPage.h b/avr/cores/megacommand/MCL/SeqExtStepPage.h index 72bed3785..340754bc6 100644 --- a/avr/cores/megacommand/MCL/SeqExtStepPage.h +++ b/avr/cores/megacommand/MCL/SeqExtStepPage.h @@ -73,21 +73,20 @@ class SeqExtStepPage : public SeqPage { void pos_cur_y(int16_t diff); void pos_cur_w(int16_t diff); - bool is_within_fov(int16_t x) { - if ((x >= fov_offset) && (x < fov_offset + fov_length)) { - return true; - } - return false; + inline bool is_within_fov(int16_t x) { + return (x - fov_offset) < fov_length; } + bool is_within_fov(int16_t start_x, int16_t end_x) { - if (is_within_fov(start_x) || is_within_fov(end_x) || - ((start_x < fov_offset) && (end_x >= fov_offset + fov_length)) || - (end_x < start_x && - !((start_x > fov_offset + fov_length) && end_x < fov_offset))) { - return true; + int16_t fov_end = fov_offset + fov_length; + // Handle wrap-around case + if (end_x < start_x) { + return (start_x < fov_end) || (end_x >= fov_offset); } - return false; + // Normal case + return (start_x < fov_end) && (end_x >= fov_offset); } + void param_select_update(); void enter_notes(); void config_menu_entries(); diff --git a/avr/cores/megacommand/MCL/SeqPage.cpp b/avr/cores/megacommand/MCL/SeqPage.cpp index d1f60a65d..e6ba45983 100644 --- a/avr/cores/megacommand/MCL/SeqPage.cpp +++ b/avr/cores/megacommand/MCL/SeqPage.cpp @@ -30,6 +30,8 @@ uint16_t SeqPage::mute_mask = 0; uint8_t SeqPage::step_select = 255; +bool SeqPage::is_midi_model = false; + uint32_t SeqPage::last_md_model = 255; uint8_t opt_speed = 1; @@ -108,8 +110,6 @@ void SeqPage::init() { config_encoders(); seqpage_midi_events.setup_callbacks(); - oled_display.clearDisplay(); - toggle_device = true; DEBUG_PRINTLN("seq page init"); @@ -207,12 +207,12 @@ void SeqPage::toggle_ext_mask(uint8_t track) { if (track > 6) { track -= 8; if (track >= mcl_seq.num_ext_tracks) { - return true; + return; } mcl_seq.ext_tracks[track].toggle_mute(); } else { if (track >= mcl_seq.num_ext_tracks) { - return true; + return; } MidiDevice *dev = midi_active_peering.get_device(UART2_PORT); midi_device = dev; @@ -232,6 +232,7 @@ void SeqPage::select_track(MidiDevice *device, uint8_t track, bool send) { DEBUG_PRINTLN(track); if (track >= NUM_MD_TRACKS) { return; } last_md_track = track; + is_midi_model = ((MD.kit.models[last_md_track] & 0xF0) == MID_01_MODEL); auto &active_track = mcl_seq.md_tracks[last_md_track]; MD.sync_seqtrack(active_track.length, active_track.speed, active_track.step_count); @@ -288,33 +289,6 @@ bool SeqPage::display_mute_mask(MidiDevice* device, uint8_t offset) { bool SeqPage::handleEvent(gui_event_t *event) { - if (note_interface.is_event(event)) { - uint8_t port = event->port; - MidiDevice *device = midi_active_peering.get_device(port); - - uint8_t track = event->source - 128; - - //Removing this block causes progmem to balloon by 1K ?? - if (BUTTON_DOWN(Buttons.BUTTON4)) { - // calculate the intended seq length. - uint8_t step = track; - step += 1 + page_select * 16; - encoders[2]->cur = step; - note_interface.ignoreNextEvent(track); - if (event->mask == EVENT_BUTTON_RELEASED) { - note_interface.clear_note(track); - } - GUI.ignoreNextEvent(Buttons.BUTTON4); - if (BUTTON_DOWN(Buttons.BUTTON3)) { - GUI.ignoreNextEvent(Buttons.BUTTON3); - } - - return true; - } - // notify derived class about unhandled TI event - return false; - } // end TI events - if (EVENT_CMD(event)) { if (trig_interface.is_key_down(MDX_KEY_PATSONG)) { return seq_menu_page.handleEvent(event); @@ -353,10 +327,6 @@ bool SeqPage::handleEvent(gui_event_t *event) { return true; } - if (EVENT_PRESSED(event, Buttons.BUTTON2)) { - mcl.setPage(PAGE_SELECT_PAGE); - } - if (EVENT_PRESSED(event, Buttons.BUTTON3)) { // If MD trig is held and BUTTON3 is pressed, launch note menu if (!show_seq_menu) { @@ -392,9 +362,9 @@ bool SeqPage::handleEvent(gui_event_t *event) { if (show_seq_menu) { row_func = seq_menu_page.menu.get_row_function(seq_menu_page.encoders[1]->cur); - MidiDevice* old_dev = opt_midi_device_capture; - opt_midi_device_capture = midi_active_peering.get_device(mcl_cfg.seq_dev); - if (old_dev == opt_midi_device_capture) { + MidiDevice* old_dev = midi_device; + midi_device = midi_active_peering.get_device(mcl_cfg.seq_dev); + if (old_dev == midi_device) { opt_speed_handler(); opt_length_handler(); opt_channel_handler(); @@ -530,7 +500,7 @@ void SeqPage::draw_knob_conditional(uint8_t cond) { conditional_str(K, cond); draw_knob(0, "COND", K); } - +/* void SeqPage::conditional_str(char *str, uint8_t cond, bool is_md) { if (cond == 0) { strcpy(str, "L1"); @@ -558,6 +528,32 @@ void SeqPage::conditional_str(char *str, uint8_t cond, bool is_md) { } } } +*/ +void SeqPage::conditional_str(char *str, uint8_t cond, bool is_md) { + if (str == nullptr) return; + + if (cond == 0) { + str[0] = 'L'; str[1] = '1'; str[2] = '\0'; + } else { + if (cond > NUM_TRIG_CONDITIONS) { + cond -= NUM_TRIG_CONDITIONS; + } + + if (cond <= 8) { + str[0] = 'L'; str[1] = cond + '0'; str[2] = '\0'; + } else if (cond <= 13) { + static const uint8_t prob[5] = {1, 2, 5, 7, 9}; + str[0] = 'P'; str[1] = prob[cond - 9] + '0'; str[2] = '\0'; + } else if (cond == 14) { + str[0] = '1'; str[1] = 'S'; str[2] = '\0'; + } + + if (seq_param1.getValue() > NUM_TRIG_CONDITIONS) { + str[2] = is_md ? '+' : '^'; + str[3] = '\0'; + } + } +} void SeqPage::draw_knob_timing(uint8_t timing, uint8_t timing_mid) { char K[4]; diff --git a/avr/cores/megacommand/MCL/SeqPage.h b/avr/cores/megacommand/MCL/SeqPage.h index a6d79f966..5bc94607f 100644 --- a/avr/cores/megacommand/MCL/SeqPage.h +++ b/avr/cores/megacommand/MCL/SeqPage.h @@ -100,6 +100,7 @@ class SeqPage : public LightPage { static uint8_t last_rec_event; static uint8_t last_step; static uint32_t last_md_model; + static bool is_midi_model; static bool recording; static uint16_t mute_mask; diff --git a/avr/cores/megacommand/MCL/SeqPtcPage.cpp b/avr/cores/megacommand/MCL/SeqPtcPage.cpp index cd0cde79b..9a2f3fa01 100644 --- a/avr/cores/megacommand/MCL/SeqPtcPage.cpp +++ b/avr/cores/megacommand/MCL/SeqPtcPage.cpp @@ -208,8 +208,6 @@ void SeqPtcPage::render_arp(bool recalc_notemask_, MidiDevice *midi_dev, void SeqPtcPage::display() { oled_display.clearDisplay(); - auto *oldfont = oled_display.getFont(); - bool is_poly = IS_BIT_SET16(mcl_cfg.poly_mask, last_md_track); draw_knob_frame(); char buf1[4]; @@ -274,8 +272,6 @@ void SeqPtcPage::display() { if (show_seq_menu) { display_mute_mask(midi_active_peering.get_device(UART2_PORT), 8); } - oled_display.display(); - oled_display.setFont(oldfont); } uint8_t SeqPtcPage::calc_scale_note(uint8_t note_num, bool padded) { @@ -415,7 +411,17 @@ void SeqPtcPage::trig_md(uint8_t note_num, uint8_t track_number, uint8_t channel } uint8_t next_track = get_next_voice(note_num, track_number, channel_event); + if (next_track > 15) { return; } + uint8_t machine_pitch = get_machine_pitch(next_track, note_num, fine_tune); + bool is_midi_model_ = ((MD.kit.models[track_number] & 0xF0) == MID_01_MODEL); + if (is_midi_model_) { + machine_pitch = note_num; + next_track = track_number; + mcl_seq.md_tracks[next_track].send_notes_off(); + mcl_seq.md_tracks[next_track].send_notes(machine_pitch); + goto rec; + } if (machine_pitch == 255) { return; } @@ -423,14 +429,18 @@ void SeqPtcPage::trig_md(uint8_t note_num, uint8_t track_number, uint8_t channel MD.setTrackParam(next_track, 0, machine_pitch, uart_); MD.triggerTrack(next_track, 127, uart_); mixer_page.trig(next_track); + rec: + record(machine_pitch, next_track); +} +void SeqPtcPage::record(uint8_t pitch, uint8_t track) { if ((recording) && (MidiClock.state == 2)) { reset_undo(); - mcl_seq.md_tracks[next_track].record_track(127); - mcl_seq.md_tracks[next_track].record_track_pitch(machine_pitch); + mcl_seq.md_tracks[track].record_track(127); + mcl_seq.md_tracks[track].record_track_pitch(pitch); } -} +} void SeqPtcPage::note_on_ext(uint8_t note_num, uint8_t velocity, uint8_t track_number, MidiUartParent *uart_) { if (track_number == 255) { @@ -747,7 +757,13 @@ void SeqPtcMidiEvents::note_on(uint8_t *msg, uint8_t channel_event) { if (pos > 15) { return; } - MD.triggerTrack(pos, msg[2]); + bool is_midi_model_ = ((MD.kit.models[pos] & 0xF0) == MID_01_MODEL);; + if (is_midi_model_) { + mcl_seq.md_tracks[pos].send_notes_on(); + } + else { + MD.triggerTrack(pos, msg[2]); + } if ((seq_ptc_page.recording) && (MidiClock.state == 2)) { reset_undo(); mcl_seq.md_tracks[pos].record_track(msg[2]); @@ -814,7 +830,14 @@ void SeqPtcMidiEvents::note_off(uint8_t *msg, uint8_t channel_event) { pitch = seq_ptc_page.process_ext_event(note_num, false, channel); uint8_t n = seq_ptc_page.find_arp_track(channel_event); seq_ptc_page.render_arp(false, SeqPage::midi_device, n); - + if (pitch == 255) { return; } + ArpSeqTrack *arp_track = &mcl_seq.md_arp_tracks[n]; + bool is_midi_model_ = ((MD.kit.models[n] & 0xF0) == MID_01_MODEL); + if (is_midi_model_) { + if (!arp_track->enabled || (MidiClock.state != 2)) { + mcl_seq.md_tracks[n].send_notes_off(); + } + } return; } diff --git a/avr/cores/megacommand/MCL/SeqPtcPage.h b/avr/cores/megacommand/MCL/SeqPtcPage.h index ad4f676c0..bb6b0d21c 100644 --- a/avr/cores/megacommand/MCL/SeqPtcPage.h +++ b/avr/cores/megacommand/MCL/SeqPtcPage.h @@ -71,7 +71,7 @@ class SeqPtcPage : public SeqPage, public ClockCallback { uint8_t fine_tune = 255); uint8_t get_next_voice(uint8_t pitch, uint8_t track_number, uint8_t channel_event); uint8_t calc_scale_note(uint8_t note_num, bool padded = false); - + void record(uint8_t pitch, uint8_t tracknumber); void trig_md(uint8_t note_num, uint8_t track_number = 255, uint8_t channel_event = CTRL_EVENT, uint8_t fine_tune = 255, MidiUartParent *uart_ = nullptr); diff --git a/avr/cores/megacommand/MCL/SeqStepPage.cpp b/avr/cores/megacommand/MCL/SeqStepPage.cpp index acea62933..83d411e26 100644 --- a/avr/cores/megacommand/MCL/SeqStepPage.cpp +++ b/avr/cores/megacommand/MCL/SeqStepPage.cpp @@ -6,11 +6,15 @@ void SeqStepPage::setup() { SeqPage::setup(); } void SeqStepPage::config() { + bool is_midi_model = ((MD.kit.models[last_md_track] & 0xF0) == MID_01_MODEL); tuning_t const *tuning = MD.getKitModelTuning(last_md_track); if (tuning) { seq_param4.max = tuning->len - 1 + tuning->base; - } else { + } else if (is_midi_model) { + seq_param4.max = 127; + } + else { seq_param4.max = 1; } seq_param4.cur = 0; @@ -113,7 +117,6 @@ void SeqStepPage::cleanup() { void SeqStepPage::display() { oled_display.clearDisplay(); - auto *oldfont = oled_display.getFont(); draw_knob_frame(); uint8_t timing_mid = mcl_seq.md_tracks[last_md_track].get_timing_mid(); @@ -130,8 +133,9 @@ void SeqStepPage::display() { draw_knob(2, "LEN", K); } tuning_t const *tuning = MD.getKitModelTuning(last_md_track); + bool is_ptc = ((MD.kit.models[last_md_track] & 0xF0) == MID_01_MODEL) || tuning != NULL; if (show_pitch) { - if (tuning != NULL) { + if (is_ptc) { strcpy(K, "--"); if (seq_param4.cur != 0) { // uint8_t base = tuning->base; @@ -151,7 +155,7 @@ void SeqStepPage::display() { if (mcl_gui.show_encoder_value(&seq_param4) && (seq_param4.cur > 0) && (note_interface.notes_count_on() > 0) && (!show_seq_menu) && - (tuning != NULL) && !(recording)) { + (is_ptc) && !(recording)) { uint64_t note_mask[2] = {}; uint8_t note = seq_param4.cur; // + tuning->base; SET_BIT64(note_mask, note); @@ -181,8 +185,6 @@ void SeqStepPage::display() { page_select_page.md_prepare(); prepare = false; } - oled_display.display(); - oled_display.setFont(oldfont); } void SeqStepPage::loop() { @@ -243,12 +245,12 @@ void SeqStepPage::loop() { break; } if (seq_param4.hasChanged() && (seq_param4.cur > 0) && - (last_md_track < NUM_MD_TRACKS) && (tuning != NULL)) { + (last_md_track < NUM_MD_TRACKS) && (tuning != NULL || is_midi_model)) { uint8_t base = tuning->base; uint8_t note_num = seq_param4.cur; uint8_t machine_pitch = seq_ptc_page.get_machine_pitch(last_md_track, note_num); - + if (is_midi_model) { machine_pitch = note_num; } if (machine_pitch != MD.kit.params[last_md_track][0]) { active_track.set_track_pitch(step, machine_pitch); seq_step_page.encoders_used_clock[3] = slowclock; // indicate that encoder has changed. @@ -376,8 +378,11 @@ bool SeqStepPage::handleEvent(gui_event_t *event) { pitch_param = 255; } else if (tuning) { */ - if (tuning) { + if (tuning || is_midi_model) { uint8_t note_num = seq_ptc_page.get_note_from_machine_pitch(pitch); + if (is_midi_model) { + note_num = pitch; + } if (note_num == 255) { seq_param4.cur = 0; } else { @@ -408,7 +413,7 @@ bool SeqStepPage::handleEvent(gui_event_t *event) { show_pitch = false; if (IS_BIT_SET16(ignore_release, track)) { CLEAR_BIT16(ignore_release, track); - return; + return true; } if (step >= active_track.length) { return true; diff --git a/avr/cores/megacommand/MCL/SeqTrack.cpp b/avr/cores/megacommand/MCL/SeqTrack.cpp index e605c1895..2f5540208 100644 --- a/avr/cores/megacommand/MCL/SeqTrack.cpp +++ b/avr/cores/megacommand/MCL/SeqTrack.cpp @@ -73,6 +73,12 @@ void SeqSlideTrack::prepare_slide(uint8_t lock_idx, int16_t x0, int16_t x1, int8 } void SeqSlideTrack::send_slides(volatile uint8_t *locks_params, uint8_t channel) { + uint8_t ccs[midi_cc_array_size]; + bool send_ccs = false; + bool is_midi_model = (MD.kit.models[track_number] & 0xF0) == MID_01_MODEL; + if (is_midi_model) { + memset(ccs, 255, sizeof(ccs)); + } for (uint8_t c = 0; c < NUM_LOCKS; c++) { if ((locks_params[c] > 0) && (locks_slide_data[c].dy > 0)) { @@ -110,7 +116,14 @@ void SeqSlideTrack::send_slides(volatile uint8_t *locks_params, uint8_t channel) uint8_t param = locks_params[c] - 1; switch (active) { case MD_TRACK_TYPE: - MD.setTrackParam_inline(track_number, param, val); + if (is_midi_model) { + uint8_t p = param; + send_ccs |= (p > 4 && p < 8) | (p > 8) && (p & 1) | (p == 20); + mcl_seq.md_tracks[track_number].process_note_locks(p, val, ccs, true); + } + else { + MD.setTrackParam_inline(track_number, param, val); + } break; default: if (param == PARAM_PB) { @@ -126,6 +139,9 @@ void SeqSlideTrack::send_slides(volatile uint8_t *locks_params, uint8_t channel) } } } + if (is_midi_model) { + mcl_seq.md_tracks[track_number].send_notes_ccs(ccs, send_ccs); + } } uint8_t SeqTrackBase::get_quantized_step(uint8_t &utiming, uint8_t quant) { @@ -230,3 +246,4 @@ bool SeqTrack::conditional(uint8_t condition) { } return send_note; } + diff --git a/avr/cores/megacommand/MCL/SeqTrack.h b/avr/cores/megacommand/MCL/SeqTrack.h index c74d31afb..f894f2d2c 100644 --- a/avr/cores/megacommand/MCL/SeqTrack.h +++ b/avr/cores/megacommand/MCL/SeqTrack.h @@ -69,6 +69,7 @@ class SeqTrackBase { uint8_t port = UART1_PORT; MidiUartParent *uart = &MidiUart; + MidiUartParent *uart2 = &MidiUart2; uint8_t mute_state = SEQ_MUTE_OFF; bool record_mutes; @@ -349,6 +350,9 @@ class SeqSlideTrack : public SeqTrack { uint8_t locks_slides_recalc = 255; uint16_t locks_slides_idx = 0; + const uint8_t number_midi_cc = 6 * 2 + 4; + const uint8_t midi_cc_array_size = 6 * 2 + 4; + ALWAYS_INLINE() void reset() { for (uint8_t n = 0; n < NUM_LOCKS; n++) { locks_slide_data[n].init(); @@ -360,6 +364,7 @@ class SeqSlideTrack : public SeqTrack { void prepare_slide(uint8_t lock_idx, int16_t x0, int16_t x1, int8_t y0, int8_t y1); void send_slides(volatile uint8_t *locks_params, uint8_t channel = 0); + }; #endif /* SEQTRACK_H__ */ diff --git a/avr/cores/megacommand/MCL/SoundBrowserPage.cpp b/avr/cores/megacommand/MCL/SoundBrowserPage.cpp index e568ad65f..9cd1bea14 100644 --- a/avr/cores/megacommand/MCL/SoundBrowserPage.cpp +++ b/avr/cores/megacommand/MCL/SoundBrowserPage.cpp @@ -38,7 +38,6 @@ void SoundBrowserPage::init() { void SoundBrowserPage::save_sound() { MDSound sound; - grid_page.prepare(); char sound_name[8]; uint8_t l = min(strlen(MD.kit.name),4); memcpy(sound_name, MD.kit.name, l); @@ -63,7 +62,6 @@ void SoundBrowserPage::save_sound() { void SoundBrowserPage::load_sound() { - grid_page.prepare(); if (file.isOpen()) { char temp_entry[FILE_ENTRY_SIZE]; MDSound sound; diff --git a/avr/cores/megacommand/MCL/TextInputPage.cpp b/avr/cores/megacommand/MCL/TextInputPage.cpp index ac61831e9..ea263efed 100644 --- a/avr/cores/megacommand/MCL/TextInputPage.cpp +++ b/avr/cores/megacommand/MCL/TextInputPage.cpp @@ -36,6 +36,7 @@ void TextInputPage::init_text(char *text_, const char *title_, uint8_t len) { title = title_; length = len; max_length = len; + memset(text,0,sizeof(text)); strncpy(text, text_, len); //Replace null characeters with space, it will be added back in upon exit. bool after = false; @@ -145,9 +146,7 @@ void TextInputPage::display_normal() { auto time = clock_diff(last_clock, slowclock); // mcl_gui.clear_popup(); <-- E_TOOSLOW - auto oldfont = oled_display.getFont(); oled_display.fillRect(s_text_x, s_text_y, 6 * length, 8, BLACK); - oled_display.setFont(); oled_display.setCursor(s_text_x, s_text_y); oled_display.println(text); if (time < FLASH_SPEED) { @@ -162,7 +161,6 @@ void TextInputPage::display_normal() { if (time > FLASH_SPEED * 2) { last_clock = slowclock; } - oled_display.setFont(oldfont); } void TextInputPage::display_charpane() { @@ -198,7 +196,6 @@ void TextInputPage::display() { else display_charpane(); - oled_display.display(); } bool TextInputPage::handleEvent(gui_event_t *event) { diff --git a/avr/cores/megacommand/MCL/WavDesigner.cpp b/avr/cores/megacommand/MCL/WavDesigner.cpp index 55780ddda..0e7ad8d97 100644 --- a/avr/cores/megacommand/MCL/WavDesigner.cpp +++ b/avr/cores/megacommand/MCL/WavDesigner.cpp @@ -84,7 +84,7 @@ bool WavDesigner::render() { uint32_t pos = 0; bool write_header = false; - float max_sine_gain = (float)1 / (float)16; + float max_sine_gain = 0.0004921259843f; ; //(float)1 / (float)16) / 127; // Zero crossing detection vars bool zero_crossing_found = false; @@ -110,8 +110,7 @@ bool WavDesigner::render() { // pages[i].get_freq() * (float) h, 0); if (pages[i].sine_levels[h - 1] != 0) { float sine_gain = - ((float)pages[i].sine_levels[h - 1] / (float)127) * - max_sine_gain; + ((float)pages[i].sine_levels[h - 1]) * max_sine_gain; osc_sample += sine_osc.get_sample(n, pages[i].get_freq() * (float)h) * @@ -239,7 +238,7 @@ bool WavDesigner::render() { } bool WavDesigner::send() { - return midi_sds.sendWav(WAV_NAME, mixer.enc4.cur, false); + return midi_sds.sendWav(WAV_NAME, WAV_NAME, mixer.enc4.cur, false); } WavDesigner wd; diff --git a/avr/cores/megacommand/MCL/WavDesignerPage.cpp b/avr/cores/megacommand/MCL/WavDesignerPage.cpp index b0df7aeea..73f653c44 100644 --- a/avr/cores/megacommand/MCL/WavDesignerPage.cpp +++ b/avr/cores/megacommand/MCL/WavDesignerPage.cpp @@ -21,7 +21,7 @@ void wavdesign_menu_handler() { if (WavDesignerPage::opt_mode == 3) { mcl.setPage(WD_MIXER_PAGE); } else { - mcl.setPage(WD_PAGE_0 + WavDesignerPage::opt_mode); + mcl.setPage((PageIndex) (WD_PAGE_0 + WavDesignerPage::opt_mode)); } } @@ -96,10 +96,6 @@ bool WavDesignerPage::handleEvent(gui_event_t *event) { } return true; } - if (EVENT_PRESSED(event, Buttons.BUTTON2)) { - mcl.setPage(PAGE_SELECT_PAGE); - return true; - } return false; } diff --git a/avr/cores/megacommand/MD/MD.cpp b/avr/cores/megacommand/MD/MD.cpp index dbebeadf4..19632dda5 100644 --- a/avr/cores/megacommand/MD/MD.cpp +++ b/avr/cores/megacommand/MD/MD.cpp @@ -174,7 +174,7 @@ void MDClass::init_grid_devices(uint8_t device_idx) { add_track_to_grid(grid_idx, MDTEMPO_TRACK_NUM, &gdt); gdt.init(PERF_TRACK_TYPE, GROUP_PERF, device_idx, - (SeqTrack *)&(mcl_seq.aux_tracks[3]), 0); + (SeqTrack *)&(mcl_seq.perf_track), 0); add_track_to_grid(grid_idx, PERF_TRACK_NUM, &gdt); } @@ -211,7 +211,7 @@ bool MDClass::probe() { ((uint16_t)FW_CAP_MASTER_FX | (uint16_t)FW_CAP_TRIG_LEDS | (uint16_t)FW_CAP_UNDOKIT_SYNC | (uint16_t)FW_CAP_TONAL | (uint16_t)FW_CAP_ENHANCED_GUI | (uint16_t)FW_CAP_ENHANCED_MIDI) | - (uint16_t)FW_CAP_MACHINE_CACHE | (uint16_t)FW_CAP_UNDO_CACHE; + (uint16_t)FW_CAP_MACHINE_CACHE | (uint16_t)FW_CAP_UNDO_CACHE | (uint16_t)FW_CAP_MID_MACHINE; while ((!get_fw_caps() || ((fw_caps & fw_caps_mask) != fw_caps_mask)) && count) { @@ -235,13 +235,15 @@ bool MDClass::probe() { mcl_gui.delay_progress(300); getCurrentTrack(CALLBACK_TIMEOUT); getBlockingKit(0x7F); + MD.save_kit_params(); setup(); - for (uint8_t x = 0; x < 2; x++) { - for (uint8_t y = 0; y < 16; y++) { - mcl_gui.draw_progress_bar(60, 60, false, 60, 25); - setStatus(0x22, y); - } + uint8_t y = 0; + for (uint8_t i = 0; i < 32; i++) { + mcl_gui.draw_progress_bar(60, 60, false, 60, 25); + setStatus(0x22, y); + y++; + if (y == 16) y = 0; } setStatus(0x22, currentTrack); @@ -274,16 +276,11 @@ MCLGIF *MDClass::gif() { return R.icons_logo->machinedrum_gif; } uint8_t *MDClass::gif_data() { return R.icons_logo->machinedrum_gif_data; } uint8_t MDClass::noteToTrack(uint8_t pitch) { - uint8_t i; - if (MD.loadedGlobal) { - for (i = 0; i < sizeof(MD.global.drumMapping); i++) { - if (pitch == MD.global.drumMapping[i]) + for (uint8_t i = 0; i < sizeof(MD.global.drumMapping); i++) { + if (pitch == MD.global.drumMapping[i]) return i; } - return 128; - } else { - return 128; - } + return 128; } void MDClass::parseCC(uint8_t channel, uint8_t cc, uint8_t *track, @@ -368,8 +365,15 @@ void MDClass::parallelTrig(uint16_t mask, MidiUartParent *uart_) { } } +void MDClass::save_kit_params() { + memcpy(kit.params_orig, kit.params, sizeof(kit.params)); + memcpy(kit.fx_orig, kit.reverb, sizeof(kit.reverb) * 4); +} + + void MDClass::restore_kit_params() { memcpy(kit.params, kit.params_orig, sizeof(kit.params)); + memcpy(kit.reverb, kit.fx_orig, sizeof(kit.reverb) * 4); } void MDClass::restore_kit_param(uint8_t track, uint8_t param) { @@ -858,11 +862,7 @@ void MDClass::getPatternName(uint8_t pattern, char str[5]) { } bool MDClass::checkParamSettings() { - if (loadedGlobal) { - return (MD.global.baseChannel <= 12); - } else { - return false; - } + return (MD.global.baseChannel <= 12); } bool MDClass::checkTriggerSettings() { return false; } diff --git a/avr/cores/megacommand/MD/MD.h b/avr/cores/megacommand/MD/MD.h index 71f9374aa..8d224b5f2 100644 --- a/avr/cores/megacommand/MD/MD.h +++ b/avr/cores/megacommand/MD/MD.h @@ -115,6 +115,7 @@ class MDClass : public ElektronDevice { /* Restore modified kit params, with the original values. */ void restore_kit_params(); + void save_kit_params(); /* Restore a single kit param, and transmit the param to the MD */ void restore_kit_param(uint8_t track, uint8_t param); diff --git a/avr/cores/megacommand/MD/MDMessages.cpp b/avr/cores/megacommand/MD/MDMessages.cpp index b73ddc256..3d5b3f239 100644 --- a/avr/cores/megacommand/MD/MDMessages.cpp +++ b/avr/cores/megacommand/MD/MDMessages.cpp @@ -9,8 +9,6 @@ #define MDX_KIT_VERSION 64 -uint8_t lfo_statestore[31]; - void MDMachine::scale_vol(float scale) { params[MODEL_VOL] = (uint8_t)((float)params[MODEL_VOL] * scale); if (params[MODEL_VOL] > 127) { @@ -206,8 +204,7 @@ bool MDKit::fromSysex(MidiClass *midi) { decoder.start7Bit(); for (uint8_t i = 0; i < 16; i++) { - decoder.get((uint8_t *)&lfos[i], 5); - decoder.get((uint8_t *)&lfo_statestore, 31); + decoder.get((uint8_t *)&lfos[i], 5 + 31); } decoder.stop7Bit(); @@ -264,9 +261,9 @@ uint16_t MDKit::toSysex(ElektronDataToSysexEncoder *encoder) { encoder->start7Bit(); for (uint8_t i = 0; i < 16; i++) { // encoder->pack((uint8_t *)&lfos[i], 36); - - encoder->pack((uint8_t *)&lfos[i], 5); - encoder->pack((uint8_t *)&lfo_statestore[i], 31); + uint16_t *lfo_states2 = (uint16_t *) &lfos[i].state[5 + 18]; + if (!lfo_states2[0] && !lfo_states2[1]) { lfo_states2[1] = 0x29a; } //666 + encoder->pack((uint8_t *)&lfos[i], 5 + 31); } encoder->stop7Bit(); diff --git a/avr/cores/megacommand/MD/MDMessages.h b/avr/cores/megacommand/MD/MDMessages.h index 1e36fc7b1..5c7825367 100644 --- a/avr/cores/megacommand/MD/MDMessages.h +++ b/avr/cores/megacommand/MD/MDMessages.h @@ -161,17 +161,11 @@ class MDLFO { uint8_t mix; void init(uint8_t track) { - destinationTrack = track; - destinationParam = 0; - shape1 = 0; - shape2 = 0; - type = 0; - for (uint8_t i = 0; i < 31; i++) { - state[i] = i; - } - speed = 64; - depth = 0; - mix = 0; + memset(&destinationTrack,0,sizeof(this)); + destinationTrack = track; + speed = 64; + uint16_t *lfo_states2 = (uint16_t *) &state[5 + 18]; + lfo_states2[1] = 0x29a; //666 } /* @} */ }; @@ -245,7 +239,6 @@ class MDKit: public ElektronSysexObject { uint32_t models[16]; /** The LFO settings for each track. **/ MDLFO lfos[16]; - /** The settings of the reverb effect. **/ uint8_t reverb[8]; /** The settings of the delay effect. **/ @@ -254,7 +247,8 @@ class MDKit: public ElektronSysexObject { uint8_t eq[8]; /** The settings of the compressor effect. **/ uint8_t dynamics[8]; - + /** Duplicate fx params not included in the origin MD structure */ + uint8_t fx_orig[4][9]; /** The trig group selected for each track (255: OFF). **/ uint8_t trigGroups[16]; /** The mute group selected for each track (255: OFF). **/ @@ -279,7 +273,23 @@ class MDKit: public ElektronSysexObject { uint8_t get_model(uint8_t track); bool get_tonal(uint8_t track); - + uint8_t get_fx_param(uint8_t fx, uint8_t param) { + uint8_t ret = 255; + switch (fx) { + case MD_FX_ECHO: + ret = delay[param]; + break; + case MD_FX_DYN: + ret = dynamics[param]; + break; + case MD_FX_REV: + ret = reverb[param]; + break; + case MD_FX_EQ: + ret = eq[param]; + } + return ret; + } /* @} */ }; diff --git a/avr/cores/megacommand/MD/MDPattern.cpp b/avr/cores/megacommand/MD/MDPattern.cpp index ad2e07ed1..86b8db9a6 100644 --- a/avr/cores/megacommand/MD/MDPattern.cpp +++ b/avr/cores/megacommand/MD/MDPattern.cpp @@ -12,7 +12,6 @@ #endif // #include "GUI.h" - void MDPattern::clearPattern() { numRows = 0; @@ -21,9 +20,8 @@ void MDPattern::clearPattern() { memset(&accentPatterns, 0, 8 * 3 * 16 + 1); memset(paramLocks, -1, sizeof(paramLocks)); - memset(lockTracks, -1, sizeof(lockTracks)); - memset(lockParams, -1, sizeof(lockParams)); - memset(locks, -1, sizeof(locks)); + + memset(locks, -1, sizeof(locks) + sizeof(lockTracks) + sizeof(lockParams)); // accentPattern = 0; // slidePattern = 0; @@ -40,7 +38,7 @@ void MDPattern::clearPattern() { // kit = 0; // scale = 0; } - +/* void MDPattern::clear_step_locks(uint8_t track, uint8_t step) { for (uint8_t p = 0; p < 24; p++) { int8_t idxn = getLockIdx(track, p); @@ -49,7 +47,7 @@ void MDPattern::clear_step_locks(uint8_t track, uint8_t step) { } } } - +*/ bool MDPattern::fromSysex(MidiClass *midi) { init(); @@ -281,7 +279,6 @@ uint16_t MDPattern::toSysex(ElektronDataToSysexEncoder *encoder) { return 0; #endif } - void MDPattern::recalculateLockPatterns() { for (uint8_t track = 0; track < 16; track++) { lockPatterns[track] = 0; @@ -298,11 +295,10 @@ void MDPattern::recalculateLockPatterns() { * Pattern edit functions * ***************************************************************************/ - bool MDPattern::isTrackEmpty(uint8_t track) { return ((trigPatterns[track] == 0) && (lockPatterns[track] == 0)); } - +/* void MDPattern::clearTrack(uint8_t track) { if (track >= 16) return; @@ -325,7 +321,7 @@ void MDPattern::setNote(uint8_t track, uint8_t step, uint8_t pitch) { addLock(track, step, 0, pitch); setTrig(track, step); } - +*/ /*************************************************************************** * * Pattern manipulation functions diff --git a/avr/cores/megacommand/MD/MDPattern.h b/avr/cores/megacommand/MD/MDPattern.h index d3f0f0781..b14acbefc 100644 --- a/avr/cores/megacommand/MD/MDPattern.h +++ b/avr/cores/megacommand/MD/MDPattern.h @@ -102,6 +102,7 @@ class MDPattern : public ElektronPattern { } virtual void clearPattern(); + /* virtual void clearTrack(uint8_t track); virtual void setTrig(uint8_t track, uint8_t trig) { @@ -116,9 +117,8 @@ class MDPattern : public ElektronPattern { virtual void setLockIdx(uint8_t track, uint8_t param, int8_t value) { paramLocks[track][param] = value; } - + */ virtual void recalculateLockPatterns(); - /** ElektronSysexObject implementation */ virtual bool fromSysex(MidiClass *midi); virtual uint16_t toSysex(ElektronDataToSysexEncoder *encoder); diff --git a/avr/cores/megacommand/MD/MDSysex.cpp b/avr/cores/megacommand/MD/MDSysex.cpp index 1ffd471ca..a43be98fe 100644 --- a/avr/cores/megacommand/MD/MDSysex.cpp +++ b/avr/cores/megacommand/MD/MDSysex.cpp @@ -33,23 +33,10 @@ void MDSysexListenerClass::end() { break; case MD_GLOBAL_MESSAGE_ID: - onGlobalMessageCallbacks.call(); - break; - case MD_KIT_MESSAGE_ID: - onKitMessageCallbacks.call(); - break; - case MD_PATTERN_MESSAGE_ID: - onPatternMessageCallbacks.call(); - break; - case MD_SONG_MESSAGE_ID: - onSongMessageCallbacks.call(); - break; - - case MD_SAMPLE_NAME_ID: - onSampleNameCallbacks.call(); + onMessageCallbacks.call(); break; case MD_SET_RHYTHM_ECHO_PARAM_ID: diff --git a/avr/cores/megacommand/MD/MDSysex.h b/avr/cores/megacommand/MD/MDSysex.h index fa9cb6d09..5b0dba8ee 100644 --- a/avr/cores/megacommand/MD/MDSysex.h +++ b/avr/cores/megacommand/MD/MDSysex.h @@ -51,7 +51,6 @@ class MDSysexListenerClass : public ElektronSysexListenerClass { **/ public: - CallbackVector onSampleNameCallbacks; /** Stores if the currently received message is a MachineDrum sysex message. * **/ bool isMDMessage; @@ -73,17 +72,7 @@ class MDSysexListenerClass : public ElektronSysexListenerClass { **/ void setup(MidiClass *_midi); - void addOnSampleNameCallback(SysexCallback *obj, sysex_callback_ptr_t func) { - onSampleNameCallbacks.add(obj, func); - } - void removeOnSampleNameCallback(SysexCallback *obj, sysex_callback_ptr_t func) { - onSampleNameCallbacks.remove(obj, func); - } - void removeOnSampleNameCallback(SysexCallback *obj) { - onSampleNameCallbacks.remove(obj); - } - - /* @} */ + /* @} */ }; #include "MDMessages.h" diff --git a/avr/cores/megacommand/MNM/MNM.cpp b/avr/cores/megacommand/MNM/MNM.cpp index 1ffa07572..a55b3b87f 100644 --- a/avr/cores/megacommand/MNM/MNM.cpp +++ b/avr/cores/megacommand/MNM/MNM.cpp @@ -138,7 +138,7 @@ void MNMClass::setMultiEnvParam(uint8_t param, uint8_t value) { uart->sendNRPN(global.baseChannel, 0x40 + param, value); } -void MNMClass::muteTrack(uint8_t track, bool mute = true, MidiUartParent *uart_ = nullptr) { +void MNMClass::muteTrack(uint8_t track, bool mute, MidiUartParent *uart_) { if (uart_ == nullptr) { uart_ = uart; } uart->sendCC(track + global.baseChannel, 3, mute ? 0 : 1); } @@ -238,9 +238,7 @@ void MNMClass::setMidiTrack(uint8_t track) { setStatus(0x23, track); } void MNMClass::revertToCurrentKit(bool reloadKit) { if (!reloadKit) { - if (loadedKit) { MNM.loadKit(MNM.currentKit); - } } else { uint8_t kit = getCurrentKit(500); if (kit != 255) { @@ -251,9 +249,7 @@ void MNMClass::revertToCurrentKit(bool reloadKit) { void MNMClass::revertToTrack(uint8_t track, bool reloadKit) { if (!reloadKit) { - if (loadedKit) { setMachine(track, track); - } } } diff --git a/avr/cores/megacommand/MNM/MNMSysex.cpp b/avr/cores/megacommand/MNM/MNMSysex.cpp index ebe7f6909..99a7d3bd7 100644 --- a/avr/cores/megacommand/MNM/MNMSysex.cpp +++ b/avr/cores/megacommand/MNM/MNMSysex.cpp @@ -28,19 +28,10 @@ void MNMSysexListenerClass::end() { break; case MNM_GLOBAL_MESSAGE_ID: - onGlobalMessageCallbacks.call(); - break; - case MNM_KIT_MESSAGE_ID: - onKitMessageCallbacks.call(); - break; - case MNM_PATTERN_MESSAGE_ID: - onPatternMessageCallbacks.call(); - break; - case MNM_SONG_MESSAGE_ID: - onSongMessageCallbacks.call(); + onMessageCallbacks.call(); break; } } diff --git a/avr/cores/megacommand/Makefile b/avr/cores/megacommand/Makefile index 344b2e380..02c48aee7 100644 --- a/avr/cores/megacommand/Makefile +++ b/avr/cores/megacommand/Makefile @@ -31,19 +31,27 @@ UISP=uisp AVR_ARCH = atmega2560 F_CPU = 16000000L +CHECKSUM ?= 0 INOFILES=$(wildcard *.pde) OPTIM_FLAGS = -Os --short-enums WARN_FLAGS = -Wall -Wextra -Wdouble-promotion -COMPILE_FLAGS = -c $(OPTIM_FLAGS) $(WARN_FLAGS) -MMD +BASE_COMPILE_FLAGS = -c $(OPTIM_FLAGS) $(WARN_FLAGS) -MMD + +ifeq ($(CHECKSUM),1) + COMPILE_FLAGS = $(BASE_COMPILE_FLAGS) -DCHECKSUM +else + COMPILE_FLAGS = $(BASE_COMPILE_FLAGS) +endif + FEATURE_FLAGS = -ffunction-sections -fdata-sections -flto=jobserver -fshort-enums LINK_FLAGS = -lm -Wl,--gc-sections,--defsym=__stack=0x801FA1,--section-start,.sdcard=0x801FA2,--section-start,.data=0x802200,--defsym=__heap_end=0x80ffff,--relax ARCH_FLAGS = -mmcu=atmega2560 -DF_CPU=16000000L -DARDUINO=10803 -DARDUINO_AVR_MEGA2560 -DARDUINO_ARCH_AVR CFLAGS = -std=gnu11 $(COMPILE_FLAGS) $(FEATURE_FLAGS) $(LINK_FLAGS) $(ARCH_FLAGS) CXXFLAGS = -std=gnu++1z $(COMPILE_FLAGS) $(FEATURE_FLAGS) $(LINK_FLAGS) $(ARCH_FLAGS) -CXXFLAGS += -fpermissive -fno-exceptions -fno-threadsafe-statics -fno-rtti +CXXFLAGS += -fno-exceptions -fno-threadsafe-statics -fno-rtti LDFLAGS = $(OPTIM_FLAGS) $(WARN_FLAGS) -flto -fuse-linker-plugin -mrelax $(LINK_FLAGS) $(ARCH_FLAGS) @@ -128,8 +136,9 @@ clean: upload: main.hex echo "DEVICE is $(AVR_DEVICE)"; \ - echo "RAM USAGE: `$(AVRSIZE) main.elf | grep main | awk '{ print $$2 + $$3}'`"; \ - ${AVRDUDE} -C${AVRDUDE_CFG} -v -V -patmega2560 -cwiring -P${AVR_DEVICE} -b115200 -D -Uflash:w:./main.hex + echo "RAM USAGE: `$(AVRSIZE) main.elf | grep main | awk '{ print $$2 + $$3}'`"; \ + ./checksum.py main.hex; \ + ${AVRDUDE} -C${AVRDUDE_CFG} -v -V -patmega2560 -cwiring -P${AVR_DEVICE} -b115200 -D -Uflash:w:./main.hex debug: CXXFLAGS += -DDEBUGMODE=1 debug: CFLAGS += -DDEBUGMODE=1 diff --git a/avr/cores/megacommand/Midi/Midi.cpp b/avr/cores/megacommand/Midi/Midi.cpp index 7ae69d42a..73004faf4 100644 --- a/avr/cores/megacommand/Midi/Midi.cpp +++ b/avr/cores/megacommand/Midi/Midi.cpp @@ -19,7 +19,7 @@ const midi_parse_t midi_parse[] = {{MIDI_NOTE_OFF, midi_wait_byte_2}, {MIDI_TUNE_REQUEST, midi_wait_status}, {0, midi_ignore_message}}; -MidiClass::MidiClass(MidiUartParent *_uart, uint16_t _sysexBufLen, +MidiClass::MidiClass(MidiUartClass *_uart, uint16_t _sysexBufLen, volatile uint8_t *ptr) : midiSysex(_uart, _sysexBufLen, ptr) { midiActive = true; diff --git a/avr/cores/megacommand/Midi/Midi.h b/avr/cores/megacommand/Midi/Midi.h index ae02e9878..55326e419 100644 --- a/avr/cores/megacommand/Midi/Midi.h +++ b/avr/cores/megacommand/Midi/Midi.h @@ -68,7 +68,7 @@ class MidiClass { uint8_t in_msg_len; uint8_t msg[3]; - MidiUartParent *uart; + MidiUartClass *uart; MidiUartClass *uart_forward[NUM_FORWARD_PORTS]; @@ -83,7 +83,7 @@ class MidiClass { MidiSysexClass midiSysex; uint8_t receiveChannel; - MidiClass(MidiUartParent *_uart, uint16_t _sysexBufLen, volatile uint8_t *ptr); + MidiClass(MidiUartClass *_uart, uint16_t _sysexBufLen, volatile uint8_t *ptr); void init(); @@ -95,8 +95,8 @@ class MidiClass { } void processMidi() { - while (uart->avail()) { - handleByte(uart->m_getc()); + while (((MidiUartParent*)uart)->avail()) { + handleByte(((MidiUartParent*)uart)->m_getc()); } } diff --git a/avr/cores/megacommand/Midi/MidiUartParent.h b/avr/cores/megacommand/Midi/MidiUartParent.h index d6848e821..8f7d9d9fc 100644 --- a/avr/cores/megacommand/Midi/MidiUartParent.h +++ b/avr/cores/megacommand/Midi/MidiUartParent.h @@ -158,25 +158,17 @@ class MidiUartParent { } */ - ALWAYS_INLINE() void sendNoteOn(uint8_t channel, uint8_t note, uint8_t velocity) { -#ifdef MIDI_VALIDATE - if ((channel >= 16) || (note >= 128) || (velocity >= 128)) + if (channel >= 16) return; -#endif - uint8_t msg[3] = {(uint8_t)(MIDI_NOTE_ON | channel), note, velocity}; // noteOnCallbacks.call(msg); sendMessage(msg[0], msg[1], msg[2]); } - ALWAYS_INLINE() void sendNoteOff(uint8_t channel, uint8_t note) { -#ifdef MIDI_VALIDATE - if ((channel >= 16) || (note >= 128)) + if (channel >= 16) return; -#endif - //uint8_t msg[3] = {(uint8_t)(MIDI_NOTE_OFF | channel), note, velocity}; //Send Note On VEL = 0, to leverage running status // @@ -186,55 +178,48 @@ class MidiUartParent { } void sendCC(uint8_t channel, uint8_t cc, uint8_t value) { -#ifdef MIDI_VALIDATE - if ((channel >= 16) || (note >= 128) || (velocity >= 128)) + if (channel >= 16) return; -#endif - uint8_t msg[3] = {(uint8_t)(MIDI_CONTROL_CHANGE | channel), cc, value}; // ccCallbacks.call(msg); sendMessage(msg[0], msg[1], msg[2]); } ALWAYS_INLINE() void sendProgramChange(uint8_t channel, uint8_t program) { -#ifdef MIDI_VALIDATE - if ((channel >= 16) || (note >= 128) || (velocity >= 128)) + if (channel >= 16) return; -#endif - sendMessage((uint8_t)(MIDI_PROGRAM_CHANGE | channel), program); } void sendPolyKeyPressure(uint8_t channel, uint8_t note, uint8_t pressure) { -#ifdef MIDI_VALIDATE - if ((channel >= 16) || (note >= 128) || (velocity >= 128)) + if (channel >= 16) return; -#endif - sendMessage((uint8_t)(MIDI_AFTER_TOUCH | channel), note, pressure); } void sendChannelPressure(uint8_t channel, uint8_t pressure) { -#ifdef MIDI_VALIDATE - if ((channel >= 16) || (note >= 128) || (velocity >= 128)) + if (channel >= 16) return; -#endif - sendMessage((uint8_t)(MIDI_CHANNEL_PRESSURE | channel), pressure); } void sendPitchBend(uint8_t channel, int16_t pitchbend) { - //pitchbend += 8192; + if (channel >= 16) + return; sendMessage((uint8_t)(MIDI_PITCH_WHEEL | channel), pitchbend, (pitchbend >> 7)); } void sendNRPN(uint8_t channel, uint16_t parameter, uint8_t value) { + if (channel >= 16) + return; sendCC(channel, 99, (parameter >> 7)); sendCC(channel, 98, (parameter)); sendCC(channel, 6, value); } void sendNRPN(uint8_t channel, uint16_t parameter, uint16_t value) { + if (channel >= 16) + return; sendCC(channel, 99, (parameter >> 7)); sendCC(channel, 98, (parameter)); sendCC(channel, 6, (value >> 7)); @@ -242,11 +227,15 @@ class MidiUartParent { } void sendRPN(uint8_t channel, uint16_t parameter, uint8_t value) { + if (channel >= 16) + return; sendCC(channel, 101, (parameter >> 7)); sendCC(channel, 100, (parameter)); sendCC(channel, 6, value); } void sendRPN(uint8_t channel, uint16_t parameter, uint16_t value) { + if (channel >= 16) + return; sendCC(channel, 101, (parameter >> 7)); sendCC(channel, 100, (parameter)); sendCC(channel, 6, (value >> 7)); @@ -258,8 +247,8 @@ class MidiUartParent { m_putc(data, cnt); sendCommandByte(0xF7); } - ALWAYS_INLINE() void sendRaw(uint8_t *msg, uint16_t cnt) { m_putc(msg, cnt); } - ALWAYS_INLINE() void sendRaw(uint8_t byte) { m_putc(byte); } + void sendRaw(uint8_t *msg, uint16_t cnt) { m_putc(msg, cnt); } + void sendRaw(uint8_t byte) { m_putc(byte); } void sendString(const char *data) { sendString(data, strlen(data)); } void sendString(const char *data, uint16_t cnt); diff --git a/avr/cores/megacommand/MidiUart.cpp b/avr/cores/megacommand/MidiUart.cpp index bb11aa07c..e90d1977d 100644 --- a/avr/cores/megacommand/MidiUart.cpp +++ b/avr/cores/megacommand/MidiUart.cpp @@ -119,31 +119,31 @@ void MidiUartClass::realtime_isr(uint8_t c) { } ISR(USART0_RX_vect) { - select_bank(0); + select_bank(BANK0); MidiUartUSB.rx_isr(); } ISR(USART0_UDRE_vect) { - select_bank(0); + select_bank(BANK0); MidiUartUSB.tx_isr(); } ISR(USART1_RX_vect) { - select_bank(0); + select_bank(BANK0); MidiUart.rx_isr(); } ISR(USART1_UDRE_vect) { - select_bank(0); + select_bank(BANK0); MidiUart.tx_isr(); } ISR(USART2_RX_vect) { - select_bank(0); + select_bank(BANK0); MidiUart2.rx_isr(); } ISR(USART2_UDRE_vect) { - select_bank(0); + select_bank(BANK0); MidiUart2.tx_isr(); } diff --git a/avr/cores/megacommand/ResourceManager.cpp b/avr/cores/megacommand/ResourceManager.cpp index e4a4a1855..2c91c95c8 100644 --- a/avr/cores/megacommand/ResourceManager.cpp +++ b/avr/cores/megacommand/ResourceManager.cpp @@ -91,7 +91,6 @@ void ResourceManager::restore_menu_layout_deps() { midi_config_page.set_layout(R.menu_layouts->midiconfig_menu_layout); md_config_page.set_layout(R.menu_layouts->mdconfig_menu_layout); mcl_config_page.set_layout(R.menu_layouts->mclconfig_menu_layout); - ram_config_page.set_layout(R.menu_layouts->rampage1_menu_layout); file_menu_page.set_layout(R.menu_layouts->file_menu_layout); seq_menu_page.set_layout(R.menu_layouts->seq_menu_layout); grid_slot_page.set_layout(R.menu_layouts->slot_menu_layout); diff --git a/avr/cores/megacommand/checksum.py b/avr/cores/megacommand/checksum.py new file mode 100755 index 000000000..b3f27d9d9 --- /dev/null +++ b/avr/cores/megacommand/checksum.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python + +import sys + +def dec(h): + return int(h, 16) + +def calculate_checksum(values): + checksum_sum = sum(values) + lsb = checksum_sum & 0xFF + twos_complement_lsb = (~lsb + 1) & 0xFF + record_checksum_str = format(twos_complement_lsb, '02X') + return record_checksum_str + +def insert_record(record_type, address, length, values): + print("insert record") + values.reverse() #endianess for atmega + output = length + address + record_type + values + checksum = calculate_checksum(output) + output = [format(byte, '02X') for byte in output] #convert to hex str format + output.append(checksum) + output.append("\n") + output = [":"] + output + print(''.join(output)) + lines.insert(-1, ''.join(output)) + +if len(sys.argv) != 2: + print("Usage: python script.py ") + sys.exit(1) + + +filename = sys.argv[1] +lines = [] +count = 0 + +b = [] +with open(filename, "r") as file: + for line in file: + lines.append(line) + line = line.strip() # Remove leading/trailing whitespace + length = len(line) + if line.startswith(":"): + n = dec(line[1:3]) # number of bytes in payload + record = line[7:7 + 2] + data = line[9:9 + (n * 2)] + data_checksum = line[-2:] + if record != "00": # only include data records + continue + # Print every two characters in the data payload + for i in range(0, n * 2, 2): + count += 1 + byte = data[i:i+2] + b.append(dec(byte)) + +n = 0 + +byte = 0 +checksum=0 +print(count) +while n < count: + last_byte = byte + byte = b[n] + if n % 2 == 0: + checksum ^= (byte << 8) | last_byte + n += 1 + +checksum_str = format(checksum, '04X') +length_str = format(count, '08X') + +print("Checksum: ", checksum_str) + +print(format(checksum, 'X')) + +print("Length: ", count) + +# Append the checksum to the main.hex file + +lines.insert(-1,":020000023000CC\n") # Extended Segment Address Record + +#256 * 1024 - 16 * 1024 - 6 + +# Length, 32bit @ 0xBFFA +data_bytes = [ dec(length_str[i:i+2]) for i in range(0, len(length_str), 2)] + +length_bytes = [ 0x04 ] +address_bytes = [ 0xBF, 0xFA ] +record_bytes = [ 0x00 ] + +insert_record(record_bytes, address_bytes, length_bytes, data_bytes) + +# Checksum, 16bit @ 0xBFFE + +data_bytes = [ dec(checksum_str[i:i+2]) for i in range(0, len(checksum_str), 2)] + +length_bytes = [ 0x02 ] +address_bytes = [ 0xBF, 0xFE ] +record_bytes = [ 0x00 ] + +insert_record(record_bytes, address_bytes, length_bytes, data_bytes) + +with open(filename, "w") as f: + f.truncate() + for line in lines: + f.write(line) + diff --git a/avr/cores/megacommand/main.cpp b/avr/cores/megacommand/main.cpp index 22915006a..04c501884 100644 --- a/avr/cores/megacommand/main.cpp +++ b/avr/cores/megacommand/main.cpp @@ -33,6 +33,47 @@ __attribute__((section(".init3"))); void(* hardwareReset) (void) = 0; +bool test_sram_banks() { + volatile uint8_t* const start = reinterpret_cast(0x2200); + volatile uint8_t* const end = reinterpret_cast(0xFFFF); + + // Data line and bank switching test + uint8_t pattern = 0x55; + for (volatile uint8_t* ptr = start; ptr < end; ++ptr) { + switch_ram_bank_noret(0); + *ptr = pattern; + if (*ptr != pattern) return false; + switch_ram_bank_noret(1); + *ptr = ~pattern; + if (*ptr != ~pattern) return false; + // *ptr = 0x00; // initialise for later + switch_ram_bank_noret(0); + if (*ptr != pattern) return false; + // *ptr = 0x00; // initialise for later + pattern = (pattern << 1) | (pattern >> 7); + } + +/* + // Address line test, assumes initialised SRAM + for (uint16_t bit = 1; bit != 0 && (start + bit) < end; bit <<= 1) { + volatile uint8_t* const test_addr = start + bit; + // Write to test address + *test_addr = 0xAA; + // Check that only the test address changed + for (volatile uint8_t* ptr = start; ptr < end; ptr++) { + if (ptr == test_addr) { + if (*ptr != 0xAA) return false; // Test address didn't hold the value + } else { + if (*ptr != 0x00) return false; // Another address was affected + } + } + // Reset test address + *test_addr = 0x00; + } +*/ + return true; +} + void my_init_ram(void) { // Set PL6 as output @@ -43,9 +84,22 @@ void my_init_ram(void) { DDRB |= _BV(PB0); PORTB &= ~(_BV(PB0)); #endif + + //External SRAM Hardware Enable XMCRA |= _BV(SRE); -} + //Leds + + DDRE |= _BV(PE4) | _BV(PE5); + //SRAM tests + + /* Still not working? + while (!test_sram_banks()) { + setLed(); + setLed2(); + } + */ +} uint8_t tcnt2; void timer_init(void) { @@ -104,15 +158,12 @@ void init(void) { /* move interrupts to bootloader section */ MCUCR = _BV(IVCE); - - // Enable External SRAM MCUCR = _BV(SRE); // activate lever converter SET_BIT(DDRD, PD4); SET_BIT(PORTD, PD4); - DDRE |= _BV(PE4) | _BV(PE5); //For MC SMD. Level shifter 1 + 2 enable. //PL4 == MEGA2560 level shifter enable @@ -132,7 +183,7 @@ void loop(); ISR(TIMER1_COMPA_vect) { - select_bank(0); + select_bank(BANK0); clock++; MidiClock.div192th_countdown++; @@ -192,7 +243,7 @@ ALWAYS_INLINE() void gui_poll() { ISR(TIMER3_COMPA_vect) { - select_bank(0); + select_bank(BANK0); slowclock++; minuteclock++; diff --git a/avr/cores/megacommand/make_and_upload.sh b/avr/cores/megacommand/make_and_upload.sh index faf2af36d..e004c369c 100755 --- a/avr/cores/megacommand/make_and_upload.sh +++ b/avr/cores/megacommand/make_and_upload.sh @@ -1,12 +1,40 @@ #!/bin/bash AVR_DIR=$(cd "../../../../tools/avr"; pwd) DEV=/dev/$(ls /dev | grep usb | grep cu | tail -n 1) -make -j8 +# Parse command line arguments -if [ $? -eq 0 ]; then +run_checksum=false +no_upload=false +while getopts "c" opt; do + case $opt in + c) + run_checksum=true + ;; + n) + no_upload=true + ;; + \?) + echo "Invalid option: -$OPTARG" >&2 + exit 1 + ;; + esac +done + + +rm main.hex +if $run_checksum; then + make -j8 CHECKSUM=1 +else + make -j8 +fi + + + + +if ! $no_upload; then size=$(${AVR_DIR}/bin/avr-size main.elf | tail -n 1 | awk '{ print $1 + $2}') - limit=$((256 * 1024 - 16 * 1024)) + limit=$((256 * 1024 - 16 * 1024 - 6)) echo ROM_SIZE : $size echo ROM_LIMIT: $limit echo ROM_FREE : $(($limit - $size)) @@ -17,10 +45,15 @@ if [ $? -eq 0 ]; then ram_free=$((1024 * 64 - $ram_used - 8 * 1024)) echo RAM_USED: $ram_used echo RAM_FREE: $ram_free - ${AVR_DIR}/bin/avr-nm main.elf -Crtd --size-sort | grep -i ' [dbv] ' | sort + hex_file=main.hex + if $run_checksum; then + cp main.hex main_checksum.hex + ./checksum.py main_checksum.hex; + hex_file=main_checksum.hex + fi #avrdude -c atmelice_isp -p m2560 -D -Uflash:w:./main.hex -B 1 - ${AVR_DIR}/bin/avrdude -C${AVR_DIR}/etc/avrdude.conf -V -patmega2560 -c arduino -P${DEV} -b115200 -D -Uflash:w:./main.hex -# ${AVR_DIR}/bin/avrdude -C${AVR_DIR}/etc/avrdude.conf -V -patmega2560 -c wiring -P${DEV} -b115200 -D -Uflash:w:./main.hex + ${AVR_DIR}/bin/avrdude -C${AVR_DIR}/etc/avrdude.conf -V -patmega2560 -c arduino -P${DEV} -b115200 -D -Uflash:w:./$hex_file + #${AVR_DIR}/bin/avrdude -C${AVR_DIR}/etc/avrdude.conf -V -patmega2560 -c wiring -P${DEV} -b115200 -D -Uflash:w:./main.hex fi diff --git a/avr/cores/megacommand/memory.h b/avr/cores/megacommand/memory.h index 8934300b6..880ece678 100644 --- a/avr/cores/megacommand/memory.h +++ b/avr/cores/megacommand/memory.h @@ -91,7 +91,7 @@ class RamBankSelector { uint8_t m_oldbank; public: FORCED_INLINE() RamBankSelector(uint8_t bank) { m_oldbank = switch_ram_bank(bank); } - FORCED_INLINE() ~RamBankSelector() { switch_ram_bank(m_oldbank); } + FORCED_INLINE() ~RamBankSelector() { switch_ram_bank_noret(m_oldbank); } }; class RamAccessFringe { @@ -116,33 +116,33 @@ class RamAccessFringe { template FORCED_INLINE() extern inline T get_bank1(volatile T *dst) { - select_bank(1); + select_bank(BANK1); return *dst; } template FORCED_INLINE() extern inline void put_bank1(volatile T *dst, T data) { - select_bank(1); + select_bank(BANK1); *dst = data; } FORCED_INLINE() extern inline int memcmp_bank1(volatile void *dst, volatile const void *src, uint16_t len) { - select_bank(1); + select_bank(BANK1); return memcmp((void*)dst, (void*)src, len); } FORCED_INLINE() extern inline void memcpy_bank1(volatile void *dst, volatile const void *src, uint16_t len) { - select_bank(1); + select_bank(BANK1); memcpy((void*)dst, (void*)src, len); } FORCED_INLINE() extern inline void put_byte_bank1(volatile uint8_t *dst, uint8_t byte) { - select_bank(1); + select_bank(BANK1); *dst = byte; } FORCED_INLINE() extern inline uint8_t get_byte_bank1(volatile uint8_t *dst) { - select_bank(1); + select_bank(BANK1); uint8_t c = *dst; return c; } @@ -155,7 +155,7 @@ FORCED_INLINE() extern inline void get_bank2(volatile void *dst, volatile const FORCED_INLINE() extern inline void get_bank3(volatile void *dst, volatile const void *src, uint16_t len) { ram_access_fringe(); - select_bank(1); + select_bank(BANK1); memcpy((void*)dst, (uint8_t*)src + 0x4000, len); } @@ -167,7 +167,7 @@ FORCED_INLINE() extern inline void put_bank2(volatile void *dst, volatile const FORCED_INLINE() extern inline void put_bank3(volatile void *dst, volatile const void *src, uint16_t len) { ram_access_fringe(); - select_bank(1); + select_bank(BANK1); memcpy((uint8_t*)dst + 0x4000, (uint8_t*)src, len); } diff --git a/avr/cores/megacommand/memorybank.h b/avr/cores/megacommand/memorybank.h index cd5748432..af45234c5 100644 --- a/avr/cores/megacommand/memorybank.h +++ b/avr/cores/megacommand/memorybank.h @@ -1,31 +1,19 @@ -#pragma once -#ifdef MEGACOMMAND - -#define PL6_MASK (1 << PL6) - -FORCED_INLINE() inline uint8_t switch_ram_bank(uint8_t x) { - uint8_t old_bank = (uint8_t) (PORTL & PL6_MASK); - - if (x != old_bank) { - PORTL ^= PL6_MASK; - return old_bank; - } - return x; -} +#define BANK0 0 +#ifdef MEGACOMMAND + #define BANK_PORT PORTL + #define BANK_MASK (1 << PL6) #else + #define BANK_PORT PORTB + #define BANK_MASK (1 << PB0) +#endif -#define PB0_MASK (1 << PB0) +#define BANK1 BANK_MASK FORCED_INLINE() inline uint8_t switch_ram_bank(uint8_t x) { - uint8_t old_bank = (uint8_t) (PORTB & PB0_MASK); - - if (x != old_bank) { - PORTB ^= PB0_MASK; - return old_bank; - } - return x; + uint8_t old_bank = BANK_PORT & BANK_MASK; + BANK_PORT = (BANK_PORT & ~BANK_MASK) | x; + return old_bank; } -#endif - +#define switch_ram_bank_noret(x) ((void)switch_ram_bank(x)) diff --git a/avr/cores/megacommand/resources/R.h b/avr/cores/megacommand/resources/R.h index c78e2ee7e..40e86043d 100644 --- a/avr/cores/megacommand/resources/R.h +++ b/avr/cores/megacommand/resources/R.h @@ -424,28 +424,22 @@ struct __T_menu_layouts { static constexpr size_t sizeofof_midiprogram_menu_layout = 74; union { menu_t midiport_menu_layout[0]; - char zz__midiport_menu_layout[116]; + char zz__midiport_menu_layout[137]; }; - static constexpr size_t countof_midiport_menu_layout = 116 / sizeof(menu_t); - static constexpr size_t sizeofof_midiport_menu_layout = 116; + static constexpr size_t countof_midiport_menu_layout = 137 / sizeof(menu_t); + static constexpr size_t sizeofof_midiport_menu_layout = 137; union { menu_t midiconfig_menu_layout[0]; char zz__midiconfig_menu_layout[137]; }; static constexpr size_t countof_midiconfig_menu_layout = 137 / sizeof(menu_t); static constexpr size_t sizeofof_midiconfig_menu_layout = 137; - union { - menu_t rampage1_menu_layout[0]; - char zz__rampage1_menu_layout[32]; - }; - static constexpr size_t countof_rampage1_menu_layout = 32 / sizeof(menu_t); - static constexpr size_t sizeofof_rampage1_menu_layout = 32; union { menu_t auxconfig_menu_layout[0]; - char zz__auxconfig_menu_layout[32]; + char zz__auxconfig_menu_layout[53]; }; - static constexpr size_t countof_auxconfig_menu_layout = 32 / sizeof(menu_t); - static constexpr size_t sizeofof_auxconfig_menu_layout = 32; + static constexpr size_t countof_auxconfig_menu_layout = 53 / sizeof(menu_t); + static constexpr size_t sizeofof_auxconfig_menu_layout = 53; union { menu_t system_menu_layout[0]; char zz__system_menu_layout[137]; @@ -464,18 +458,18 @@ struct __T_menu_layouts { }; static constexpr size_t countof_boot_menu_layout = 95 / sizeof(menu_t); static constexpr size_t sizeofof_boot_menu_layout = 95; - static constexpr size_t __total_size = 2131; + static constexpr size_t __total_size = 2141; }; extern const unsigned char __R_menu_options[] PROGMEM; struct __T_menu_options { union { menu_option_t MENU_OPTIONS[0]; - char zz__MENU_OPTIONS[1098]; + char zz__MENU_OPTIONS[1134]; }; - static constexpr size_t countof_MENU_OPTIONS = 1098 / sizeof(menu_option_t); - static constexpr size_t sizeofof_MENU_OPTIONS = 1098; - static constexpr size_t __total_size = 1098; + static constexpr size_t countof_MENU_OPTIONS = 1134 / sizeof(menu_option_t); + static constexpr size_t sizeofof_MENU_OPTIONS = 1134; + static constexpr size_t __total_size = 1134; }; extern const unsigned char __R_page_entries[] PROGMEM; diff --git a/avr/cores/megacommand/resources/R_menu_layouts.cpp b/avr/cores/megacommand/resources/R_menu_layouts.cpp index 5df75eaed..324fab513 100644 --- a/avr/cores/megacommand/resources/R_menu_layouts.cpp +++ b/avr/cores/megacommand/resources/R_menu_layouts.cpp @@ -262,190 +262,191 @@ const unsigned char __R_menu_layouts[] PROGMEM = { 79, 67, 104, - 119, - 211, + 183, + 31, + 2, 75, 69, + 176, 89, - 96, 63, - 125, + 62, 12, 12, 19, - 184, + 220, 41, 104, 86, - 68, + 34, 233, - 37, + 18, 27, - 225, + 240, 0, 20, + 193, 48, - 130, 6, - 236, + 118, 78, 68, 21, - 191, + 95, 1, 15, 15, + 183, 21, - 110, 20, 60, 83, - 219, + 109, 82, 69, + 128, 21, - 1, - 252, + 254, 7, 7, 22, 255, 5, 41, - 55, + 27, 132, 71, 84, + 194, 72, - 132, 58, 153, - 191, + 95, 23, 255, 6, + 176, 0, - 97, 20, - 121, + 188, 2, 129, - 28, + 142, 67, 72, - 45, + 22, 248, 78, - 146, + 201, 108, - 27, + 13, 16, 24, + 225, 255, - 194, 7, 0, 111, - 67, + 33, + 252, 3, - 248, 3, 25, 255, 8, 27, - 66, + 33, 153, - 221, + 110, 20, + 228, 26, - 200, 255, 9, - 7, + 3, + 194, 10, - 132, 30, 153, - 45, - 223, + 22, + 239, 20, 27, 255, 11, 27, + 240, 83, - 225, 72, 73, 70, + 128, 59, - 1, - 252, + 254, 5, 5, 28, 255, 12, 35, - 43, + 21, 174, + 187, 232, - 118, 82, 83, 43, - 178, + 89, 41, - 127, + 63, 29, 255, 13, 27, 80, + 251, 79, - 246, 76, 89, 80, 72, 235, - 217, + 108, 89, 44, - 54, + 155, 11, 2, - 237, + 118, 81, 85, 167, - 132, + 194, 84, 79, - 14, + 7, 42, - 96, - 182, + 48, + 91, 121, 32, 65, - 133, + 66, 125, - 101, + 178, 20, - 205, + 230, 30, + 225, 83, - 194, 79, 85, 38, - 216, - 0, - 0, - 29, - 40, + 66, + 144, + 6, + 53, + 129, 189, 2, 14, @@ -570,481 +571,488 @@ const unsigned char __R_menu_layouts[] PROGMEM = { 176, 84, 31, - 56, - 33, - 102, - 7, + 55, + 86, + 91, + 78, 18, - 219, 77, + 110, 178, 73, - 133, 90, + 21, 146, - 96, + 131, 147, - 219, 8, + 111, 73, 16, - 74, - 253, - 222, + 1, + 71, + 111, 201, 32, 77, 73, - 215, + 107, 175, 62, - 91, + 173, 85, 188, + 140, 32, - 25, 240, - 125, + 190, 129, 1, 60, - 187, + 221, 31, 121, 24, + 172, 84, - 88, 30, - 35, + 17, + 220, 78, - 184, 82, 79, 32, - 246, + 123, 83, 33, - 125, + 62, 17, 2, 9, - 176, + 216, 31, 18, - 236, + 118, 208, 20, - 38, + 19, + 46, 46, - 93, 88, 84, - 109, + 182, 81, 71, - 132, + 194, 20, - 221, + 110, 57, 41, + 218, 24, - 180, 82, 201, - 32, + 16, 113, - 191, + 95, 80, 32, + 241, 49, - 227, 32, 70, 87, + 169, 220, - 82, 127, - 118, + 59, 7, 31, - 216, + 108, 10, 20, - 200, + 100, 50, - 12, + 6, 51, - 190, + 95, 92, 85, 83, 66, - 193, + 96, 17, - 72, + 164, 169, - 54, + 27, 52, 20, - 199, + 99, 96, 26, - 47, + 151, 116, - 9, + 132, 92, - 118, + 187, 11, 20, - 225, + 112, 86, 24, + 161, 124, - 66, 251, - 140, + 70, 5, - 22, + 11, 29, - 174, + 87, 8, - 15, + 7, 183, + 140, 58, - 25, 121, - 219, + 237, 5, 31, + 129, 7, - 2, 5, - 44, + 22, 20, - 14, + 7, 53, - 102, + 51, 41, - 97, + 48, + 204, 204, - 152, 115, - 112, + 56, 6, - 182, + 91, 72, 100, 41, - 44, + 22, 20, - 14, + 7, 54, - 222, + 111, 41, 100, 24, 80, - 219, + 109, 190, 71, + 161, 24, - 67, 220, - 181, + 218, 9, - 186, + 221, 220, 77, 79, - 230, + 115, 1, 126, - 29, + 14, 49, - 183, + 219, 31, 90, 20, - 225, + 240, 73, 78, + 147, 167, - 39, 18, + 195, 2, - 134, 47, 7, - 123, + 61, 20, + 206, 244, - 156, 21, - 16, + 8, 7, - 110, + 55, 48, 20, - 135, + 67, 24, 154, - 172, + 214, 83, 177, - 252, + 126, 85, 82, 66, 79, - 43, + 21, 8, + 151, 221, - 47, 2, + 181, 255, - 107, 78, + 156, 20, - 57, 50, - 46, + 151, 3, - 73, - 13, + 36, + 134, 13, + 176, 58, - 96, 20, - 205, + 102, 55, + 133, 68, - 10, 102, - 153, - 98, - 172, - 42, - 136, - 155, - 4, - 189, - 96, - 84, - 197, 76, - 224, 98, + 214, + 63, + 136, 77, - 5, - 183, - 41, - 56, - 189, - 132, - 194, - 23, + 61, + 182, 189, + 124, + 20, + 12, + 50, + 147, + 4, + 44, + 84, + 24, + 97, + 188, + 119, + 9, + 26, + 182, 62, + 56, + 240, + 210, + 130, + 215, + 231, + 210, 26, + 215, 32, - 186, - 109, + 130, + 66, 70, - 21, - 162, + 183, + 176, + 118, + 99, + 33, + 205, 131, - 97, - 34, - 28, - 184, - 24, - 59, - 97, - 79, - 113, - 36, - 206, + 80, + 12, 100, - 186, - 109, - 210, + 46, + 35, + 57, + 121, + 205, + 207, + 231, + 176, 71, - 128, 20, - 218, - 37, - 252, - 16, - 6, - 88, - 20, - 12, - 35, - 104, - 120, - 193, - 35, - 96, + 24, + 36, + 80, + 17, + 130, + 27, + 192, 20, + 99, + 34, + 141, + 70, 56, - 38, - 0, - 246, - 88, + 11, + 20, + 1, + 131, + 37, + 107, + 71, + 109, + 54, 40, - 216, 76, - 24, - 29, - 39, - 206, - 3, - 59, - 109, - 157, - 65, - 160, - 27, - 230, - 55, - 91, 192, - 75, - 150, - 7, - 234, - 189, - 1, + 24, + 239, + 38, 126, - 66, - 65, - 85, - 88, - 198, - 31, - 83, - 207, - 41, - 97, - 103, - 178, - 101, - 34, - 225, - 31, - 219, - 153, - 185, - 97, - 186, - 109, + 180, 65, + 23, + 25, + 139, 118, + 32, + 35, + 180, + 138, + 43, + 123, + 189, + 59, + 62, + 168, + 110, + 122, + 90, + 10, + 240, + 219, 116, - 142, - 74, - 40, + 75, 210, - 193, - 233, - 164, - 25, - 235, - 88, - 19, + 39, + 1, + 255, + 115, + 196, + 174, + 44, + 45, + 196, + 65, + 174, + 52, + 131, + 133, 74, - 104, + 220, 24, + 243, + 52, + 25, + 139, + 245, + 19, + 9, + 77, + 34, 2, - 197, - 110, - 133, - 221, - 221, + 24, + 120, + 176, + 210, + 187, 26, - 179, + 168, + 163, 65, - 26, - 160, - 208, - 129, - 42, - 94, - 86, + 170, + 90, + 93, + 5, + 104, 74, - 204, - 29, + 84, + 195, + 193, + 179, 27, - 128, - 125, - 178, + 146, + 28, + 3, + 22, + 119, + 80, + 195, 41, - 105, + 164, 29, - 213, - 13, - 129, + 223, + 54, 62, - 137, - 136, - 216, + 6, + 39, + 146, + 96, 101, - 44, + 176, 136, - 34, - 113, + 137, + 198, 0, 66, - 172, - 182, + 192, + 176, 14, - 28, + 99, 79, - 83, - 44, - 205, + 107, + 90, + 100, + 24, + 62, + 106, 80, - 48, 73, - 212, - 70, - 146, - 193, - 222, + 203, + 111, 127, 68, 70, 85, - 49, - 89, - 72, - 214, - 11, + 24, + 99, + 164, + 224, + 5, 169, - 83, - 2, - 174, - 78, - 176, + 169, + 12, + 215, + 88, + 88, 75, 20, - 24, + 12, 28, - 150, - 253, + 91, + 7, 88, - 13, + 6, + 182, 172, - 89, - 0, - 11, + 10, + 133, + 192, 169, - 128, 0, 0, 0, 0, - 1, - 63, + 0, + 159, 255, }; diff --git a/avr/cores/megacommand/resources/R_menu_options.cpp b/avr/cores/megacommand/resources/R_menu_options.cpp index 8700bd812..2a29d177d 100644 --- a/avr/cores/megacommand/resources/R_menu_options.cpp +++ b/avr/cores/megacommand/resources/R_menu_options.cpp @@ -469,12 +469,25 @@ const unsigned char __R_menu_options[] PROGMEM = { 97, 128, 40, - 12, + 130, + 175, + 67, + 80, + 10, + 92, + 208, + 128, + 132, + 103, + 216, + 77, + 45, + 32, 0, 0, 0, 0, 0, - 19, + 159, 255, }; diff --git a/avr/cores/megacommand/resources/R_page_entries.cpp b/avr/cores/megacommand/resources/R_page_entries.cpp index ad92cc649..6a8bad035 100644 --- a/avr/cores/megacommand/resources/R_page_entries.cpp +++ b/avr/cores/megacommand/resources/R_page_entries.cpp @@ -33,7 +33,7 @@ const unsigned char __R_page_entries[] PROGMEM = { 96, 42, 123, - 41, + 40, 2, 22, 109, diff --git a/avr/cores/megacommand/wiring.c b/avr/cores/megacommand/wiring.c index 95c9baa56..a7dbc63c2 100644 --- a/avr/cores/megacommand/wiring.c +++ b/avr/cores/megacommand/wiring.c @@ -51,7 +51,7 @@ ISR(TIMER0_OVF_vect) // copy these to local variables so they can be stored in registers // (volatile variables must be read from memory on every access) - uint8_t old_bank = switch_ram_bank(0); + uint8_t old_bank = switch_ram_bank(BANK0); unsigned long m = timer0_millis; unsigned char f = timer0_fract; diff --git a/resource/menu_layouts.cpp b/resource/menu_layouts.cpp index 2cb2d2798..6c8aba518 100644 --- a/resource/menu_layouts.cpp +++ b/resource/menu_layouts.cpp @@ -43,28 +43,21 @@ menu_t system_menu_layout = { {"NEW PROJECT", 0, 0, 0, 0, NULL_PAGE, 2, 0}, {"MIDI", 0, 0, 0, 0, MIDI_CONFIG_PAGE, 0, 0}, {"MACHINEDRUM", 0, 0, 0, 0, MD_CONFIG_PAGE, 0, 0}, - {"AUX PAGES", 0, 0, 0, 0, AUX_CONFIG_PAGE, 0, 0}, + {"PAGE SETUP", 0, 0, 0, 0, AUX_CONFIG_PAGE, 0, 0}, {"SYSTEM", 0, 0, 0, 0, MCL_CONFIG_PAGE, 0, 0}, }, 0 }; menu_t auxconfig_menu_layout = { - "AUX PAGES", + "PAGE", { // m r n d p f o - {"RAM Page" ,0, 0, 0, 0, RAM_CONFIG_PAGE, 0, 0}, - }, - 0 -}; -menu_t rampage1_menu_layout = { - "RAM PAGE", - { - // m r n d p f o - {"LINK:", 0, 2, 2, 1, NULL_PAGE, 0, 0}, + {"GRID ENCOD:", 0, 2, 2, 62, NULL_PAGE, 0, 122}, + {"RAM LINK:", 0, 2, 2, 1, NULL_PAGE, 0, 0}, }, - 0 + 1 }; menu_t midiconfig_menu_layout = { @@ -86,6 +79,7 @@ menu_t midiport_menu_layout = { {"TURBO 1:", 0, 4, 4, 2, NULL_PAGE, 0, 2}, {"TURBO 2:", 0, 4, 4, 3, NULL_PAGE, 0, 2}, {"TURBO USB:", 0, 4, 4, 55, NULL_PAGE , 0, 2}, + {"DRIVER 1:", 0, 2, 2, 61, 0, NULL_PAGE, 124}, {"DRIVER 2:", 0, 2, 2, 4, 0, NULL_PAGE, 84}, {"CTRL PORT:", 1, 4, 4, 56, NULL_PAGE, 0, 100}, }, @@ -156,7 +150,7 @@ menu_t mdconfig_menu_layout = { {"IMPORT", 0, 0, 0, 0, MD_IMPORT_PAGE, 0, 0}, {"NORMALIZE:", 0, 2, 2, 8, NULL_PAGE, 0, 16}, }, - 0 + 1 }; menu_t mdimport_menu_layout = { diff --git a/resource/menu_options.cpp b/resource/menu_options.cpp index 251c75009..6d9172cb5 100644 --- a/resource/menu_options.cpp +++ b/resource/menu_options.cpp @@ -69,6 +69,10 @@ menu_option_t MENU_OPTIONS[] = { // 117 {0, "A"}, {1, "B"}, {2, "C"}, {3, "D"}, // 121 - {128, "--"} + {128, "--"}, + // 122 + {0, "--"}, {1,"PERF"}, + // 124 + {0, "GENER"}, {1,"MD"} };