Delayed UI updates with locking

This commit is contained in:
Jean Pierre Cimalando 2020-11-24 07:24:24 +01:00
parent 8a7a223777
commit 03cc5d2e5f
4 changed files with 122 additions and 112 deletions

View file

@ -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<const char *>(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<const char *>(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<const SfizzPlayState*>(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<Vst::IEditController*>(new SfizzVstController);

View file

@ -11,6 +11,7 @@
#include "vstgui/plugin-bindings/vst3editor.h"
#include <sfizz_message.h>
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<StateListener*> _stateListeners;
std::vector<MessageListener*> _messageListeners;
Steinberg::IPtr<SfizzVstEditor> _editor;
};

View file

@ -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<std::recursive_mutex> 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<std::recursive_mutex> lock(stateMutex_);
uiState_ = uiState;
mustRedisplayUiState_ = true;
}
void SfizzVstEditor::updatePlayState(const SfizzPlayState& playState)
{
std::lock_guard<std::recursive_mutex> lock(stateMutex_);
playState_ = playState;
mustRedisplayPlayState_ = true;
}
SfizzUiState SfizzVstEditor::getCurrentUiState() const
{
std::lock_guard<std::recursive_mutex> 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<int32>(v.to_float());
uiState_.activePanel = static_cast<int32>(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<std::recursive_mutex> 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)

View file

@ -8,6 +8,7 @@
#include "SfizzVstController.h"
#include "editor/EditorController.h"
#include "public.sdk/source/vst/vstguieditor.h"
#include <mutex>
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<uint8[]> 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;
};