From 1c3d9677a8ac363ce93470019d5abd2033ad5418 Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Mon, 15 Jan 2024 17:53:16 -0500 Subject: [PATCH 01/19] get cmake building for macos --- CMakeLists.txt | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a64ee02..49afb05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,11 +34,6 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") set(LibraryPath "${CMAKE_CURRENT_SOURCE_DIR}/Libraries/win64") set(LibraryInclude "${LibraryPath}/include") set(LibraryCode "${LibraryInclude}/libssh2.h") - # set(CryptoLib "${CMAKE_CURRENT_SOURCE_DIR}/Libraries/win64/bin/libcrypto-1_1-x64.dll") - # set(SSHLib "${CMAKE_CURRENT_SOURCE_DIR}/Libraries/win64/bin/libssh2-x64.dll") - - # add_library( CryptoLib SHARED IMPORTED ) - # set_target_properties( CryptoLib PROPERTIES IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/libcrypto-1_1-x64.dll" ) add_library( SSHLib SHARED IMPORTED ) set_target_properties( SSHLib PROPERTIES IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/libssh2-x64.dll" ) @@ -46,14 +41,12 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") endif() if (UNIX) - set(LibraryInclude "${CMAKE_CURRENT_SOURCE_DIR}/Libraries/mac/include") - set(LibraryCode "${CMAKE_CURRENT_SOURCE_DIR}/Libraries/mac/include/libssh2.h") - file(READ - CryptoLib - "${CMAKE_CURRENT_SOURCE_DIR}/Libraries/mac/lib/libgpg-error.dylib" - "${CMAKE_CURRENT_SOURCE_DIR}/Libraries/mac/lib/libgcrypt.dylib" - ) - file(READ SSHLib "${CMAKE_CURRENT_SOURCE_DIR}/Libraries/mac/lib/libssh2.dylib") + set(LibraryPath "${CMAKE_CURRENT_SOURCE_DIR}/Libraries/mac") + set(LibraryInclude "${LibraryPath}/include") + set(LibraryCode "${LibraryInclude}/libssh2.h") + + add_library(SSHLib SHARED IMPORTED) + set_target_properties( SSHLib PROPERTIES IMPORTED_LOCATION "${LibraryPath}/lib/libssh2.dylib") endif() include_directories(${LibraryInclude}) @@ -133,3 +126,18 @@ target_link_libraries(LumatoneEditor juce::juce_recommended_lto_flags juce::juce_recommended_warning_flags ) + +# if (APPLE) +# add_custom_command( +# LumatoneEditor ${JUCE_PRODUCT_NAME} POST_BUILD +# COMMAND +# ${CMAKE_COMMAND} -E copy +# "${LibraryPath}/lib/libssh2.dylib" +# "$/../Resources/libssh2.dylib" +# ) +# add_custom_command( +# LumatoneEditor ${JUCE_PRODUCT_NAME} POST_BUILD +# COMMAND install_name_tool -change @rpath/libssh2.dylib @loader_path/../Frameworks/libssh2.dylib $ +# ) +# endif() + From be20632ef1b0c8dbfe1c1ad21c508e853ef0ff03 Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Tue, 16 Jan 2024 02:25:40 -0500 Subject: [PATCH 02/19] move application state setters to controller class --- Source/LumatoneEditorState.cpp | 6 +-- Source/LumatoneEditorState.h | 18 ++++++- .../data/application_state.cpp | 32 +++++++----- .../data/application_state.h | 41 +++++++++++---- .../device/activity_monitor.cpp | 12 ++--- .../device/activity_monitor.h | 4 +- .../device/lumatone_controller.cpp | 52 +++---------------- .../device/lumatone_controller.h | 2 +- 8 files changed, 86 insertions(+), 81 deletions(-) diff --git a/Source/LumatoneEditorState.cpp b/Source/LumatoneEditorState.cpp index c01a764..59e2789 100644 --- a/Source/LumatoneEditorState.cpp +++ b/Source/LumatoneEditorState.cpp @@ -35,7 +35,7 @@ juce::Array GetLumatoneEditorProperty() LumatoneEditorState::LumatoneEditorState(juce::String name, LumatoneFirmwareDriver& driverIn, juce::UndoManager *undoManagerIn) - : LumatoneApplicationState("LumatoneEditor", driverIn, juce::ValueTree(), undoManagerIn) + : LumatoneApplicationStateController("LumatoneEditor", driverIn, juce::ValueTree(), undoManagerIn) { appFonts = std::make_shared(); lookAndFeel = std::make_shared(*appFonts, true); @@ -62,11 +62,11 @@ LumatoneEditorState::LumatoneEditorState(juce::String name, LumatoneFirmwareDriv } LumatoneEditorState::LumatoneEditorState(juce::String name, const LumatoneEditorState &stateIn) - : LumatoneApplicationState(name, stateIn) + : LumatoneApplicationStateController(name, stateIn) , appFonts(stateIn.appFonts) , lookAndFeel(stateIn.lookAndFeel) - , propertiesFile(stateIn.propertiesFile) , recentFiles(stateIn.recentFiles) + , propertiesFile(stateIn.propertiesFile) , colourPalettes(stateIn.colourPalettes) { } diff --git a/Source/LumatoneEditorState.h b/Source/LumatoneEditorState.h index 003f717..f58b79b 100644 --- a/Source/LumatoneEditorState.h +++ b/Source/LumatoneEditorState.h @@ -72,7 +72,7 @@ static juce::Array GetLumatoneEditorProperties(); class LumatoneEditorStateController; -class LumatoneEditorState : public LumatoneApplicationState +class LumatoneEditorState : public LumatoneApplicationStateController { public: LumatoneEditorState(juce::String name, const LumatoneEditorState& stateIn); @@ -129,6 +129,13 @@ class LumatoneEditorState : public LumatoneApplicationState EditorMode editorMode = EditorMode::OFFLINE; +private: + using LumatoneApplicationStateController::setConnectionState; + using LumatoneApplicationStateController::getEditorListeners; + using LumatoneApplicationStateController::getStatusListeners; + using LumatoneApplicationStateController::getFirmwareListeners; + using LumatoneApplicationStateController::getMidiListeners; + private: std::shared_ptr appFonts; std::shared_ptr lookAndFeel; @@ -139,7 +146,7 @@ class LumatoneEditorState : public LumatoneApplicationState std::shared_ptr propertiesFile; - friend class LumatoneEditorStateController; + friend class LumatoneEditorStateController; }; class LumatoneEditorStateController : public LumatoneEditorState @@ -169,6 +176,13 @@ class LumatoneEditorStateController : public LumatoneEditorState void setDeveloperMode(bool developerModeOn) override { LumatoneEditorState::setDeveloperMode(developerModeOn); } void setEditMode(EditorMode editMode) override { LumatoneEditorState::setEditMode(editMode); } + +protected: + using LumatoneApplicationStateController::setConnectionState; + using LumatoneApplicationStateController::getEditorListeners; + using LumatoneApplicationStateController::getStatusListeners; + using LumatoneApplicationStateController::getFirmwareListeners; + using LumatoneApplicationStateController::getMidiListeners; }; diff --git a/Source/lumatone_editor_library/data/application_state.cpp b/Source/lumatone_editor_library/data/application_state.cpp index f4bb272..062e7c3 100644 --- a/Source/lumatone_editor_library/data/application_state.cpp +++ b/Source/lumatone_editor_library/data/application_state.cpp @@ -21,15 +21,15 @@ juce::Array getLumatoneApplicationProperties() LumatoneApplicationState::LumatoneApplicationState(juce::String nameIn, LumatoneFirmwareDriver& driverIn, juce::ValueTree stateIn, juce::UndoManager *undoManagerIn) : LumatoneState(nameIn, stateIn, undoManagerIn) { + editorListeners = std::make_shared>(); + statusListeners = std::make_shared>(); + firmwareListeners = std::make_shared>(); + midiListeners = std::make_shared>(); + layoutContext = std::make_shared(*mappingData); controller = std::make_shared(*this, driverIn); colourModel = std::make_shared(); - editorListeners.reset(new juce::ListenerList()); - statusListeners.reset(new juce::ListenerList()); - firmwareListeners.reset(new juce::ListenerList()); - midiListeners.reset(new juce::ListenerList()); - loadStateProperties(stateIn); } @@ -43,13 +43,13 @@ LumatoneApplicationState::LumatoneApplicationState(juce::String nameIn, Lumatone LumatoneApplicationState::LumatoneApplicationState(juce::String nameIn, const LumatoneApplicationState &stateIn) : LumatoneState(nameIn, (const LumatoneState&)stateIn) - , layoutContext(stateIn.layoutContext) - , controller(stateIn.controller) - , colourModel(stateIn.colourModel) , editorListeners(stateIn.editorListeners) , statusListeners(stateIn.statusListeners) , firmwareListeners(stateIn.firmwareListeners) , midiListeners(stateIn.midiListeners) + , layoutContext(stateIn.layoutContext) + , controller(stateIn.controller) + , colourModel(stateIn.colourModel) { loadStateProperties(state); } @@ -417,9 +417,9 @@ void LumatoneApplicationState::addFirmwareListener(LumatoneEditor::FirmwareListe firmwareListeners->add(listenerIn); } -void LumatoneApplicationState::removeMidiListener(LumatoneEditor::MidiListener* listenerIn) +void LumatoneApplicationState::removeFirmwareListener(LumatoneEditor::FirmwareListener* listenerIn) { - midiListeners->remove(listenerIn); + firmwareListeners->remove(listenerIn); } void LumatoneApplicationState::addMidiListener(LumatoneEditor::MidiListener* listenerIn) @@ -427,7 +427,15 @@ void LumatoneApplicationState::addMidiListener(LumatoneEditor::MidiListener* lis midiListeners->add(listenerIn); } -void LumatoneApplicationState::removeFirmwareListener(LumatoneEditor::FirmwareListener* listenerIn) +void LumatoneApplicationState::removeMidiListener(LumatoneEditor::MidiListener* listenerIn) { - firmwareListeners->remove(listenerIn); + midiListeners->remove(listenerIn); +} + +void LumatoneApplicationStateController::setConnectionState(ConnectionState newState, bool sendNotification) +{ + connectionState = newState; + state.setPropertyExcludingListener(this, LumatoneApplicationProperty::ConnectionStateId, juce::var((int)connectionState), nullptr); + if (sendNotification) + statusListeners->call(&LumatoneEditor::StatusListener::connectionStateChanged, connectionState); } diff --git a/Source/lumatone_editor_library/data/application_state.h b/Source/lumatone_editor_library/data/application_state.h index 45178e9..90fea58 100644 --- a/Source/lumatone_editor_library/data/application_state.h +++ b/Source/lumatone_editor_library/data/application_state.h @@ -50,13 +50,14 @@ class LumatoneColourModel; class LumatoneAction; class DeviceActivityMonitor; +class LumatoneApplicationStateController; class LumatoneApplicationState : public LumatoneState { public: LumatoneApplicationState(juce::String nameIn, LumatoneFirmwareDriver& driverIn, juce::ValueTree stateIn=juce::ValueTree(), juce::UndoManager* undoManager=nullptr); LumatoneApplicationState(juce::String nameIn, const LumatoneApplicationState& stateIn); - virtual ~LumatoneApplicationState(); + virtual ~LumatoneApplicationState() override; LumatoneController* getLumatoneController() const; LumatoneColourModel* getColourModel() const; @@ -113,12 +114,6 @@ class LumatoneApplicationState : public LumatoneState private: ConnectionState connectionState = ConnectionState::DISCONNECTED; - std::shared_ptr layoutContext; - std::shared_ptr controller; - std::shared_ptr colourModel; - - bool contextIsSet = false; - private: std::shared_ptr> statusListeners; public: @@ -143,9 +138,35 @@ class LumatoneApplicationState : public LumatoneState void addFirmwareListener(LumatoneEditor::FirmwareListener* listenerIn); void removeFirmwareListener(LumatoneEditor::FirmwareListener* listenerIn); - // Allow these to edit state and signal listeners - friend class LumatoneController; - friend class DeviceActivityMonitor; + +private: + std::shared_ptr layoutContext; + std::shared_ptr controller; + std::shared_ptr colourModel; + + bool contextIsSet = false; + +//================================================================================ + + friend class LumatoneApplicationStateController; +}; + +class LumatoneApplicationStateController : public LumatoneApplicationState +{ +public: + LumatoneApplicationStateController(juce::String nameIn, LumatoneFirmwareDriver& driverIn, juce::ValueTree stateIn=juce::ValueTree(), juce::UndoManager* undoManager=nullptr) + : LumatoneApplicationState(nameIn, driverIn, stateIn, undoManager) {} + LumatoneApplicationStateController(juce::String nameIn, const LumatoneApplicationState& stateIn) + : LumatoneApplicationState(nameIn, stateIn) {} + +protected: + virtual void setConnectionState(ConnectionState newState, bool sendNotification=true); + + juce::ListenerList* getEditorListeners() const { return editorListeners.get(); } + juce::ListenerList* getStatusListeners() const { return statusListeners.get(); } + juce::ListenerList* getFirmwareListeners() const { return firmwareListeners.get(); } + juce::ListenerList* getMidiListeners() const { return midiListeners.get(); } + }; #endif LUMATONE_APPLICATION_STATE_H diff --git a/Source/lumatone_editor_library/device/activity_monitor.cpp b/Source/lumatone_editor_library/device/activity_monitor.cpp index ef1b66d..9fdaaf7 100644 --- a/Source/lumatone_editor_library/device/activity_monitor.cpp +++ b/Source/lumatone_editor_library/device/activity_monitor.cpp @@ -15,8 +15,8 @@ #include "../listeners/status_listener.h" -DeviceActivityMonitor::DeviceActivityMonitor(LumatoneFirmwareDriver* midiDriverIn, LumatoneApplicationState stateIn) - : LumatoneApplicationState("DeviceActivityMonitor", stateIn) +DeviceActivityMonitor::DeviceActivityMonitor(LumatoneFirmwareDriver* midiDriverIn, const LumatoneApplicationState& stateIn) + : LumatoneApplicationStateController("DeviceActivityMonitor", stateIn) , midiDriver(midiDriverIn) { // detectDevicesIfDisconnected = getBoolProperty(LumatoneApplicationProperty::DetectDeviceIfDisconnected, true); @@ -265,7 +265,7 @@ void DeviceActivityMonitor::checkDetectionStatus() if (isConnectionEstablished()) { deviceDetectInProgress = false; - statusListeners->call(&LumatoneEditor::StatusListener::connectionStateChanged, ConnectionState::ONLINE); + getStatusListeners()->call(&LumatoneEditor::StatusListener::connectionStateChanged, ConnectionState::ONLINE); outputPingIds.clear(); @@ -286,7 +286,7 @@ void DeviceActivityMonitor::checkDetectionStatus() waitingForResponse = false; startTimer(detectRoutineTimeoutMs); - statusListeners->call(&LumatoneEditor::StatusListener::connectionFailed); + getStatusListeners()->call(&LumatoneEditor::StatusListener::connectionFailed); } else { @@ -340,7 +340,7 @@ void DeviceActivityMonitor::checkDetectionStatus() waitingForResponse = false; startTimer(detectRoutineTimeoutMs); - statusListeners->call(&LumatoneEditor::StatusListener::connectionFailed); + getStatusListeners()->call(&LumatoneEditor::StatusListener::connectionFailed); } } @@ -570,7 +570,7 @@ void DeviceActivityMonitor::onDisconnection() waitingForResponse = false; - statusListeners->call(&LumatoneEditor::StatusListener::connectionStateChanged, ConnectionState::DISCONNECTED); + getStatusListeners()->call(&LumatoneEditor::StatusListener::connectionStateChanged, ConnectionState::DISCONNECTED); if (detectDevicesIfDisconnected) { diff --git a/Source/lumatone_editor_library/device/activity_monitor.h b/Source/lumatone_editor_library/device/activity_monitor.h index 80056f3..096c2ea 100644 --- a/Source/lumatone_editor_library/device/activity_monitor.h +++ b/Source/lumatone_editor_library/device/activity_monitor.h @@ -24,7 +24,7 @@ class LumatoneFirmwareDriver; -class DeviceActivityMonitor : protected LumatoneApplicationState, +class DeviceActivityMonitor : protected LumatoneApplicationStateController, public juce::Timer, protected LumatoneFirmwareDriverListener { @@ -40,7 +40,7 @@ class DeviceActivityMonitor : protected LumatoneApplicationState, public: - DeviceActivityMonitor(LumatoneFirmwareDriver* midiDriverIn, LumatoneApplicationState stateIn); + DeviceActivityMonitor(LumatoneFirmwareDriver* midiDriverIn, const LumatoneApplicationState& stateIn); ~DeviceActivityMonitor() override; DetectConnectionMode getMode() const { return deviceConnectionMode; } diff --git a/Source/lumatone_editor_library/device/lumatone_controller.cpp b/Source/lumatone_editor_library/device/lumatone_controller.cpp index 1ca0173..9bccc80 100644 --- a/Source/lumatone_editor_library/device/lumatone_controller.cpp +++ b/Source/lumatone_editor_library/device/lumatone_controller.cpp @@ -16,7 +16,7 @@ #include "../listeners/editor_listener.h" LumatoneController::LumatoneController(const LumatoneApplicationState& stateIn, LumatoneFirmwareDriver& firmwareDriverIn) - : LumatoneApplicationState("LumatoneController", stateIn) + : LumatoneApplicationStateController("LumatoneController", stateIn) , LumatoneApplicationMidiController(stateIn, firmwareDriverIn) , firmwareDriver(firmwareDriverIn) , updateBuffer(firmwareDriverIn, stateIn) @@ -36,22 +36,9 @@ LumatoneController::~LumatoneController() juce::ValueTree LumatoneController::loadStateProperties(juce::ValueTree stateIn) { LumatoneApplicationState::loadStateProperties(stateIn); - //editorListeners.call(&LumatoneEditor::EditorListener::completeMappingLoaded, *getMappingData()); return state; } -// void LumatoneController::setContext(const LumatoneContext& contextIn) -// { -// LumatoneApplicationState::setContext(contextIn); -// editorListeners.call(&LumatoneEditor::EditorListener::contextChanged, layoutContext.get()); -// } - -// void LumatoneController::clearContext() -// { -// LumatoneApplicationState::clearContext(); -// editorListeners.call(&LumatoneEditor::EditorListener::contextChanged, nullptr); -// } - void LumatoneController::connectionStateChanged(ConnectionState newState) { switch (newState) @@ -149,9 +136,6 @@ void LumatoneController::sendAllParamsOfBoard(int boardId, const LumatoneBoard* LumatoneKey key = boardData->getKey(keyIndex); sendKeyParam(boardId, keyIndex, key, false, bufferKeyUpdates); } - - //if (signalEditorListeners) - // editorListeners.call(&LumatoneEditor::EditorListener::boardChanged, *boardData); } void LumatoneController::sendCompleteMapping(const LumatoneLayout& mappingData, bool signalEditorListeners, bool bufferKeyUpdates) @@ -160,9 +144,6 @@ void LumatoneController::sendCompleteMapping(const LumatoneLayout& mappingData, sendAllParamsOfBoard(boardId, &mappingData.getBoard(boardId - 1), false, bufferKeyUpdates); clearContext(); - - //if (signalEditorListeners) - // editorListeners.call(&LumatoneEditor::EditorListener::completeMappingLoaded, mappingData); } void LumatoneController::sendCurrentCompleteConfig(bool signalEditorListeners) @@ -275,9 +256,6 @@ void LumatoneController::sendKeyParam(int boardId, int keyIndex, LumatoneKey key // Default CC polarity = 1, Inverted CC polarity = 0 sendKeyConfig(boardId, keyIndex, keyData, false, bufferKeyUpdates); sendKeyColourConfig(boardId, keyIndex, keyData, false, bufferKeyUpdates); - - //if (signalEditorListeners) - // editorListeners.call(&LumatoneEditor::EditorListener::keyChanged, boardId - 1, keyIndex, keyData); } // Send configuration of a certain look up table @@ -339,9 +317,6 @@ void LumatoneController::sendKeyConfig(int boardId, int keyIndex, const Lumatone updateBuffer.sendKeyConfig(boardId, keyIndex, keyData); else firmwareDriver.sendKeyFunctionParameters(boardId, keyIndex, keyData.getMidiNumber(), keyData.getMidiChannel(), keyData.getType(), keyData.isCCFaderDefault()); - - //if (signalEditorListeners) - // editorListeners.call(&LumatoneEditor::EditorListener::keyConfigChanged, boardId - 1, keyIndex, keyData); } void LumatoneController::sendKeyColourConfig(int boardId, int keyIndex, juce::Colour colour, bool signalEditorListeners, bool bufferKeyUpdates) @@ -355,9 +330,6 @@ void LumatoneController::sendKeyColourConfig(int boardId, int keyIndex, juce::Co else firmwareDriver.sendKeyLightParameters_Version_1_0_0(boardId, keyIndex, colour.getRed() / 2, colour.getGreen() / 2, colour.getBlue() / 2); } - - //if (signalEditorListeners) - //editorListeners.call(&LumatoneEditor::EditorListener::keyColourChanged, boardId - 1, keyIndex, colour); } void LumatoneController::sendKeyColourConfig(int boardId, int keyIndex, const LumatoneKey& keyColourConfig, bool signalEditorListeners, bool bufferKeyUpdates) @@ -371,7 +343,6 @@ void LumatoneController::sendExpressionPedalSensivity(unsigned char value) { setExpressionSensitivity(value); firmwareDriver.sendExpressionPedalSensivity(value); - //editorListeners.call(&LumatoneEditor::EditorListener::expressionPedalSensitivityChanged, value); } // Send parametrization of foot controller @@ -379,7 +350,6 @@ void LumatoneController::sendInvertFootController(bool value) { setInvertExpression(value); firmwareDriver.sendInvertFootController(value); - //editorListeners.call(&LumatoneEditor::EditorListener::invertFootControllerChanged, value); } // Colour for macro button in active state @@ -390,7 +360,6 @@ void LumatoneController::sendMacroButtonActiveColour(juce::String colourAsString firmwareDriver.sendMacroButtonActiveColour(c.getRed(), c.getGreen(), c.getBlue()); else firmwareDriver.sendMacroButtonActiveColour_Version_1_0_0(c.getRed(), c.getGreen(), c.getBlue()); - //editorListeners.call(&LumatoneEditor::EditorListener::macroButtonActiveColourChagned, c); } // Colour for macro button in inactive state @@ -401,21 +370,18 @@ void LumatoneController::sendMacroButtonInactiveColour(juce::String colourAsStri firmwareDriver.sendMacroButtonInactiveColour(c.getRed(), c.getGreen(), c.getBlue()); else firmwareDriver.sendMacroButtonInactiveColour_Version_1_0_0(c.getRed(), c.getGreen(), c.getBlue()); - //editorListeners.call(&LumatoneEditor::EditorListener::macroButtonInactiveColourChanged, c); } // Send parametrization of light on keystrokes void LumatoneController::sendLightOnKeyStrokes(bool value) { firmwareDriver.sendLightOnKeyStrokes(value); - //editorListeners.call(&LumatoneEditor::EditorListener::lightOnKeyStrokesChanged, value); } // Send a value for a velocity lookup table void LumatoneController::sendVelocityConfig(const juce::uint8 velocityTable[]) { firmwareDriver.sendVelocityConfig(velocityTable); - //editorListeners.call(&LumatoneEditor::EditorListener::tableChanged, LumatoneConfigTable::TableType::velocityInterval, velocityTable, VELOCITYINTERVALTABLESIZE); } // Save velocity config to EEPROM @@ -432,7 +398,6 @@ void LumatoneController::resetVelocityConfig() void LumatoneController::setFaderConfig(const juce::uint8 faderTable[]) { firmwareDriver.sendFaderConfig(faderTable); - //editorListeners.call(&LumatoneEditor::EditorListener::tableChanged, LumatoneConfigTable::TableType::fader, faderTable, VELOCITYINTERVALTABLESIZE); } void LumatoneController::resetFaderConfig() @@ -453,7 +418,6 @@ void LumatoneController::startCalibrateAftertouch() void LumatoneController::setAftertouchConfig(const juce::uint8 aftertouchTable[]) { firmwareDriver.sendAftertouchConfig(aftertouchTable); - //editorListeners.call(&LumatoneEditor::EditorListener::tableChanged, LumatoneConfigTable::TableType::afterTouch, aftertouchTable, VELOCITYINTERVALTABLESIZE); } void LumatoneController::resetAftertouchConfig() @@ -541,7 +505,6 @@ void LumatoneController::setCalibratePitchModWheel(bool startCalibration) void LumatoneController::setLumatouchConfig(const juce::uint8 lumatouchTable[]) { firmwareDriver.setLumatouchConfig(lumatouchTable); - //editorListeners.call(&LumatoneEditor::EditorListener::tableChanged, LumatoneConfigTable::TableType::lumaTouch, lumatouchTable, VELOCITYINTERVALTABLESIZE); } void LumatoneController::resetLumatouchConfig() @@ -642,7 +605,7 @@ void LumatoneController::onConnectionConfirmed() sendGetFirmwareRevisionRequest(); } - statusListeners->call(&LumatoneEditor::StatusListener::connectionStateChanged, ConnectionState::ONLINE); + setConnectionState(ConnectionState::ONLINE); } void LumatoneController::handleStatePropertyChange(juce::ValueTree stateIn, const juce::Identifier &property) @@ -718,9 +681,8 @@ void LumatoneController::octaveColourConfigReceived(int boardId, juce::uint8 rgb } LumatoneState::setBoard(editedBoard, boardId); - editorListeners->call(&LumatoneEditor::EditorListener::boardChanged, editedBoard); -}; - + getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, editedBoard); +} void LumatoneController::octaveChannelConfigReceived(int boardId, const int* channelData) { @@ -738,7 +700,7 @@ void LumatoneController::octaveChannelConfigReceived(int boardId, const int* cha } LumatoneState::setBoard(editedBoard, boardId); - editorListeners->call(&LumatoneEditor::EditorListener::boardChanged, editedBoard); + getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, editedBoard); } void LumatoneController::octaveNoteConfigReceived(int boardId, const int* noteData) @@ -757,7 +719,7 @@ void LumatoneController::octaveNoteConfigReceived(int boardId, const int* noteDa } LumatoneState::setBoard(editedBoard, boardId); - editorListeners->call(&LumatoneEditor::EditorListener::boardChanged, editedBoard); + getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, editedBoard); } void LumatoneController::keyTypeConfigReceived(int boardId, const int* keyTypeData) @@ -774,7 +736,7 @@ void LumatoneController::keyTypeConfigReceived(int boardId, const int* keyTypeDa } LumatoneState::setBoard(editedBoard, boardId); - editorListeners->call(&LumatoneEditor::EditorListener::boardChanged, editedBoard); + getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, editedBoard); } void LumatoneController::macroButtonColoursReceived(juce::Colour inactiveColour, juce::Colour activeColour) diff --git a/Source/lumatone_editor_library/device/lumatone_controller.h b/Source/lumatone_editor_library/device/lumatone_controller.h index 323636d..4f42b18 100644 --- a/Source/lumatone_editor_library/device/lumatone_controller.h +++ b/Source/lumatone_editor_library/device/lumatone_controller.h @@ -26,7 +26,7 @@ class LumatoneAction; // Helper class for parsing and comparing (todo) firmware versions -class LumatoneController : private LumatoneApplicationState +class LumatoneController : private LumatoneApplicationStateController , public LumatoneApplicationMidiController , public LumatoneEditor::StatusListener , protected LumatoneEditor::FirmwareListener From a79ca5fdef0249caba080f472d76b170497a6c80 Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Tue, 16 Jan 2024 02:25:58 -0500 Subject: [PATCH 03/19] fix midi edit area connect callback --- Source/MidiEditArea.cpp | 150 ++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 84 deletions(-) diff --git a/Source/MidiEditArea.cpp b/Source/MidiEditArea.cpp index d78294c..bae92d3 100644 --- a/Source/MidiEditArea.cpp +++ b/Source/MidiEditArea.cpp @@ -79,28 +79,24 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) cbMidiInput.reset (new juce::ComboBox ("cbMidiInput")); addAndMakeVisible (cbMidiInput.get()); - cbMidiInput->setTooltip (TRANS("Receives answers to sent SysEx commands and the current configuration from controller ")); + cbMidiInput->setTooltip (juce::translate("Receives answers to sent SysEx commands and the current configuration from controller ")); cbMidiInput->setEditableText (false); cbMidiInput->setJustificationType (juce::Justification::centredLeft); - cbMidiInput->setTextWhenNothingSelected (TRANS("Select MIDI Input")); - cbMidiInput->setTextWhenNoChoicesAvailable (TRANS("(no choices)")); + cbMidiInput->setTextWhenNothingSelected (juce::translate("Select MIDI Input")); + cbMidiInput->setTextWhenNoChoicesAvailable (juce::translate("(no choices)")); cbMidiInput->addListener (this); - cbMidiInput->setBounds (232, 8, 184, 24); - cbMidiOutput.reset (new juce::ComboBox ("cbMidiOutput")); addAndMakeVisible (cbMidiOutput.get()); - cbMidiOutput->setTooltip (TRANS("Key mappings are sent to this port. This happens automatically if a valid MIDI port is selected.")); + cbMidiOutput->setTooltip (juce::translate("Key mappings are sent to this port. This happens automatically if a valid MIDI port is selected.")); cbMidiOutput->setEditableText (false); cbMidiOutput->setJustificationType (juce::Justification::centredLeft); - cbMidiOutput->setTextWhenNothingSelected (TRANS("Select MIDI Output")); - cbMidiOutput->setTextWhenNoChoicesAvailable (TRANS("(no choices)")); + cbMidiOutput->setTextWhenNothingSelected (juce::translate("Select MIDI Output")); + cbMidiOutput->setTextWhenNoChoicesAvailable (juce::translate("(no choices)")); cbMidiOutput->addListener (this); - cbMidiOutput->setBounds (432, 8, 184, 24); - lblConnectionState.reset (new juce::Label ("lblConnectionState", - TRANS("Disconnected"))); + juce::translate("Disconnected"))); addAndMakeVisible (lblConnectionState.get()); lblConnectionState->setFont (juce::Font (15.00f, juce::Font::plain).withTypefaceStyle ("Regular")); lblConnectionState->setJustificationType (juce::Justification::centredLeft); @@ -108,10 +104,8 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) lblConnectionState->setColour (juce::TextEditor::textColourId, juce::Colours::black); lblConnectionState->setColour (juce::TextEditor::backgroundColourId, juce::Colour (0x00000000)); - lblConnectionState->setBounds (624, 8, 150, 24); - lblEditMode.reset (new juce::Label ("lblEditMode", - TRANS("Edit Mode:"))); + juce::translate("Edit Mode:"))); addAndMakeVisible (lblEditMode.get()); lblEditMode->setFont (juce::Font (18.00f, juce::Font::plain).withTypefaceStyle ("Regular")); lblEditMode->setJustificationType (juce::Justification::centredLeft); @@ -119,16 +113,12 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) lblEditMode->setColour (juce::TextEditor::textColourId, juce::Colours::black); lblEditMode->setColour (juce::TextEditor::backgroundColourId, juce::Colour (0x00000000)); - lblEditMode->setBounds (8, 8, 96, 24); - btnAutoConnect.reset (new juce::TextButton ("btnAutoConnect")); addAndMakeVisible (btnAutoConnect.get()); - btnAutoConnect->setTooltip (TRANS("Toggle between automatic or manual connection to Lumatone")); - btnAutoConnect->setButtonText (TRANS("auto")); + btnAutoConnect->setTooltip (juce::translate("Toggle between automatic or manual connection to Lumatone")); + btnAutoConnect->setButtonText (juce::translate("auto")); btnAutoConnect->addListener (this); - btnAutoConnect->setBounds (184, 8, 39, 24); - //[UserPreSize] cbMidiInput->getProperties().set(LumatoneEditorStyleIDs::popupMenuTargetWidth, 1); @@ -161,18 +151,16 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) ioAreaFlexBox.justifyContent = juce::FlexBox::JustifyContent::spaceBetween; //[/UserPreSize] - setSize (1024, 48); - - //[Constructor] You can add your own custom stuff here.. - // getLumatoneController()->addStatusListener(this); - // getLumatoneController()->addEditorListener(this); + // auto inputs = getLumatoneController()->getMidiInputList(); // auto outputs = getLumatoneController()->getMidiOutputList(); refreshInputMenuAndSetSelected(0, dontSendNotification); refreshOutputMenuAndSetSelected(0, dontSendNotification); setConnectivity(false); + addEditorListener(this); + addStatusListener(this); // btnAutoConnect->setToggleState(getLumatoneController()->isDetectingLumatone(), sendNotificationSync); //[/Constructor] @@ -293,7 +281,7 @@ void MidiEditArea::resized() int lblMarginY = roundToInt((ioBounds.getHeight() - h * connectivityHeight) * 0.5f); ioAreaFlexBox.items.clear(); - ioAreaFlexBox.items.add(FlexItem(*btnAutoConnect).withFlex(0).withWidth(controlHeight * 1.6f).withHeight(controlHeight)); + ioAreaFlexBox.items.add(juce::FlexItem(*btnAutoConnect).withFlex(0).withWidth(controlHeight * 1.6f).withHeight(controlHeight)); if (btnAutoConnect->getToggleState()) { @@ -302,19 +290,19 @@ void MidiEditArea::resized() else { int deviceBoxWidth = roundToInt(ioBounds.getWidth() * midiDeviceControlBoundsWidth); - ioAreaFlexBox.items.add(FlexItem(*cbMidiInput).withFlex(0).withWidth(deviceBoxWidth).withHeight(controlHeight)); - ioAreaFlexBox.items.add(FlexItem(*cbMidiOutput).withFlex(0).withWidth(deviceBoxWidth).withHeight(controlHeight)); + ioAreaFlexBox.items.add(juce::FlexItem(*cbMidiInput).withFlex(0).withWidth(deviceBoxWidth).withHeight(controlHeight)); + ioAreaFlexBox.items.add(juce::FlexItem(*cbMidiOutput).withFlex(0).withWidth(deviceBoxWidth).withHeight(controlHeight)); lblConnectionState->setJustificationType(juce::Justification::centredRight); } // Not sure why AlignSelf is necessary... - ioAreaFlexBox.items.add(FlexItem(*lblConnectionState).withFlex(1).withHeight(h * connectivityHeight).withAlignSelf(FlexItem::AlignSelf::center)); + ioAreaFlexBox.items.add(juce::FlexItem(*lblConnectionState).withFlex(1).withHeight(h * connectivityHeight).withAlignSelf(FlexItem::AlignSelf::center)); float itemMargin = lblMarginX * 0.5f; for (int i = 0; i < ioAreaFlexBox.items.size(); i++) { - ioAreaFlexBox.items.getReference(i).margin = FlexItem::Margin(0, itemMargin, 0, 0); + ioAreaFlexBox.items.getReference(i).margin = juce::FlexItem::Margin(0, itemMargin, 0, 0); } ioAreaFlexBox.performLayout( @@ -353,7 +341,7 @@ void MidiEditArea::comboBoxChanged (juce::ComboBox* comboBoxThatHasChanged) else { jassert(!isConnected()); - lblConnectionState->setText("Connecting...", NotificationType::dontSendNotification); + lblConnectionState->setText("Connecting...", juce::NotificationType::dontSendNotification); } //[/UserComboBoxCode_cbMidiInput] } @@ -435,7 +423,7 @@ void MidiEditArea::lookAndFeelChanged() connectedColours.add(getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::ConnectedGreen)); } -void MidiEditArea::setConnectivity(bool isConnectedIn, String connectionStatus) +void MidiEditArea::setConnectivity(bool isConnectedIn, juce::String connectionStatus) { bool isNotConnected = !isConnectedIn; @@ -486,7 +474,6 @@ void MidiEditArea::setConnectivity(bool isConnectedIn, String connectionStatus) lblConnectionState->setColour(juce::Label::ColourIds::textColourId, connectedColours[isConnectedIn]); resized(); - repaint(); } void MidiEditArea::connectionFailed() @@ -507,13 +494,9 @@ void MidiEditArea::connectionStateChanged(ConnectionState state) // { // refreshInputMenuAndSetSelected(inputDevice + 1, dontSendNotification); // refreshOutputMenuAndSetSelected(outputDevice + 1, dontSendNotification); - // setConnectivity(true); + setConnectivity(true); - // onOpenConnectionToDevice(); - // } - // else - // { - // jassertfalse; + onOpenConnectionToDevice(); // } } else if (state == ConnectionState::DISCONNECTED) @@ -521,18 +504,17 @@ void MidiEditArea::connectionStateChanged(ConnectionState state) // Lost should only happen after connection is established // jassert(isConnected); - // if (!btnAutoConnect->getToggleState()) - // startTimer(deviceRefreshTimeoutMs); + if (!btnAutoConnect->getToggleState()) + startTimer(deviceRefreshTimeoutMs); - // else - // { - // refreshInputMenuAndSetSelected(0, NotificationType::dontSendNotification); - // refreshOutputMenuAndSetSelected(0, NotificationType::sendNotificationAsync); - // } + else + { + refreshInputMenuAndSetSelected(0, juce::NotificationType::dontSendNotification); + refreshOutputMenuAndSetSelected(0, juce::NotificationType::sendNotificationAsync); + } - // setConnectivity(false); + setConnectivity(false); } - //deviceMonitor.intializeConnectionLossDetection(); } void MidiEditArea::editorModeChanged(EditorMode editModeIn) @@ -542,14 +524,14 @@ void MidiEditArea::editorModeChanged(EditorMode editModeIn) switch (editModeIn) { case EditorMode::ONLINE: - liveEditorBtn->setToggleState(true, NotificationType::dontSendNotification); + liveEditorBtn->setToggleState(true, juce::NotificationType::dontSendNotification); if (getHasChangesToSave()) onOpenConnectionToDevice(translate("Switch to Live Mode with unsaved changes")); break; case EditorMode::OFFLINE: - offlineEditorBtn->setToggleState(true, NotificationType::dontSendNotification); - lblConnectionState->setText(translate("Offline"), NotificationType::dontSendNotification); + offlineEditorBtn->setToggleState(true, juce::NotificationType::dontSendNotification); + lblConnectionState->setText(translate("Offline"), juce::NotificationType::dontSendNotification); //errorVisualizer.setErrorLevel( // *lblConnectionState.get(), // HajuErrorVisualizer::ErrorLevel::noError, @@ -565,7 +547,7 @@ void MidiEditArea::editorModeChanged(EditorMode editModeIn) repaint(); } -void MidiEditArea::onOpenConnectionToDevice(String dialogTitle) +void MidiEditArea::onOpenConnectionToDevice(juce::String dialogTitle) { jassert(cbMidiInput->getSelectedItemIndex() >= 0 && cbMidiOutput->getSelectedItemIndex() >= 0); @@ -581,43 +563,43 @@ void MidiEditArea::onOpenConnectionToDevice(String dialogTitle) isWaitingForUserChoice = true; - auto alertOptions = MessageBoxOptions().withTitle(dialogTitle) - .withMessage(translate("Do you want to send the current setup to your Lumatone?")) - .withIconType(AlertWindow::AlertIconType::QuestionIcon) - .withAssociatedComponent(getParentComponent()) - .withButton("Send Editor Layout") - .withButton("Keep Editing Offline") - .withButton("Import From Lumatone"); + auto alertOptions = juce::MessageBoxOptions().withTitle(dialogTitle) + .withMessage(translate("Do you want to send the current setup to your Lumatone?")) + .withIconType(juce::AlertWindow::AlertIconType::QuestionIcon) + .withAssociatedComponent(getParentComponent()) + .withButton("Send Editor Layout") + .withButton("Keep Editing Offline") + .withButton("Import From Lumatone"); + + juce::AlertWindow::showAsync(alertOptions, [&](int retc) + { + isWaitingForUserChoice = false; - AlertWindow::showAsync(alertOptions, [&](int retc) + if (retc == 0) // Import + { + getLumatoneController()->sendGetCompleteMappingRequest(); + // TerpstraSysExApplication::getApp().requestConfigurationFromDevice(); + liveEditorBtn->setToggleState(true, juce::NotificationType::sendNotification); + lblConnectionState->setText("Connected", juce::NotificationType::dontSendNotification); + } + else if (retc == 1) // Send { - isWaitingForUserChoice = false; - - if (retc == 0) // Import - { - getLumatoneController()->sendGetCompleteMappingRequest(); - // TerpstraSysExApplication::getApp().requestConfigurationFromDevice(); - liveEditorBtn->setToggleState(true, NotificationType::sendNotification); - lblConnectionState->setText("Connected", NotificationType::dontSendNotification); - } - else if (retc == 1) // Send - { - getLumatoneController()->sendCompleteMapping(*getMappingData(), true, false); - // TerpstraSysExApplication::getApp().sendCurrentConfigurationToDevice(); - liveEditorBtn->setToggleState(true, NotificationType::sendNotification); - lblConnectionState->setText("Connected", NotificationType::dontSendNotification); - } - else if (retc == 2) // Offline - { - offlineEditorBtn->setToggleState(true, NotificationType::sendNotification); - lblConnectionState->setText("Offline", NotificationType::dontSendNotification); - } - }); + getLumatoneController()->sendCompleteMapping(*getMappingData(), true, false); + // TerpstraSysExApplication::getApp().sendCurrentConfigurationToDevice(); + liveEditorBtn->setToggleState(true, juce::NotificationType::sendNotification); + lblConnectionState->setText("Connected", juce::NotificationType::dontSendNotification); + } + else if (retc == 2) // Offline + { + offlineEditorBtn->setToggleState(true, juce::NotificationType::sendNotification); + lblConnectionState->setText("Offline", juce::NotificationType::dontSendNotification); + } + }); } void MidiEditArea::refreshInputMenuAndSetSelected(int inputDeviceIndex, juce::NotificationType notificationType) { - cbMidiInput->clear(NotificationType::dontSendNotification); + cbMidiInput->clear(juce::NotificationType::dontSendNotification); int i = 1; for (auto device : getLumatoneController()->getMidiInputList()) cbMidiInput->addItem(device.name, i++); @@ -628,7 +610,7 @@ void MidiEditArea::refreshInputMenuAndSetSelected(int inputDeviceIndex, juce::No void MidiEditArea::refreshOutputMenuAndSetSelected(int outputDeviceIndex, juce::NotificationType notificationType) { - cbMidiOutput->clear(NotificationType::dontSendNotification); + cbMidiOutput->clear(juce::NotificationType::dontSendNotification); int i = 1; for (auto device : getLumatoneController()->getMidiOutputList()) cbMidiOutput->addItem(device.name, i++); From 818289648652d7540a30168ff98ff54541a13efb Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Tue, 16 Jan 2024 02:37:09 -0500 Subject: [PATCH 04/19] move activity monitor into shared application state --- Source/Main.cpp | 3 --- Source/Main.h | 23 +++++++------------ .../data/application_state.cpp | 8 ++++--- .../data/application_state.h | 1 + .../device/activity_monitor.cpp | 2 +- .../device/activity_monitor.h | 2 +- 6 files changed, 16 insertions(+), 23 deletions(-) diff --git a/Source/Main.cpp b/Source/Main.cpp index c3ac7a2..f24c14d 100644 --- a/Source/Main.cpp +++ b/Source/Main.cpp @@ -40,8 +40,6 @@ TerpstraSysExApplication::TerpstraSysExApplication() : firmwareDriver(LumatoneFirmwareDriver::HostMode::Driver) , state("LumatoneEditor", firmwareDriver, &undoManager) { - activityMonitor.reset(new DeviceActivityMonitor(&firmwareDriver, state)); - // Localisation String localisation = getLocalisation(SystemStats::getDisplayLanguage()); LocalisedStrings::setCurrentMappings(new LocalisedStrings(localisation, false)); @@ -106,7 +104,6 @@ void TerpstraSysExApplication::shutdown() if (state.firmwareUpdateCompleted()) FirmwareTransfer::exitLibSsh2(); - activityMonitor = nullptr; //delete firmwareDriver; // commandManager = nullptr; diff --git a/Source/Main.h b/Source/Main.h index 2a754dc..8d976f2 100644 --- a/Source/Main.h +++ b/Source/Main.h @@ -26,16 +26,14 @@ class MainContentComponent; class DeviceActivityMonitor; //============================================================================== -class TerpstraSysExApplication : public JUCEApplication +class TerpstraSysExApplication : public juce::JUCEApplication { public: //============================================================================== TerpstraSysExApplication(); - //LumatoneFirmwareDriver& initializeDriver(); - - const String getApplicationName() override { return ProjectInfo::projectName; } - const String getApplicationVersion() override { return ProjectInfo::versionString; } + const juce::String getApplicationName() override { return ProjectInfo::projectName; } + const juce::String getApplicationVersion() override { return ProjectInfo::versionString; } bool moreThanOneInstanceAllowed() override { return true; } void initialise(const String& commandLine) override; @@ -46,9 +44,9 @@ class TerpstraSysExApplication : public JUCEApplication void loadPropertiesFile(); // Menu functionality - void getAllCommands(Array & commands) override; - void getCommandInfo(CommandID commandID, ApplicationCommandInfo& result) override; - bool perform(const InvocationInfo& info) override; + void getAllCommands(juce::Array & commands) override; + void getCommandInfo(juce::CommandID commandID, juce::ApplicationCommandInfo& result) override; + bool perform(const juce::ApplicationCommandTarget::InvocationInfo& info) override; bool openSysExMapping(); bool saveSysExMapping(std::function saveFileCallback = CHOOSE_FILE_NOOP); @@ -62,10 +60,10 @@ class TerpstraSysExApplication : public JUCEApplication bool deleteSubBoardData(); bool copySubBoardData(); bool pasteSubBoardData(); - bool pasteModifiedSubBoardData(CommandID commandID); + bool pasteModifiedSubBoardData(juce::CommandID commandID); bool canPasteSubBoardData() const; - bool performUndoableAction(UndoableAction* editAction, bool newTransaction=true); + bool performUndoableAction(juce::UndoableAction* editAction, bool newTransaction=true); bool undo(); bool redo(); @@ -85,16 +83,11 @@ class TerpstraSysExApplication : public JUCEApplication bool aboutTerpstraSysEx(); - //MainContentComponent* getMainContentComponent() const; - private: LumatoneFirmwareDriver firmwareDriver; juce::UndoManager undoManager; LumatoneEditorStateController state; - - std::unique_ptr activityMonitor; - std::unique_ptr commandManager; MainContentComponent* mainComponent; diff --git a/Source/lumatone_editor_library/data/application_state.cpp b/Source/lumatone_editor_library/data/application_state.cpp index 062e7c3..9c3a4d6 100644 --- a/Source/lumatone_editor_library/data/application_state.cpp +++ b/Source/lumatone_editor_library/data/application_state.cpp @@ -1,5 +1,6 @@ #include "application_state.h" #include "../device/lumatone_controller.h" +#include "../device/activity_monitor.h" #include "../color/colour_model.h" #include "../data/lumatone_context.h" @@ -28,6 +29,7 @@ LumatoneApplicationState::LumatoneApplicationState(juce::String nameIn, Lumatone layoutContext = std::make_shared(*mappingData); controller = std::make_shared(*this, driverIn); + activityMonitor = std::make_shared(*this, &driverIn); colourModel = std::make_shared(); loadStateProperties(stateIn); @@ -49,6 +51,7 @@ LumatoneApplicationState::LumatoneApplicationState(juce::String nameIn, const Lu , midiListeners(stateIn.midiListeners) , layoutContext(stateIn.layoutContext) , controller(stateIn.controller) + , activityMonitor(stateIn.activityMonitor) , colourModel(stateIn.colourModel) { loadStateProperties(state); @@ -56,9 +59,10 @@ LumatoneApplicationState::LumatoneApplicationState(juce::String nameIn, const Lu LumatoneApplicationState::~LumatoneApplicationState() { + layoutContext = nullptr; + activityMonitor = nullptr; controller = nullptr; colourModel = nullptr; - layoutContext = nullptr; } ConnectionState LumatoneApplicationState::getConnectionState() const @@ -254,7 +258,6 @@ void LumatoneApplicationState::sendSelectionParam(const juce::ArraysendKeyParam(mappedKey.boardIndex + 1, mappedKey.keyIndex, static_cast(mappedKey)); - //sendKeyConfig(mappedKey.boardIndex + 1, mappedKey.keyIndex, (LumatoneKey)mappedKey, false, bufferKeyUpdates); } //if (signalEditorListeners) @@ -268,7 +271,6 @@ void LumatoneApplicationState::sendSelectionColours(const juce::ArraysendKeyColourConfig(mappedKey.boardIndex, mappedKey.keyIndex, static_cast(mappedKey)); - //sendKeyColourConfig(mappedKey.boardIndex + 1, mappedKey.keyIndex, (LumatoneKey)mappedKey, false, bufferKeyUpdates); } //if (signalEditorListeners) diff --git a/Source/lumatone_editor_library/data/application_state.h b/Source/lumatone_editor_library/data/application_state.h index 90fea58..9c0d328 100644 --- a/Source/lumatone_editor_library/data/application_state.h +++ b/Source/lumatone_editor_library/data/application_state.h @@ -142,6 +142,7 @@ class LumatoneApplicationState : public LumatoneState private: std::shared_ptr layoutContext; std::shared_ptr controller; + std::shared_ptr activityMonitor; std::shared_ptr colourModel; bool contextIsSet = false; diff --git a/Source/lumatone_editor_library/device/activity_monitor.cpp b/Source/lumatone_editor_library/device/activity_monitor.cpp index 9fdaaf7..c1a50e0 100644 --- a/Source/lumatone_editor_library/device/activity_monitor.cpp +++ b/Source/lumatone_editor_library/device/activity_monitor.cpp @@ -15,7 +15,7 @@ #include "../listeners/status_listener.h" -DeviceActivityMonitor::DeviceActivityMonitor(LumatoneFirmwareDriver* midiDriverIn, const LumatoneApplicationState& stateIn) +DeviceActivityMonitor::DeviceActivityMonitor(const LumatoneApplicationState& stateIn, LumatoneFirmwareDriver* midiDriverIn) : LumatoneApplicationStateController("DeviceActivityMonitor", stateIn) , midiDriver(midiDriverIn) { diff --git a/Source/lumatone_editor_library/device/activity_monitor.h b/Source/lumatone_editor_library/device/activity_monitor.h index 096c2ea..a7ae3a3 100644 --- a/Source/lumatone_editor_library/device/activity_monitor.h +++ b/Source/lumatone_editor_library/device/activity_monitor.h @@ -40,7 +40,7 @@ class DeviceActivityMonitor : protected LumatoneApplicationStateController, public: - DeviceActivityMonitor(LumatoneFirmwareDriver* midiDriverIn, const LumatoneApplicationState& stateIn); + DeviceActivityMonitor(const LumatoneApplicationState& stateIn, LumatoneFirmwareDriver* midiDriverIn); ~DeviceActivityMonitor() override; DetectConnectionMode getMode() const { return deviceConnectionMode; } From 1ae9476145cc781f6d1cbbcb083ffb62959eaca0 Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Sat, 20 Jan 2024 01:17:51 -0500 Subject: [PATCH 05/19] add set property shortcut to states --- Source/lumatone_editor_library/data/state_base.cpp | 5 +++++ Source/lumatone_editor_library/data/state_base.h | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Source/lumatone_editor_library/data/state_base.cpp b/Source/lumatone_editor_library/data/state_base.cpp index 1bf69c9..721e149 100644 --- a/Source/lumatone_editor_library/data/state_base.cpp +++ b/Source/lumatone_editor_library/data/state_base.cpp @@ -16,6 +16,11 @@ bool LumatoneStateBase::writeToPropertiesFile() return false; } +void LumatoneStateBase::setStateProperty(const juce::Identifier &id, juce::var value) +{ + state.setPropertyExcludingListener(this, id, value, nullptr); +} + bool LumatoneStateBase::getBoolProperty(const juce::Identifier key, bool fallback) const { auto prop = state.getProperty(key, juce::var((bool)fallback)); diff --git a/Source/lumatone_editor_library/data/state_base.h b/Source/lumatone_editor_library/data/state_base.h index 0a01f55..c6a6153 100644 --- a/Source/lumatone_editor_library/data/state_base.h +++ b/Source/lumatone_editor_library/data/state_base.h @@ -17,9 +17,6 @@ class LumatoneStateBase : protected juce::ValueTree::Listener { public: LumatoneStateBase(juce::String nameIn) : name(nameIn) { } - // LumatoneStateBase(const LumatoneStateBase& stateIn) - // : state(stateIn.state) - // , name(stateIn.name) { } bool getBoolProperty(const juce::Identifier key, bool fallback) const; int getIntProperty(const juce::Identifier key, int fallback) const; @@ -27,6 +24,9 @@ class LumatoneStateBase : protected juce::ValueTree::Listener virtual bool writeToPropertiesFile(); +protected: + void setStateProperty(const juce::Identifier& id, juce::var value); + protected: void writeBoolProperty(const juce::Identifier key, bool value, juce::UndoManager* undo=nullptr); void writeIntProperty(const juce::Identifier key, int value, juce::UndoManager* undo=nullptr); From ec337590312ebd9ede2d67d79f9518fd6eab21ef Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Sat, 20 Jan 2024 01:23:53 -0500 Subject: [PATCH 06/19] refactor state mutators into controller classes --- Source/ColourPaletteWindow.cpp | 5 +- Source/ColourPaletteWindow.h | 3 +- Source/LumatoneEditorState.cpp | 139 ++++++++++-------- Source/LumatoneEditorState.h | 83 +++++------ Source/LumatoneMenu.cpp | 6 +- Source/LumatoneMenu.h | 3 +- Source/Main.cpp | 111 +++++--------- Source/Main.h | 16 +- Source/MainComponent.cpp | 6 +- Source/MainComponent.h | 6 +- Source/MainWindow.cpp | 26 +++- Source/MainWindow.h | 14 +- Source/NoteEditArea.cpp | 7 +- Source/NoteEditArea.h | 9 +- Source/Settings/SettingsContainer.h | 2 +- .../data/application_state.cpp | 105 ++++++++++++- .../data/application_state.h | 74 +++++++--- .../data/lumatone_state.cpp | 16 +- Source/palette_edit_panel.h | 2 +- 19 files changed, 369 insertions(+), 264 deletions(-) diff --git a/Source/ColourPaletteWindow.cpp b/Source/ColourPaletteWindow.cpp index c1c59a4..f7866ff 100644 --- a/Source/ColourPaletteWindow.cpp +++ b/Source/ColourPaletteWindow.cpp @@ -23,13 +23,16 @@ // ColourPaletteWindow Definitions ColourPaletteWindow::ColourPaletteWindow(const LumatoneEditorState& stateIn) - : LumatoneEditorStateController("ColourPaletteWindow", stateIn) + : LumatoneEditorState("ColourPaletteWindow", stateIn) + , LumatoneEditorState::Controller(static_cast(*this)) { setName("ColourPaletteWindow"); setLookAndFeel(&getEditorLookAndFeel()); colourSelectorGroup.reset(new ColourSelectionGroup()); + loadColourPalettesFromFile(); + palettePanel.reset(new ColourPalettesPanel(getColourPalettes(), colourSelectorGroup.get())); palettePanel->addListener(this); diff --git a/Source/ColourPaletteWindow.h b/Source/ColourPaletteWindow.h index 2b24bd1..31554fc 100644 --- a/Source/ColourPaletteWindow.h +++ b/Source/ColourPaletteWindow.h @@ -27,7 +27,8 @@ class PaletteEditPanel; /* */ class ColourPaletteWindow : public juce::Component - , private LumatoneEditorStateController + , public LumatoneEditorState + , private LumatoneEditorState::Controller , public juce::ChangeListener , public ColourPalettesPanel::Listener { diff --git a/Source/LumatoneEditorState.cpp b/Source/LumatoneEditorState.cpp index 59e2789..4a65f8d 100644 --- a/Source/LumatoneEditorState.cpp +++ b/Source/LumatoneEditorState.cpp @@ -35,7 +35,7 @@ juce::Array GetLumatoneEditorProperty() LumatoneEditorState::LumatoneEditorState(juce::String name, LumatoneFirmwareDriver& driverIn, juce::UndoManager *undoManagerIn) - : LumatoneApplicationStateController("LumatoneEditor", driverIn, juce::ValueTree(), undoManagerIn) + : LumatoneApplicationState("LumatoneEditor", driverIn, juce::ValueTree(), undoManagerIn) { appFonts = std::make_shared(); lookAndFeel = std::make_shared(*appFonts, true); @@ -62,7 +62,7 @@ LumatoneEditorState::LumatoneEditorState(juce::String name, LumatoneFirmwareDriv } LumatoneEditorState::LumatoneEditorState(juce::String name, const LumatoneEditorState &stateIn) - : LumatoneApplicationStateController(name, stateIn) + : LumatoneApplicationState(name, stateIn) , appFonts(stateIn.appFonts) , lookAndFeel(stateIn.lookAndFeel) , recentFiles(stateIn.recentFiles) @@ -158,22 +158,7 @@ juce::File LumatoneEditorState::getUserPalettesDirectory() const void LumatoneEditorState::setHasChangesToSave(bool hasChangesToSaveIn) { hasChangesToSave = hasChangesToSaveIn; - state.setPropertyExcludingListener(this, LumatoneEditorProperty::HasChangesToSave, hasChangesToSave, nullptr); -} - -void LumatoneEditorState::setCalibrationMode(bool calibrationModeOn) -{ - calibrationModeOn = calibrationModeOn; - getLumatoneController()->setCalibratePitchModWheel(calibrationModeOn); - // writeBoolProperty(LumatoneEditorProperty::InCalibrationMode, calibrationModeOn, nullptr); - state.setPropertyExcludingListener(this, LumatoneEditorProperty::InCalibrationMode, calibrationModeOn, nullptr); -} - -void LumatoneEditorState::setDeveloperMode(bool developerModeOn) -{ - inDeveloperMode = developerModeOn; - // writeBoolProperty(LumatoneEditorProperty::DeveloperModeOn, inDeveloperMode, undoManager); - state.setPropertyExcludingListener(this, LumatoneEditorProperty::DeveloperModeOn, inDeveloperMode, undoManager); + setStateProperty(LumatoneEditorProperty::HasChangesToSave, hasChangesToSave); } bool LumatoneEditorState::doSendChangesToDevice() const @@ -181,10 +166,10 @@ bool LumatoneEditorState::doSendChangesToDevice() const return LumatoneApplicationState::doSendChangesToDevice() && editorMode == EditorMode::ONLINE; } -void LumatoneEditorState::setEditMode(EditorMode editMode) +void LumatoneEditorState::Controller::setEditMode(EditorMode editMode) { - editorMode = editMode; - state.setPropertyExcludingListener(this, LumatoneEditorProperty::EditorMode, (int)editorMode, nullptr); + editorState.editorMode = editMode; + editorState.setStateProperty(LumatoneEditorProperty::EditorMode, (int)editorState.editorMode); } juce::ValueTree LumatoneEditorState::loadStateProperties(juce::ValueTree stateIn) @@ -241,14 +226,16 @@ void LumatoneEditorState::handleStatePropertyChange(juce::ValueTree stateIn, con } } -void LumatoneEditorStateController::setColourPalettes(const juce::Array &palettesIn) +void LumatoneEditorState::Controller::setColourPalettes(const juce::Array &palettesIn) { - *colourPalettes = palettesIn; + *editorState.colourPalettes = palettesIn; + // TODO + // editorState.setPropertyExcludingListener(this, LumatoneEditorProperty::ColourPalettes, "", nullptr); } -void LumatoneEditorStateController::loadColourPalettesFromFile() +void LumatoneEditorState::Controller::loadColourPalettesFromFile() { - auto directory = getUserPalettesDirectory(); + auto directory = editorState.getUserPalettesDirectory(); auto foundPaletteFiles = directory.findChildFiles(juce::File::TypesOfFileToFind::findFiles, true, '*' + juce::String(PALETTEFILEEXTENSION)); juce::Array newPalettes; @@ -263,20 +250,14 @@ void LumatoneEditorStateController::loadColourPalettesFromFile() setColourPalettes(newPalettes); } -const juce::Array& LumatoneEditorStateController::getColourPalettes() -{ - loadColourPalettesFromFile(); - return LumatoneEditorState::getColourPalettes(); -} - -void LumatoneEditorStateController::addPalette(const LumatoneEditorColourPalette &newPalette) +void LumatoneEditorState::Controller::addPalette(const LumatoneEditorColourPalette &newPalette) { - colourPalettes->add(newPalette); + editorState.colourPalettes->add(newPalette); // TODO - state.setPropertyExcludingListener(this, LumatoneEditorProperty::ColourPalettes, "", nullptr); + // editorState.setPropertyExcludingListener(this, LumatoneEditorProperty::ColourPalettes, "", nullptr); } -bool LumatoneEditorStateController::deletePaletteFile(juce::File pathToPalette) +bool LumatoneEditorState::Controller::deletePaletteFile(juce::File pathToPalette) { bool success = false; @@ -288,23 +269,34 @@ bool LumatoneEditorStateController::deletePaletteFile(juce::File pathToPalette) return success; } +bool LumatoneEditorState::Controller::performAction(LumatoneAction *action, bool undoable, bool newTransaction) +{ + if (LumatoneApplicationState::Controller::performAction(action, undoable, newTransaction)) + { + setHasChangesToSave(true); + return true; + } + + return false; +} + // Open a SysEx mapping from the file specified in currentFile -bool LumatoneEditorStateController::resetToCurrentFile() +bool LumatoneEditorState::Controller::resetToCurrentFile() { - if (getCurrentFile().getFullPathName().isEmpty()) + if (editorState.getCurrentFile().getFullPathName().isEmpty()) { // Replace with blank file LumatoneLayout defaultLayout; - setCompleteConfig(defaultLayout); - setHasChangesToSave(false); + editorState.setCompleteConfig(defaultLayout); + editorState.setHasChangesToSave(false); return true; } - if (getCurrentFile().existsAsFile()) + if (editorState.getCurrentFile().existsAsFile()) { // XXX StringArray format: platform-independent? juce::StringArray stringArray; - getCurrentFile().readLines(stringArray); + editorState.getCurrentFile().readLines(stringArray); LumatoneLayout keyMapping(stringArray); // ((MainContentComponent*)(mainWindow->getContentComponent()))->setData(keyMapping); @@ -314,45 +306,51 @@ bool LumatoneEditorStateController::resetToCurrentFile() // updateMainTitle(); // Send configuration to controller, if connected - // controller->sendCurrentCompleteConfig(); + editorState.setCompleteConfig(keyMapping); - setCompleteConfig(keyMapping); // Mark file as unchanged - setHasChangesToSave(false); + editorState.setHasChangesToSave(false); - // Clear undo history - // undoManager.clearUndoHistory(); + // Clear undo history + editorState.undoManager->clearUndoHistory(); // Add file to recent files list - recentFiles->addFile(currentFile); + editorState.recentFiles->addFile(editorState.currentFile); return true; } // Show error message - AlertWindow::showMessageBoxAsync(AlertWindow::AlertIconType::WarningIcon, "Open File Error", "The file " + getCurrentFile().getFullPathName() + " could not be opened."); + AlertWindow::showMessageBoxAsync(AlertWindow::AlertIconType::WarningIcon, "Open File Error", "The file " + editorState.getCurrentFile().getFullPathName() + " could not be opened."); // XXX Update Window title in any case? Make file name empty/make data empty in case of error? return false; } -bool LumatoneEditorStateController::setCurrentFile(File fileToOpen) +bool LumatoneEditorState::Controller::setCurrentFile(File fileToOpen) { - currentFile = fileToOpen; - state.setPropertyExcludingListener(this, LumatoneEditorProperty::CurrentFile, currentFile.getFullPathName(), nullptr); + editorState.currentFile = fileToOpen; + // editorState.setPropertyExcludingListener(this, LumatoneEditorProperty::CurrentFile, editorState.currentFile.getFullPathName(), nullptr); return resetToCurrentFile(); } // open a file from the "recent files" menu -bool LumatoneEditorStateController::openRecentFile(int recentFileIndex) +bool LumatoneEditorState::Controller::openRecentFile(int recentFileIndex) +{ + jassert(recentFileIndex >= 0 && recentFileIndex < editorState.recentFiles->getNumFiles()); + return setCurrentFile(editorState.recentFiles->getFile(recentFileIndex)); +} + +bool LumatoneEditorState::Controller::requestCompleteConfigFromDevice() { - jassert(recentFileIndex >= 0 && recentFileIndex < recentFiles->getNumFiles()); - return setCurrentFile(recentFiles->getFile(recentFileIndex)); + setHasChangesToSave(false); + editorState.undoManager->clearUndoHistory(); + LumatoneApplicationState::Controller::requestCompleteConfigFromDevice(); } -bool LumatoneEditorStateController::saveMappingToFile(juce::File fileToSave) +bool LumatoneEditorState::Controller::saveMappingToFile(juce::File fileToSave) { - juce::StringArray stringArray = getMappingData()->toStringArray(); + juce::StringArray stringArray = editorState.getMappingData()->toStringArray(); juce::String fileText = stringArray.joinIntoString("\n"); bool success = false; @@ -360,12 +358,12 @@ bool LumatoneEditorStateController::saveMappingToFile(juce::File fileToSave) if (fileToSave.existsAsFile()) success = fileToSave.replaceWithText(fileText, false, false); - else if (fileToSave.create().ok) + else if (fileToSave.create().ok()) { success = fileToSave.appendText(fileText, false, false); } - if (success && getCurrentFile() != fileToSave) + if (success && editorState.getCurrentFile() != fileToSave) { // TODO skip certain updates? setCurrentFile(fileToSave); @@ -374,7 +372,7 @@ bool LumatoneEditorStateController::saveMappingToFile(juce::File fileToSave) return success; } -bool LumatoneEditorStateController::savePropertiesFile() const +bool LumatoneEditorState::Controller::savePropertiesFile() const { // TODO Save documents directories (Future: provide option to change them and save after changed by user) //propertiesFile->setValue(LumatoneEditorProperty::UserDocumentsDirectory, getUserDocumentsDirectory().getFullPathName()); @@ -382,10 +380,25 @@ bool LumatoneEditorStateController::savePropertiesFile() const //propertiesFile->setValue(LumatoneEditorProperty::UserPalettesDirectory, getUserPalettesDirectory().getFullPathName()); // Save recent files list - recentFiles->removeNonExistentFiles(); - jassert(propertiesFile != nullptr); - propertiesFile->setValue(LumatoneEditorProperty::RecentFiles, recentFiles->toString()); + editorState.recentFiles->removeNonExistentFiles(); + jassert(editorState.propertiesFile != nullptr); + editorState.propertiesFile->setValue(LumatoneEditorProperty::RecentFiles, editorState.recentFiles->toString()); - return propertiesFile->saveIfNeeded(); + return editorState.propertiesFile->saveIfNeeded(); +} + +void LumatoneEditorState::Controller::setCalibrationMode(bool calibrationModeOn) +{ + editorState.inCalibrationMode = calibrationModeOn; + editorState.getLumatoneController()->setCalibratePitchModWheel(calibrationModeOn); + // writeBoolProperty(LumatoneEditorProperty::InCalibrationMode, calibrationModeOn, nullptr); + editorState.setStateProperty(LumatoneEditorProperty::InCalibrationMode, editorState.inCalibrationMode); +} + +void LumatoneEditorState::Controller::setDeveloperMode(bool developerModeOn) +{ + editorState.inDeveloperMode = developerModeOn; + // writeBoolProperty(LumatoneEditorProperty::DeveloperModeOn, inDeveloperMode, undoManager); + editorState.setStateProperty(LumatoneEditorProperty::DeveloperModeOn, editorState.inDeveloperMode); } diff --git a/Source/LumatoneEditorState.h b/Source/LumatoneEditorState.h index f58b79b..e017330 100644 --- a/Source/LumatoneEditorState.h +++ b/Source/LumatoneEditorState.h @@ -70,15 +70,12 @@ enum class EditorMode static juce::Array GetLumatoneEditorProperties(); -class LumatoneEditorStateController; - -class LumatoneEditorState : public LumatoneApplicationStateController +class LumatoneEditorState : public LumatoneApplicationState { public: - LumatoneEditorState(juce::String name, const LumatoneEditorState& stateIn); -protected: LumatoneEditorState(juce::String name, LumatoneFirmwareDriver& driverIn, juce::UndoManager* undoManagerIn); -public: + LumatoneEditorState(juce::String name, const LumatoneEditorState& stateIn); + ~LumatoneEditorState() override; const juce::String getApplicationName() const { return ProjectInfo::projectName; } @@ -115,10 +112,7 @@ class LumatoneEditorState : public LumatoneApplicationStateController juce::ValueTree loadStateProperties(juce::ValueTree stateIn) override; void handleStatePropertyChange(juce::ValueTree stateIn, const juce::Identifier& property) override; - virtual void setHasChangesToSave(bool hasChangesToSave); - virtual void setCalibrationMode(bool calibrationModeOn); - virtual void setDeveloperMode(bool developerModeOn); - virtual void setEditMode(EditorMode editMode); + void setHasChangesToSave(bool hasChangesToSave); protected: bool hasChangesToSave = false; @@ -128,13 +122,6 @@ class LumatoneEditorState : public LumatoneApplicationStateController bool firmwareUpdateWasPerformed = false; EditorMode editorMode = EditorMode::OFFLINE; - -private: - using LumatoneApplicationStateController::setConnectionState; - using LumatoneApplicationStateController::getEditorListeners; - using LumatoneApplicationStateController::getStatusListeners; - using LumatoneApplicationStateController::getFirmwareListeners; - using LumatoneApplicationStateController::getMidiListeners; private: std::shared_ptr appFonts; @@ -144,46 +131,48 @@ class LumatoneEditorState : public LumatoneApplicationStateController juce::File currentFile; std::shared_ptr recentFiles; - std::shared_ptr propertiesFile; + std::shared_ptr propertiesFile; // TODO move to state base? - friend class LumatoneEditorStateController; -}; - -class LumatoneEditorStateController : public LumatoneEditorState -{ +//================================================================================ public: - LumatoneEditorStateController(juce::String name, LumatoneFirmwareDriver& driverIn, juce::UndoManager* undoManagerIn) - : LumatoneEditorState(name, driverIn, undoManagerIn) {} - LumatoneEditorStateController(juce::String name, const LumatoneEditorState& stateIn) - : LumatoneEditorState(name, stateIn) {} + class Controller : protected LumatoneApplicationState::Controller + { + public: + Controller(LumatoneEditorState& stateIn) + : LumatoneApplicationState::Controller(stateIn) + , editorState(stateIn) {} - const juce::Array& getColourPalettes() override; + bool performAction(LumatoneAction* action, bool undoable=true, bool newTransaction=true) override; - bool resetToCurrentFile(); - bool openRecentFile(int recentFileIndex); + bool resetToCurrentFile(); + bool openRecentFile(int recentFileIndex); - void addPalette(const LumatoneEditorColourPalette& newPalette); - bool deletePaletteFile(juce::File pathToPalette); + virtual bool requestCompleteConfigFromDevice(); - void setColourPalettes(const juce::Array& palettesIn); - void loadColourPalettesFromFile(); + void addPalette(const LumatoneEditorColourPalette& newPalette); + bool deletePaletteFile(juce::File pathToPalette); - bool setCurrentFile(juce::File fileToOpen); - bool saveMappingToFile(juce::File fileToSave); + void setColourPalettes(const juce::Array& palettesIn); + void loadColourPalettesFromFile(); - juce::PropertiesFile* getPropertiesFile() const { return propertiesFile.get(); } - bool savePropertiesFile() const; + bool setCurrentFile(juce::File fileToOpen); + bool saveMappingToFile(juce::File fileToSave); - void setDeveloperMode(bool developerModeOn) override { LumatoneEditorState::setDeveloperMode(developerModeOn); } - void setEditMode(EditorMode editMode) override { LumatoneEditorState::setEditMode(editMode); } + juce::PropertiesFile* getPropertiesFile() const { return editorState.propertiesFile.get(); } + bool savePropertiesFile() const; -protected: - using LumatoneApplicationStateController::setConnectionState; - using LumatoneApplicationStateController::getEditorListeners; - using LumatoneApplicationStateController::getStatusListeners; - using LumatoneApplicationStateController::getFirmwareListeners; - using LumatoneApplicationStateController::getMidiListeners; + void setHasChangesToSave(bool hasChanges) { editorState.setHasChangesToSave(hasChanges); } + void setCalibrationMode(bool calibrationModeOn); + void setDeveloperMode(bool developerModeOn); + void setEditMode(EditorMode editMode); + + private: + LumatoneEditorState& editorState; + }; + +private: + friend class LumatoneEditorStateController; }; -#endif LUMATONE_EDITOR_STATE_H +#endif // LUMATONE_EDITOR_STATE_H diff --git a/Source/LumatoneMenu.cpp b/Source/LumatoneMenu.cpp index e919f7f..4e765d7 100644 --- a/Source/LumatoneMenu.cpp +++ b/Source/LumatoneMenu.cpp @@ -15,7 +15,8 @@ namespace Lumatone { namespace Menu { MainMenuModel::MainMenuModel(const LumatoneEditorState& state, juce::ApplicationCommandManager* commandManager) - : LumatoneEditorStateController("MainMenu", state) + : LumatoneEditorState("MainMenu", state) + , LumatoneEditorState::Controller(static_cast(*this)) { theManager = commandManager; setApplicationCommandManagerToWatch(commandManager); @@ -33,7 +34,8 @@ namespace Lumatone { menu.addCommandItem(theManager, saveSysExMapping); menu.addCommandItem(theManager, saveSysExMappingAs); menu.addCommandItem(theManager, resetSysExMapping); - + menu.addCommandItem(theManager, importSysExMapping); + menu.addSeparator(); PopupMenu recentFilesMenu; diff --git a/Source/LumatoneMenu.h b/Source/LumatoneMenu.h index e089530..28eb690 100644 --- a/Source/LumatoneMenu.h +++ b/Source/LumatoneMenu.h @@ -40,7 +40,8 @@ namespace Lumatone { }; class MainMenuModel : public juce::MenuBarModel - , public LumatoneEditorStateController + , public LumatoneEditorState + , private LumatoneEditorState::Controller { public: MainMenuModel(const LumatoneEditorState& stateIn, ApplicationCommandManager* commandManager); diff --git a/Source/Main.cpp b/Source/Main.cpp index f24c14d..3809a4c 100644 --- a/Source/Main.cpp +++ b/Source/Main.cpp @@ -39,13 +39,14 @@ TerpstraSysExApplication::TerpstraSysExApplication() : firmwareDriver(LumatoneFirmwareDriver::HostMode::Driver) , state("LumatoneEditor", firmwareDriver, &undoManager) + , LumatoneEditorState::Controller(state) { // Localisation String localisation = getLocalisation(SystemStats::getDisplayLanguage()); LocalisedStrings::setCurrentMappings(new LocalisedStrings(localisation, false)); LocalisedStrings::getCurrentMappings()->setFallback(new LocalisedStrings(BinaryData::engb_txt, false)); - state.loadColourPalettesFromFile(); + loadColourPalettesFromFile(); } //============================================================================== @@ -65,14 +66,14 @@ void TerpstraSysExApplication::initialise(const String& commandLine) // Try to open a config file if (File::isAbsolutePath(commandLineParameter)) { - state.setCurrentFile(juce::File(commandLineParameter)); + setCurrentFile(juce::File(commandLineParameter)); } else { // If file name is with quotes, try removing the quotes if (commandLine.startsWithChar('"') && commandLine.endsWithChar('"')) - state.setCurrentFile(juce::File(commandLine.substring(1, commandLine.length() - 1))); - //state.setCurrentFile(commandLine.substring(1, commandLine.length()-1)); + setCurrentFile(juce::File(commandLine.substring(1, commandLine.length() - 1))); + //setCurrentFile(commandLine.substring(1, commandLine.length()-1)); } if (state.getCurrentFile().existsAsFile()) @@ -84,11 +85,11 @@ void TerpstraSysExApplication::initialise(const String& commandLine) commandManager->registerAllCommandsForTarget(this); mainWindow.reset(new MainWindow(state, commandManager.get())); - mainWindow->restoreStateFromPropertiesFile(state.getPropertiesFile()); + mainWindow->restoreStateFromPropertiesFile(getPropertiesFile()); if (state.getCurrentFile().existsAsFile()) - state.resetToCurrentFile(); + resetToCurrentFile(); } void TerpstraSysExApplication::shutdown() @@ -99,7 +100,7 @@ void TerpstraSysExApplication::shutdown() //mainWindow->saveStateToPropertiesFile(state.propertiesFile.get()); mainWindow = nullptr; - state.savePropertiesFile(); + savePropertiesFile(); if (state.firmwareUpdateCompleted()) FirmwareTransfer::exitLibSsh2(); @@ -269,7 +270,7 @@ void TerpstraSysExApplication::getCommandInfo(CommandID commandID, ApplicationCo break; case Lumatone::Menu::commandIDs::importSysExMapping: - result.setInfo("New", "Import mapping from device.", "File", 0); + result.setInfo("Import", "Import mapping from device.", "File", 0); result.addDefaultKeypress('i', ModifierKeys::commandModifier); break; @@ -356,7 +357,7 @@ bool TerpstraSysExApplication::perform(const InvocationInfo& info) case Lumatone::Menu::commandIDs::resetSysExMapping: return resetSysExMapping(); case Lumatone::Menu::commandIDs::importSysExMapping: - return requestConfigurationFromDevice(); + return onRequestDeviceConfig(); case Lumatone::Menu::commandIDs::deleteOctaveBoard: return deleteSubBoardData(); @@ -392,11 +393,16 @@ bool TerpstraSysExApplication::openSysExMapping() fileChooser->launchAsync(FileBrowserComponent::FileChooserFlags::canSelectFiles | FileBrowserComponent::FileChooserFlags::openMode, [&](const FileChooser& chooser) { - state.setCurrentFile(chooser.getResult()); - state.resetToCurrentFile(); + setCurrentFile(chooser.getResult()); + if (resetToCurrentFile()) + { + // Clear undo history + undoManager.clearUndoHistory(); + } }); return true; + } bool TerpstraSysExApplication::saveSysExMapping(std::function saveFileCallback) @@ -413,14 +419,9 @@ bool TerpstraSysExApplication::saveSysExMappingAs(std::function save fileChooser->launchAsync(FileBrowserComponent::FileChooserFlags::saveMode | FileBrowserComponent::FileChooserFlags::warnAboutOverwriting, [this, saveFileCallback](const FileChooser& chooser) { - state.setCurrentFile(chooser.getResult()); + setCurrentFile(chooser.getResult()); bool saved = saveCurrentFile(); - if (saved) - { - // Window title - updateMainTitle(); - } - + setHasChangesToSave(!saved); saveFileCallback(saved); }); @@ -429,22 +430,21 @@ bool TerpstraSysExApplication::saveSysExMappingAs(std::function save bool TerpstraSysExApplication::resetSysExMapping() { - state.setCurrentFile(juce::File()); - updateMainTitle(); + setCurrentFile(juce::File()); return true; } // Saves the current mapping to file, specified in state.getCurrentFile(). bool TerpstraSysExApplication::saveCurrentFile(std::function saveFileCallback) { - bool success = state.saveMappingToFile(state.getCurrentFile()); + bool success = saveMappingToFile(state.getCurrentFile()); saveFileCallback(success); return success; } bool TerpstraSysExApplication::deleteSubBoardData() { - return performUndoableAction(((MainContentComponent*)(mainWindow->getContentComponent()))->createDeleteCurrentSectionAction()); + return performAction(((MainContentComponent*)(mainWindow->getContentComponent()))->createDeleteCurrentSectionAction()); } bool TerpstraSysExApplication::copySubBoardData() @@ -454,7 +454,7 @@ bool TerpstraSysExApplication::copySubBoardData() bool TerpstraSysExApplication::pasteSubBoardData() { - return performUndoableAction(((MainContentComponent*)(mainWindow->getContentComponent()))->createPasteCurrentSectionAction()); + return performAction(((MainContentComponent*)(mainWindow->getContentComponent()))->createPasteCurrentSectionAction()); } bool TerpstraSysExApplication::pasteModifiedSubBoardData(CommandID commandID) @@ -465,7 +465,7 @@ bool TerpstraSysExApplication::pasteModifiedSubBoardData(CommandID commandID) case Lumatone::Menu::pasteOctaveBoardColours: case Lumatone::Menu::pasteOctaveBoardChannels: case Lumatone::Menu::pasteOctaveBoardTypes: - return performUndoableAction(((MainContentComponent*)(mainWindow->getContentComponent()))->createModifiedPasteCurrentSectionAction(commandID)); + return performAction(((MainContentComponent*)(mainWindow->getContentComponent()))->createModifiedPasteCurrentSectionAction(commandID)); default: jassertfalse; return false; @@ -479,30 +479,11 @@ bool TerpstraSysExApplication::canPasteSubBoardData() const return false; } -bool TerpstraSysExApplication::performUndoableAction(UndoableAction* editAction, bool newTransaction) -{ - if (editAction != nullptr) - { - if (newTransaction) - undoManager.beginNewTransaction(); - - if (undoManager.perform(editAction)) // UndoManager will check for nullptr and also for disposing of the object - { - // setHasChangesToSave(true); - //((MainContentComponent*)(mainWindow->getContentComponent()))->refreshAllFields(); - return true; - } - } - - return false; -} - bool TerpstraSysExApplication::undo() { if (undoManager.undo()) { - // setHasChangesToSave(true); - // ((MainContentComponent*)(mainWindow->getContentComponent()))->refreshAllFields(); + setHasChangesToSave(true); return true; } else @@ -513,8 +494,7 @@ bool TerpstraSysExApplication::redo() { if (undoManager.redo()) { - // setHasChangesToSave(true); - // ((MainContentComponent*)(mainWindow->getContentComponent()))->refreshAllFields(); + setHasChangesToSave(true); return true; } else @@ -523,7 +503,7 @@ bool TerpstraSysExApplication::redo() bool TerpstraSysExApplication::toggleDeveloperMode() { - state.setDeveloperMode(!state.getInDeveloperMode()); + setDeveloperMode(!state.getInDeveloperMode()); return true; // bool newMode = !propertiesFile->getBoolValue("DeveloperMode"); // propertiesFile->setValue("DeveloperMode", newMode); @@ -624,7 +604,7 @@ bool TerpstraSysExApplication::toggleDeveloperMode() // } -bool TerpstraSysExApplication::requestConfigurationFromDevice() +bool TerpstraSysExApplication::onRequestDeviceConfig() { // if editing operations were done that have not been saved, give the possibility to save them if (state.getHasChangesToSave()) @@ -640,7 +620,7 @@ bool TerpstraSysExApplication::requestConfigurationFromDevice() { // "Cancel". Do not receive config, go offline DBG("Layout import cancelled"); - state.setEditMode(EditorMode::OFFLINE); + setEditMode(EditorMode::OFFLINE); return; } else if (retc == 1) @@ -649,7 +629,7 @@ bool TerpstraSysExApplication::requestConfigurationFromDevice() saveSysExMapping([this](bool success) { if (success) - this->requestConfigurationFromDevice(); + onRequestDeviceConfig(); else DBG("Cancelled layout import"); }); @@ -658,8 +638,8 @@ bool TerpstraSysExApplication::requestConfigurationFromDevice() { // retc == 2: "No" -> no saving, overwrite DBG("Overwriting current edits"); - //state.setHasChangesToSave(false); - requestConfigurationFromDevice(); + setHasChangesToSave(false); + onRequestDeviceConfig(); } }) ); @@ -667,35 +647,12 @@ bool TerpstraSysExApplication::requestConfigurationFromDevice() return true; } - resetSysExMapping(); - - // Request MIDI channel, MIDI note, colour and key type config for all keys - state.getLumatoneController()->sendGetCompleteMappingRequest(); - - // General options - state.getLumatoneController()->requestPresetFlags(); - state.getLumatoneController()->requestExpressionPedalSensitivity(); - - // Velocity curve config - state.getLumatoneController()->sendVelocityIntervalConfigRequest(); - state.getLumatoneController()->sendVelocityConfigRequest(); - state.getLumatoneController()->sendFaderConfigRequest(); - state.getLumatoneController()->sendAftertouchConfigRequest(); + // resetSysExMapping(); + requestCompleteConfigFromDevice(); return true; } -void TerpstraSysExApplication::updateMainTitle() -{ - String windowTitle("Lumatone Editor"); - - if (!state.getCurrentFile().getFileName().isEmpty()) - windowTitle << " - " << state.getCurrentFile().getFileName(); - if (state.getHasChangesToSave()) - windowTitle << "*"; - mainWindow->setName(windowTitle); -} - // //https://forum.juce.com/t/closing-dialog-windows-on-shutdown/27326/6 void TerpstraSysExApplication::setOpenDialogWindow(DialogWindow* dialogWindowIn) diff --git a/Source/Main.h b/Source/Main.h index 8d976f2..e68a773 100644 --- a/Source/Main.h +++ b/Source/Main.h @@ -26,7 +26,7 @@ class MainContentComponent; class DeviceActivityMonitor; //============================================================================== -class TerpstraSysExApplication : public juce::JUCEApplication +class TerpstraSysExApplication : public juce::JUCEApplication, private LumatoneEditorState::Controller { public: //============================================================================== @@ -43,6 +43,7 @@ class TerpstraSysExApplication : public juce::JUCEApplication void loadPropertiesFile(); + //============================================================================== // Menu functionality void getAllCommands(juce::Array & commands) override; void getCommandInfo(juce::CommandID commandID, juce::ApplicationCommandInfo& result) override; @@ -63,7 +64,6 @@ class TerpstraSysExApplication : public juce::JUCEApplication bool pasteModifiedSubBoardData(juce::CommandID commandID); bool canPasteSubBoardData() const; - bool performUndoableAction(juce::UndoableAction* editAction, bool newTransaction=true); bool undo(); bool redo(); @@ -74,20 +74,20 @@ class TerpstraSysExApplication : public juce::JUCEApplication // bool faderVelocityCurveDialog(); // bool aftertouchVelocityCurveDialog(); - // void sendCurrentConfigurationToDevice(); - bool requestConfigurationFromDevice(); + bool aboutTerpstraSysEx(); - void updateMainTitle(); + //============================================================================== +private: + bool onRequestDeviceConfig(); void setOpenDialogWindow(juce::DialogWindow* dialogWindowIn); - bool aboutTerpstraSysEx(); - private: LumatoneFirmwareDriver firmwareDriver; juce::UndoManager undoManager; - LumatoneEditorStateController state; + LumatoneEditorState state; + std::unique_ptr commandManager; MainContentComponent* mainComponent; diff --git a/Source/MainComponent.cpp b/Source/MainComponent.cpp index a805fc5..83791aa 100644 --- a/Source/MainComponent.cpp +++ b/Source/MainComponent.cpp @@ -176,7 +176,7 @@ TabbedButtonBar *MainContentComponent::getOctaveBoardSelectorTab() return noteEditArea->getOctaveBoardSelectorTab(); } -UndoableAction* MainContentComponent::createDeleteCurrentSectionAction() +LumatoneAction* MainContentComponent::createDeleteCurrentSectionAction() { auto currentSetSelection = noteEditArea->getOctaveBoardSelectorTab()->getCurrentTabIndex(); if (currentSetSelection >= 0 && currentSetSelection < getOctaveBoardSize()) @@ -200,7 +200,7 @@ bool MainContentComponent::copyCurrentSubBoardData() return false; } -UndoableAction* MainContentComponent::createPasteCurrentSectionAction() +LumatoneAction* MainContentComponent::createPasteCurrentSectionAction() { auto currentSetSelection = noteEditArea->getOctaveBoardSelectorTab()->getCurrentTabIndex(); if (currentSetSelection >= 0 && currentSetSelection < getNumBoards() @@ -212,7 +212,7 @@ UndoableAction* MainContentComponent::createPasteCurrentSectionAction() return nullptr; } -UndoableAction* MainContentComponent::createModifiedPasteCurrentSectionAction(CommandID commandID) +LumatoneAction* MainContentComponent::createModifiedPasteCurrentSectionAction(CommandID commandID) { auto currentSetSelectionIndex = noteEditArea->getOctaveBoardSelectorTab()->getCurrentTabIndex(); if (currentSetSelectionIndex >= 0 && currentSetSelectionIndex < getNumBoards() diff --git a/Source/MainComponent.h b/Source/MainComponent.h index 4d83d54..843e328 100644 --- a/Source/MainComponent.h +++ b/Source/MainComponent.h @@ -47,10 +47,10 @@ class MainContentComponent : public juce::Component CurvesArea* getCurvesArea() { return curvesArea.get(); } // Board edit operations - juce::UndoableAction* createDeleteCurrentSectionAction(); + LumatoneAction* createDeleteCurrentSectionAction(); bool copyCurrentSubBoardData(); - juce::UndoableAction* createPasteCurrentSectionAction(); - juce::UndoableAction* createModifiedPasteCurrentSectionAction(CommandID commandID); + LumatoneAction* createPasteCurrentSectionAction(); + LumatoneAction* createModifiedPasteCurrentSectionAction(CommandID commandID); bool canPasteCopiedSubBoard() const; // Implementation of ChangeListener diff --git a/Source/MainWindow.cpp b/Source/MainWindow.cpp index 98ace86..c9c927c 100644 --- a/Source/MainWindow.cpp +++ b/Source/MainWindow.cpp @@ -17,7 +17,8 @@ MainWindow::MainWindow(const LumatoneEditorState& stateIn, juce::ApplicationCommandManager* cmdManager) : juce::DocumentWindow("Lumatone Editor", juce::Colours::black, juce::DocumentWindow::minimiseButton + juce::DocumentWindow::closeButton) - , LumatoneEditorStateController("MainWindow", stateIn) + , LumatoneEditorState("MainWindow", stateIn) + , LumatoneEditorState::Controller(static_cast(*this)) , commandManager(cmdManager) { setContentOwned(new MainContentComponent(*this, commandManager), true); @@ -177,3 +178,26 @@ void MainWindow::timerCallback() updateBounds(); } + +void MainWindow::updateTitle() +{ + juce::String windowTitle("Lumatone Editor"); + + if (!getCurrentFile().getFileName().isEmpty()) + windowTitle << " - " << getCurrentFile().getFileName(); + + if (getHasChangesToSave()) + windowTitle << "*"; + + setName(windowTitle); +} + +void MainWindow::handleStatePropertyChange(juce::ValueTree stateIn, const juce::Identifier &property) +{ + LumatoneEditorState::handleStatePropertyChange(stateIn, property); + + if (property == LumatoneEditorProperty::HasChangesToSave) + { + updateTitle(); + } +} diff --git a/Source/MainWindow.h b/Source/MainWindow.h index baa22ff..acc9956 100644 --- a/Source/MainWindow.h +++ b/Source/MainWindow.h @@ -12,7 +12,6 @@ #include "LumatoneMenu.h" #include "LumatoneEditorState.h" -//class LumatoneEditorState; //============================================================================== /* @@ -20,13 +19,14 @@ This class implements the desktop window that contains an instance of our MainContentComponent class. */ class MainWindow : public juce::DocumentWindow - , public LumatoneEditorStateController - , public juce::Timer + , public LumatoneEditorState + , private LumatoneEditorState::Controller + , private juce::Timer { public: MainWindow(const LumatoneEditorState& stateIn, juce::ApplicationCommandManager* commandManager); - virtual ~MainWindow(); + virtual ~MainWindow() override; void closeButtonPressed() override; @@ -59,6 +59,12 @@ class MainWindow : public juce::DocumentWindow void timerCallback() override; + void updateTitle(); + +private: + + void handleStatePropertyChange(juce::ValueTree stateIn, const juce::Identifier &property) override; + private: juce::ApplicationCommandManager* commandManager; std::unique_ptr menuModel; diff --git a/Source/NoteEditArea.cpp b/Source/NoteEditArea.cpp index 6481f0e..f18fc96 100644 --- a/Source/NoteEditArea.cpp +++ b/Source/NoteEditArea.cpp @@ -40,6 +40,7 @@ //============================================================================== NoteEditArea::NoteEditArea (const LumatoneEditorState& stateIn) : LumatoneEditorState("NoteEditArea", stateIn) + , LumatoneEditorState::Controller(static_cast(*this)) , currentSingleKeySelection(-1) { //[Constructor_pre] You can add your own custom stuff here.. @@ -413,17 +414,17 @@ Colour NoteEditArea::getSelectedColour() return Colour(); } -void NoteEditArea::completeMappingLoaded(LumatoneLayout mappingData) +void NoteEditArea::completeMappingLoaded(const LumatoneLayout& mappingData) { refreshKeyFields(); } -void NoteEditArea::boardChanged(LumatoneBoard boardData) +void NoteEditArea::boardChanged(const LumatoneBoard& boardData) { refreshKeyFields(); } -void NoteEditArea::keyChanged(int boardIndex, int keyIndex, LumatoneKey lumatoneKey) +void NoteEditArea::keyChanged(int boardIndex, int keyIndex, const LumatoneKey& lumatoneKey) { refreshKeyFields(); } diff --git a/Source/NoteEditArea.h b/Source/NoteEditArea.h index 6dfe968..8b5a54d 100644 --- a/Source/NoteEditArea.h +++ b/Source/NoteEditArea.h @@ -47,6 +47,7 @@ class LumatoneKeyEdit; */ class NoteEditArea : public juce::Component, public LumatoneEditorState, + public LumatoneEditorState::Controller, public juce::ChangeListener, public LumatoneEditor::EditorListener, public ColourSelectionBroadcaster @@ -77,7 +78,7 @@ class NoteEditArea : public juce::Component, // ColourSelectionBroadcaster Implementation juce::Colour getSelectedColour() override; - void deselectColour() override {}; + void deselectColour() override {} // Helper method for aligning the Octave Section TabbedButtonBar void setControlsTopLeftPosition(int controlsAreaX, int controlsAreaY); @@ -104,9 +105,9 @@ class NoteEditArea : public juce::Component, private: // LumatoneEditor::EditorListener - void completeMappingLoaded(LumatoneLayout mappingData) override; - void boardChanged(LumatoneBoard boardData) override; - void keyChanged(int boardIndex, int keyIndex, LumatoneKey lumatoneKey) override; + void completeMappingLoaded(const LumatoneLayout& mappingData) override; + void boardChanged(const LumatoneBoard& boardData) override; + void keyChanged(int boardIndex, int keyIndex, const LumatoneKey& lumatoneKey) override; void selectionChanged(juce::Array selection) override; // LumatoneEditorState implementaiton diff --git a/Source/Settings/SettingsContainer.h b/Source/Settings/SettingsContainer.h index 7fc6ff0..64df86c 100644 --- a/Source/Settings/SettingsContainer.h +++ b/Source/Settings/SettingsContainer.h @@ -47,7 +47,7 @@ class SettingsCategoryModel : public ListBoxModel, public ChangeBroadcaster }; class SettingsContainer : public Component - , private LumatoneEditorState + , public LumatoneEditorState , protected ChangeListener { public: diff --git a/Source/lumatone_editor_library/data/application_state.cpp b/Source/lumatone_editor_library/data/application_state.cpp index 9c3a4d6..1b642c9 100644 --- a/Source/lumatone_editor_library/data/application_state.cpp +++ b/Source/lumatone_editor_library/data/application_state.cpp @@ -3,12 +3,15 @@ #include "../device/activity_monitor.h" #include "../color/colour_model.h" #include "../data/lumatone_context.h" +#include "../actions/lumatone_action.h" #include "../listeners/status_listener.h" #include "../listeners/editor_listener.h" #include "../listeners/firmware_listener.h" #include "../listeners/midi_listener.h" +#include "../lumatone_midi_driver/lumatone_midi_driver.h" + juce::Array getLumatoneApplicationProperties() { juce::Array properties; @@ -21,6 +24,7 @@ juce::Array getLumatoneApplicationProperties() LumatoneApplicationState::LumatoneApplicationState(juce::String nameIn, LumatoneFirmwareDriver& driverIn, juce::ValueTree stateIn, juce::UndoManager *undoManagerIn) : LumatoneState(nameIn, stateIn, undoManagerIn) + , firmwareDriver(driverIn) { editorListeners = std::make_shared>(); statusListeners = std::make_shared>(); @@ -45,6 +49,7 @@ LumatoneApplicationState::LumatoneApplicationState(juce::String nameIn, Lumatone LumatoneApplicationState::LumatoneApplicationState(juce::String nameIn, const LumatoneApplicationState &stateIn) : LumatoneState(nameIn, (const LumatoneState&)stateIn) + , firmwareDriver(stateIn.firmwareDriver) , editorListeners(stateIn.editorListeners) , statusListeners(stateIn.statusListeners) , firmwareListeners(stateIn.firmwareListeners) @@ -72,12 +77,17 @@ ConnectionState LumatoneApplicationState::getConnectionState() const int LumatoneApplicationState::getMidiInputIndex() const { - return controller->getMidiInputIndex(); + return firmwareDriver.getMidiInputIndex(); } int LumatoneApplicationState::getMidiOutputIndex() const { - return controller->getMidiOutputIndex(); + return firmwareDriver.getMidiOutputIndex(); +} + +bool LumatoneApplicationState::isAutoConnectionEnabled() const +{ + return activityMonitor->willDetectDeviceIfDisconnected(); } bool LumatoneApplicationState::doSendChangesToDevice() const @@ -105,6 +115,25 @@ std::shared_ptr LumatoneApplicationState::shareContext() return layoutContext; } +bool LumatoneApplicationState::performLumatoneAction(LumatoneAction *action, bool undoable, bool newTransaction) +{ + if (action == nullptr) + return false; + + if (undoable) + { + if (undoManager == nullptr) + return false; + + if (newTransaction) + undoManager->beginNewTransaction(); + + return undoManager->perform((juce::UndoableAction*)action, action->getName()); + } + + return action->perform(); +} + juce::ValueTree LumatoneApplicationState::loadStateProperties(juce::ValueTree stateIn) { juce::ValueTree newState = (stateIn.hasType(LumatoneStateProperty::StateTree)) @@ -389,9 +418,9 @@ void LumatoneApplicationState::setConfigTable(LumatoneConfigTable::TableType typ // } //} -bool LumatoneApplicationState::performAction(LumatoneAction *action, bool undoable, bool newTransaction) +bool LumatoneApplicationState::Controller::performAction(LumatoneAction *action, bool undoable, bool newTransaction) { - return controller->performAction(action, undoable, newTransaction); + return appState.performLumatoneAction(action, undoable, newTransaction); } void LumatoneApplicationState::addStatusListener(LumatoneEditor::StatusListener* listenerIn) @@ -434,10 +463,70 @@ void LumatoneApplicationState::removeMidiListener(LumatoneEditor::MidiListener* midiListeners->remove(listenerIn); } -void LumatoneApplicationStateController::setConnectionState(ConnectionState newState, bool sendNotification) +bool LumatoneApplicationState::Controller::requestCompleteConfigFromDevice() +{ + if (appState.connectionState != ConnectionState::ONLINE) + return false; + + // Request MIDI channel, MIDI note, colour and key type config for all keys + appState.controller->sendGetCompleteMappingRequest(); + + // General options + appState.controller->requestPresetFlags(); + appState.controller->requestExpressionPedalSensitivity(); + + // Velocity curve config + appState.controller->sendVelocityIntervalConfigRequest(); + appState.controller->sendVelocityConfigRequest(); + appState.controller->sendFaderConfigRequest(); + appState.controller->sendAftertouchConfigRequest(); + + return true; +} + +bool LumatoneApplicationState::Controller::requestMappingFromDevice() { - connectionState = newState; - state.setPropertyExcludingListener(this, LumatoneApplicationProperty::ConnectionStateId, juce::var((int)connectionState), nullptr); + if (appState.connectionState != ConnectionState::ONLINE) + return false; + + appState.controller->sendGetCompleteMappingRequest(); + return true; +} + +void LumatoneApplicationState::DeviceController::setConnectionState(ConnectionState newState, bool sendNotification) +{ + deviceAppState.connectionState = newState; + deviceAppState.setStateProperty(LumatoneApplicationProperty::ConnectionStateId, juce::var((int)deviceAppState.connectionState)); if (sendNotification) - statusListeners->call(&LumatoneEditor::StatusListener::connectionStateChanged, connectionState); + getStatusListeners()->call(&LumatoneEditor::StatusListener::connectionStateChanged, deviceAppState.connectionState); +} + +void LumatoneApplicationState::DeviceController::setAutoConnectionEnabled(bool enabled) +{ + deviceAppState.activityMonitor->setDetectDeviceIfDisconnected(enabled); + deviceAppState.activityMonitor->setCheckForInactivity(enabled); +} + +juce::Array LumatoneApplicationState::DeviceController::getMidiInputList() +{ + return deviceAppState.firmwareDriver.getMidiInputList(); +} + +juce::Array LumatoneApplicationState::DeviceController::getMidiOutputList() +{ + return deviceAppState.firmwareDriver.getMidiOutputList(); +} + +void LumatoneApplicationState::DeviceController::setMidiInput(int deviceIndex, bool test) +{ + auto deviceInfo = getMidiInputList()[deviceIndex]; + deviceAppState.setStateProperty(LumatoneApplicationProperty::LastInputDeviceId, deviceInfo.identifier); + deviceAppState.controller->setDriverMidiInput(deviceIndex, test); +} + +void LumatoneApplicationState::DeviceController::setMidiOutput(int deviceIndex, bool test) +{ + auto deviceInfo = getMidiOutputList()[deviceIndex]; + deviceAppState.setStateProperty(LumatoneApplicationProperty::LastOutputDeviceId, deviceInfo.identifier); + deviceAppState.controller->setDriverMidiOutput(deviceIndex, test); } diff --git a/Source/lumatone_editor_library/data/application_state.h b/Source/lumatone_editor_library/data/application_state.h index 9c0d328..5822079 100644 --- a/Source/lumatone_editor_library/data/application_state.h +++ b/Source/lumatone_editor_library/data/application_state.h @@ -25,8 +25,8 @@ namespace LumatoneEditor namespace LumatoneApplicationProperty { // Device Management - // static const juce::Identifier DetectDeviceIfDisconnected = juce::Identifier("DetectDeviceIfDisconnected"); - // static const juce::Identifier CheckConnectionIfInactive = juce::Identifier("CheckConnectionIfInactive"); + static const juce::Identifier DetectDeviceIfDisconnected = juce::Identifier("DetectDeviceIfDisconnected"); + static const juce::Identifier CheckConnectionIfInactive = juce::Identifier("CheckConnectionIfInactive"); static const juce::Identifier DetectDevicesTimeout = juce::Identifier("DetectDevicesTimeout"); static const juce::Identifier LastInputDeviceId = juce::Identifier("LastInputDeviceId"); @@ -50,7 +50,6 @@ class LumatoneColourModel; class LumatoneAction; class DeviceActivityMonitor; -class LumatoneApplicationStateController; class LumatoneApplicationState : public LumatoneState { public: @@ -67,6 +66,8 @@ class LumatoneApplicationState : public LumatoneState int getMidiInputIndex() const; int getMidiOutputIndex() const; + bool isAutoConnectionEnabled() const; + virtual bool doSendChangesToDevice() const; // Context Methods @@ -103,8 +104,8 @@ class LumatoneApplicationState : public LumatoneState //void setAftertouchTable(const LumatoneConfigTable& tableIn) override; //void setLumatouchTable(const LumatoneConfigTable& tableIn) override; - virtual bool performAction(LumatoneAction* action, bool undoable = true, bool newTransaction = true); - +private: + bool performLumatoneAction(LumatoneAction* action, bool undoable = true, bool newTransaction = true); protected: virtual juce::ValueTree loadStateProperties(juce::ValueTree stateIn); @@ -140,6 +141,8 @@ class LumatoneApplicationState : public LumatoneState private: + LumatoneFirmwareDriver& firmwareDriver; + std::shared_ptr layoutContext; std::shared_ptr controller; std::shared_ptr activityMonitor; @@ -148,26 +151,53 @@ class LumatoneApplicationState : public LumatoneState bool contextIsSet = false; //================================================================================ +public: + class Controller + { + public: + Controller(LumatoneApplicationState& stateIn) + : appState(stateIn) {} - friend class LumatoneApplicationStateController; -}; + virtual bool requestCompleteConfigFromDevice(); + virtual bool requestMappingFromDevice(); -class LumatoneApplicationStateController : public LumatoneApplicationState -{ -public: - LumatoneApplicationStateController(juce::String nameIn, LumatoneFirmwareDriver& driverIn, juce::ValueTree stateIn=juce::ValueTree(), juce::UndoManager* undoManager=nullptr) - : LumatoneApplicationState(nameIn, driverIn, stateIn, undoManager) {} - LumatoneApplicationStateController(juce::String nameIn, const LumatoneApplicationState& stateIn) - : LumatoneApplicationState(nameIn, stateIn) {} + virtual bool performAction(LumatoneAction* action, bool undoable=true, bool newTransaction=true); -protected: - virtual void setConnectionState(ConnectionState newState, bool sendNotification=true); + protected: + juce::ListenerList* getEditorListeners() const { return appState.editorListeners.get(); } + juce::ListenerList* getStatusListeners() const { return appState.statusListeners.get(); } + juce::ListenerList* getFirmwareListeners() const { return appState.firmwareListeners.get(); } + juce::ListenerList* getMidiListeners() const { return appState.midiListeners.get(); } - juce::ListenerList* getEditorListeners() const { return editorListeners.get(); } - juce::ListenerList* getStatusListeners() const { return statusListeners.get(); } - juce::ListenerList* getFirmwareListeners() const { return firmwareListeners.get(); } - juce::ListenerList* getMidiListeners() const { return midiListeners.get(); } - + private: + LumatoneApplicationState& appState; + }; + + class DeviceController : protected Controller + { + public: + DeviceController(LumatoneApplicationState& stateIn) + : Controller(stateIn) + , deviceAppState(stateIn) {} + + juce::Array getMidiInputList(); + juce::Array getMidiOutputList(); + + protected: + virtual void setMidiInput(int deviceIndex, bool test = true); + virtual void setMidiOutput(int deviceIndex, bool test = true); + + void setConnectionState(ConnectionState newState, bool sendNotification=true); + + void setAutoConnectionEnabled(bool enabled); + + private: + LumatoneApplicationState& deviceAppState; + }; + +private: + friend class Controller; + friend class DeviceController; }; -#endif LUMATONE_APPLICATION_STATE_H +#endif // LUMATONE_APPLICATION_STATE_H diff --git a/Source/lumatone_editor_library/data/lumatone_state.cpp b/Source/lumatone_editor_library/data/lumatone_state.cpp index 4cde442..d140e75 100644 --- a/Source/lumatone_editor_library/data/lumatone_state.cpp +++ b/Source/lumatone_editor_library/data/lumatone_state.cpp @@ -108,7 +108,6 @@ void LumatoneState::setConnectedSerialNumber(juce::String serialNumberIn) connectedSerialNumber, undoManager); - // numBoards = 5; if (connectedSerialNumber == SERIAL_55_KEYS) { @@ -126,18 +125,6 @@ void LumatoneState::setLumatoneVersion(LumatoneFirmware::ReleaseVersion versionI { determinedVersion = versionIn; - // numBoards = 5; - - switch (determinedVersion) - { - case LumatoneFirmware::ReleaseVersion::VERSION_55_KEYS: - mappingData->setOctaveBoardSize(55); - break; - default: - mappingData->setOctaveBoardSize(56); - break; - } - if (writeToState) { state.setPropertyExcludingListener( @@ -150,7 +137,8 @@ void LumatoneState::setLumatoneVersion(LumatoneFirmware::ReleaseVersion versionI void LumatoneState::setCompleteConfig(const LumatoneLayout &layoutIn) { - *mappingData = layoutIn; + if (mappingData.get() != &layoutIn) + *mappingData = layoutIn; } void LumatoneState::setLayout(const LumatoneLayout &layoutIn) diff --git a/Source/palette_edit_panel.h b/Source/palette_edit_panel.h index 8e156cc..815583d 100644 --- a/Source/palette_edit_panel.h +++ b/Source/palette_edit_panel.h @@ -21,7 +21,7 @@ * Colour palette edtior panel */ class PaletteEditPanel : public juce::Component - , private LumatoneEditorState + , public LumatoneEditorState , public juce::Button::Listener , public juce::Label::Listener , public juce::ChangeBroadcaster From bf083c0a27c4f47454d8f58ff75d82857c283af1 Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Sat, 20 Jan 2024 01:27:29 -0500 Subject: [PATCH 07/19] device controller implementation and fix auto connection handling --- Source/MidiEditArea.cpp | 209 ++++++++++-------- Source/MidiEditArea.h | 26 +-- .../device/activity_monitor.cpp | 15 +- .../device/activity_monitor.h | 7 +- .../device/lumatone_controller.cpp | 151 ++++++------- .../device/lumatone_controller.h | 31 +-- .../device/lumatone_event_manager.cpp | 13 +- 7 files changed, 222 insertions(+), 230 deletions(-) diff --git a/Source/MidiEditArea.cpp b/Source/MidiEditArea.cpp index bae92d3..449ceea 100644 --- a/Source/MidiEditArea.cpp +++ b/Source/MidiEditArea.cpp @@ -33,6 +33,8 @@ //============================================================================== MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) : LumatoneEditorState("MidiEditArea", stateIn) + , LumatoneEditorState::Controller(static_cast(*this)) + , LumatoneApplicationState::DeviceController(static_cast(*this)) { //[Constructor_pre] You can add your own custom stuff here.. setName("MidiEditArea"); @@ -44,22 +46,38 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) addAndMakeVisible(lumatoneLabel.get()); liveEditorBtn.reset(new juce::TextButton("LiveEditorButton")); - getEditorLookAndFeel().setupRadioTextButton(*liveEditorBtn, 10, true); + getEditorLookAndFeel().setupRadioTextButton(*liveEditorBtn, 10, false); liveEditorBtn->setButtonText(translate("LiveEditor")); liveEditorBtn->setConnectedEdges(juce::Button::ConnectedOnRight); liveEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontOverride, LumatoneEditorFont::UniviaProBold); liveEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontHeightScalar, editModeFontScalar); addChildComponent(liveEditorBtn.get()); - liveEditorBtn->addListener(this); + // liveEditorBtn->addListener(this); + liveEditorBtn->onClick = [&]() + { + if (liveEditorBtn->getToggleState()) + { + setEditMode(EditorMode::ONLINE); + editModeChangedCallback(); + } + }; offlineEditorBtn.reset(new juce::TextButton("OfflineEditorButton")); - getEditorLookAndFeel().setupRadioTextButton(*offlineEditorBtn, 10, false); + getEditorLookAndFeel().setupRadioTextButton(*offlineEditorBtn, 10, true); offlineEditorBtn->setButtonText(translate("OfflineEditor")); offlineEditorBtn->setConnectedEdges(juce::Button::ConnectedOnLeft); offlineEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontOverride, LumatoneEditorFont::UniviaProBold); offlineEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontHeightScalar, editModeFontScalar); addChildComponent(offlineEditorBtn.get()); - offlineEditorBtn->addListener(this); + // offlineEditorBtn->addListener(this); + offlineEditorBtn->onClick = [&]() + { + if (offlineEditorBtn->getToggleState()) + { + setEditMode(EditorMode::OFFLINE); + editModeChangedCallback(); + } + }; pleaseConnectLabel.reset(new juce::Label("PleaseConnectLabel", translate("PleaseConnect"))); pleaseConnectLabel->setFont(getAppFonts().getFont(LumatoneEditorFont::UniviaProBold)); @@ -117,8 +135,10 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) addAndMakeVisible (btnAutoConnect.get()); btnAutoConnect->setTooltip (juce::translate("Toggle between automatic or manual connection to Lumatone")); btnAutoConnect->setButtonText (juce::translate("auto")); - btnAutoConnect->addListener (this); - + btnAutoConnect->onClick = [&]() + { + toggleAutoConnection(); + }; //[UserPreSize] cbMidiInput->getProperties().set(LumatoneEditorStyleIDs::popupMenuTargetWidth, 1); @@ -153,15 +173,13 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) //[Constructor] You can add your own custom stuff here.. - // auto inputs = getLumatoneController()->getMidiInputList(); - // auto outputs = getLumatoneController()->getMidiOutputList(); refreshInputMenuAndSetSelected(0, dontSendNotification); refreshOutputMenuAndSetSelected(0, dontSendNotification); setConnectivity(false); addEditorListener(this); addStatusListener(this); - // btnAutoConnect->setToggleState(getLumatoneController()->isDetectingLumatone(), sendNotificationSync); + btnAutoConnect->setToggleState(isAutoConnectionEnabled(), sendNotificationSync); //[/Constructor] } @@ -328,7 +346,7 @@ void MidiEditArea::comboBoxChanged (juce::ComboBox* comboBoxThatHasChanged) { //[UserComboBoxCode_cbMidiInput] -- add your combo box handling code here.. if (cbMidiInput->getSelectedItemIndex() >= 0) - getLumatoneController()->setMidiInput(cbMidiInput->getSelectedItemIndex()); + setMidiInput(cbMidiInput->getSelectedItemIndex()); if (cbMidiInput->getSelectedItemIndex() < 0 || cbMidiOutput->getSelectedItemIndex() < 0) { @@ -349,7 +367,7 @@ void MidiEditArea::comboBoxChanged (juce::ComboBox* comboBoxThatHasChanged) { //[UserComboBoxCode_cbMidiOutput] -- add your combo box handling code here.. if (cbMidiOutput->getSelectedItemIndex() >= 0) - getLumatoneController()->setMidiOutput(cbMidiOutput->getSelectedItemIndex()); + setMidiOutput(cbMidiOutput->getSelectedItemIndex()); if (cbMidiInput->getSelectedItemIndex() < 0 || cbMidiOutput->getSelectedItemIndex() < 0) { @@ -371,49 +389,6 @@ void MidiEditArea::comboBoxChanged (juce::ComboBox* comboBoxThatHasChanged) //[/UsercomboBoxChanged_Post] } -void MidiEditArea::buttonClicked (juce::Button* buttonThatWasClicked) -{ - //[UserbuttonClicked_Pre] - - //[/UserbuttonClicked_Pre] - - if (buttonThatWasClicked == btnAutoConnect.get()) - { - //[UserButtonCode_btnAutoConnect] -- add your button handler code here.. - cbMidiInput->setVisible(!btnAutoConnect->getToggleState()); - cbMidiOutput->setVisible(!btnAutoConnect->getToggleState()); - - if (btnAutoConnect->getToggleState()) - { - // getLumatoneController()->detectAndConnectToLumatone(); - lblConnectionState->setText(translate("Searching for Lumatone..."), dontSendNotification); - //errorVisualizer.setErrorLevel( - // *lblConnectionState.get(), - // HajuErrorVisualizer::ErrorLevel::error, - // translate("Waiting for response from connected devices...")); - } - else - { - // getLumatoneController()->stopAutoConnection(); - lblConnectionState->setText(translate("Disconnected"), dontSendNotification); - startTimer(deviceRefreshTimeoutMs); - } - - resized(); - //[/UserButtonCode_btnAutoConnect] - } - - //[UserbuttonClicked_Post] - else if (buttonThatWasClicked == liveEditorBtn.get()) - { - // auto sysExSendingMode = editModeTabIndexToMidiSysExSendingMode((int)!liveEditorBtn->getToggleState()); - // TerpstraSysExApplication::getApp().setEditMode(sysExSendingMode); - } - //[/UserbuttonClicked_Post] -} - - - //[MiscUserCode] You can add your own definitions of your custom methods or any other code here... void MidiEditArea::lookAndFeelChanged() @@ -476,6 +451,51 @@ void MidiEditArea::setConnectivity(bool isConnectedIn, juce::String connectionSt resized(); } +void MidiEditArea::toggleAutoConnection() +{ + cbMidiInput->setVisible(!btnAutoConnect->getToggleState()); + cbMidiOutput->setVisible(!btnAutoConnect->getToggleState()); + + setAutoConnectionEnabled(btnAutoConnect->getToggleState()); + + if (btnAutoConnect->getToggleState()) + { + lblConnectionState->setText(translate("Searching for Lumatone..."), dontSendNotification); + //errorVisualizer.setErrorLevel( + // *lblConnectionState.get(), + // HajuErrorVisualizer::ErrorLevel::error, + // translate("Waiting for response from connected devices...")); + } + else + { + // getLumatoneController()->stopAutoConnection(); + lblConnectionState->setText(translate("Disconnected"), dontSendNotification); + startTimer(deviceRefreshTimeoutMs); + } + + resized(); +} + +void MidiEditArea::editModeChangedCallback() +{ + if (getEditorMode() == EditorMode::ONLINE) + { + liveEditorBtn->setToggleState(true, juce::NotificationType::sendNotification); + lblConnectionState->setText("Connected", juce::NotificationType::dontSendNotification); + + if (getHasChangesToSave()) + onOpenConnectionToDevice(translate("Switch to Live Mode with unsaved changes")); + } + else + { + offlineEditorBtn->setToggleState(true, juce::NotificationType::sendNotification); + lblConnectionState->setText("Offline", juce::NotificationType::dontSendNotification); + } + + lblConnectionState->setColour(juce::Label::ColourIds::textColourId, connectedColours[(int)liveEditorBtn->getToggleState()]); + repaint(); +} + void MidiEditArea::connectionFailed() { setConnectivity(false, "No answer"); @@ -492,8 +512,8 @@ void MidiEditArea::connectionStateChanged(ConnectionState state) { // if (inputDevice >= 0 && outputDevice >= 0) // { - // refreshInputMenuAndSetSelected(inputDevice + 1, dontSendNotification); - // refreshOutputMenuAndSetSelected(outputDevice + 1, dontSendNotification); + refreshInputMenuAndSetSelected(getMidiInputIndex() + 1, dontSendNotification); + refreshOutputMenuAndSetSelected(getMidiOutputIndex() + 1, dontSendNotification); setConnectivity(true); onOpenConnectionToDevice(); @@ -519,32 +539,29 @@ void MidiEditArea::connectionStateChanged(ConnectionState state) void MidiEditArea::editorModeChanged(EditorMode editModeIn) { - // editorMode = editModeIn; - - switch (editModeIn) - { - case EditorMode::ONLINE: - liveEditorBtn->setToggleState(true, juce::NotificationType::dontSendNotification); - if (getHasChangesToSave()) - onOpenConnectionToDevice(translate("Switch to Live Mode with unsaved changes")); - break; - - case EditorMode::OFFLINE: - offlineEditorBtn->setToggleState(true, juce::NotificationType::dontSendNotification); - lblConnectionState->setText(translate("Offline"), juce::NotificationType::dontSendNotification); - //errorVisualizer.setErrorLevel( - // *lblConnectionState.get(), - // HajuErrorVisualizer::ErrorLevel::noError, - // "Offline"); - break; - - default: - jassertfalse; - break; - } - - lblConnectionState->setColour(juce::Label::ColourIds::textColourId, connectedColours[(int)liveEditorBtn->getToggleState()]); - repaint(); + // switch (editModeIn) + // { + // case EditorMode::ONLINE: + // liveEditorBtn->setToggleState(true, juce::NotificationType::dontSendNotification); + // if (getHasChangesToSave()) + // onOpenConnectionToDevice(translate("Switch to Live Mode with unsaved changes")); + // break; + + // case EditorMode::OFFLINE: + // offlineEditorBtn->setToggleState(true, juce::NotificationType::dontSendNotification); + // lblConnectionState->setText(translate("Offline"), juce::NotificationType::dontSendNotification); + // //errorVisualizer.setErrorLevel( + // // *lblConnectionState.get(), + // // HajuErrorVisualizer::ErrorLevel::noError, + // // "Offline"); + // break; + + // default: + // jassertfalse; + // break; + // } + + editModeChangedCallback(); } void MidiEditArea::onOpenConnectionToDevice(juce::String dialogTitle) @@ -577,23 +594,21 @@ void MidiEditArea::onOpenConnectionToDevice(juce::String dialogTitle) if (retc == 0) // Import { - getLumatoneController()->sendGetCompleteMappingRequest(); - // TerpstraSysExApplication::getApp().requestConfigurationFromDevice(); - liveEditorBtn->setToggleState(true, juce::NotificationType::sendNotification); - lblConnectionState->setText("Connected", juce::NotificationType::dontSendNotification); + // TODO non getLumatoneController call + LumatoneEditorState::Controller::requestCompleteConfigFromDevice(); + setEditMode(EditorMode::ONLINE); } else if (retc == 1) // Send { - getLumatoneController()->sendCompleteMapping(*getMappingData(), true, false); - // TerpstraSysExApplication::getApp().sendCurrentConfigurationToDevice(); - liveEditorBtn->setToggleState(true, juce::NotificationType::sendNotification); - lblConnectionState->setText("Connected", juce::NotificationType::dontSendNotification); + LumatoneEditorState::setCompleteConfig(*getMappingData()); + setEditMode(EditorMode::ONLINE); } else if (retc == 2) // Offline { - offlineEditorBtn->setToggleState(true, juce::NotificationType::sendNotification); - lblConnectionState->setText("Offline", juce::NotificationType::dontSendNotification); + setEditMode(EditorMode::OFFLINE); } + + editModeChangedCallback(); }); } @@ -601,7 +616,7 @@ void MidiEditArea::refreshInputMenuAndSetSelected(int inputDeviceIndex, juce::No { cbMidiInput->clear(juce::NotificationType::dontSendNotification); int i = 1; - for (auto device : getLumatoneController()->getMidiInputList()) + for (auto device : getMidiInputList()) cbMidiInput->addItem(device.name, i++); if (inputDeviceIndex >= 0) @@ -612,7 +627,7 @@ void MidiEditArea::refreshOutputMenuAndSetSelected(int outputDeviceIndex, juce:: { cbMidiOutput->clear(juce::NotificationType::dontSendNotification); int i = 1; - for (auto device : getLumatoneController()->getMidiOutputList()) + for (auto device : getMidiOutputList()) cbMidiOutput->addItem(device.name, i++); if (outputDeviceIndex >= 0) @@ -627,15 +642,13 @@ void MidiEditArea::timerCallback() } else { - // getLumatoneController()->refreshAvailableMidiDevices(); - refreshInputMenuAndSetSelected( - getLumatoneController()->getMidiInputIndex() + 1, + getMidiInputIndex() + 1, juce::NotificationType::dontSendNotification ); refreshOutputMenuAndSetSelected( - getLumatoneController()->getMidiOutputIndex() + 1, + getMidiOutputIndex() + 1, juce::NotificationType::dontSendNotification ); } diff --git a/Source/MidiEditArea.h b/Source/MidiEditArea.h index 0274819..e75ce66 100644 --- a/Source/MidiEditArea.h +++ b/Source/MidiEditArea.h @@ -39,13 +39,14 @@ Describe your class and how it works here! //[/Comments] */ -class MidiEditArea : public juce::Component, - public LumatoneEditorState, - public LumatoneEditor::StatusListener, - public LumatoneEditor::EditorListener, - public juce::ComboBox::Listener, - public juce::Button::Listener, - public juce::Timer +class MidiEditArea : public juce::Component + , public LumatoneEditorState + , private LumatoneEditorState::Controller + , private LumatoneApplicationState::DeviceController + , public LumatoneEditor::StatusListener + , public LumatoneEditor::EditorListener + , public juce::ComboBox::Listener + , public juce::Timer { public: //============================================================================== @@ -73,22 +74,21 @@ class MidiEditArea : public juce::Component, void timerCallback() override; private: - void setConnectivity(bool isConnected, juce::String connectionStatus=String()); + void toggleAutoConnection(); + + void editModeChangedCallback(); + public: //[/UserMethods] void paint (juce::Graphics& g) override; void resized() override; void comboBoxChanged (juce::ComboBox* comboBoxThatHasChanged) override; - void buttonClicked (juce::Button* buttonThatWasClicked) override; - - private: - //[UserVariables] -- You can add your own custom variables in this section. - // bool isConnected = false; + bool isWaitingForConnectionTest = false; bool isWaitingForUserChoice = false; diff --git a/Source/lumatone_editor_library/device/activity_monitor.cpp b/Source/lumatone_editor_library/device/activity_monitor.cpp index c1a50e0..77c6774 100644 --- a/Source/lumatone_editor_library/device/activity_monitor.cpp +++ b/Source/lumatone_editor_library/device/activity_monitor.cpp @@ -16,11 +16,12 @@ DeviceActivityMonitor::DeviceActivityMonitor(const LumatoneApplicationState& stateIn, LumatoneFirmwareDriver* midiDriverIn) - : LumatoneApplicationStateController("DeviceActivityMonitor", stateIn) + : LumatoneApplicationState("DeviceActivityMonitor", stateIn) + , LumatoneApplicationState::DeviceController(static_cast(*this)) , midiDriver(midiDriverIn) { - // detectDevicesIfDisconnected = getBoolProperty(LumatoneApplicationProperty::DetectDeviceIfDisconnected, true); - // checkConnectionOnInactivity = getBoolProperty(LumatoneApplicationProperty::CheckConnectionIfInactive, true); + detectDevicesIfDisconnected = getBoolProperty(LumatoneApplicationProperty::DetectDeviceIfDisconnected, true); + checkConnectionOnInactivity = getBoolProperty(LumatoneApplicationProperty::CheckConnectionIfInactive, true); responseTimeoutMs = getIntProperty(LumatoneApplicationProperty::DetectDevicesTimeout, detectRoutineTimeoutMs); midiDriver->addDriverListener(this); @@ -37,7 +38,7 @@ DeviceActivityMonitor::~DeviceActivityMonitor() void DeviceActivityMonitor::setDetectDeviceIfDisconnected(bool doDetection) { detectDevicesIfDisconnected = doDetection; - // writeBoolProperty(LumatoneApplicationProperty::DetectDeviceIfDisconnected, detectDevicesIfDisconnected); + writeBoolProperty(LumatoneApplicationProperty::DetectDeviceIfDisconnected, detectDevicesIfDisconnected); if (!detectDevicesIfDisconnected) { @@ -53,7 +54,7 @@ void DeviceActivityMonitor::setDetectDeviceIfDisconnected(bool doDetection) void DeviceActivityMonitor::setCheckForInactivity(bool monitorActivity) { checkConnectionOnInactivity = monitorActivity; - // writeBoolProperty(LumatoneApplicationProperty::CheckConnectionIfInactive, checkConnectionOnInactivity); + writeBoolProperty(LumatoneApplicationProperty::CheckConnectionIfInactive, checkConnectionOnInactivity); if (checkConnectionOnInactivity && isConnectionEstablished()) { @@ -265,8 +266,6 @@ void DeviceActivityMonitor::checkDetectionStatus() if (isConnectionEstablished()) { deviceDetectInProgress = false; - getStatusListeners()->call(&LumatoneEditor::StatusListener::connectionStateChanged, ConnectionState::ONLINE); - outputPingIds.clear(); if (checkConnectionOnInactivity) @@ -619,5 +618,7 @@ void DeviceActivityMonitor::establishConnection(int inputIndex, int outputIndex) DBG("\tPlugin host mode."); } + setConnectionState(ConnectionState::ONLINE); + startTimer(threadDelayMs); } diff --git a/Source/lumatone_editor_library/device/activity_monitor.h b/Source/lumatone_editor_library/device/activity_monitor.h index a7ae3a3..dd7ed81 100644 --- a/Source/lumatone_editor_library/device/activity_monitor.h +++ b/Source/lumatone_editor_library/device/activity_monitor.h @@ -24,9 +24,10 @@ class LumatoneFirmwareDriver; -class DeviceActivityMonitor : protected LumatoneApplicationStateController, - public juce::Timer, - protected LumatoneFirmwareDriverListener +class DeviceActivityMonitor : protected LumatoneApplicationState + , protected LumatoneApplicationState::DeviceController + , public juce::Timer + , protected LumatoneFirmwareDriverListener { public: diff --git a/Source/lumatone_editor_library/device/lumatone_controller.cpp b/Source/lumatone_editor_library/device/lumatone_controller.cpp index 9bccc80..e47b1fa 100644 --- a/Source/lumatone_editor_library/device/lumatone_controller.cpp +++ b/Source/lumatone_editor_library/device/lumatone_controller.cpp @@ -11,21 +11,23 @@ #include "lumatone_controller.h" #include "lumatone_event_manager.h" -#include "../actions/lumatone_action.h" #include "../lumatone_midi_driver/lumatone_midi_driver.h" #include "../listeners/editor_listener.h" -LumatoneController::LumatoneController(const LumatoneApplicationState& stateIn, LumatoneFirmwareDriver& firmwareDriverIn) - : LumatoneApplicationStateController("LumatoneController", stateIn) - , LumatoneApplicationMidiController(stateIn, firmwareDriverIn) - , firmwareDriver(firmwareDriverIn) - , updateBuffer(firmwareDriverIn, stateIn) +LumatoneController::LumatoneController(const LumatoneApplicationState& stateIn, LumatoneFirmwareDriver& driverIn) + : LumatoneApplicationState("LumatoneController", stateIn) + , LumatoneApplicationState::DeviceController(static_cast(*this)) + , LumatoneApplicationMidiController(stateIn, driverIn) + , firmwareDriver(driverIn) + , updateBuffer(driverIn, stateIn) // , LumatoneSandboxLogger("LumatoneController") { firmwareDriver.addDriverListener(this); eventManager = std::make_unique(firmwareDriver, stateIn); eventManager->addFirmwareListener(this); + + addStatusListener(this); } LumatoneController::~LumatoneController() @@ -58,30 +60,20 @@ void LumatoneController::connectionStateChanged(ConnectionState newState) //statusListeners.call(&LumatoneEditor::StatusListener::connectionStateChanged, newState); } -juce::Array LumatoneController::getMidiInputList() -{ - return firmwareDriver.getMidiInputList(); -} -juce::Array LumatoneController::getMidiOutputList() -{ - return firmwareDriver.getMidiOutputList(); -} +// int LumatoneController::getMidiInputIndex() const +// { +// return firmwareDriver.getMidiInputIndex(); +// } -int LumatoneController::getMidiInputIndex() const -{ - return firmwareDriver.getMidiInputIndex(); -} - -int LumatoneController::getMidiOutputIndex() const -{ - return firmwareDriver.getMidiOutputIndex(); -} +// int LumatoneController::getMidiOutputIndex() const +// { +// return firmwareDriver.getMidiOutputIndex(); +// } -void LumatoneController::setMidiInput(int deviceIndex, bool test) +void LumatoneController::setDriverMidiInput(int deviceIndex, bool test) { const bool changed = firmwareDriver.getMidiInputIndex() != deviceIndex; - firmwareDriver.setMidiInput(deviceIndex); if (changed) @@ -91,7 +83,7 @@ void LumatoneController::setMidiInput(int deviceIndex, bool test) testCurrentDeviceConnection(); } -void LumatoneController::setMidiOutput(int deviceIndex, bool test) +void LumatoneController::setDriverMidiOutput(int deviceIndex, bool test) { const bool changed = firmwareDriver.getMidiOutputIndex() != deviceIndex; @@ -104,25 +96,6 @@ void LumatoneController::setMidiOutput(int deviceIndex, bool test) testCurrentDeviceConnection(); } -bool LumatoneController::performAction(LumatoneAction* action, bool undoable, bool newTransaction) -{ - if (action == nullptr) - return false; - - if (undoable) - { - if (undoManager == nullptr) - return false; - - if (newTransaction) - undoManager->beginNewTransaction(); - - return undoManager->perform((juce::UndoableAction*)action, action->getName()); - } - - return action->perform(); -} - /* ============================================================================== Combined (hi-level) commands @@ -222,7 +195,7 @@ unsigned int LumatoneController::sendTestMessageToDevice(int deviceIndex, unsign } // lastTestDeviceSent = deviceIndex; - waitingForTestResponse = true; + checkingDeviceIsLumatone = true; return value; } @@ -232,7 +205,7 @@ void LumatoneController::testCurrentDeviceConnection() // On confirmed connection send connection listener message if (firmwareDriver.hasDevicesDefined()) { - waitingForTestResponse = true; + checkingDeviceIsLumatone = true; if (getSerialNumber().isNotEmpty() && getLumatoneVersion() >= LumatoneFirmware::ReleaseVersion::VERSION_1_0_9) { @@ -241,7 +214,7 @@ void LumatoneController::testCurrentDeviceConnection() else { - sendGetSerialIdentityRequest(true); + sendGetSerialIdentityRequest(); } } else @@ -341,14 +314,14 @@ void LumatoneController::sendKeyColourConfig(int boardId, int keyIndex, const Lu // Send expression pedal sensivity void LumatoneController::sendExpressionPedalSensivity(unsigned char value) { - setExpressionSensitivity(value); + LumatoneState::setExpressionSensitivity(value); firmwareDriver.sendExpressionPedalSensivity(value); } // Send parametrization of foot controller void LumatoneController::sendInvertFootController(bool value) { - setInvertExpression(value); + LumatoneState::setInvertExpression(value); firmwareDriver.sendInvertFootController(value); } @@ -486,9 +459,8 @@ void LumatoneController::getFaderTypeConfig(int boardIndex) } // This command is used to read back the serial identification number of the keyboard. -void LumatoneController::sendGetSerialIdentityRequest(bool confirmConnectionAfterResponse) +void LumatoneController::sendGetSerialIdentityRequest() { - waitingForTestResponse = confirmConnectionAfterResponse; firmwareDriver.sendGetSerialIdentityRequest(); } @@ -550,7 +522,7 @@ void LumatoneController::getPeripheralChannels() void LumatoneController::invertSustainPedal(bool setInverted) { - setInvertSustain(setInverted); + LumatoneState::setInvertSustain(setInverted); if (firmwareSupport.versionAcknowledgesCommand(getLumatoneVersion(), INVERT_SUSTAIN_PEDAL)) firmwareDriver.sendInvertSustainPedal(setInverted); @@ -591,21 +563,23 @@ bool LumatoneController::connectionConfirmed() const void LumatoneController::onConnectionConfirmed() { - waitingForTestResponse = false; + checkingDeviceIsLumatone = false; currentDevicePairConfirmed = true; - waitingForFirmwareVersion = true; - + if (getSerialNumber().isEmpty()) { - sendGetSerialIdentityRequest(true); - return; // a bit of a kludge + waitingForFirmwareVersion = true; + sendGetSerialIdentityRequest(); } else if (getSerialNumber() != SERIAL_55_KEYS) { + waitingForFirmwareVersion = true; sendGetFirmwareRevisionRequest(); } - - setConnectionState(ConnectionState::ONLINE); + else + { + waitingForFirmwareVersion = false; + } } void LumatoneController::handleStatePropertyChange(juce::ValueTree stateIn, const juce::Identifier &property) @@ -615,7 +589,6 @@ void LumatoneController::handleStatePropertyChange(juce::ValueTree stateIn, cons if (waitingForFirmwareVersion && property == LumatoneStateProperty::LastConnectedFirmwareVersion) { waitingForFirmwareVersion = false; - sendGetCompleteMappingRequest(); } } @@ -628,38 +601,52 @@ void LumatoneController::serialIdentityReceived(const int* serialBytes) setConnectedSerialNumber(serialNumber); - if (waitingForTestResponse) + if (checkingDeviceIsLumatone) { if (serialNumber != SERIAL_55_KEYS) sendGetFirmwareRevisionRequest(); else onConnectionConfirmed(); + + setConnectionState(ConnectionState::ONLINE); + } + + if (waitingForFirmwareVersion) + { + sendGetFirmwareRevisionRequest(); } } void LumatoneController::firmwareRevisionReceived(LumatoneFirmware::Version version) { // setFirmwareVersion(version, true); + waitingForFirmwareVersion = false; - if (waitingForTestResponse) + if (checkingDeviceIsLumatone) + { onConnectionConfirmed(); + setConnectionState(ConnectionState::ONLINE); + } } void LumatoneController::pingResponseReceived(unsigned int pingValue) { - if (waitingForTestResponse) + if (checkingDeviceIsLumatone) + { onConnectionConfirmed(); + setConnectionState(ConnectionState::ONLINE); + } } void LumatoneController::octaveColourConfigReceived(int boardId, juce::uint8 rgbFlag, const int* colourData) { - LumatoneBoard editedBoard = getBoard(boardId - 1); + int boardIndex = boardId - 1; for (int keyIndex = 0; keyIndex < getOctaveBoardSize(); keyIndex++) { auto newValue = colourData[keyIndex]; - juce::Colour colour = editedBoard.getKey(keyIndex).getColour(); + juce::Colour colour = getKey(boardIndex, keyIndex).getColour(); if (rgbFlag == 0) { colour = juce::Colour(newValue, colour.getGreen(), colour.getBlue()); @@ -677,16 +664,15 @@ void LumatoneController::octaveColourConfigReceived(int boardId, juce::uint8 rgb jassertfalse; } - editedBoard.setKeyColour(colour, keyIndex); + LumatoneState::setKeyColour(colour, boardId, keyIndex); } - LumatoneState::setBoard(editedBoard, boardId); - getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, editedBoard); + getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, getBoard(boardIndex)); } void LumatoneController::octaveChannelConfigReceived(int boardId, const int* channelData) { - LumatoneBoard editedBoard = getBoard(boardId - 1); + int boardIndex = boardId - 1; for (int keyIndex = 0; keyIndex < getOctaveBoardSize(); keyIndex++) { @@ -694,18 +680,17 @@ void LumatoneController::octaveChannelConfigReceived(int boardId, const int* cha if (ch == 0 || ch > 16) ch = 1; - auto key = editedBoard.getKey(keyIndex); + auto key = getKey(boardIndex, keyIndex); key.setChannelNumber(ch); - editedBoard.setKeyConfig(key, keyIndex); + LumatoneState::setKeyConfig(key, boardId, keyIndex); } - LumatoneState::setBoard(editedBoard, boardId); - getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, editedBoard); + getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, getBoard(boardIndex)); } void LumatoneController::octaveNoteConfigReceived(int boardId, const int* noteData) { - LumatoneBoard editedBoard = getBoard(boardId - 1); + int boardIndex = boardId - 1; for (int keyIndex = 0; keyIndex < getOctaveBoardSize(); keyIndex++) { @@ -713,30 +698,28 @@ void LumatoneController::octaveNoteConfigReceived(int boardId, const int* noteDa if (note < 0 || note > 127) note = 0; - auto key = editedBoard.getKey(keyIndex); + auto key = getKey(boardIndex, keyIndex); key.setNoteOrCC(noteData[keyIndex]); - editedBoard.setKeyConfig(key, keyIndex); + LumatoneState::setKeyConfig(key, boardId, keyIndex); } - LumatoneState::setBoard(editedBoard, boardId); - getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, editedBoard); + getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, getBoard(boardIndex)); } void LumatoneController::keyTypeConfigReceived(int boardId, const int* keyTypeData) { - LumatoneBoard editedBoard = getBoard(boardId - 1); + int boardIndex = boardId - 1; for (int keyIndex = 0; keyIndex < getOctaveBoardSize(); keyIndex++) { auto type = LumatoneKeyType(keyTypeData[keyIndex]); - auto key = editedBoard.getKey(keyIndex); + auto key = getKey(boardIndex, keyIndex); key.setKeyType(type); - editedBoard.setKeyConfig(key, keyIndex); + LumatoneState::setKeyConfig(key, boardId, keyIndex); } - LumatoneState::setBoard(editedBoard, boardId); - getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, editedBoard); + getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, getBoard(boardIndex)); } void LumatoneController::macroButtonColoursReceived(juce::Colour inactiveColour, juce::Colour activeColour) diff --git a/Source/lumatone_editor_library/device/lumatone_controller.h b/Source/lumatone_editor_library/device/lumatone_controller.h index 4f42b18..0009c96 100644 --- a/Source/lumatone_editor_library/device/lumatone_controller.h +++ b/Source/lumatone_editor_library/device/lumatone_controller.h @@ -26,7 +26,8 @@ class LumatoneAction; // Helper class for parsing and comparing (todo) firmware versions -class LumatoneController : private LumatoneApplicationStateController +class LumatoneController : private LumatoneApplicationState + , private LumatoneApplicationState::DeviceController , public LumatoneApplicationMidiController , public LumatoneEditor::StatusListener , protected LumatoneEditor::FirmwareListener @@ -39,22 +40,11 @@ class LumatoneController : private LumatoneApplicationStateController juce::ValueTree loadStateProperties(juce::ValueTree stateIn) override; - // void setContext(const LumatoneContext& contextIn) override; - // void clearContext() override; - //============================================================================ // Methods to configure firmware communication parameters - const FirmwareSupport& getFirmwareSupport() const { return firmwareSupport; } - - juce::Array getMidiInputList(); - juce::Array getMidiOutputList(); - - int getMidiInputIndex() const; - int getMidiOutputIndex() const; - - void setMidiInput(int deviceIndex, bool test = true); - void setMidiOutput(int deviceIndex, bool test = true); + void setDriverMidiInput(int deviceIndex, bool test = true); + void setDriverMidiOutput(int deviceIndex, bool test = true); bool connectionConfirmed() const; private: @@ -175,7 +165,7 @@ class LumatoneController : private LumatoneApplicationStateController void getFaderTypeConfig(int boardIndex); // This command is used to read back the serial identification number of the keyboard. - void sendGetSerialIdentityRequest(bool confirmConnectionAfterResponse); + void sendGetSerialIdentityRequest(); void startCalibrateKeys(); @@ -211,12 +201,6 @@ class LumatoneController : private LumatoneApplicationStateController // Get sensitivity setting of expression pedal void requestExpressionPedalSensitivity(); -public: - - bool performAction(LumatoneAction* action, bool undoable=true, bool newTransaction=true); - - // bool loadLayoutFromFile(const juce::File& file) override; - private: // juce::ValueTree::Listener implementation @@ -245,15 +229,14 @@ class LumatoneController : private LumatoneApplicationStateController //void loadRandomMapping(int testTimeoutMs, int maxIterations, int i = 0); private: - LumatoneFirmwareDriver& firmwareDriver; LumatoneKeyUpdateBuffer updateBuffer; std::unique_ptr eventManager; - bool waitingForTestResponse = false; + bool checkingDeviceIsLumatone = false; bool currentDevicePairConfirmed = false; bool waitingForFirmwareVersion = false; }; -#endif LUMATONE_CONTROLLER_H +#endif // LUMATONE_CONTROLLER_H diff --git a/Source/lumatone_editor_library/device/lumatone_event_manager.cpp b/Source/lumatone_editor_library/device/lumatone_event_manager.cpp index c32cee0..ea810e1 100644 --- a/Source/lumatone_editor_library/device/lumatone_event_manager.cpp +++ b/Source/lumatone_editor_library/device/lumatone_event_manager.cpp @@ -233,7 +233,18 @@ FirmwareSupport::Error LumatoneEventManager::handleFirmwareRevisionResponse(cons return errorCode; auto version = LumatoneFirmware::Version(major, minor, revision); - setLumatoneVersion(getFirmwareSupport().getReleaseVersion(version), true); + auto releaseVersion = getFirmwareSupport().getReleaseVersion(version); + switch (releaseVersion) + { + case LumatoneFirmware::ReleaseVersion::VERSION_55_KEYS: + mappingData->setOctaveBoardSize(55); + break; + default: + mappingData->setOctaveBoardSize(56); + break; + } + + setLumatoneVersion(releaseVersion, true); DBG("Firmware version is: " + version.toString()); firmwareListeners.call(&LumatoneEditor::FirmwareListener::firmwareRevisionReceived, version); From c9bab276662382f4690014034c40bfaa74d482cb Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Sat, 20 Jan 2024 01:28:29 -0500 Subject: [PATCH 08/19] use modelled black as default transparent color in model --- Source/lumatone_editor_library/color/colour_model.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/lumatone_editor_library/color/colour_model.cpp b/Source/lumatone_editor_library/color/colour_model.cpp index f37e6d7..6e46626 100644 --- a/Source/lumatone_editor_library/color/colour_model.cpp +++ b/Source/lumatone_editor_library/color/colour_model.cpp @@ -24,7 +24,7 @@ LumatoneColourModel::~LumatoneColourModel() juce::Colour LumatoneColourModel::getModelColour(juce::Colour colour) { if (colour.isTransparent()) - return juce::Colour(); + colour = juce::Colours::black; LumatoneEditor::ColourHash hash = LumatoneEditor::getColourHash(colour); auto cached = (*cache)[hash]; From 230b13dd011d5e5db616bc8ffe0698eb21b1caf5 Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Sat, 20 Jan 2024 01:31:46 -0500 Subject: [PATCH 09/19] fix some data structure bugs --- .../data/lumatone_board.cpp | 3 +-- .../lumatone_editor_library/data/lumatone_key.cpp | 14 +++++++------- .../data/lumatone_layout.cpp | 4 ++++ 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Source/lumatone_editor_library/data/lumatone_board.cpp b/Source/lumatone_editor_library/data/lumatone_board.cpp index 7269239..58eda4a 100644 --- a/Source/lumatone_editor_library/data/lumatone_board.cpp +++ b/Source/lumatone_editor_library/data/lumatone_board.cpp @@ -48,8 +48,7 @@ LumatoneBoard::LumatoneBoard(juce::ValueTree stateIn) void LumatoneBoard::operator=(const LumatoneBoard& copyBoard) { numKeys = copyBoard.numKeys; - state.copyPropertiesAndChildrenFrom(copyBoard.state, nullptr); - + for (int i = 0; i < numKeys; i++) { theKeys[i] = copyBoard.getKey(i); diff --git a/Source/lumatone_editor_library/data/lumatone_key.cpp b/Source/lumatone_editor_library/data/lumatone_key.cpp index f4b7f99..12ff4fc 100644 --- a/Source/lumatone_editor_library/data/lumatone_key.cpp +++ b/Source/lumatone_editor_library/data/lumatone_key.cpp @@ -119,13 +119,13 @@ juce::ValueTree LumatoneKey::getState() const void LumatoneKey::updateState() { - juce::ValueTree newState(LumatoneKeyProperty::State); - newState.setProperty(LumatoneKeyProperty::Type, keyType, nullptr); - newState.setProperty(LumatoneKeyProperty::Colour, colour.toString(), nullptr); - newState.setProperty(LumatoneKeyProperty::MidiNote, noteNumber, nullptr); - newState.setProperty(LumatoneKeyProperty::MidiChnl, channelNumber, nullptr); - newState.setProperty(LumatoneKeyProperty::DefaultCCFader, ccFaderDefault, nullptr); - state.copyPropertiesFrom(newState, nullptr); + // juce::ValueTree newState(LumatoneKeyProperty::State); + state.setProperty(LumatoneKeyProperty::Type, keyType, nullptr); + state.setProperty(LumatoneKeyProperty::Colour, colour.toString(), nullptr); + state.setProperty(LumatoneKeyProperty::MidiNote, noteNumber, nullptr); + state.setProperty(LumatoneKeyProperty::MidiChnl, channelNumber, nullptr); + state.setProperty(LumatoneKeyProperty::DefaultCCFader, ccFaderDefault, nullptr); + // state.copyPropertiesFrom(newState, nullptr); } void LumatoneKey::refreshFromState() diff --git a/Source/lumatone_editor_library/data/lumatone_layout.cpp b/Source/lumatone_editor_library/data/lumatone_layout.cpp index 9698a16..bc93a6d 100644 --- a/Source/lumatone_editor_library/data/lumatone_layout.cpp +++ b/Source/lumatone_editor_library/data/lumatone_layout.cpp @@ -213,6 +213,10 @@ LumatoneLayout::LumatoneLayout(int numBoardsIn, int octaveBoardSizeIn, bool init , octaveBoardSize(octaveBoardSizeIn) { state = juce::ValueTree(LumatoneConfigProperty::State); + + for (int i = 0; i < numBoards; i++) + boards[i].board_idx = i; + clearAll(initWithNotes); } From 7996b40c9dcde338a885bdda596040bbeeed0781 Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Sat, 20 Jan 2024 01:44:33 -0500 Subject: [PATCH 10/19] optimize layout change messages, fix key gfx update issues --- .../listeners/editor_listener.h | 8 ++--- .../ui/key_component.cpp | 35 +++++-------------- .../ui/key_component.h | 9 ++--- .../ui/keyboard_component.cpp | 28 +++++++-------- .../ui/keyboard_component.h | 10 +++--- 5 files changed, 32 insertions(+), 58 deletions(-) diff --git a/Source/lumatone_editor_library/listeners/editor_listener.h b/Source/lumatone_editor_library/listeners/editor_listener.h index 32b9183..6f5c857 100644 --- a/Source/lumatone_editor_library/listeners/editor_listener.h +++ b/Source/lumatone_editor_library/listeners/editor_listener.h @@ -14,9 +14,9 @@ class EditorListener virtual ~EditorListener() {} // App Actions - virtual void completeMappingLoaded(LumatoneLayout mappingData) {} - virtual void boardChanged(LumatoneBoard boardData) {} - virtual void keyChanged(int boardIndex, int keyIndex, LumatoneKey lumatoneKey) {} + virtual void completeMappingLoaded(const LumatoneLayout& mappingData) {} + virtual void boardChanged(const LumatoneBoard& boardData) {} + virtual void keyChanged(int boardIndex, int keyIndex, const LumatoneKey& lumatoneKey) {} virtual void selectionChanged(juce::Array selection) {} @@ -28,7 +28,7 @@ class EditorListener // Firmware Actions - virtual void keyConfigChanged(int boardIndex, int keyIndex, LumatoneKey keyData) {} + virtual void keyConfigChanged(int boardIndex, int keyIndex, const LumatoneKey& keyData) {} virtual void keyColourChanged(int boardIndex, int keyIndex, juce::Colour keyColour) {} virtual void expressionPedalSensitivityChanged(unsigned char value) {} diff --git a/Source/lumatone_editor_library/ui/key_component.cpp b/Source/lumatone_editor_library/ui/key_component.cpp index 7bc40e6..5056cc2 100644 --- a/Source/lumatone_editor_library/ui/key_component.cpp +++ b/Source/lumatone_editor_library/ui/key_component.cpp @@ -16,6 +16,9 @@ LumatoneKeyDisplay::LumatoneKeyDisplay(int newBoardIndex, int newKeyIndex, const : LumatoneKeyContext(keyDataIn, newBoardIndex, newKeyIndex) , Component("LumatoneKeyDisplay_" + LumatoneKeyCoord::toString(newBoardIndex, newKeyIndex)) { + boardIndex = newBoardIndex; + keyIndex = newKeyIndex; + renderMode = LumatoneComponentRenderMode::GraphicInteractive; clearUiState(); } @@ -218,38 +221,18 @@ void LumatoneKeyDisplay::endDrag() } } -// const LumatoneKey* LumatoneKeyDisplay::getKeyData() const -// { -// return &keyData; -// } - -// juce::Colour LumatoneKeyDisplay::getKeyColour() const -// { - -// } - -void LumatoneKeyDisplay::setLumatoneKey(const LumatoneKey& lumatoneKey, int boardIdx, int keyIdx) -{ - auto thisKey = static_cast(this); - *thisKey = lumatoneKey; - - boardIndex = boardIdx; - keyIndex = keyIdx; - // repaint(); -} - -void LumatoneKeyDisplay::setDisplayColour(const juce::Colour& colourIn) -{ - LumatoneKey::setColour(colourIn); - // redrawRender(); -} - void LumatoneKeyDisplay::setKeyGraphics(juce::Image& colourGraphicIn, juce::Image& shadowGraphicIn) { colourGraphic = colourGraphicIn; shadowGraphic = shadowGraphicIn; } +void LumatoneKeyDisplay::setLumatoneKey(const LumatoneKey &lumatoneKey, juce::Colour displayColour) +{ + LumatoneKey::operator=(lumatoneKey); + LumatoneKey::setColour(displayColour); +} + void LumatoneKeyDisplay::setSelected(bool selected) { isSelected = selected; diff --git a/Source/lumatone_editor_library/ui/key_component.h b/Source/lumatone_editor_library/ui/key_component.h index 0804014..acbb49e 100644 --- a/Source/lumatone_editor_library/ui/key_component.h +++ b/Source/lumatone_editor_library/ui/key_component.h @@ -43,7 +43,7 @@ class LumatoneKeyDisplay : public LumatoneKeyContext, public: LumatoneKeyDisplay(int newBoardIndex, int newKeyIndex, const LumatoneKey& keyData=LumatoneKey()); - ~LumatoneKeyDisplay(); + ~LumatoneKeyDisplay() override; LumatoneComponentRenderMode getRenderMode() const { return renderMode; } void setRenderMode(LumatoneComponentRenderMode uiModeIn); @@ -53,12 +53,7 @@ class LumatoneKeyDisplay : public LumatoneKeyContext, void setKeyGraphics(juce::Image& colourGraphicIn, juce::Image& shadowGraphicIn); - void setLumatoneKey(const LumatoneKey& lumatoneKey, int boardIdx, int keyIdx); - - void setDisplayColour(const juce::Colour& colour); - - // const LumatoneKey* getKeyData() const; - // juce::Colour getKeyColour() const; + void setLumatoneKey(const LumatoneKey& lumatoneKey, juce::Colour displayColour); int getBoardIndex() const { return boardIndex; } int getKeyIndex() const { return keyIndex; } diff --git a/Source/lumatone_editor_library/ui/keyboard_component.cpp b/Source/lumatone_editor_library/ui/keyboard_component.cpp index c8b92c0..9a654ef 100644 --- a/Source/lumatone_editor_library/ui/keyboard_component.cpp +++ b/Source/lumatone_editor_library/ui/keyboard_component.cpp @@ -189,7 +189,7 @@ void LumatoneKeyboardComponent::setUiMode(LumatoneKeyboardComponent::UiMode mode uiMode = modeIn; } -void LumatoneKeyboardComponent::completeMappingLoaded(LumatoneLayout mappingData) +void LumatoneKeyboardComponent::completeMappingLoaded(const LumatoneLayout& mappingData) { for (int boardIndex = 0; boardIndex < octaveBoards.size(); boardIndex++) { @@ -199,23 +199,20 @@ void LumatoneKeyboardComponent::completeMappingLoaded(LumatoneLayout mappingData { const LumatoneKey& keyData = mappingData.getKey(boardIndex, keyIndex); keyUpdateCallback(boardIndex, keyIndex, keyData, false); - } } resetLayoutState(&mappingData); } -void LumatoneKeyboardComponent::boardChanged(LumatoneBoard boardData) +void LumatoneKeyboardComponent::boardChanged(const LumatoneBoard& boardData) { - auto board = octaveBoards[boardData.getBoardIndex()]; + int boardIndex = boardData.getBoardIndex(); - for (int keyIndex = 0; keyIndex < getOctaveBoardSize(); keyIndex++) + for (int keyIndex = 0; keyIndex < octaveBoards[boardIndex]->keyMiniDisplay.size(); keyIndex++) { - auto key = board->keyMiniDisplay[keyIndex]; - const LumatoneKey& keyData = boardData.getKey(keyIndex); - keyUpdateCallback(boardData.getBoardIndex(), keyIndex, keyData, false); + keyUpdateCallback(boardIndex, keyIndex, keyData, false); } resetLayoutState(); @@ -230,12 +227,12 @@ void LumatoneKeyboardComponent::contextChanged(LumatoneContext *newOrEmptyContex // completeMappingLoaded(layout); } -void LumatoneKeyboardComponent::keyChanged(int boardIndex, int keyIndex, LumatoneKey lumatoneKey) +void LumatoneKeyboardComponent::keyChanged(int boardIndex, int keyIndex, const LumatoneKey& lumatoneKey) { keyUpdateCallback(boardIndex, keyIndex, lumatoneKey); } -void LumatoneKeyboardComponent::keyConfigChanged(int boardIndex, int keyIndex, LumatoneKey keyData) +void LumatoneKeyboardComponent::keyConfigChanged(int boardIndex, int keyIndex, const LumatoneKey& keyData) { keyUpdateCallback(boardIndex, keyIndex, keyData); } @@ -261,8 +258,7 @@ void LumatoneKeyboardComponent::keyUpdateCallback(int boardIndex, int keyIndex, { auto key = octaveBoards[boardIndex]->keyMiniDisplay[keyIndex]; - key->setLumatoneKey(newKey, boardIndex, keyIndex); - updateKeyColour(boardIndex, keyIndex, newKey.getColour()); + applyKeyUpdates(boardIndex, keyIndex, newKey); if (!doRepaint) return; @@ -292,7 +288,7 @@ void LumatoneKeyboardComponent::mappingUpdateCallback() if (currentWidth == 0 || currentHeight == 0) return; - resized(); + // resized(); repaint(lumatoneBounds); } @@ -303,11 +299,11 @@ void LumatoneKeyboardComponent::rerender() repaint(lumatoneBounds); } -void LumatoneKeyboardComponent::updateKeyColour(int boardIndex, int keyIndex, const juce::Colour& colour) +void LumatoneKeyboardComponent::applyKeyUpdates(int boardIndex, int keyIndex, const LumatoneKey& keyData) { - auto modelColour = getColourModel()->getModelColour(colour); + auto modelColour = getColourModel()->getModelColour(keyData.getColour()); auto key = octaveBoards[boardIndex]->keyMiniDisplay[keyIndex]; - key->setDisplayColour(modelColour); + key->setLumatoneKey(keyData, modelColour); } void LumatoneKeyboardComponent::resetLayoutState(const LumatoneLayout* optionalLayout) diff --git a/Source/lumatone_editor_library/ui/keyboard_component.h b/Source/lumatone_editor_library/ui/keyboard_component.h index 8d54351..c9a41fc 100644 --- a/Source/lumatone_editor_library/ui/keyboard_component.h +++ b/Source/lumatone_editor_library/ui/keyboard_component.h @@ -80,16 +80,16 @@ class LumatoneKeyboardComponent : public juce::Component, public: // LumatoneEditor::EditorListener Implementation - void completeMappingLoaded(LumatoneLayout mappingData) override; - void boardChanged(LumatoneBoard boardData) override; + void completeMappingLoaded(const LumatoneLayout& mappingData) override; + void boardChanged(const LumatoneBoard& boardData) override; void contextChanged(LumatoneContext* newOrEmptyContext) override; - void keyChanged(int boardIndex, int keyIndex, LumatoneKey lumatoneKey) override; - void keyConfigChanged(int boardIndex, int keyIndex, LumatoneKey keyData) override; + void keyChanged(int boardIndex, int keyIndex, const LumatoneKey& lumatoneKey) override; + void keyConfigChanged(int boardIndex, int keyIndex, const LumatoneKey& keyData) override; void keyColourChanged(int octaveNumber, int keyNumber, juce::Colour keyColour) override; void selectionChanged(juce::Array selection) override; private: - void updateKeyColour(int boardIndex, int keyIndex, const juce::Colour& colour); + void applyKeyUpdates(int boardIndex, int keyIndex, const LumatoneKey& keyData); void resetLayoutState(const LumatoneLayout* optionalLayout=nullptr); void keyUpdateCallback(int boardIndex, int keyIndex, const LumatoneKey& keyData, bool doRepaint=true); From 5de6bd6c7154db3cfc3440acf2f361ef07a6af60 Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Sat, 20 Jan 2024 01:44:49 -0500 Subject: [PATCH 11/19] translate sysex debug messages --- .../lumatone_midi_driver/lumatone_midi_driver.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Source/lumatone_editor_library/lumatone_midi_driver/lumatone_midi_driver.cpp b/Source/lumatone_editor_library/lumatone_midi_driver/lumatone_midi_driver.cpp index f2c8d1f..8db80b9 100644 --- a/Source/lumatone_editor_library/lumatone_midi_driver/lumatone_midi_driver.cpp +++ b/Source/lumatone_editor_library/lumatone_midi_driver/lumatone_midi_driver.cpp @@ -885,7 +885,13 @@ void LumatoneFirmwareDriver::sendCurrentMessage() sendMessageNow(currentMsgWaitingForAck); // send it // Notify listeners - DBG("SENT: " + currentMsgWaitingForAck.getDescription()); + #if JUCE_DEBUG + { + juce::String msg = "SENT: " + FirmwareSupport::getCommandDescription(currentMsgWaitingForAck); + // DBG("SENT: " + currentMsgWaitingForAck.getDescription()); + DBG(msg); + } + #endif // const juce::MessageManagerLock mmLock; // this->listeners.call(&Listener::midiMessageSent, currentMsgWaitingForAck); // notifyMessageSent(midiOutput, currentMsgWaitingForAck); @@ -899,10 +905,11 @@ void LumatoneFirmwareDriver::handleIncomingMidiMessage(juce::MidiInput* source, #if JUCE_DEBUG if (message.isSysEx()) { + auto msg = "RCVD: " + FirmwareSupport::getCommandDescription(message); if (source) - DBG("RCVD: " + message.getDescription() + "; from " + source->getName()); + DBG(msg + "; from " + source->getName()); else - DBG("RCVD: " + message.getDescription() + "; called by processor"); + DBG(msg + "; called by processor"); } if (!message.isSysEx() && !message.isMidiClock()) { From e287c115deba6d668d4f7d91299d2dcc6adefb21 Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Sun, 21 Jan 2024 02:07:19 -0500 Subject: [PATCH 12/19] implement get macro led intensity command --- .../lumatone_midi_driver/firmware_sysex.cpp | 35 +++++++++++++++++-- .../lumatone_midi_driver/firmware_sysex.h | 9 ++++- .../lumatone_midi_driver.cpp | 5 +++ .../lumatone_midi_driver.h | 3 ++ 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/Source/lumatone_editor_library/lumatone_midi_driver/firmware_sysex.cpp b/Source/lumatone_editor_library/lumatone_midi_driver/firmware_sysex.cpp index f1b0001..d39cebe 100644 --- a/Source/lumatone_editor_library/lumatone_midi_driver/firmware_sysex.cpp +++ b/Source/lumatone_editor_library/lumatone_midi_driver/firmware_sysex.cpp @@ -90,9 +90,16 @@ juce::MidiMessage LumatoneSysEx::createTableSysEx(juce::uint8 boardIndex, juce:: return msg; } +juce::Colour LumatoneSysEx::parseLedIntensity8Bit(const juce::uint8 *data) +{ + return juce::Colour::fromRGB( + *data << 4 | *(data + 1), + *(data + 3) << 4 | *(data + 2), + *(data + 5) << 4 | *(data + 4) + ); +} -// Checks if message is a valid Lumatone firmware response and is expected length, then runs supplied unpacking function or returns an error code -FirmwareSupport::Error LumatoneSysEx::unpackIfValid(const juce::MidiMessage& response, size_t numBytes, std::function unpackFunction) +FirmwareSupport::Error LumatoneSysEx::isValid(const juce::MidiMessage &response, size_t numBytes) { auto status = messageIsValidLumatoneResponse(response); if (status != FirmwareSupport::Error::noError) @@ -102,6 +109,16 @@ FirmwareSupport::Error LumatoneSysEx::unpackIfValid(const juce::MidiMessage& res if (status != FirmwareSupport::Error::noError) return status; + return FirmwareSupport::Error::noError; +} + +// Checks if message is a valid Lumatone firmware response and is expected length, then runs supplied unpacking function or returns an error code +FirmwareSupport::Error LumatoneSysEx::unpackIfValid(const juce::MidiMessage& response, size_t numBytes, std::function unpackFunction) +{ + auto status = isValid(response, numBytes); + if (status != FirmwareSupport::Error::noError) + return status; + return unpackFunction(&response.getSysExData()[PAYLOAD_INIT]); } @@ -185,6 +202,7 @@ FirmwareSupport::Error LumatoneSysEx::unpack12BitDataFrom4Bit(const juce::MidiMe return unpackIfValid(msg, numBytes, unpack); } + bool LumatoneSysEx::messageIsResponseToMessage(const juce::MidiMessage& answer, const juce::MidiMessage& originalMessage) { // Only for SysEx messages @@ -635,3 +653,16 @@ FirmwareSupport::Error LumatoneSysEx::unpackGetExpressionPedalSensitivityRespons return status; } + +FirmwareSupport::Error LumatoneSysEx::unpackGetMacroLightIntensityResponse(const juce::MidiMessage &response, juce::Colour &activeColour, juce::Colour &inactiveColour) +{ + auto status = isValid(response, 12); + if (status != FirmwareSupport::Error::noError) + return status; + + const juce::uint8* payload = &response.getSysExData()[PAYLOAD_INIT]; + activeColour = parseLedIntensity8Bit(payload); + inactiveColour = parseLedIntensity8Bit(payload + 6); + + return FirmwareSupport::Error::noError; +} diff --git a/Source/lumatone_editor_library/lumatone_midi_driver/firmware_sysex.h b/Source/lumatone_editor_library/lumatone_midi_driver/firmware_sysex.h index ad80c17..597b6d5 100644 --- a/Source/lumatone_editor_library/lumatone_midi_driver/firmware_sysex.h +++ b/Source/lumatone_editor_library/lumatone_midi_driver/firmware_sysex.h @@ -34,8 +34,13 @@ static juce::MidiMessage createExtendedMacroColourSysEx(juce::uint8 cmd, int red // Create a SysEx message encoding a table with a defined size static juce::MidiMessage createTableSysEx(juce::uint8 boardIndex, juce::uint8 cmd, juce::uint8 tableSize, const juce::uint8 table[]); +// Returns colour parsed from 6 nibbles of RGB LED intensity data +static juce::Colour parseLedIntensity8Bit(const juce::uint8* data); -// Checks if message is a valid Lumatone firmware response and is expected length, then runs supplied unpacking function or returns an error code +// Checks if message is a valid Lumatone firmware response and is expected length, +static FirmwareSupport::Error isValid(const juce::MidiMessage& response, size_t numBytes); + +// Checks message validity, then runs supplied unpacking function or returns an error code static FirmwareSupport::Error unpackIfValid(const juce::MidiMessage& response, size_t numBytes, std::function unpackFunction); // Generic unpacking of octave data from a SysEx message @@ -157,6 +162,8 @@ static FirmwareSupport::Error unpackGetPresetFlagsResponse(const juce::MidiMessa // For CMD 48h response: get expression pedal sensitivity static FirmwareSupport::Error unpackGetExpressionPedalSensitivityResponse(const juce::MidiMessage& response, int& sensitivity); +static FirmwareSupport::Error unpackGetMacroLightIntensityResponse(const juce::MidiMessage& response, juce::Colour& activeColour, juce::Colour& inactiveColour); + // Message is an answer to a sent message yes/no static bool messageIsResponseToMessage(const juce::MidiMessage& answer, const juce::MidiMessage& originalMessage); }; diff --git a/Source/lumatone_editor_library/lumatone_midi_driver/lumatone_midi_driver.cpp b/Source/lumatone_editor_library/lumatone_midi_driver/lumatone_midi_driver.cpp index 8db80b9..d8b5d67 100644 --- a/Source/lumatone_editor_library/lumatone_midi_driver/lumatone_midi_driver.cpp +++ b/Source/lumatone_editor_library/lumatone_midi_driver/lumatone_midi_driver.cpp @@ -742,6 +742,11 @@ void LumatoneFirmwareDriver::sendGetExpressionPedalSensitivity() sendSysExRequest(0, GET_EXPRESSION_PEDAL_SENSITIVIY); } +void LumatoneFirmwareDriver::sendGetMacroLightIntensity() +{ + sendSysExRequest(0, GET_MACRO_LIGHT_INTENSITY); +} + /* ============================================================================== Low-level SysEx calls diff --git a/Source/lumatone_editor_library/lumatone_midi_driver/lumatone_midi_driver.h b/Source/lumatone_editor_library/lumatone_midi_driver/lumatone_midi_driver.h index ffea6ab..157f1b1 100644 --- a/Source/lumatone_editor_library/lumatone_midi_driver/lumatone_midi_driver.h +++ b/Source/lumatone_editor_library/lumatone_midi_driver/lumatone_midi_driver.h @@ -343,6 +343,9 @@ class LumatoneFirmwareDriver : public HajuMidiDriver // For CMD 48h response: get expression pedal sensitivity void sendGetExpressionPedalSensitivity(); + + // For CMD 49h: Get Macro button colours + void sendGetMacroLightIntensity(); // TODO CMD 49h-4Eh From ce465ca81983caa0ad26e4d448abdbcedefe3361 Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Sun, 21 Jan 2024 02:09:06 -0500 Subject: [PATCH 13/19] move state response handling to event manager, implement get macro colour callbacks --- Source/GlobalSettingsArea.cpp | 54 +++---- Source/GlobalSettingsArea.h | 14 +- Source/MainComponent.cpp | 2 +- Source/colour_view_component.cpp | 5 +- Source/colour_view_component.h | 2 +- .../device/lumatone_controller.cpp | 117 +------------- .../device/lumatone_controller.h | 12 +- .../device/lumatone_event_manager.cpp | 145 +++++++++++++++++- .../device/lumatone_event_manager.h | 44 +++--- .../listeners/editor_listener.h | 2 +- 10 files changed, 211 insertions(+), 186 deletions(-) diff --git a/Source/GlobalSettingsArea.cpp b/Source/GlobalSettingsArea.cpp index 3bb0a76..601836d 100644 --- a/Source/GlobalSettingsArea.cpp +++ b/Source/GlobalSettingsArea.cpp @@ -22,7 +22,6 @@ #include "./Settings/SettingsContainer.h" -#include "./lumatone_editor_library/device/lumatone_controller.h" //[/Headers] #include "GlobalSettingsArea.h" @@ -76,10 +75,12 @@ GlobalSettingsArea::GlobalSettingsArea (const LumatoneEditorState& stateIn) activeMacroButtonColourEdit.reset(new ColourViewComponent()); addAndMakeVisible(activeMacroButtonColourEdit.get()); activeMacroButtonColourEdit->addChangeListener(this); + activeMacroButtonColourEdit->setColour(getActiveMacroButtonColour().toString(), false); inactiveMacroButtonColourEdit.reset(new ColourViewComponent()); addAndMakeVisible(inactiveMacroButtonColourEdit.get()); inactiveMacroButtonColourEdit->addChangeListener(this); + inactiveMacroButtonColourEdit->setColour(getInactiveMacroButtonColour().toString(), false); lblDeveloperMode.reset(new juce::Label("DeveloperModeLabel", "Developer Mode")); addChildComponent(lblDeveloperMode.get()); @@ -90,9 +91,18 @@ GlobalSettingsArea::GlobalSettingsArea (const LumatoneEditorState& stateIn) lblPresetButtonColours->setFont(getAppFonts().getFont(LumatoneEditorFont::UniviaProBold)); addStatusListener(this); + addEditorListener(this); settingsButton->setEnabled(false); + lblPresetButtonColours->setColour(Label::ColourIds::textColourId, getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::LabelPink)); + + lblColourActiveMacroButton->setColour(Label::ColourIds::textColourId, getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::DescriptionText)); + lblColourInactiveMacroButton->setColour(Label::ColourIds::textColourId, getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::DescriptionText)); + + settingsButton->setColour(TextButton::ColourIds::buttonColourId, Colour(0xff383b3d)); + settingsButton->setColour(TextButton::ColourIds::textColourOffId, Colour(0xffffffff)); + /* We don't want a resize here /* //[/UserPreSize] @@ -126,6 +136,16 @@ GlobalSettingsArea::~GlobalSettingsArea() //[/Destructor] } +void GlobalSettingsArea::macroButtonInactiveColourChanged(juce::Colour colour) +{ + inactiveMacroButtonColourEdit->setColour(colour.toString(), false); +} + +void GlobalSettingsArea::macroButtonActiveColourChanged(juce::Colour colour) +{ + activeMacroButtonColourEdit->setColour(colour.toString(), false); +} + //============================================================================== void GlobalSettingsArea::paint (juce::Graphics& g) { @@ -220,46 +240,18 @@ void GlobalSettingsArea::buttonClicked (juce::Button* buttonThatWasClicked) //[MiscUserCode] You can add your own definitions of your custom methods or any other code here... -void GlobalSettingsArea::lookAndFeelChanged() -{ - lblPresetButtonColours->setColour(Label::ColourIds::textColourId, getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::LabelPink)); - - lblColourActiveMacroButton->setColour(Label::ColourIds::textColourId, getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::DescriptionText)); - lblColourInactiveMacroButton->setColour(Label::ColourIds::textColourId, getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::DescriptionText)); - - settingsButton->setColour(TextButton::ColourIds::buttonColourId, Colour(0xff383b3d)); - settingsButton->setColour(TextButton::ColourIds::textColourOffId, Colour(0xffffffff)); -} - void GlobalSettingsArea::changeListenerCallback(ChangeBroadcaster *source) { if (source == inactiveMacroButtonColourEdit.get()) { - String inactiveMacroButtonColour = inactiveMacroButtonColourEdit->getColourAsString(); - getLumatoneController()->sendMacroButtonInactiveColour(inactiveMacroButtonColour); + setInactiveMacroButtonColour(inactiveMacroButtonColourEdit->getColourAsObject()); } else if (source == activeMacroButtonColourEdit.get()) { - String activeMacroButtonColour = activeMacroButtonColourEdit->getColourAsString(); - getLumatoneController()->sendMacroButtonActiveColour(activeMacroButtonColour); + setActiveMacroButtonColour(activeMacroButtonColourEdit->getColourAsObject()); } } -void GlobalSettingsArea::restoreStateFromPropertiesFile() -{ - inactiveMacroButtonColourEdit->setColour(getProperty(LumatoneEditorProperty::InactiveMacroButtonColour, "000000")); - activeMacroButtonColourEdit->setColour(getProperty(LumatoneEditorProperty::ActiveMacroButtonColour, "FFFFFF")); -} - -void GlobalSettingsArea::saveStateToPropertiesFile(PropertiesFile* propertiesFile) -{ - String inactiveMacroButtonColour = inactiveMacroButtonColourEdit->getColourAsString(); - propertiesFile->setValue(LumatoneEditorProperty::InactiveMacroButtonColour, inactiveMacroButtonColour); - - String activeMacroButtonColour = activeMacroButtonColourEdit->getColourAsString(); - propertiesFile->setValue(LumatoneEditorProperty::ActiveMacroButtonColour, activeMacroButtonColour); -} - void GlobalSettingsArea::listenToColourEditButtons(Button::Listener* listenerIn) { inactiveMacroButtonColourEdit->addListener(listenerIn); diff --git a/Source/GlobalSettingsArea.h b/Source/GlobalSettingsArea.h index 15a97ad..5109c48 100644 --- a/Source/GlobalSettingsArea.h +++ b/Source/GlobalSettingsArea.h @@ -25,6 +25,7 @@ #include "./LumatoneEditorState.h" #include "./lumatone_editor_library/listeners/status_listener.h" +#include "./lumatone_editor_library/listeners/editor_listener.h" #include "./colour_view_component.h" //[/Headers] @@ -43,6 +44,7 @@ class GlobalSettingsArea : public juce::Component, public LumatoneEditorState, public ChangeListener, public LumatoneEditor::StatusListener, + public LumatoneEditor::EditorListener, public juce::Button::Listener { public: @@ -54,18 +56,16 @@ class GlobalSettingsArea : public juce::Component, //[UserMethods] -- You can add your own custom methods in this section. void changeListenerCallback(ChangeBroadcaster *source) override; - void saveStateToPropertiesFile(PropertiesFile* propertiesFile); - void listenToColourEditButtons(Button::Listener* listenerIn); - void lookAndFeelChanged() override; - void setDeveloperMode(bool devModeOn); // LumatoneEditor::StatusListener implementation - // void connectionEstablished(int inputDevice, int outputDevice) override; void connectionStateChanged(ConnectionState newState) override; - // void connectionFailed() override; + + // LumatoneEditor::EditorListener implementation + void macroButtonInactiveColourChanged(juce::Colour colour) override; + void macroButtonActiveColourChanged(juce::Colour colour) override; //[/UserMethods] @@ -73,8 +73,6 @@ class GlobalSettingsArea : public juce::Component, void resized() override; void buttonClicked (juce::Button* buttonThatWasClicked) override; -private: - void restoreStateFromPropertiesFile(); private: //[UserVariables] -- You can add your own custom variables in this section. diff --git a/Source/MainComponent.cpp b/Source/MainComponent.cpp index 83791aa..fde8fb0 100644 --- a/Source/MainComponent.cpp +++ b/Source/MainComponent.cpp @@ -143,7 +143,7 @@ MainContentComponent::~MainContentComponent() void MainContentComponent::saveStateToPropertiesFile(PropertiesFile* propertiesFile) { noteEditArea->saveStateToPropertiesFile(propertiesFile); - globalSettingsArea->saveStateToPropertiesFile(propertiesFile); + // globalSettingsArea->saveStateToPropertiesFile(propertiesFile); } // Set the currentSectionKey mapping to be edited to the value passed in parameter diff --git a/Source/colour_view_component.cpp b/Source/colour_view_component.cpp index 37ac297..ffa7eb2 100644 --- a/Source/colour_view_component.cpp +++ b/Source/colour_view_component.cpp @@ -241,7 +241,7 @@ void ColourViewComponent::paintButton(juce::Graphics& g, bool shouldDrawButtonAs g.drawFittedText(getButtonText(), getLocalBounds(), juce::Justification::centred, 1); } -void ColourViewComponent::setColour(juce::String colourAsString) +void ColourViewComponent::setColour(juce::String colourAsString, bool sendChange) { //jassert(colourCombo != nullptr); @@ -254,7 +254,8 @@ void ColourViewComponent::setColour(juce::String colourAsString) repaint(); // Notify parent that value has changed and can be sent to MIDI controller - sendChangeMessage(); + if (sendChange) + sendChangeMessage(); } juce::String ColourViewComponent::getColourAsString() diff --git a/Source/colour_view_component.h b/Source/colour_view_component.h index 918eda5..29ffde9 100644 --- a/Source/colour_view_component.h +++ b/Source/colour_view_component.h @@ -94,7 +94,7 @@ class ColourViewComponent : public juce::Button, //[UserMethods] -- You can add your own custom methods in this section. //void changeListenerCallback(juce::ChangeBroadcaster *source) override; - void setColour(juce::String colourAsString); + void setColour(juce::String colourAsString, bool sendChangeMessage = true); juce::String getColourAsString(); int getColourAsNumber(); juce::Colour getColourAsObject(); diff --git a/Source/lumatone_editor_library/device/lumatone_controller.cpp b/Source/lumatone_editor_library/device/lumatone_controller.cpp index e47b1fa..b68d080 100644 --- a/Source/lumatone_editor_library/device/lumatone_controller.cpp +++ b/Source/lumatone_editor_library/device/lumatone_controller.cpp @@ -556,6 +556,12 @@ void LumatoneController::requestExpressionPedalSensitivity() firmwareDriver.sendGetExpressionPedalSensitivity(); } +void LumatoneController::requestMacroButtonColours() +{ + if (firmwareSupport.versionAcknowledgesCommand(getLumatoneVersion(), GET_MACRO_LIGHT_INTENSITY)) + firmwareDriver.sendGetMacroLightIntensity(); +} + bool LumatoneController::connectionConfirmed() const { return firmwareDriver.hasDevicesDefined() && currentDevicePairConfirmed; @@ -637,114 +643,3 @@ void LumatoneController::pingResponseReceived(unsigned int pingValue) setConnectionState(ConnectionState::ONLINE); } } - -void LumatoneController::octaveColourConfigReceived(int boardId, juce::uint8 rgbFlag, const int* colourData) -{ - int boardIndex = boardId - 1; - - for (int keyIndex = 0; keyIndex < getOctaveBoardSize(); keyIndex++) - { - auto newValue = colourData[keyIndex]; - - juce::Colour colour = getKey(boardIndex, keyIndex).getColour(); - if (rgbFlag == 0) - { - colour = juce::Colour(newValue, colour.getGreen(), colour.getBlue()); - } - else if (rgbFlag == 1) - { - colour = juce::Colour(colour.getRed(), newValue, colour.getBlue()); - } - else if (rgbFlag == 2) - { - colour = juce::Colour(colour.getRed(), colour.getGreen(), newValue); - } - else - { - jassertfalse; - } - - LumatoneState::setKeyColour(colour, boardId, keyIndex); - } - - getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, getBoard(boardIndex)); -} - -void LumatoneController::octaveChannelConfigReceived(int boardId, const int* channelData) -{ - int boardIndex = boardId - 1; - - for (int keyIndex = 0; keyIndex < getOctaveBoardSize(); keyIndex++) - { - juce::uint8 ch = channelData[keyIndex]; - if (ch == 0 || ch > 16) - ch = 1; - - auto key = getKey(boardIndex, keyIndex); - key.setChannelNumber(ch); - LumatoneState::setKeyConfig(key, boardId, keyIndex); - } - - getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, getBoard(boardIndex)); -} - -void LumatoneController::octaveNoteConfigReceived(int boardId, const int* noteData) -{ - int boardIndex = boardId - 1; - - for (int keyIndex = 0; keyIndex < getOctaveBoardSize(); keyIndex++) - { - int note = noteData[keyIndex]; - if (note < 0 || note > 127) - note = 0; - - auto key = getKey(boardIndex, keyIndex); - key.setNoteOrCC(noteData[keyIndex]); - LumatoneState::setKeyConfig(key, boardId, keyIndex); - } - - getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, getBoard(boardIndex)); -} - -void LumatoneController::keyTypeConfigReceived(int boardId, const int* keyTypeData) -{ - int boardIndex = boardId - 1; - - for (int keyIndex = 0; keyIndex < getOctaveBoardSize(); keyIndex++) - { - auto type = LumatoneKeyType(keyTypeData[keyIndex]); - - auto key = getKey(boardIndex, keyIndex); - key.setKeyType(type); - LumatoneState::setKeyConfig(key, boardId, keyIndex); - } - - getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, getBoard(boardIndex)); -} - -void LumatoneController::macroButtonColoursReceived(juce::Colour inactiveColour, juce::Colour activeColour) -{ - -} - -//void LumatoneController::loadRandomMapping(int testTimeoutMs, int maxIterations, int i) -//{ -// auto dir = juce::File::getSpecialLocation(juce::File::SpecialLocationType::userDocumentsDirectory).getChildFile("Lumatone Editor").getChildFile("Mappings"); -// auto mappings = dir.findChildFiles(juce::File::TypesOfFileToFind::findFiles, true); -// auto numfiles = mappings.size(); -// auto r = juce::Random(); -// -// auto fileIndex = r.nextInt(numfiles-1); -// auto file = mappings[fileIndex]; -// -// if (file.exists() && file.hasFileExtension(".ltn")) -// { -// DBG("Found " + juce::String(numfiles) + " files, loading " + file.getFileName()); -// juce::MessageManager::callAsync([file]() { TerpstraSysExApplication::getApp().setCurrentFile(file); }); -// } -// -//// if (i < maxIterations) -//// Timer::callAfterDelay(testTimeoutMs, [&]() { loadRandomMapping(testTimeoutMs, maxIterations, i + 1); }); -//// else -//// DBG("Finished random mappings test."); -//} diff --git a/Source/lumatone_editor_library/device/lumatone_controller.h b/Source/lumatone_editor_library/device/lumatone_controller.h index 0009c96..42156eb 100644 --- a/Source/lumatone_editor_library/device/lumatone_controller.h +++ b/Source/lumatone_editor_library/device/lumatone_controller.h @@ -201,6 +201,9 @@ class LumatoneController : private LumatoneApplicationState // Get sensitivity setting of expression pedal void requestExpressionPedalSensitivity(); + // Get preset button light colours + void requestMacroButtonColours(); + private: // juce::ValueTree::Listener implementation @@ -208,7 +211,7 @@ class LumatoneController : private LumatoneApplicationState protected: //============================================================================ - // LumatoneEditor::FirmwareListener implementation + // LumatoneEditor::FirmwareListener implementation - use to establish device connection void serialIdentityReceived(const int* serialBytes) override; @@ -216,13 +219,6 @@ class LumatoneController : private LumatoneApplicationState void pingResponseReceived(unsigned int pingValue) override; - void octaveColourConfigReceived(int boardId, juce::uint8 rgbFlag, const int* colourData) override; - void octaveChannelConfigReceived(int octaveIndex, const int* channelData) override; - void octaveNoteConfigReceived(int octaveIndex, const int* noteData) override; - void keyTypeConfigReceived(int boardId, const int* keyTypeData) override; - - void macroButtonColoursReceived(juce::Colour inactiveColour, juce::Colour activeColour) override; - //============================================================================ // Test functions diff --git a/Source/lumatone_editor_library/device/lumatone_event_manager.cpp b/Source/lumatone_editor_library/device/lumatone_event_manager.cpp index ea810e1..5b4c076 100644 --- a/Source/lumatone_editor_library/device/lumatone_event_manager.cpp +++ b/Source/lumatone_editor_library/device/lumatone_event_manager.cpp @@ -13,11 +13,15 @@ #include "../lumatone_midi_driver/lumatone_midi_driver.h" #include "../lumatone_midi_driver/firmware_sysex.h" -LumatoneEventManager::LumatoneEventManager(LumatoneFirmwareDriver& midiDriverIn, const LumatoneState& stateIn) - : LumatoneState(stateIn) +#include "../listeners/editor_listener.h" + +LumatoneEventManager::LumatoneEventManager(LumatoneFirmwareDriver& midiDriverIn, const LumatoneApplicationState& stateIn) + : LumatoneApplicationState("LumatoneEventManager", stateIn) + , LumatoneApplicationState::Controller(static_cast(*this)) , midiDriver(midiDriverIn) { midiDriver.addDriverListener(this); + addFirmwareListener(this); juce::MidiMessageCollector::reset(bufferReadTimeoutMs); } @@ -299,6 +303,11 @@ FirmwareSupport::Error LumatoneEventManager::handleGetPresetFlagsResponse(const presetFlags.sustainPedalInverted ); + mappingData->setLightOnKeyStrokes(presetFlags.polyphonicAftertouch); + mappingData->setAftertouchEnabled(presetFlags.polyphonicAftertouch); + mappingData->setInvertExpression(presetFlags.expressionPedalInverted); + mappingData->setInvertSustain(presetFlags.sustainPedalInverted); + firmwareListeners.call(&LumatoneEditor::FirmwareListener::presetFlagsReceived, presetFlags); return errorCode; @@ -309,11 +318,31 @@ FirmwareSupport::Error LumatoneEventManager::handleGetExpressionPedalSensitivity int sensitivity = 127; auto errorCode = LumatoneSysEx::unpackGetExpressionPedalSensitivityResponse(midiMessage, sensitivity); + mappingData->setExpressionSensitivity(sensitivity); + firmwareListeners.call(&LumatoneEditor::FirmwareListener::expressionPedalSensitivityReceived, sensitivity); return errorCode; } +FirmwareSupport::Error LumatoneEventManager::handleGetMacroLightIntensityResponse(const juce::MidiMessage &midiMessage) +{ + juce::Colour activeColour; + juce::Colour inactiveColour; + + auto errorCode = LumatoneSysEx::unpackGetMacroLightIntensityResponse(midiMessage, activeColour, inactiveColour); + if (errorCode != FirmwareSupport::Error::noError) + return errorCode; + + LumatoneState::setActiveMacroButtonColour(activeColour); + getEditorListeners()->call(&LumatoneEditor::EditorListener::macroButtonActiveColourChanged, activeColour); + + LumatoneState::setInactiveMacroButtonColour(inactiveColour); + getEditorListeners()->call(&LumatoneEditor::EditorListener::macroButtonInactiveColourChanged, inactiveColour); + + return FirmwareSupport::Error::noError; +} + FirmwareSupport::Error LumatoneEventManager::handlePeripheralCalibrationData(const juce::MidiMessage& midiMessage) { int mode = -1; @@ -503,6 +532,9 @@ FirmwareSupport::Error LumatoneEventManager::handleBufferCommand(const juce::Mid // loadRandomMapping(1000, 1); // uncomment for test sequence return FirmwareSupport::Error::noError; + case GET_MACRO_LIGHT_INTENSITY: + return handleGetMacroLightIntensityResponse(midiMessage); + default: jassert(sysExData[MSG_STATUS] == LumatoneFirmware::ReturnCode::ACK); if (midiMessage.getRawDataSize() <= 8) @@ -565,3 +597,112 @@ void LumatoneEventManager::timerCallback() bufferReadRequested = false; } + +void LumatoneEventManager::octaveColourConfigReceived(int boardId, juce::uint8 rgbFlag, const int* colourData) +{ + int boardIndex = boardId - 1; + + for (int keyIndex = 0; keyIndex < getOctaveBoardSize(); keyIndex++) + { + auto newValue = colourData[keyIndex]; + + juce::Colour colour = getKey(boardIndex, keyIndex).getColour(); + if (rgbFlag == 0) + { + colour = juce::Colour(newValue, colour.getGreen(), colour.getBlue()); + } + else if (rgbFlag == 1) + { + colour = juce::Colour(colour.getRed(), newValue, colour.getBlue()); + } + else if (rgbFlag == 2) + { + colour = juce::Colour(colour.getRed(), colour.getGreen(), newValue); + } + else + { + jassertfalse; + } + + LumatoneState::setKeyColour(colour, boardId, keyIndex); + } + + getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, getBoard(boardIndex)); +} + +void LumatoneEventManager::octaveChannelConfigReceived(int boardId, const int* channelData) +{ + int boardIndex = boardId - 1; + + for (int keyIndex = 0; keyIndex < getOctaveBoardSize(); keyIndex++) + { + juce::uint8 ch = channelData[keyIndex]; + if (ch == 0 || ch > 16) + ch = 1; + + auto key = getKey(boardIndex, keyIndex); + key.setChannelNumber(ch); + LumatoneState::setKeyConfig(key, boardId, keyIndex); + } + + getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, getBoard(boardIndex)); +} + +void LumatoneEventManager::octaveNoteConfigReceived(int boardId, const int* noteData) +{ + int boardIndex = boardId - 1; + + for (int keyIndex = 0; keyIndex < getOctaveBoardSize(); keyIndex++) + { + int note = noteData[keyIndex]; + if (note < 0 || note > 127) + note = 0; + + auto key = getKey(boardIndex, keyIndex); + key.setNoteOrCC(noteData[keyIndex]); + LumatoneState::setKeyConfig(key, boardId, keyIndex); + } + + getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, getBoard(boardIndex)); +} + +void LumatoneEventManager::keyTypeConfigReceived(int boardId, const int* keyTypeData) +{ + int boardIndex = boardId - 1; + + for (int keyIndex = 0; keyIndex < getOctaveBoardSize(); keyIndex++) + { + auto type = LumatoneKeyType(keyTypeData[keyIndex]); + + auto key = getKey(boardIndex, keyIndex); + key.setKeyType(type); + LumatoneState::setKeyConfig(key, boardId, keyIndex); + } + + getEditorListeners()->call(&LumatoneEditor::EditorListener::boardChanged, getBoard(boardIndex)); +} + +void LumatoneEventManager::macroButtonColoursReceived(juce::Colour inactiveColour, juce::Colour activeColour) +{ + getEditorListeners()->call(&LumatoneEditor::EditorListener::macroButtonInactiveColourChanged, inactiveColour); + getEditorListeners()->call(&LumatoneEditor::EditorListener::macroButtonActiveColourChanged, activeColour); +} + +void LumatoneEventManager::presetFlagsReceived(LumatoneFirmware::PresetFlags presetFlags) +{ + LumatoneState::setLightOnKeyStrokes(presetFlags.lightsOnKeystroke); + setStateProperty(LumatoneStateProperty::LightsOnAfterKeystroke, presetFlags.lightsOnKeystroke); + getEditorListeners()->call(&LumatoneEditor::EditorListener::lightOnKeyStrokesChanged, presetFlags.lightsOnKeystroke); + + LumatoneState::setAftertouchEnabled(presetFlags.polyphonicAftertouch); + setStateProperty(LumatoneStateProperty::AftertouchEnabled, presetFlags.polyphonicAftertouch); + getEditorListeners()->call(&LumatoneEditor::EditorListener::aftertouchToggled, presetFlags.polyphonicAftertouch); + + LumatoneState::setInvertSustain(presetFlags.sustainPedalInverted); + setStateProperty(LumatoneStateProperty::InvertSustain, presetFlags.sustainPedalInverted); + getEditorListeners()->call(&LumatoneEditor::EditorListener::invertSustainToggled, presetFlags.sustainPedalInverted); + + LumatoneState::setInvertExpression(presetFlags.expressionPedalInverted); + setStateProperty(LumatoneStateProperty::InvertExpression, presetFlags.expressionPedalInverted); + getEditorListeners()->call(&LumatoneEditor::EditorListener::invertFootControllerChanged, presetFlags.expressionPedalInverted); +} diff --git a/Source/lumatone_editor_library/device/lumatone_event_manager.h b/Source/lumatone_editor_library/device/lumatone_event_manager.h index 1fd7f74..641a195 100644 --- a/Source/lumatone_editor_library/device/lumatone_event_manager.h +++ b/Source/lumatone_editor_library/device/lumatone_event_manager.h @@ -10,23 +10,21 @@ #pragma once -#include "../listeners/status_listener.h" -#include "../listeners/firmware_listener.h" +#include "../data/application_state.h" #include "../midi/lumatone_midi_state.h" - #include "../lumatone_midi_driver/firmware_driver_listener.h" +#include "../listeners/firmware_listener.h" -class LumatoneFirmwareDriver; - -class LumatoneEventManager : private LumatoneFirmwareDriverListener, - public LumatoneMidiState, - public LumatoneState, - private juce::Timer +class LumatoneEventManager : public LumatoneApplicationState + , public LumatoneMidiState + , private LumatoneApplicationState::Controller + , private LumatoneFirmwareDriverListener + , private LumatoneEditor::FirmwareListener + , private juce::Timer { public: - - LumatoneEventManager(LumatoneFirmwareDriver& midiDriver, const LumatoneState& stateIn); + LumatoneEventManager(LumatoneFirmwareDriver& midiDriver, const LumatoneApplicationState& stateIn); ~LumatoneEventManager() override; private: @@ -43,6 +41,17 @@ class LumatoneEventManager : private LumatoneFirmwareDriverListener, //virtual void generalLogMessage(juce::String textMessage, HajuErrorVisualizer::ErrorLevel errorLevel) override; virtual void noAnswerToMessage(juce::MidiDeviceInfo expectedDevice, const juce::MidiMessage& midiMessage) override; + //============================================================================ + // Implementation of LumatoneEditor::FirmwareListener + void octaveColourConfigReceived(int boardId, juce::uint8 rgbFlag, const int* colourData) override; + void octaveChannelConfigReceived(int octaveIndex, const int* channelData) override; + void octaveNoteConfigReceived(int octaveIndex, const int* noteData) override; + void keyTypeConfigReceived(int boardId, const int* keyTypeData) override; + + void macroButtonColoursReceived(juce::Colour inactiveColour, juce::Colour activeColour) override; + + void presetFlagsReceived(LumatoneFirmware::PresetFlags presetFlags) override; + private: juce::ListenerList firmwareListeners; public: @@ -107,23 +116,17 @@ class LumatoneEventManager : private LumatoneFirmwareDriverListener, FirmwareSupport::Error handleGetExpressionPedalSensitivityResponse(const juce::MidiMessage& midiMessage); + FirmwareSupport::Error handleGetMacroLightIntensityResponse(const juce::MidiMessage& midiMessage); + void handleMidiDriverError(FirmwareSupport::Error errorToHandle, int commandReceived = -1); // Buffer read helpers FirmwareSupport::Error getBufferErrorCode(const juce::uint8* sysExData); FirmwareSupport::Error handleBufferCommand(const juce::MidiMessage& midiMessage); -private: - //void confirmAutoConnection(); - //void onConnectionConfirm(bool sendChangeSignal); - //void onDisconnection(); - //void onFirmwareUpdateReceived(); private: - LumatoneFirmwareDriver& midiDriver; - - FirmwareSupport firmwareSupport; - + LumatoneFirmwareDriver& midiDriver; const int bufferReadTimeoutMs = 30; const int bufferReadSize = 16; @@ -132,6 +135,5 @@ class LumatoneEventManager : private LumatoneFirmwareDriverListener, std::atomic readQueueSize; int sendQueueSize = 0; - int verbose = 0; }; diff --git a/Source/lumatone_editor_library/listeners/editor_listener.h b/Source/lumatone_editor_library/listeners/editor_listener.h index 6f5c857..27a7df1 100644 --- a/Source/lumatone_editor_library/listeners/editor_listener.h +++ b/Source/lumatone_editor_library/listeners/editor_listener.h @@ -34,7 +34,7 @@ class EditorListener virtual void expressionPedalSensitivityChanged(unsigned char value) {} virtual void invertFootControllerChanged(bool inverted) {} - virtual void macroButtonActiveColourChagned(juce::Colour colour) {} + virtual void macroButtonActiveColourChanged(juce::Colour colour) {} virtual void macroButtonInactiveColourChanged(juce::Colour colour) {} virtual void lightOnKeyStrokesChanged(bool lightOn) {} From 5278bd7e40704600907bb93e45a9d53c88cbe49e Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Sun, 21 Jan 2024 02:10:25 -0500 Subject: [PATCH 14/19] fix callbacks for general settings --- Source/LumatoneEditorState.h | 3 - Source/Main.cpp | 22 ++++ .../data/application_state.cpp | 50 +++++++- .../data/application_state.h | 16 ++- .../data/lumatone_state.cpp | 108 +++++------------- .../data/lumatone_state.h | 18 ++- 6 files changed, 127 insertions(+), 90 deletions(-) diff --git a/Source/LumatoneEditorState.h b/Source/LumatoneEditorState.h index e017330..8a1a6a8 100644 --- a/Source/LumatoneEditorState.h +++ b/Source/LumatoneEditorState.h @@ -31,9 +31,6 @@ namespace LumatoneEditorProperty static const juce::Identifier InCalibrationMode = juce::Identifier("InCalibrationMode"); static const juce::Identifier FirmwareUpdatePerformed = juce::Identifier("FirmwareUpdatePerformed"); - static const juce::Identifier InactiveMacroButtonColour = juce::Identifier("InactiveMacroButtonColour"); - static const juce::Identifier ActiveMacroButtonColour = juce::Identifier("ActiveMacroButtonColour"); - static const juce::Identifier ColourPalettes = juce::Identifier("ColourPalettes"); static const juce::Identifier CurrentFile = juce::Identifier("CurrentFile"); diff --git a/Source/Main.cpp b/Source/Main.cpp index 3809a4c..9e79331 100644 --- a/Source/Main.cpp +++ b/Source/Main.cpp @@ -720,6 +720,28 @@ bool TerpstraSysExApplication::aboutTerpstraSysEx() return true; } +//void LumatoneController::loadRandomMapping(int testTimeoutMs, int maxIterations, int i) +//{ +// auto dir = juce::File::getSpecialLocation(juce::File::SpecialLocationType::userDocumentsDirectory).getChildFile("Lumatone Editor").getChildFile("Mappings"); +// auto mappings = dir.findChildFiles(juce::File::TypesOfFileToFind::findFiles, true); +// auto numfiles = mappings.size(); +// auto r = juce::Random(); +// +// auto fileIndex = r.nextInt(numfiles-1); +// auto file = mappings[fileIndex]; +// +// if (file.exists() && file.hasFileExtension(".ltn")) +// { +// DBG("Found " + juce::String(numfiles) + " files, loading " + file.getFileName()); +// juce::MessageManager::callAsync([file]() { TerpstraSysExApplication::getApp().setCurrentFile(file); }); +// } +// +//// if (i < maxIterations) +//// Timer::callAfterDelay(testTimeoutMs, [&]() { loadRandomMapping(testTimeoutMs, maxIterations, i + 1); }); +//// else +//// DBG("Finished random mappings test."); +//} + //============================================================================== // This macro generates the main() routine that launches the app. START_JUCE_APPLICATION(TerpstraSysExApplication) diff --git a/Source/lumatone_editor_library/data/application_state.cpp b/Source/lumatone_editor_library/data/application_state.cpp index 1b642c9..14fd2dc 100644 --- a/Source/lumatone_editor_library/data/application_state.cpp +++ b/Source/lumatone_editor_library/data/application_state.cpp @@ -134,6 +134,30 @@ bool LumatoneApplicationState::performLumatoneAction(LumatoneAction *action, boo return action->perform(); } +void LumatoneApplicationState::setInactiveMacroButtonColour(juce::Colour buttonColour) +{ + LumatoneState::setInactiveMacroButtonColour(buttonColour); + + if (doSendChangesToDevice()) + { + controller->sendMacroButtonInactiveColour(buttonColour.toString()); + } + + editorListeners->call(&LumatoneEditor::EditorListener::macroButtonInactiveColourChanged, buttonColour); +} + +void LumatoneApplicationState::setActiveMacroButtonColour(juce::Colour buttonColour) +{ + LumatoneState::setInactiveMacroButtonColour(buttonColour); + + if (doSendChangesToDevice()) + { + controller->sendMacroButtonInactiveColour(buttonColour.toString()); + } + + editorListeners->call(&LumatoneEditor::EditorListener::macroButtonActiveColourChanged, buttonColour); +} + juce::ValueTree LumatoneApplicationState::loadStateProperties(juce::ValueTree stateIn) { juce::ValueTree newState = (stateIn.hasType(LumatoneStateProperty::StateTree)) @@ -468,9 +492,20 @@ bool LumatoneApplicationState::Controller::requestCompleteConfigFromDevice() if (appState.connectionState != ConnectionState::ONLINE) return false; - // Request MIDI channel, MIDI note, colour and key type config for all keys - appState.controller->sendGetCompleteMappingRequest(); + requestSettingsFromDevice(); + requestMappingFromDevice(); + + return true; +} + +bool LumatoneApplicationState::Controller::requestSettingsFromDevice() +{ + if (appState.connectionState != ConnectionState::ONLINE) + return false; + // Macro button colours + appState.controller->requestMacroButtonColours(); + // General options appState.controller->requestPresetFlags(); appState.controller->requestExpressionPedalSensitivity(); @@ -489,10 +524,21 @@ bool LumatoneApplicationState::Controller::requestMappingFromDevice() if (appState.connectionState != ConnectionState::ONLINE) return false; + // Request MIDI channel, MIDI note, colour and key type config for all keys appState.controller->sendGetCompleteMappingRequest(); return true; } +void LumatoneApplicationState::Controller::setInactiveMacroButtonColour(juce::Colour buttonColour) +{ + appState.setInactiveMacroButtonColour(buttonColour); +} + +void LumatoneApplicationState::Controller::setActiveMacroButtonColour(juce::Colour buttonColour) +{ + appState.setActiveMacroButtonColour(buttonColour); +} + void LumatoneApplicationState::DeviceController::setConnectionState(ConnectionState newState, bool sendNotification) { deviceAppState.connectionState = newState; diff --git a/Source/lumatone_editor_library/data/application_state.h b/Source/lumatone_editor_library/data/application_state.h index 5822079..31f4e9f 100644 --- a/Source/lumatone_editor_library/data/application_state.h +++ b/Source/lumatone_editor_library/data/application_state.h @@ -99,14 +99,14 @@ class LumatoneApplicationState : public LumatoneState virtual void setConfigTable(LumatoneConfigTable::TableType type, const LumatoneConfigTable& table) override; - //void setVelocityIntervalTable(const LumatoneConfigTable& table) override; - //void setNoteVelocityTable(const LumatoneConfigTable& tableIn) override; - //void setAftertouchTable(const LumatoneConfigTable& tableIn) override; - //void setLumatouchTable(const LumatoneConfigTable& tableIn) override; - private: bool performLumatoneAction(LumatoneAction* action, bool undoable = true, bool newTransaction = true); + +protected: + virtual void setInactiveMacroButtonColour(juce::Colour buttonColour) override; + virtual void setActiveMacroButtonColour(juce::Colour buttonColour) override; + protected: virtual juce::ValueTree loadStateProperties(juce::ValueTree stateIn); @@ -158,8 +158,12 @@ class LumatoneApplicationState : public LumatoneState Controller(LumatoneApplicationState& stateIn) : appState(stateIn) {} - virtual bool requestCompleteConfigFromDevice(); + virtual bool requestSettingsFromDevice(); virtual bool requestMappingFromDevice(); + virtual bool requestCompleteConfigFromDevice(); + + void setInactiveMacroButtonColour(juce::Colour buttonColour); + void setActiveMacroButtonColour(juce::Colour buttonColour); virtual bool performAction(LumatoneAction* action, bool undoable=true, bool newTransaction=true); diff --git a/Source/lumatone_editor_library/data/lumatone_state.cpp b/Source/lumatone_editor_library/data/lumatone_state.cpp index d140e75..25ffbdd 100644 --- a/Source/lumatone_editor_library/data/lumatone_state.cpp +++ b/Source/lumatone_editor_library/data/lumatone_state.cpp @@ -19,6 +19,16 @@ juce::Array LumatoneState::getLumatoneStateProperties() properties.add(LumatoneStateProperty::LastConnectedFirmwareVersion); properties.add(LumatoneStateProperty::LastConnectedNumBoards); + properties.add(LumatoneStateProperty::LightsOnAfterKeystroke); + properties.add(LumatoneStateProperty::AftertouchEnabled); + properties.add(LumatoneStateProperty::InvertExpression); + properties.add(LumatoneStateProperty::InvertSustain); + + properties.add(LumatoneStateProperty::ExpressionSensitivity); + + properties.add(LumatoneStateProperty::InactiveMacroButtonColour); + properties.add(LumatoneStateProperty::ActiveMacroButtonColour); + properties.add(LumatoneStateProperty::MappingData); return properties; @@ -46,6 +56,8 @@ LumatoneState::LumatoneState(juce::String nameIn, const LumatoneState& stateToCo midiKeyMap = stateToCopy.midiKeyMap; } +LumatoneState::LumatoneState(const LumatoneState &stateIn) : LumatoneState(stateIn.name + "Copy", stateIn) {} + LumatoneState::~LumatoneState() { state.removeListener(this); @@ -82,20 +94,15 @@ void LumatoneState::handleStatePropertyChange(juce::ValueTree stateIn, const juc ); firmwareVersion = LumatoneFirmware::Version::fromReleaseVersion(determinedVersion); } - else if (property == LumatoneStateProperty::MappingData) + else if (property == LumatoneStateProperty::InactiveMacroButtonColour) + { + auto readColour = juce::Colour::fromString(stateIn[property].toString()); + inactiveMacroButtonColour = readColour; + } + else if (property == LumatoneStateProperty::ActiveMacroButtonColour) { - // juce::String mappingString = stateIn.getProperty(property).toString(); - // if (mappingString.isEmpty()) - // return; - - // auto stringArray = juce::StringArray::fromLines(mappingString); - // LumatoneLayout loadedLayout(getNumBoards(), getOctaveBoardSize()); - // loadedLayout.fromStringArray(stringArray); - - // if (!loadedLayout.isEmpty()) - // { - // mappingData.reset(new LumatoneLayout(loadedLayout)); - // } + auto readColour = juce::Colour::fromString(stateIn[property].toString()); + activeMacroButtonColour = readColour; } } @@ -127,11 +134,7 @@ void LumatoneState::setLumatoneVersion(LumatoneFirmware::ReleaseVersion versionI if (writeToState) { - state.setPropertyExcludingListener( - this, - LumatoneStateProperty::LastConnectedFirmwareVersion, - (int)determinedVersion, - undoManager); + setStateProperty(LumatoneStateProperty::LastConnectedFirmwareVersion, (int)determinedVersion); } } @@ -273,63 +276,14 @@ void LumatoneState::setConfigTable(LumatoneConfigTable::TableType type, const Lu mappingData->setConfigTable(type, table.velocityValues); } -// bool LumatoneState::loadLayoutFromFile(const juce::File& layoutFile) -// { -// bool fileOpened = false; -// bool fileParsed = false; - -// if (layoutFile.existsAsFile()) -// { -// fileOpened = true; - -// juce::StringArray stringArray; -// layoutFile.readLines(stringArray); - -// LumatoneLayout newLayout(getNumBoards(), getOctaveBoardSize(), true); -// newLayout.fromStringArray(stringArray); - -// // TODO: something if boards/size don't match? -// fileParsed = true; - - -// if (fileParsed) -// { -// *mappingData = LumatoneLayout(newLayout); - -// auto layoutString = mappingData->toStringArray().joinIntoString(juce::newLine); -// DBG("Loaded: " + layoutString); - -// writeStringProperty(LumatoneStateProperty::MappingData, layoutString, undoManager); - -// invertSustain = mappingData->invertSustain; -// writeBoolProperty(LumatoneStateProperty::InvertSustain, invertSustain, undoManager); - -// invertExpression = mappingData->invertExpression; -// writeBoolProperty(LumatoneStateProperty::InvertExpression, invertExpression, undoManager); - -// expressionSensitivity = mappingData->expressionSensitivity; -// writeIntProperty(LumatoneStateProperty::ExpressionSensitivity, expressionSensitivity, undoManager); - -// // Mark file as unchanged -// //setHasChangesToSave(false); - -// // Clear undo history -// //undoManager.clearUndoHistory(); - -// // Add file to recent files list -// //recentFiles.addFile(currentFile); - -// return true; -// } -// } - -// if (fileOpened) -// { -// // Show error message -// juce::AlertWindow::showMessageBoxAsync(juce::AlertWindow::AlertIconType::WarningIcon, "Open File Error", "The file " + layoutFile.getFullPathName() + " could not be opened."); - -// // XXX Update Window title in any case? Make file name empty/make data empty in case of error? -// } +void LumatoneState::setInactiveMacroButtonColour(juce::Colour buttonColour) +{ + inactiveMacroButtonColour = buttonColour; + setStateProperty(LumatoneStateProperty::InactiveMacroButtonColour, buttonColour.toString()); +} -// return false; -// } +void LumatoneState::setActiveMacroButtonColour(juce::Colour buttonColour) +{ + activeMacroButtonColour = buttonColour; + setStateProperty(LumatoneStateProperty::InactiveMacroButtonColour, buttonColour.toString()); +} diff --git a/Source/lumatone_editor_library/data/lumatone_state.h b/Source/lumatone_editor_library/data/lumatone_state.h index 7fd32bc..d88b25b 100644 --- a/Source/lumatone_editor_library/data/lumatone_state.h +++ b/Source/lumatone_editor_library/data/lumatone_state.h @@ -30,9 +30,14 @@ namespace LumatoneStateProperty static const juce::Identifier MappingData = juce::Identifier("MappingData"); + static const juce::Identifier LightsOnAfterKeystroke = juce::Identifier("LightsOnAfterKeystroke"); + static const juce::Identifier AftertouchEnabled = juce::Identifier("AftertouchEnabled"); static const juce::Identifier InvertExpression = juce::Identifier("InvertExpression"); static const juce::Identifier InvertSustain = juce::Identifier("InvertSustain"); static const juce::Identifier ExpressionSensitivity = juce::Identifier("ExpressionSensitivity"); + + static const juce::Identifier InactiveMacroButtonColour = juce::Identifier("InactiveMacroButtonColour"); + static const juce::Identifier ActiveMacroButtonColour = juce::Identifier("ActiveMacroButtonColour"); }; class LumatoneState : public LumatoneStateBase @@ -41,6 +46,7 @@ class LumatoneState : public LumatoneStateBase LumatoneState(juce::String nameIn, juce::ValueTree stateIn=juce::ValueTree(), juce::UndoManager* undoManager=nullptr); LumatoneState(juce::String nameIn, const LumatoneState& stateToCopy); + LumatoneState(const LumatoneState& stateIn); virtual ~LumatoneState() override; @@ -82,6 +88,9 @@ class LumatoneState : public LumatoneStateBase virtual void setConfigTable(LumatoneConfigTable::TableType type, const LumatoneConfigTable& table); + virtual void setInactiveMacroButtonColour(juce::Colour buttonColour); + virtual void setActiveMacroButtonColour(juce::Colour buttonColour); + public: // Layout Helpers int getNumBoards() const { return mappingData->getNumBoards(); } @@ -93,6 +102,9 @@ class LumatoneState : public LumatoneStateBase bool getInvertSustain() const { return mappingData->getInvertSustain(); } int getExpressionSensitivity() const { return mappingData->getExpressionSensitivity(); } + juce::Colour getInactiveMacroButtonColour() const { return inactiveMacroButtonColour; } + juce::Colour getActiveMacroButtonColour() const { return activeMacroButtonColour; } + protected: void setConnectedSerialNumber(juce::String serialNumberIn); void setFirmwareVersion(LumatoneFirmware::Version& versionIn, bool writeToState=false); @@ -119,15 +131,17 @@ class LumatoneState : public LumatoneStateBase std::shared_ptr mappingData; std::shared_ptr midiKeyMap; - private: juce::String connectedSerialNumber = juce::String(); LumatoneFirmware::ReleaseVersion determinedVersion; LumatoneFirmware::Version firmwareVersion; LumatoneFirmware::Version incomingVersion; + + juce::Colour inactiveMacroButtonColour; + juce::Colour activeMacroButtonColour; }; -#endif LUMATONE_STATE_H +#endif // LUMATONE_STATE_H From 685876797ff26d4311c7f87381871fdbbfedc155 Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Mon, 22 Jan 2024 16:27:10 -0500 Subject: [PATCH 15/19] fix some connection state changed callbacks --- Source/GlobalSettingsArea.cpp | 2 ++ Source/LumatoneEditorState.cpp | 5 ++--- Source/Main.cpp | 4 +++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/GlobalSettingsArea.cpp b/Source/GlobalSettingsArea.cpp index 601836d..573b3be 100644 --- a/Source/GlobalSettingsArea.cpp +++ b/Source/GlobalSettingsArea.cpp @@ -103,6 +103,8 @@ GlobalSettingsArea::GlobalSettingsArea (const LumatoneEditorState& stateIn) settingsButton->setColour(TextButton::ColourIds::buttonColourId, Colour(0xff383b3d)); settingsButton->setColour(TextButton::ColourIds::textColourOffId, Colour(0xffffffff)); + connectionStateChanged(getConnectionState()); + /* We don't want a resize here /* //[/UserPreSize] diff --git a/Source/LumatoneEditorState.cpp b/Source/LumatoneEditorState.cpp index 4a65f8d..e1740dd 100644 --- a/Source/LumatoneEditorState.cpp +++ b/Source/LumatoneEditorState.cpp @@ -345,7 +345,7 @@ bool LumatoneEditorState::Controller::requestCompleteConfigFromDevice() { setHasChangesToSave(false); editorState.undoManager->clearUndoHistory(); - LumatoneApplicationState::Controller::requestCompleteConfigFromDevice(); + return LumatoneApplicationState::Controller::requestCompleteConfigFromDevice(); } bool LumatoneEditorState::Controller::saveMappingToFile(juce::File fileToSave) @@ -357,7 +357,7 @@ bool LumatoneEditorState::Controller::saveMappingToFile(juce::File fileToSave) if (fileToSave.existsAsFile()) success = fileToSave.replaceWithText(fileText, false, false); - + else if (fileToSave.create().ok()) { success = fileToSave.appendText(fileText, false, false); @@ -401,4 +401,3 @@ void LumatoneEditorState::Controller::setDeveloperMode(bool developerModeOn) // writeBoolProperty(LumatoneEditorProperty::DeveloperModeOn, inDeveloperMode, undoManager); editorState.setStateProperty(LumatoneEditorProperty::DeveloperModeOn, editorState.inDeveloperMode); } - diff --git a/Source/Main.cpp b/Source/Main.cpp index 9e79331..960398c 100644 --- a/Source/Main.cpp +++ b/Source/Main.cpp @@ -164,7 +164,7 @@ void TerpstraSysExApplication::anotherInstanceStarted(const String& commandLine) // if (palette.hasBeenModified()) // { // ValueTree paletteNode = palette.toValueTree(); -// +// // // pathToFile is optional - default to path defined in palette // if (pathToFile == File()) // pathToFile = File(palette.getPathToFile()); @@ -272,6 +272,8 @@ void TerpstraSysExApplication::getCommandInfo(CommandID commandID, ApplicationCo case Lumatone::Menu::commandIDs::importSysExMapping: result.setInfo("Import", "Import mapping from device.", "File", 0); result.addDefaultKeypress('i', ModifierKeys::commandModifier); + if (state.getConnectionState() != ConnectionState::ONLINE) + result.setActive(false); break; case Lumatone::Menu::commandIDs::deleteOctaveBoard: From b4c8b307e1fd8e1d2806bef5ae567fe0b64b5ef1 Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Mon, 22 Jan 2024 16:27:45 -0500 Subject: [PATCH 16/19] fix MidiEditArea combo boxes --- Source/LumatoneEditorLookAndFeel.h | 12 +- Source/MidiEditArea.cpp | 221 ++++++++++------------------- Source/MidiEditArea.h | 27 ++-- 3 files changed, 92 insertions(+), 168 deletions(-) diff --git a/Source/LumatoneEditorLookAndFeel.h b/Source/LumatoneEditorLookAndFeel.h index 2fcc537..8f5a565 100644 --- a/Source/LumatoneEditorLookAndFeel.h +++ b/Source/LumatoneEditorLookAndFeel.h @@ -639,7 +639,7 @@ class LumatoneEditorLookAndFeel : public LookAndFeel_V4 Label* label = new Label(sld.getName() + "_ValueLabel"); label->setText(String(sld.getValue()), dontSendNotification); label->setJustificationType(Justification::centred); - // label->setFont(getAppFont(LumatoneEditorFont::GothamNarrowMedium)); + label->setFont(getAppFont(LumatoneEditorFont::GothamNarrowMedium)); Colour textColour = (sld.isEnabled()) ? findColour(LumatoneEditorColourIDs::DescriptionText) @@ -820,8 +820,10 @@ class LumatoneEditorLookAndFeel : public LookAndFeel_V4 for (auto prop : box.getProperties()) l->getProperties().set(prop.name, prop.value); + auto name = box.getName(); + auto fontHeight = box.getHeight() * CONTROLBOXFONTHEIGHTSCALAR; l->setBounds(box.getLocalBounds()); - l->setFont(getComboBoxFont(box).withHeight(box.getHeight() * CONTROLBOXFONTHEIGHTSCALAR)); // Any style overrides should have been passed to Label + l->setFont(getComboBoxFont(box)); // Any style overrides should have been passed to Label return l; } @@ -832,8 +834,10 @@ class LumatoneEditorLookAndFeel : public LookAndFeel_V4 float fontHeight = labelToPosition.getFont().getHeight(); labelToPosition.setBounds( - margin, roundToInt((box.getHeight() - fontHeight) * 0.5f), - box.getWidth() - box.getHeight() - margin, fontHeight + margin + , (box.getHeight() - fontHeight) * 0.5 + , box.getWidth() - box.getHeight() - margin /* leave room for down arrow glyph */ + , fontHeight ); } diff --git a/Source/MidiEditArea.cpp b/Source/MidiEditArea.cpp index 449ceea..0880695 100644 --- a/Source/MidiEditArea.cpp +++ b/Source/MidiEditArea.cpp @@ -52,7 +52,6 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) liveEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontOverride, LumatoneEditorFont::UniviaProBold); liveEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontHeightScalar, editModeFontScalar); addChildComponent(liveEditorBtn.get()); - // liveEditorBtn->addListener(this); liveEditorBtn->onClick = [&]() { if (liveEditorBtn->getToggleState()) @@ -69,7 +68,6 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) offlineEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontOverride, LumatoneEditorFont::UniviaProBold); offlineEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontHeightScalar, editModeFontScalar); addChildComponent(offlineEditorBtn.get()); - // offlineEditorBtn->addListener(this); offlineEditorBtn->onClick = [&]() { if (offlineEditorBtn->getToggleState()) @@ -79,6 +77,10 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) } }; + // liveEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontHeightScalar, 0.6f); + // offlineEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontHeightScalar, 0.6f); + + pleaseConnectLabel.reset(new juce::Label("PleaseConnectLabel", translate("PleaseConnect"))); pleaseConnectLabel->setFont(getAppFonts().getFont(LumatoneEditorFont::UniviaProBold)); pleaseConnectLabel->setColour(juce::Label::ColourIds::textColourId, getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::ActiveText)); @@ -93,16 +95,19 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) addAndMakeVisible(logomark.get()); logomarkPath = createLogomark(); - //[/Constructor_pre] cbMidiInput.reset (new juce::ComboBox ("cbMidiInput")); addAndMakeVisible (cbMidiInput.get()); cbMidiInput->setTooltip (juce::translate("Receives answers to sent SysEx commands and the current configuration from controller ")); cbMidiInput->setEditableText (false); cbMidiInput->setJustificationType (juce::Justification::centredLeft); - cbMidiInput->setTextWhenNothingSelected (juce::translate("Select MIDI Input")); + // cbMidiInput->setTextWhenNothingSelected (juce::translate("Select MIDI Input")); + cbMidiInput->setTextWhenNothingSelected ("pick something ya dummy"); cbMidiInput->setTextWhenNoChoicesAvailable (juce::translate("(no choices)")); - cbMidiInput->addListener (this); + cbMidiInput->onChange = [&]() + { + midiInputChangedCallback(); + }; cbMidiOutput.reset (new juce::ComboBox ("cbMidiOutput")); addAndMakeVisible (cbMidiOutput.get()); @@ -111,7 +116,10 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) cbMidiOutput->setJustificationType (juce::Justification::centredLeft); cbMidiOutput->setTextWhenNothingSelected (juce::translate("Select MIDI Output")); cbMidiOutput->setTextWhenNoChoicesAvailable (juce::translate("(no choices)")); - cbMidiOutput->addListener (this); + cbMidiOutput->onChange = [&]() + { + midiOutputChangedCallback(); + }; lblConnectionState.reset (new juce::Label ("lblConnectionState", juce::translate("Disconnected"))); @@ -139,8 +147,14 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) { toggleAutoConnection(); }; + btnAutoConnect->setClickingTogglesState(true); + + + // Set up styles + + connectedColours.add(getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::DisconnectedRed)); + connectedColours.add(getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::ConnectedGreen)); - //[UserPreSize] cbMidiInput->getProperties().set(LumatoneEditorStyleIDs::popupMenuTargetWidth, 1); cbMidiInput->getProperties().set(LumatoneEditorStyleIDs::popupMenuBackgroundColour, getEditorLookAndFeel().findColour(ComboBox::ColourIds::backgroundColourId).toString()); cbMidiInput->setVisible(false); @@ -156,55 +170,34 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) lblEditMode->setFont(getAppFonts().getFont(LumatoneEditorFont::UniviaProBold)); lblEditMode->setColour(juce::Label::ColourIds::textColourId, getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::LabelPink)); - offlineEditorBtn->setClickingTogglesState(true); - offlineEditorBtn->setRadioGroupId(10, dontSendNotification); - liveEditorBtn->setClickingTogglesState(true); - liveEditorBtn->setRadioGroupId(10, dontSendNotification); - liveEditorBtn->setToggleState(true, dontSendNotification); - liveEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontHeightScalar, 0.6f); - offlineEditorBtn->getProperties().set(LumatoneEditorStyleIDs::fontHeightScalar, 0.6f); - - btnAutoConnect->setClickingTogglesState(true); - ioAreaFlexBox.alignContent = juce::FlexBox::AlignContent::center; ioAreaFlexBox.alignItems = juce::FlexBox::AlignItems::center; ioAreaFlexBox.justifyContent = juce::FlexBox::JustifyContent::spaceBetween; - //[/UserPreSize] - //[Constructor] You can add your own custom stuff here.. - refreshInputMenuAndSetSelected(0, dontSendNotification); - refreshOutputMenuAndSetSelected(0, dontSendNotification); + refreshInputMenuAndSetSelected(-1, dontSendNotification); + refreshOutputMenuAndSetSelected(-1, dontSendNotification); setConnectivity(false); addEditorListener(this); addStatusListener(this); btnAutoConnect->setToggleState(isAutoConnectionEnabled(), sendNotificationSync); - //[/Constructor] } MidiEditArea::~MidiEditArea() { - //[Destructor_pre]. You can add your own custom destruction code here.. liveEditorBtn = nullptr; offlineEditorBtn = nullptr; offlineMsgLabel = nullptr; pleaseConnectLabel = nullptr; logomark = nullptr; - //[/Destructor_pre] cbMidiInput = nullptr; cbMidiOutput = nullptr; lblConnectionState = nullptr; lblEditMode = nullptr; btnAutoConnect = nullptr; - - - //[Destructor]. You can add your own custom destruction code here.. - //deviceMonitor.stopThread(100); - // getLumatoneController()->removeStatusListener(this); - //[/Destructor] } bool MidiEditArea::isConnected() const @@ -215,12 +208,8 @@ bool MidiEditArea::isConnected() const //============================================================================== void MidiEditArea::paint (juce::Graphics& g) { - //[UserPrePaint] Add your own custom painting code here.. - //[/UserPrePaint] - g.fillAll (juce::Colour (0xffbad0de)); - //[UserPaint] Add your own custom painting code here.. g.fillAll(getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::LightBackground)); // Dark background for title and logomark @@ -237,17 +226,12 @@ void MidiEditArea::paint (juce::Graphics& g) g.setColour(connectedColours[(int)(isConnected() && liveEditorBtn->getToggleState())]); drawPathToFillBounds(g, logomarkPath, logomarkBounds); - //[/UserPaint] } void MidiEditArea::resized() { - //[UserPreResize] Add your own custom resize code here.. float w = getWidth(); float h = getHeight(); - //[/UserPreResize] - - //[UserResized] Add your own custom resize handling here.. lumatoneLabelBounds = getBounds().withRight(roundToInt(w * lumatoneLabelAreaWidth)); resizeLabelWithWidth(lumatoneLabel.get(), lumatoneLabelBounds.proportionOfWidth(lumatoneLabelWidthInArea)); @@ -301,13 +285,18 @@ void MidiEditArea::resized() ioAreaFlexBox.items.clear(); ioAreaFlexBox.items.add(juce::FlexItem(*btnAutoConnect).withFlex(0).withWidth(controlHeight * 1.6f).withHeight(controlHeight)); + int deviceBoxWidth = roundToInt(ioBounds.getWidth() * midiDeviceControlBoundsWidth); + if (btnAutoConnect->getToggleState()) { lblConnectionState->setJustificationType(juce::Justification::centredLeft); + + // Make sure these are never 0 size + cbMidiInput->setSize(deviceBoxWidth, controlHeight); + cbMidiOutput->setSize(deviceBoxWidth, controlHeight); } else { - int deviceBoxWidth = roundToInt(ioBounds.getWidth() * midiDeviceControlBoundsWidth); ioAreaFlexBox.items.add(juce::FlexItem(*cbMidiInput).withFlex(0).withWidth(deviceBoxWidth).withHeight(controlHeight)); ioAreaFlexBox.items.add(juce::FlexItem(*cbMidiOutput).withFlex(0).withWidth(deviceBoxWidth).withHeight(controlHeight)); @@ -334,68 +323,6 @@ void MidiEditArea::resized() offlineMsgLabel->setSize(connectivityArea.getX() - pleaseConnectLabel->getX(), roundToInt(h * connectionDirectionsHeight)); offlineMsgLabel->setFont(offlineMsgLabel->getFont().withHeight(offlineMsgLabel->getHeight())); } - //[/UserResized] -} - -void MidiEditArea::comboBoxChanged (juce::ComboBox* comboBoxThatHasChanged) -{ - //[UsercomboBoxChanged_Pre] - //[/UsercomboBoxChanged_Pre] - - if (comboBoxThatHasChanged == cbMidiInput.get()) - { - //[UserComboBoxCode_cbMidiInput] -- add your combo box handling code here.. - if (cbMidiInput->getSelectedItemIndex() >= 0) - setMidiInput(cbMidiInput->getSelectedItemIndex()); - - if (cbMidiInput->getSelectedItemIndex() < 0 || cbMidiOutput->getSelectedItemIndex() < 0) - { - setConnectivity(false); - //errorVisualizer.setErrorLevel( - // *lblConnectionState.get(), - // HajuErrorVisualizer::ErrorLevel::error, - // translate("Select both a MIDI input and output")); - } - else - { - jassert(!isConnected()); - lblConnectionState->setText("Connecting...", juce::NotificationType::dontSendNotification); - } - //[/UserComboBoxCode_cbMidiInput] - } - else if (comboBoxThatHasChanged == cbMidiOutput.get()) - { - //[UserComboBoxCode_cbMidiOutput] -- add your combo box handling code here.. - if (cbMidiOutput->getSelectedItemIndex() >= 0) - setMidiOutput(cbMidiOutput->getSelectedItemIndex()); - - if (cbMidiInput->getSelectedItemIndex() < 0 || cbMidiOutput->getSelectedItemIndex() < 0) - { - setConnectivity(false); - //errorVisualizer.setErrorLevel( - // *lblConnectionState.get(), - // HajuErrorVisualizer::ErrorLevel::error, - // translate("Select both a MIDI input and output")); - } - else - { - jassert(!isConnected()); - lblConnectionState->setText("Connecting...", juce::NotificationType::dontSendNotification); - } - //[/UserComboBoxCode_cbMidiOutput] - } - - //[UsercomboBoxChanged_Post] - //[/UsercomboBoxChanged_Post] -} - -//[MiscUserCode] You can add your own definitions of your custom methods or any other code here... - -void MidiEditArea::lookAndFeelChanged() -{ - connectedColours.clear(); - connectedColours.add(getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::DisconnectedRed)); - connectedColours.add(getEditorLookAndFeel().findColour(LumatoneEditorColourIDs::ConnectedGreen)); } void MidiEditArea::setConnectivity(bool isConnectedIn, juce::String connectionStatus) @@ -457,18 +384,13 @@ void MidiEditArea::toggleAutoConnection() cbMidiOutput->setVisible(!btnAutoConnect->getToggleState()); setAutoConnectionEnabled(btnAutoConnect->getToggleState()); - + if (btnAutoConnect->getToggleState()) { lblConnectionState->setText(translate("Searching for Lumatone..."), dontSendNotification); - //errorVisualizer.setErrorLevel( - // *lblConnectionState.get(), - // HajuErrorVisualizer::ErrorLevel::error, - // translate("Waiting for response from connected devices...")); } else { - // getLumatoneController()->stopAutoConnection(); lblConnectionState->setText(translate("Disconnected"), dontSendNotification); startTimer(deviceRefreshTimeoutMs); } @@ -482,7 +404,7 @@ void MidiEditArea::editModeChangedCallback() { liveEditorBtn->setToggleState(true, juce::NotificationType::sendNotification); lblConnectionState->setText("Connected", juce::NotificationType::dontSendNotification); - + if (getHasChangesToSave()) onOpenConnectionToDevice(translate("Switch to Live Mode with unsaved changes")); } @@ -491,11 +413,43 @@ void MidiEditArea::editModeChangedCallback() offlineEditorBtn->setToggleState(true, juce::NotificationType::sendNotification); lblConnectionState->setText("Offline", juce::NotificationType::dontSendNotification); } - + lblConnectionState->setColour(juce::Label::ColourIds::textColourId, connectedColours[(int)liveEditorBtn->getToggleState()]); repaint(); } +void MidiEditArea::midiInputChangedCallback() +{ + if (cbMidiInput->getSelectedItemIndex() >= 0) + setMidiInput(cbMidiInput->getSelectedItemIndex()); + + if (cbMidiInput->getSelectedItemIndex() < 0 || cbMidiOutput->getSelectedItemIndex() < 0) + { + setConnectivity(false); + } + else + { + jassert(!isConnected()); + lblConnectionState->setText("Connecting...", juce::NotificationType::dontSendNotification); + } +} + +void MidiEditArea::midiOutputChangedCallback() +{ + if (cbMidiOutput->getSelectedItemIndex() >= 0) + setMidiOutput(cbMidiOutput->getSelectedItemIndex()); + + if (cbMidiInput->getSelectedItemIndex() < 0 || cbMidiOutput->getSelectedItemIndex() < 0) + { + setConnectivity(false); + } + else + { + jassert(!isConnected()); + lblConnectionState->setText("Connecting...", juce::NotificationType::dontSendNotification); + } +} + void MidiEditArea::connectionFailed() { setConnectivity(false, "No answer"); @@ -506,31 +460,26 @@ void MidiEditArea::connectionFailed() // getLumatoneController()->setMidiInput(-1); // getLumatoneController()->setMidiOutput(-1); } + void MidiEditArea::connectionStateChanged(ConnectionState state) { if (state == ConnectionState::ONLINE) { - // if (inputDevice >= 0 && outputDevice >= 0) - // { - refreshInputMenuAndSetSelected(getMidiInputIndex() + 1, dontSendNotification); - refreshOutputMenuAndSetSelected(getMidiOutputIndex() + 1, dontSendNotification); - setConnectivity(true); - - onOpenConnectionToDevice(); - // } + refreshInputMenuAndSetSelected(getMidiInputIndex(), dontSendNotification); + refreshOutputMenuAndSetSelected(getMidiOutputIndex(), dontSendNotification); + setConnectivity(true); + + onOpenConnectionToDevice(); } else if (state == ConnectionState::DISCONNECTED) { - // Lost should only happen after connection is established - // jassert(isConnected); - if (!btnAutoConnect->getToggleState()) startTimer(deviceRefreshTimeoutMs); else { - refreshInputMenuAndSetSelected(0, juce::NotificationType::dontSendNotification); - refreshOutputMenuAndSetSelected(0, juce::NotificationType::sendNotificationAsync); + refreshInputMenuAndSetSelected(-1, juce::NotificationType::dontSendNotification); + refreshOutputMenuAndSetSelected(-1, juce::NotificationType::sendNotificationAsync); } setConnectivity(false); @@ -539,28 +488,6 @@ void MidiEditArea::connectionStateChanged(ConnectionState state) void MidiEditArea::editorModeChanged(EditorMode editModeIn) { - // switch (editModeIn) - // { - // case EditorMode::ONLINE: - // liveEditorBtn->setToggleState(true, juce::NotificationType::dontSendNotification); - // if (getHasChangesToSave()) - // onOpenConnectionToDevice(translate("Switch to Live Mode with unsaved changes")); - // break; - - // case EditorMode::OFFLINE: - // offlineEditorBtn->setToggleState(true, juce::NotificationType::dontSendNotification); - // lblConnectionState->setText(translate("Offline"), juce::NotificationType::dontSendNotification); - // //errorVisualizer.setErrorLevel( - // // *lblConnectionState.get(), - // // HajuErrorVisualizer::ErrorLevel::noError, - // // "Offline"); - // break; - - // default: - // jassertfalse; - // break; - // } - editModeChangedCallback(); } @@ -643,12 +570,12 @@ void MidiEditArea::timerCallback() else { refreshInputMenuAndSetSelected( - getMidiInputIndex() + 1, + cbMidiInput->getSelectedId(), juce::NotificationType::dontSendNotification ); refreshOutputMenuAndSetSelected( - getMidiOutputIndex() + 1, + cbMidiOutput->getSelectedId(), juce::NotificationType::dontSendNotification ); } diff --git a/Source/MidiEditArea.h b/Source/MidiEditArea.h index e75ce66..245de5a 100644 --- a/Source/MidiEditArea.h +++ b/Source/MidiEditArea.h @@ -45,7 +45,6 @@ class MidiEditArea : public juce::Component , private LumatoneApplicationState::DeviceController , public LumatoneEditor::StatusListener , public LumatoneEditor::EditorListener - , public juce::ComboBox::Listener , public juce::Timer { public: @@ -53,11 +52,13 @@ class MidiEditArea : public juce::Component MidiEditArea (const LumatoneEditorState& stateIn); ~MidiEditArea() override; - bool isConnected() const; +public: + + void paint (juce::Graphics& g) override; + void resized() override; //============================================================================== - //[UserMethods] -- You can add your own custom methods in this section. - void lookAndFeelChanged() override; + bool isConnected() const; void onOpenConnectionToDevice(String dialogTitle = ""); @@ -80,18 +81,11 @@ class MidiEditArea : public juce::Component void editModeChangedCallback(); -public: - //[/UserMethods] + void midiInputChangedCallback(); + void midiOutputChangedCallback(); - void paint (juce::Graphics& g) override; - void resized() override; - void comboBoxChanged (juce::ComboBox* comboBoxThatHasChanged) override; private: - - bool isWaitingForConnectionTest = false; - bool isWaitingForUserChoice = false; - std::unique_ptr lumatoneLabel; std::unique_ptr liveEditorBtn; @@ -103,13 +97,12 @@ class MidiEditArea : public juce::Component std::unique_ptr logomark; juce::Path logomarkPath; - const int deviceRefreshTimeoutMs = 500; + bool isWaitingForUserChoice = false; + const int deviceRefreshTimeoutMs = 500; //============================================================================== // Helpers - //std::unique_ptr alert; - juce::FlexBox ioAreaFlexBox; juce::Rectangle lumatoneLabelBounds; @@ -117,7 +110,7 @@ class MidiEditArea : public juce::Component juce::Rectangle logomarkBounds; juce::Rectangle ioBounds; - juce::Array connectedColours = { juce::Colour(0xffd7002a), juce::Colour(0xff84aea3) }; + juce::Array connectedColours; //============================================================================== // Position & Size constants From e532408de21ece6db578d10f6082ff5a68936f0e Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Thu, 25 Jan 2024 18:34:21 -0800 Subject: [PATCH 17/19] fix main window title new file callback, add controller methods for saving properties to file --- Source/LumatoneEditorState.cpp | 33 ++++++++++++++----- Source/LumatoneEditorState.h | 9 +++-- Source/MainWindow.cpp | 12 ++++++- Source/MainWindow.h | 15 ++++++++- .../listeners/editor_listener.h | 2 ++ 5 files changed, 58 insertions(+), 13 deletions(-) diff --git a/Source/LumatoneEditorState.cpp b/Source/LumatoneEditorState.cpp index e1740dd..c356c01 100644 --- a/Source/LumatoneEditorState.cpp +++ b/Source/LumatoneEditorState.cpp @@ -14,6 +14,7 @@ #include "./KeyEditComponent.h" #include "./lumatone_editor_library/device/lumatone_controller.h" +#include "./lumatone_editor_library/listeners/editor_listener.h" juce::Array GetLumatoneEditorProperty() { @@ -283,6 +284,8 @@ bool LumatoneEditorState::Controller::performAction(LumatoneAction *action, bool // Open a SysEx mapping from the file specified in currentFile bool LumatoneEditorState::Controller::resetToCurrentFile() { + getEditorListeners()->call(&LumatoneEditor::EditorListener::newFileLoaded, editorState.getCurrentFile()); + if (editorState.getCurrentFile().getFullPathName().isEmpty()) { // Replace with blank file @@ -299,12 +302,6 @@ bool LumatoneEditorState::Controller::resetToCurrentFile() editorState.getCurrentFile().readLines(stringArray); LumatoneLayout keyMapping(stringArray); - // ((MainContentComponent*)(mainWindow->getContentComponent()))->setData(keyMapping); - - // TODO FIX - // Window title - // updateMainTitle(); - // Send configuration to controller, if connected editorState.setCompleteConfig(keyMapping); @@ -330,7 +327,7 @@ bool LumatoneEditorState::Controller::resetToCurrentFile() bool LumatoneEditorState::Controller::setCurrentFile(File fileToOpen) { editorState.currentFile = fileToOpen; - // editorState.setPropertyExcludingListener(this, LumatoneEditorProperty::CurrentFile, editorState.currentFile.getFullPathName(), nullptr); + editorState.state.setPropertyExcludingListener(&editorState, LumatoneEditorProperty::CurrentFile, editorState.currentFile.getFullPathName(), nullptr); return resetToCurrentFile(); } @@ -387,17 +384,35 @@ bool LumatoneEditorState::Controller::savePropertiesFile() const return editorState.propertiesFile->saveIfNeeded(); } +void LumatoneEditorState::Controller::savePropertyBoolValue(const juce::Identifier &id, bool value) +{ + editorState.propertiesFile->setValue(id.toString(), juce::var(value)); + savePropertiesFile(); +} + +void LumatoneEditorState::Controller::savePropertyIntValue(const juce::Identifier &id, int value) +{ + editorState.propertiesFile->setValue(id.toString(), juce::var(value)); + savePropertiesFile(); +} + +void LumatoneEditorState::Controller::savePropertyStringValue(const juce::Identifier &id, juce::String value) +{ + editorState.propertiesFile->setValue(id.toString(), juce::var(value)); + savePropertiesFile(); +} + void LumatoneEditorState::Controller::setCalibrationMode(bool calibrationModeOn) { editorState.inCalibrationMode = calibrationModeOn; editorState.getLumatoneController()->setCalibratePitchModWheel(calibrationModeOn); - // writeBoolProperty(LumatoneEditorProperty::InCalibrationMode, calibrationModeOn, nullptr); editorState.setStateProperty(LumatoneEditorProperty::InCalibrationMode, editorState.inCalibrationMode); + savePropertyBoolValue(LumatoneEditorProperty::InCalibrationMode, calibrationModeOn); } void LumatoneEditorState::Controller::setDeveloperMode(bool developerModeOn) { editorState.inDeveloperMode = developerModeOn; - // writeBoolProperty(LumatoneEditorProperty::DeveloperModeOn, inDeveloperMode, undoManager); editorState.setStateProperty(LumatoneEditorProperty::DeveloperModeOn, editorState.inDeveloperMode); + savePropertyBoolValue(LumatoneEditorProperty::DeveloperModeOn, developerModeOn); } diff --git a/Source/LumatoneEditorState.h b/Source/LumatoneEditorState.h index 8a1a6a8..bcef96e 100644 --- a/Source/LumatoneEditorState.h +++ b/Source/LumatoneEditorState.h @@ -128,7 +128,7 @@ class LumatoneEditorState : public LumatoneApplicationState juce::File currentFile; std::shared_ptr recentFiles; - std::shared_ptr propertiesFile; // TODO move to state base? + std::shared_ptr propertiesFile; //================================================================================ public: @@ -144,7 +144,7 @@ class LumatoneEditorState : public LumatoneApplicationState bool resetToCurrentFile(); bool openRecentFile(int recentFileIndex); - virtual bool requestCompleteConfigFromDevice(); + virtual bool requestCompleteConfigFromDevice() override; void addPalette(const LumatoneEditorColourPalette& newPalette); bool deletePaletteFile(juce::File pathToPalette); @@ -158,6 +158,11 @@ class LumatoneEditorState : public LumatoneApplicationState juce::PropertiesFile* getPropertiesFile() const { return editorState.propertiesFile.get(); } bool savePropertiesFile() const; + // Sets a property in the juce::PropertyFile and saves it to file + void savePropertyBoolValue(const juce::Identifier& id, bool value); + void savePropertyIntValue(const juce::Identifier& id, int value); + void savePropertyStringValue(const juce::Identifier& id, juce::String value); + void setHasChangesToSave(bool hasChanges) { editorState.setHasChangesToSave(hasChanges); } void setCalibrationMode(bool calibrationModeOn); void setDeveloperMode(bool developerModeOn); diff --git a/Source/MainWindow.cpp b/Source/MainWindow.cpp index c9c927c..045f39f 100644 --- a/Source/MainWindow.cpp +++ b/Source/MainWindow.cpp @@ -10,6 +10,8 @@ #include "MainWindow.h" #include "MainComponent.h" +#include "LumatoneMenu.h" + #include "LumatoneEditorLookAndFeel.h" #include "./lumatone_editor_library/palettes/colour_palette_file.h" @@ -52,12 +54,15 @@ MainWindow::MainWindow(const LumatoneEditorState& stateIn, juce::ApplicationComm addKeyListener(commandManager->getKeyMappings()); updateBounds(); + addEditorListener(this); + startTimer(2000); #endif } MainWindow::~MainWindow() { + removeEditorListener(this); removeKeyListener(commandManager->getKeyMappings()); #if JUCE_MAC @@ -183,7 +188,7 @@ void MainWindow::updateTitle() { juce::String windowTitle("Lumatone Editor"); - if (!getCurrentFile().getFileName().isEmpty()) + if (getCurrentFile().getFileName().isNotEmpty()) windowTitle << " - " << getCurrentFile().getFileName(); if (getHasChangesToSave()) @@ -192,6 +197,11 @@ void MainWindow::updateTitle() setName(windowTitle); } +void MainWindow::newFileLoaded(juce::File file) +{ + updateTitle(); +} + void MainWindow::handleStatePropertyChange(juce::ValueTree stateIn, const juce::Identifier &property) { LumatoneEditorState::handleStatePropertyChange(stateIn, property); diff --git a/Source/MainWindow.h b/Source/MainWindow.h index acc9956..a7e0bf9 100644 --- a/Source/MainWindow.h +++ b/Source/MainWindow.h @@ -10,9 +10,18 @@ #pragma once #include -#include "LumatoneMenu.h" #include "LumatoneEditorState.h" +#include "./lumatone_editor_library/listeners/editor_listener.h" + +namespace Lumatone +{ + namespace Menu + { + class MainMenuModel; + } +} + //============================================================================== /* This class implements the desktop window that contains an instance of @@ -21,6 +30,7 @@ our MainContentComponent class. class MainWindow : public juce::DocumentWindow , public LumatoneEditorState , private LumatoneEditorState::Controller + , private LumatoneEditor::EditorListener , private juce::Timer { public: @@ -61,6 +71,9 @@ class MainWindow : public juce::DocumentWindow void updateTitle(); + // LumatoneEditor::EditorListener implementation + void newFileLoaded(juce::File file) override; + private: void handleStatePropertyChange(juce::ValueTree stateIn, const juce::Identifier &property) override; diff --git a/Source/lumatone_editor_library/listeners/editor_listener.h b/Source/lumatone_editor_library/listeners/editor_listener.h index 27a7df1..a01b5fa 100644 --- a/Source/lumatone_editor_library/listeners/editor_listener.h +++ b/Source/lumatone_editor_library/listeners/editor_listener.h @@ -20,6 +20,8 @@ class EditorListener virtual void selectionChanged(juce::Array selection) {} + virtual void newFileLoaded(juce::File file) {} + //virtual void tableChanged(LumatoneConfigTable::TableType type, const juce::uint8* table, int tableSize) {} virtual void contextChanged(LumatoneContext* context) {} From a084d8a536fd97914d274978a9645ca165825d97 Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Thu, 25 Jan 2024 19:59:12 -0800 Subject: [PATCH 18/19] add properties file integration into LumatoneState, implement in most properties --- Source/LumatoneEditorState.cpp | 87 +++++++++++++++---- Source/LumatoneEditorState.h | 7 ++ Source/MidiEditArea.cpp | 27 +++--- Source/MidiEditArea.h | 2 +- Source/NoteEditArea.cpp | 2 +- Source/SingleNoteAssign.cpp | 56 ++++++------ Source/SingleNoteAssign.h | 25 +++--- .../data/application_state.cpp | 13 ++- .../data/application_state.h | 2 + .../data/lumatone_state.cpp | 5 ++ .../data/lumatone_state.h | 2 + .../data/state_base.cpp | 21 ----- .../lumatone_editor_library/data/state_base.h | 11 +-- .../device/activity_monitor.cpp | 4 +- 14 files changed, 157 insertions(+), 107 deletions(-) diff --git a/Source/LumatoneEditorState.cpp b/Source/LumatoneEditorState.cpp index c356c01..a9fda4b 100644 --- a/Source/LumatoneEditorState.cpp +++ b/Source/LumatoneEditorState.cpp @@ -16,6 +16,20 @@ #include "./lumatone_editor_library/device/lumatone_controller.h" #include "./lumatone_editor_library/listeners/editor_listener.h" + +static juce::File getDefaultUserDocumentsDirectory() +{ + return File::getSpecialLocation(File::userDocumentsDirectory).getChildFile("Lumatone Editor"); +} +static juce::File getDefaultUserMappingsDirectory() +{ + return getDefaultUserDocumentsDirectory().getChildFile("Mappings"); +} +static juce::File getDefaultUserPalettesDirectory() +{ + return getDefaultUserDocumentsDirectory().getChildFile("Palettes"); +} + juce::Array GetLumatoneEditorProperty() { juce::Array properties; @@ -41,23 +55,7 @@ LumatoneEditorState::LumatoneEditorState(juce::String name, LumatoneFirmwareDriv appFonts = std::make_shared(); lookAndFeel = std::make_shared(*appFonts, true); - juce::PropertiesFile::Options options; - options.applicationName = "LumatoneSetup"; - options.filenameSuffix = "settings"; - options.osxLibrarySubFolder = "Application Support"; -#if JUCE_LINUX - options.folderName = "~/.config/LumatoneSetup"; -#else - options.folderName = "LumatoneSetup"; -#endif - - propertiesFile = std::make_shared(options); - DBG(propertiesFile->createXml("LumatoneEditorSettings")->toString()); - jassert(propertiesFile != nullptr); - - recentFiles = std::make_shared(); - recentFiles->restoreFromString(propertiesFile->getValue(LumatoneEditorProperty::RecentFiles)); - recentFiles->removeNonExistentFiles(); + loadPropertiesFile(nullptr); colourPalettes = std::make_shared>(); } @@ -227,6 +225,56 @@ void LumatoneEditorState::handleStatePropertyChange(juce::ValueTree stateIn, con } } +void LumatoneEditorState::loadPropertiesFile(juce::PropertiesFile *propertiesIn) +{ + juce::PropertiesFile::Options options; + options.applicationName = "LumatoneSetup"; + options.filenameSuffix = "settings"; + options.osxLibrarySubFolder = "Application Support"; +#if JUCE_LINUX + options.folderName = "~/.config/LumatoneSetup"; +#else + options.folderName = "LumatoneSetup"; +#endif + + propertiesFile = std::make_shared(options); + DBG(propertiesFile->createXml("LumatoneEditorSettings")->toString()); + jassert(propertiesFile != nullptr); + + recentFiles = std::make_shared(); + recentFiles->restoreFromString(propertiesFile->getValue(LumatoneEditorProperty::RecentFiles)); + recentFiles->removeNonExistentFiles(); + + LumatoneApplicationState::loadPropertiesFile(propertiesFile.get()); + + setStateProperty(LumatoneEditorProperty::UserDocumentsDirectory, propertiesFile->getValue(LumatoneEditorProperty::UserDocumentsDirectory.toString(), getDefaultUserDocumentsDirectory().getFullPathName())); + setStateProperty(LumatoneEditorProperty::UserMappingsDirectory, propertiesFile->getValue(LumatoneEditorProperty::UserMappingsDirectory.toString(), getDefaultUserMappingsDirectory().getFullPathName())); + setStateProperty(LumatoneEditorProperty::UserPalettesDirectory, propertiesFile->getValue(LumatoneEditorProperty::UserPalettesDirectory.toString(), getDefaultUserPalettesDirectory().getFullPathName())); + setStateProperty(LumatoneEditorProperty::RecentFiles, propertiesFile->getValue(LumatoneEditorProperty::RecentFiles.toString(), juce::String())); + setStateProperty(LumatoneEditorProperty::MainWindowState, propertiesFile->getValue(LumatoneEditorProperty::MainWindowState.toString(), juce::String())); + + setStateProperty(LumatoneEditorProperty::AutoConnectDevice, propertiesFile->getBoolValue(LumatoneEditorProperty::AutoConnectDevice.toString(), true)); + + setStateProperty(LumatoneEditorProperty::SingleNoteKeyTypeSetActive, propertiesFile->getBoolValue(LumatoneEditorProperty::SingleNoteKeyTypeSetActive.toString(), true)); + setStateProperty(LumatoneEditorProperty::SingleNoteNoteSetActive, propertiesFile->getBoolValue(LumatoneEditorProperty::SingleNoteNoteSetActive.toString(), true)); + setStateProperty(LumatoneEditorProperty::SingleNoteChannelSetActive, propertiesFile->getBoolValue(LumatoneEditorProperty::SingleNoteChannelSetActive.toString(), true)); + setStateProperty(LumatoneEditorProperty::SingleNoteColourSetActive, propertiesFile->getBoolValue(LumatoneEditorProperty::SingleNoteColourSetActive.toString(), true)); + setStateProperty(LumatoneEditorProperty::SingleNoteCCFaderIsDefault, propertiesFile->getBoolValue(LumatoneEditorProperty::SingleNoteCCFaderIsDefault.toString(), false)); + setStateProperty(LumatoneEditorProperty::SingleNoteAutoIncNoteActive, propertiesFile->getBoolValue(LumatoneEditorProperty::SingleNoteAutoIncNoteActive.toString(), true)); + setStateProperty(LumatoneEditorProperty::SingleNoteAutoIncChannelActive, propertiesFile->getBoolValue(LumatoneEditorProperty::SingleNoteAutoIncChannelActive.toString(), true)); + setStateProperty(LumatoneEditorProperty::SingleNoteAutoIncChannelAfterNumNotes, propertiesFile->getIntValue(LumatoneEditorProperty::SingleNoteAutoIncChannelAfterNumNotes.toString(), 127)); + + setStateProperty(LumatoneEditorProperty::IsomorphicMassAssign, propertiesFile->getBoolValue(LumatoneEditorProperty::IsomorphicMassAssign.toString(), false)); + + setStateProperty(LumatoneEditorProperty::LastSettingsPanel, propertiesFile->getIntValue(LumatoneEditorProperty::LastSettingsPanel.toString(), 1)); + setStateProperty(LumatoneEditorProperty::LastColourWindowTab, propertiesFile->getIntValue(LumatoneEditorProperty::LastColourWindowTab.toString(), 1)); + setStateProperty(LumatoneEditorProperty::LastFirmwareBinPath, propertiesFile->getValue(LumatoneEditorProperty::LastFirmwareBinPath.toString() + , juce::File::getSpecialLocation(juce::File::SpecialLocationType::userHomeDirectory).getFullPathName() + )); + + setStateProperty(LumatoneEditorProperty::DeveloperModeOn, propertiesFile->getBoolValue(LumatoneEditorProperty::DeveloperModeOn, false)); +} + void LumatoneEditorState::Controller::setColourPalettes(const juce::Array &palettesIn) { *editorState.colourPalettes = palettesIn; @@ -327,7 +375,7 @@ bool LumatoneEditorState::Controller::resetToCurrentFile() bool LumatoneEditorState::Controller::setCurrentFile(File fileToOpen) { editorState.currentFile = fileToOpen; - editorState.state.setPropertyExcludingListener(&editorState, LumatoneEditorProperty::CurrentFile, editorState.currentFile.getFullPathName(), nullptr); + editorState.setStateProperty(LumatoneEditorProperty::CurrentFile, editorState.currentFile.getFullPathName()); return resetToCurrentFile(); } @@ -388,18 +436,21 @@ void LumatoneEditorState::Controller::savePropertyBoolValue(const juce::Identifi { editorState.propertiesFile->setValue(id.toString(), juce::var(value)); savePropertiesFile(); + editorState.setStateProperty(id, juce::var(value)); } void LumatoneEditorState::Controller::savePropertyIntValue(const juce::Identifier &id, int value) { editorState.propertiesFile->setValue(id.toString(), juce::var(value)); savePropertiesFile(); + editorState.setStateProperty(id, juce::var(value)); } void LumatoneEditorState::Controller::savePropertyStringValue(const juce::Identifier &id, juce::String value) { editorState.propertiesFile->setValue(id.toString(), juce::var(value)); savePropertiesFile(); + editorState.setStateProperty(id, juce::var(value)); } void LumatoneEditorState::Controller::setCalibrationMode(bool calibrationModeOn) diff --git a/Source/LumatoneEditorState.h b/Source/LumatoneEditorState.h index bcef96e..461c919 100644 --- a/Source/LumatoneEditorState.h +++ b/Source/LumatoneEditorState.h @@ -52,11 +52,16 @@ namespace LumatoneEditorProperty static const juce::Identifier SingleNoteChannelSetActive = juce::Identifier("SingleNoteChannelSetActive"); static const juce::Identifier SingleNoteColourSetActive = juce::Identifier("SingleNoteColourSetActive"); static const juce::Identifier SingleNoteKeyTypeSetActive = juce::Identifier("SingleNoteKeyTypeSetActive"); + static const juce::Identifier SingleNoteAutoIncNoteActive = juce::Identifier("SingleNoteAutoIncNoteActive"); + static const juce::Identifier SingleNoteAutoIncChannelActive = juce::Identifier("SingleNoteAutoIncChannelActive"); + static const juce::Identifier SingleNoteAutoIncChannelAfterNumNotes = juce::Identifier("SingleNoteAutoIncChannelAfterNumNotes"); + static const juce::Identifier SingleNoteCCFaderIsDefault = juce::Identifier("SingleNoteCCFaderIsDefault"); static const juce::Identifier IsomorphicMassAssign = juce::Identifier("IsomorphicMassAssign"); static const juce::Identifier LastSettingsPanel = juce::Identifier("LastSettingsPanel"); static const juce::Identifier LastColourWindowTab = juce::Identifier("LastColourWindowTab"); + static const juce::Identifier LastFirmwareBinPath = juce::Identifier("LastFirmwareBinPath"); } enum class EditorMode @@ -109,6 +114,8 @@ class LumatoneEditorState : public LumatoneApplicationState juce::ValueTree loadStateProperties(juce::ValueTree stateIn) override; void handleStatePropertyChange(juce::ValueTree stateIn, const juce::Identifier& property) override; + void loadPropertiesFile(juce::PropertiesFile* properties); + void setHasChangesToSave(bool hasChangesToSave); protected: diff --git a/Source/MidiEditArea.cpp b/Source/MidiEditArea.cpp index 0880695..fba8c42 100644 --- a/Source/MidiEditArea.cpp +++ b/Source/MidiEditArea.cpp @@ -101,8 +101,7 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) cbMidiInput->setTooltip (juce::translate("Receives answers to sent SysEx commands and the current configuration from controller ")); cbMidiInput->setEditableText (false); cbMidiInput->setJustificationType (juce::Justification::centredLeft); - // cbMidiInput->setTextWhenNothingSelected (juce::translate("Select MIDI Input")); - cbMidiInput->setTextWhenNothingSelected ("pick something ya dummy"); + cbMidiInput->setTextWhenNothingSelected (juce::translate("Select MIDI Input")); cbMidiInput->setTextWhenNoChoicesAvailable (juce::translate("(no choices)")); cbMidiInput->onChange = [&]() { @@ -143,11 +142,11 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) addAndMakeVisible (btnAutoConnect.get()); btnAutoConnect->setTooltip (juce::translate("Toggle between automatic or manual connection to Lumatone")); btnAutoConnect->setButtonText (juce::translate("auto")); + btnAutoConnect->setClickingTogglesState(true); btnAutoConnect->onClick = [&]() { - toggleAutoConnection(); + onAutoConnectionChanged(); }; - btnAutoConnect->setClickingTogglesState(true); // Set up styles @@ -181,8 +180,11 @@ MidiEditArea::MidiEditArea (const LumatoneEditorState& stateIn) addEditorListener(this); addStatusListener(this); - btnAutoConnect->setToggleState(isAutoConnectionEnabled(), sendNotificationSync); + // btnAutoConnect->setToggleState(isAutoConnectionEnabled(), sendNotificationSync); + bool enableAutoConnection = getBoolProperty(LumatoneEditorProperty::AutoConnectDevice, true); + btnAutoConnect->setToggleState(enableAutoConnection, dontSendNotification); + onAutoConnectionChanged(); } MidiEditArea::~MidiEditArea() @@ -378,14 +380,19 @@ void MidiEditArea::setConnectivity(bool isConnectedIn, juce::String connectionSt resized(); } -void MidiEditArea::toggleAutoConnection() +void MidiEditArea::onAutoConnectionChanged() { - cbMidiInput->setVisible(!btnAutoConnect->getToggleState()); - cbMidiOutput->setVisible(!btnAutoConnect->getToggleState()); + bool isAuto = btnAutoConnect->getToggleState(); + bool isNotAuto = !isAuto; + + savePropertyBoolValue(LumatoneEditorProperty::AutoConnectDevice, isAuto); + + cbMidiInput->setVisible(isNotAuto); + cbMidiOutput->setVisible(isNotAuto); - setAutoConnectionEnabled(btnAutoConnect->getToggleState()); + setAutoConnectionEnabled(isAuto); - if (btnAutoConnect->getToggleState()) + if (isAuto) { lblConnectionState->setText(translate("Searching for Lumatone..."), dontSendNotification); } diff --git a/Source/MidiEditArea.h b/Source/MidiEditArea.h index 245de5a..f58c62b 100644 --- a/Source/MidiEditArea.h +++ b/Source/MidiEditArea.h @@ -77,7 +77,7 @@ class MidiEditArea : public juce::Component private: void setConnectivity(bool isConnected, juce::String connectionStatus=String()); - void toggleAutoConnection(); + void onAutoConnectionChanged(); void editModeChangedCallback(); diff --git a/Source/NoteEditArea.cpp b/Source/NoteEditArea.cpp index f18fc96..51f70d9 100644 --- a/Source/NoteEditArea.cpp +++ b/Source/NoteEditArea.cpp @@ -303,7 +303,7 @@ void NoteEditArea::setControlsTopLeftPosition(int controlsAreaX, int controlsAre void NoteEditArea::saveStateToPropertiesFile(PropertiesFile* propertiesFile) { - dynamic_cast(editFunctionsTab->getTabContentComponent(noteEditMode::SingleNoteAssignMode))->saveStateToPropertiesFile(propertiesFile); + // dynamic_cast(editFunctionsTab->getTabContentComponent(noteEditMode::SingleNoteAssignMode))->saveStateToPropertiesFile(propertiesFile); if (showIsomorphicMassAssign) dynamic_cast(editFunctionsTab->getTabContentComponent(noteEditMode::IsomorphicMassAssignMode))->saveStateToPropertiesFile(propertiesFile); diff --git a/Source/SingleNoteAssign.cpp b/Source/SingleNoteAssign.cpp index f803ad4..13dca54 100644 --- a/Source/SingleNoteAssign.cpp +++ b/Source/SingleNoteAssign.cpp @@ -34,10 +34,8 @@ //============================================================================== SingleNoteAssign::SingleNoteAssign (const LumatoneEditorState& stateIn) : LumatoneEditorState("SingleNoteAssign", stateIn) + , LumatoneEditorState::Controller(static_cast(*this)) { - //[Constructor_pre] You can add your own custom stuff here.. - //[/Constructor_pre] - setName ("SingleNoteAssign"); noteAutoIncrButton.reset (new juce::ToggleButton ("noteAutoIncrButton")); addAndMakeVisible (noteAutoIncrButton.get()); @@ -175,25 +173,19 @@ SingleNoteAssign::SingleNoteAssign (const LumatoneEditorState& stateIn) FlexBox::JustifyContent::flexStart)); } - //[/UserPreSize] - - setSize (320, 400); - - - //[Constructor] You can add your own custom stuff here.. - setNoteToggleButton->setToggleState(getProperty(LumatoneEditorProperty::SingleNoteNoteSetActive).getIntValue(), juce::NotificationType::sendNotification); - setChannelToggleButton->setToggleState(getProperty(LumatoneEditorProperty::SingleNoteChannelSetActive).getIntValue(), juce::NotificationType::sendNotification); - setColourToggleButton->setToggleState(getProperty(LumatoneEditorProperty::SingleNoteColourSetActive).getIntValue(), juce::NotificationType::sendNotification); - keyTypeToggleButton->setToggleState(getProperty(LumatoneEditorProperty::SingleNoteKeyTypeSetActive).getIntValue(), juce::NotificationType::sendNotification); + setNoteToggleButton->setToggleState(getBoolProperty(LumatoneEditorProperty::SingleNoteNoteSetActive, true), juce::NotificationType::sendNotification); + setChannelToggleButton->setToggleState(getBoolProperty(LumatoneEditorProperty::SingleNoteChannelSetActive, true), juce::NotificationType::sendNotification); + setColourToggleButton->setToggleState(getBoolProperty(LumatoneEditorProperty::SingleNoteColourSetActive, true), juce::NotificationType::sendNotification); + keyTypeToggleButton->setToggleState(getBoolProperty(LumatoneEditorProperty::SingleNoteKeyTypeSetActive, true), juce::NotificationType::sendNotification); + noteAutoIncrButton->setToggleState(getBoolProperty(LumatoneEditorProperty::SingleNoteAutoIncNoteActive, true), juce::NotificationType::sendNotification); + channelAutoIncrButton->setToggleState(getBoolProperty(LumatoneEditorProperty::SingleNoteAutoIncChannelActive, true), juce::NotificationType::sendNotification); + channelAutoIncrNoteInput->setValue(getIntProperty(LumatoneEditorProperty::SingleNoteAutoIncChannelAfterNumNotes, true), juce::NotificationType::sendNotification); keyTypeCombo->setSelectedId(LumatoneKeyType::noteOnNoteOff); - //[/Constructor] } SingleNoteAssign::~SingleNoteAssign() { - //[Destructor_pre]. You can add your own custom destruction code here.. colourSubwindow = nullptr; - //[/Destructor_pre] noteAutoIncrButton = nullptr; channelAutoIncrButton = nullptr; @@ -217,12 +209,6 @@ SingleNoteAssign::~SingleNoteAssign() //============================================================================== void SingleNoteAssign::paint (juce::Graphics& g) { - //[UserPrePaint] Add your own custom painting code here.. - //[/UserPrePaint] - - g.fillAll (juce::Colour (0xffbad0de)); - - //[UserPaint] Add your own custom painting code here.. g.fillAll(Colour(0xff212626)); Rectangle bottomPart = getLocalBounds().toFloat().withTrimmedTop(instructionsAreaBounds.getBottom()); @@ -428,6 +414,8 @@ void SingleNoteAssign::buttonClicked (juce::Button* buttonThatWasClicked) if (buttonThatWasClicked == noteAutoIncrButton.get()) { //[UserButtonCode_noteAutoIncrButton] -- add your button handler code here.. + bool fieldActive = noteAutoIncrButton->getToggleState(); + savePropertyBoolValue(LumatoneEditorProperty::SingleNoteAutoIncNoteActive, fieldActive); //[/UserButtonCode_noteAutoIncrButton] } else if (buttonThatWasClicked == channelAutoIncrButton.get()) @@ -435,6 +423,7 @@ void SingleNoteAssign::buttonClicked (juce::Button* buttonThatWasClicked) //[UserButtonCode_channelAutoIncrButton] -- add your button handler code here.. bool fieldActive = channelAutoIncrButton->getToggleState(); channelAutoIncrNoteInput->setEnabled(fieldActive); + savePropertyBoolValue(LumatoneEditorProperty::SingleNoteAutoIncChannelActive, fieldActive); //[/UserButtonCode_channelAutoIncrButton] } else if (buttonThatWasClicked == setNoteToggleButton.get()) @@ -443,6 +432,7 @@ void SingleNoteAssign::buttonClicked (juce::Button* buttonThatWasClicked) bool fieldActive = setNoteToggleButton->getToggleState(); noteInput->setEnabled(fieldActive); noteAutoIncrButton->setEnabled(fieldActive); + savePropertyBoolValue(LumatoneEditorProperty::SingleNoteNoteSetActive, fieldActive); //[/UserButtonCode_setNoteToggleButton] } else if (buttonThatWasClicked == setChannelToggleButton.get()) @@ -452,6 +442,7 @@ void SingleNoteAssign::buttonClicked (juce::Button* buttonThatWasClicked) channelInput->setEnabled(fieldActive); channelAutoIncrButton->setEnabled(fieldActive); channelAutoIncrNoteInput->setEnabled(fieldActive); + savePropertyBoolValue(LumatoneEditorProperty::SingleNoteChannelSetActive, fieldActive); //[/UserButtonCode_setChannelToggleButton] } else if (buttonThatWasClicked == setColourToggleButton.get()) @@ -460,6 +451,7 @@ void SingleNoteAssign::buttonClicked (juce::Button* buttonThatWasClicked) bool fieldActive = setColourToggleButton->getToggleState(); colourSubwindow->setEnabled(fieldActive); colourTextEditor->setEnabled(fieldActive); + savePropertyBoolValue(LumatoneEditorProperty::SingleNoteColourSetActive, fieldActive); //[/UserButtonCode_setColourToggleButton] } else if (buttonThatWasClicked == keyTypeToggleButton.get()) @@ -467,12 +459,15 @@ void SingleNoteAssign::buttonClicked (juce::Button* buttonThatWasClicked) //[UserButtonCode_keyTypeToggleButton] -- add your button handler code here.. bool fieldActive = keyTypeToggleButton->getToggleState(); keyTypeCombo->setEnabled(fieldActive); + savePropertyBoolValue(LumatoneEditorProperty::SingleNoteKeyTypeSetActive, fieldActive); //[/UserButtonCode_keyTypeToggleButton] } //[UserbuttonClicked_Post] else if (buttonThatWasClicked == ccFaderIsDefault.get()) { + bool fieldActive = ccFaderIsDefault->getToggleState(); + savePropertyBoolValue(LumatoneEditorProperty::SingleNoteCCFaderIsDefault, fieldActive); } //[/UserbuttonClicked_Post] } @@ -525,6 +520,8 @@ void SingleNoteAssign::sliderValueChanged (juce::Slider* sliderThatWasMoved) else if (sliderThatWasMoved == channelAutoIncrNoteInput.get()) { //[UserSliderCode_channelAutoIncrNoteInput] -- add your slider handling code here.. + int numNotes = channelAutoIncrNoteInput->getValue(); + savePropertyIntValue(LumatoneEditorProperty::SingleNoteAutoIncChannelAfterNumNotes, numNotes); //[/UserSliderCode_channelAutoIncrNoteInput] } @@ -589,13 +586,14 @@ LumatoneAction* SingleNoteAssign::createEditAction(int setSelection, int keySele return editAction; } -void SingleNoteAssign::saveStateToPropertiesFile(PropertiesFile* propertiesFile) -{ - propertiesFile->setValue(LumatoneEditorProperty::SingleNoteNoteSetActive, setNoteToggleButton->getToggleState()); - propertiesFile->setValue(LumatoneEditorProperty::SingleNoteChannelSetActive, setChannelToggleButton->getToggleState()); - propertiesFile->setValue(LumatoneEditorProperty::SingleNoteColourSetActive, setColourToggleButton->getToggleState()); - propertiesFile->setValue(LumatoneEditorProperty::SingleNoteKeyTypeSetActive, keyTypeToggleButton->getToggleState()); -} +// void SingleNoteAssign::saveStateToPropertiesFile(PropertiesFile* propertiesFile) +// { +// propertiesFile->setValue(LumatoneEditorProperty::SingleNoteNoteSetActive, setNoteToggleButton->getToggleState()); +// propertiesFile->setValue(LumatoneEditorProperty::SingleNoteChannelSetActive, setChannelToggleButton->getToggleState()); +// propertiesFile->setValue(LumatoneEditorProperty::SingleNoteColourSetActive, setColourToggleButton->getToggleState()); +// propertiesFile->setValue(LumatoneEditorProperty::SingleNoteKeyTypeSetActive, keyTypeToggleButton->getToggleState()); +// propertiesFile->setValue(LumatoneEditorProperty::SingleNoteAutoIncChannelActive, channelAutoIncrButton->getToggleState()); +// } void SingleNoteAssign::redrawCCFlipBtn() { diff --git a/Source/SingleNoteAssign.h b/Source/SingleNoteAssign.h index bcf0e13..e03c924 100644 --- a/Source/SingleNoteAssign.h +++ b/Source/SingleNoteAssign.h @@ -41,13 +41,14 @@ class LumatoneAction; Describe your class and how it works here! //[/Comments] */ -class SingleNoteAssign : public juce::Component, - public LumatoneEditorState, - public ColourSelectionListener, - public TextEditor::Listener, - public juce::Button::Listener, - public juce::ComboBox::Listener, - public juce::Slider::Listener +class SingleNoteAssign : public juce::Component + , public ColourSelectionListener + , private LumatoneEditorState + , private LumatoneEditorState::Controller + , private TextEditor::Listener + , private juce::Button::Listener + , private juce::ComboBox::Listener + , private juce::Slider::Listener { public: //============================================================================== @@ -55,12 +56,9 @@ class SingleNoteAssign : public juce::Component, ~SingleNoteAssign() override; //============================================================================== - //[UserMethods] -- You can add your own custom methods in this section. LumatoneAction* createEditAction(int setSelection, int keySelection); - //void onSetData(LumatoneLayout& newData); - //void restoreStateFromPropertiesFile(juce::PropertiesFile* propertiesFile); - void saveStateToPropertiesFile(juce::PropertiesFile* propertiesFile); + // void saveStateToPropertiesFile(juce::PropertiesFile* propertiesFile); ColourViewComponent* getColourViewComponent() { return colourSubwindow.get(); } ColourTextEditor* getColourTextEditor() { return colourTextEditor.get(); } @@ -68,18 +66,15 @@ class SingleNoteAssign : public juce::Component, void colourChangedCallback(ColourSelectionBroadcaster* source, Colour newColour) override; void redrawCCFlipBtn(); - //[/UserMethods] + //============================================================================== void paint (juce::Graphics& g) override; void resized() override; void buttonClicked (juce::Button* buttonThatWasClicked) override; void comboBoxChanged (juce::ComboBox* comboBoxThatHasChanged) override; void sliderValueChanged (juce::Slider* sliderThatWasMoved) override; - - private: - //[UserVariables] -- You can add your own custom variables in this section. //============================================================================== // Style Helpers int roundedCornerSize; diff --git a/Source/lumatone_editor_library/data/application_state.cpp b/Source/lumatone_editor_library/data/application_state.cpp index 14fd2dc..aea4c6e 100644 --- a/Source/lumatone_editor_library/data/application_state.cpp +++ b/Source/lumatone_editor_library/data/application_state.cpp @@ -16,8 +16,6 @@ juce::Array getLumatoneApplicationProperties() { juce::Array properties; properties.add(LumatoneApplicationProperty::ConnectionStateId); - // properties.add(LumatoneApplicationProperty::DetectDeviceIfDisconnected); - // properties.add(LumatoneApplicationProperty::CheckConnectionIfInactive); properties.add(LumatoneApplicationProperty::LayoutContextIsSetId); return properties; } @@ -192,6 +190,17 @@ void LumatoneApplicationState::handleStatePropertyChange(juce::ValueTree stateIn } } +void LumatoneApplicationState::loadPropertiesFile(juce::PropertiesFile *properties) +{ + LumatoneState::loadPropertiesFile(properties); + + setStateProperty(LumatoneApplicationProperty::DetectDeviceIfDisconnected, properties->getBoolValue(LumatoneApplicationProperty::DetectDeviceIfDisconnected.toString(), true)); + setStateProperty(LumatoneApplicationProperty::CheckConnectionIfInactive, properties->getBoolValue(LumatoneApplicationProperty::CheckConnectionIfInactive.toString(), true)); + + setStateProperty(LumatoneApplicationProperty::LastInputDeviceId, properties->getValue(LumatoneApplicationProperty::LastInputDeviceId.toString(), juce::String())); + setStateProperty(LumatoneApplicationProperty::LastOutputDeviceId, properties->getValue(LumatoneApplicationProperty::LastOutputDeviceId.toString(), juce::String())); +} + LumatoneKeyContext LumatoneApplicationState::getKeyContext(int boardIndex, int keyIndex) const { if (contextIsSet) diff --git a/Source/lumatone_editor_library/data/application_state.h b/Source/lumatone_editor_library/data/application_state.h index 31f4e9f..893c28e 100644 --- a/Source/lumatone_editor_library/data/application_state.h +++ b/Source/lumatone_editor_library/data/application_state.h @@ -112,6 +112,8 @@ class LumatoneApplicationState : public LumatoneState virtual void handleStatePropertyChange(juce::ValueTree stateIn, const juce::Identifier& property) override; + virtual void loadPropertiesFile(juce::PropertiesFile* properties) override; + private: ConnectionState connectionState = ConnectionState::DISCONNECTED; diff --git a/Source/lumatone_editor_library/data/lumatone_state.cpp b/Source/lumatone_editor_library/data/lumatone_state.cpp index 25ffbdd..31b8862 100644 --- a/Source/lumatone_editor_library/data/lumatone_state.cpp +++ b/Source/lumatone_editor_library/data/lumatone_state.cpp @@ -106,6 +106,11 @@ void LumatoneState::handleStatePropertyChange(juce::ValueTree stateIn, const juc } } +void LumatoneState::loadPropertiesFile(juce::PropertiesFile *properties) +{ + // No global properties for now +} + void LumatoneState::setConnectedSerialNumber(juce::String serialNumberIn) { connectedSerialNumber = serialNumberIn; diff --git a/Source/lumatone_editor_library/data/lumatone_state.h b/Source/lumatone_editor_library/data/lumatone_state.h index d88b25b..af73b16 100644 --- a/Source/lumatone_editor_library/data/lumatone_state.h +++ b/Source/lumatone_editor_library/data/lumatone_state.h @@ -119,6 +119,8 @@ class LumatoneState : public LumatoneStateBase virtual void handleStatePropertyChange(juce::ValueTree stateIn, const juce::Identifier& property) override; + virtual void loadPropertiesFile(juce::PropertiesFile* properties) override; + public: static juce::Array getLumatoneStateProperties(); diff --git a/Source/lumatone_editor_library/data/state_base.cpp b/Source/lumatone_editor_library/data/state_base.cpp index 721e149..921c5fa 100644 --- a/Source/lumatone_editor_library/data/state_base.cpp +++ b/Source/lumatone_editor_library/data/state_base.cpp @@ -10,12 +10,6 @@ #include "state_base.h" -bool LumatoneStateBase::writeToPropertiesFile() -{ - // todo - return false; -} - void LumatoneStateBase::setStateProperty(const juce::Identifier &id, juce::var value) { state.setPropertyExcludingListener(this, id, value, nullptr); @@ -39,21 +33,6 @@ juce::String LumatoneStateBase::getStringProperty(const juce::Identifier key, ju return prop.toString(); } -void LumatoneStateBase::writeBoolProperty(const juce::Identifier key, bool value, juce::UndoManager* undo) -{ - state.setPropertyExcludingListener(this, key, value, undo); -} - -void LumatoneStateBase::writeIntProperty(const juce::Identifier key, int value, juce::UndoManager* undo ) -{ - state.setPropertyExcludingListener(this, key, value, undo); -} - -void LumatoneStateBase::writeStringProperty(const juce::Identifier key, juce::String value, juce::UndoManager* undo) -{ - state.setPropertyExcludingListener(this, key, value, undo); -} - void LumatoneStateBase::valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier &property) { handleStatePropertyChange(treeWhosePropertyHasChanged, property); diff --git a/Source/lumatone_editor_library/data/state_base.h b/Source/lumatone_editor_library/data/state_base.h index c6a6153..7c74ce7 100644 --- a/Source/lumatone_editor_library/data/state_base.h +++ b/Source/lumatone_editor_library/data/state_base.h @@ -22,25 +22,20 @@ class LumatoneStateBase : protected juce::ValueTree::Listener int getIntProperty(const juce::Identifier key, int fallback) const; juce::String getStringProperty(const juce::Identifier key, juce::String fallback = juce::String()) const; - virtual bool writeToPropertiesFile(); protected: void setStateProperty(const juce::Identifier& id, juce::var value); -protected: - void writeBoolProperty(const juce::Identifier key, bool value, juce::UndoManager* undo=nullptr); - void writeIntProperty(const juce::Identifier key, int value, juce::UndoManager* undo=nullptr); - void writeStringProperty(const juce::Identifier key, juce::String value, juce::UndoManager* undo=nullptr); - -protected: virtual void valueTreePropertyChanged(juce::ValueTree& treeWhosePropertyHasChanged, const juce::Identifier& property) override; virtual juce::ValueTree loadStateProperties(juce::ValueTree stateIn) = 0; virtual void handleStatePropertyChange(juce::ValueTree stateIn, const juce::Identifier& property) = 0; + + virtual void loadPropertiesFile(juce::PropertiesFile* properties) = 0; protected: juce::ValueTree state; juce::String name; }; -#endif LUMATONE_STATE_BASE_H +#endif // LUMATONE_STATE_BASE_H diff --git a/Source/lumatone_editor_library/device/activity_monitor.cpp b/Source/lumatone_editor_library/device/activity_monitor.cpp index 77c6774..e28eb08 100644 --- a/Source/lumatone_editor_library/device/activity_monitor.cpp +++ b/Source/lumatone_editor_library/device/activity_monitor.cpp @@ -38,7 +38,7 @@ DeviceActivityMonitor::~DeviceActivityMonitor() void DeviceActivityMonitor::setDetectDeviceIfDisconnected(bool doDetection) { detectDevicesIfDisconnected = doDetection; - writeBoolProperty(LumatoneApplicationProperty::DetectDeviceIfDisconnected, detectDevicesIfDisconnected); + setStateProperty(LumatoneApplicationProperty::DetectDeviceIfDisconnected, detectDevicesIfDisconnected); if (!detectDevicesIfDisconnected) { @@ -54,7 +54,7 @@ void DeviceActivityMonitor::setDetectDeviceIfDisconnected(bool doDetection) void DeviceActivityMonitor::setCheckForInactivity(bool monitorActivity) { checkConnectionOnInactivity = monitorActivity; - writeBoolProperty(LumatoneApplicationProperty::CheckConnectionIfInactive, checkConnectionOnInactivity); + setStateProperty(LumatoneApplicationProperty::CheckConnectionIfInactive, checkConnectionOnInactivity); if (checkConnectionOnInactivity && isConnectionEstablished()) { From 8e8aceccb0e2ab37f2b3f21c3b72c49d3446d73a Mon Sep 17 00:00:00 2001 From: Vincenzo Sicurella Date: Sun, 12 May 2024 16:18:41 -0400 Subject: [PATCH 19/19] implement get recent files from state --- Source/LumatoneEditorState.cpp | 5 +++++ Source/LumatoneEditorState.h | 2 ++ Source/Main.cpp | 4 ++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Source/LumatoneEditorState.cpp b/Source/LumatoneEditorState.cpp index a9fda4b..d6f3158 100644 --- a/Source/LumatoneEditorState.cpp +++ b/Source/LumatoneEditorState.cpp @@ -154,6 +154,11 @@ juce::File LumatoneEditorState::getUserPalettesDirectory() const return directory; } +juce::File LumatoneEditorState::getLastOpenedMappingsDirectory() const +{ + return recentFiles->getFile(0).getParentDirectory(); +} + void LumatoneEditorState::setHasChangesToSave(bool hasChangesToSaveIn) { hasChangesToSave = hasChangesToSaveIn; diff --git a/Source/LumatoneEditorState.h b/Source/LumatoneEditorState.h index 461c919..10ffaed 100644 --- a/Source/LumatoneEditorState.h +++ b/Source/LumatoneEditorState.h @@ -106,6 +106,8 @@ class LumatoneEditorState : public LumatoneApplicationState juce::File getUserMappingsDirectory() const; juce::File getUserPalettesDirectory() const; + juce::File getLastOpenedMappingsDirectory() const; + public: bool doSendChangesToDevice() const override; diff --git a/Source/Main.cpp b/Source/Main.cpp index 960398c..d05b718 100644 --- a/Source/Main.cpp +++ b/Source/Main.cpp @@ -391,7 +391,7 @@ bool TerpstraSysExApplication::perform(const InvocationInfo& info) bool TerpstraSysExApplication::openSysExMapping() { - fileChooser = std::make_unique("Open a Lumatone key mapping", state.getRecentFiles().getFile(0).getParentDirectory(), "*.ltn;*.tsx"); + fileChooser = std::make_unique("Open a Lumatone key mapping", state.getLastOpenedMappingsDirectory(), "*.ltn"); fileChooser->launchAsync(FileBrowserComponent::FileChooserFlags::canSelectFiles | FileBrowserComponent::FileChooserFlags::openMode, [&](const FileChooser& chooser) { @@ -417,7 +417,7 @@ bool TerpstraSysExApplication::saveSysExMapping(std::function saveFileCallback) { - fileChooser = std::make_unique("Lumatone Key Mapping Files", state.getRecentFiles().getFile(0).getParentDirectory(), "*.ltn"); + fileChooser = std::make_unique("Lumatone Key Mapping Files", state.getLastOpenedMappingsDirectory(), "*.ltn"); fileChooser->launchAsync(FileBrowserComponent::FileChooserFlags::saveMode | FileBrowserComponent::FileChooserFlags::warnAboutOverwriting, [this, saveFileCallback](const FileChooser& chooser) {