From 42bf66dd74a21311f31a3121dcfa805131c19328 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 20 Jun 2020 05:49:00 +0200 Subject: [PATCH] Update the VST plugin --- vst/SfizzVstController.cpp | 60 ++++++- vst/SfizzVstController.h | 2 + vst/SfizzVstEditor.cpp | 359 ++++++++++++++++++++++++++++++++++--- vst/SfizzVstEditor.h | 32 +++- vst/SfizzVstProcessor.cpp | 55 +++++- vst/SfizzVstProcessor.h | 1 + vst/SfizzVstState.cpp | 46 +++++ vst/SfizzVstState.h | 14 +- 8 files changed, 541 insertions(+), 28 deletions(-) diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp index 8f4ef70d..7e04f8ba 100644 --- a/vst/SfizzVstController.cpp +++ b/vst/SfizzVstController.cpp @@ -34,10 +34,22 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) kParamPreloadSizeRange.createParameter( Steinberg::String("Preload size"), pid++, nullptr, 0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId)); + parameters.addParameter( + kParamScalaRootKey.createParameter( + Steinberg::String("Scala root key"), pid++, nullptr, + 0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId)); + parameters.addParameter( + kParamTuningFrequency.createParameter( + Steinberg::String("Tuning frequency"), pid++, Steinberg::String("Hz"), + 0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId)); + parameters.addParameter( + kParamStretchedTuning.createParameter( + Steinberg::String("Stretched tuning"), pid++, nullptr, + 0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId)); // MIDI special controllers parameters.addParameter(Steinberg::String("Aftertouch"), nullptr, 0, 0.5, 0, pid++, Vst::kRootUnitId); - parameters.addParameter(Steinberg::String("Pitch Bend"), nullptr, 0, 0.5, 0, pid++, Vst::kRootUnitId); + parameters.addParameter(Steinberg::String("Pitch bend"), nullptr, 0, 0.5, 0, pid++, Vst::kRootUnitId); // MIDI controllers for (unsigned i = 0; i < kNumControllerParams; ++i) { @@ -161,6 +173,21 @@ tresult PLUGIN_API SfizzVstController::setParamNormalized(Vst::ParamID tag, Vst: value = kParamPreloadSizeRange.denormalize(normValue); break; } + case kPidScalaRootKey: { + slotI32 = &_state.scalaRootKey; + value = kParamScalaRootKey.denormalize(normValue); + break; + } + case kPidTuningFrequency: { + slotF32 = &_state.tuningFrequency; + value = kParamTuningFrequency.denormalize(normValue); + break; + } + case kPidStretchedTuning: { + slotF32 = &_state.stretchedTuning; + value = kParamStretchedTuning.denormalize(normValue); + break; + } } bool update = false; @@ -217,6 +244,9 @@ tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* state) setParamNormalized(kPidNumVoices, kParamNumVoicesRange.normalize(s.numVoices)); setParamNormalized(kPidOversampling, kParamOversamplingRange.normalize(s.oversamplingLog2)); setParamNormalized(kPidPreloadSize, kParamPreloadSizeRange.normalize(s.preloadSize)); + setParamNormalized(kPidScalaRootKey, kParamScalaRootKey.normalize(s.scalaRootKey)); + setParamNormalized(kPidTuningFrequency, kParamTuningFrequency.normalize(s.tuningFrequency)); + setParamNormalized(kPidStretchedTuning, kParamStretchedTuning.normalize(s.stretchedTuning)); for (StateListener* listener : _stateListeners) listener->onStateChanged(); @@ -224,6 +254,34 @@ tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* state) return kResultTrue; } +tresult SfizzVstController::notify(Vst::IMessage* message) +{ + tresult result = SfizzVstControllerNoUi::notify(message); + if (result != kResultFalse) + return result; + + const char* id = message->getMessageID(); + Vst::IAttributeList* attr = message->getAttributes(); + + if (!strcmp(id, "LoadedSfz")) { + const void* data = nullptr; + uint32 size = 0; + result = attr->getBinary("File", data, size); + _state.sfzFile.assign(static_cast(data), size); + } + else if (!strcmp(id, "LoadedScala")) { + const void* data = nullptr; + uint32 size = 0; + result = attr->getBinary("File", data, size); + _state.scalaFile.assign(static_cast(data), size); + } + + for (StateListener* listener : _stateListeners) + listener->onStateChanged(); + + return result; +} + void SfizzVstController::addSfizzStateListener(StateListener* listener) { _stateListeners.push_back(listener); diff --git a/vst/SfizzVstController.h b/vst/SfizzVstController.h index b8455ecd..854a3722 100644 --- a/vst/SfizzVstController.h +++ b/vst/SfizzVstController.h @@ -44,12 +44,14 @@ public: tresult PLUGIN_API setState(IBStream* state) override; tresult PLUGIN_API getState(IBStream* state) override; tresult PLUGIN_API setComponentState(IBStream* state) override; + tresult PLUGIN_API notify(Vst::IMessage* message) override; struct StateListener { virtual void onStateChanged() = 0; }; const SfizzVstState& getSfizzState() const { return _state; } + SfizzVstState& getSfizzState() { return _state; } const SfizzUiState& getSfizzUiState() const { return _uiState; } SfizzUiState& getSfizzUiState() { return _uiState; } diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index b57af2c5..95e47db8 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -86,24 +86,53 @@ void SfizzVstEditor::valueChanged(CControl* ctl) Call::later([this]() { chooseSfzFile(); }); break; + case kTagLoadScalaFile: + if (value != 1) + break; + + Call::later([this]() { chooseScalaFile(); }); + break; + case kTagSetVolume: controller->setParamNormalized(kPidVolume, valueNorm); controller->performEdit(kPidVolume, valueNorm); + updateVolumeLabel(value); break; case kTagSetNumVoices: controller->setParamNormalized(kPidNumVoices, valueNorm); controller->performEdit(kPidNumVoices, valueNorm); + updateNumVoicesLabel(static_cast(value)); break; case kTagSetOversampling: controller->setParamNormalized(kPidOversampling, valueNorm); controller->performEdit(kPidOversampling, valueNorm); + updateOversamplingLabel(static_cast(value)); break; case kTagSetPreloadSize: controller->setParamNormalized(kPidPreloadSize, valueNorm); controller->performEdit(kPidPreloadSize, valueNorm); + updatePreloadSizeLabel(static_cast(value)); + break; + + case kTagSetScalaRootKey: + controller->setParamNormalized(kPidScalaRootKey, valueNorm); + controller->performEdit(kPidScalaRootKey, valueNorm); + updateScalaRootKeyLabel(value); + break; + + case kTagSetTuningFrequency: + controller->setParamNormalized(kPidTuningFrequency, valueNorm); + controller->performEdit(kPidTuningFrequency, valueNorm); + updateTuningFrequencyLabel(value); + break; + + case kTagSetStretchedTuning: + controller->setParamNormalized(kPidStretchedTuning, valueNorm); + controller->performEdit(kPidStretchedTuning, valueNorm); + updateStretchedTuningLabel(value); break; default: @@ -123,6 +152,9 @@ void SfizzVstEditor::enterOrLeaveEdit(CControl* ctl, bool enter) case kTagSetNumVoices: id = kPidNumVoices; break; case kTagSetOversampling: id = kPidOversampling; break; case kTagSetPreloadSize: id = kPidPreloadSize; break; + case kTagSetScalaRootKey: id = kPidScalaRootKey; break; + case kTagSetTuningFrequency: id = kPidTuningFrequency; break; + case kTagSetStretchedTuning: id = kPidStretchedTuning; break; default: return; } @@ -191,7 +223,7 @@ void SfizzVstEditor::loadSfzFile(const std::string& filePath) { SfizzVstController* ctl = getController(); - Vst::IMessage *msg = ctl->allocateMessage(); + Steinberg::OPtr msg { ctl->allocateMessage() }; if (!msg) { fprintf(stderr, "[Sfizz] UI could not allocate message\n"); return; @@ -201,9 +233,40 @@ void SfizzVstEditor::loadSfzFile(const std::string& filePath) Vst::IAttributeList* attr = msg->getAttributes(); attr->setBinary("File", filePath.data(), filePath.size()); ctl->sendMessage(msg); - msg->release(); - updateFileLabel(filePath); + updateSfzFileLabel(filePath); +} + +void SfizzVstEditor::chooseScalaFile() +{ + SharedPointer fs(CNewFileSelector::create(frame)); + + fs->setTitle("Load Scala file"); + fs->setDefaultExtension(CFileExtension("SCL", "scl")); + + if (fs->runModal()) { + UTF8StringPtr file = fs->getSelectedFile(0); + if (file) + loadScalaFile(file); + } +} + +void SfizzVstEditor::loadScalaFile(const std::string& filePath) +{ + SfizzVstController* ctl = getController(); + + Steinberg::OPtr msg { ctl->allocateMessage() }; + if (!msg) { + fprintf(stderr, "[Sfizz] UI could not allocate message\n"); + return; + } + + msg->setMessageID("LoadScala"); + Vst::IAttributeList* attr = msg->getAttributes(); + attr->setBinary("File", filePath.data(), filePath.size()); + ctl->sendMessage(msg); + + updateScalaFileLabel(filePath); } void SfizzVstEditor::createFrameContents() @@ -241,7 +304,7 @@ void SfizzVstEditor::createFrameContents() topLeftLabel->setFontColor(CColor(0x00, 0x00, 0x00)); topLeftLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); panel->addView(topLeftLabel); - _fileLabel = topLeftLabel; + _sfzFileLabel = topLeftLabel; _subPanels[kPanelGeneral] = panel; } @@ -277,6 +340,13 @@ void SfizzVstEditor::createFrameContents() return div; }; + auto labelArea = [&topRow, &row]() -> CRect { + CRect div = row; + div.right = topRow.right - 10.0; + div.left = div.right - 100.0 + 20.0; + return div; + }; + CTextLabel* label; SimpleSlider* slider; @@ -290,6 +360,9 @@ void SfizzVstEditor::createFrameContents() panel->addView(slider); adjustMinMaxToRangeParam(slider, kPidVolume); _volumeSlider = slider; + label = new CTextLabel(labelArea(), ""); + _volumeLabel = label; + panel->addView(label); row.top += interRow; row.bottom += interRow; @@ -304,6 +377,9 @@ void SfizzVstEditor::createFrameContents() panel->addView(slider); adjustMinMaxToRangeParam(slider, kPidNumVoices); _numVoicesSlider = slider; + label = new CTextLabel(labelArea(), ""); + _numVoicesLabel = label; + panel->addView(label); row.top += interRow; row.bottom += interRow; @@ -318,6 +394,9 @@ void SfizzVstEditor::createFrameContents() panel->addView(slider); adjustMinMaxToRangeParam(slider, kPidOversampling); _oversamplingSlider = slider; + label = new CTextLabel(labelArea(), ""); + _oversamplingLabel = label; + panel->addView(label); row.top += interRow; row.bottom += interRow; @@ -332,6 +411,9 @@ void SfizzVstEditor::createFrameContents() panel->addView(slider); adjustMinMaxToRangeParam(slider, kPidPreloadSize); _preloadSizeSlider = slider; + label = new CTextLabel(labelArea(), ""); + _preloadSizeLabel = label; + panel->addView(label); // row.top += interRow; // row.bottom += interRow; @@ -350,6 +432,114 @@ void SfizzVstEditor::createFrameContents() _subPanels[kPanelSettings] = panel; } + // tuning panel + { + panel = new CViewContainer(bounds); + frame->addView(panel); + panel->setTransparency(true); + + CTextLabel* topLeftLabel = new CTextLabel(topLeftLabelBox, "Tuning"); + topLeftLabel->setFontColor(CColor(0x00, 0x00, 0x00)); + topLeftLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + panel->addView(topLeftLabel); + + CRect row = topRow; + row.top += 45.0; + row.bottom += 45.0; + row.left += 100.0; + row.right -= 100.0; + + CCoord interRow = 35.0; + + auto leftSide = [&row]() -> CRect { + CRect div = row; + div.right = 0.5 * (div.left + div.right); + return div; + }; + + auto rightSide = [&row]() -> CRect { + CRect div = row; + div.left = 0.5 * (div.left + div.right); + return div; + }; + + auto labelArea = [&topRow, &row]() -> CRect { + CRect div = row; + div.right = topRow.right - 10.0; + div.left = div.right - 100.0 + 20.0; + return div; + }; + + CTextLabel* label; + SimpleSlider* slider; + CTextButton* textbutton; + + label = new CTextLabel(leftSide(), "Scala file"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + textbutton = new CTextButton(rightSide(), this, kTagLoadScalaFile, "Choose"); + panel->addView(textbutton); + label = new CTextLabel(labelArea(), ""); + _scalaFileLabel = label; + panel->addView(label); + + row.top += interRow; + row.bottom += interRow; + + label = new CTextLabel(leftSide(), "Scala root key"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + slider = new SimpleSlider(rightSide(), this, kTagSetScalaRootKey); + panel->addView(slider); + adjustMinMaxToRangeParam(slider, kPidScalaRootKey); + _scalaRootKeySlider = slider; + label = new CTextLabel(labelArea(), ""); + _scalaRootKeyLabel = label; + panel->addView(label); + + row.top += interRow; + row.bottom += interRow; + + label = new CTextLabel(leftSide(), "Tuning frequency"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + slider = new SimpleSlider(rightSide(), this, kTagSetTuningFrequency); + panel->addView(slider); + adjustMinMaxToRangeParam(slider, kPidTuningFrequency); + _tuningFrequencySlider = slider; + label = new CTextLabel(labelArea(), ""); + _tuningFrequencyLabel = label; + panel->addView(label); + + row.top += interRow; + row.bottom += interRow; + + label = new CTextLabel(leftSide(), "Stretched tuning"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + slider = new SimpleSlider(rightSide(), this, kTagSetStretchedTuning); + panel->addView(slider); + adjustMinMaxToRangeParam(slider, kPidStretchedTuning); + _stretchedTuningSlider = slider; + label = new CTextLabel(labelArea(), ""); + _stretchedTuningLabel = label; + panel->addView(label); + + _subPanels[kPanelTuning] = panel; + } + // all panels for (unsigned currentPanel = 0; currentPanel < kNumPanels; ++currentPanel) { panel = _subPanels[currentPanel]; @@ -369,6 +559,7 @@ void SfizzVstEditor::createFrameContents() switch (i) { case kPanelGeneral: text = "File"; break; case kPanelSettings: text = "Setup"; break; + case kPanelTuning: text = "Tuning"; break; default: text = "?"; break; } @@ -391,38 +582,164 @@ void SfizzVstEditor::updateStateDisplay() const SfizzVstState& state = controller->getSfizzState(); const SfizzUiState& uiState = controller->getSfizzUiState(); - updateFileLabel(state.sfzFile); + updateSfzFileLabel(state.sfzFile); if (_volumeSlider) _volumeSlider->setValue(state.volume); + updateVolumeLabel(state.volume); if (_numVoicesSlider) _numVoicesSlider->setValue(state.numVoices); + updateNumVoicesLabel(state.numVoices); if (_oversamplingSlider) _oversamplingSlider->setValue(state.oversamplingLog2); + updateOversamplingLabel(state.oversamplingLog2); if (_preloadSizeSlider) _preloadSizeSlider->setValue(state.preloadSize); + updatePreloadSizeLabel(state.preloadSize); + updateScalaFileLabel(state.scalaFile); + if (_scalaRootKeySlider) + _scalaRootKeySlider->setValue(state.scalaRootKey); + updateScalaRootKeyLabel(state.scalaRootKey); + if (_tuningFrequencySlider) + _tuningFrequencySlider->setValue(state.tuningFrequency); + updateTuningFrequencyLabel(state.tuningFrequency); + if (_stretchedTuningSlider) + _stretchedTuningSlider->setValue(state.stretchedTuning); + updateStretchedTuningLabel(state.stretchedTuning); setActivePanel(uiState.activePanel); } -void SfizzVstEditor::updateFileLabel(const std::string& filePath) +void SfizzVstEditor::updateSfzFileLabel(const std::string& filePath) { - if (_fileLabel) { - std::string fileName; - if (filePath.empty()) - fileName = ""; - else { -#if defined (_WIN32) - size_t pos = filePath.find_last_of("/\\"); -#else - size_t pos = filePath.rfind('/'); -#endif - fileName = (pos != filePath.npos) ? - filePath.substr(pos + 1) : filePath; - } - _fileLabel->setText(fileName.c_str()); - } + updateLabelWithFileName(_sfzFileLabel, filePath); } +void SfizzVstEditor::updateScalaFileLabel(const std::string& filePath) +{ + updateLabelWithFileName(_scalaFileLabel, filePath); +} + +void SfizzVstEditor::updateLabelWithFileName(CTextLabel* label, const std::string& filePath) +{ + if (!label) + return; + + std::string fileName; + if (filePath.empty()) + fileName = ""; + else { +#if defined (_WIN32) + size_t pos = filePath.find_last_of("/\\"); +#else + size_t pos = filePath.rfind('/'); +#endif + fileName = (pos != filePath.npos) ? + filePath.substr(pos + 1) : filePath; + } + label->setText(fileName.c_str()); +} + +void SfizzVstEditor::updateVolumeLabel(float volume) +{ + CTextLabel* label = _volumeLabel; + if (!label) + return; + + char text[64]; + sprintf(text, "%.1f dB", volume); + text[sizeof(text) - 1] = '\0'; + label->setText(text); +} + +void SfizzVstEditor::updateNumVoicesLabel(int numVoices) +{ + CTextLabel* label = _numVoicesLabel; + if (!label) + return; + + char text[64]; + sprintf(text, "%d", numVoices); + text[sizeof(text) - 1] = '\0'; + label->setText(text); +} + +void SfizzVstEditor::updateOversamplingLabel(int oversamplingLog2) +{ + CTextLabel* label = _oversamplingLabel; + if (!label) + return; + + char text[64]; + sprintf(text, "%dx", 1 << oversamplingLog2); + text[sizeof(text) - 1] = '\0'; + label->setText(text); +} + +void SfizzVstEditor::updatePreloadSizeLabel(int preloadSize) +{ + CTextLabel* label = _preloadSizeLabel; + if (!label) + return; + + char text[64]; + sprintf(text, "%.1f kB", preloadSize * (1.0 / 1024)); + text[sizeof(text) - 1] = '\0'; + label->setText(text); +} + +void SfizzVstEditor::updateScalaRootKeyLabel(int rootKey) +{ + CTextLabel* label = _scalaRootKeyLabel; + if (!label) + return; + + static const char *octNoteNames[12] = { + "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", + }; + + auto noteName = [](int key) -> std::string + { + int octNum; + int octNoteNum; + if (key >= 0) { + octNum = key / 12 - 1; + octNoteNum = key % 12; + } + else { + octNum = -2 - (key + 1) / -12; + octNoteNum = (key % 12 + 12) % 12; + } + return std::string(octNoteNames[octNoteNum]) + std::to_string(octNum); + }; + + label->setText(noteName(rootKey)); +} + +void SfizzVstEditor::updateTuningFrequencyLabel(float tuningFrequency) +{ + CTextLabel* label = _tuningFrequencyLabel; + if (!label) + return; + + char text[64]; + sprintf(text, "%.1f", tuningFrequency); + text[sizeof(text) - 1] = '\0'; + label->setText(text); +} + +void SfizzVstEditor::updateStretchedTuningLabel(float stretchedTuning) +{ + CTextLabel* label = _stretchedTuningLabel; + if (!label) + return; + + char text[64]; + sprintf(text, "%.3f", stretchedTuning); + text[sizeof(text) - 1] = '\0'; + label->setText(text); +} + + void SfizzVstEditor::setActivePanel(unsigned panelId) { panelId = std::max(0, std::min(kNumPanels - 1, static_cast(panelId))); diff --git a/vst/SfizzVstEditor.h b/vst/SfizzVstEditor.h index d023f4ed..f0228b7e 100644 --- a/vst/SfizzVstEditor.h +++ b/vst/SfizzVstEditor.h @@ -43,9 +43,21 @@ private: void chooseSfzFile(); void loadSfzFile(const std::string& filePath); + void chooseScalaFile(); + void loadScalaFile(const std::string& filePath); + void createFrameContents(); void updateStateDisplay(); - void updateFileLabel(const std::string& filePath); + void updateSfzFileLabel(const std::string& filePath); + void updateScalaFileLabel(const std::string& filePath); + static void updateLabelWithFileName(CTextLabel* label, const std::string& filePath); + void updateVolumeLabel(float volume); + void updateNumVoicesLabel(int numVoices); + void updateOversamplingLabel(int oversamplingLog2); + void updatePreloadSizeLabel(int preloadSize); + void updateScalaRootKeyLabel(int rootKey); + void updateTuningFrequencyLabel(float tuningFrequency); + void updateStretchedTuningLabel(float stretchedTuning); void setActivePanel(unsigned panelId); template @@ -60,6 +72,7 @@ private: kPanelGeneral, // kPanelControls, kPanelSettings, + kPanelTuning, kNumPanels, }; @@ -72,16 +85,31 @@ private: kTagSetNumVoices, kTagSetOversampling, kTagSetPreloadSize, + kTagLoadScalaFile, + kTagSetScalaRootKey, + kTagSetTuningFrequency, + kTagSetStretchedTuning, kTagFirstChangePanel, kTagLastChangePanel = kTagFirstChangePanel + kNumPanels - 1, }; CBitmap _logo; - CTextLabel* _fileLabel = nullptr; + CTextLabel* _sfzFileLabel = nullptr; + CTextLabel* _scalaFileLabel = nullptr; CSliderBase *_volumeSlider = nullptr; + CTextLabel* _volumeLabel = nullptr; CSliderBase *_numVoicesSlider = nullptr; + CTextLabel* _numVoicesLabel = nullptr; CSliderBase *_oversamplingSlider = nullptr; + CTextLabel* _oversamplingLabel = nullptr; CSliderBase *_preloadSizeSlider = nullptr; + CTextLabel* _preloadSizeLabel = nullptr; + CSliderBase *_scalaRootKeySlider = nullptr; + CTextLabel* _scalaRootKeyLabel = nullptr; + CSliderBase *_tuningFrequencySlider = nullptr; + CTextLabel* _tuningFrequencyLabel = nullptr; + CSliderBase *_stretchedTuningSlider = nullptr; + CTextLabel* _stretchedTuningLabel = nullptr; #if !defined(__APPLE__) && !defined(_WIN32) SharedPointer _runLoop; diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index 944a07c3..56d951e3 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -52,6 +52,7 @@ tresult PLUGIN_API SfizzVstProcessor::initialize(FUnknown* context) fprintf(stderr, "[sfizz] new synth\n"); _synth.reset(new sfz::Sfizz); + _currentStretchedTuning = 0.0; loadSfzFileOrDefault(*_synth, {}); return result; @@ -101,6 +102,10 @@ void SfizzVstProcessor::syncStateToSynth() synth->setNumVoices(_state.numVoices); synth->setOversamplingFactor(1 << _state.oversamplingLog2); synth->setPreloadSize(_state.preloadSize); + synth->loadScalaFile(_state.scalaFile); + synth->setScalaRootKey(_state.scalaRootKey); + synth->setTuningFrequency(_state.tuningFrequency); + synth->loadStretchTuningByRatio(_state.stretchedTuning); } tresult PLUGIN_API SfizzVstProcessor::canProcessSampleSize(int32 symbolicSampleSize) @@ -174,6 +179,12 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data) processEvents(*events); synth.setVolume(_state.volume); + synth.setScalaRootKey(_state.scalaRootKey); + synth.setTuningFrequency(_state.tuningFrequency); + if (_currentStretchedTuning != _state.stretchedTuning) { + synth.loadStretchTuningByRatio(_state.stretchedTuning); + _currentStretchedTuning = _state.stretchedTuning; + } synth.renderBlock(outputs, numFrames, numChannels); @@ -230,6 +241,18 @@ void SfizzVstProcessor::processParameterChanges(Vst::IParameterChanges& pc) _semaToWorker.post(); } break; + case kPidScalaRootKey: + if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) + _state.scalaRootKey = static_cast(kParamScalaRootKey.denormalize(value)); + break; + case kPidTuningFrequency: + if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) + _state.tuningFrequency = kParamTuningFrequency.denormalize(value); + break; + case kPidStretchedTuning: + if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) + _state.stretchedTuning = kParamStretchedTuning.denormalize(value); + break; } } } @@ -328,9 +351,33 @@ tresult PLUGIN_API SfizzVstProcessor::notify(Vst::IMessage* message) if (result != kResultTrue) return result; - std::lock_guard lock(_processMutex); + std::unique_lock lock(_processMutex); _state.sfzFile.assign(static_cast(data), size); loadSfzFileOrDefault(*_synth, _state.sfzFile); + lock.unlock(); + + Steinberg::OPtr reply { allocateMessage() }; + reply->setMessageID("LoadedSfz"); + reply->getAttributes()->setBinary("File", _state.sfzFile.data(), _state.sfzFile.size()); + sendMessage(reply); + } + else if (!std::strcmp(id, "LoadScala")) { + const void* data = nullptr; + uint32 size = 0; + result = attr->getBinary("File", data, size); + + if (result != kResultTrue) + return result; + + std::unique_lock lock(_processMutex); + _state.scalaFile.assign(static_cast(data), size); + _synth->loadScalaFile(_state.scalaFile); + lock.unlock(); + + Steinberg::OPtr reply { allocateMessage() }; + reply->setMessageID("LoadedScala"); + reply->getAttributes()->setBinary("File", _state.scalaFile.data(), _state.scalaFile.size()); + sendMessage(reply); } return result; @@ -379,9 +426,13 @@ void SfizzVstProcessor::doBackgroundWork() } else if (!std::strcmp(id, "CheckShouldReload")) { if (_synth->shouldReloadFile()) { - fprintf(stderr, "[Sfizz] file has changed, reloading\n"); + fprintf(stderr, "[Sfizz] sfz file has changed, reloading\n"); loadSfzFileOrDefault(*_synth, _state.sfzFile); } + else if (_synth->shouldReloadScala()) { + fprintf(stderr, "[Sfizz] scala file has changed, reloading\n"); + _synth->loadScalaFile(_state.scalaFile); + } } } } diff --git a/vst/SfizzVstProcessor.h b/vst/SfizzVstProcessor.h index 946e6772..f215baf2 100644 --- a/vst/SfizzVstProcessor.h +++ b/vst/SfizzVstProcessor.h @@ -48,6 +48,7 @@ private: // synth state. acquire processMutex before accessing std::unique_ptr _synth; SfizzVstState _state; + float _currentStretchedTuning = 0; // misc static void loadSfzFileOrDefault(sfz::Sfizz& synth, const std::string& filePath); diff --git a/vst/SfizzVstState.cpp b/vst/SfizzVstState.cpp index 17240921..1eaac01f 100644 --- a/vst/SfizzVstState.cpp +++ b/vst/SfizzVstState.cpp @@ -34,6 +34,33 @@ tresult SfizzVstState::load(IBStream* state) if (!s.readInt32(preloadSize)) return kResultFalse; + const SfizzVstState defaults; + + if (version >= 1) { + if (const char* str = s.readStr8()) + scalaFile = str; + else + return kResultFalse; + + if (!s.readInt32(scalaRootKey)) + return kResultFalse; + + if (!s.readFloat(tuningFrequency)) + return kResultFalse; + + if (!s.readFloat(stretchedTuning)) + return kResultFalse; + } + else { + scalaFile = defaults.scalaFile; + scalaRootKey = defaults.scalaRootKey; + tuningFrequency = defaults.tuningFrequency; + stretchedTuning = defaults.stretchedTuning; + } + + if (version > 1) + return kResultFalse; + return kResultTrue; } @@ -59,9 +86,23 @@ tresult SfizzVstState::store(IBStream* state) const if (!s.writeInt32(preloadSize)) return kResultFalse; + if (!s.writeStr8(scalaFile.c_str())) + return kResultFalse; + + if (!s.writeInt32(scalaRootKey)) + return kResultFalse; + + if (!s.writeFloat(tuningFrequency)) + return kResultFalse; + + if (!s.writeFloat(stretchedTuning)) + return kResultFalse; + return kResultTrue; } +constexpr uint64 SfizzVstState::currentStateVersion; + tresult SfizzUiState::load(IBStream* state) { IBStreamer s(state, kLittleEndian); @@ -73,6 +114,9 @@ tresult SfizzUiState::load(IBStream* state) if (!s.readInt32u(activePanel)) return kResultFalse; + if (version > 0) + return kResultFalse; + return kResultTrue; } @@ -88,3 +132,5 @@ tresult SfizzUiState::store(IBStream* state) const return kResultTrue; } + +constexpr uint64 SfizzUiState::currentStateVersion; diff --git a/vst/SfizzVstState.h b/vst/SfizzVstState.h index 020e0fe8..a00d37a9 100644 --- a/vst/SfizzVstState.h +++ b/vst/SfizzVstState.h @@ -22,6 +22,9 @@ enum { kPidNumVoices, kPidOversampling, kPidPreloadSize, + kPidScalaRootKey, + kPidTuningFrequency, + kPidStretchedTuning, kPidMidiAftertouch, kPidMidiPitchBend, kPidMidiCC0, @@ -31,15 +34,19 @@ enum { class SfizzVstState { public: - SfizzVstState() { sfzFile.reserve(8192); } + SfizzVstState() { sfzFile.reserve(8192); scalaFile.reserve(8192); } std::string sfzFile; float volume = 0; int32 numVoices = 64; int32 oversamplingLog2 = 0; int32 preloadSize = 8192; + std::string scalaFile; + int32 scalaRootKey = 60; + float tuningFrequency = 440.0; + float stretchedTuning = 0.0; - static constexpr uint64 currentStateVersion = 0; + static constexpr uint64 currentStateVersion = 1; tresult load(IBStream* state); tresult store(IBStream* state) const; @@ -83,3 +90,6 @@ static constexpr SfizzParameterRange kParamVolumeRange(0.0, -60.0, +6.0); static constexpr SfizzParameterRange kParamNumVoicesRange(256.0, 1.0, 512.0); static constexpr SfizzParameterRange kParamOversamplingRange(0.0, 0.0, 3.0); static constexpr SfizzParameterRange kParamPreloadSizeRange(8192.0, 1024.0, 65536.0); +static constexpr SfizzParameterRange kParamScalaRootKey(60.0, 0.0, 127.0); +static constexpr SfizzParameterRange kParamTuningFrequency(440.0, 300.0, 500.0); +static constexpr SfizzParameterRange kParamStretchedTuning(0.0, 0.0, 1.0);