CC automations for VST, saving and loading
This commit is contained in:
parent
ba8227de24
commit
087180db41
10 changed files with 149 additions and 155 deletions
|
|
@ -306,12 +306,6 @@ void Editor::close()
|
|||
}
|
||||
}
|
||||
|
||||
void Editor::sendQueuedOSC(const char* path, const char* sig, const sfizz_arg_t* args)
|
||||
{
|
||||
Impl& impl = *impl_;
|
||||
impl.sendQueuedOSC(path, sig, args);
|
||||
}
|
||||
|
||||
void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v)
|
||||
{
|
||||
switch (id) {
|
||||
|
|
@ -488,12 +482,6 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v)
|
|||
else if (editIdIsCCUsed(id)) {
|
||||
bool used = v.to_float() != 0;
|
||||
updateCCUsed(ccUsedForEditId(id), used);
|
||||
// TODO(jpc) remove value requests, when implementing CC automation
|
||||
if (used) {
|
||||
char pathBuf[256];
|
||||
sprintf(pathBuf, "/cc%u/value", ccUsedForEditId(id));
|
||||
sendQueuedOSC(pathBuf, "", nullptr);
|
||||
}
|
||||
}
|
||||
else if (editIdIsCCDefault(id)) {
|
||||
updateCCDefaultValue(ccDefaultForEditId(id), v.to_float());
|
||||
|
|
@ -509,22 +497,7 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi
|
|||
{
|
||||
unsigned indices[8];
|
||||
|
||||
if (Messages::matchOSC("/cc/changed~", path, indices) && !strcmp(sig, "b")) {
|
||||
size_t numBits = 8 * args[0].b->size;
|
||||
ConstBitSpan bits { args[0].b->data, numBits };
|
||||
for (unsigned cc = 0; cc < numBits; ++cc) {
|
||||
bool changed = bits.test(cc);
|
||||
if (changed) {
|
||||
char pathBuf[256];
|
||||
sprintf(pathBuf, "/cc%u/value", cc);
|
||||
sendQueuedOSC(pathBuf, "", nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Messages::matchOSC("/cc&/value", path, indices) && !strcmp(sig, "f")) {
|
||||
updateCCValue(indices[0], args[0].f);
|
||||
}
|
||||
else if (Messages::matchOSC("/sw/last/current", path, indices) && !strcmp(sig, "i")) {
|
||||
if (Messages::matchOSC("/sw/last/current", path, indices) && !strcmp(sig, "i")) {
|
||||
updateSWLastCurrent(args[0].i);
|
||||
}
|
||||
else if (Messages::matchOSC("/sw/last/current", path, indices) && !strcmp(sig, "N")) {
|
||||
|
|
|
|||
|
|
@ -25,9 +25,6 @@ public:
|
|||
void open(CFrame& frame);
|
||||
void close();
|
||||
|
||||
// TODO(jpc) remove me after doing parameter automations
|
||||
void sendQueuedOSC(const char* path, const char* sig, const sfizz_arg_t* args);
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl_;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context)
|
|||
sfzUpdate_ = Steinberg::owned(new SfzUpdate);
|
||||
sfzDescriptionUpdate_ = Steinberg::owned(new SfzDescriptionUpdate);
|
||||
scalaUpdate_ = Steinberg::owned(new ScalaUpdate);
|
||||
processorStateUpdate_ = Steinberg::owned(new ProcessorStateUpdate);
|
||||
playStateUpdate_ = Steinberg::owned(new PlayStateUpdate);
|
||||
|
||||
// Parameters
|
||||
|
|
@ -73,8 +72,9 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context)
|
|||
shortTitle.printf("CC%u", i);
|
||||
|
||||
parameters.addParameter(
|
||||
title, nullptr, 0, 0, Vst::ParameterInfo::kNoFlags,
|
||||
pid++, Vst::kRootUnitId, shortTitle);
|
||||
SfizzRange::getForParameter(kPidStretchedTuning).createParameter(
|
||||
title, pid++, nullptr, 0, Vst::ParameterInfo::kCanAutomate,
|
||||
Vst::kRootUnitId, shortTitle));
|
||||
}
|
||||
|
||||
// Initial MIDI mapping
|
||||
|
|
@ -158,42 +158,6 @@ tresult SfizzVstControllerNoUi::setParam(Vst::ParamID tag, float value)
|
|||
return setParamNormalized(tag, range.normalize(value));
|
||||
}
|
||||
|
||||
tresult PLUGIN_API SfizzVstControllerNoUi::setParamNormalized(Vst::ParamID tag, Vst::ParamValue normValue)
|
||||
{
|
||||
tresult r = EditController::setParamNormalized(tag, normValue);
|
||||
if (r != kResultTrue)
|
||||
return r;
|
||||
|
||||
processorStateUpdate_->access([tag, normValue](SfizzVstState& state) {
|
||||
const SfizzRange range = SfizzRange::getForParameter(tag);
|
||||
switch (tag) {
|
||||
case kPidVolume:
|
||||
state.volume = range.denormalize(normValue);
|
||||
break;
|
||||
case kPidNumVoices:
|
||||
state.numVoices = (int32)range.denormalize(normValue);
|
||||
break;
|
||||
case kPidOversampling:
|
||||
state.oversamplingLog2 = (int32)range.denormalize(normValue);
|
||||
break;
|
||||
case kPidPreloadSize:
|
||||
state.preloadSize = (int32)range.denormalize(normValue);
|
||||
break;
|
||||
case kPidScalaRootKey:
|
||||
state.scalaRootKey = (int32)range.denormalize(normValue);
|
||||
break;
|
||||
case kPidTuningFrequency:
|
||||
state.tuningFrequency = (float)range.denormalize(normValue);
|
||||
break;
|
||||
case kPidStretchedTuning:
|
||||
state.stretchedTuning = range.denormalize(normValue);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
tresult PLUGIN_API SfizzVstControllerNoUi::setComponentState(IBStream* stream)
|
||||
{
|
||||
SfizzVstState s;
|
||||
|
|
@ -202,8 +166,6 @@ tresult PLUGIN_API SfizzVstControllerNoUi::setComponentState(IBStream* stream)
|
|||
if (r != kResultTrue)
|
||||
return r;
|
||||
|
||||
processorStateUpdate_->setState(s);
|
||||
|
||||
setParam(kPidVolume, s.volume);
|
||||
setParam(kPidNumVoices, s.numVoices);
|
||||
setParam(kPidOversampling, s.oversamplingLog2);
|
||||
|
|
@ -212,6 +174,12 @@ tresult PLUGIN_API SfizzVstControllerNoUi::setComponentState(IBStream* stream)
|
|||
setParam(kPidTuningFrequency, s.tuningFrequency);
|
||||
setParam(kPidStretchedTuning, s.stretchedTuning);
|
||||
|
||||
uint32 ccLimit = uint32(std::min(s.controllers.size(), size_t(sfz::config::numCCs)));
|
||||
for (uint32 cc = 0; cc < ccLimit; ++cc) {
|
||||
if (absl::optional<float> value = s.controllers[cc])
|
||||
setParam(kPidCC0 + cc, *value);
|
||||
}
|
||||
|
||||
sfzUpdate_->setPath(s.sfzFile);
|
||||
sfzUpdate_->deferUpdate();
|
||||
scalaUpdate_->setPath(s.scalaFile);
|
||||
|
|
@ -254,9 +222,6 @@ tresult SfizzVstControllerNoUi::notify(Vst::IMessage* message)
|
|||
if (result != kResultTrue)
|
||||
return result;
|
||||
|
||||
processorStateUpdate_->access([sfzFile](SfizzVstState& state) {
|
||||
state.sfzFile = std::string(sfzFile);
|
||||
});
|
||||
sfzUpdate_->setPath(std::string(sfzFile));
|
||||
sfzUpdate_->deferUpdate();
|
||||
sfzDescriptionUpdate_->setDescription(std::string(sfzDescriptionBlob));
|
||||
|
|
@ -269,9 +234,6 @@ tresult SfizzVstControllerNoUi::notify(Vst::IMessage* message)
|
|||
if (result != kResultTrue)
|
||||
return result;
|
||||
|
||||
processorStateUpdate_->access([scalaFile](SfizzVstState& state) {
|
||||
state.scalaFile = std::string(scalaFile);
|
||||
});
|
||||
scalaUpdate_->setPath(std::string(scalaFile));
|
||||
scalaUpdate_->deferUpdate();
|
||||
}
|
||||
|
|
@ -313,6 +275,25 @@ tresult SfizzVstControllerNoUi::notify(Vst::IMessage* message)
|
|||
noteUpdate_->changed();
|
||||
noteUpdate_->clear();
|
||||
}
|
||||
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 (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);
|
||||
setParam(pid, value);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ public:
|
|||
tresult PLUGIN_API getParamValueByString(Vst::ParamID tag, Vst::TChar* string, Vst::ParamValue& valueNormalized) override;
|
||||
|
||||
tresult setParam(Vst::ParamID tag, float value);
|
||||
tresult PLUGIN_API setParamNormalized(Vst::ParamID tag, Vst::ParamValue value) override;
|
||||
tresult PLUGIN_API setComponentState(IBStream* stream) override;
|
||||
tresult PLUGIN_API notify(Vst::IMessage* message) override;
|
||||
|
||||
|
|
@ -50,7 +49,6 @@ protected:
|
|||
Steinberg::IPtr<SfzUpdate> sfzUpdate_;
|
||||
Steinberg::IPtr<SfzDescriptionUpdate> sfzDescriptionUpdate_;
|
||||
Steinberg::IPtr<ScalaUpdate> scalaUpdate_;
|
||||
Steinberg::IPtr<ProcessorStateUpdate> processorStateUpdate_;
|
||||
Steinberg::IPtr<PlayStateUpdate> playStateUpdate_;
|
||||
Vst::ParamID midiMapping_[Vst::kCountCtrlNumber] {};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -188,11 +188,13 @@ void PLUGIN_API SfizzVstEditor::update(FUnknown* changedUnknown, int32 message)
|
|||
if (NoteEventsVec* queue = noteEventQueue_.get())
|
||||
std::copy(events, events + count, std::back_inserter(*queue));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (SfzUpdate* update = FCast<SfzUpdate>(changedUnknown)) {
|
||||
const std::string path = update->getPath();
|
||||
uiReceiveValue(EditId::SfzFile, path);
|
||||
return;
|
||||
}
|
||||
|
||||
if (SfzDescriptionUpdate* update = FCast<SfzDescriptionUpdate>(changedUnknown)) {
|
||||
|
|
@ -227,24 +229,13 @@ void PLUGIN_API SfizzVstEditor::update(FUnknown* changedUnknown, int32 message)
|
|||
uiReceiveValue(editIdForCCLabel(int(cc)), desc.ccLabel[cc]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ScalaUpdate* update = FCast<ScalaUpdate>(changedUnknown)) {
|
||||
const std::string path = update->getPath();
|
||||
uiReceiveValue(EditId::ScalaFile, path);
|
||||
}
|
||||
|
||||
if (ProcessorStateUpdate* update = FCast<ProcessorStateUpdate>(changedUnknown)) {
|
||||
const SfizzVstState state = update->getState();
|
||||
uiReceiveValue(EditId::SfzFile, state.sfzFile);
|
||||
uiReceiveValue(EditId::Volume, state.volume);
|
||||
uiReceiveValue(EditId::Polyphony, state.numVoices);
|
||||
uiReceiveValue(EditId::Oversampling, float(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);
|
||||
return;
|
||||
}
|
||||
|
||||
if (PlayStateUpdate* update = FCast<PlayStateUpdate>(changedUnknown)) {
|
||||
|
|
@ -279,6 +270,12 @@ void PLUGIN_API SfizzVstEditor::update(FUnknown* changedUnknown, int32 message)
|
|||
case kPidStretchedTuning:
|
||||
uiReceiveValue(EditId::StretchTuning, range.denormalize(value));
|
||||
break;
|
||||
default:
|
||||
if (id >= kPidCC0 && id <= kPidCCLast) {
|
||||
int cc = id - kPidCC0;
|
||||
uiReceiveValue(editIdForCC(cc), range.denormalize(value));
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -329,18 +326,7 @@ void SfizzVstEditor::processNoteEventQueue()
|
|||
///
|
||||
void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v)
|
||||
{
|
||||
if (editIdIsCC(id)) {
|
||||
int cc = ccForEditId(id);
|
||||
// TODO(jpc) CC as parameters and automation
|
||||
if (Editor* editor = editor_.get()) {
|
||||
char pathBuf[256];
|
||||
sprintf(pathBuf, "/cc%u/value", cc);
|
||||
sfizz_arg_t args[1];
|
||||
args[0].f = v.to_float();
|
||||
editor->sendQueuedOSC(pathBuf, "f", args);
|
||||
}
|
||||
}
|
||||
else if (id == EditId::SfzFile)
|
||||
if (id == EditId::SfzFile)
|
||||
loadSfzFile(v.to_string());
|
||||
else if (id == EditId::ScalaFile)
|
||||
loadScalaFile(v.to_string());
|
||||
|
|
@ -384,6 +370,8 @@ void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v)
|
|||
break;
|
||||
|
||||
default:
|
||||
if (editIdIsCC(id))
|
||||
normalizeAndSet(kPidCC0 + ccForEditId(id), v.to_float());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -482,6 +470,9 @@ Vst::ParamID SfizzVstEditor::parameterOfEditId(EditId id)
|
|||
case EditId::ScalaRootKey: return kPidScalaRootKey;
|
||||
case EditId::TuningFrequency: return kPidTuningFrequency;
|
||||
case EditId::StretchTuning: return kPidStretchedTuning;
|
||||
default: return Vst::kNoParamId;
|
||||
default:
|
||||
if (editIdIsCC(id))
|
||||
return kPidCC0 + ccForEditId(id);
|
||||
return Vst::kNoParamId;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,6 +84,9 @@ tresult PLUGIN_API SfizzVstProcessor::initialize(FUnknown* context)
|
|||
|
||||
_state = SfizzVstState();
|
||||
|
||||
// allocate needed space to track CC values
|
||||
_state.controllers.resize(sfz::config::numCCs);
|
||||
|
||||
fprintf(stderr, "[sfizz] new synth\n");
|
||||
_synth.reset(new sfz::Sfizz);
|
||||
|
||||
|
|
@ -97,7 +100,7 @@ tresult PLUGIN_API SfizzVstProcessor::initialize(FUnknown* context)
|
|||
_synth->setBroadcastCallback(onMessage, this);
|
||||
|
||||
_currentStretchedTuning = 0.0;
|
||||
loadSfzFileOrDefault({});
|
||||
loadSfzFileOrDefault({}, false);
|
||||
|
||||
_synth->tempo(0, 0.5);
|
||||
_timeSigNumerator = 4;
|
||||
|
|
@ -130,6 +133,8 @@ tresult PLUGIN_API SfizzVstProcessor::connect(IConnectionPoint* other)
|
|||
// when controller connects, send these messages that we couldn't earlier
|
||||
if (_loadedSfzMessage)
|
||||
sendMessage(_loadedSfzMessage);
|
||||
if (_automateMessage)
|
||||
sendMessage(_automateMessage);
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
|
@ -168,6 +173,9 @@ tresult PLUGIN_API SfizzVstProcessor::setState(IBStream* stream)
|
|||
std::lock_guard<SpinMutex> lock(_processMutex);
|
||||
_state = s;
|
||||
|
||||
// allocate needed space to track CC values
|
||||
_state.controllers.resize(sfz::config::numCCs);
|
||||
|
||||
syncStateToSynth();
|
||||
|
||||
return r;
|
||||
|
|
@ -186,7 +194,7 @@ void SfizzVstProcessor::syncStateToSynth()
|
|||
if (!synth)
|
||||
return;
|
||||
|
||||
loadSfzFileOrDefault(_state.sfzFile);
|
||||
loadSfzFileOrDefault(_state.sfzFile, true);
|
||||
synth->setVolume(_state.volume);
|
||||
synth->setNumVoices(_state.numVoices);
|
||||
synth->setOversamplingFactor(1 << _state.oversamplingLog2);
|
||||
|
|
@ -284,7 +292,6 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data)
|
|||
|
||||
// Request OSC updates
|
||||
sfz::Client& client = *_client;
|
||||
synth.sendMessage(client, 0, "/cc/changed~", "", nullptr);
|
||||
synth.sendMessage(client, 0, "/sw/last/current", "", nullptr);
|
||||
|
||||
//
|
||||
|
|
@ -409,8 +416,10 @@ void SfizzVstProcessor::processControllerChanges(Vst::IParameterChanges& pc)
|
|||
if (id >= kPidCC0 && id <= kPidCCLast) {
|
||||
auto ccNumber = static_cast<int>(id - kPidCC0);
|
||||
for (uint32 pointIndex = 0; pointIndex < pointCount; ++pointIndex) {
|
||||
if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue)
|
||||
if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue) {
|
||||
synth.hdcc(sampleOffset, ccNumber, value);
|
||||
_state.controllers[ccNumber] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -561,7 +570,7 @@ tresult PLUGIN_API SfizzVstProcessor::notify(Vst::IMessage* message)
|
|||
|
||||
std::unique_lock<SpinMutex> lock(_processMutex);
|
||||
_state.sfzFile.assign(static_cast<const char *>(data), size);
|
||||
loadSfzFileOrDefault(_state.sfzFile);
|
||||
loadSfzFileOrDefault(_state.sfzFile, false);
|
||||
lock.unlock();
|
||||
}
|
||||
else if (!std::strcmp(id, "LoadScala")) {
|
||||
|
|
@ -614,7 +623,7 @@ void SfizzVstProcessor::receiveMessage(int delay, const char* path, const char*
|
|||
}
|
||||
}
|
||||
|
||||
void SfizzVstProcessor::loadSfzFileOrDefault(const std::string& filePath)
|
||||
void SfizzVstProcessor::loadSfzFileOrDefault(const std::string& filePath, bool initParametersFromState)
|
||||
{
|
||||
sfz::Sfizz& synth = *_synth;
|
||||
|
||||
|
|
@ -634,18 +643,56 @@ void SfizzVstProcessor::loadSfzFileOrDefault(const std::string& filePath)
|
|||
synth.loadSfzString("default.sfz", defaultSfzText);
|
||||
}
|
||||
|
||||
const std::string desc = getDescriptionBlob(synth.handle());
|
||||
const std::string descBlob = getDescriptionBlob(synth.handle());
|
||||
|
||||
Steinberg::OPtr<Vst::IMessage> message { allocateMessage() };
|
||||
message->setMessageID("LoadedSfz");
|
||||
Vst::IAttributeList* attrs = message->getAttributes();
|
||||
attrs->setBinary("File", filePath.data(), filePath.size());
|
||||
attrs->setBinary("Description", desc.data(), desc.size());
|
||||
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);
|
||||
// collect initial CC from instrument
|
||||
const InstrumentDescription desc = parseDescriptionBlob(descBlob);
|
||||
for (uint32 cc = 0; cc < sfz::config::numCCs; ++cc) {
|
||||
if (desc.ccUsed.test(cc))
|
||||
newControllers[cc] = desc.ccDefault[cc];
|
||||
}
|
||||
// set CC from existing state
|
||||
if (initParametersFromState) {
|
||||
for (uint32 cc = 0; cc < sfz::config::numCCs; ++cc) {
|
||||
if (absl::optional<float> value = oldControllers[cc]) {
|
||||
newControllers[cc] = *value;
|
||||
synth.hdcc(0, int(cc), *value);
|
||||
}
|
||||
}
|
||||
}
|
||||
_state.controllers = std::move(newControllers);
|
||||
}
|
||||
|
||||
// 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)));
|
||||
for (uint32 cc = 0; cc < sfz::config::numCCs; ++cc) {
|
||||
uint32 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));
|
||||
}
|
||||
automateAttrs->setBinary("Data", automateBlob.data(), uint32(automateBlob.size()));
|
||||
|
||||
// sending can fail if controller is not connected yet, so keep it around
|
||||
_loadedSfzMessage = message;
|
||||
_loadedSfzMessage = loadMessage;
|
||||
_automateMessage = automateMessage;
|
||||
|
||||
sendMessage(message);
|
||||
// send message
|
||||
sendMessage(loadMessage);
|
||||
sendMessage(automateMessage);
|
||||
}
|
||||
|
||||
void SfizzVstProcessor::doBackgroundWork()
|
||||
|
|
@ -726,7 +773,7 @@ void SfizzVstProcessor::doBackgroundIdle(size_t idleCounter)
|
|||
if (_synth->shouldReloadFile()) {
|
||||
fprintf(stderr, "[Sfizz] sfz file has changed, reloading\n");
|
||||
std::lock_guard<SpinMutex> lock(_processMutex);
|
||||
loadSfzFileOrDefault(_state.sfzFile);
|
||||
loadSfzFileOrDefault(_state.sfzFile, false);
|
||||
}
|
||||
if (_synth->shouldReloadScala()) {
|
||||
fprintf(stderr, "[Sfizz] scala file has changed, reloading\n");
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ 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;
|
||||
|
|
@ -62,7 +63,7 @@ private:
|
|||
void receiveMessage(int delay, const char* path, const char* sig, const sfizz_arg_t* args);
|
||||
|
||||
// misc
|
||||
void loadSfzFileOrDefault(const std::string& filePath);
|
||||
void loadSfzFileOrDefault(const std::string& filePath, bool initParametersFromState);
|
||||
|
||||
// note event tracking
|
||||
std::array<float, 128> _noteEventsCurrentCycle; // 0: off, >0: on, <0: no change
|
||||
|
|
|
|||
|
|
@ -58,7 +58,26 @@ tresult SfizzVstState::load(IBStream* state)
|
|||
stretchedTuning = defaults.stretchedTuning;
|
||||
}
|
||||
|
||||
if (version > 1)
|
||||
controllers.clear();
|
||||
if (version >= 2) {
|
||||
uint32 count;
|
||||
if (!s.readInt32u(count))
|
||||
return kResultFalse;
|
||||
controllers.resize(0x10000);
|
||||
uint32 size = 0;
|
||||
for (uint32 i = 0; i < count; ++i) {
|
||||
uint16 cc;
|
||||
float value;
|
||||
if (!s.readInt16u(cc) || !s.readFloat(value))
|
||||
return kResultFalse;
|
||||
controllers[cc] = value;
|
||||
size = std::max(size, uint32(cc) + 1);
|
||||
}
|
||||
controllers.resize(size);
|
||||
controllers.shrink_to_fit();
|
||||
}
|
||||
|
||||
if (version > 2)
|
||||
return kResultFalse;
|
||||
|
||||
return kResultTrue;
|
||||
|
|
@ -98,6 +117,21 @@ tresult SfizzVstState::store(IBStream* state) const
|
|||
if (!s.writeFloat(stretchedTuning))
|
||||
return kResultFalse;
|
||||
|
||||
{
|
||||
uint32 ccCount = 0;
|
||||
uint32 ccLimit = uint32(std::min(controllers.size(), size_t(0x10000)));
|
||||
for (uint32_t cc = 0; cc < ccLimit; ++cc)
|
||||
ccCount += controllers[cc] != absl::nullopt;
|
||||
if (!s.writeInt32u(ccCount))
|
||||
return kResultFalse;
|
||||
for (uint32_t cc = 0; cc < ccLimit; ++cc) {
|
||||
if (absl::optional<float> ccValue = controllers[cc]) {
|
||||
if (!s.writeInt16u(uint16(cc)) || !s.writeFloat(*ccValue))
|
||||
return kResultFalse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
#pragma once
|
||||
#include "base/source/fstreamer.h"
|
||||
#include <absl/types/optional.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace Steinberg;
|
||||
|
||||
|
|
@ -23,8 +25,9 @@ public:
|
|||
int32 scalaRootKey = 60;
|
||||
float tuningFrequency = 440.0;
|
||||
float stretchedTuning = 0.0;
|
||||
std::vector<absl::optional<float>> controllers;
|
||||
|
||||
static constexpr uint64 currentStateVersion = 1;
|
||||
static constexpr uint64 currentStateVersion = 2;
|
||||
|
||||
tresult load(IBStream* state);
|
||||
tresult store(IBStream* state) const;
|
||||
|
|
|
|||
|
|
@ -138,37 +138,6 @@ private:
|
|||
mutable std::mutex mutex_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Update which indicates the processor status.
|
||||
*/
|
||||
class ProcessorStateUpdate : public Steinberg::FObject {
|
||||
public:
|
||||
void setState(SfizzVstState newState)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
state_ = std::move(newState);
|
||||
}
|
||||
|
||||
SfizzVstState getState() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
return state_;
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void access(F&& fn)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
fn(state_);
|
||||
}
|
||||
|
||||
OBJ_METHODS(ProcessorStateUpdate, FObject)
|
||||
|
||||
private:
|
||||
SfizzVstState state_;
|
||||
mutable std::mutex mutex_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Update which indicates the playing SFZ status.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue