From d3ef79a7294c5f77604226d217943c802c982cc8 Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Mon, 21 Aug 2023 00:37:52 -0400 Subject: [PATCH] add key update buffer --- Source/LumatoneController.cpp | 54 ++++++-------- Source/LumatoneController.h | 15 ++-- Source/Main.h | 1 + Source/key_update_buffer.cpp | 134 ++++++++++++++++++++++++++++++++++ Source/key_update_buffer.h | 40 ++++++++++ TerpstraSysEx.jucer | 4 + 6 files changed, 212 insertions(+), 36 deletions(-) create mode 100644 Source/key_update_buffer.cpp create mode 100644 Source/key_update_buffer.h diff --git a/Source/LumatoneController.cpp b/Source/LumatoneController.cpp index ea23c44f..66936fd1 100644 --- a/Source/LumatoneController.cpp +++ b/Source/LumatoneController.cpp @@ -16,6 +16,7 @@ LumatoneController::LumatoneController() : midiDriver(getNumBoards()) , errorVisualizer(TerpstraSysExApplication::getApp().getLookAndFeel()) , readQueueSize(0) + , keyUpdater(midiDriver) { reset(bufferReadSize); midiDriver.addMessageCollector(this); @@ -174,34 +175,19 @@ Combined (hi-level) commands */ -void LumatoneController::sendAllParamsOfBoard(int boardIndex, LumatoneBoard boardData) +void LumatoneController::sendAllParamsOfBoard(int boardIndex, LumatoneBoard boardData, bool bufferMessages) { - if (determinedVersion >= LumatoneFirmwareVersion::VERSION_1_0_11) + for (int keyIndex = 0; keyIndex < octaveSize; keyIndex++) { - for (int keyIndex = 0; keyIndex < octaveSize; keyIndex++) - { - auto key = &boardData.theKeys[keyIndex]; - midiDriver.sendKeyFunctionParameters(boardIndex, keyIndex, key->noteNumber, key->channelNumber, key->keyType & 0x3); - midiDriver.sendKeyLightParameters(boardIndex, keyIndex, key->colour.getRed(), key->colour.getGreen(), key->colour.getBlue()); - *getKey(boardIndex - 1, keyIndex) = *key; - } - } - else - { - for (int keyIndex = 0; keyIndex < octaveSize; keyIndex++) - { - auto key = &boardData.theKeys[keyIndex]; - midiDriver.sendKeyFunctionParameters(boardIndex, keyIndex, key->noteNumber, key->channelNumber, key->keyType & 0x3); - midiDriver.sendKeyLightParameters_Version_1_0_0(boardIndex, keyIndex, key->colour.getRed() / 2, key->colour.getGreen() / 2, key->colour.getBlue() / 2); - *getKey(boardIndex - 1, keyIndex) = *key; - } + auto key = &boardData.theKeys[keyIndex]; + sendKeyParam(boardIndex, keyIndex, *key, bufferMessages); } } -void LumatoneController::sendCompleteMapping(LumatoneLayout mappingData) +void LumatoneController::sendCompleteMapping(LumatoneLayout mappingData, bool bufferMessages) { for (int boardIndex = 1; boardIndex <= getNumBoards(); boardIndex++) - sendAllParamsOfBoard(boardIndex, *mappingData.getBoard(boardIndex - 1)); + sendAllParamsOfBoard(boardIndex, *mappingData.getBoard(boardIndex - 1), bufferMessages); } void LumatoneController::sendGetMappingOfBoardRequest(int boardIndex) @@ -292,12 +278,12 @@ void LumatoneController::testCurrentDeviceConnection() } } -void LumatoneController::sendKeyParam(int boardIndex, int keyIndex, LumatoneKey keyData) +void LumatoneController::sendKeyParam(int boardIndex, int keyIndex, LumatoneKey keyData, bool bufferMessages) // Send parametrization of one key to the device { // Default CC polarity = 1, Inverted CC polarity = 0 - sendKeyConfig(boardIndex, keyIndex, keyData.noteNumber, keyData.channelNumber, keyData.keyType, keyData.ccFaderDefault); - sendKeyColourConfig(boardIndex, keyIndex, keyData.colour); + sendKeyConfig(boardIndex, keyIndex, keyData.noteNumber, keyData.channelNumber, keyData.keyType, keyData.ccFaderDefault, bufferMessages); + sendKeyColourConfig(boardIndex, keyIndex, keyData.colour, bufferMessages); } // Send configuration of a certain look up table @@ -326,20 +312,28 @@ void LumatoneController::sendTableConfig(LumatoneConfigTable::TableType velocity // Mid-level firmware functions // Send note, channel, cc, and fader polarity data -void LumatoneController::sendKeyConfig(int boardIndex, int keyIndex, int noteOrCCNum, int channel, int keyType, bool faderUpIsNull) +void LumatoneController::sendKeyConfig(int boardIndex, int keyIndex, int noteOrCCNum, int channel, int keyType, bool faderUpIsNull, bool bufferMessages) { - midiDriver.sendKeyFunctionParameters(boardIndex, keyIndex, noteOrCCNum, channel, keyType & 0x3, faderUpIsNull); + if (bufferMessages) + keyUpdater.sendKeyConfig(boardIndex, keyIndex, noteOrCCNum, channel, keyType & 0x3, faderUpIsNull); + else + midiDriver.sendKeyFunctionParameters(boardIndex, keyIndex, noteOrCCNum, channel, keyType & 0x3, faderUpIsNull); auto key = getKey(boardIndex - 1, keyIndex); *key = LumatoneKey((LumatoneKeyType)keyType, channel - 1, noteOrCCNum, key->colour, faderUpIsNull); } -void LumatoneController::sendKeyColourConfig(int boardIndex, int keyIndex, Colour colour) +void LumatoneController::sendKeyColourConfig(int boardIndex, int keyIndex, Colour colour, bool bufferMessages) { - if (determinedVersion >= LumatoneFirmwareVersion::VERSION_1_0_11) - midiDriver.sendKeyLightParameters(boardIndex, keyIndex, colour.getRed(), colour.getGreen(), colour.getBlue()); + if (bufferMessages) + keyUpdater.sendKeyColourConfig(boardIndex, keyIndex, colour); else - midiDriver.sendKeyLightParameters_Version_1_0_0(boardIndex, keyIndex, colour.getRed() / 2, colour.getGreen() / 2, colour.getBlue() / 2); + { + if (determinedVersion >= LumatoneFirmwareVersion::VERSION_1_0_11) + midiDriver.sendKeyLightParameters(boardIndex, keyIndex, colour.getRed(), colour.getGreen(), colour.getBlue()); + else + midiDriver.sendKeyLightParameters_Version_1_0_0(boardIndex, keyIndex, colour.getRed() / 2, colour.getGreen() / 2, colour.getBlue() / 2); + } getKey(boardIndex - 1, keyIndex)->colour = colour; } diff --git a/Source/LumatoneController.h b/Source/LumatoneController.h index 9f5ba0ce..6bdc4988 100644 --- a/Source/LumatoneController.h +++ b/Source/LumatoneController.h @@ -15,6 +15,7 @@ #include "TerpstraMidiDriver.h" #include "DeviceActivityMonitor.h" #include "FirmwareTransfer.h" +#include "key_update_buffer.h" //============================================================================== // Helper class for parsing and comparing (todo) firmware versions @@ -41,7 +42,7 @@ class LumatoneController : private TerpstraMidiDriver::Collector, FirmwareVersion getFirmwareVersion() const { return firmwareVersion; } - LumatoneFirmwareVersion getConfirmedVersion() const { return determinedVersion; } + LumatoneFirmwareVersion getLumatoneVersion() const { return determinedVersion; } const FirmwareSupport& getFirmwareSupport() const { return firmwareSupport; } @@ -92,10 +93,10 @@ class LumatoneController : private TerpstraMidiDriver::Collector, // Combined (hi-level) commands // Send all parametrizations of one sub board - void sendAllParamsOfBoard(int boardIndex, LumatoneBoard boardData); + void sendAllParamsOfBoard(int boardIndex, LumatoneBoard boardData, bool bufferMessages=false); // Send and save a complete key mapping - void sendCompleteMapping(LumatoneLayout mappingData); + void sendCompleteMapping(LumatoneLayout mappingData, bool bufferMessages=false); // Send request to receive the current mapping of one sub board on the controller void sendGetMappingOfBoardRequest(int boardIndex); @@ -104,7 +105,7 @@ class LumatoneController : private TerpstraMidiDriver::Collector, void sendGetCompleteMappingRequest(); // Send parametrization of one key to the device - void sendKeyParam(int boardIndex, int keyIndex, LumatoneKey keyData); + void sendKeyParam(int boardIndex, int keyIndex, LumatoneKey keyData, bool bufferMessages = false); // Send configuration of a certain look up table void sendTableConfig(LumatoneConfigTable::TableType velocityCurveType, const uint8* table); @@ -122,9 +123,9 @@ class LumatoneController : private TerpstraMidiDriver::Collector, // Single (mid-level) commands // Send note, channel, cc, and fader polarity data - void sendKeyConfig(int boardIndex, int keyIndex, int noteOrCCNum, int channel, int keyType, bool faderUpIsNull = true); + void sendKeyConfig(int boardIndex, int keyIndex, int noteOrCCNum, int channel, int keyType, bool faderUpIsNull = true, bool bufferMessages = false); - void sendKeyColourConfig(int boardIndex, int keyIndex, Colour colour); + void sendKeyColourConfig(int boardIndex, int keyIndex, Colour colour, bool bufferMessages = false); // Send expression pedal sensivity void sendExpressionPedalSensivity(unsigned char value); @@ -373,6 +374,8 @@ class LumatoneController : private TerpstraMidiDriver::Collector, HajuErrorVisualizer errorVisualizer; TerpstraMidiDriver midiDriver; + LumatoneKeyUpdateBuffer keyUpdater; + std::unique_ptr deviceMonitor; std::unique_ptr firmwareTransfer; diff --git a/Source/Main.h b/Source/Main.h index bd086bba..4946a239 100644 --- a/Source/Main.h +++ b/Source/Main.h @@ -58,6 +58,7 @@ class TerpstraSysExApplication : public JUCEApplication int getOctaveBoardSize() const { return lumatoneController->getOctaveBoardSize(); } int getNumBoards() const { return lumatoneController->getNumBoards(); } + LumatoneFirmwareVersion getLumatoneVersion() const { return lumatoneController->getLumatoneVersion(); } FirmwareVersion getFirmwareVersion() const { return lumatoneController->getFirmwareVersion(); } String getFirmwareVersionStr() const { return lumatoneController->getFirmwareVersion().toDisplayString(); } diff --git a/Source/key_update_buffer.cpp b/Source/key_update_buffer.cpp new file mode 100644 index 00000000..c8ed8907 --- /dev/null +++ b/Source/key_update_buffer.cpp @@ -0,0 +1,134 @@ +#include "key_update_buffer.h" +#include "Main.h" + +LumatoneKeyUpdateBuffer::LumatoneKeyUpdateBuffer(TerpstraMidiDriver& driverIn) + : midiDriver(driverIn) +{ + keysToUpdate.remapTable(280); +} + +LumatoneKeyUpdateBuffer::~LumatoneKeyUpdateBuffer() +{ + +} + +int LumatoneKeyUpdateBuffer::getKeyNum(int boardIndex, int keyIndex) const +{ + return boardIndex * TerpstraSysExApplication::getApp().getOctaveBoardSize() + keyIndex; +} + +LumatoneKeyCoord LumatoneKeyUpdateBuffer::getKeyCoord(int keyNum) const +{ + return LumatoneKeyCoord(keyNum / TerpstraSysExApplication::getApp().getOctaveBoardSize(), + keyNum % TerpstraSysExApplication::getApp().getOctaveBoardSize()); +} + +void LumatoneKeyUpdateBuffer::sendKeyConfig(int boardId, int keyIndex, const LumatoneKey& noteDataConfig, bool signalEditorListeners) +{ + updateKeyConfig(boardId - 1, keyIndex, noteDataConfig); +} + +void LumatoneKeyUpdateBuffer::sendKeyConfig(int boardIndex, int keyIndex, int noteOrCCNum, int channel, int keyType, bool faderUpIsNull) +{ + auto config = LumatoneKey(LumatoneKeyType(keyType), channel, noteOrCCNum, juce::Colour(), faderUpIsNull); + updateKeyConfig(boardIndex, keyIndex, config); +} + +void LumatoneKeyUpdateBuffer::sendKeyColourConfig(int boardId, int keyIndex, juce::Colour colour, bool signalEditorListeners) +{ + updateKeyColour(boardId - 1, keyIndex, colour); +} + +void LumatoneKeyUpdateBuffer::updateKeyConfig(int boardIndex, int keyIndex, const LumatoneKey& config) +{ + lock.enter(); + // while (!lock.tryEnter()) {} + + auto keyNum = getKeyNum(boardIndex, keyIndex); + MappedLumatoneKey currentUpdateData = keysToUpdate[keyNum]; + + auto currentKey = TerpstraSysExApplication::getApp().getMappingData()->readKey(boardIndex, keyIndex); + preUpdateLayout.getBoard(boardIndex)->theKeys[keyIndex] = *currentKey; + + if (*currentKey == config) + { + keysToUpdate.set(keyNum, MappedLumatoneKey()); + } + else if (currentUpdateData.boardIndex < 0 || currentUpdateData.keyIndex < 0) + { + keysToUpdate.set(keyNum, MappedLumatoneKey(config.withColour(currentKey->colour), boardIndex, keyIndex)); + } + else if (!currentUpdateData.configIsEqual(config)) + { + keysToUpdate.set(keyNum, MappedLumatoneKey(config.withColour(currentUpdateData.colour), boardIndex, keyIndex)); + } + + lock.exit(); + startTimer(updateMs); +} + +void LumatoneKeyUpdateBuffer::updateKeyColour(int boardIndex, int keyIndex, juce::Colour colour) +{ + lock.enter(); + // while (!lock.tryEnter()) {} + + auto keyNum = getKeyNum(boardIndex, keyIndex); + MappedLumatoneKey currentUpdateData = keysToUpdate[keyNum]; + auto currentKey = TerpstraSysExApplication::getApp().getMappingData()->readKey(boardIndex, keyIndex); + preUpdateLayout.getBoard(boardIndex)->theKeys[keyIndex] = *currentKey; + + if (currentKey->colour == colour && currentKey->configIsEqual(currentUpdateData)) + { + keysToUpdate.set(keyNum, MappedLumatoneKey()); + } + else if (currentUpdateData.boardIndex < 0 || currentUpdateData.keyIndex < 0) + { + keysToUpdate.set(keyNum, MappedLumatoneKey(currentKey->withColour(colour), boardIndex, keyIndex)); + } + else if (currentUpdateData.colour != colour) + { + keysToUpdate.set(keyNum, MappedLumatoneKey(currentUpdateData.withColour(colour), boardIndex, keyIndex)); + } + + lock.exit(); + startTimer(updateMs); +} + +void LumatoneKeyUpdateBuffer::timerCallback() +{ + stopTimer(); + + if (! lock.tryEnter()) + return; + + int keyNum = 0; + for (int board = 0; board < TerpstraSysExApplication::getApp().getNumBoards(); board++) + { + int boardId = board + 1; + for (int keyIndex = 0; keyIndex < TerpstraSysExApplication::getApp().getOctaveBoardSize(); keyIndex++) + { + auto keyUpdate = keysToUpdate[keyNum]; + if (keyUpdate.boardIndex >= 0 && keyUpdate.keyIndex >= 0) + { + // auto currentKey = getKey(board, keyIndex); + auto currentKey = preUpdateLayout.getBoard(board)->theKeys[keyIndex]; + if (!currentKey.configIsEqual(keyUpdate)) + midiDriver.sendKeyFunctionParameters(boardId, keyIndex, keyUpdate.noteNumber, keyUpdate.channelNumber, keyUpdate.keyType, keyUpdate.ccFaderDefault); + + if (!currentKey.colourIsEqual(keyUpdate)) + { + auto colour = keyUpdate.colour; + if (TerpstraSysExApplication::getApp().getLumatoneVersion() >= LumatoneFirmwareVersion::VERSION_1_0_11) + midiDriver.sendKeyLightParameters(boardId, keyIndex, colour.getRed(), colour.getGreen(), colour.getBlue()); + else + midiDriver.sendKeyLightParameters_Version_1_0_0(boardId, keyIndex, colour.getRed() * 0.5f, colour.getGreen() * 0.5f, colour.getBlue() * 0.5f); + } + } + + keysToUpdate.set(keyNum, MappedLumatoneKey()); + keyNum++; + } + } + + lock.exit(); +} diff --git a/Source/key_update_buffer.h b/Source/key_update_buffer.h new file mode 100644 index 00000000..e57dfe87 --- /dev/null +++ b/Source/key_update_buffer.h @@ -0,0 +1,40 @@ +#pragma once + +#include "./data/lumatone_layout.h" + +#include "TerpstraMidiDriver.h" + +class LumatoneKeyUpdateBuffer : private juce::Timer +{ +public: + + LumatoneKeyUpdateBuffer(TerpstraMidiDriver& midiDriver); + ~LumatoneKeyUpdateBuffer() override; + + void sendKeyConfig(int boardId, int keyIndex, const LumatoneKey& noteDataConfig, bool signalEditorListeners = true); + void sendKeyConfig(int boardIndex, int keyIndex, int noteOrCCNum, int channel, int keyType, bool faderUpIsNull = true); + + void sendKeyColourConfig(int boardId, int keyIndex, juce::Colour colour, bool signalEditorListeners = true); + + void timerCallback() override; + +private: + + int getKeyNum(int boardIndex, int keyIndex) const; + LumatoneKeyCoord getKeyCoord(int keyNum) const; + + void updateKeyConfig(int boardIndex, int keyIndex, const LumatoneKey& config); + void updateKeyColour(int boardIndex, int keyIndex, juce::Colour colour); + +private: + + juce::CriticalSection lock; + + TerpstraMidiDriver& midiDriver; + + juce::HashMap keysToUpdate; + + LumatoneLayout preUpdateLayout; + + int updateMs = 300; +}; diff --git a/TerpstraSysEx.jucer b/TerpstraSysEx.jucer index bca776b9..6cab7a0c 100644 --- a/TerpstraSysEx.jucer +++ b/TerpstraSysEx.jucer @@ -173,6 +173,10 @@ + +