From 03cc5d2e5ffa5493310463ce30942287ae650f78 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Tue, 24 Nov 2020 07:24:24 +0100 Subject: [PATCH] Delayed UI updates with locking --- vst/SfizzVstController.cpp | 86 ++++++++++++++-------------------- vst/SfizzVstController.h | 26 +---------- vst/SfizzVstEditor.cpp | 96 ++++++++++++++++++++++++++------------ vst/SfizzVstEditor.h | 26 +++++++---- 4 files changed, 122 insertions(+), 112 deletions(-) diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp index 970f3f1a..089cafd3 100644 --- a/vst/SfizzVstController.cpp +++ b/vst/SfizzVstController.cpp @@ -139,7 +139,20 @@ IPlugView* PLUGIN_API SfizzVstController::createView(FIDString _name) if (name != Vst::ViewType::kEditor) return nullptr; - return new SfizzVstEditor(this); + if (_editor) { + _uiState = _editor->getCurrentUiState(); + _editor.reset(); + } + + SfizzVstEditor* editor = new SfizzVstEditor(this); + _editor = Steinberg::owned(editor); + + editor->updateState(_state); + editor->updateUiState(_uiState); + editor->updatePlayState(_playState); + + editor->remember(); + return editor; } tresult PLUGIN_API SfizzVstController::setParamNormalized(Vst::ParamID tag, Vst::ParamValue normValue) @@ -190,20 +203,15 @@ tresult PLUGIN_API SfizzVstController::setParamNormalized(Vst::ParamID tag, Vst: } } - bool update = false; - if (slotF32 && *slotF32 != value) { *slotF32 = value; - update = true; + if (SfizzVstEditor* editor = _editor) + editor->updateState(_state); } else if (slotI32 && *slotI32 != (int32)value) { *slotI32 = (int32)value; - update = true; - } - - if (update) { - for (StateListener* listener : _stateListeners) - listener->onStateChanged(); + if (SfizzVstEditor* editor = _editor) + editor->updateState(_state); } return kResultTrue; @@ -219,14 +227,17 @@ tresult PLUGIN_API SfizzVstController::setState(IBStream* state) _uiState = s; - for (StateListener* listener : _stateListeners) - listener->onStateChanged(); + if (SfizzVstEditor* editor = _editor) + editor->updateUiState(_uiState); return kResultTrue; } tresult PLUGIN_API SfizzVstController::getState(IBStream* state) { + if (_editor) + _uiState = _editor->getCurrentUiState(); + return _uiState.store(state); } @@ -248,8 +259,8 @@ tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* state) setParamNormalized(kPidTuningFrequency, kParamTuningFrequencyRange.normalize(s.tuningFrequency)); setParamNormalized(kPidStretchedTuning, kParamStretchedTuningRange.normalize(s.stretchedTuning)); - for (StateListener* listener : _stateListeners) - listener->onStateChanged(); + if (SfizzVstEditor* editor = _editor) + editor->updateState(_state); return kResultTrue; } @@ -272,6 +283,9 @@ tresult SfizzVstController::notify(Vst::IMessage* message) return result; _state.sfzFile.assign(static_cast(data), size); + + if (SfizzVstEditor* editor = _editor) + editor->updateState(_state); } else if (!strcmp(id, "LoadedScala")) { const void* data = nullptr; @@ -282,6 +296,9 @@ tresult SfizzVstController::notify(Vst::IMessage* message) return result; _state.scalaFile.assign(static_cast(data), size); + + if (SfizzVstEditor* editor = _editor) + editor->updateState(_state); } else if (!strcmp(id, "NotifiedPlayState")) { const void* data = nullptr; @@ -292,6 +309,9 @@ tresult SfizzVstController::notify(Vst::IMessage* message) return result; _playState = *static_cast(data); + + if (SfizzVstEditor* editor = _editor) + editor->updatePlayState(_playState); } else if (!strcmp(id, "ReceivedMessage")) { const void* data = nullptr; @@ -301,47 +321,13 @@ tresult SfizzVstController::notify(Vst::IMessage* message) if (result != kResultTrue) return result; - const char* path; - const char* sig; - const sfizz_arg_t* args; - uint8_t buffer[1024]; - - if (sfizz_extract_message(data, size, buffer, sizeof(buffer), &path, &sig, &args) > 0) { - for (MessageListener* listener : _messageListeners) - listener->onMessageReceived(path, sig, args); - } + if (SfizzVstEditor* editor = _editor) + editor->receiveMessage(data, size); } - for (StateListener* listener : _stateListeners) - listener->onStateChanged(); - return result; } -void SfizzVstController::addSfizzStateListener(StateListener* listener) -{ - _stateListeners.push_back(listener); -} - -void SfizzVstController::removeSfizzStateListener(StateListener* listener) -{ - auto it = std::find(_stateListeners.begin(), _stateListeners.end(), listener); - if (it != _stateListeners.end()) - _stateListeners.erase(it); -} - -void SfizzVstController::addSfizzMessageListener(MessageListener* listener) -{ - _messageListeners.push_back(listener); -} - -void SfizzVstController::removeSfizzMessageListener(MessageListener* listener) -{ - auto it = std::find(_messageListeners.begin(), _messageListeners.end(), listener); - if (it != _messageListeners.end()) - _messageListeners.erase(it); -} - FUnknown* SfizzVstController::createInstance(void*) { return static_cast(new SfizzVstController); diff --git a/vst/SfizzVstController.h b/vst/SfizzVstController.h index 796d6628..69670a55 100644 --- a/vst/SfizzVstController.h +++ b/vst/SfizzVstController.h @@ -11,6 +11,7 @@ #include "vstgui/plugin-bindings/vst3editor.h" #include class SfizzVstState; +class SfizzVstEditor; using namespace Steinberg; using namespace VSTGUI; @@ -47,28 +48,6 @@ public: tresult PLUGIN_API setComponentState(IBStream* state) override; tresult PLUGIN_API notify(Vst::IMessage* message) override; - struct StateListener { - virtual void onStateChanged() = 0; - }; - struct MessageListener { - virtual void onMessageReceived(const char* path, const char* sig, const sfizz_arg_t* args) = 0; - }; - - const SfizzVstState& getSfizzState() const { return _state; } - SfizzVstState& getSfizzState() { return _state; } - - const SfizzUiState& getSfizzUiState() const { return _uiState; } - SfizzUiState& getSfizzUiState() { return _uiState; } - - const SfizzPlayState& getSfizzPlayState() const { return _playState; } - SfizzPlayState& getSfizzPlayState() { return _playState; } - - void addSfizzStateListener(StateListener* listener); - void removeSfizzStateListener(StateListener* listener); - - void addSfizzMessageListener(MessageListener* listener); - void removeSfizzMessageListener(MessageListener* listener); - /// static FUnknown* createInstance(void*); @@ -78,6 +57,5 @@ private: SfizzVstState _state; SfizzUiState _uiState; SfizzPlayState _playState {}; - std::vector _stateListeners; - std::vector _messageListeners; + Steinberg::IPtr _editor; }; diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index e972b9bf..a37602c1 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -20,18 +20,14 @@ enum { kOscTempSize = 8192, }; -SfizzVstEditor::SfizzVstEditor(void *controller) +SfizzVstEditor::SfizzVstEditor(SfizzVstController* controller) : VSTGUIEditor(controller, &sfizzUiViewRect), oscTemp_(new uint8_t[kOscTempSize]) { - getController()->addSfizzStateListener(this); - getController()->addSfizzMessageListener(this); } SfizzVstEditor::~SfizzVstEditor() { - getController()->removeSfizzStateListener(this); - getController()->removeSfizzMessageListener(this); } bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& platformType) @@ -105,17 +101,48 @@ CMessageResult SfizzVstEditor::notify(CBaseObject* sender, const char* message) } #endif + if (message == CVSTGUITimer::kMsgTimer) + updateStateDisplay(); + return result; } -void SfizzVstEditor::onStateChanged() +void SfizzVstEditor::updateState(const SfizzVstState& state) { - updateStateDisplay(); + std::lock_guard lock(stateMutex_); + state_ = state; + mustRedisplayState_ = true; } -void SfizzVstEditor::onMessageReceived(const char* path, const char* sig, const sfizz_arg_t* args) +void SfizzVstEditor::updateUiState(const SfizzUiState& uiState) { - uiReceiveMessage(path, sig, args); + std::lock_guard lock(stateMutex_); + uiState_ = uiState; + mustRedisplayUiState_ = true; +} + +void SfizzVstEditor::updatePlayState(const SfizzPlayState& playState) +{ + std::lock_guard lock(stateMutex_); + playState_ = playState; + mustRedisplayPlayState_ = true; +} + +SfizzUiState SfizzVstEditor::getCurrentUiState() const +{ + std::lock_guard lock(stateMutex_); + return uiState_; +} + +void SfizzVstEditor::receiveMessage(const void* data, uint32_t size) +{ + const char* path; + const char* sig; + const sfizz_arg_t* args; + uint8_t buffer[1024]; + + if (sfizz_extract_message(data, size, buffer, sizeof(buffer), &path, &sig, &args) > 0) + uiReceiveMessage(path, sig, args); } /// @@ -166,7 +193,7 @@ void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v) break; case EditId::UIActivePanel: - ctrl->getSfizzUiState().activePanel = static_cast(v.to_float()); + uiState_.activePanel = static_cast(v.to_float()); break; default: @@ -263,32 +290,41 @@ void SfizzVstEditor::updateStateDisplay() if (!frame) return; - SfizzVstController* controller = getController(); - const SfizzVstState& state = controller->getSfizzState(); - const SfizzUiState& uiState = controller->getSfizzUiState(); - const SfizzPlayState& playState = controller->getSfizzPlayState(); + if (!(mustRedisplayState_ || mustRedisplayUiState_ || mustRedisplayPlayState_)) + return; + + std::lock_guard lock(stateMutex_); /// - uiReceiveValue(EditId::SfzFile, state.sfzFile); - uiReceiveValue(EditId::Volume, state.volume); - uiReceiveValue(EditId::Polyphony, state.numVoices); - uiReceiveValue(EditId::Oversampling, 1u << state.oversamplingLog2); - uiReceiveValue(EditId::PreloadSize, state.preloadSize); - uiReceiveValue(EditId::ScalaFile, state.scalaFile); - uiReceiveValue(EditId::ScalaRootKey, state.scalaRootKey); - uiReceiveValue(EditId::TuningFrequency, state.tuningFrequency); - uiReceiveValue(EditId::StretchTuning, state.stretchedTuning); + if (mustRedisplayState_) { + uiReceiveValue(EditId::SfzFile, state_.sfzFile); + uiReceiveValue(EditId::Volume, state_.volume); + uiReceiveValue(EditId::Polyphony, state_.numVoices); + uiReceiveValue(EditId::Oversampling, 1u << state_.oversamplingLog2); + uiReceiveValue(EditId::PreloadSize, state_.preloadSize); + uiReceiveValue(EditId::ScalaFile, state_.scalaFile); + uiReceiveValue(EditId::ScalaRootKey, state_.scalaRootKey); + uiReceiveValue(EditId::TuningFrequency, state_.tuningFrequency); + uiReceiveValue(EditId::StretchTuning, state_.stretchedTuning); + mustRedisplayState_ = false; + } /// - uiReceiveValue(EditId::UINumCurves, playState.curves); - uiReceiveValue(EditId::UINumMasters, playState.masters); - uiReceiveValue(EditId::UINumGroups, playState.groups); - uiReceiveValue(EditId::UINumRegions, playState.regions); - uiReceiveValue(EditId::UINumPreloadedSamples, playState.preloadedSamples); - uiReceiveValue(EditId::UINumActiveVoices, playState.activeVoices); + if (mustRedisplayUiState_) { + uiReceiveValue(EditId::UIActivePanel, uiState_.activePanel); + mustRedisplayUiState_ = false; + } /// - uiReceiveValue(EditId::UIActivePanel, uiState.activePanel); + if (mustRedisplayPlayState_) { + uiReceiveValue(EditId::UINumCurves, playState_.curves); + uiReceiveValue(EditId::UINumMasters, playState_.masters); + uiReceiveValue(EditId::UINumGroups, playState_.groups); + uiReceiveValue(EditId::UINumRegions, playState_.regions); + uiReceiveValue(EditId::UINumPreloadedSamples, playState_.preloadedSamples); + uiReceiveValue(EditId::UINumActiveVoices, playState_.activeVoices); + mustRedisplayPlayState_ = false; + } } Vst::ParamID SfizzVstEditor::parameterOfEditId(EditId id) diff --git a/vst/SfizzVstEditor.h b/vst/SfizzVstEditor.h index ad45f352..e3bb1126 100644 --- a/vst/SfizzVstEditor.h +++ b/vst/SfizzVstEditor.h @@ -8,6 +8,7 @@ #include "SfizzVstController.h" #include "editor/EditorController.h" #include "public.sdk/source/vst/vstguieditor.h" +#include class Editor; #if !defined(__APPLE__) && !defined(_WIN32) namespace VSTGUI { class RunLoop; } @@ -17,11 +18,9 @@ using namespace Steinberg; using namespace VSTGUI; class SfizzVstEditor : public Vst::VSTGUIEditor, - public SfizzVstController::StateListener, - public SfizzVstController::MessageListener, public EditorController { public: - explicit SfizzVstEditor(void *controller); + explicit SfizzVstEditor(SfizzVstController* controller); ~SfizzVstEditor(); bool PLUGIN_API open(void* parent, const VSTGUI::PlatformType& platformType = VSTGUI::kDefaultNative) override; @@ -35,11 +34,12 @@ public: // VSTGUIEditor CMessageResult notify(CBaseObject* sender, const char* message) override; - // SfizzVstController::StateListener - void onStateChanged() override; - - // SfizzVstController::MessageListener - void onMessageReceived(const char* path, const char* sig, const sfizz_arg_t* args) override; + // + void updateState(const SfizzVstState& state); + void updateUiState(const SfizzUiState& uiState); + void updatePlayState(const SfizzPlayState& playState); + SfizzUiState getCurrentUiState() const; + void receiveMessage(const void* data, uint32_t size); protected: // EditorController @@ -65,4 +65,14 @@ private: // messaging std::unique_ptr oscTemp_; + + // editor state + // note: might be updated from a non-UI thread + mutable std::recursive_mutex stateMutex_; + SfizzVstState state_; + SfizzUiState uiState_; + SfizzPlayState playState_; + volatile bool mustRedisplayState_ = false; + volatile bool mustRedisplayUiState_ = false; + volatile bool mustRedisplayPlayState_ = false; };