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)
|
void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v)
|
||||||
{
|
{
|
||||||
switch (id) {
|
switch (id) {
|
||||||
|
|
@ -488,12 +482,6 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v)
|
||||||
else if (editIdIsCCUsed(id)) {
|
else if (editIdIsCCUsed(id)) {
|
||||||
bool used = v.to_float() != 0;
|
bool used = v.to_float() != 0;
|
||||||
updateCCUsed(ccUsedForEditId(id), used);
|
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)) {
|
else if (editIdIsCCDefault(id)) {
|
||||||
updateCCDefaultValue(ccDefaultForEditId(id), v.to_float());
|
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];
|
unsigned indices[8];
|
||||||
|
|
||||||
if (Messages::matchOSC("/cc/changed~", path, indices) && !strcmp(sig, "b")) {
|
if (Messages::matchOSC("/sw/last/current", path, indices) && !strcmp(sig, "i")) {
|
||||||
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")) {
|
|
||||||
updateSWLastCurrent(args[0].i);
|
updateSWLastCurrent(args[0].i);
|
||||||
}
|
}
|
||||||
else if (Messages::matchOSC("/sw/last/current", path, indices) && !strcmp(sig, "N")) {
|
else if (Messages::matchOSC("/sw/last/current", path, indices) && !strcmp(sig, "N")) {
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,6 @@ public:
|
||||||
void open(CFrame& frame);
|
void open(CFrame& frame);
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
// TODO(jpc) remove me after doing parameter automations
|
|
||||||
void sendQueuedOSC(const char* path, const char* sig, const sfizz_arg_t* args);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Impl;
|
struct Impl;
|
||||||
std::unique_ptr<Impl> impl_;
|
std::unique_ptr<Impl> impl_;
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context)
|
||||||
sfzUpdate_ = Steinberg::owned(new SfzUpdate);
|
sfzUpdate_ = Steinberg::owned(new SfzUpdate);
|
||||||
sfzDescriptionUpdate_ = Steinberg::owned(new SfzDescriptionUpdate);
|
sfzDescriptionUpdate_ = Steinberg::owned(new SfzDescriptionUpdate);
|
||||||
scalaUpdate_ = Steinberg::owned(new ScalaUpdate);
|
scalaUpdate_ = Steinberg::owned(new ScalaUpdate);
|
||||||
processorStateUpdate_ = Steinberg::owned(new ProcessorStateUpdate);
|
|
||||||
playStateUpdate_ = Steinberg::owned(new PlayStateUpdate);
|
playStateUpdate_ = Steinberg::owned(new PlayStateUpdate);
|
||||||
|
|
||||||
// Parameters
|
// Parameters
|
||||||
|
|
@ -73,8 +72,9 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context)
|
||||||
shortTitle.printf("CC%u", i);
|
shortTitle.printf("CC%u", i);
|
||||||
|
|
||||||
parameters.addParameter(
|
parameters.addParameter(
|
||||||
title, nullptr, 0, 0, Vst::ParameterInfo::kNoFlags,
|
SfizzRange::getForParameter(kPidStretchedTuning).createParameter(
|
||||||
pid++, Vst::kRootUnitId, shortTitle);
|
title, pid++, nullptr, 0, Vst::ParameterInfo::kCanAutomate,
|
||||||
|
Vst::kRootUnitId, shortTitle));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial MIDI mapping
|
// Initial MIDI mapping
|
||||||
|
|
@ -158,42 +158,6 @@ tresult SfizzVstControllerNoUi::setParam(Vst::ParamID tag, float value)
|
||||||
return setParamNormalized(tag, range.normalize(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)
|
tresult PLUGIN_API SfizzVstControllerNoUi::setComponentState(IBStream* stream)
|
||||||
{
|
{
|
||||||
SfizzVstState s;
|
SfizzVstState s;
|
||||||
|
|
@ -202,8 +166,6 @@ tresult PLUGIN_API SfizzVstControllerNoUi::setComponentState(IBStream* stream)
|
||||||
if (r != kResultTrue)
|
if (r != kResultTrue)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
processorStateUpdate_->setState(s);
|
|
||||||
|
|
||||||
setParam(kPidVolume, s.volume);
|
setParam(kPidVolume, s.volume);
|
||||||
setParam(kPidNumVoices, s.numVoices);
|
setParam(kPidNumVoices, s.numVoices);
|
||||||
setParam(kPidOversampling, s.oversamplingLog2);
|
setParam(kPidOversampling, s.oversamplingLog2);
|
||||||
|
|
@ -212,6 +174,12 @@ tresult PLUGIN_API SfizzVstControllerNoUi::setComponentState(IBStream* stream)
|
||||||
setParam(kPidTuningFrequency, s.tuningFrequency);
|
setParam(kPidTuningFrequency, s.tuningFrequency);
|
||||||
setParam(kPidStretchedTuning, s.stretchedTuning);
|
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_->setPath(s.sfzFile);
|
||||||
sfzUpdate_->deferUpdate();
|
sfzUpdate_->deferUpdate();
|
||||||
scalaUpdate_->setPath(s.scalaFile);
|
scalaUpdate_->setPath(s.scalaFile);
|
||||||
|
|
@ -254,9 +222,6 @@ tresult SfizzVstControllerNoUi::notify(Vst::IMessage* message)
|
||||||
if (result != kResultTrue)
|
if (result != kResultTrue)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
processorStateUpdate_->access([sfzFile](SfizzVstState& state) {
|
|
||||||
state.sfzFile = std::string(sfzFile);
|
|
||||||
});
|
|
||||||
sfzUpdate_->setPath(std::string(sfzFile));
|
sfzUpdate_->setPath(std::string(sfzFile));
|
||||||
sfzUpdate_->deferUpdate();
|
sfzUpdate_->deferUpdate();
|
||||||
sfzDescriptionUpdate_->setDescription(std::string(sfzDescriptionBlob));
|
sfzDescriptionUpdate_->setDescription(std::string(sfzDescriptionBlob));
|
||||||
|
|
@ -269,9 +234,6 @@ tresult SfizzVstControllerNoUi::notify(Vst::IMessage* message)
|
||||||
if (result != kResultTrue)
|
if (result != kResultTrue)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
processorStateUpdate_->access([scalaFile](SfizzVstState& state) {
|
|
||||||
state.scalaFile = std::string(scalaFile);
|
|
||||||
});
|
|
||||||
scalaUpdate_->setPath(std::string(scalaFile));
|
scalaUpdate_->setPath(std::string(scalaFile));
|
||||||
scalaUpdate_->deferUpdate();
|
scalaUpdate_->deferUpdate();
|
||||||
}
|
}
|
||||||
|
|
@ -313,6 +275,25 @@ tresult SfizzVstControllerNoUi::notify(Vst::IMessage* message)
|
||||||
noteUpdate_->changed();
|
noteUpdate_->changed();
|
||||||
noteUpdate_->clear();
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@ public:
|
||||||
tresult PLUGIN_API getParamValueByString(Vst::ParamID tag, Vst::TChar* string, Vst::ParamValue& valueNormalized) override;
|
tresult PLUGIN_API getParamValueByString(Vst::ParamID tag, Vst::TChar* string, Vst::ParamValue& valueNormalized) override;
|
||||||
|
|
||||||
tresult setParam(Vst::ParamID tag, float value);
|
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 setComponentState(IBStream* stream) override;
|
||||||
tresult PLUGIN_API notify(Vst::IMessage* message) override;
|
tresult PLUGIN_API notify(Vst::IMessage* message) override;
|
||||||
|
|
||||||
|
|
@ -50,7 +49,6 @@ protected:
|
||||||
Steinberg::IPtr<SfzUpdate> sfzUpdate_;
|
Steinberg::IPtr<SfzUpdate> sfzUpdate_;
|
||||||
Steinberg::IPtr<SfzDescriptionUpdate> sfzDescriptionUpdate_;
|
Steinberg::IPtr<SfzDescriptionUpdate> sfzDescriptionUpdate_;
|
||||||
Steinberg::IPtr<ScalaUpdate> scalaUpdate_;
|
Steinberg::IPtr<ScalaUpdate> scalaUpdate_;
|
||||||
Steinberg::IPtr<ProcessorStateUpdate> processorStateUpdate_;
|
|
||||||
Steinberg::IPtr<PlayStateUpdate> playStateUpdate_;
|
Steinberg::IPtr<PlayStateUpdate> playStateUpdate_;
|
||||||
Vst::ParamID midiMapping_[Vst::kCountCtrlNumber] {};
|
Vst::ParamID midiMapping_[Vst::kCountCtrlNumber] {};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -188,11 +188,13 @@ void PLUGIN_API SfizzVstEditor::update(FUnknown* changedUnknown, int32 message)
|
||||||
if (NoteEventsVec* queue = noteEventQueue_.get())
|
if (NoteEventsVec* queue = noteEventQueue_.get())
|
||||||
std::copy(events, events + count, std::back_inserter(*queue));
|
std::copy(events, events + count, std::back_inserter(*queue));
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SfzUpdate* update = FCast<SfzUpdate>(changedUnknown)) {
|
if (SfzUpdate* update = FCast<SfzUpdate>(changedUnknown)) {
|
||||||
const std::string path = update->getPath();
|
const std::string path = update->getPath();
|
||||||
uiReceiveValue(EditId::SfzFile, path);
|
uiReceiveValue(EditId::SfzFile, path);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SfzDescriptionUpdate* update = FCast<SfzDescriptionUpdate>(changedUnknown)) {
|
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]);
|
uiReceiveValue(editIdForCCLabel(int(cc)), desc.ccLabel[cc]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ScalaUpdate* update = FCast<ScalaUpdate>(changedUnknown)) {
|
if (ScalaUpdate* update = FCast<ScalaUpdate>(changedUnknown)) {
|
||||||
const std::string path = update->getPath();
|
const std::string path = update->getPath();
|
||||||
uiReceiveValue(EditId::ScalaFile, path);
|
uiReceiveValue(EditId::ScalaFile, path);
|
||||||
}
|
return;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PlayStateUpdate* update = FCast<PlayStateUpdate>(changedUnknown)) {
|
if (PlayStateUpdate* update = FCast<PlayStateUpdate>(changedUnknown)) {
|
||||||
|
|
@ -279,6 +270,12 @@ void PLUGIN_API SfizzVstEditor::update(FUnknown* changedUnknown, int32 message)
|
||||||
case kPidStretchedTuning:
|
case kPidStretchedTuning:
|
||||||
uiReceiveValue(EditId::StretchTuning, range.denormalize(value));
|
uiReceiveValue(EditId::StretchTuning, range.denormalize(value));
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
if (id >= kPidCC0 && id <= kPidCCLast) {
|
||||||
|
int cc = id - kPidCC0;
|
||||||
|
uiReceiveValue(editIdForCC(cc), range.denormalize(value));
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -329,18 +326,7 @@ void SfizzVstEditor::processNoteEventQueue()
|
||||||
///
|
///
|
||||||
void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v)
|
void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v)
|
||||||
{
|
{
|
||||||
if (editIdIsCC(id)) {
|
if (id == EditId::SfzFile)
|
||||||
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)
|
|
||||||
loadSfzFile(v.to_string());
|
loadSfzFile(v.to_string());
|
||||||
else if (id == EditId::ScalaFile)
|
else if (id == EditId::ScalaFile)
|
||||||
loadScalaFile(v.to_string());
|
loadScalaFile(v.to_string());
|
||||||
|
|
@ -384,6 +370,8 @@ void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
if (editIdIsCC(id))
|
||||||
|
normalizeAndSet(kPidCC0 + ccForEditId(id), v.to_float());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -482,6 +470,9 @@ Vst::ParamID SfizzVstEditor::parameterOfEditId(EditId id)
|
||||||
case EditId::ScalaRootKey: return kPidScalaRootKey;
|
case EditId::ScalaRootKey: return kPidScalaRootKey;
|
||||||
case EditId::TuningFrequency: return kPidTuningFrequency;
|
case EditId::TuningFrequency: return kPidTuningFrequency;
|
||||||
case EditId::StretchTuning: return kPidStretchedTuning;
|
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();
|
_state = SfizzVstState();
|
||||||
|
|
||||||
|
// allocate needed space to track CC values
|
||||||
|
_state.controllers.resize(sfz::config::numCCs);
|
||||||
|
|
||||||
fprintf(stderr, "[sfizz] new synth\n");
|
fprintf(stderr, "[sfizz] new synth\n");
|
||||||
_synth.reset(new sfz::Sfizz);
|
_synth.reset(new sfz::Sfizz);
|
||||||
|
|
||||||
|
|
@ -97,7 +100,7 @@ tresult PLUGIN_API SfizzVstProcessor::initialize(FUnknown* context)
|
||||||
_synth->setBroadcastCallback(onMessage, this);
|
_synth->setBroadcastCallback(onMessage, this);
|
||||||
|
|
||||||
_currentStretchedTuning = 0.0;
|
_currentStretchedTuning = 0.0;
|
||||||
loadSfzFileOrDefault({});
|
loadSfzFileOrDefault({}, false);
|
||||||
|
|
||||||
_synth->tempo(0, 0.5);
|
_synth->tempo(0, 0.5);
|
||||||
_timeSigNumerator = 4;
|
_timeSigNumerator = 4;
|
||||||
|
|
@ -130,6 +133,8 @@ tresult PLUGIN_API SfizzVstProcessor::connect(IConnectionPoint* other)
|
||||||
// when controller connects, send these messages that we couldn't earlier
|
// when controller connects, send these messages that we couldn't earlier
|
||||||
if (_loadedSfzMessage)
|
if (_loadedSfzMessage)
|
||||||
sendMessage(_loadedSfzMessage);
|
sendMessage(_loadedSfzMessage);
|
||||||
|
if (_automateMessage)
|
||||||
|
sendMessage(_automateMessage);
|
||||||
|
|
||||||
return kResultTrue;
|
return kResultTrue;
|
||||||
}
|
}
|
||||||
|
|
@ -168,6 +173,9 @@ tresult PLUGIN_API SfizzVstProcessor::setState(IBStream* stream)
|
||||||
std::lock_guard<SpinMutex> lock(_processMutex);
|
std::lock_guard<SpinMutex> lock(_processMutex);
|
||||||
_state = s;
|
_state = s;
|
||||||
|
|
||||||
|
// allocate needed space to track CC values
|
||||||
|
_state.controllers.resize(sfz::config::numCCs);
|
||||||
|
|
||||||
syncStateToSynth();
|
syncStateToSynth();
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
|
@ -186,7 +194,7 @@ void SfizzVstProcessor::syncStateToSynth()
|
||||||
if (!synth)
|
if (!synth)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
loadSfzFileOrDefault(_state.sfzFile);
|
loadSfzFileOrDefault(_state.sfzFile, true);
|
||||||
synth->setVolume(_state.volume);
|
synth->setVolume(_state.volume);
|
||||||
synth->setNumVoices(_state.numVoices);
|
synth->setNumVoices(_state.numVoices);
|
||||||
synth->setOversamplingFactor(1 << _state.oversamplingLog2);
|
synth->setOversamplingFactor(1 << _state.oversamplingLog2);
|
||||||
|
|
@ -284,7 +292,6 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data)
|
||||||
|
|
||||||
// Request OSC updates
|
// Request OSC updates
|
||||||
sfz::Client& client = *_client;
|
sfz::Client& client = *_client;
|
||||||
synth.sendMessage(client, 0, "/cc/changed~", "", nullptr);
|
|
||||||
synth.sendMessage(client, 0, "/sw/last/current", "", nullptr);
|
synth.sendMessage(client, 0, "/sw/last/current", "", nullptr);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -409,8 +416,10 @@ void SfizzVstProcessor::processControllerChanges(Vst::IParameterChanges& pc)
|
||||||
if (id >= kPidCC0 && id <= kPidCCLast) {
|
if (id >= kPidCC0 && id <= kPidCCLast) {
|
||||||
auto ccNumber = static_cast<int>(id - kPidCC0);
|
auto ccNumber = static_cast<int>(id - kPidCC0);
|
||||||
for (uint32 pointIndex = 0; pointIndex < pointCount; ++pointIndex) {
|
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);
|
synth.hdcc(sampleOffset, ccNumber, value);
|
||||||
|
_state.controllers[ccNumber] = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -561,7 +570,7 @@ tresult PLUGIN_API SfizzVstProcessor::notify(Vst::IMessage* message)
|
||||||
|
|
||||||
std::unique_lock<SpinMutex> lock(_processMutex);
|
std::unique_lock<SpinMutex> lock(_processMutex);
|
||||||
_state.sfzFile.assign(static_cast<const char *>(data), size);
|
_state.sfzFile.assign(static_cast<const char *>(data), size);
|
||||||
loadSfzFileOrDefault(_state.sfzFile);
|
loadSfzFileOrDefault(_state.sfzFile, false);
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
else if (!std::strcmp(id, "LoadScala")) {
|
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;
|
sfz::Sfizz& synth = *_synth;
|
||||||
|
|
||||||
|
|
@ -634,18 +643,56 @@ void SfizzVstProcessor::loadSfzFileOrDefault(const std::string& filePath)
|
||||||
synth.loadSfzString("default.sfz", defaultSfzText);
|
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() };
|
Steinberg::OPtr<Vst::IMessage> loadMessage { allocateMessage() };
|
||||||
message->setMessageID("LoadedSfz");
|
loadMessage->setMessageID("LoadedSfz");
|
||||||
Vst::IAttributeList* attrs = message->getAttributes();
|
Vst::IAttributeList* loadAttrs = loadMessage->getAttributes();
|
||||||
attrs->setBinary("File", filePath.data(), filePath.size());
|
loadAttrs->setBinary("File", filePath.data(), filePath.size());
|
||||||
attrs->setBinary("Description", desc.data(), desc.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
|
// 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()
|
void SfizzVstProcessor::doBackgroundWork()
|
||||||
|
|
@ -726,7 +773,7 @@ void SfizzVstProcessor::doBackgroundIdle(size_t idleCounter)
|
||||||
if (_synth->shouldReloadFile()) {
|
if (_synth->shouldReloadFile()) {
|
||||||
fprintf(stderr, "[Sfizz] sfz file has changed, reloading\n");
|
fprintf(stderr, "[Sfizz] sfz file has changed, reloading\n");
|
||||||
std::lock_guard<SpinMutex> lock(_processMutex);
|
std::lock_guard<SpinMutex> lock(_processMutex);
|
||||||
loadSfzFileOrDefault(_state.sfzFile);
|
loadSfzFileOrDefault(_state.sfzFile, false);
|
||||||
}
|
}
|
||||||
if (_synth->shouldReloadScala()) {
|
if (_synth->shouldReloadScala()) {
|
||||||
fprintf(stderr, "[Sfizz] scala file has changed, reloading\n");
|
fprintf(stderr, "[Sfizz] scala file has changed, reloading\n");
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ private:
|
||||||
// synth state. acquire processMutex before accessing
|
// synth state. acquire processMutex before accessing
|
||||||
std::unique_ptr<sfz::Sfizz> _synth;
|
std::unique_ptr<sfz::Sfizz> _synth;
|
||||||
Steinberg::IPtr<Vst::IMessage> _loadedSfzMessage;
|
Steinberg::IPtr<Vst::IMessage> _loadedSfzMessage;
|
||||||
|
Steinberg::IPtr<Vst::IMessage> _automateMessage;
|
||||||
bool _isActive = false;
|
bool _isActive = false;
|
||||||
SfizzVstState _state;
|
SfizzVstState _state;
|
||||||
float _currentStretchedTuning = 0;
|
float _currentStretchedTuning = 0;
|
||||||
|
|
@ -62,7 +63,7 @@ private:
|
||||||
void receiveMessage(int delay, const char* path, const char* sig, const sfizz_arg_t* args);
|
void receiveMessage(int delay, const char* path, const char* sig, const sfizz_arg_t* args);
|
||||||
|
|
||||||
// misc
|
// misc
|
||||||
void loadSfzFileOrDefault(const std::string& filePath);
|
void loadSfzFileOrDefault(const std::string& filePath, bool initParametersFromState);
|
||||||
|
|
||||||
// note event tracking
|
// note event tracking
|
||||||
std::array<float, 128> _noteEventsCurrentCycle; // 0: off, >0: on, <0: no change
|
std::array<float, 128> _noteEventsCurrentCycle; // 0: off, >0: on, <0: no change
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,26 @@ tresult SfizzVstState::load(IBStream* state)
|
||||||
stretchedTuning = defaults.stretchedTuning;
|
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 kResultFalse;
|
||||||
|
|
||||||
return kResultTrue;
|
return kResultTrue;
|
||||||
|
|
@ -98,6 +117,21 @@ tresult SfizzVstState::store(IBStream* state) const
|
||||||
if (!s.writeFloat(stretchedTuning))
|
if (!s.writeFloat(stretchedTuning))
|
||||||
return kResultFalse;
|
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;
|
return kResultTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "base/source/fstreamer.h"
|
#include "base/source/fstreamer.h"
|
||||||
|
#include <absl/types/optional.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
using namespace Steinberg;
|
using namespace Steinberg;
|
||||||
|
|
||||||
|
|
@ -23,8 +25,9 @@ public:
|
||||||
int32 scalaRootKey = 60;
|
int32 scalaRootKey = 60;
|
||||||
float tuningFrequency = 440.0;
|
float tuningFrequency = 440.0;
|
||||||
float stretchedTuning = 0.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 load(IBStream* state);
|
||||||
tresult store(IBStream* state) const;
|
tresult store(IBStream* state) const;
|
||||||
|
|
|
||||||
|
|
@ -138,37 +138,6 @@ private:
|
||||||
mutable std::mutex mutex_;
|
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.
|
* @brief Update which indicates the playing SFZ status.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue