Display key events on VK, with VST
This commit is contained in:
parent
c5c7e2bb63
commit
34ca6d69e3
12 changed files with 207 additions and 11 deletions
|
|
@ -22,6 +22,9 @@ enum class EditId : int {
|
||||||
UserFilesDir,
|
UserFilesDir,
|
||||||
FallbackFilesDir,
|
FallbackFilesDir,
|
||||||
//
|
//
|
||||||
|
Key0,
|
||||||
|
KeyLast = Key0 + 128 - 1,
|
||||||
|
//
|
||||||
Controller0,
|
Controller0,
|
||||||
ControllerLast = Controller0 + sfz::config::numCCs - 1,
|
ControllerLast = Controller0 + sfz::config::numCCs - 1,
|
||||||
//
|
//
|
||||||
|
|
@ -58,3 +61,16 @@ inline bool editIdIsCC(EditId id)
|
||||||
return int(id) >= int(EditId::Controller0) &&
|
return int(id) >= int(EditId::Controller0) &&
|
||||||
int(id) <= int(EditId::ControllerLast);
|
int(id) <= int(EditId::ControllerLast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline EditId editIdForKey(int key)
|
||||||
|
{
|
||||||
|
return EditId(int(EditId::Key0) + key);
|
||||||
|
}
|
||||||
|
inline int keyForEditId(EditId id)
|
||||||
|
{
|
||||||
|
return int(id) - int(EditId::Key0);
|
||||||
|
}
|
||||||
|
inline bool editIdIsKey(EditId id)
|
||||||
|
{
|
||||||
|
return int(id) >= int(EditId::Key0) && int(id) <= int(EditId::KeyLast);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -387,6 +387,14 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v)
|
||||||
setActivePanel(value);
|
setActivePanel(value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
if (editIdIsKey(id)) {
|
||||||
|
const int key = keyForEditId(id);
|
||||||
|
const float value = v.to_float();
|
||||||
|
if (SPiano* piano = piano_)
|
||||||
|
piano->setKeyValue(key, value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,20 @@ void SPiano::setKeyUsed(unsigned key, bool used)
|
||||||
invalid();
|
invalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SPiano::setKeyValue(unsigned key, float value)
|
||||||
|
{
|
||||||
|
if (key >= 128)
|
||||||
|
return;
|
||||||
|
|
||||||
|
value = std::max(0.0f, std::min(1.0f, value));
|
||||||
|
|
||||||
|
if (keyval_[key] == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
keyval_[key] = value;
|
||||||
|
invalid();
|
||||||
|
}
|
||||||
|
|
||||||
void SPiano::draw(CDrawContext* dc)
|
void SPiano::draw(CDrawContext* dc)
|
||||||
{
|
{
|
||||||
const Dimensions dim = getDimensions(false);
|
const Dimensions dim = getDimensions(false);
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ public:
|
||||||
void setNumOctaves(unsigned octs);
|
void setNumOctaves(unsigned octs);
|
||||||
|
|
||||||
void setKeyUsed(unsigned key, bool used);
|
void setKeyUsed(unsigned key, bool used);
|
||||||
|
void setKeyValue(unsigned key, float value);
|
||||||
|
|
||||||
std::function<void(unsigned, float)> onKeyPressed;
|
std::function<void(unsigned, float)> onKeyPressed;
|
||||||
std::function<void(unsigned, float)> onKeyReleased;
|
std::function<void(unsigned, float)> onKeyReleased;
|
||||||
|
|
@ -54,7 +55,7 @@ private:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned octs_ {};
|
unsigned octs_ {};
|
||||||
std::vector<unsigned> keyval_;
|
std::vector<float> keyval_;
|
||||||
std::bitset<128> keyUsed_;
|
std::bitset<128> keyUsed_;
|
||||||
unsigned mousePressedKey_ = ~0u;
|
unsigned mousePressedKey_ = ~0u;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context)
|
||||||
|
|
||||||
// create update objects
|
// create update objects
|
||||||
oscUpdate_ = Steinberg::owned(new OSCUpdate);
|
oscUpdate_ = Steinberg::owned(new OSCUpdate);
|
||||||
|
noteUpdate_ = Steinberg::owned(new NoteUpdate);
|
||||||
sfzPathUpdate_ = Steinberg::owned(new FilePathUpdate(kFilePathUpdateSfz));
|
sfzPathUpdate_ = Steinberg::owned(new FilePathUpdate(kFilePathUpdateSfz));
|
||||||
scalaPathUpdate_ = Steinberg::owned(new FilePathUpdate(kFilePathUpdateScala));
|
scalaPathUpdate_ = Steinberg::owned(new FilePathUpdate(kFilePathUpdateScala));
|
||||||
processorStateUpdate_ = Steinberg::owned(new ProcessorStateUpdate);
|
processorStateUpdate_ = Steinberg::owned(new ProcessorStateUpdate);
|
||||||
|
|
@ -283,6 +284,20 @@ tresult SfizzVstControllerNoUi::notify(Vst::IMessage* message)
|
||||||
oscUpdate_->changed();
|
oscUpdate_->changed();
|
||||||
oscUpdate_->clear();
|
oscUpdate_->clear();
|
||||||
}
|
}
|
||||||
|
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]);
|
||||||
|
|
||||||
|
// this is a synchronous send, because the update object gets reused
|
||||||
|
noteUpdate_->setEvents(events, numEvents, false);
|
||||||
|
noteUpdate_->changed();
|
||||||
|
noteUpdate_->clear();
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -307,6 +322,7 @@ IPlugView* PLUGIN_API SfizzVstController::createView(FIDString _name)
|
||||||
|
|
||||||
std::vector<FObject*> triggerUpdates;
|
std::vector<FObject*> triggerUpdates;
|
||||||
triggerUpdates.push_back(oscUpdate_);
|
triggerUpdates.push_back(oscUpdate_);
|
||||||
|
triggerUpdates.push_back(noteUpdate_);
|
||||||
|
|
||||||
IPtr<SfizzVstEditor> editor = Steinberg::owned(
|
IPtr<SfizzVstEditor> editor = Steinberg::owned(
|
||||||
new SfizzVstEditor(this, absl::MakeSpan(continuousUpdates), absl::MakeSpan(triggerUpdates)));
|
new SfizzVstEditor(this, absl::MakeSpan(continuousUpdates), absl::MakeSpan(triggerUpdates)));
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Steinberg::IPtr<OSCUpdate> oscUpdate_;
|
Steinberg::IPtr<OSCUpdate> oscUpdate_;
|
||||||
|
Steinberg::IPtr<NoteUpdate> noteUpdate_;
|
||||||
Steinberg::IPtr<FilePathUpdate> sfzPathUpdate_;
|
Steinberg::IPtr<FilePathUpdate> sfzPathUpdate_;
|
||||||
Steinberg::IPtr<FilePathUpdate> scalaPathUpdate_;
|
Steinberg::IPtr<FilePathUpdate> scalaPathUpdate_;
|
||||||
Steinberg::IPtr<ProcessorStateUpdate> processorStateUpdate_;
|
Steinberg::IPtr<ProcessorStateUpdate> processorStateUpdate_;
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ static ViewRect sfizzUiViewRect { 0, 0, Editor::viewWidth, Editor::viewHeight };
|
||||||
enum {
|
enum {
|
||||||
kOscTempSize = 8192,
|
kOscTempSize = 8192,
|
||||||
kOscQueueSize = 65536,
|
kOscQueueSize = 65536,
|
||||||
|
kNoteEventQueueSize = 8192,
|
||||||
};
|
};
|
||||||
|
|
||||||
SfizzVstEditor::SfizzVstEditor(
|
SfizzVstEditor::SfizzVstEditor(
|
||||||
|
|
@ -70,6 +71,12 @@ bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& p
|
||||||
oscQueue_.reset(queue);
|
oscQueue_.reset(queue);
|
||||||
queue->reserve(kOscQueueSize);
|
queue->reserve(kOscQueueSize);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(noteEventQueueMutex_);
|
||||||
|
NoteEventsVec* queue = new NoteEventsVec;
|
||||||
|
noteEventQueue_.reset(queue);
|
||||||
|
queue->reserve(kNoteEventQueueSize);
|
||||||
|
}
|
||||||
|
|
||||||
if (!frame->open(parent, platformType, config)) {
|
if (!frame->open(parent, platformType, config)) {
|
||||||
fprintf(stderr, "[sfizz] error opening frame\n");
|
fprintf(stderr, "[sfizz] error opening frame\n");
|
||||||
|
|
@ -116,8 +123,14 @@ void PLUGIN_API SfizzVstEditor::close()
|
||||||
this->frame = nullptr;
|
this->frame = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(oscQueueMutex_);
|
{
|
||||||
oscQueue_.reset();
|
std::lock_guard<std::mutex> lock(oscQueueMutex_);
|
||||||
|
oscQueue_.reset();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(noteEventQueueMutex_);
|
||||||
|
noteEventQueue_.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|
@ -144,6 +157,7 @@ CMessageResult SfizzVstEditor::notify(CBaseObject* sender, const char* message)
|
||||||
|
|
||||||
if (message == CVSTGUITimer::kMsgTimer) {
|
if (message == CVSTGUITimer::kMsgTimer) {
|
||||||
processOscQueue();
|
processOscQueue();
|
||||||
|
processNoteEventQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -163,6 +177,17 @@ void PLUGIN_API SfizzVstEditor::update(FUnknown* changedUnknown, int32 message)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (NoteUpdate* update = FCast<NoteUpdate>(changedUnknown)) {
|
||||||
|
// this update is synchronous: may happen from non-UI thread
|
||||||
|
uint32 count = update->count();
|
||||||
|
if (count > 0) {
|
||||||
|
const auto* events = update->events();
|
||||||
|
std::lock_guard<std::mutex> lock(noteEventQueueMutex_);
|
||||||
|
if (NoteEventsVec* queue = noteEventQueue_.get())
|
||||||
|
std::copy(events, events + count, std::back_inserter(*queue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (FilePathUpdate* update = FCast<FilePathUpdate>(changedUnknown)) {
|
if (FilePathUpdate* update = FCast<FilePathUpdate>(changedUnknown)) {
|
||||||
const std::string path = update->getPath();
|
const std::string path = update->getPath();
|
||||||
switch (update->getType()) {
|
switch (update->getType()) {
|
||||||
|
|
@ -259,6 +284,20 @@ void SfizzVstEditor::processOscQueue()
|
||||||
queue->clear();
|
queue->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SfizzVstEditor::processNoteEventQueue()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(noteEventQueueMutex_);
|
||||||
|
|
||||||
|
NoteEventsVec* queue = noteEventQueue_.get();
|
||||||
|
if (!queue)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (std::pair<uint32, float> event : *queue)
|
||||||
|
uiReceiveValue(editIdForKey(event.first), event.second);
|
||||||
|
|
||||||
|
queue->clear();
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v)
|
void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void processOscQueue();
|
void processOscQueue();
|
||||||
|
void processNoteEventQueue();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// EditorController
|
// EditorController
|
||||||
|
|
@ -77,6 +78,9 @@ private:
|
||||||
typedef std::vector<uint8_t> OscByteVec;
|
typedef std::vector<uint8_t> OscByteVec;
|
||||||
std::unique_ptr<OscByteVec> oscQueue_;
|
std::unique_ptr<OscByteVec> oscQueue_;
|
||||||
std::mutex oscQueueMutex_;
|
std::mutex oscQueueMutex_;
|
||||||
|
typedef std::vector<std::pair<uint32, float>> NoteEventsVec;
|
||||||
|
std::unique_ptr<NoteEventsVec> noteEventQueue_;
|
||||||
|
std::mutex noteEventQueueMutex_;
|
||||||
|
|
||||||
// subscribed updates
|
// subscribed updates
|
||||||
std::vector<IPtr<FObject>> continuousUpdates_;
|
std::vector<IPtr<FObject>> continuousUpdates_;
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,8 @@ tresult PLUGIN_API SfizzVstProcessor::initialize(FUnknown* context)
|
||||||
_synth->timePosition(0, 0, 0);
|
_synth->timePosition(0, 0, 0);
|
||||||
_synth->playbackState(0, 0);
|
_synth->playbackState(0, 0);
|
||||||
|
|
||||||
|
_noteEventsCurrentCycle.fill(-1.0f);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -281,6 +283,21 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data)
|
||||||
_semaToWorker.post();
|
_semaToWorker.post();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
std::pair<uint32, float> noteEvents[128];
|
||||||
|
size_t numNoteEvents = 0;
|
||||||
|
for (uint32 key = 0; key < 128; ++key) {
|
||||||
|
float value = _noteEventsCurrentCycle[key];
|
||||||
|
if (value < 0.0f)
|
||||||
|
continue;
|
||||||
|
noteEvents[numNoteEvents++] = std::make_pair(key, value);
|
||||||
|
_noteEventsCurrentCycle[key] = -1.0f;
|
||||||
|
}
|
||||||
|
if (numNoteEvents > 0) {
|
||||||
|
if (writeWorkerMessage("NoteEvents", noteEvents, numNoteEvents * sizeof(noteEvents[0])))
|
||||||
|
_semaToWorker.post();
|
||||||
|
}
|
||||||
|
|
||||||
return kResultTrue;
|
return kResultTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -422,15 +439,28 @@ void SfizzVstProcessor::processEvents(Vst::IEventList& events)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
switch (e.type) {
|
switch (e.type) {
|
||||||
case Vst::Event::kNoteOnEvent:
|
case Vst::Event::kNoteOnEvent: {
|
||||||
if (e.noteOn.velocity == 0.0f)
|
int pitch = e.noteOn.pitch;
|
||||||
synth.noteOff(e.sampleOffset, e.noteOn.pitch, 0);
|
if (pitch < 0 || pitch >= 128)
|
||||||
else
|
break;
|
||||||
synth.noteOn(e.sampleOffset, e.noteOn.pitch, convertVelocityFromFloat(e.noteOn.velocity));
|
if (e.noteOn.velocity <= 0.0f) {
|
||||||
|
synth.noteOff(e.sampleOffset, pitch, 0);
|
||||||
|
_noteEventsCurrentCycle[pitch] = 0.0f;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
synth.noteOn(e.sampleOffset, pitch, convertVelocityFromFloat(e.noteOn.velocity));
|
||||||
|
_noteEventsCurrentCycle[pitch] = e.noteOn.velocity;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Vst::Event::kNoteOffEvent:
|
}
|
||||||
synth.noteOff(e.sampleOffset, e.noteOff.pitch, convertVelocityFromFloat(e.noteOff.velocity));
|
case Vst::Event::kNoteOffEvent: {
|
||||||
|
int pitch = e.noteOn.pitch;
|
||||||
|
if (pitch < 0 || pitch >= 128)
|
||||||
|
break;
|
||||||
|
synth.noteOff(e.sampleOffset, pitch, convertVelocityFromFloat(e.noteOff.velocity));
|
||||||
|
_noteEventsCurrentCycle[pitch] = 0.0f;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
// case Vst::Event::kPolyPressureEvent:
|
// case Vst::Event::kPolyPressureEvent:
|
||||||
// synth.aftertouch(e.sampleOffset, convertVelocityFromFloat(e.polyPressure.pressure));
|
// synth.aftertouch(e.sampleOffset, convertVelocityFromFloat(e.polyPressure.pressure));
|
||||||
// break;
|
// break;
|
||||||
|
|
@ -574,7 +604,7 @@ FUnknown* SfizzVstProcessor::createInstance(void*)
|
||||||
void SfizzVstProcessor::receiveMessage(int delay, const char* path, const char* sig, const sfizz_arg_t* args)
|
void SfizzVstProcessor::receiveMessage(int delay, const char* path, const char* sig, const sfizz_arg_t* args)
|
||||||
{
|
{
|
||||||
uint8_t* oscTemp = _oscTemp.get();
|
uint8_t* oscTemp = _oscTemp.get();
|
||||||
uint32_t oscSize = sfizz_prepare_message(oscTemp, kOscTempSize, path, sig, args);
|
uint32 oscSize = sfizz_prepare_message(oscTemp, kOscTempSize, path, sig, args);
|
||||||
if (oscSize <= kOscTempSize) {
|
if (oscSize <= kOscTempSize) {
|
||||||
if (writeWorkerMessage("ReceiveMessage", oscTemp, oscSize))
|
if (writeWorkerMessage("ReceiveMessage", oscTemp, oscSize))
|
||||||
_semaToWorker.post();
|
_semaToWorker.post();
|
||||||
|
|
@ -650,6 +680,12 @@ void SfizzVstProcessor::doBackgroundWork()
|
||||||
notification->getAttributes()->setBinary("Message", msg->payload<uint8_t>(), msg->size);
|
notification->getAttributes()->setBinary("Message", msg->payload<uint8_t>(), msg->size);
|
||||||
sendMessage(notification);
|
sendMessage(notification);
|
||||||
}
|
}
|
||||||
|
else if (!std::strcmp(id, "NoteEvents")) {
|
||||||
|
Steinberg::OPtr<Vst::IMessage> notification { allocateMessage() };
|
||||||
|
notification->setMessageID("NoteEvents");
|
||||||
|
notification->getAttributes()->setBinary("Events", msg->payload<uint8_t>(), msg->size);
|
||||||
|
sendMessage(notification);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include "public.sdk/source/vst/vstaudioeffect.h"
|
#include "public.sdk/source/vst/vstaudioeffect.h"
|
||||||
#include <sfizz.hpp>
|
#include <sfizz.hpp>
|
||||||
#include <SpinMutex.h>
|
#include <SpinMutex.h>
|
||||||
|
#include <array>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
@ -60,6 +61,9 @@ private:
|
||||||
// misc
|
// misc
|
||||||
static void loadSfzFileOrDefault(sfz::Sfizz& synth, const std::string& filePath);
|
static void loadSfzFileOrDefault(sfz::Sfizz& synth, const std::string& filePath);
|
||||||
|
|
||||||
|
// note event tracking
|
||||||
|
std::array<float, 128> _noteEventsCurrentCycle; // 0: off, >0: on, <0: no change
|
||||||
|
|
||||||
// worker and thread sync
|
// worker and thread sync
|
||||||
std::thread _worker;
|
std::thread _worker;
|
||||||
volatile bool _workRunning = false;
|
volatile bool _workRunning = false;
|
||||||
|
|
|
||||||
|
|
@ -35,3 +35,33 @@ void OSCUpdate::setMessage(const void* data, uint32_t size, bool copy)
|
||||||
size_ = size;
|
size_ = size;
|
||||||
allocated_ = copy;
|
allocated_ = copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
NoteUpdate::~NoteUpdate()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoteUpdate::clear()
|
||||||
|
{
|
||||||
|
if (allocated_)
|
||||||
|
delete[] events_;
|
||||||
|
events_ = nullptr;
|
||||||
|
count_ = 0;
|
||||||
|
allocated_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoteUpdate::setEvents(const std::pair<uint32_t, float>* events, uint32_t count, bool copy)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
|
||||||
|
if (copy) {
|
||||||
|
auto *buffer = new std::pair<uint32_t, float>[count];
|
||||||
|
std::memcpy(buffer, events, count);
|
||||||
|
events = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
events_ = events;
|
||||||
|
count_ = count;
|
||||||
|
allocated_ = copy;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,33 @@ private:
|
||||||
OSCUpdate& operator=(const OSCUpdate&) = delete;
|
OSCUpdate& operator=(const OSCUpdate&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update which notifies one or more note on/off events
|
||||||
|
* Is is supposed to be used synchronously.
|
||||||
|
* (ie. FObject::changed or UpdateHandler::triggerUpdates)
|
||||||
|
*/
|
||||||
|
class NoteUpdate : public Steinberg::FObject {
|
||||||
|
public:
|
||||||
|
NoteUpdate() = default;
|
||||||
|
~NoteUpdate();
|
||||||
|
void clear();
|
||||||
|
void setEvents(const std::pair<uint32_t, float>* events, uint32_t count, bool copy);
|
||||||
|
|
||||||
|
const std::pair<uint32_t, float>* events() const noexcept { return events_; }
|
||||||
|
const uint32_t count() const noexcept { return count_; }
|
||||||
|
|
||||||
|
OBJ_METHODS(NoteUpdate, FObject)
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::pair<uint32_t, float>* events_ = nullptr;
|
||||||
|
uint32_t count_ = 0;
|
||||||
|
bool allocated_ = false;
|
||||||
|
|
||||||
|
private:
|
||||||
|
NoteUpdate(const NoteUpdate&) = delete;
|
||||||
|
NoteUpdate& operator=(const NoteUpdate&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Update which notifies a change of file path pseudo-parameter
|
* @brief Update which notifies a change of file path pseudo-parameter
|
||||||
* The message ID is used to indicate which path it is.
|
* The message ID is used to indicate which path it is.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue