Defered message sending from VST processor

This commit is contained in:
Jean Pierre Cimalando 2021-04-28 18:06:01 +02:00
parent e93e760f4f
commit eb22706fcd
6 changed files with 363 additions and 179 deletions

View file

@ -11,6 +11,7 @@
#include "base/source/fstreamer.h"
#include "base/source/updatehandler.h"
#include <atomic>
#include <cassert>
tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context)
{
@ -226,7 +227,7 @@ tresult PLUGIN_API SfizzVstControllerNoUi::setComponentState(IBStream* stream)
tresult SfizzVstControllerNoUi::notify(Vst::IMessage* message)
{
// Note: may be called from any thread (Reaper)
// Note: is expected to be called from the controller thread only
tresult result = EditController::notify(message);
if (result != kResultFalse)
@ -239,103 +240,62 @@ tresult SfizzVstControllerNoUi::notify(Vst::IMessage* message)
}
const char* id = message->getMessageID();
Vst::IAttributeList* attr = message->getAttributes();
///
auto stringFromBinaryAttribute = [attr](const char* id, absl::string_view& string) -> tresult {
const void* data = nullptr;
uint32 size = 0;
tresult result = attr->getBinary(id, data, size);
if (result == kResultTrue)
string = absl::string_view(reinterpret_cast<const char*>(data), size);
return result;
};
///
if (!strcmp(id, "LoadedSfz")) {
absl::string_view sfzFile;
absl::string_view sfzDescriptionBlob;
result = stringFromBinaryAttribute("File", sfzFile);
if (result != kResultTrue)
return result;
result = stringFromBinaryAttribute("Description", sfzDescriptionBlob);
if (result != kResultTrue)
return result;
sfzUpdate_->setPath(std::string(sfzFile));
if (!strcmp(id, SfzUpdate::getFClassID())) {
if (!sfzUpdate_->convertFromMessage(*message)) {
assert(false);
return kResultFalse;
}
sfzUpdate_->deferUpdate();
sfzDescriptionUpdate_->setDescription(std::string(sfzDescriptionBlob));
}
else if (!strcmp(id, SfzDescriptionUpdate::getFClassID())) {
if (!sfzDescriptionUpdate_->convertFromMessage(*message)) {
assert(false);
return kResultFalse;
}
sfzDescriptionUpdate_->deferUpdate();
}
else if (!strcmp(id, "LoadedScala")) {
absl::string_view scalaFile;
result = stringFromBinaryAttribute("File", scalaFile);
if (result != kResultTrue)
return result;
scalaUpdate_->setPath(std::string(scalaFile));
else if (!strcmp(id, ScalaUpdate::getFClassID())) {
if (!scalaUpdate_->convertFromMessage(*message)) {
assert(false);
return kResultFalse;
}
scalaUpdate_->deferUpdate();
}
else if (!strcmp(id, "NotifiedPlayState")) {
const void* data = nullptr;
uint32 size = 0;
result = attr->getBinary("PlayState", data, size);
if (result != kResultTrue)
return result;
playStateUpdate_->setState(*static_cast<const SfizzPlayState*>(data));
else if (!strcmp(id, PlayStateUpdate::getFClassID())) {
if (!playStateUpdate_->convertFromMessage(*message)) {
assert(false);
return kResultFalse;
}
playStateUpdate_->deferUpdate();
}
else if (!strcmp(id, "ReceivedMessage")) {
const void* data = nullptr;
uint32 size = 0;
result = attr->getBinary("Message", data, size);
if (result != kResultTrue)
return result;
IPtr<OSCUpdate> update = Steinberg::owned(
new OSCUpdate(reinterpret_cast<const uint8*>(data), size));
queuedUpdates_->enqueue(update);
queuedUpdates_->deferUpdate();
}
else if (!strcmp(id, "NoteEvents")) {
const void* data = nullptr;
uint32 size = 0;
result = attr->getBinary("Events", data, size);
const auto* events = reinterpret_cast<
const std::pair<uint32_t, float>*>(data);
uint32 numEvents = size / sizeof(events[0]);
IPtr<NoteUpdate> update = Steinberg::owned(
new NoteUpdate(events, numEvents));
queuedUpdates_->enqueue(update);
queuedUpdates_->deferUpdate();
}
else if (!strcmp(id, "Automate")) {
const void* data = nullptr;
uint32 size = 0;
result = attr->getBinary("Data", data, size);
if (result != kResultTrue)
return result;
const uint8* pos = reinterpret_cast<const uint8*>(data);
const uint8* end = pos + size;
while (static_cast<size_t>(end - pos) >= sizeof(uint32) + sizeof(float)) {
Vst::ParamID pid = *reinterpret_cast<const uint32*>(pos);
pos += sizeof(uint32);
float value = *reinterpret_cast<const float*>(pos);
pos += sizeof(float);
#pragma message("setParam() on non-UI thread is dangerous on Reaper, make it deferred instead") //NOLINT
setParam(pid, value);
else if (!strcmp(id, OSCUpdate::getFClassID())) {
IPtr<OSCUpdate> update = OSCUpdate::createFromMessage(*message);
if (!update) {
assert(false);
return kResultFalse;
}
queuedUpdates_->enqueue(update);
queuedUpdates_->deferUpdate();
}
else if (!strcmp(id, NoteUpdate::getFClassID())) {
IPtr<NoteUpdate> update = NoteUpdate::createFromMessage(*message);
if (!update) {
assert(false);
return kResultFalse;
}
queuedUpdates_->enqueue(update);
queuedUpdates_->deferUpdate();
}
else if (!strcmp(id, AutomationUpdate::getFClassID())) {
IPtr<AutomationUpdate> update = AutomationUpdate::createFromMessage(*message);
if (!update) {
assert(false);
return kResultFalse;
}
for (AutomationUpdate::Item item : update->getItems())
setParam(item.first, item.second);
}
return result;

View file

@ -78,6 +78,20 @@ tresult PLUGIN_API SfizzVstProcessor::initialize(FUnknown* context)
// initialize the update handler
Steinberg::UpdateHandler::instance();
_queuedMessages = Steinberg::owned(new QueuedUpdates);
_playStateUpdate = Steinberg::owned(new PlayStateUpdate);
_sfzUpdate = Steinberg::owned(new SfzUpdate);
_sfzDescriptionUpdate = Steinberg::owned(new SfzDescriptionUpdate);
_scalaUpdate = Steinberg::owned(new ScalaUpdate);
_automationUpdate = Steinberg::owned(new AutomationUpdate);
_queuedMessages->addDependent(this);
_playStateUpdate->addDependent(this);
_sfzUpdate->addDependent(this);
_sfzDescriptionUpdate->addDependent(this);
_scalaUpdate->addDependent(this);
_automationUpdate->addDependent(this);
addAudioOutput(STR16("Audio Output"), Vst::SpeakerArr::kStereo);
addEventInput(STR16("Event Input"), 1);
@ -115,6 +129,18 @@ tresult PLUGIN_API SfizzVstProcessor::initialize(FUnknown* context)
return result;
}
tresult PLUGIN_API SfizzVstProcessor::terminate()
{
_queuedMessages->removeDependent(this);
_playStateUpdate->removeDependent(this);
_sfzUpdate->removeDependent(this);
_sfzDescriptionUpdate->removeDependent(this);
_scalaUpdate->removeDependent(this);
_automationUpdate->removeDependent(this);
return AudioEffect::terminate();
}
tresult PLUGIN_API SfizzVstProcessor::setBusArrangements(Vst::SpeakerArrangement* inputs, int32 numIns, Vst::SpeakerArrangement* outputs, int32 numOuts)
{
bool isStereo = numIns == 0 && numOuts == 1 && outputs[0] == Vst::SpeakerArr::kStereo;
@ -132,10 +158,7 @@ tresult PLUGIN_API SfizzVstProcessor::connect(IConnectionPoint* other)
return result;
// when controller connects, send these messages that we couldn't earlier
if (_loadedSfzMessage)
sendMessage(_loadedSfzMessage);
if (_automateMessage)
sendMessage(_automateMessage);
_queuedMessages->deferUpdate();
return kResultTrue;
}
@ -316,7 +339,7 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data)
synth.sendMessage(client, 0, "/sw/last/current", "", nullptr);
//
std::pair<uint32, float> noteEvents[128];
NoteUpdate::Item noteEvents[128];
size_t numNoteEvents = 0;
for (uint32 key = 0; key < 128; ++key) {
float value = _noteEventsCurrentCycle[key];
@ -528,7 +551,7 @@ void SfizzVstProcessor::processMessagesFromUi()
tresult PLUGIN_API SfizzVstProcessor::notify(Vst::IMessage* message)
{
// Note(jpc) this notification is not necessarily handled by the RT thread
// Note(jpc) this notification is not handled by the RT thread
tresult result = AudioEffect::notify(message);
if (result != kResultFalse)
@ -563,10 +586,8 @@ tresult PLUGIN_API SfizzVstProcessor::notify(Vst::IMessage* message)
_synth->loadScalaFile(_state.scalaFile);
lock.unlock();
Steinberg::OPtr<Vst::IMessage> reply { allocateMessage() };
reply->setMessageID("LoadedScala");
reply->getAttributes()->setBinary("File", _state.scalaFile.data(), _state.scalaFile.size());
sendMessage(reply);
_scalaUpdate->setPath(_state.scalaFile);
_scalaUpdate->deferUpdate();
}
else if (!std::strcmp(id, "MidiMessage")) {
const void* data = nullptr;
@ -601,7 +622,48 @@ bool SfizzVstProcessor::processUpdate(FUnknown* changedUnknown, int32 message)
return true;
}
// TODO
if (OSCUpdate* update = FCast<OSCUpdate>(changedUnknown)) {
if (IPtr<Vst::IMessage> message = update->convertToMessage(this))
sendMessage(message);
return true;
}
if (PlayStateUpdate* update = FCast<PlayStateUpdate>(changedUnknown)) {
if (IPtr<Vst::IMessage> message = update->convertToMessage(this))
sendMessage(message);
return true;
}
if (NoteUpdate* update = FCast<NoteUpdate>(changedUnknown)) {
if (IPtr<Vst::IMessage> message = update->convertToMessage(this))
sendMessage(message);
return true;
}
if (SfzUpdate* update = FCast<SfzUpdate>(changedUnknown)) {
if (IPtr<Vst::IMessage> message = update->convertToMessage(this))
sendMessage(message);
return true;
}
if (SfzDescriptionUpdate* update = FCast<SfzDescriptionUpdate>(changedUnknown)) {
if (IPtr<Vst::IMessage> message = update->convertToMessage(this))
sendMessage(message);
return true;
}
if (ScalaUpdate* update = FCast<ScalaUpdate>(changedUnknown)) {
if (IPtr<Vst::IMessage> message = update->convertToMessage(this))
sendMessage(message);
return true;
}
if (AutomationUpdate* update = FCast<AutomationUpdate>(changedUnknown)) {
if (IPtr<Vst::IMessage> message = update->convertToMessage(this))
sendMessage(message);
return true;
}
return false;
}
@ -637,12 +699,6 @@ void SfizzVstProcessor::loadSfzFileOrDefault(const std::string& filePath, bool i
const std::string descBlob = getDescriptionBlob(synth.handle());
Steinberg::OPtr<Vst::IMessage> loadMessage { allocateMessage() };
loadMessage->setMessageID("LoadedSfz");
Vst::IAttributeList* loadAttrs = loadMessage->getAttributes();
loadAttrs->setBinary("File", filePath.data(), filePath.size());
loadAttrs->setBinary("Description", descBlob.data(), descBlob.size());
{
std::vector<absl::optional<float>> newControllers(sfz::config::numCCs);
const std::vector<absl::optional<float>> oldControllers = std::move(_state.controllers);
@ -665,26 +721,21 @@ void SfizzVstProcessor::loadSfzFileOrDefault(const std::string& filePath, bool i
}
// create a message which requests the controller to automate initial parameters
Steinberg::OPtr<Vst::IMessage> automateMessage { allocateMessage() };
automateMessage->setMessageID("Automate");
Vst::IAttributeList* automateAttrs = automateMessage->getAttributes();
std::string automateBlob;
automateBlob.reserve(sfz::config::numCCs * (sizeof(uint32) + sizeof(float)));
std::vector<AutomationUpdate::Item> automationItems;
automationItems.reserve(sfz::config::numCCs);
for (uint32 cc = 0; cc < sfz::config::numCCs; ++cc) {
uint32 pid = kPidCC0 + cc;
Vst::ParamID pid = kPidCC0 + cc;
float value = _state.controllers[cc].value_or(0.0f);
automateBlob.append(reinterpret_cast<const char*>(&pid), sizeof(uint32));
automateBlob.append(reinterpret_cast<const char*>(&value), sizeof(float));
automationItems.emplace_back(pid, value);
}
automateAttrs->setBinary("Data", automateBlob.data(), uint32(automateBlob.size()));
// sending can fail if controller is not connected yet, so keep it around
_loadedSfzMessage = loadMessage;
_automateMessage = automateMessage;
// send message
sendMessage(loadMessage);
sendMessage(automateMessage);
_sfzUpdate->setPath(filePath);
_sfzUpdate->deferUpdate();
_sfzDescriptionUpdate->setDescription(descBlob);
_sfzDescriptionUpdate->deferUpdate();
_automationUpdate->setItems(std::move(automationItems));
_automationUpdate->deferUpdate();
}
void SfizzVstProcessor::doBackgroundWork()
@ -729,16 +780,16 @@ void SfizzVstProcessor::doBackgroundWork()
_synth->setPreloadSize(value);
}
else if (id == kMsgIdReceiveOSC) {
Steinberg::OPtr<Vst::IMessage> notification { allocateMessage() };
notification->setMessageID("ReceivedMessage");
notification->getAttributes()->setBinary("Message", msg->payload<uint8_t>(), msg->size);
sendMessage(notification);
IPtr<OSCUpdate> update = Steinberg::owned(
new OSCUpdate(msg->payload<uint8>(), msg->size));
_queuedMessages->enqueue(update);
_queuedMessages->deferUpdate();
}
else if (id == kMsgIdNoteEvents) {
Steinberg::OPtr<Vst::IMessage> notification { allocateMessage() };
notification->setMessageID("NoteEvents");
notification->getAttributes()->setBinary("Events", msg->payload<uint8_t>(), msg->size);
sendMessage(notification);
IPtr<NoteUpdate> update = Steinberg::owned(
new NoteUpdate(msg->payload<NoteUpdate::Item>(), msg->size / sizeof(NoteUpdate::Item)));
_queuedMessages->enqueue(update);
_queuedMessages->deferUpdate();
}
Clock::time_point currentTime = Clock::now();
@ -755,10 +806,8 @@ void SfizzVstProcessor::doBackgroundIdle(size_t idleCounter)
{
SfizzPlayState ps;
ps.activeVoices = _synth->getNumActiveVoices();
Steinberg::OPtr<Vst::IMessage> notification { allocateMessage() };
notification->setMessageID("NotifiedPlayState");
notification->getAttributes()->setBinary("PlayState", &ps, sizeof(ps));
sendMessage(notification);
_playStateUpdate->setState(ps);
_playStateUpdate->deferUpdate();
}
if (idleCounter % 25 == 0) {

View file

@ -6,6 +6,7 @@
#pragma once
#include "SfizzVstState.h"
#include "SfizzVstUpdates.h"
#include "OrderedEventProcessor.h"
#include "plugin/RMSFollower.h"
#include "sfizz/RTSemaphore.h"
@ -27,6 +28,7 @@ public:
~SfizzVstProcessor();
tresult PLUGIN_API initialize(FUnknown* context) override;
tresult PLUGIN_API terminate() override;
tresult PLUGIN_API setBusArrangements(Vst::SpeakerArrangement* inputs, int32 numIns, Vst::SpeakerArrangement* outputs, int32 numOuts) override;
tresult PLUGIN_API connect(IConnectionPoint* other) override;
@ -56,8 +58,6 @@ public:
private:
// synth state. acquire processMutex before accessing
std::unique_ptr<sfz::Sfizz> _synth;
Steinberg::IPtr<Vst::IMessage> _loadedSfzMessage;
Steinberg::IPtr<Vst::IMessage> _automateMessage;
bool _isActive = false;
SfizzVstState _state;
float _currentStretchedTuning = 0;
@ -70,6 +70,12 @@ private:
bool _editorIsOpen = false;
// updates
IPtr<QueuedUpdates> _queuedMessages;
IPtr<PlayStateUpdate> _playStateUpdate;
IPtr<SfzUpdate> _sfzUpdate;
IPtr<SfzDescriptionUpdate> _sfzDescriptionUpdate;
IPtr<ScalaUpdate> _scalaUpdate;
IPtr<AutomationUpdate> _automationUpdate;
bool processUpdate(FUnknown* changedUnknown, int32 message);
// client

View file

@ -57,10 +57,118 @@ bool OSCUpdate::loadFromAttributes(Vst::IAttributeList* attrs)
}
///
NoteUpdate::NoteUpdate(const Item* items, uint32 count)
bool NoteUpdate::saveToAttributes(Vst::IAttributeList* attrs) const
{
Item* copy = new Item[count];
std::copy_n(items, count, copy);
events_.reset(copy);
count_ = count;
return attrs->setBinary("Events", events_.data(), events_.size() * sizeof(Item)) == kResultTrue;
}
bool NoteUpdate::loadFromAttributes(Vst::IAttributeList* attrs)
{
const void* binData = nullptr;
uint32 binSize = 0;
if (attrs->getBinary("Events", binData, binSize) != kResultTrue)
return false;
const Item* events = reinterpret_cast<const Item*>(binData);
uint32 numEvents = binSize / sizeof(Item);
events_.assign(events, events + numEvents);
return true;
}
///
bool FilePathUpdate::saveFilePathAttributes_(Vst::IAttributeList* attrs) const
{
std::lock_guard<std::mutex> lock(mutex_);
return attrs->setBinary("Path", path_.data(), path_.size()) == kResultTrue;
}
bool FilePathUpdate::loadFilePathAttributes_(Vst::IAttributeList* attrs)
{
const void* binData = nullptr;
uint32 binSize = 0;
if (attrs->getBinary("Path", binData, binSize) != kResultTrue)
return false;
std::lock_guard<std::mutex> lock(mutex_);
path_.assign(reinterpret_cast<const char *>(binData), binSize);
return true;
}
///
bool SfzUpdate::saveToAttributes(Vst::IAttributeList* attrs) const
{
return saveFilePathAttributes_(attrs);
}
bool SfzUpdate::loadFromAttributes(Vst::IAttributeList* attrs)
{
return loadFilePathAttributes_(attrs);
}
///
bool ScalaUpdate::saveToAttributes(Vst::IAttributeList* attrs) const
{
return saveFilePathAttributes_(attrs);
}
bool ScalaUpdate::loadFromAttributes(Vst::IAttributeList* attrs)
{
return loadFilePathAttributes_(attrs);
}
///
bool SfzDescriptionUpdate::saveToAttributes(Vst::IAttributeList* attrs) const
{
std::lock_guard<std::mutex> lock(mutex_);
return attrs->setBinary("Blob", description_.data(), description_.size()) == kResultTrue;
}
bool SfzDescriptionUpdate::loadFromAttributes(Vst::IAttributeList* attrs)
{
const void* binData = nullptr;
uint32 binSize = 0;
if (attrs->getBinary("Blob", binData, binSize) != kResultTrue)
return false;
std::lock_guard<std::mutex> lock(mutex_);
description_.assign(reinterpret_cast<const char *>(binData), binSize);
return true;
}
///
bool PlayStateUpdate::saveToAttributes(Vst::IAttributeList* attrs) const
{
std::lock_guard<std::mutex> lock(mutex_);
return attrs->setInt("ActiveVoices", state_.activeVoices) == kResultTrue;
}
bool PlayStateUpdate::loadFromAttributes(Vst::IAttributeList* attrs)
{
int64 activeVoices;
if (attrs->getInt("ActiveVoices", activeVoices) != kResultTrue)
return false;
std::lock_guard<std::mutex> lock(mutex_);
state_.activeVoices = static_cast<uint32>(activeVoices);
return true;
}
///
bool AutomationUpdate::saveToAttributes(Vst::IAttributeList* attrs) const
{
std::lock_guard<std::mutex> lock(mutex_);
return attrs->setBinary("Items", items_.data(), items_.size() * sizeof(Item)) == kResultTrue;
}
bool AutomationUpdate::loadFromAttributes(Vst::IAttributeList* attrs)
{
const void* binData = nullptr;
uint32 binSize = 0;
if (attrs->getBinary("Items", binData, binSize) != kResultTrue)
return false;
const Item* events = reinterpret_cast<const Item*>(binData);
uint32 numEvents = binSize / sizeof(Item);
std::lock_guard<std::mutex> lock(mutex_);
items_.assign(events, events + numEvents);
return true;
}

View file

@ -25,7 +25,8 @@ public:
virtual ~IConvertibleToMessage() {}
IPtr<Vst::IMessage> convertToMessage(Vst::ComponentBase* sender) const;
static IPtr<T> convertFromMessage(Vst::IMessage& message);
bool convertFromMessage(Vst::IMessage& message);
static IPtr<T> createFromMessage(Vst::IMessage& message);
protected:
virtual bool saveToAttributes(Vst::IAttributeList* attrs) const = 0;
@ -75,25 +76,32 @@ private:
/**
* @brief Update which notifies one or more note on/off events
*/
class NoteUpdate : public Steinberg::FObject {
class NoteUpdate : public Steinberg::FObject,
public IConvertibleToMessage<NoteUpdate> {
public:
using Item = std::pair<uint32_t, float>;
using Item = std::pair<uint32, float>;
NoteUpdate(const Item* items, uint32 count);
const Item* events() const noexcept { return events_.get(); }
const uint32_t count() const noexcept { return count_; }
NoteUpdate() = default;
NoteUpdate(const Item* items, uint32 count) : events_(items, items + count) {}
const Item* events() const noexcept { return events_.data(); }
const uint32 count() const noexcept { return static_cast<uint32>(events_.size()); }
bool saveToAttributes(Vst::IAttributeList* attrs) const override;
bool loadFromAttributes(Vst::IAttributeList* attrs) override;
OBJ_METHODS(NoteUpdate, FObject)
private:
std::unique_ptr<Item[]> events_;
uint32_t count_ = 0;
std::vector<Item> events_;
};
/**
* @brief Update which notifies a change of SFZ file.
* @brief Abstract update which notifies change of a certain file path.
*/
class SfzUpdate : public Steinberg::FObject {
class FilePathUpdate : public Steinberg::FObject {
protected:
FilePathUpdate() = default;
public:
void setPath(std::string newPath)
{
@ -107,17 +115,46 @@ public:
return path_;
}
OBJ_METHODS(SfzUpdate, FObject)
OBJ_METHODS(FilePathUpdate, FObject)
protected:
bool saveFilePathAttributes_(Vst::IAttributeList* attrs) const;
bool loadFilePathAttributes_(Vst::IAttributeList* attrs);
private:
std::string path_;
mutable std::mutex mutex_;
};
/**
* @brief Update which notifies a change of SFZ file.
*/
class SfzUpdate : public FilePathUpdate,
public IConvertibleToMessage<SfzUpdate> {
public:
OBJ_METHODS(SfzUpdate, FilePathUpdate)
bool saveToAttributes(Vst::IAttributeList* attrs) const override;
bool loadFromAttributes(Vst::IAttributeList* attrs) override;
};
/**
* @brief Update which notifies a change of scala file.
*/
class ScalaUpdate : public FilePathUpdate,
public IConvertibleToMessage<ScalaUpdate> {
public:
OBJ_METHODS(ScalaUpdate, FilePathUpdate)
bool saveToAttributes(Vst::IAttributeList* attrs) const override;
bool loadFromAttributes(Vst::IAttributeList* attrs) override;
};
/**
* @brief Update which notifies a change of SFZ description.
*/
class SfzDescriptionUpdate : public Steinberg::FObject {
class SfzDescriptionUpdate : public Steinberg::FObject,
public IConvertibleToMessage<SfzDescriptionUpdate> {
public:
void setDescription(std::string newDescription)
{
@ -131,6 +168,9 @@ public:
return description_;
}
bool saveToAttributes(Vst::IAttributeList* attrs) const override;
bool loadFromAttributes(Vst::IAttributeList* attrs) override;
OBJ_METHODS(SfzDescriptionUpdate, FObject)
private:
@ -138,34 +178,11 @@ private:
mutable std::mutex mutex_;
};
/**
* @brief Update which notifies a change of scala file.
*/
class ScalaUpdate : public Steinberg::FObject {
public:
void setPath(std::string newPath)
{
std::lock_guard<std::mutex> lock(mutex_);
path_ = std::move(newPath);
}
std::string getPath() const
{
std::lock_guard<std::mutex> lock(mutex_);
return path_;
}
OBJ_METHODS(ScalaUpdate, FObject)
private:
std::string path_;
mutable std::mutex mutex_;
};
/**
* @brief Update which indicates the playing SFZ status.
*/
class PlayStateUpdate : public Steinberg::FObject {
class PlayStateUpdate : public Steinberg::FObject,
public IConvertibleToMessage<PlayStateUpdate> {
public:
void setState(SfizzPlayState newState)
{
@ -179,6 +196,9 @@ public:
return state_;
}
bool saveToAttributes(Vst::IAttributeList* attrs) const override;
virtual bool loadFromAttributes(Vst::IAttributeList* attrs) override;
OBJ_METHODS(PlayStateUpdate, FObject)
private:
@ -186,4 +206,36 @@ private:
mutable std::mutex mutex_;
};
/**
* @brief Update which automates a pack of parameters
*/
class AutomationUpdate : public Steinberg::FObject,
public IConvertibleToMessage<AutomationUpdate> {
public:
using Item = std::pair<Vst::ParamID, float>;
AutomationUpdate() = default;
void setItems(std::vector<Item> newItems)
{
std::lock_guard<std::mutex> lock(mutex_);
items_ = std::move(newItems);
}
std::vector<Item> getItems() const
{
std::lock_guard<std::mutex> lock(mutex_);
return items_;
}
bool saveToAttributes(Vst::IAttributeList* attrs) const override;
bool loadFromAttributes(Vst::IAttributeList* attrs) override;
OBJ_METHODS(AutomationUpdate, FObject)
private:
std::vector<Item> items_;
mutable std::mutex mutex_;
};
#include "SfizzVstUpdates.hpp"

View file

@ -10,7 +10,7 @@
template <class T>
IPtr<Vst::IMessage> IConvertibleToMessage<T>::convertToMessage(Vst::ComponentBase* sender) const
{
IPtr<Vst::IMessage> message = owned(sender->allocateMessage());
IPtr<Vst::IMessage> message = Steinberg::owned(sender->allocateMessage());
if (!message)
return nullptr;
message->setMessageID(static_cast<const T*>(this)->isA());
@ -20,13 +20,22 @@ IPtr<Vst::IMessage> IConvertibleToMessage<T>::convertToMessage(Vst::ComponentBas
}
template <class T>
IPtr<T> IConvertibleToMessage<T>::convertFromMessage(Vst::IMessage& message)
IPtr<T> IConvertibleToMessage<T>::createFromMessage(Vst::IMessage& message)
{
IPtr<T> object;
if (!strcmp(T::getFClassID(), message.getMessageID())) {
object = owned(new T);
object = Steinberg::owned(new T);
if (!object->loadFromAttributes(message.getAttributes()))
object = nullptr;
}
return object;
}
template <class T>
bool IConvertibleToMessage<T>::convertFromMessage(Vst::IMessage& message)
{
bool success = false;
if (!strcmp(T::getFClassID(), message.getMessageID()))
success = loadFromAttributes(message.getAttributes());
return success;
}