From 2dc41f45035e5b11cf6bdbe7b119efa9c685be34 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 5 Mar 2020 11:16:47 +0100 Subject: [PATCH 01/42] Initial VST plugin --- .gitignore | 3 + CMakeLists.txt | 5 + cmake/VSTConfig.cmake | 4 + vst/CMakeLists.txt | 77 +++++++ vst/RTSemaphore.h | 167 ++++++++++++++ vst/SfizzVstController.cpp | 121 ++++++++++ vst/SfizzVstController.h | 69 ++++++ vst/SfizzVstEditor.cpp | 180 +++++++++++++++ vst/SfizzVstEditor.h | 40 ++++ vst/SfizzVstProcessor.cpp | 284 ++++++++++++++++++++++++ vst/SfizzVstProcessor.h | 57 +++++ vst/SfizzVstState.cpp | 42 ++++ vst/SfizzVstState.h | 21 ++ vst/VstPluginDefs.h.in | 11 + vst/VstPluginFactory.cpp | 49 ++++ vst/cmake/Vst3.cmake | 244 ++++++++++++++++++++ vst/external/steinberg/LICENSE | 27 +++ vst/external/steinberg/src/x11runloop.h | 110 +++++++++ vst/vst3.version | 7 + 19 files changed, 1518 insertions(+) create mode 100644 cmake/VSTConfig.cmake create mode 100644 vst/CMakeLists.txt create mode 100644 vst/RTSemaphore.h create mode 100644 vst/SfizzVstController.cpp create mode 100644 vst/SfizzVstController.h create mode 100644 vst/SfizzVstEditor.cpp create mode 100644 vst/SfizzVstEditor.h create mode 100644 vst/SfizzVstProcessor.cpp create mode 100644 vst/SfizzVstProcessor.h create mode 100644 vst/SfizzVstState.cpp create mode 100644 vst/SfizzVstState.h create mode 100644 vst/VstPluginDefs.h.in create mode 100644 vst/VstPluginFactory.cpp create mode 100644 vst/cmake/Vst3.cmake create mode 100644 vst/external/steinberg/LICENSE create mode 100644 vst/external/steinberg/src/x11runloop.h create mode 100644 vst/vst3.version diff --git a/.gitignore b/.gitignore index 4196b1a0..d232a9b0 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,6 @@ node_modules/ *.lock *.sublime-* *.code-* + +/vst/download +/vst/external/VST_SDK diff --git a/CMakeLists.txt b/CMakeLists.txt index 91a45430..00adb2e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ endif() option (ENABLE_LTO "Enable Link Time Optimization [default: ON]" ON) option (SFIZZ_JACK "Enable JACK stand-alone build [default: ON]" ON) option (SFIZZ_LV2 "Enable LV2 plug-in build [default: ON]" ON) +option (SFIZZ_VST "Enable VST plug-in build [default: OFF]" OFF) option (SFIZZ_BENCHMARKS "Enable benchmarks build [default: OFF]" OFF) option (SFIZZ_TESTS "Enable tests build [default: OFF]" OFF) option (SFIZZ_SHARED "Enable shared library build [default: ON]" ON) @@ -51,6 +52,10 @@ if (SFIZZ_LV2) add_subdirectory (lv2) endif() +if (SFIZZ_VST) + add_subdirectory (vst) +endif() + if (SFIZZ_BENCHMARKS) add_subdirectory (benchmarks) endif() diff --git a/cmake/VSTConfig.cmake b/cmake/VSTConfig.cmake new file mode 100644 index 00000000..0d1de3e1 --- /dev/null +++ b/cmake/VSTConfig.cmake @@ -0,0 +1,4 @@ +set (VSTPLUGIN_NAME "sfizz") +set (VSTPLUGIN_VENDOR "Paul Ferrand") +set (VSTPLUGIN_URL "http://sfztools.github.io/sfizz") +set (VSTPLUGIN_EMAIL "paul@ferrand.cc") diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt new file mode 100644 index 00000000..4cafc961 --- /dev/null +++ b/vst/CMakeLists.txt @@ -0,0 +1,77 @@ +set (VSTPLUGIN_PRJ_NAME "${PROJECT_NAME}_vst3") +set (VSTPLUGIN_BUNDLE_NAME "${PROJECT_NAME}.vst3") + +set (VST3SDK_BASEDIR "${CMAKE_CURRENT_SOURCE_DIR}/external/VST_SDK/VST3_SDK") +set (VST3SDK_ARCHIVE "vst-sdk_3.6.14_build-24_2019-11-29.zip") + +if (NOT EXISTS "${VST3SDK_BASEDIR}") + message (STATUS "VST3 SDK is not found, downloading") + + execute_process ( + COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_SOURCE_DIR}/download") + + if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/download/${VST3SDK_ARCHIVE}") + file (DOWNLOAD + "https://download.steinberg.net/sdk_downloads/${VST3SDK_ARCHIVE}" + "${CMAKE_CURRENT_SOURCE_DIR}/download/${VST3SDK_ARCHIVE}" + SHOW_PROGRESS) + endif() + + execute_process ( + COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_SOURCE_DIR}/external" + COMMAND "${CMAKE_COMMAND}" -E tar xvf "../download/${VST3SDK_ARCHIVE}" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/external") +endif() + +# stop trying to include this atrocity.. build it ourselves +#add_subdirectory("${VST3SDK_BASEDIR}" EXCLUDE_FROM_ALL) + +# VST plugin specific settings +include (VSTConfig) + +configure_file (VstPluginDefs.h.in "${CMAKE_CURRENT_BINARY_DIR}/VstPluginDefs.h") + +# Build VST3 SDK +include("cmake/Vst3.cmake") + +# Build the plugin +add_library(${VSTPLUGIN_PRJ_NAME} MODULE + SfizzVstProcessor.cpp + SfizzVstController.cpp + SfizzVstEditor.cpp + SfizzVstState.cpp + VstPluginFactory.cpp) +target_link_libraries(${VSTPLUGIN_PRJ_NAME} + PRIVATE ${PROJECT_NAME}::${PROJECT_NAME}) +target_include_directories(${VSTPLUGIN_PRJ_NAME} + PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") +set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES + OUTPUT_NAME "${PROJECT_NAME}" + PREFIX "") + +plugin_add_vst3sdk(${VSTPLUGIN_PRJ_NAME}) +plugin_add_vstgui(${VSTPLUGIN_PRJ_NAME}) + +if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE + "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/vst3.version") +endif() + +# Create the bundle (see "VST 3 Locations / Format") +if(WIN32) + set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-win") + # TODO: make desktop.ini, Plugin.ico +elseif(APPLE) + set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/MacOS") + # TODO: make Info.plist, PkgInfo +else() + set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-linux") +endif() + +# To help debugging the link only +if (FALSE) + target_link_options(${VSTPLUGIN_PRJ_NAME} PRIVATE "-Wl,-no-undefined") +endif() diff --git a/vst/RTSemaphore.h b/vst/RTSemaphore.h new file mode 100644 index 00000000..0cd6135b --- /dev/null +++ b/vst/RTSemaphore.h @@ -0,0 +1,167 @@ +// Copyright Jean Pierre Cimalando 2018-2020. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#pragma once +#if defined(__APPLE__) +#include +#elif defined(_WIN32) +#include +#include +#else +#include +#include +#endif +#include + +class RTSemaphore { +public: + explicit RTSemaphore(unsigned value = 0); + ~RTSemaphore(); + + RTSemaphore(const RTSemaphore &) = delete; + RTSemaphore &operator=(const RTSemaphore &) = delete; + + void post(); + void wait(); + bool try_wait(); + +private: +#if defined(__APPLE__) + semaphore_t sem_; +#elif defined(_WIN32) + HANDLE sem_; +#else + sem_t sem_; +#endif +}; + +#if defined(__APPLE__) +inline RTSemaphore::RTSemaphore(unsigned value) +{ + if (semaphore_create(mach_task_self(), &sem_, SYNC_POLICY_FIFO, value) != 0) + throw std::runtime_error("RTSemaphore::RTSemaphore"); +} + +inline RTSemaphore::~RTSemaphore() +{ + semaphore_destroy(mach_task_self(), sem_); +} + +inline void RTSemaphore::post() +{ + if (semaphore_signal(sem_) != KERN_SUCCESS) + throw std::runtime_error("RTSemaphore::post"); +} + +inline void RTSemaphore::wait() +{ + do { + switch (semaphore_wait(sem_)) { + case KERN_SUCCESS: + return; + case KERN_ABORTED: + break; + default: + throw std::runtime_error("RTSemaphore::wait"); + } + } while (1); +} + +inline bool RTSemaphore::try_wait() +{ + do { + const mach_timespec_t timeout = {0, 0}; + switch (semaphore_timedwait(sem_, timeout)) { + case KERN_SUCCESS: + return true; + case KERN_OPERATION_TIMED_OUT: + return false; + case KERN_ABORTED: + break; + default: + throw std::runtime_error("RTSemaphore::try_wait"); + } + } while (1); +} +#elif defined(_WIN32) +inline RTSemaphore::RTSemaphore(unsigned value) +{ + sem_ = CreateRTSemaphore(nullptr, value, LONG_MAX, nullptr); + if (!sem_) + throw std::runtime_error("RTSemaphore::RTSemaphore"); +} + +inline RTSemaphore::~RTSemaphore() +{ + CloseHandle(sem_); +} + +inline void RTSemaphore::post() +{ + if (!ReleaseRTSemaphore(sem_, 1, nullptr)) + throw std::runtime_error("RTSemaphore::post"); +} + +inline void RTSemaphore::wait() +{ + if (WaitForSingleObject(sem_, INFINITE) != WAIT_OBJECT_0) + throw std::runtime_error("RTSemaphore::wait"); +} + +inline bool RTSemaphore::try_wait() +{ + switch (WaitForSingleObject(sem_, 0)) { + case WAIT_OBJECT_0: + return true; + case WAIT_TIMEOUT: + return false; + default: + throw std::runtime_error("RTSemaphore::try_wait"); + } +} +#else +inline RTSemaphore::RTSemaphore(unsigned value) +{ + if (sem_init(&sem_, 0, value) != 0) + throw std::runtime_error("RTSemaphore::RTSemaphore"); +} + +inline RTSemaphore::~RTSemaphore() +{ + sem_destroy(&sem_); +} + +inline void RTSemaphore::post() +{ + while (sem_post(&sem_) != 0) { + if (errno != EINTR) + throw std::runtime_error("RTSemaphore::post"); + } +} + +inline void RTSemaphore::wait() +{ + while (sem_wait(&sem_) != 0) { + if (errno != EINTR) + throw std::runtime_error("RTSemaphore::wait"); + } +} + +inline bool RTSemaphore::try_wait() +{ + do { + if (sem_trywait(&sem_) == 0) + return true; + switch (errno) { + case EINTR: + break; + case EAGAIN: + return false; + default: + throw std::runtime_error("RTSemaphore::try_wait"); + } + } while (1); +} +#endif diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp new file mode 100644 index 00000000..88fcc6f0 --- /dev/null +++ b/vst/SfizzVstController.cpp @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "SfizzVstController.h" +#include "SfizzVstEditor.h" +#include "base/source/fstreamer.h" +#include "pluginterfaces/vst/ivstmidicontrollers.h" + +tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) +{ + tresult result = EditController::initialize(context); + if (result != kResultTrue) + return result; + + Vst::ParamID pid = 0; + + // MIDI controllers + for (unsigned i = 0; i < numControllerParams; ++i) { + Steinberg::String title; + Steinberg::String shortTitle; + title.printf("Controller %u", i); + shortTitle.printf("CC%u", i); + + parameters.addParameter( + title, nullptr, 0, 0, Vst::ParameterInfo::kCanAutomate, + pid++, Vst::kRootUnitId, shortTitle); + } + + // MIDI extra 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); + + return kResultTrue; +} + +tresult PLUGIN_API SfizzVstControllerNoUi::terminate() +{ + return EditController::terminate(); +} + +tresult PLUGIN_API SfizzVstControllerNoUi::getMidiControllerAssignment(int32 busIndex, int16 channel, Vst::CtrlNumber midiControllerNumber, Vst::ParamID& id) +{ + switch (midiControllerNumber) { + case Vst::kAfterTouch: + id = kPidMidiAftertouch; + return kResultTrue; + + case Vst::kPitchBend: + id = kPidMidiPitchBend; + return kResultTrue; + + default: + if (midiControllerNumber < 0 || midiControllerNumber >= numControllerParams) + return kResultFalse; + + id = kPidMidiCC0 + midiControllerNumber; + return kResultTrue; + } +} + +// --- Controller with UI --- // + +IPlugView* PLUGIN_API SfizzVstController::createView(FIDString _name) +{ + ConstString name(_name); + + if (name != Vst::ViewType::kEditor) + return nullptr; + + return new SfizzVstEditor(this); +} + +tresult PLUGIN_API SfizzVstController::setParamNormalized(Vst::ParamID tag, Vst::ParamValue value) +{ + tresult r = SfizzVstControllerNoUi::setParamNormalized(tag, value); + if (r != kResultTrue) + return r; + + return kResultTrue; +} + +tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* state) +{ + SfizzVstState s; + + tresult r = s.load(state); + if (r != kResultTrue) + return r; + + for (StateListener* listener : _stateListeners) + listener->onStateChanged(); + + _state = s; + return kResultTrue; +} + +void SfizzVstController::addStateListener(StateListener* listener) +{ + _stateListeners.push_back(listener); +} + +void SfizzVstController::removeStateListener(StateListener* listener) +{ + auto it = std::find(_stateListeners.begin(), _stateListeners.end(), listener); + if (it != _stateListeners.end()) + _stateListeners.erase(it); +} + +FUnknown* SfizzVstController::createInstance(void*) +{ + return static_cast(new SfizzVstController); +} + +/* + Note(jpc) Generated at random with uuidgen. + Can't find docs on it... maybe it's to register somewhere? + */ +FUID SfizzVstController::cid(0x7129736c, 0xbc784134, 0xbb899d56, 0x2ebafe4f); diff --git a/vst/SfizzVstController.h b/vst/SfizzVstController.h new file mode 100644 index 00000000..47c3ba3c --- /dev/null +++ b/vst/SfizzVstController.h @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "SfizzVstState.h" +#include "public.sdk/source/vst/vsteditcontroller.h" +#include "public.sdk/source/vst/vstparameters.h" +#include "vstgui/plugin-bindings/vst3editor.h" +class SfizzVstState; + +using namespace Steinberg; +using namespace VSTGUI; + +class SfizzVstControllerNoUi : public Vst::EditController, + public Vst::IMidiMapping { +public: + virtual ~SfizzVstControllerNoUi() {} + + tresult PLUGIN_API initialize(FUnknown* context) override; + tresult PLUGIN_API terminate() override; + + tresult PLUGIN_API getMidiControllerAssignment(int32 busIndex, int16 channel, Vst::CtrlNumber midiControllerNumber, Vst::ParamID& id) override; + + enum { numControllerParams = 128 }; + + // interfaces + OBJ_METHODS(SfizzVstControllerNoUi, Vst::EditController) + DEFINE_INTERFACES + DEF_INTERFACE(Vst::IMidiMapping) + END_DEFINE_INTERFACES(Vst::EditController) + REFCOUNT_METHODS(Vst::EditController) + + enum { + kPidMidiCC0, + kPidMidiCCLast = kPidMidiCC0 + numControllerParams - 1, + kPidMidiAftertouch, + kPidMidiPitchBend, + /* Reserved */ + }; +}; + +class SfizzVstController : public SfizzVstControllerNoUi, public VSTGUI::VST3EditorDelegate { +public: + IPlugView* PLUGIN_API createView(FIDString name) override; + + tresult PLUGIN_API setParamNormalized(Vst::ParamID tag, Vst::ParamValue value) override; + tresult PLUGIN_API setComponentState(IBStream* state) override; + + struct StateListener { + virtual void onStateChanged() = 0; + }; + + const SfizzVstState& getSfizzState() const { return _state; } + + void addStateListener(StateListener* listener); + void removeStateListener(StateListener* listener); + + /// + static FUnknown* createInstance(void*); + + static FUID cid; + +private: + SfizzVstState _state; + std::vector _stateListeners; +}; diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp new file mode 100644 index 00000000..46bd7139 --- /dev/null +++ b/vst/SfizzVstEditor.cpp @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "SfizzVstEditor.h" +#include "SfizzVstState.h" +#if !defined(__APPLE__) && !defined(_WIN32) +#include "x11runloop.h" +#endif + +using namespace VSTGUI; + +static constexpr int kEditorWidth = 800; +static constexpr int kEditorHeight = 40; + +SfizzVstEditor::SfizzVstEditor(void *controller) + : VSTGUIEditor(controller) +{ + static_cast(getController())->addStateListener(this); +} + +SfizzVstEditor::~SfizzVstEditor() +{ + static_cast(getController())->removeStateListener(this); +} + +bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& platformType) +{ + CRect wsize(0, 0, kEditorWidth, kEditorHeight); + CFrame *frame = new CFrame(wsize, this); + this->frame = frame; + + IPlatformFrameConfig* config = nullptr; + +#if !defined(__APPLE__) && !defined(_WIN32) + X11::FrameConfig x11config; + x11config.runLoop = VSTGUI::owned(new RunLoop(plugFrame)); + config = &x11config; +#endif + + createFrameContents(); + updateStateDisplay(); + + frame->open(parent, platformType, config); + return true; +} + +void PLUGIN_API SfizzVstEditor::close() +{ + CFrame *frame = this->frame; + if (frame) { + frame->forget(); + this->frame = nullptr; + } +} + +/// +void SfizzVstEditor::valueChanged(CControl* ctl) +{ + int32_t tag = ctl->getTag(); + float value = ctl->getValue(); + + switch (tag) { + case kTagLoadSfzFile: + if (value != 1) + break; + + chooseSfzFile(); + + break; + } +} + +void SfizzVstEditor::onStateChanged() +{ + updateStateDisplay(); +} + +/// +void SfizzVstEditor::chooseSfzFile() +{ + SharedPointer fs(CNewFileSelector::create(frame)); + + fs->setTitle("Load SFZ file"); + fs->setDefaultExtension(CFileExtension("SFZ", "sfz")); + + if (fs->runModal()) { + UTF8StringPtr file = fs->getSelectedFile(0); + if (file) + loadSfzFile(file); + } +} + +void SfizzVstEditor::loadSfzFile(const std::string& filePath) +{ + _fileLabel->setText(filePath.c_str()); + + Vst::EditController* ctl = getController(); + + Vst::IMessage *msg = ctl->allocateMessage(); + if (msg) { + msg->setMessageID("LoadSfz"); + Vst::IAttributeList* attr = msg->getAttributes(); + attr->setString("File", Steinberg::String(filePath.c_str()).text()); + ctl->sendMessage(msg); + msg->release(); + } +} + +/// +class SimpleButton : public CControl { +public: + explicit SimpleButton(const CRect& size, IControlListener* listener = nullptr, int32_t tag = -1, UTF8StringPtr title = nullptr) + : CControl(size, listener, tag), _title(title ? title : "") { + } + + void draw(CDrawContext *dc) override + { + CRect bounds = getViewSize(); + dc->setFrameColor(CColor(0xff, 0xff, 0xff)); + dc->drawRect(bounds, kDrawStroked); + dc->drawString(_title.c_str(), bounds); + } + + CMouseEventResult onMouseDown(CPoint& where, const CButtonState& buttons) override + { + if (!buttons.isLeftButton()) + return kMouseEventNotHandled; + + value = getMin(); + if (isDirty()) { + valueChanged(); + invalid(); + } + value = getMax(); + if (isDirty()) + { + valueChanged(); + invalid(); + } + + return kMouseEventHandled; + } + + CLASS_METHODS(SimpleButton, CControl) + +private: + std::string _title; +}; + +/// +void SfizzVstEditor::createFrameContents() +{ + CFrame* frame = this->frame; + CRect bounds = frame->getViewSize(); + + CTextLabel *label; + CRect rect; + CRect rect2; + + rect = CRect(10.0, 10.0, 120.0, 30.0); + frame->addView(new SimpleButton(rect, this, kTagLoadSfzFile, "Load SFZ file")); + + rect2 = CRect(150.0, 10.0, bounds.right - 10.0, 30.0); + frame->addView((label = new CTextLabel(rect2, "no file"))); + label->setHoriAlign(kLeftText); + _fileLabel = label; +} + +void SfizzVstEditor::updateStateDisplay() +{ + if (!frame) + return; + + const SfizzVstState& state = static_cast(getController())->getSfizzState(); + + _fileLabel->setText(state.sfzFile.c_str()); +} diff --git a/vst/SfizzVstEditor.h b/vst/SfizzVstEditor.h new file mode 100644 index 00000000..4c3c44c5 --- /dev/null +++ b/vst/SfizzVstEditor.h @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "SfizzVstController.h" +#include "public.sdk/source/vst/vstguieditor.h" + +using namespace Steinberg; +using namespace VSTGUI; + +class SfizzVstEditor : public Vst::VSTGUIEditor, public IControlListener, public SfizzVstController::StateListener { +public: + explicit SfizzVstEditor(void *controller); + ~SfizzVstEditor(); + + bool PLUGIN_API open(void* parent, const VSTGUI::PlatformType& platformType = VSTGUI::kDefaultNative) override; + void PLUGIN_API close() override; + + // IControlListener + void valueChanged(CControl* ctl) override; + + // SfizzVstController::StateListener + void onStateChanged() override; + +private: + void chooseSfzFile(); + void loadSfzFile(const std::string& filePath); + + void createFrameContents(); + void updateStateDisplay(); + + enum { + kTagLoadSfzFile, + }; + + CTextLabel* _fileLabel = nullptr; +}; diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp new file mode 100644 index 00000000..88e71d1a --- /dev/null +++ b/vst/SfizzVstProcessor.cpp @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "SfizzVstProcessor.h" +#include "SfizzVstController.h" +#include "SfizzVstState.h" +#include "base/source/fstreamer.h" +#include "pluginterfaces/vst/ivstevents.h" +#include "pluginterfaces/vst/ivstparameterchanges.h" +#include + +#pragma message("TODO: send tempo") + +SfizzVstProcessor::SfizzVstProcessor() + : _fifoToWorker(1024) +{ + setControllerClass(SfizzVstController::cid); +} + +SfizzVstProcessor::~SfizzVstProcessor() +{ + setActive(false); // to be sure +} + +tresult PLUGIN_API SfizzVstProcessor::initialize(FUnknown* context) +{ + tresult result = AudioEffect::initialize(context); + if (result != kResultTrue) + return result; + + addAudioOutput(STR16("Audio Output"), Vst::SpeakerArr::kStereo); + addEventInput(STR16("Event Input"), 1); + + return result; +} + +tresult PLUGIN_API SfizzVstProcessor::setBusArrangements(Vst::SpeakerArrangement* inputs, int32 numIns, Vst::SpeakerArrangement* outputs, int32 numOuts) +{ + bool isStereo = numIns == 0 && numOuts == 1 && outputs[0] == Vst::SpeakerArr::kStereo; + + if (!isStereo) + return kResultFalse; + + return AudioEffect::setBusArrangements(inputs, numIns, outputs, numOuts); +} + +tresult PLUGIN_API SfizzVstProcessor::setState(IBStream* state) +{ + SfizzVstState s; + + tresult r = s.load(state); + if (r != kResultTrue) + return r; + + loadSfzFile(s.sfzFile); + + return r; +} + +tresult PLUGIN_API SfizzVstProcessor::getState(IBStream* state) +{ + SfizzVstState s; + { + std::lock_guard lock(_processMutex); + s.sfzFile = _sfzFile; + } + + return s.store(state); +} + +tresult PLUGIN_API SfizzVstProcessor::canProcessSampleSize(int32 symbolicSampleSize) +{ + if (symbolicSampleSize != Vst::kSample32) + return kResultFalse; + + return kResultTrue; +} + +tresult PLUGIN_API SfizzVstProcessor::setActive(TBool state) +{ + stopBackgroundWork(); + _synth.reset(); + + if (state) { + fprintf(stderr, "[Sfizz] new synth\n"); + sfz::Sfizz* synth = new sfz::Sfizz; + _synth.reset(synth); + + synth->setSampleRate(processSetup.sampleRate); + synth->setSamplesPerBlock(processSetup.maxSamplesPerBlock); + + loadSfzFile(_sfzFile); + + _workRunning = true; + _worker = std::thread([this]() { doBackgroundWork(); }); + } + + return kResultTrue; +} + +tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data) +{ + sfz::Sfizz& synth = *_synth; + + if (data.numOutputs < 1) // flush mode + return kResultTrue; + + uint32 numFrames = data.numSamples; + constexpr uint32 numChannels = 2; + float* outputs[numChannels]; + + assert(numChannels == data.outputs[0].numChannels); + + for (unsigned c = 0; c < numChannels; ++c) + outputs[c] = data.outputs[0].channelBuffers32[c]; + + std::unique_lock lock(_processMutex, std::try_to_lock); + if (!lock.owns_lock()) { + for (unsigned c = 0; c < numChannels; ++c) + std::memset(outputs[c], 0, numFrames * sizeof(float)); + data.outputs[0].silenceFlags = 3; + return kResultTrue; + } + + if (Vst::IParameterChanges* pc = data.inputParameterChanges) { + uint32 paramCount = pc->getParameterCount(); + + for (uint32 paramIndex = 0; paramIndex < paramCount; ++paramIndex) { + Vst::IParamValueQueue* vq = pc->getParameterData(paramIndex); + + Vst::ParamID id = vq->getParameterId(); + + switch (id) { + default: + if (id >= SfizzVstController::kPidMidiCC0 && id <= SfizzVstController::kPidMidiCCLast) { + int ccNumber = id - SfizzVstController::kPidMidiCC0; + for (uint32 pointIndex = 0, pointCount = vq->getPointCount(); pointIndex < pointCount; ++pointIndex) { + int32 sampleOffset; + Vst::ParamValue value; + if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue) + synth.cc(sampleOffset, ccNumber, (int)(0.5 + value * 127.0)); + } + } + break; + + case SfizzVstController::kPidMidiAftertouch: + for (uint32 pointIndex = 0, pointCount = vq->getPointCount(); pointIndex < pointCount; ++pointIndex) { + int32 sampleOffset; + Vst::ParamValue value; + if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue) + synth.aftertouch(sampleOffset, (int)(0.5 + value * 127.0)); + } + break; + + case SfizzVstController::kPidMidiPitchBend: + for (uint32 pointIndex = 0, pointCount = vq->getPointCount(); pointIndex < pointCount; ++pointIndex) { + int32 sampleOffset; + Vst::ParamValue value; + if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue) + synth.pitchWheel(sampleOffset, (int)(0.5 + value * 16383) - 8192); + } + break; + } + } + } + + if (Vst::IEventList* events = data.inputEvents) { + uint32 numEvents = events->getEventCount(); + + for (uint32 i = 0; i < numEvents; i++) { + Vst::Event e; + if (events->getEvent(i, e) != kResultTrue) + continue; + + auto convertVelocityFromFloat = [](float x) -> int { + return std::min(127, std::max(0, (int)(x * 127.0f))); + }; + + switch (e.type) { + case Vst::Event::kNoteOnEvent: + synth.noteOn(e.sampleOffset, e.noteOn.pitch, convertVelocityFromFloat(e.noteOn.velocity)); + break; + case Vst::Event::kNoteOffEvent: + synth.noteOff(e.sampleOffset, e.noteOff.pitch, convertVelocityFromFloat(e.noteOff.velocity)); + break; + // case Vst::Event::kPolyPressureEvent: + // synth.aftertouch(e.sampleOffset, convertVelocityFromFloat(e.polyPressure.pressure)); + // break; + } + } + } + + synth.renderBlock(outputs, numFrames, numChannels); + return kResultTrue; +} + +tresult PLUGIN_API SfizzVstProcessor::notify(Vst::IMessage* message) +{ + tresult result = AudioEffect::notify(message); + if (result != kResultFalse) + return result; + + if (!_fifoToWorker.push(message)) + return kOutOfMemory; + + message->addRef(); + _semaToWorker.post(); + + return kResultTrue; +} + +FUnknown* SfizzVstProcessor::createInstance(void*) +{ + return static_cast(new SfizzVstProcessor); +} + +void SfizzVstProcessor::loadSfzFile(std::string file) +{ + std::lock_guard lock(_processMutex); + + if (_synth) { + fprintf(stderr, "[Sfizz] load SFZ file: %s\n", file.c_str()); + _synth->loadSfzFile(file); + } + + _sfzFile = std::move(file); +} + +void SfizzVstProcessor::doBackgroundWork() +{ + constexpr uint32 maxPathLen = 32768; + + for (;;) { + _semaToWorker.wait(); + + if (!_workRunning) + break; + + Vst::IMessage* msg; + if (!_fifoToWorker.pop(msg)) { + fprintf(stderr, "[Sfizz] message synchronization error in worker\n"); + std::abort(); + } + + const char* id = msg->getMessageID(); + Vst::IAttributeList* attr = msg->getAttributes(); + + if (!std::strcmp(id, "LoadSfz")) { + std::vector path(maxPathLen + 1); + if (attr->getString("File", path.data(), maxPathLen) == kResultTrue) + loadSfzFile(Steinberg::String(path.data()).text8()); + } + + msg->release(); + } +} + +void SfizzVstProcessor::stopBackgroundWork() +{ + if (!_workRunning) + return; + + _workRunning = false; + _semaToWorker.post(); + _worker.join(); + + while (_semaToWorker.try_wait()) { + Vst::IMessage* msg; + if (!_fifoToWorker.pop(msg)) { + fprintf(stderr, "[Sfizz] message synchronization error in processor\n"); + std::abort(); + } + msg->release(); + } +} + +/* + Note(jpc) Generated at random with uuidgen. + Can't find docs on it... maybe it's to register somewhere? + */ +FUID SfizzVstProcessor::cid(0xe8fab718, 0x15ed46e3, 0x8b598310, 0x1e12993f); diff --git a/vst/SfizzVstProcessor.h b/vst/SfizzVstProcessor.h new file mode 100644 index 00000000..86bbab81 --- /dev/null +++ b/vst/SfizzVstProcessor.h @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "public.sdk/source/vst/vstaudioeffect.h" +#include "public.sdk/source/vst/utility/ringbuffer.h" +#include "RTSemaphore.h" +#include +#include +#include +#include + +using namespace Steinberg; + +class SfizzVstProcessor : public Vst::AudioEffect { +public: + SfizzVstProcessor(); + ~SfizzVstProcessor(); + + tresult PLUGIN_API initialize(FUnknown* context) override; + tresult PLUGIN_API setBusArrangements(Vst::SpeakerArrangement* inputs, int32 numIns, Vst::SpeakerArrangement* outputs, int32 numOuts) override; + + tresult PLUGIN_API setState(IBStream* state) override; + tresult PLUGIN_API getState(IBStream* state) override; + + tresult PLUGIN_API canProcessSampleSize(int32 symbolicSampleSize) override; + tresult PLUGIN_API setActive(TBool state) override; + tresult PLUGIN_API process(Vst::ProcessData& data) override; + + tresult PLUGIN_API notify(Vst::IMessage* message) override; + + static FUnknown* createInstance(void*); + + static FUID cid; + + // --- Sfizz stuff here below --- +private: + std::unique_ptr _synth; + std::thread _worker; + volatile bool _workRunning = false; + Steinberg::OneReaderOneWriter::RingBuffer _fifoToWorker; + RTSemaphore _semaToWorker; + std::mutex _processMutex; + + // state + std::string _sfzFile; + + // + void loadSfzFile(std::string file); + + // worker + void doBackgroundWork(); + void stopBackgroundWork(); +}; diff --git a/vst/SfizzVstState.cpp b/vst/SfizzVstState.cpp new file mode 100644 index 00000000..447f7ad0 --- /dev/null +++ b/vst/SfizzVstState.cpp @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "SfizzVstState.h" +#include +#include + +tresult SfizzVstState::load(IBStream* state) +{ + IBStreamer s(state, kLittleEndian); + + uint64 version = 0; + if (!s.readInt64u(version)) + return kResultFalse; + + while (const char* key = s.readStr8()) { + if (!std::strcmp(key, "SfzFile")) { + const char* value = s.readStr8(); + if (!value) + return kResultFalse; + sfzFile = value; + } + } + + return kResultTrue; +} + +tresult SfizzVstState::store(IBStream* state) const +{ + IBStreamer s(state, kLittleEndian); + + if (!s.writeInt64u(currentStateVersion)) + return kResultFalse; + + if (!s.writeStr8("SfzFile") || !s.writeStr8(sfzFile.c_str())) + return kResultFalse; + + return kResultTrue; +} diff --git a/vst/SfizzVstState.h b/vst/SfizzVstState.h new file mode 100644 index 00000000..df0adecc --- /dev/null +++ b/vst/SfizzVstState.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "base/source/fstreamer.h" +#include + +using namespace Steinberg; + +class SfizzVstState { +public: + std::string sfzFile; + + static constexpr uint64 currentStateVersion = 0; + + tresult load(IBStream* state); + tresult store(IBStream* state) const; +}; diff --git a/vst/VstPluginDefs.h.in b/vst/VstPluginDefs.h.in new file mode 100644 index 00000000..c67283d8 --- /dev/null +++ b/vst/VstPluginDefs.h.in @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#define VSTPLUGIN_NAME "@VSTPLUGIN_NAME@" +#define VSTPLUGIN_VENDOR "@VSTPLUGIN_VENDOR@" +#define VSTPLUGIN_URL "@VSTPLUGIN_URL@" +#define VSTPLUGIN_EMAIL "@VSTPLUGIN_EMAIL@" +#define VSTPLUGIN_VERSION "@PROJECT_VERSION@" diff --git a/vst/VstPluginFactory.cpp b/vst/VstPluginFactory.cpp new file mode 100644 index 00000000..cda0d7f3 --- /dev/null +++ b/vst/VstPluginFactory.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "SfizzVstProcessor.h" +#include "SfizzVstController.h" +#include "VstPluginDefs.h" +#include "public.sdk/source/main/pluginfactory.h" +#include "pluginterfaces/vst/ivstcomponent.h" +#include "pluginterfaces/vst/ivstaudioprocessor.h" +#include "pluginterfaces/vst/ivsteditcontroller.h" + +BEGIN_FACTORY_DEF(VSTPLUGIN_VENDOR, + VSTPLUGIN_URL, + "mailto:" VSTPLUGIN_EMAIL) + +DEF_CLASS2 (INLINE_UID_FROM_FUID(SfizzVstProcessor::cid), + PClassInfo::kManyInstances, + kVstAudioEffectClass, + VSTPLUGIN_NAME, + Vst::kDistributable, + Vst::PlugType::kInstrumentSynth, + VSTPLUGIN_VERSION, + kVstVersionString, + SfizzVstProcessor::createInstance) + +DEF_CLASS2 (INLINE_UID_FROM_FUID(SfizzVstController::cid), + PClassInfo::kManyInstances, + kVstComponentControllerClass, + VSTPLUGIN_NAME, + 0, // not used here + "", // not used here + VSTPLUGIN_VERSION, + kVstVersionString, + SfizzVstController::createInstance) + +END_FACTORY + +bool InitModule() +{ + return true; +} + +bool DeinitModule() +{ + return true; +} diff --git a/vst/cmake/Vst3.cmake b/vst/cmake/Vst3.cmake new file mode 100644 index 00000000..32b9b96a --- /dev/null +++ b/vst/cmake/Vst3.cmake @@ -0,0 +1,244 @@ +find_package(Threads REQUIRED) + +# --- VST3SDK --- +function(plugin_add_vst3sdk NAME) + target_sources("${NAME}" PRIVATE + "${VST3SDK_BASEDIR}/base/source/baseiids.cpp" + "${VST3SDK_BASEDIR}/base/source/fbuffer.cpp" + "${VST3SDK_BASEDIR}/base/source/fdebug.cpp" + "${VST3SDK_BASEDIR}/base/source/fdynlib.cpp" + "${VST3SDK_BASEDIR}/base/source/fobject.cpp" + "${VST3SDK_BASEDIR}/base/source/fstreamer.cpp" + "${VST3SDK_BASEDIR}/base/source/fstring.cpp" + # "${VST3SDK_BASEDIR}/base/source/timer.cpp" + "${VST3SDK_BASEDIR}/base/source/updatehandler.cpp" + "${VST3SDK_BASEDIR}/base/thread/source/fcondition.cpp" + "${VST3SDK_BASEDIR}/base/thread/source/flock.cpp" + "${VST3SDK_BASEDIR}/pluginterfaces/base/conststringtable.cpp" + "${VST3SDK_BASEDIR}/pluginterfaces/base/coreiids.cpp" + "${VST3SDK_BASEDIR}/pluginterfaces/base/funknown.cpp" + "${VST3SDK_BASEDIR}/pluginterfaces/base/ustring.cpp" + "${VST3SDK_BASEDIR}/public.sdk/source/common/commoniids.cpp" + "${VST3SDK_BASEDIR}/public.sdk/source/common/pluginview.cpp" + "${VST3SDK_BASEDIR}/public.sdk/source/main/pluginfactory.cpp" + "${VST3SDK_BASEDIR}/public.sdk/source/vst/vstaudioeffect.cpp" + "${VST3SDK_BASEDIR}/public.sdk/source/vst/vstbus.cpp" + "${VST3SDK_BASEDIR}/public.sdk/source/vst/vstcomponent.cpp" + "${VST3SDK_BASEDIR}/public.sdk/source/vst/vstcomponentbase.cpp" + "${VST3SDK_BASEDIR}/public.sdk/source/vst/vsteditcontroller.cpp" + "${VST3SDK_BASEDIR}/public.sdk/source/vst/vstinitiids.cpp" + "${VST3SDK_BASEDIR}/public.sdk/source/vst/vstnoteexpressiontypes.cpp" + "${VST3SDK_BASEDIR}/public.sdk/source/vst/vstparameters.cpp" + "${VST3SDK_BASEDIR}/public.sdk/source/vst/vstpresetfile.cpp" + "${VST3SDK_BASEDIR}/public.sdk/source/vst/vstrepresentation.cpp") + if(WIN32) + target_sources("${NAME}" PRIVATE + "${VST3SDK_BASEDIR}/public.sdk/source/common/threadchecker_win32.cpp" + "${VST3SDK_BASEDIR}/public.sdk/source/vst/vstgui_win32_bundle_support.cpp" + "${VST3SDK_BASEDIR}/public.sdk/source/main/dllmain.cpp") + elseif(APPLE) + target_sources("${NAME}" PRIVATE + "${VST3SDK_BASEDIR}/public.sdk/source/main/macmain.cpp") + else() + target_sources("${NAME}" PRIVATE + "${VST3SDK_BASEDIR}/public.sdk/source/common/threadchecker_linux.cpp" + "${VST3SDK_BASEDIR}/public.sdk/source/main/linuxmain.cpp") + endif() + target_include_directories("${NAME}" PRIVATE "${VST3SDK_BASEDIR}") + target_link_libraries("${NAME}" PRIVATE Threads::Threads) +endfunction() + +# --- VSTGUI --- +function(plugin_add_vstgui NAME) + target_sources("${NAME}" PRIVATE + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/animation/animations.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/animation/animator.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/animation/timingfunctions.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cbitmap.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cbitmapfilter.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/ccolor.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cdatabrowser.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cdrawcontext.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cdrawmethods.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cdropsource.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cfileselector.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cfont.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cframe.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cgradientview.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cgraphicspath.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/clayeredviewcontainer.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/clinestyle.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/coffscreencontext.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cautoanimation.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cbuttons.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/ccolorchooser.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/ccontrol.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cfontchooser.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cknob.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/clistcontrol.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cmoviebitmap.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cmoviebutton.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/coptionmenu.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cparamdisplay.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cscrollbar.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/csearchtextedit.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/csegmentbutton.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cslider.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cspecialdigit.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/csplashscreen.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cstringlist.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cswitch.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/ctextedit.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/ctextlabel.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cvumeter.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cxypad.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/copenglview.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cpoint.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/crect.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/crowcolumnview.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cscrollview.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cshadowviewcontainer.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/csplitview.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cstring.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/ctabview.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/ctooltipsupport.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cview.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cviewcontainer.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cvstguitimer.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/genericstringlistdatabrowsersource.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/common/genericoptionmenu.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/vstguidebug.cpp") + + if(WIN32) + target_sources("${NAME}" PRIVATE + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/common/fileresourceinputstream.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/direct2d/d2dbitmap.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/direct2d/d2ddrawcontext.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/direct2d/d2dfont.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/direct2d/d2dgraphicspath.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/win32datapackage.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/win32dragging.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/win32frame.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/win32openglview.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/win32optionmenu.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/win32support.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/win32textedit.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/winfileselector.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/winstring.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/wintimer.cpp") + elseif(APPLE) + target_sources("${NAME}" PRIVATE + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/common/fileresourceinputstream.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/common/genericoptionmenu.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/common/generictextedit.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/carbon/hiviewframe.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/carbon/hiviewoptionmenu.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/carbon/hiviewtextedit.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/caviewlayer.mm" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cfontmac.mm" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cgbitmap.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cgdrawcontext.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cocoa/autoreleasepool.mm" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cocoa/cocoahelpers.mm" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cocoa/cocoaopenglview.mm" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cocoa/cocoatextedit.mm" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cocoa/nsviewdraggingsession.mm" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cocoa/nsviewframe.mm" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cocoa/nsviewoptionmenu.mm" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/macclipboard.mm" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/macfileselector.mm" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/macglobals.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/macstring.mm" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/mactimer.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/quartzgraphicspath.cpp") + else() + target_sources("${NAME}" PRIVATE + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/common/fileresourceinputstream.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/common/generictextedit.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/cairobitmap.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/cairocontext.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/cairofont.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/cairogradient.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/cairopath.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/linuxstring.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/x11fileselector.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/x11frame.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/x11platform.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/x11timer.cpp" + "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/x11utils.cpp") + endif() + + target_include_directories("${NAME}" PRIVATE "${VST3SDK_BASEDIR}/vstgui4") + + if(WIN32) + # + elseif(APPLE) + # + else() + find_package(X11 REQUIRED) + find_package(Freetype REQUIRED) + find_package(PkgConfig REQUIRED) + pkg_check_modules(LIBXCB REQUIRED xcb) + pkg_check_modules(LIBXCB_UTIL REQUIRED xcb-util) + pkg_check_modules(LIBXCB_CURSOR REQUIRED xcb-cursor) + pkg_check_modules(LIBXCB_KEYSYMS REQUIRED xcb-keysyms) + pkg_check_modules(LIBXCB_XKB REQUIRED xcb-xkb) + pkg_check_modules(LIBXKB_COMMON REQUIRED xkbcommon) + pkg_check_modules(LIBXKB_COMMON_X11 REQUIRED xkbcommon-x11) + pkg_check_modules(CAIRO REQUIRED cairo) + pkg_check_modules(FONTCONFIG REQUIRED fontconfig) + target_include_directories("${NAME}" PRIVATE + ${X11_INCLUDE_DIRS} + ${FREETYPE_INCLUDE_DIRS} + ${LIBXCB_INCLUDE_DIRS} + ${LIBXCB_UTIL_INCLUDE_DIRS} + ${LIBXCB_CURSOR_INCLUDE_DIRS} + ${LIBXCB_KEYSYMS_INCLUDE_DIRS} + ${LIBXCB_XKB_INCLUDE_DIRS} + ${LIBXKB_COMMON_INCLUDE_DIRS} + ${LIBXKB_COMMON_X11_INCLUDE_DIRS} + ${CAIRO_INCLUDE_DIRS} + ${FONTCONFIG_INCLUDE_DIRS}) + target_link_libraries("${NAME}" PRIVATE + ${X11_LIBRARIES} + ${FREETYPE_LIBRARIES} + ${LIBXCB_LIBRARIES} + ${LIBXCB_UTIL_LIBRARIES} + ${LIBXCB_CURSOR_LIBRARIES} + ${LIBXCB_KEYSYMS_LIBRARIES} + ${LIBXCB_XKB_LIBRARIES} + ${LIBXKB_COMMON_LIBRARIES} + ${LIBXKB_COMMON_X11_LIBRARIES} + ${CAIRO_LIBRARIES} + ${FONTCONFIG_LIBRARIES}) + find_library(DL_LIBRARY "dl") + if(DL_LIBRARY) + target_link_libraries("${NAME}" PRIVATE "${DL_LIBRARY}") + endif() + endif() + + target_sources("${NAME}" PRIVATE + "${VST3SDK_BASEDIR}/public.sdk/source/vst/vstguieditor.cpp") + + target_include_directories("${NAME}" PRIVATE + external/steinberg/src) +endfunction() + +# --- VST3 Bundle architecture --- +if(NOT VST3_PACKAGE_ARCHITECTURE) + if(APPLE) + # VST3 packages are universal on Apple, architecture string not needed + else() + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + set(VST3_PACKAGE_ARCHITECTURE "x86_64") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$") + if(WIN32) + set(VST3_PACKAGE_ARCHITECTURE "x86") + else() + set(VST3_PACKAGE_ARCHITECTURE "i386") + endif() + else() + message(FATAL_ERROR "We don't know this architecture for VST3: ${CMAKE_SYSTEM_PROCESSOR}.") + endif() + endif() +endif() diff --git a/vst/external/steinberg/LICENSE b/vst/external/steinberg/LICENSE new file mode 100644 index 00000000..a75f1d5b --- /dev/null +++ b/vst/external/steinberg/LICENSE @@ -0,0 +1,27 @@ +//----------------------------------------------------------------------------- +// VSTGUI LICENSE +// (c) 2018, Steinberg Media Technologies, All Rights Reserved +//----------------------------------------------------------------------------- +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Steinberg Media Technologies nor the names of its +// contributors may be used to endorse or promote products derived from this +// software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +// OF THE POSSIBILITY OF SUCH DAMAGE. +//----------------------------------------------------------------------------- diff --git a/vst/external/steinberg/src/x11runloop.h b/vst/external/steinberg/src/x11runloop.h new file mode 100644 index 00000000..7cece455 --- /dev/null +++ b/vst/external/steinberg/src/x11runloop.h @@ -0,0 +1,110 @@ +#include "vstgui/lib/platform/linux/x11frame.h" +#include "pluginterfaces/gui/iplugview.h" +#include "base/source/fstring.h" + +namespace VSTGUI { + +// Map Steinberg Vst Interface to VSTGUI Interface +class RunLoop : public X11::IRunLoop, public AtomicReferenceCounted +{ +public: + struct EventHandler : Steinberg::Linux::IEventHandler, public Steinberg::FObject + { + X11::IEventHandler* handler {nullptr}; + + void PLUGIN_API onFDIsSet (Steinberg::Linux::FileDescriptor) override + { + if (handler) + handler->onEvent (); + } + DELEGATE_REFCOUNT (Steinberg::FObject) + DEFINE_INTERFACES + DEF_INTERFACE (Steinberg::Linux::IEventHandler) + END_DEFINE_INTERFACES (Steinberg::FObject) + }; + struct TimerHandler : Steinberg::Linux::ITimerHandler, public Steinberg::FObject + { + X11::ITimerHandler* handler {nullptr}; + + void PLUGIN_API onTimer () final + { + if (handler) + handler->onTimer (); + } + DELEGATE_REFCOUNT (Steinberg::FObject) + DEFINE_INTERFACES + DEF_INTERFACE (Steinberg::Linux::ITimerHandler) + END_DEFINE_INTERFACES (Steinberg::FObject) + }; + + bool registerEventHandler (int fd, X11::IEventHandler* handler) final + { + if(!runLoop) + return false; + + auto smtgHandler = Steinberg::owned (new EventHandler ()); + smtgHandler->handler = handler; + if (runLoop->registerEventHandler (smtgHandler, fd) == Steinberg::kResultTrue) + { + eventHandlers.push_back (smtgHandler); + return true; + } + return false; + } + bool unregisterEventHandler (X11::IEventHandler* handler) final + { + if(!runLoop) + return false; + + for (auto it = eventHandlers.begin (), end = eventHandlers.end (); it != end; ++it) + { + if ((*it)->handler == handler) + { + runLoop->unregisterEventHandler ((*it)); + eventHandlers.erase (it); + return true; + } + } + return false; + } + bool registerTimer (uint64_t interval, X11::ITimerHandler* handler) final + { + if(!runLoop) + return false; + + auto smtgHandler = Steinberg::owned (new TimerHandler ()); + smtgHandler->handler = handler; + if (runLoop->registerTimer (smtgHandler, interval) == Steinberg::kResultTrue) + { + timerHandlers.push_back (smtgHandler); + return true; + } + return false; + } + bool unregisterTimer (X11::ITimerHandler* handler) final + { + if(!runLoop) + return false; + + for (auto it = timerHandlers.begin (), end = timerHandlers.end (); it != end; ++it) + { + if ((*it)->handler == handler) + { + runLoop->unregisterTimer ((*it)); + timerHandlers.erase (it); + return true; + } + } + return false; + } + + RunLoop (Steinberg::FUnknown* runLoop) : runLoop (runLoop) {} +private: + using EventHandlers = std::vector>; + using TimerHandlers = std::vector>; + EventHandlers eventHandlers; + TimerHandlers timerHandlers; + Steinberg::FUnknownPtr runLoop; +}; + +} // namespace diff --git a/vst/vst3.version b/vst/vst3.version new file mode 100644 index 00000000..f86d95c3 --- /dev/null +++ b/vst/vst3.version @@ -0,0 +1,7 @@ +VST3ABI_1.0 { + global: + *GetPluginFactory*; + *ModuleEntry*; + *ModuleExit*; + local: *; +}; From f315ba5e290fe283b5b9254cfe075055953debbb Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 5 Mar 2020 13:59:37 +0100 Subject: [PATCH 02/42] Add the macOS VST bundle --- vst/CMakeLists.txt | 11 ++++++++++- vst/mac/Info.plist | 24 ++++++++++++++++++++++++ vst/mac/PkgInfo | 1 + 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 vst/mac/Info.plist create mode 100644 vst/mac/PkgInfo diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 4cafc961..7eaa90f7 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -58,14 +58,23 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") endif() # Create the bundle (see "VST 3 Locations / Format") +execute_process ( + COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents") if(WIN32) set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-win") # TODO: make desktop.ini, Plugin.ico elseif(APPLE) set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES + SUFFIX "" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/MacOS") - # TODO: make Info.plist, PkgInfo + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/mac/PkgInfo" + DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents") + set(SFIZZ_VST3_BUNDLE_EXECUTABLE "${PROJECT_NAME}") + set(SFIZZ_VST3_BUNDLE_VERSION "${PROJECT_VERSION}") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/mac/Info.plist" + "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Info.plist" @ONLY) + # TODO: create icons as sfizz.icns, and fill it in as CFBundleIconFile else() set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-linux") diff --git a/vst/mac/Info.plist b/vst/mac/Info.plist new file mode 100644 index 00000000..00c2b750 --- /dev/null +++ b/vst/mac/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + @SFIZZ_VST3_BUNDLE_EXECUTABLE@ + CFBundleIconFile + + CFBundleIdentifier + tools.sfz.sfizz + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + @SFIZZ_VST3_BUNDLE_VERSION@ + CSResourcesFileMapped + + + diff --git a/vst/mac/PkgInfo b/vst/mac/PkgInfo new file mode 100644 index 00000000..19a9cf67 --- /dev/null +++ b/vst/mac/PkgInfo @@ -0,0 +1 @@ +BNDL???? \ No newline at end of file From 29cf293d95494b0bd1c034278cf093fce504d364 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 5 Mar 2020 15:05:05 +0100 Subject: [PATCH 03/42] Add bundle icons of Windows and Mac --- scripts/create_mac_icon.sh | 18 ++++++++ scripts/create_windows_icon.sh | 18 ++++++++ vst/CMakeLists.txt | 7 ++- vst/mac/Info.plist | 2 +- vst/mac/Plugin.icns | Bin 0 -> 34703 bytes vst/resources/logo.svg | 78 +++++++++++++++++++++++++++++++++ vst/win/Plugin.ico | Bin 0 -> 351974 bytes vst/win/desktop.ini | 2 + 8 files changed, 122 insertions(+), 3 deletions(-) create mode 100755 scripts/create_mac_icon.sh create mode 100755 scripts/create_windows_icon.sh create mode 100644 vst/mac/Plugin.icns create mode 100644 vst/resources/logo.svg create mode 100644 vst/win/Plugin.ico create mode 100644 vst/win/desktop.ini diff --git a/scripts/create_mac_icon.sh b/scripts/create_mac_icon.sh new file mode 100755 index 00000000..3467da93 --- /dev/null +++ b/scripts/create_mac_icon.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -e + +svg_file="$1" +test -z "$svg_file" && exit 1 + +sizes="32 48 128 256" + +rm -f "$svg_file".icon.*.png + +for size in $sizes; do + png_file="$svg_file".icon."$size".png + inkscape -e "$png_file" "$svg_file" -w "$size" -h "$size" + optipng "$png_file" +done + +png2icns "$svg_file".icns "$svg_file".icon.*.png +rm -f "$svg_file".icon.*.png diff --git a/scripts/create_windows_icon.sh b/scripts/create_windows_icon.sh new file mode 100755 index 00000000..710fbdc8 --- /dev/null +++ b/scripts/create_windows_icon.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -e + +svg_file="$1" +test -z "$svg_file" && exit 1 + +sizes="32 48 128 256" + +rm -f "$svg_file".icon.*.png + +for size in $sizes; do + png_file="$svg_file".icon."$size".png + inkscape -e "$png_file" "$svg_file" -w "$size" -h "$size" + optipng "$png_file" +done + +icotool -c -o "$svg_file".ico "$svg_file".icon.*.png +rm -f "$svg_file".icon.*.png diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 7eaa90f7..808660c0 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -63,7 +63,9 @@ execute_process ( if(WIN32) set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-win") - # TODO: make desktop.ini, Plugin.ico + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/win/Plugin.ico" + "${CMAKE_CURRENT_SOURCE_DIR}/win/desktop.ini" + DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}") elseif(APPLE) set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES SUFFIX "" @@ -74,7 +76,8 @@ elseif(APPLE) set(SFIZZ_VST3_BUNDLE_VERSION "${PROJECT_VERSION}") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/mac/Info.plist" "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Info.plist" @ONLY) - # TODO: create icons as sfizz.icns, and fill it in as CFBundleIconFile + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/mac/Plugin.icns" + DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources") else() set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-linux") diff --git a/vst/mac/Info.plist b/vst/mac/Info.plist index 00c2b750..fe09355f 100644 --- a/vst/mac/Info.plist +++ b/vst/mac/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable @SFIZZ_VST3_BUNDLE_EXECUTABLE@ CFBundleIconFile - + Plugin.icns CFBundleIdentifier tools.sfz.sfizz CFBundleInfoDictionaryVersion diff --git a/vst/mac/Plugin.icns b/vst/mac/Plugin.icns new file mode 100644 index 0000000000000000000000000000000000000000..f8ce53c4c6ff49a7b7db1d70664f955ff0e68c83 GIT binary patch literal 34703 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 literal 0 HcmV?d00001 diff --git a/vst/resources/logo.svg b/vst/resources/logo.svg new file mode 100644 index 00000000..f4a65f2c --- /dev/null +++ b/vst/resources/logo.svg @@ -0,0 +1,78 @@ + + + + +Created by potrace 1.11, written by Peter Selinger 2001-2013 + + + + + + + + + + diff --git a/vst/win/Plugin.ico b/vst/win/Plugin.ico new file mode 100644 index 0000000000000000000000000000000000000000..516565763840869a9599eb1fecf90b068b7f048c GIT binary patch literal 351974 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 literal 0 HcmV?d00001 diff --git a/vst/win/desktop.ini b/vst/win/desktop.ini new file mode 100644 index 00000000..be3001a9 --- /dev/null +++ b/vst/win/desktop.ini @@ -0,0 +1,2 @@ +[.ShellClassInfo] +IconResource=Plugin.ico,0 From 8fc43bc0be963659d4e95609cb83eab9e5a91799 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 5 Mar 2020 15:53:01 +0100 Subject: [PATCH 04/42] Update of VST UI --- vst/CMakeLists.txt | 4 ++- vst/SfizzVstEditor.cpp | 79 ++++++++++++++++++++++++++++------------- vst/SfizzVstEditor.h | 1 + vst/resources/logo.png | Bin 0 -> 20594 bytes 4 files changed, 58 insertions(+), 26 deletions(-) create mode 100644 vst/resources/logo.png diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 808660c0..b9217f22 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -59,7 +59,9 @@ endif() # Create the bundle (see "VST 3 Locations / Format") execute_process ( - COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents") + COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources") +file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/resources/logo.png" + DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources") if(WIN32) set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-win") diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index 46bd7139..adad6f6d 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -12,11 +12,9 @@ using namespace VSTGUI; -static constexpr int kEditorWidth = 800; -static constexpr int kEditorHeight = 40; - SfizzVstEditor::SfizzVstEditor(void *controller) - : VSTGUIEditor(controller) + : VSTGUIEditor(controller), + _logo("logo.png") { static_cast(getController())->addStateListener(this); } @@ -28,7 +26,7 @@ SfizzVstEditor::~SfizzVstEditor() bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& platformType) { - CRect wsize(0, 0, kEditorWidth, kEditorHeight); + CRect wsize(0, 0, _logo.getWidth(), _logo.getHeight()); CFrame *frame = new CFrame(wsize, this); this->frame = frame; @@ -67,8 +65,7 @@ void SfizzVstEditor::valueChanged(CControl* ctl) if (value != 1) break; - chooseSfzFile(); - + Call::later([this]() { chooseSfzFile(); }); break; } } @@ -95,18 +92,23 @@ void SfizzVstEditor::chooseSfzFile() void SfizzVstEditor::loadSfzFile(const std::string& filePath) { - _fileLabel->setText(filePath.c_str()); - Vst::EditController* ctl = getController(); + Vst::IMessage *msg = ctl->allocateMessage(); - if (msg) { - msg->setMessageID("LoadSfz"); - Vst::IAttributeList* attr = msg->getAttributes(); - attr->setString("File", Steinberg::String(filePath.c_str()).text()); - ctl->sendMessage(msg); - msg->release(); + if (!msg) { + fprintf(stderr, "[Sfizz] UI could not allocate message\n"); + return; } + + msg->setMessageID("LoadSfz"); + Vst::IAttributeList* attr = msg->getAttributes(); + attr->setString("File", Steinberg::String(filePath.c_str()).text()); + ctl->sendMessage(msg); + msg->release(); + + if (_fileLabel) + _fileLabel->setText(("File: " + filePath).c_str()); } /// @@ -156,17 +158,43 @@ void SfizzVstEditor::createFrameContents() CFrame* frame = this->frame; CRect bounds = frame->getViewSize(); - CTextLabel *label; - CRect rect; - CRect rect2; + frame->setBackgroundColor(CColor(0xff, 0xff, 0xff)); - rect = CRect(10.0, 10.0, 120.0, 30.0); - frame->addView(new SimpleButton(rect, this, kTagLoadSfzFile, "Load SFZ file")); + CKickButton* sfizzButton = new CKickButton(bounds, this, kTagLoadSfzFile, &_logo); + frame->addView(sfizzButton); - rect2 = CRect(150.0, 10.0, bounds.right - 10.0, 30.0); - frame->addView((label = new CTextLabel(rect2, "no file"))); - label->setHoriAlign(kLeftText); - _fileLabel = label; + CRect bottomRow = bounds; + bottomRow.top = bottomRow.bottom - 30; + + CRect topRow = bounds; + topRow.bottom = topRow.top + 30; + + CTextLabel* descLabel = new CTextLabel( + bottomRow, "Paul Ferrand and the SFZ Tools work group"); + descLabel->setFontColor(CColor(0x00, 0x00, 0x00)); + descLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + frame->addView(descLabel); + + CRect fileBox = topRow; + fileBox.right = fileBox.left + 400; + CTextLabel* fileLabel = new CTextLabel(fileBox, "No file loaded"); + fileLabel->setFontColor(CColor(0x00, 0x00, 0x00)); + fileLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + // fileLabel->setHoriAlign(kLeftText); + frame->addView(fileLabel); + _fileLabel = fileLabel; + + // CTextLabel *label; + // CRect rect; + // CRect rect2; + + // rect = CRect(10.0, 10.0, 120.0, 30.0); + // frame->addView(new SimpleButton(rect, this, kTagLoadSfzFile, "Load SFZ file")); + + // rect2 = CRect(150.0, 10.0, bounds.right - 10.0, 30.0); + // frame->addView((label = new CTextLabel(rect2, "no file"))); + // label->setHoriAlign(kLeftText); + // _fileLabel = label; } void SfizzVstEditor::updateStateDisplay() @@ -176,5 +204,6 @@ void SfizzVstEditor::updateStateDisplay() const SfizzVstState& state = static_cast(getController())->getSfizzState(); - _fileLabel->setText(state.sfzFile.c_str()); + if (_fileLabel) + _fileLabel->setText(("File: " + state.sfzFile).c_str()); } diff --git a/vst/SfizzVstEditor.h b/vst/SfizzVstEditor.h index 4c3c44c5..44839788 100644 --- a/vst/SfizzVstEditor.h +++ b/vst/SfizzVstEditor.h @@ -36,5 +36,6 @@ private: kTagLoadSfzFile, }; + CBitmap _logo; CTextLabel* _fileLabel = nullptr; }; diff --git a/vst/resources/logo.png b/vst/resources/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e67a60a3b53ed37a95de6223ed33633d6f43107a GIT binary patch literal 20594 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 literal 0 HcmV?d00001 From 092b95fc3c6785b460c5d6c1d6ba9869563f5abe Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 5 Mar 2020 16:41:59 +0100 Subject: [PATCH 05/42] Update VST UI --- vst/SfizzVstEditor.cpp | 145 ++++++++++++++++++++++------------------- vst/SfizzVstEditor.h | 13 ++++ 2 files changed, 91 insertions(+), 67 deletions(-) diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index adad6f6d..4d5820d1 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -67,6 +67,11 @@ void SfizzVstEditor::valueChanged(CControl* ctl) Call::later([this]() { chooseSfzFile(); }); break; + + default: + if (tag >= kTagFirstChangePanel && tag <= kTagLastChangePanel) + setActivePanel(tag - kTagFirstChangePanel); + break; } } @@ -111,48 +116,6 @@ void SfizzVstEditor::loadSfzFile(const std::string& filePath) _fileLabel->setText(("File: " + filePath).c_str()); } -/// -class SimpleButton : public CControl { -public: - explicit SimpleButton(const CRect& size, IControlListener* listener = nullptr, int32_t tag = -1, UTF8StringPtr title = nullptr) - : CControl(size, listener, tag), _title(title ? title : "") { - } - - void draw(CDrawContext *dc) override - { - CRect bounds = getViewSize(); - dc->setFrameColor(CColor(0xff, 0xff, 0xff)); - dc->drawRect(bounds, kDrawStroked); - dc->drawString(_title.c_str(), bounds); - } - - CMouseEventResult onMouseDown(CPoint& where, const CButtonState& buttons) override - { - if (!buttons.isLeftButton()) - return kMouseEventNotHandled; - - value = getMin(); - if (isDirty()) { - valueChanged(); - invalid(); - } - value = getMax(); - if (isDirty()) - { - valueChanged(); - invalid(); - } - - return kMouseEventHandled; - } - - CLASS_METHODS(SimpleButton, CControl) - -private: - std::string _title; -}; - -/// void SfizzVstEditor::createFrameContents() { CFrame* frame = this->frame; @@ -160,41 +123,80 @@ void SfizzVstEditor::createFrameContents() frame->setBackgroundColor(CColor(0xff, 0xff, 0xff)); - CKickButton* sfizzButton = new CKickButton(bounds, this, kTagLoadSfzFile, &_logo); - frame->addView(sfizzButton); - CRect bottomRow = bounds; bottomRow.top = bottomRow.bottom - 30; CRect topRow = bounds; topRow.bottom = topRow.top + 30; - CTextLabel* descLabel = new CTextLabel( - bottomRow, "Paul Ferrand and the SFZ Tools work group"); - descLabel->setFontColor(CColor(0x00, 0x00, 0x00)); - descLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - frame->addView(descLabel); + CViewContainer* panel; + _activePanel = kPanelGeneral; - CRect fileBox = topRow; - fileBox.right = fileBox.left + 400; - CTextLabel* fileLabel = new CTextLabel(fileBox, "No file loaded"); - fileLabel->setFontColor(CColor(0x00, 0x00, 0x00)); - fileLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - // fileLabel->setHoriAlign(kLeftText); - frame->addView(fileLabel); - _fileLabel = fileLabel; + CRect topLeftLabelBox = topRow; + topLeftLabelBox.right -= 20 * kNumPanels; - // CTextLabel *label; - // CRect rect; - // CRect rect2; + // general panel + { + panel = new CViewContainer(bounds); + frame->addView(panel); + panel->setTransparency(true); - // rect = CRect(10.0, 10.0, 120.0, 30.0); - // frame->addView(new SimpleButton(rect, this, kTagLoadSfzFile, "Load SFZ file")); + CKickButton* sfizzButton = new CKickButton(bounds, this, kTagLoadSfzFile, &_logo); + panel->addView(sfizzButton); - // rect2 = CRect(150.0, 10.0, bounds.right - 10.0, 30.0); - // frame->addView((label = new CTextLabel(rect2, "no file"))); - // label->setHoriAlign(kLeftText); - // _fileLabel = label; + CTextLabel* topLeftLabel = new CTextLabel(topLeftLabelBox, "No file loaded"); + topLeftLabel->setFontColor(CColor(0x00, 0x00, 0x00)); + topLeftLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + panel->addView(topLeftLabel); + _fileLabel = topLeftLabel; + + _subPanels[kPanelGeneral] = panel; + } + + // settings panel + { + panel = new CViewContainer(bounds); + frame->addView(panel); + panel->setTransparency(true); + + CTextLabel* topLeftLabel = new CTextLabel(topLeftLabelBox, "Settings"); + topLeftLabel->setFontColor(CColor(0x00, 0x00, 0x00)); + topLeftLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + panel->addView(topLeftLabel); + + _subPanels[kPanelSettings] = panel; + } + + // all panels + for (unsigned currentPanel = 0; currentPanel < kNumPanels; ++currentPanel) { + panel = _subPanels[currentPanel]; + + CTextLabel* descLabel = new CTextLabel( + bottomRow, "Paul Ferrand and the SFZ Tools work group"); + descLabel->setFontColor(CColor(0x00, 0x00, 0x00)); + descLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + panel->addView(descLabel); + + for (unsigned i = 0; i < kNumPanels; ++i) { + CRect btnRect = topRow; + btnRect.left = topRow.right - (kNumPanels - i) * 20; + btnRect.right = btnRect.left + 20; + + const char *text; + switch (i) { + case kPanelGeneral: text = "G"; break; + case kPanelSettings: text = "S"; break; + default: text = "?"; break; + } + + CTextButton* changePanelButton = new CTextButton(btnRect, this, kTagFirstChangePanel + i, text); + panel->addView(changePanelButton); + + changePanelButton->setRoundRadius(0.0); + } + + panel->setVisible(currentPanel == _activePanel); + } } void SfizzVstEditor::updateStateDisplay() @@ -207,3 +209,12 @@ void SfizzVstEditor::updateStateDisplay() if (_fileLabel) _fileLabel->setText(("File: " + state.sfzFile).c_str()); } + +void SfizzVstEditor::setActivePanel(unsigned panelId) +{ + if (_activePanel != panelId) { + _subPanels[_activePanel]->setVisible(false); + _subPanels[panelId]->setVisible(true); + _activePanel = panelId; + } +} diff --git a/vst/SfizzVstEditor.h b/vst/SfizzVstEditor.h index 44839788..b293be5c 100644 --- a/vst/SfizzVstEditor.h +++ b/vst/SfizzVstEditor.h @@ -31,9 +31,22 @@ private: void createFrameContents(); void updateStateDisplay(); + void setActivePanel(unsigned panelId); + + enum { + kPanelGeneral, + // kPanelControls, + kPanelSettings, + kNumPanels, + }; + + unsigned _activePanel = 0; + CViewContainer* _subPanels[kNumPanels] = {}; enum { kTagLoadSfzFile, + kTagFirstChangePanel, + kTagLastChangePanel = kTagFirstChangePanel + kNumPanels - 1, }; CBitmap _logo; From d8b1a79fe7784f90569c9f666f1b7bbf0786a421 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Thu, 5 Mar 2020 18:21:46 +0100 Subject: [PATCH 06/42] Add other parameter: volume + the UI --- vst/CMakeLists.txt | 1 + vst/GUIComponents.cpp | 33 ++++++ vst/GUIComponents.h | 23 ++++ vst/SfizzVstController.cpp | 61 ++++++++-- vst/SfizzVstController.h | 20 ++-- vst/SfizzVstEditor.cpp | 149 +++++++++++++++++++++++-- vst/SfizzVstEditor.h | 18 +++ vst/SfizzVstProcessor.cpp | 223 ++++++++++++++++++++++--------------- vst/SfizzVstProcessor.h | 22 ++-- vst/SfizzVstState.cpp | 47 ++++++-- vst/SfizzVstState.h | 53 +++++++++ 11 files changed, 515 insertions(+), 135 deletions(-) create mode 100644 vst/GUIComponents.cpp create mode 100644 vst/GUIComponents.h diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index b9217f22..0d8c505f 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -40,6 +40,7 @@ add_library(${VSTPLUGIN_PRJ_NAME} MODULE SfizzVstController.cpp SfizzVstEditor.cpp SfizzVstState.cpp + GUIComponents.cpp VstPluginFactory.cpp) target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE ${PROJECT_NAME}::${PROJECT_NAME}) diff --git a/vst/GUIComponents.cpp b/vst/GUIComponents.cpp new file mode 100644 index 00000000..314ba642 --- /dev/null +++ b/vst/GUIComponents.cpp @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "GUIComponents.h" +#include "vstgui/lib/cdrawcontext.h" + +SimpleSlider::SimpleSlider(const CRect& bounds, IControlListener* listener, int32_t tag) + : CSliderBase(bounds, listener, tag) +{ + setStyle(kHorizontal|kLeft); + + CPoint offsetHandle(2.0, 2.0); + setOffsetHandle(offsetHandle); + + CCoord handleSize = 20.0; + setHandleSizePrivate(handleSize, bounds.bottom - bounds.top - 2 * offsetHandle.y); + setHandleRangePrivate(bounds.right - bounds.left - handleSize - 2 * offsetHandle.x); +} + +void SimpleSlider::draw(CDrawContext* dc) +{ + CRect bounds = getViewSize(); + CRect handle = calculateHandleRect(getValueNormalized()); + + dc->setFrameColor(_frame); + dc->drawRect(bounds, kDrawStroked); + + dc->setFillColor(_fill); + dc->drawRect(handle, kDrawFilled); +} diff --git a/vst/GUIComponents.h b/vst/GUIComponents.h new file mode 100644 index 00000000..003d219b --- /dev/null +++ b/vst/GUIComponents.h @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include "vstgui/lib/controls/cslider.h" +#include "vstgui/lib/ccolor.h" + +using namespace VSTGUI; + +class SimpleSlider : public CSliderBase { +public: + SimpleSlider(const CRect& bounds, IControlListener* listener, int32_t tag); + void draw(CDrawContext* dc) override; + + CLASS_METHODS(SimpleSlider, CSliderBase) + +private: + CColor _frame = CColor(0x00, 0x00, 0x00); + CColor _fill = CColor(0x00, 0x00, 0x00); +}; diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp index 88fcc6f0..fc7cfe5e 100644 --- a/vst/SfizzVstController.cpp +++ b/vst/SfizzVstController.cpp @@ -17,8 +17,14 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) Vst::ParamID pid = 0; + // Ordinary parameters + parameters.addParameter( + kParamVolumeRange.createParameter( + Steinberg::String("Volume"), pid++, Steinberg::String("dB"), + 0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId)); + // MIDI controllers - for (unsigned i = 0; i < numControllerParams; ++i) { + for (unsigned i = 0; i < kNumControllerParams; ++i) { Steinberg::String title; Steinberg::String shortTitle; title.printf("Controller %u", i); @@ -53,7 +59,7 @@ tresult PLUGIN_API SfizzVstControllerNoUi::getMidiControllerAssignment(int32 bus return kResultTrue; default: - if (midiControllerNumber < 0 || midiControllerNumber >= numControllerParams) + if (midiControllerNumber < 0 || midiControllerNumber >= kNumControllerParams) return kResultFalse; id = kPidMidiCC0 + midiControllerNumber; @@ -73,15 +79,53 @@ IPlugView* PLUGIN_API SfizzVstController::createView(FIDString _name) return new SfizzVstEditor(this); } -tresult PLUGIN_API SfizzVstController::setParamNormalized(Vst::ParamID tag, Vst::ParamValue value) +tresult PLUGIN_API SfizzVstController::setParamNormalized(Vst::ParamID tag, Vst::ParamValue normValue) { - tresult r = SfizzVstControllerNoUi::setParamNormalized(tag, value); + tresult r = SfizzVstControllerNoUi::setParamNormalized(tag, normValue); if (r != kResultTrue) return r; + float *slot = nullptr; + float value = 0; + + switch (tag) { + case kPidVolume: { + slot = &_state.volume; + value = kParamVolumeRange.denormalize(normValue); + break; + } + } + + if (slot && *slot != value) { + *slot = value; + for (StateListener* listener : _stateListeners) + listener->onStateChanged(); + } + return kResultTrue; } +tresult PLUGIN_API SfizzVstController::setState(IBStream* state) +{ + SfizzUiState s; + + tresult r = s.load(state); + if (r != kResultTrue) + return r; + + _uiState = s; + + for (StateListener* listener : _stateListeners) + listener->onStateChanged(); + + return kResultTrue; +} + +tresult PLUGIN_API SfizzVstController::getState(IBStream* state) +{ + return _uiState.store(state); +} + tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* state) { SfizzVstState s; @@ -90,19 +134,22 @@ tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* state) if (r != kResultTrue) return r; + _state = s; + + setParamNormalized(kPidVolume, kParamVolumeRange.normalize(s.volume)); + for (StateListener* listener : _stateListeners) listener->onStateChanged(); - _state = s; return kResultTrue; } -void SfizzVstController::addStateListener(StateListener* listener) +void SfizzVstController::addSfizzStateListener(StateListener* listener) { _stateListeners.push_back(listener); } -void SfizzVstController::removeStateListener(StateListener* listener) +void SfizzVstController::removeSfizzStateListener(StateListener* listener) { auto it = std::find(_stateListeners.begin(), _stateListeners.end(), listener); if (it != _stateListeners.end()) diff --git a/vst/SfizzVstController.h b/vst/SfizzVstController.h index 47c3ba3c..e8ca3037 100644 --- a/vst/SfizzVstController.h +++ b/vst/SfizzVstController.h @@ -24,22 +24,12 @@ public: tresult PLUGIN_API getMidiControllerAssignment(int32 busIndex, int16 channel, Vst::CtrlNumber midiControllerNumber, Vst::ParamID& id) override; - enum { numControllerParams = 128 }; - // interfaces OBJ_METHODS(SfizzVstControllerNoUi, Vst::EditController) DEFINE_INTERFACES DEF_INTERFACE(Vst::IMidiMapping) END_DEFINE_INTERFACES(Vst::EditController) REFCOUNT_METHODS(Vst::EditController) - - enum { - kPidMidiCC0, - kPidMidiCCLast = kPidMidiCC0 + numControllerParams - 1, - kPidMidiAftertouch, - kPidMidiPitchBend, - /* Reserved */ - }; }; class SfizzVstController : public SfizzVstControllerNoUi, public VSTGUI::VST3EditorDelegate { @@ -47,6 +37,8 @@ public: IPlugView* PLUGIN_API createView(FIDString name) override; tresult PLUGIN_API setParamNormalized(Vst::ParamID tag, Vst::ParamValue value) override; + tresult PLUGIN_API setState(IBStream* state) override; + tresult PLUGIN_API getState(IBStream* state) override; tresult PLUGIN_API setComponentState(IBStream* state) override; struct StateListener { @@ -55,8 +47,11 @@ public: const SfizzVstState& getSfizzState() const { return _state; } - void addStateListener(StateListener* listener); - void removeStateListener(StateListener* listener); + const SfizzUiState& getSfizzUiState() const { return _uiState; } + SfizzUiState& getSfizzUiState() { return _uiState; } + + void addSfizzStateListener(StateListener* listener); + void removeSfizzStateListener(StateListener* listener); /// static FUnknown* createInstance(void*); @@ -65,5 +60,6 @@ public: private: SfizzVstState _state; + SfizzUiState _uiState; std::vector _stateListeners; }; diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index 4d5820d1..9b197331 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -6,6 +6,7 @@ #include "SfizzVstEditor.h" #include "SfizzVstState.h" +#include "GUIComponents.h" #if !defined(__APPLE__) && !defined(_WIN32) #include "x11runloop.h" #endif @@ -16,12 +17,12 @@ SfizzVstEditor::SfizzVstEditor(void *controller) : VSTGUIEditor(controller), _logo("logo.png") { - static_cast(getController())->addStateListener(this); + getController()->addSfizzStateListener(this); } SfizzVstEditor::~SfizzVstEditor() { - static_cast(getController())->removeStateListener(this); + getController()->removeSfizzStateListener(this); } bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& platformType) @@ -59,6 +60,8 @@ void SfizzVstEditor::valueChanged(CControl* ctl) { int32_t tag = ctl->getTag(); float value = ctl->getValue(); + float valueNorm = ctl->getValueNormalized(); + SfizzVstController* controller = getController(); switch (tag) { case kTagLoadSfzFile: @@ -68,6 +71,11 @@ void SfizzVstEditor::valueChanged(CControl* ctl) Call::later([this]() { chooseSfzFile(); }); break; + case kTagSetVolume: + controller->setParamNormalized(kPidVolume, valueNorm); + controller->performEdit(kPidVolume, valueNorm); + break; + default: if (tag >= kTagFirstChangePanel && tag <= kTagLastChangePanel) setActivePanel(tag - kTagFirstChangePanel); @@ -75,6 +83,33 @@ void SfizzVstEditor::valueChanged(CControl* ctl) } } +void SfizzVstEditor::enterOrLeaveEdit(CControl* ctl, bool enter) +{ + int32_t tag = ctl->getTag(); + Vst::ParamID id; + + switch (tag) { + case kTagSetVolume: id = kPidVolume; break; + default: return; + } + + SfizzVstController* controller = getController(); + if (enter) + controller->beginEdit(id); + else + controller->endEdit(id); +} + +void SfizzVstEditor::controlBeginEdit(CControl* ctl) +{ + enterOrLeaveEdit(ctl, true); +} + +void SfizzVstEditor::controlEndEdit(CControl* ctl) +{ + enterOrLeaveEdit(ctl, false); +} + void SfizzVstEditor::onStateChanged() { updateStateDisplay(); @@ -97,8 +132,7 @@ void SfizzVstEditor::chooseSfzFile() void SfizzVstEditor::loadSfzFile(const std::string& filePath) { - Vst::EditController* ctl = getController(); - + SfizzVstController* ctl = getController(); Vst::IMessage *msg = ctl->allocateMessage(); if (!msg) { @@ -118,6 +152,9 @@ void SfizzVstEditor::loadSfzFile(const std::string& filePath) void SfizzVstEditor::createFrameContents() { + SfizzVstController* controller = getController(); + const SfizzUiState& uiState = controller->getSfizzUiState(); + CFrame* frame = this->frame; CRect bounds = frame->getViewSize(); @@ -130,7 +167,7 @@ void SfizzVstEditor::createFrameContents() topRow.bottom = topRow.top + 30; CViewContainer* panel; - _activePanel = kPanelGeneral; + _activePanel = std::max(0, std::min(kNumPanels - 1, static_cast(uiState.activePanel))); CRect topLeftLabelBox = topRow; topLeftLabelBox.right -= 20 * kNumPanels; @@ -164,6 +201,88 @@ void SfizzVstEditor::createFrameContents() topLeftLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); panel->addView(topLeftLabel); + CRect row = topRow; + row.top += 200.0; + row.bottom += 200.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; + }; + + CTextLabel* label; + SimpleSlider* slider; + + label = new CTextLabel(leftSide(), "Volume"); + 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, kTagSetVolume); + adjustMinMaxToRangeParam(slider, kPidVolume); + panel->addView(slider); + _volumeSlider = slider; + + // row.top += interRow; + // row.bottom += interRow; + + // label = new CTextLabel(leftSide(), "Polyphony"); + // 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, -1); + // panel->addView(slider); + + // row.top += interRow; + // row.bottom += interRow; + + // label = new CTextLabel(leftSide(), "Oversampling"); + // 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, -1); + // panel->addView(slider); + + // row.top += interRow; + // row.bottom += interRow; + + // label = new CTextLabel(leftSide(), "Preload size"); + // 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, -1); + // panel->addView(slider); + + // row.top += interRow; + // row.bottom += interRow; + + // label = new CTextLabel(leftSide(), "Freewheel"); + // 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, -1); + // panel->addView(slider); + _subPanels[kPanelSettings] = panel; } @@ -204,17 +323,31 @@ void SfizzVstEditor::updateStateDisplay() if (!frame) return; - const SfizzVstState& state = static_cast(getController())->getSfizzState(); + SfizzVstController* controller = getController(); + const SfizzVstState& state = controller->getSfizzState(); + const SfizzUiState& uiState = controller->getSfizzUiState(); if (_fileLabel) _fileLabel->setText(("File: " + state.sfzFile).c_str()); + if (_volumeSlider) + _volumeSlider->setValue(state.volume); + + setActivePanel(uiState.activePanel); } void SfizzVstEditor::setActivePanel(unsigned panelId) { + panelId = std::max(0, std::min(kNumPanels - 1, static_cast(panelId))); + + getController()->getSfizzUiState().activePanel = panelId; + if (_activePanel != panelId) { - _subPanels[_activePanel]->setVisible(false); - _subPanels[panelId]->setVisible(true); + if (frame) + _subPanels[_activePanel]->setVisible(false); + _activePanel = panelId; + + if (frame) + _subPanels[panelId]->setVisible(true); } } diff --git a/vst/SfizzVstEditor.h b/vst/SfizzVstEditor.h index b293be5c..1acd7492 100644 --- a/vst/SfizzVstEditor.h +++ b/vst/SfizzVstEditor.h @@ -19,8 +19,16 @@ public: bool PLUGIN_API open(void* parent, const VSTGUI::PlatformType& platformType = VSTGUI::kDefaultNative) override; void PLUGIN_API close() override; + SfizzVstController* getController() const + { + return static_cast(Vst::VSTGUIEditor::getController()); + } + // IControlListener void valueChanged(CControl* ctl) override; + void enterOrLeaveEdit(CControl* ctl, bool enter); + void controlBeginEdit(CControl* ctl) override; + void controlEndEdit(CControl* ctl) override; // SfizzVstController::StateListener void onStateChanged() override; @@ -33,6 +41,14 @@ private: void updateStateDisplay(); void setActivePanel(unsigned panelId); + template + void adjustMinMaxToRangeParam(Control* c, Vst::ParamID id) + { + auto* p = static_cast(getController()->getParameterObject(id)); + c->setMin(p->getMin()); + c->setMax(p->getMax()); + } + enum { kPanelGeneral, // kPanelControls, @@ -45,10 +61,12 @@ private: enum { kTagLoadSfzFile, + kTagSetVolume, kTagFirstChangePanel, kTagLastChangePanel = kTagFirstChangePanel + kNumPanels - 1, }; CBitmap _logo; CTextLabel* _fileLabel = nullptr; + CSliderBase *_volumeSlider = nullptr; }; diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index 88e71d1a..6a7160df 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -34,6 +34,8 @@ tresult PLUGIN_API SfizzVstProcessor::initialize(FUnknown* context) addAudioOutput(STR16("Audio Output"), Vst::SpeakerArr::kStereo); addEventInput(STR16("Event Input"), 1); + _state = SfizzVstState(); + return result; } @@ -47,28 +49,37 @@ tresult PLUGIN_API SfizzVstProcessor::setBusArrangements(Vst::SpeakerArrangement return AudioEffect::setBusArrangements(inputs, numIns, outputs, numOuts); } -tresult PLUGIN_API SfizzVstProcessor::setState(IBStream* state) +tresult PLUGIN_API SfizzVstProcessor::setState(IBStream* stream) { SfizzVstState s; - tresult r = s.load(state); + tresult r = s.load(stream); if (r != kResultTrue) return r; - loadSfzFile(s.sfzFile); + std::lock_guard lock(_processMutex); + _state = s; + + syncStateToSynth(); return r; } -tresult PLUGIN_API SfizzVstProcessor::getState(IBStream* state) +tresult PLUGIN_API SfizzVstProcessor::getState(IBStream* stream) { - SfizzVstState s; - { - std::lock_guard lock(_processMutex); - s.sfzFile = _sfzFile; - } + std::lock_guard lock(_processMutex); + return _state.store(stream); +} - return s.store(state); +void SfizzVstProcessor::syncStateToSynth() +{ + sfz::Sfizz* synth = _synth.get(); + + if (!synth) + return; + + synth->loadSfzFile(_state.sfzFile); + synth->setVolume(_state.volume); } tresult PLUGIN_API SfizzVstProcessor::canProcessSampleSize(int32 symbolicSampleSize) @@ -92,7 +103,7 @@ tresult PLUGIN_API SfizzVstProcessor::setActive(TBool state) synth->setSampleRate(processSetup.sampleRate); synth->setSamplesPerBlock(processSetup.maxSamplesPerBlock); - loadSfzFile(_sfzFile); + syncStateToSynth(); _workRunning = true; _worker = std::thread([this]() { doBackgroundWork(); }); @@ -105,6 +116,11 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data) { sfz::Sfizz& synth = *_synth; + if (Vst::IParameterChanges* pc = data.inputParameterChanges) { + std::unique_lock lock(_processMutex, std::try_to_lock); + processParameterChanges(*pc); + } + if (data.numOutputs < 1) // flush mode return kResultTrue; @@ -118,6 +134,7 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data) outputs[c] = data.outputs[0].channelBuffers32[c]; std::unique_lock lock(_processMutex, std::try_to_lock); + if (!lock.owns_lock()) { for (unsigned c = 0; c < numChannels; ++c) std::memset(outputs[c], 0, numFrames * sizeof(float)); @@ -125,78 +142,113 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data) return kResultTrue; } - if (Vst::IParameterChanges* pc = data.inputParameterChanges) { - uint32 paramCount = pc->getParameterCount(); + if (Vst::IParameterChanges* pc = data.inputParameterChanges) + processControllerChanges(*pc); - for (uint32 paramIndex = 0; paramIndex < paramCount; ++paramIndex) { - Vst::IParamValueQueue* vq = pc->getParameterData(paramIndex); + if (Vst::IEventList* events = data.inputEvents) + processEvents(*events); - Vst::ParamID id = vq->getParameterId(); - - switch (id) { - default: - if (id >= SfizzVstController::kPidMidiCC0 && id <= SfizzVstController::kPidMidiCCLast) { - int ccNumber = id - SfizzVstController::kPidMidiCC0; - for (uint32 pointIndex = 0, pointCount = vq->getPointCount(); pointIndex < pointCount; ++pointIndex) { - int32 sampleOffset; - Vst::ParamValue value; - if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue) - synth.cc(sampleOffset, ccNumber, (int)(0.5 + value * 127.0)); - } - } - break; - - case SfizzVstController::kPidMidiAftertouch: - for (uint32 pointIndex = 0, pointCount = vq->getPointCount(); pointIndex < pointCount; ++pointIndex) { - int32 sampleOffset; - Vst::ParamValue value; - if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue) - synth.aftertouch(sampleOffset, (int)(0.5 + value * 127.0)); - } - break; - - case SfizzVstController::kPidMidiPitchBend: - for (uint32 pointIndex = 0, pointCount = vq->getPointCount(); pointIndex < pointCount; ++pointIndex) { - int32 sampleOffset; - Vst::ParamValue value; - if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue) - synth.pitchWheel(sampleOffset, (int)(0.5 + value * 16383) - 8192); - } - break; - } - } - } - - if (Vst::IEventList* events = data.inputEvents) { - uint32 numEvents = events->getEventCount(); - - for (uint32 i = 0; i < numEvents; i++) { - Vst::Event e; - if (events->getEvent(i, e) != kResultTrue) - continue; - - auto convertVelocityFromFloat = [](float x) -> int { - return std::min(127, std::max(0, (int)(x * 127.0f))); - }; - - switch (e.type) { - case Vst::Event::kNoteOnEvent: - synth.noteOn(e.sampleOffset, e.noteOn.pitch, convertVelocityFromFloat(e.noteOn.velocity)); - break; - case Vst::Event::kNoteOffEvent: - synth.noteOff(e.sampleOffset, e.noteOff.pitch, convertVelocityFromFloat(e.noteOff.velocity)); - break; - // case Vst::Event::kPolyPressureEvent: - // synth.aftertouch(e.sampleOffset, convertVelocityFromFloat(e.polyPressure.pressure)); - // break; - } - } - } + synth.setVolume(_state.volume); synth.renderBlock(outputs, numFrames, numChannels); return kResultTrue; } +void SfizzVstProcessor::processParameterChanges(Vst::IParameterChanges& pc) +{ + uint32 paramCount = pc.getParameterCount(); + + for (uint32 paramIndex = 0; paramIndex < paramCount; ++paramIndex) { + Vst::IParamValueQueue* vq = pc.getParameterData(paramIndex); + if (!vq) + continue; + + Vst::ParamID id = vq->getParameterId(); + uint32 pointCount = vq->getPointCount(); + int32 sampleOffset; + Vst::ParamValue value; + + switch (id) { + case kPidVolume: + if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) + _state.volume = kParamVolumeRange.denormalize(value); + break; + } + } +} + +void SfizzVstProcessor::processControllerChanges(Vst::IParameterChanges& pc) +{ + sfz::Sfizz& synth = *_synth; + uint32 paramCount = pc.getParameterCount(); + + for (uint32 paramIndex = 0; paramIndex < paramCount; ++paramIndex) { + Vst::IParamValueQueue* vq = pc.getParameterData(paramIndex); + if (!vq) + continue; + + Vst::ParamID id = vq->getParameterId(); + uint32 pointCount = vq->getPointCount(); + int32 sampleOffset; + Vst::ParamValue value; + + switch (id) { + default: + if (id >= kPidMidiCC0 && id <= kPidMidiCCLast) { + int ccNumber = id - kPidMidiCC0; + for (uint32 pointIndex = 0; pointIndex < pointCount; ++pointIndex) { + if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue) + synth.cc(sampleOffset, ccNumber, (int)(0.5 + value * 127.0)); + } + } + break; + + case kPidMidiAftertouch: + for (uint32 pointIndex = 0; pointIndex < pointCount; ++pointIndex) { + if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue) + synth.aftertouch(sampleOffset, (int)(0.5 + value * 127.0)); + } + break; + + case kPidMidiPitchBend: + for (uint32 pointIndex = 0; pointIndex < pointCount; ++pointIndex) { + if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue) + synth.pitchWheel(sampleOffset, (int)(0.5 + value * 16383) - 8192); + } + break; + } + } +} + +void SfizzVstProcessor::processEvents(Vst::IEventList& events) +{ + sfz::Sfizz& synth = *_synth; + uint32 numEvents = events.getEventCount(); + + for (uint32 i = 0; i < numEvents; i++) { + Vst::Event e; + if (events.getEvent(i, e) != kResultTrue) + continue; + + switch (e.type) { + case Vst::Event::kNoteOnEvent: + synth.noteOn(e.sampleOffset, e.noteOn.pitch, convertVelocityFromFloat(e.noteOn.velocity)); + break; + case Vst::Event::kNoteOffEvent: + synth.noteOff(e.sampleOffset, e.noteOff.pitch, convertVelocityFromFloat(e.noteOff.velocity)); + break; + // case Vst::Event::kPolyPressureEvent: + // synth.aftertouch(e.sampleOffset, convertVelocityFromFloat(e.polyPressure.pressure)); + // break; + } + } +} + +int SfizzVstProcessor::convertVelocityFromFloat(float x) +{ + return std::min(127, std::max(0, (int)(x * 127.0f))); +} + tresult PLUGIN_API SfizzVstProcessor::notify(Vst::IMessage* message) { tresult result = AudioEffect::notify(message); @@ -217,18 +269,6 @@ FUnknown* SfizzVstProcessor::createInstance(void*) return static_cast(new SfizzVstProcessor); } -void SfizzVstProcessor::loadSfzFile(std::string file) -{ - std::lock_guard lock(_processMutex); - - if (_synth) { - fprintf(stderr, "[Sfizz] load SFZ file: %s\n", file.c_str()); - _synth->loadSfzFile(file); - } - - _sfzFile = std::move(file); -} - void SfizzVstProcessor::doBackgroundWork() { constexpr uint32 maxPathLen = 32768; @@ -250,8 +290,11 @@ void SfizzVstProcessor::doBackgroundWork() if (!std::strcmp(id, "LoadSfz")) { std::vector path(maxPathLen + 1); - if (attr->getString("File", path.data(), maxPathLen) == kResultTrue) - loadSfzFile(Steinberg::String(path.data()).text8()); + if (attr->getString("File", path.data(), maxPathLen) == kResultTrue) { + std::lock_guard lock(_processMutex); + _state.sfzFile = Steinberg::String(path.data()).text8(); + _synth->loadSfzFile(_state.sfzFile); + } } msg->release(); diff --git a/vst/SfizzVstProcessor.h b/vst/SfizzVstProcessor.h index 86bbab81..86811e75 100644 --- a/vst/SfizzVstProcessor.h +++ b/vst/SfizzVstProcessor.h @@ -5,9 +5,10 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#include "SfizzVstState.h" +#include "RTSemaphore.h" #include "public.sdk/source/vst/vstaudioeffect.h" #include "public.sdk/source/vst/utility/ringbuffer.h" -#include "RTSemaphore.h" #include #include #include @@ -23,12 +24,17 @@ public: tresult PLUGIN_API initialize(FUnknown* context) override; tresult PLUGIN_API setBusArrangements(Vst::SpeakerArrangement* inputs, int32 numIns, Vst::SpeakerArrangement* outputs, int32 numOuts) override; - tresult PLUGIN_API setState(IBStream* state) override; - tresult PLUGIN_API getState(IBStream* state) override; + tresult PLUGIN_API setState(IBStream* stream) override; + tresult PLUGIN_API getState(IBStream* stream) override; + void syncStateToSynth(); tresult PLUGIN_API canProcessSampleSize(int32 symbolicSampleSize) override; tresult PLUGIN_API setActive(TBool state) override; tresult PLUGIN_API process(Vst::ProcessData& data) override; + void processParameterChanges(Vst::IParameterChanges& pc); + void processControllerChanges(Vst::IParameterChanges& pc); + void processEvents(Vst::IEventList& events); + static int convertVelocityFromFloat(float x); tresult PLUGIN_API notify(Vst::IMessage* message) override; @@ -38,19 +44,17 @@ public: // --- Sfizz stuff here below --- private: + // synth state. acquire processMutex before accessing std::unique_ptr _synth; + SfizzVstState _state; + + // worker and thread sync std::thread _worker; volatile bool _workRunning = false; Steinberg::OneReaderOneWriter::RingBuffer _fifoToWorker; RTSemaphore _semaToWorker; std::mutex _processMutex; - // state - std::string _sfzFile; - - // - void loadSfzFile(std::string file); - // worker void doBackgroundWork(); void stopBackgroundWork(); diff --git a/vst/SfizzVstState.cpp b/vst/SfizzVstState.cpp index 447f7ad0..fffeaae2 100644 --- a/vst/SfizzVstState.cpp +++ b/vst/SfizzVstState.cpp @@ -16,14 +16,13 @@ tresult SfizzVstState::load(IBStream* state) if (!s.readInt64u(version)) return kResultFalse; - while (const char* key = s.readStr8()) { - if (!std::strcmp(key, "SfzFile")) { - const char* value = s.readStr8(); - if (!value) - return kResultFalse; - sfzFile = value; - } - } + if (const char* str = s.readStr8()) + sfzFile = str; + else + return kResultFalse; + + if (!s.readFloat(volume)) + return kResultFalse; return kResultTrue; } @@ -35,7 +34,37 @@ tresult SfizzVstState::store(IBStream* state) const if (!s.writeInt64u(currentStateVersion)) return kResultFalse; - if (!s.writeStr8("SfzFile") || !s.writeStr8(sfzFile.c_str())) + if (!s.writeStr8(sfzFile.c_str())) + return kResultFalse; + + if (!s.writeFloat(volume)) + return kResultFalse; + + return kResultTrue; +} + +tresult SfizzUiState::load(IBStream* state) +{ + IBStreamer s(state, kLittleEndian); + + uint64 version = 0; + if (!s.readInt64u(version)) + return kResultFalse; + + if (!s.readInt32u(activePanel)) + return kResultFalse; + + return kResultTrue; +} + +tresult SfizzUiState::store(IBStream* state) const +{ + IBStreamer s(state, kLittleEndian); + + if (!s.writeInt64u(currentStateVersion)) + return kResultFalse; + + if (!s.writeInt32u(activePanel)) return kResultFalse; return kResultTrue; diff --git a/vst/SfizzVstState.h b/vst/SfizzVstState.h index df0adecc..f1cfc563 100644 --- a/vst/SfizzVstState.h +++ b/vst/SfizzVstState.h @@ -6,16 +6,69 @@ #pragma once #include "base/source/fstreamer.h" +#include "public.sdk/source/vst/vstparameters.h" #include using namespace Steinberg; +// number of MIDI CC +enum { + kNumControllerParams = 128, +}; + +// parameters +enum { + kPidVolume, + kPidMidiCC0, + kPidMidiCCLast = kPidMidiCC0 + kNumControllerParams - 1, + kPidMidiAftertouch, + kPidMidiPitchBend, + /* Reserved */ +}; + class SfizzVstState { public: std::string sfzFile; + float volume = 0; static constexpr uint64 currentStateVersion = 0; tresult load(IBStream* state); tresult store(IBStream* state) const; }; + +class SfizzUiState { +public: + unsigned activePanel = 0; + + static constexpr uint64 currentStateVersion = 0; + + tresult load(IBStream* state); + tresult store(IBStream* state) const; +}; + +struct SfizzParameterRange { + float def = 0.0; + float min = 0.0; + float max = 1.0; + + constexpr SfizzParameterRange() {} + constexpr SfizzParameterRange(float def, float min, float max) : def(def), min(min), max(max) {} + + constexpr float normalize(float x) const noexcept + { + return (x - min) / (max - min); + } + + constexpr float denormalize(float x) const noexcept + { + return min + x * (max - min); + } + + Vst::RangeParameter* createParameter(const Vst::TChar *title, Vst::ParamID tag, const Vst::TChar *units = nullptr, int32 stepCount = 0, int32 flags = Vst::ParameterInfo::kCanAutomate, Vst::UnitID unitID = Vst::kRootUnitId, const Vst::TChar *shortTitle = nullptr) const + { + return new Vst::RangeParameter(title, tag, units, min, max, def, stepCount, flags, unitID, shortTitle); + } +}; + +static constexpr SfizzParameterRange kParamVolumeRange(0.0, -60.0, +6.0); From aa9a5d26f4b4a86659bf947072eeba13d75d3f0f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 11:46:49 +0100 Subject: [PATCH 07/42] Add the polyphony parameter --- vst/SfizzVstController.cpp | 29 +++++++++++++++++++++++++---- vst/SfizzVstEditor.cpp | 32 +++++++++++++++++++++----------- vst/SfizzVstEditor.h | 2 ++ vst/SfizzVstProcessor.cpp | 23 +++++++++++++++++++++++ vst/SfizzVstState.cpp | 6 ++++++ vst/SfizzVstState.h | 3 +++ 6 files changed, 80 insertions(+), 15 deletions(-) diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp index fc7cfe5e..eba85ca2 100644 --- a/vst/SfizzVstController.cpp +++ b/vst/SfizzVstController.cpp @@ -22,6 +22,10 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) kParamVolumeRange.createParameter( Steinberg::String("Volume"), pid++, Steinberg::String("dB"), 0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId)); + parameters.addParameter( + kParamNumVoicesRange.createParameter( + Steinberg::String("Polyphony"), pid++, nullptr, + 0, Vst::ParameterInfo::kNoFlags, Vst::kRootUnitId)); // MIDI controllers for (unsigned i = 0; i < kNumControllerParams; ++i) { @@ -85,19 +89,35 @@ tresult PLUGIN_API SfizzVstController::setParamNormalized(Vst::ParamID tag, Vst: if (r != kResultTrue) return r; - float *slot = nullptr; + float *slotF32 = nullptr; + int32 *slotI32 = nullptr; float value = 0; switch (tag) { case kPidVolume: { - slot = &_state.volume; + slotF32 = &_state.volume; value = kParamVolumeRange.denormalize(normValue); break; } + case kPidNumVoices: { + slotI32 = &_state.numVoices; + value = kParamNumVoicesRange.denormalize(normValue); + break; + } } - if (slot && *slot != value) { - *slot = value; + bool update = false; + + if (slotF32 && *slotF32 != value) { + *slotF32 = value; + update = true; + } + else if (slotI32 && *slotI32 != (int32)value) { + *slotI32 = (int32)value; + update = true; + } + + if (update) { for (StateListener* listener : _stateListeners) listener->onStateChanged(); } @@ -137,6 +157,7 @@ tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* state) _state = s; setParamNormalized(kPidVolume, kParamVolumeRange.normalize(s.volume)); + setParamNormalized(kPidNumVoices, kParamNumVoicesRange.normalize(s.numVoices)); for (StateListener* listener : _stateListeners) listener->onStateChanged(); diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index 9b197331..d3079626 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -76,6 +76,11 @@ void SfizzVstEditor::valueChanged(CControl* ctl) controller->performEdit(kPidVolume, valueNorm); break; + case kTagSetNumVoices: + controller->setParamNormalized(kPidNumVoices, valueNorm); + controller->performEdit(kPidNumVoices, valueNorm); + break; + default: if (tag >= kTagFirstChangePanel && tag <= kTagLastChangePanel) setActivePanel(tag - kTagFirstChangePanel); @@ -90,6 +95,7 @@ void SfizzVstEditor::enterOrLeaveEdit(CControl* ctl, bool enter) switch (tag) { case kTagSetVolume: id = kPidVolume; break; + case kTagSetNumVoices: id = kPidNumVoices; break; default: return; } @@ -231,21 +237,23 @@ void SfizzVstEditor::createFrameContents() label->setHoriAlign(kLeftText); panel->addView(label); slider = new SimpleSlider(rightSide(), this, kTagSetVolume); - adjustMinMaxToRangeParam(slider, kPidVolume); panel->addView(slider); + adjustMinMaxToRangeParam(slider, kPidVolume); _volumeSlider = slider; - // row.top += interRow; - // row.bottom += interRow; + row.top += interRow; + row.bottom += interRow; - // label = new CTextLabel(leftSide(), "Polyphony"); - // 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, -1); - // panel->addView(slider); + label = new CTextLabel(leftSide(), "Polyphony"); + 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, kTagSetNumVoices); + panel->addView(slider); + adjustMinMaxToRangeParam(slider, kPidNumVoices); + _numVoicesSlider = slider; // row.top += interRow; // row.bottom += interRow; @@ -331,6 +339,8 @@ void SfizzVstEditor::updateStateDisplay() _fileLabel->setText(("File: " + state.sfzFile).c_str()); if (_volumeSlider) _volumeSlider->setValue(state.volume); + if (_numVoicesSlider) + _numVoicesSlider->setValue(state.numVoices); setActivePanel(uiState.activePanel); } diff --git a/vst/SfizzVstEditor.h b/vst/SfizzVstEditor.h index 1acd7492..e71bd284 100644 --- a/vst/SfizzVstEditor.h +++ b/vst/SfizzVstEditor.h @@ -62,6 +62,7 @@ private: enum { kTagLoadSfzFile, kTagSetVolume, + kTagSetNumVoices, kTagFirstChangePanel, kTagLastChangePanel = kTagFirstChangePanel + kNumPanels - 1, }; @@ -69,4 +70,5 @@ private: CBitmap _logo; CTextLabel* _fileLabel = nullptr; CSliderBase *_volumeSlider = nullptr; + CSliderBase *_numVoicesSlider = nullptr; }; diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index 6a7160df..5cdafaf9 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -80,6 +80,7 @@ void SfizzVstProcessor::syncStateToSynth() synth->loadSfzFile(_state.sfzFile); synth->setVolume(_state.volume); + synth->setNumVoices(_state.numVoices); } tresult PLUGIN_API SfizzVstProcessor::canProcessSampleSize(int32 symbolicSampleSize) @@ -173,6 +174,21 @@ void SfizzVstProcessor::processParameterChanges(Vst::IParameterChanges& pc) if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) _state.volume = kParamVolumeRange.denormalize(value); break; + case kPidNumVoices: + if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) { + Vst::IMessage* msg = allocateMessage(); + if (!msg) + break; + msg->setMessageID("SetNumVoices"); + Vst::IAttributeList* attr = msg->getAttributes(); + attr->setInt("NumVoices", kParamNumVoicesRange.denormalize(value)); + if (!_fifoToWorker.push(msg)) { + msg->release(); + break; + } + _semaToWorker.post(); + } + break; } } } @@ -296,6 +312,13 @@ void SfizzVstProcessor::doBackgroundWork() _synth->loadSfzFile(_state.sfzFile); } } + else if (!std::strcmp(id, "SetNumVoices")) { + int64 value; + if (attr->getInt("NumVoices", value) == kResultTrue) { + _state.numVoices = value; + _synth->setNumVoices(value); + } + } msg->release(); } diff --git a/vst/SfizzVstState.cpp b/vst/SfizzVstState.cpp index fffeaae2..6c951314 100644 --- a/vst/SfizzVstState.cpp +++ b/vst/SfizzVstState.cpp @@ -24,6 +24,9 @@ tresult SfizzVstState::load(IBStream* state) if (!s.readFloat(volume)) return kResultFalse; + if (!s.readInt32(numVoices)) + return kResultFalse; + return kResultTrue; } @@ -40,6 +43,9 @@ tresult SfizzVstState::store(IBStream* state) const if (!s.writeFloat(volume)) return kResultFalse; + if (!s.writeInt32(numVoices)) + return kResultFalse; + return kResultTrue; } diff --git a/vst/SfizzVstState.h b/vst/SfizzVstState.h index f1cfc563..f68412f6 100644 --- a/vst/SfizzVstState.h +++ b/vst/SfizzVstState.h @@ -19,6 +19,7 @@ enum { // parameters enum { kPidVolume, + kPidNumVoices, kPidMidiCC0, kPidMidiCCLast = kPidMidiCC0 + kNumControllerParams - 1, kPidMidiAftertouch, @@ -30,6 +31,7 @@ class SfizzVstState { public: std::string sfzFile; float volume = 0; + int numVoices = 64; static constexpr uint64 currentStateVersion = 0; @@ -72,3 +74,4 @@ struct SfizzParameterRange { }; static constexpr SfizzParameterRange kParamVolumeRange(0.0, -60.0, +6.0); +static constexpr SfizzParameterRange kParamNumVoicesRange(64.0, 1.0, 256.0); From 26ba7f33b0bca9d7e98840cf90b8fdddd27438fb Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 11:55:52 +0100 Subject: [PATCH 08/42] Add oversampling --- vst/SfizzVstController.cpp | 44 ++++++++++++++++++++++++++++++++++++++ vst/SfizzVstController.h | 4 ++++ vst/SfizzVstEditor.cpp | 38 +++++++++++++++++++++----------- vst/SfizzVstEditor.h | 2 ++ vst/SfizzVstProcessor.cpp | 25 ++++++++++++++++++++++ vst/SfizzVstState.cpp | 20 +++++++++++++++++ vst/SfizzVstState.h | 8 +++++++ 7 files changed, 129 insertions(+), 12 deletions(-) diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp index eba85ca2..065c41fa 100644 --- a/vst/SfizzVstController.cpp +++ b/vst/SfizzVstController.cpp @@ -26,6 +26,10 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) kParamNumVoicesRange.createParameter( Steinberg::String("Polyphony"), pid++, nullptr, 0, Vst::ParameterInfo::kNoFlags, Vst::kRootUnitId)); + parameters.addParameter( + kParamOversamplingRange.createParameter( + Steinberg::String("Oversampling"), pid++, nullptr, + 0, Vst::ParameterInfo::kNoFlags, Vst::kRootUnitId)); // MIDI controllers for (unsigned i = 0; i < kNumControllerParams; ++i) { @@ -71,6 +75,40 @@ tresult PLUGIN_API SfizzVstControllerNoUi::getMidiControllerAssignment(int32 bus } } +tresult PLUGIN_API SfizzVstControllerNoUi::getParamStringByValue(Vst::ParamID tag, Vst::ParamValue valueNormalized, Vst::String128 string) +{ + switch (tag) { + case kPidOversampling: + { + int factor = SfizzMisc::adaptOversamplingFactor( + kParamOversamplingRange.denormalize(valueNormalized)); + Steinberg::String buf; + buf.printf("%dX", factor); + buf.copyTo(string); + return kResultTrue; + } + } + + return EditController::getParamStringByValue(tag, valueNormalized, string); +} + +tresult PLUGIN_API SfizzVstControllerNoUi::getParamValueByString(Vst::ParamID tag, Vst::TChar* string, Vst::ParamValue& valueNormalized) +{ + switch (tag) { + case kPidOversampling: + { + int factor; + if (!Steinberg::String::scanInt32(string, factor, false)) + factor = 1; + valueNormalized = kParamOversamplingRange.normalize( + SfizzMisc::adaptOversamplingFactor(factor)); + return kResultTrue; + } + } + + return EditController::getParamValueByString(tag, string, valueNormalized); +} + // --- Controller with UI --- // IPlugView* PLUGIN_API SfizzVstController::createView(FIDString _name) @@ -104,6 +142,11 @@ tresult PLUGIN_API SfizzVstController::setParamNormalized(Vst::ParamID tag, Vst: value = kParamNumVoicesRange.denormalize(normValue); break; } + case kPidOversampling: { + slotI32 = &_state.oversampling; + value = kParamOversamplingRange.denormalize(normValue); + break; + } } bool update = false; @@ -158,6 +201,7 @@ tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* state) setParamNormalized(kPidVolume, kParamVolumeRange.normalize(s.volume)); setParamNormalized(kPidNumVoices, kParamNumVoicesRange.normalize(s.numVoices)); + setParamNormalized(kPidOversampling, kParamOversamplingRange.normalize(s.oversampling)); for (StateListener* listener : _stateListeners) listener->onStateChanged(); diff --git a/vst/SfizzVstController.h b/vst/SfizzVstController.h index e8ca3037..b8455ecd 100644 --- a/vst/SfizzVstController.h +++ b/vst/SfizzVstController.h @@ -24,6 +24,10 @@ public: tresult PLUGIN_API getMidiControllerAssignment(int32 busIndex, int16 channel, Vst::CtrlNumber midiControllerNumber, Vst::ParamID& id) override; + tresult PLUGIN_API getParamStringByValue(Vst::ParamID tag, Vst::ParamValue valueNormalized, Vst::String128 string) override; + tresult PLUGIN_API getParamValueByString(Vst::ParamID tag, Vst::TChar* string, Vst::ParamValue& valueNormalized) override; + + // interfaces OBJ_METHODS(SfizzVstControllerNoUi, Vst::EditController) DEFINE_INTERFACES diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index d3079626..65da051a 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -81,6 +81,11 @@ void SfizzVstEditor::valueChanged(CControl* ctl) controller->performEdit(kPidNumVoices, valueNorm); break; + case kTagSetOversampling: + controller->setParamNormalized(kPidOversampling, valueNorm); + controller->performEdit(kPidOversampling, valueNorm); + break; + default: if (tag >= kTagFirstChangePanel && tag <= kTagLastChangePanel) setActivePanel(tag - kTagFirstChangePanel); @@ -96,6 +101,7 @@ void SfizzVstEditor::enterOrLeaveEdit(CControl* ctl, bool enter) switch (tag) { case kTagSetVolume: id = kPidVolume; break; case kTagSetNumVoices: id = kPidNumVoices; break; + case kTagSetOversampling: id = kPidOversampling; break; default: return; } @@ -255,17 +261,19 @@ void SfizzVstEditor::createFrameContents() adjustMinMaxToRangeParam(slider, kPidNumVoices); _numVoicesSlider = slider; - // row.top += interRow; - // row.bottom += interRow; + row.top += interRow; + row.bottom += interRow; - // label = new CTextLabel(leftSide(), "Oversampling"); - // 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, -1); - // panel->addView(slider); + label = new CTextLabel(leftSide(), "Oversampling"); + 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, kTagSetOversampling); + panel->addView(slider); + adjustMinMaxToRangeParam(slider, kPidOversampling); + _oversamplingSlider = slider; // row.top += interRow; // row.bottom += interRow; @@ -276,8 +284,10 @@ void SfizzVstEditor::createFrameContents() // label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); // label->setHoriAlign(kLeftText); // panel->addView(label); - // slider = new SimpleSlider(rightSide(), this, -1); + // slider = new SimpleSlider(rightSide(), this, kTag); // panel->addView(slider); + // adjustMinMaxToRangeParam(slider, kPid); + // _aSlider = slider; // row.top += interRow; // row.bottom += interRow; @@ -288,8 +298,10 @@ void SfizzVstEditor::createFrameContents() // label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); // label->setHoriAlign(kLeftText); // panel->addView(label); - // slider = new SimpleSlider(rightSide(), this, -1); + // slider = new SimpleSlider(rightSide(), this, kTag); // panel->addView(slider); + // adjustMinMaxToRangeParam(slider, kPid); + // _aSlider = slider; _subPanels[kPanelSettings] = panel; } @@ -341,6 +353,8 @@ void SfizzVstEditor::updateStateDisplay() _volumeSlider->setValue(state.volume); if (_numVoicesSlider) _numVoicesSlider->setValue(state.numVoices); + if (_oversamplingSlider) + _oversamplingSlider->setValue(state.oversampling); setActivePanel(uiState.activePanel); } diff --git a/vst/SfizzVstEditor.h b/vst/SfizzVstEditor.h index e71bd284..353db127 100644 --- a/vst/SfizzVstEditor.h +++ b/vst/SfizzVstEditor.h @@ -63,6 +63,7 @@ private: kTagLoadSfzFile, kTagSetVolume, kTagSetNumVoices, + kTagSetOversampling, kTagFirstChangePanel, kTagLastChangePanel = kTagFirstChangePanel + kNumPanels - 1, }; @@ -71,4 +72,5 @@ private: CTextLabel* _fileLabel = nullptr; CSliderBase *_volumeSlider = nullptr; CSliderBase *_numVoicesSlider = nullptr; + CSliderBase *_oversamplingSlider = nullptr; }; diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index 5cdafaf9..b7111dce 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -81,6 +81,8 @@ void SfizzVstProcessor::syncStateToSynth() synth->loadSfzFile(_state.sfzFile); synth->setVolume(_state.volume); synth->setNumVoices(_state.numVoices); + synth->setOversamplingFactor( + SfizzMisc::adaptOversamplingFactor(_state.oversampling)); } tresult PLUGIN_API SfizzVstProcessor::canProcessSampleSize(int32 symbolicSampleSize) @@ -189,6 +191,21 @@ void SfizzVstProcessor::processParameterChanges(Vst::IParameterChanges& pc) _semaToWorker.post(); } break; + case kPidOversampling: + if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) { + Vst::IMessage* msg = allocateMessage(); + if (!msg) + break; + msg->setMessageID("SetOversampling"); + Vst::IAttributeList* attr = msg->getAttributes(); + attr->setInt("Oversampling", kParamOversamplingRange.denormalize(value)); + if (!_fifoToWorker.push(msg)) { + msg->release(); + break; + } + _semaToWorker.post(); + } + break; } } } @@ -319,6 +336,14 @@ void SfizzVstProcessor::doBackgroundWork() _synth->setNumVoices(value); } } + else if (!std::strcmp(id, "SetOversampling")) { + int64 value; + if (attr->getInt("Oversampling", value) == kResultTrue) { + _state.oversampling = value; + _synth->setOversamplingFactor( + SfizzMisc::adaptOversamplingFactor(value)); + } + } msg->release(); } diff --git a/vst/SfizzVstState.cpp b/vst/SfizzVstState.cpp index 6c951314..0b416c3d 100644 --- a/vst/SfizzVstState.cpp +++ b/vst/SfizzVstState.cpp @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "SfizzVstState.h" +#include #include #include @@ -27,6 +28,9 @@ tresult SfizzVstState::load(IBStream* state) if (!s.readInt32(numVoices)) return kResultFalse; + if (!s.readInt32(oversampling)) + return kResultFalse; + return kResultTrue; } @@ -46,6 +50,9 @@ tresult SfizzVstState::store(IBStream* state) const if (!s.writeInt32(numVoices)) return kResultFalse; + if (!s.writeInt32(oversampling)) + return kResultFalse; + return kResultTrue; } @@ -75,3 +82,16 @@ tresult SfizzUiState::store(IBStream* state) const return kResultTrue; } + +/// +int SfizzMisc::adaptOversamplingFactor(int valueDenorm) +{ + if (valueDenorm >= 8) + return SFIZZ_OVERSAMPLING_X8; + else if (valueDenorm >= 4) + return SFIZZ_OVERSAMPLING_X4; + else if (valueDenorm >= 2) + return SFIZZ_OVERSAMPLING_X2; + else + return SFIZZ_OVERSAMPLING_X1; +} diff --git a/vst/SfizzVstState.h b/vst/SfizzVstState.h index f68412f6..6bc6dbe5 100644 --- a/vst/SfizzVstState.h +++ b/vst/SfizzVstState.h @@ -20,6 +20,7 @@ enum { enum { kPidVolume, kPidNumVoices, + kPidOversampling, kPidMidiCC0, kPidMidiCCLast = kPidMidiCC0 + kNumControllerParams - 1, kPidMidiAftertouch, @@ -32,6 +33,7 @@ public: std::string sfzFile; float volume = 0; int numVoices = 64; + int oversampling = 1; static constexpr uint64 currentStateVersion = 0; @@ -75,3 +77,9 @@ struct SfizzParameterRange { static constexpr SfizzParameterRange kParamVolumeRange(0.0, -60.0, +6.0); static constexpr SfizzParameterRange kParamNumVoicesRange(64.0, 1.0, 256.0); +static constexpr SfizzParameterRange kParamOversamplingRange(1.0, 1.0, 8.0); + +class SfizzMisc { +public: + static int adaptOversamplingFactor(int factor); +}; From ca044d98c50952ad945fa29cdd2f2b029d24c0a1 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 13:15:32 +0100 Subject: [PATCH 09/42] Preload size and log2 oversampling --- vst/SfizzVstController.cpp | 29 +++++++++++++++++++++-------- vst/SfizzVstEditor.cpp | 34 +++++++++++++++++++++------------- vst/SfizzVstEditor.h | 2 ++ vst/SfizzVstProcessor.cpp | 31 ++++++++++++++++++++++++++----- vst/SfizzVstState.cpp | 23 ++++++++--------------- vst/SfizzVstState.h | 12 +++++------- 6 files changed, 83 insertions(+), 48 deletions(-) diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp index 065c41fa..984a2521 100644 --- a/vst/SfizzVstController.cpp +++ b/vst/SfizzVstController.cpp @@ -30,6 +30,10 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) kParamOversamplingRange.createParameter( Steinberg::String("Oversampling"), pid++, nullptr, 0, Vst::ParameterInfo::kNoFlags, Vst::kRootUnitId)); + parameters.addParameter( + kParamPreloadSizeRange.createParameter( + Steinberg::String("Preload size"), pid++, nullptr, + 0, Vst::ParameterInfo::kNoFlags, Vst::kRootUnitId)); // MIDI controllers for (unsigned i = 0; i < kNumControllerParams; ++i) { @@ -80,10 +84,9 @@ tresult PLUGIN_API SfizzVstControllerNoUi::getParamStringByValue(Vst::ParamID ta switch (tag) { case kPidOversampling: { - int factor = SfizzMisc::adaptOversamplingFactor( - kParamOversamplingRange.denormalize(valueNormalized)); + int factorLog2 = kParamOversamplingRange.denormalize(valueNormalized); Steinberg::String buf; - buf.printf("%dX", factor); + buf.printf("%dX", 1 << factorLog2); buf.copyTo(string); return kResultTrue; } @@ -98,10 +101,14 @@ tresult PLUGIN_API SfizzVstControllerNoUi::getParamValueByString(Vst::ParamID ta case kPidOversampling: { int factor; - if (!Steinberg::String::scanInt32(string, factor, false)) + if (!Steinberg::String::scanInt32(string, factor, false) || factor < 1) factor = 1; - valueNormalized = kParamOversamplingRange.normalize( - SfizzMisc::adaptOversamplingFactor(factor)); + + int log2Factor = 0; + for (int f = factor; f > 1; f /= 2) + ++log2Factor; + + valueNormalized = kParamOversamplingRange.normalize(log2Factor); return kResultTrue; } } @@ -143,10 +150,15 @@ tresult PLUGIN_API SfizzVstController::setParamNormalized(Vst::ParamID tag, Vst: break; } case kPidOversampling: { - slotI32 = &_state.oversampling; + slotI32 = &_state.oversamplingLog2; value = kParamOversamplingRange.denormalize(normValue); break; } + case kPidPreloadSize: { + slotI32 = &_state.preloadSize; + value = kParamPreloadSizeRange.denormalize(normValue); + break; + } } bool update = false; @@ -201,7 +213,8 @@ tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* state) setParamNormalized(kPidVolume, kParamVolumeRange.normalize(s.volume)); setParamNormalized(kPidNumVoices, kParamNumVoicesRange.normalize(s.numVoices)); - setParamNormalized(kPidOversampling, kParamOversamplingRange.normalize(s.oversampling)); + setParamNormalized(kPidOversampling, kParamOversamplingRange.normalize(s.oversamplingLog2)); + setParamNormalized(kPidPreloadSize, kParamPreloadSizeRange.normalize(s.preloadSize)); for (StateListener* listener : _stateListeners) listener->onStateChanged(); diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index 65da051a..422c1b01 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -86,6 +86,11 @@ void SfizzVstEditor::valueChanged(CControl* ctl) controller->performEdit(kPidOversampling, valueNorm); break; + case kTagSetPreloadSize: + controller->setParamNormalized(kPidPreloadSize, valueNorm); + controller->performEdit(kPidPreloadSize, valueNorm); + break; + default: if (tag >= kTagFirstChangePanel && tag <= kTagLastChangePanel) setActivePanel(tag - kTagFirstChangePanel); @@ -102,6 +107,7 @@ void SfizzVstEditor::enterOrLeaveEdit(CControl* ctl, bool enter) case kTagSetVolume: id = kPidVolume; break; case kTagSetNumVoices: id = kPidNumVoices; break; case kTagSetOversampling: id = kPidOversampling; break; + case kTagSetPreloadSize: id = kPidPreloadSize; break; default: return; } @@ -275,19 +281,19 @@ void SfizzVstEditor::createFrameContents() adjustMinMaxToRangeParam(slider, kPidOversampling); _oversamplingSlider = slider; - // row.top += interRow; - // row.bottom += interRow; + row.top += interRow; + row.bottom += interRow; - // label = new CTextLabel(leftSide(), "Preload size"); - // 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, kTag); - // panel->addView(slider); - // adjustMinMaxToRangeParam(slider, kPid); - // _aSlider = slider; + label = new CTextLabel(leftSide(), "Preload size"); + 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, kTagSetPreloadSize); + panel->addView(slider); + adjustMinMaxToRangeParam(slider, kPidPreloadSize); + _preloadSizeSlider = slider; // row.top += interRow; // row.bottom += interRow; @@ -354,7 +360,9 @@ void SfizzVstEditor::updateStateDisplay() if (_numVoicesSlider) _numVoicesSlider->setValue(state.numVoices); if (_oversamplingSlider) - _oversamplingSlider->setValue(state.oversampling); + _oversamplingSlider->setValue(state.oversamplingLog2); + if (_preloadSizeSlider) + _preloadSizeSlider->setValue(state.preloadSize); setActivePanel(uiState.activePanel); } diff --git a/vst/SfizzVstEditor.h b/vst/SfizzVstEditor.h index 353db127..7ed9a4dd 100644 --- a/vst/SfizzVstEditor.h +++ b/vst/SfizzVstEditor.h @@ -64,6 +64,7 @@ private: kTagSetVolume, kTagSetNumVoices, kTagSetOversampling, + kTagSetPreloadSize, kTagFirstChangePanel, kTagLastChangePanel = kTagFirstChangePanel + kNumPanels - 1, }; @@ -73,4 +74,5 @@ private: CSliderBase *_volumeSlider = nullptr; CSliderBase *_numVoicesSlider = nullptr; CSliderBase *_oversamplingSlider = nullptr; + CSliderBase *_preloadSizeSlider = nullptr; }; diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index b7111dce..3380fbb3 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -81,8 +81,8 @@ void SfizzVstProcessor::syncStateToSynth() synth->loadSfzFile(_state.sfzFile); synth->setVolume(_state.volume); synth->setNumVoices(_state.numVoices); - synth->setOversamplingFactor( - SfizzMisc::adaptOversamplingFactor(_state.oversampling)); + synth->setOversamplingFactor(1 << _state.oversamplingLog2); + synth->setPreloadSize(_state.preloadSize); } tresult PLUGIN_API SfizzVstProcessor::canProcessSampleSize(int32 symbolicSampleSize) @@ -206,6 +206,21 @@ void SfizzVstProcessor::processParameterChanges(Vst::IParameterChanges& pc) _semaToWorker.post(); } break; + case kPidPreloadSize: + if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) { + Vst::IMessage* msg = allocateMessage(); + if (!msg) + break; + msg->setMessageID("SetPreloadSize"); + Vst::IAttributeList* attr = msg->getAttributes(); + attr->setInt("PreloadSize", kParamPreloadSizeRange.denormalize(value)); + if (!_fifoToWorker.push(msg)) { + msg->release(); + break; + } + _semaToWorker.post(); + } + break; } } } @@ -339,9 +354,15 @@ void SfizzVstProcessor::doBackgroundWork() else if (!std::strcmp(id, "SetOversampling")) { int64 value; if (attr->getInt("Oversampling", value) == kResultTrue) { - _state.oversampling = value; - _synth->setOversamplingFactor( - SfizzMisc::adaptOversamplingFactor(value)); + _state.oversamplingLog2 = value; + _synth->setOversamplingFactor(1 << value); + } + } + else if (!std::strcmp(id, "SetPreloadSize")) { + int64 value; + if (attr->getInt("PreloadSize", value) == kResultTrue) { + _state.preloadSize = value; + _synth->setPreloadSize(value); } } diff --git a/vst/SfizzVstState.cpp b/vst/SfizzVstState.cpp index 0b416c3d..17240921 100644 --- a/vst/SfizzVstState.cpp +++ b/vst/SfizzVstState.cpp @@ -28,7 +28,10 @@ tresult SfizzVstState::load(IBStream* state) if (!s.readInt32(numVoices)) return kResultFalse; - if (!s.readInt32(oversampling)) + if (!s.readInt32(oversamplingLog2)) + return kResultFalse; + + if (!s.readInt32(preloadSize)) return kResultFalse; return kResultTrue; @@ -50,7 +53,10 @@ tresult SfizzVstState::store(IBStream* state) const if (!s.writeInt32(numVoices)) return kResultFalse; - if (!s.writeInt32(oversampling)) + if (!s.writeInt32(oversamplingLog2)) + return kResultFalse; + + if (!s.writeInt32(preloadSize)) return kResultFalse; return kResultTrue; @@ -82,16 +88,3 @@ tresult SfizzUiState::store(IBStream* state) const return kResultTrue; } - -/// -int SfizzMisc::adaptOversamplingFactor(int valueDenorm) -{ - if (valueDenorm >= 8) - return SFIZZ_OVERSAMPLING_X8; - else if (valueDenorm >= 4) - return SFIZZ_OVERSAMPLING_X4; - else if (valueDenorm >= 2) - return SFIZZ_OVERSAMPLING_X2; - else - return SFIZZ_OVERSAMPLING_X1; -} diff --git a/vst/SfizzVstState.h b/vst/SfizzVstState.h index 6bc6dbe5..f42817b3 100644 --- a/vst/SfizzVstState.h +++ b/vst/SfizzVstState.h @@ -21,6 +21,7 @@ enum { kPidVolume, kPidNumVoices, kPidOversampling, + kPidPreloadSize, kPidMidiCC0, kPidMidiCCLast = kPidMidiCC0 + kNumControllerParams - 1, kPidMidiAftertouch, @@ -33,7 +34,8 @@ public: std::string sfzFile; float volume = 0; int numVoices = 64; - int oversampling = 1; + int oversamplingLog2 = 0; + int preloadSize = 8192; static constexpr uint64 currentStateVersion = 0; @@ -77,9 +79,5 @@ struct SfizzParameterRange { static constexpr SfizzParameterRange kParamVolumeRange(0.0, -60.0, +6.0); static constexpr SfizzParameterRange kParamNumVoicesRange(64.0, 1.0, 256.0); -static constexpr SfizzParameterRange kParamOversamplingRange(1.0, 1.0, 8.0); - -class SfizzMisc { -public: - static int adaptOversamplingFactor(int factor); -}; +static constexpr SfizzParameterRange kParamOversamplingRange(0.0, 0.0, 3.0); +static constexpr SfizzParameterRange kParamPreloadSizeRange(8192.0, 1024.0, 65536.0); From ee530c623df19013ab044c16533c1b777bb67ada Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 13:32:41 +0100 Subject: [PATCH 10/42] Move aftertouch and pitchbend up in the parameter list --- vst/SfizzVstController.cpp | 8 ++++---- vst/SfizzVstState.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp index 984a2521..e9869e50 100644 --- a/vst/SfizzVstController.cpp +++ b/vst/SfizzVstController.cpp @@ -35,6 +35,10 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) Steinberg::String("Preload size"), pid++, nullptr, 0, Vst::ParameterInfo::kNoFlags, 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); + // MIDI controllers for (unsigned i = 0; i < kNumControllerParams; ++i) { Steinberg::String title; @@ -47,10 +51,6 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) pid++, Vst::kRootUnitId, shortTitle); } - // MIDI extra 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); - return kResultTrue; } diff --git a/vst/SfizzVstState.h b/vst/SfizzVstState.h index f42817b3..3a2c712b 100644 --- a/vst/SfizzVstState.h +++ b/vst/SfizzVstState.h @@ -22,10 +22,10 @@ enum { kPidNumVoices, kPidOversampling, kPidPreloadSize, - kPidMidiCC0, - kPidMidiCCLast = kPidMidiCC0 + kNumControllerParams - 1, kPidMidiAftertouch, kPidMidiPitchBend, + kPidMidiCC0, + kPidMidiCCLast = kPidMidiCC0 + kNumControllerParams - 1, /* Reserved */ }; From b0840ef2adfda8d6e9583d938829c8f2f423bc06 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 13:37:12 +0100 Subject: [PATCH 11/42] Add the offline mode (freewheeling) --- vst/SfizzVstProcessor.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index 3380fbb3..580f113e 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -145,6 +145,11 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data) return kResultTrue; } + if (data.processMode == Vst::kOffline) + synth.enableFreeWheeling(); + else + synth.disableFreeWheeling(); + if (Vst::IParameterChanges* pc = data.inputParameterChanges) processControllerChanges(*pc); From 598aeae2bafe4accd5757e9206dcbe12e25f2b59 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 14:37:25 +0100 Subject: [PATCH 12/42] Set the Windows compatibility version to 7 --- cmake/SfizzConfig.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index e2be25e1..19215e3a 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -12,9 +12,9 @@ set (CMAKE_POSITION_INDEPENDENT_CODE ON) set (CMAKE_CXX_VISIBILITY_PRESET hidden) set (CMAKE_VISIBILITY_INLINES_HIDDEN ON) -# Set Windows compatibility level to Vista +# Set Windows compatibility level to 7 if (WIN32) - add_compile_definitions(_WIN32_WINNT=0x600) + add_compile_definitions(_WIN32_WINNT=0x601) endif() # Add required flags for the builds From 3e93b7ffac47b8fad5707df618a97877e2ebdc41 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 14:38:54 +0100 Subject: [PATCH 13/42] Fix a renaming problem in RTSemaphore --- vst/RTSemaphore.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vst/RTSemaphore.h b/vst/RTSemaphore.h index 0cd6135b..5ec3c765 100644 --- a/vst/RTSemaphore.h +++ b/vst/RTSemaphore.h @@ -88,7 +88,7 @@ inline bool RTSemaphore::try_wait() #elif defined(_WIN32) inline RTSemaphore::RTSemaphore(unsigned value) { - sem_ = CreateRTSemaphore(nullptr, value, LONG_MAX, nullptr); + sem_ = CreateSemaphore(nullptr, value, LONG_MAX, nullptr); if (!sem_) throw std::runtime_error("RTSemaphore::RTSemaphore"); } @@ -100,7 +100,7 @@ inline RTSemaphore::~RTSemaphore() inline void RTSemaphore::post() { - if (!ReleaseRTSemaphore(sem_, 1, nullptr)) + if (!ReleaseSemaphore(sem_, 1, nullptr)) throw std::runtime_error("RTSemaphore::post"); } From 985cabeb27c977bdea1b563714672df546f6f667 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 14:46:46 +0100 Subject: [PATCH 14/42] Workaround for VST wide character in MinGW --- vst/cmake/Vst3.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vst/cmake/Vst3.cmake b/vst/cmake/Vst3.cmake index 32b9b96a..6c8f5963 100644 --- a/vst/cmake/Vst3.cmake +++ b/vst/cmake/Vst3.cmake @@ -46,6 +46,10 @@ function(plugin_add_vst3sdk NAME) endif() target_include_directories("${NAME}" PRIVATE "${VST3SDK_BASEDIR}") target_link_libraries("${NAME}" PRIVATE Threads::Threads) + if(MINGW) + target_compile_definitions("${NAME}" PRIVATE + "_NATIVE_WCHAR_T_DEFINED=1" "__wchar_t=wchar_t") + endif() endfunction() # --- VSTGUI --- From 86c4ed00aea057133545b55c41365804d4885205 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 14:59:19 +0100 Subject: [PATCH 15/42] Link system libs for Windows VSTGUI --- vst/cmake/Vst3.cmake | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/vst/cmake/Vst3.cmake b/vst/cmake/Vst3.cmake index 6c8f5963..d1e3fdc2 100644 --- a/vst/cmake/Vst3.cmake +++ b/vst/cmake/Vst3.cmake @@ -175,7 +175,19 @@ function(plugin_add_vstgui NAME) target_include_directories("${NAME}" PRIVATE "${VST3SDK_BASEDIR}/vstgui4") if(WIN32) - # + find_library(OPENGL32_LIBRARY "opengl32") + find_library(D2D1_LIBRARY "d2d1") + find_library(DWRITE_LIBRARY "dwrite") + find_library(DWMAPI_LIBRARY "dwmapi") + find_library(WINDOWSCODECS_LIBRARY "windowscodecs") + find_library(SHLWAPI_LIBRARY "shlwapi") + target_link_libraries("${NAME}" PRIVATE + "${OPENGL32_LIBRARY}" + "${D2D1_LIBRARY}" + "${DWRITE_LIBRARY}" + "${DWMAPI_LIBRARY}" + "${WINDOWSCODECS_LIBRARY}" + "${SHLWAPI_LIBRARY}") elseif(APPLE) # else() From 7eadbbd75306c526002c298f64d6d5123ae199ca Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 15:02:58 +0100 Subject: [PATCH 16/42] Add the Cocoa library to the MacOS link (add others later..) --- vst/cmake/Vst3.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vst/cmake/Vst3.cmake b/vst/cmake/Vst3.cmake index d1e3fdc2..bbac4600 100644 --- a/vst/cmake/Vst3.cmake +++ b/vst/cmake/Vst3.cmake @@ -189,6 +189,9 @@ function(plugin_add_vstgui NAME) "${WINDOWSCODECS_LIBRARY}" "${SHLWAPI_LIBRARY}") elseif(APPLE) + find_library(COCOA_LIBRARY "Cocoa") + target_link_libraries("${NAME}" PRIVATE + "${COCOA_LIBRARY}") # else() find_package(X11 REQUIRED) From c44e2e69855c7111a81d2d7a9a78e254ece6ba6f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 15:24:57 +0100 Subject: [PATCH 17/42] Add linker options for MinGW --- vst/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 0d8c505f..89c9bfc4 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -57,6 +57,10 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/vst3.version") endif() +sfizz_enable_lto_if_needed (${VSTPLUGIN_PRJ_NAME}) +if (MINGW) + set_target_properties (${VSTPLUGIN_PRJ_NAME} PROPERTIES LINK_FLAGS "-static") +endif() # Create the bundle (see "VST 3 Locations / Format") execute_process ( From 4648e656b40152b56fa1085a6752e996f6fb5df6 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 15:36:16 +0100 Subject: [PATCH 18/42] Ignore lots of VST warnings to make the log lighter --- vst/CMakeLists.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 89c9bfc4..61e8f6e4 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -90,6 +90,18 @@ else() LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-linux") endif() +if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + target_compile_options(${VSTPLUGIN_PRJ_NAME} PRIVATE + "-Wno-extra" + "-Wno-multichar" + "-Wno-reorder" + "-Wno-class-memaccess" + "-Wno-ignored-qualifiers" + "-Wno-unused-function" + "-Wno-unused-parameter" + "-Wno-unused-variable") +endif() + # To help debugging the link only if (FALSE) target_link_options(${VSTPLUGIN_PRJ_NAME} PRIVATE "-Wl,-no-undefined") From 003b2c8cf4562e706d035e074b2de7849bca3403 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 16:40:40 +0100 Subject: [PATCH 19/42] Silent extraction of SDK archive --- vst/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 61e8f6e4..27df8777 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -19,7 +19,7 @@ if (NOT EXISTS "${VST3SDK_BASEDIR}") execute_process ( COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_SOURCE_DIR}/external" - COMMAND "${CMAKE_COMMAND}" -E tar xvf "../download/${VST3SDK_ARCHIVE}" + COMMAND "${CMAKE_COMMAND}" -E tar xf "../download/${VST3SDK_ARCHIVE}" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/external") endif() From 44271b5dfec31e37991434ea8f202c934a3344f1 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 16:41:38 +0100 Subject: [PATCH 20/42] Add the correct link frameworks for Mac --- vst/cmake/Vst3.cmake | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/vst/cmake/Vst3.cmake b/vst/cmake/Vst3.cmake index bbac4600..62c430a7 100644 --- a/vst/cmake/Vst3.cmake +++ b/vst/cmake/Vst3.cmake @@ -189,10 +189,19 @@ function(plugin_add_vstgui NAME) "${WINDOWSCODECS_LIBRARY}" "${SHLWAPI_LIBRARY}") elseif(APPLE) - find_library(COCOA_LIBRARY "Cocoa") + find_library(APPLE_COREFOUNDATION_LIBRARY "CoreFoundation") + find_library(APPLE_COCOA_LIBRARY "Cocoa") + find_library(APPLE_OPENGL_LIBRARY "OpenGL") + find_library(APPLE_ACCELERATE_LIBRARY "Accelerate") + find_library(APPLE_QUARTZCORE_LIBRARY "QuartzCore") + find_library(APPLE_CARBON_LIBRARY "Carbon") target_link_libraries("${NAME}" PRIVATE - "${COCOA_LIBRARY}") - # + "${APPLE_COREFOUNDATION_LIBRARY}" + "${APPLE_COCOA_LIBRARY}" + "${APPLE_OPENGL_LIBRARY}" + "${APPLE_ACCELERATE_LIBRARY}" + "${APPLE_QUARTZCORE_LIBRARY}" + "${APPLE_CARBON_LIBRARY}") else() find_package(X11 REQUIRED) find_package(Freetype REQUIRED) From 784352a444dc4002e717707efb60353df1f5bdb6 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 16:47:48 +0100 Subject: [PATCH 21/42] Have the vst3 bundle in the project binary dir --- vst/CMakeLists.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 27df8777..b9450c3b 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -64,30 +64,30 @@ endif() # Create the bundle (see "VST 3 Locations / Format") execute_process ( - COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources") + COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources") file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/resources/logo.png" - DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources") + DESTINATION "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources") if(WIN32) set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-win") + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-win") file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/win/Plugin.ico" "${CMAKE_CURRENT_SOURCE_DIR}/win/desktop.ini" - DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}") + DESTINATION "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}") elseif(APPLE) set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES SUFFIX "" - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/MacOS") + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/MacOS") file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/mac/PkgInfo" - DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents") + DESTINATION "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents") set(SFIZZ_VST3_BUNDLE_EXECUTABLE "${PROJECT_NAME}") set(SFIZZ_VST3_BUNDLE_VERSION "${PROJECT_VERSION}") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/mac/Info.plist" - "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Info.plist" @ONLY) + "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Info.plist" @ONLY) file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/mac/Plugin.icns" - DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources") + DESTINATION "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources") else() set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES - LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-linux") + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-linux") endif() if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") From e2bf7f6f2110ce5c016804078334a479a25cd610 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 16:48:39 +0100 Subject: [PATCH 22/42] Attempt appveyor build of VST3 --- appveyor.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 99b80d33..8bc4f3f8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,6 +6,7 @@ platform: - x64 cache: - c:\tools\vcpkg\installed\ -> appveyor.yml + - vst\download install: - cmd: choco install -y innosetup @@ -20,7 +21,7 @@ before_build: - cmd: cd CMakeBuild - cmd: if %platform%==Win32 set CMAKE_GENERATOR=Visual Studio 15 2017 - cmd: if %platform%==x64 set CMAKE_GENERATOR=Visual Studio 15 2017 Win64 -- cmd: cmake .. -G"%CMAKE_GENERATOR%" -DSFIZZ_JACK=OFF -DSFIZZ_BENCHMARKS=OFF -DSFIZZ_TESTS=OFF -DSFIZZ_LV2=ON -DCMAKE_BUILD_TYPE=Release -DVCPKG_TARGET_TRIPLET=%VCPKG_TRIPLET% -DCMAKE_TOOLCHAIN_FILE=C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake +- cmd: cmake .. -G"%CMAKE_GENERATOR%" -DSFIZZ_JACK=OFF -DSFIZZ_BENCHMARKS=OFF -DSFIZZ_TESTS=OFF -DSFIZZ_LV2=ON -DSFIZZ_VST=ON -DCMAKE_BUILD_TYPE=Release -DVCPKG_TARGET_TRIPLET=%VCPKG_TRIPLET% -DCMAKE_TOOLCHAIN_FILE=C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake build_script: - cmd: cmake --build . --config Release -j @@ -31,6 +32,7 @@ after_build: - cmd: if %platform%==Win32 set RELEASE_ARCH=x86 - cmd: if %platform%==x64 set RELEASE_ARCH=x64 - cmd: 7z a sfizz-lv2-%APPVEYOR_REPO_TAG_NAME%-%RELEASE_ARCH%-msvc.zip sfizz.lv2 +- cmd: 7z a sfizz-vst3-%APPVEYOR_REPO_TAG_NAME%-%RELEASE_ARCH%-msvc.zip sfizz.vst3 - cmd: 7z a sfizz-lib-%APPVEYOR_REPO_TAG_NAME%-%RELEASE_ARCH%-msvc.zip src/Release/sfizz* - cmd: iscc.exe /dARCH=%RELEASE_ARCH% innosetup.iss From 52e7120dbd0d17d64a9c519bf5bb1f983c135508 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 17:00:08 +0100 Subject: [PATCH 23/42] Match more patterns of X86 processor --- vst/cmake/Vst3.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vst/cmake/Vst3.cmake b/vst/cmake/Vst3.cmake index 62c430a7..215ca7a0 100644 --- a/vst/cmake/Vst3.cmake +++ b/vst/cmake/Vst3.cmake @@ -257,9 +257,9 @@ if(NOT VST3_PACKAGE_ARCHITECTURE) if(APPLE) # VST3 packages are universal on Apple, architecture string not needed else() - if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64)$") set(VST3_PACKAGE_ARCHITECTURE "x86_64") - elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(i.86|x86)$") if(WIN32) set(VST3_PACKAGE_ARCHITECTURE "x86") else() From 73fde1ae22a8dcb765197f1c80cc144b764cd022 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 17:07:37 +0100 Subject: [PATCH 24/42] Link system libs MinGW-only --- vst/cmake/Vst3.cmake | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/vst/cmake/Vst3.cmake b/vst/cmake/Vst3.cmake index 215ca7a0..1a17b6f3 100644 --- a/vst/cmake/Vst3.cmake +++ b/vst/cmake/Vst3.cmake @@ -175,19 +175,22 @@ function(plugin_add_vstgui NAME) target_include_directories("${NAME}" PRIVATE "${VST3SDK_BASEDIR}/vstgui4") if(WIN32) - find_library(OPENGL32_LIBRARY "opengl32") - find_library(D2D1_LIBRARY "d2d1") - find_library(DWRITE_LIBRARY "dwrite") - find_library(DWMAPI_LIBRARY "dwmapi") - find_library(WINDOWSCODECS_LIBRARY "windowscodecs") - find_library(SHLWAPI_LIBRARY "shlwapi") - target_link_libraries("${NAME}" PRIVATE - "${OPENGL32_LIBRARY}" - "${D2D1_LIBRARY}" - "${DWRITE_LIBRARY}" - "${DWMAPI_LIBRARY}" - "${WINDOWSCODECS_LIBRARY}" - "${SHLWAPI_LIBRARY}") + if (NOT MSVC) + # autolinked on MSVC with pragmas + find_library(OPENGL32_LIBRARY "opengl32") + find_library(D2D1_LIBRARY "d2d1") + find_library(DWRITE_LIBRARY "dwrite") + find_library(DWMAPI_LIBRARY "dwmapi") + find_library(WINDOWSCODECS_LIBRARY "windowscodecs") + find_library(SHLWAPI_LIBRARY "shlwapi") + target_link_libraries("${NAME}" PRIVATE + "${OPENGL32_LIBRARY}" + "${D2D1_LIBRARY}" + "${DWRITE_LIBRARY}" + "${DWMAPI_LIBRARY}" + "${WINDOWSCODECS_LIBRARY}" + "${SHLWAPI_LIBRARY}") + endif() elseif(APPLE) find_library(APPLE_COREFOUNDATION_LIBRARY "CoreFoundation") find_library(APPLE_COCOA_LIBRARY "Cocoa") From 836df51264cdf63ee832a4d899e864d449ee87e1 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 17:36:54 +0100 Subject: [PATCH 25/42] Need NOMINMAX for Windows VST --- vst/cmake/Vst3.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/vst/cmake/Vst3.cmake b/vst/cmake/Vst3.cmake index 1a17b6f3..5272d57a 100644 --- a/vst/cmake/Vst3.cmake +++ b/vst/cmake/Vst3.cmake @@ -175,6 +175,7 @@ function(plugin_add_vstgui NAME) target_include_directories("${NAME}" PRIVATE "${VST3SDK_BASEDIR}/vstgui4") if(WIN32) + target_compile_definitions("${NAME}" PRIVATE "NOMINMAX=1") if (NOT MSVC) # autolinked on MSVC with pragmas find_library(OPENGL32_LIBRARY "opengl32") From 95d6c581f74e61dc2b8a57652c06ff72af4032fb Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 17:50:32 +0100 Subject: [PATCH 26/42] Silence VST warning: unknown pragmas --- vst/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index b9450c3b..c8b203cc 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -97,6 +97,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") "-Wno-reorder" "-Wno-class-memaccess" "-Wno-ignored-qualifiers" + "-Wno-unknown-pragmas" "-Wno-unused-function" "-Wno-unused-parameter" "-Wno-unused-variable") From 14d76e6282b4426f3d101ace025ff4ade81d3f03 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 17:51:06 +0100 Subject: [PATCH 27/42] Use Steinberg's fixed size types, to fix MSVC build --- vst/SfizzVstController.cpp | 6 +++--- vst/SfizzVstState.h | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp index e9869e50..77b71279 100644 --- a/vst/SfizzVstController.cpp +++ b/vst/SfizzVstController.cpp @@ -100,12 +100,12 @@ tresult PLUGIN_API SfizzVstControllerNoUi::getParamValueByString(Vst::ParamID ta switch (tag) { case kPidOversampling: { - int factor; + int32 factor; if (!Steinberg::String::scanInt32(string, factor, false) || factor < 1) factor = 1; - int log2Factor = 0; - for (int f = factor; f > 1; f /= 2) + int32 log2Factor = 0; + for (int32 f = factor; f > 1; f /= 2) ++log2Factor; valueNormalized = kParamOversamplingRange.normalize(log2Factor); diff --git a/vst/SfizzVstState.h b/vst/SfizzVstState.h index 3a2c712b..5f3a0fb0 100644 --- a/vst/SfizzVstState.h +++ b/vst/SfizzVstState.h @@ -33,9 +33,9 @@ class SfizzVstState { public: std::string sfzFile; float volume = 0; - int numVoices = 64; - int oversamplingLog2 = 0; - int preloadSize = 8192; + int32 numVoices = 64; + int32 oversamplingLog2 = 0; + int32 preloadSize = 8192; static constexpr uint64 currentStateVersion = 0; @@ -45,7 +45,7 @@ public: class SfizzUiState { public: - unsigned activePanel = 0; + uint32 activePanel = 0; static constexpr uint64 currentStateVersion = 0; From 7ab7f9864e763272dc4c0bd8635f089dabc7919e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 18:16:45 +0100 Subject: [PATCH 28/42] Try fixing the library output path on MS (no Release/ subfolder) --- vst/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index c8b203cc..cf83113c 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -70,6 +70,11 @@ file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/resources/logo.png" if(WIN32) set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-win") + foreach(config ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER "${config}" config) + set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES + "LIBRARY_OUTPUT_DIRECTORY_${config}" "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-win") + endforeach() file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/win/Plugin.ico" "${CMAKE_CURRENT_SOURCE_DIR}/win/desktop.ini" DESTINATION "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}") From 9dcefe740cf40f37dd7c62ba02f255d53c6cfc21 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 18:58:11 +0100 Subject: [PATCH 29/42] Add the GPL 3.0 license for VST [ci skip] --- vst/gpl-3.0.txt | 674 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 vst/gpl-3.0.txt diff --git a/vst/gpl-3.0.txt b/vst/gpl-3.0.txt new file mode 100644 index 00000000..f288702d --- /dev/null +++ b/vst/gpl-3.0.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. From 5b91f71c68d292b834f8e208bf27fa18f5d9e0bd Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 19:00:09 +0100 Subject: [PATCH 30/42] Copy gpl-3.0.txt in the VST bundle [ci skip] --- vst/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index cf83113c..94d924b4 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -95,6 +95,9 @@ else() LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-linux") endif() +file(COPY "gpl-3.0.txt" + DESTINATION "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}") + if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") target_compile_options(${VSTPLUGIN_PRJ_NAME} PRIVATE "-Wno-extra" From 99317e764d92ae3bb002e8995e160cd5edc6ba1e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 19:55:36 +0100 Subject: [PATCH 31/42] Update the installer script for VST --- cmake/VSTConfig.cmake | 19 +++++++++++++++++++ scripts/innosetup.iss.in | 29 ++++++++++++++++++++--------- src/CMakeLists.txt | 4 +++- vst/cmake/Vst3.cmake | 19 ------------------- 4 files changed, 42 insertions(+), 29 deletions(-) diff --git a/cmake/VSTConfig.cmake b/cmake/VSTConfig.cmake index 0d1de3e1..e595db5c 100644 --- a/cmake/VSTConfig.cmake +++ b/cmake/VSTConfig.cmake @@ -2,3 +2,22 @@ set (VSTPLUGIN_NAME "sfizz") set (VSTPLUGIN_VENDOR "Paul Ferrand") set (VSTPLUGIN_URL "http://sfztools.github.io/sfizz") set (VSTPLUGIN_EMAIL "paul@ferrand.cc") + +# --- VST3 Bundle architecture --- +if(NOT VST3_PACKAGE_ARCHITECTURE) + if(APPLE) + # VST3 packages are universal on Apple, architecture string not needed + else() + if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64)$") + set(VST3_PACKAGE_ARCHITECTURE "x86_64") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(i.86|x86)$") + if(WIN32) + set(VST3_PACKAGE_ARCHITECTURE "x86") + else() + set(VST3_PACKAGE_ARCHITECTURE "i386") + endif() + else() + message(FATAL_ERROR "We don't know this architecture for VST3: ${CMAKE_SYSTEM_PROCESSOR}.") + endif() + endif() +endif() diff --git a/scripts/innosetup.iss.in b/scripts/innosetup.iss.in index 92de0abf..00d5642c 100644 --- a/scripts/innosetup.iss.in +++ b/scripts/innosetup.iss.in @@ -1,4 +1,5 @@ -#define MyAppName "sfizz-lv2" +; -*- mode: iss; -*- +#define MyAppName "sfizz" #define MyAppVersion "@PROJECT_VERSION@" #define MyAppPublisher "sfizz Team" #define MyAppURL "https://sfztools.github.io/sfizz/" @@ -28,25 +29,35 @@ ArchitecturesInstallIn64BitMode={#Arch} Compression=lzma SolidCompression=yes -DefaultDirName={commoncf}\LV2 +DefaultDirName={commonpf}\{#MyAppName} DefaultGroupName={#MyAppPublisher} -DisableDirPage=yes +;DisableDirPage=yes LicenseFile="sfizz.lv2\LICENSE.md" OutputBaseFileName={#MyAppName}-{#MyAppVersion}-{#Arch}-msvc-setup OutputDir=. -UninstallFilesDir={commonpf}\{#MyAppName} +UninstallFilesDir={app} WizardImageFile="C:\Program Files (x86)\Inno Setup 6\WizModernImage-IS.bmp" WizardSmallImageFile="C:\Program Files (x86)\Inno Setup 6\WizModernSmallImage-IS.bmp" [Languages] Name: "english"; MessagesFile: "compiler:Default.isl" +[Components] +Name: "main"; Description: "Shared files"; Types: full custom; Flags: fixed +Name: "lv2"; Description: "LV2 plugin"; Types: full custom; +Name: "vst3"; Description: "VST3 plugin"; Types: full custom; + [Files] -Source: "sfizz.lv2\sfizz.dll"; DestDir: {commoncf}\LV2\sfizz.lv2; Flags: ignoreversion -Source: "sfizz.lv2\manifest.ttl"; DestDir: {commoncf}\LV2\sfizz.lv2 -Source: "sfizz.lv2\sfizz.ttl"; DestDir: {commoncf}\LV2\sfizz.lv2 -Source: "sfizz.lv2\lgpl-3.0.txt"; DestDir: {commonpf}\{#MyAppName} -Source: "sfizz.lv2\LICENSE.md"; DestDir: {commonpf}\{#MyAppName} +Source: "sfizz.lv2\sfizz.dll"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2"; Flags: ignoreversion +Source: "sfizz.lv2\manifest.ttl"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2" +Source: "sfizz.lv2\sfizz.ttl"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2" +Source: "sfizz.lv2\lgpl-3.0.txt"; Components: main; DestDir: "{app}" +Source: "sfizz.lv2\LICENSE.md"; Components: main; DestDir: "{app}" +Source: "sfizz.vst3\desktop.ini"; Components: vst3; DestDir: "{commoncf}\VST3\sfizz.vst3" +Source: "sfizz.vst3\Contents\@VST3_PACKAGE_ARCHITECTURE@-win\sfizz.dll"; Components: vst3; DestDir: "{commoncf}\VST3\sfizz.vst3\Contents\@VST3_PACKAGE_ARCHITECTURE@-win"; Flags: ignoreversion +Source: "sfizz.vst3\Contents\Resources\logo.png"; Components: vst3; DestDir: "{commoncf}\VST3\sfizz.vst3\Contents\Resources" +Source: "sfizz.vst3\Plugin.ico"; Components: vst3; DestDir: "{commoncf}\VST3\sfizz.vst3" +Source: "sfizz.vst3\gpl-3.0.txt"; Components: main; DestDir: "{app}" ;Source: "setup\vc_redist.x64.exe"; DestDir: {tmp}; Flags: deleteafterinstall ; NOTE: Don't use "Flags: ignoreversion" on any shared system files diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3580130c..fcaeca79 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,7 +47,9 @@ if (NOT MSVC) PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) configure_file (${PROJECT_SOURCE_DIR}/scripts/sfizz.pc.in sfizz.pc @ONLY) -else() +endif() +if(WIN32) + include(VSTConfig) configure_file (${PROJECT_SOURCE_DIR}/scripts/innosetup.iss.in ${PROJECT_BINARY_DIR}/innosetup.iss @ONLY) endif() diff --git a/vst/cmake/Vst3.cmake b/vst/cmake/Vst3.cmake index 5272d57a..fb89987c 100644 --- a/vst/cmake/Vst3.cmake +++ b/vst/cmake/Vst3.cmake @@ -255,22 +255,3 @@ function(plugin_add_vstgui NAME) target_include_directories("${NAME}" PRIVATE external/steinberg/src) endfunction() - -# --- VST3 Bundle architecture --- -if(NOT VST3_PACKAGE_ARCHITECTURE) - if(APPLE) - # VST3 packages are universal on Apple, architecture string not needed - else() - if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64)$") - set(VST3_PACKAGE_ARCHITECTURE "x86_64") - elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(i.86|x86)$") - if(WIN32) - set(VST3_PACKAGE_ARCHITECTURE "x86") - else() - set(VST3_PACKAGE_ARCHITECTURE "i386") - endif() - else() - message(FATAL_ERROR "We don't know this architecture for VST3: ${CMAKE_SYSTEM_PROCESSOR}.") - endif() - endif() -endif() From a82d866866b44a26e78900b7449fcad7af484220 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 20:09:34 +0100 Subject: [PATCH 32/42] Print the VST architecture at CMake time --- cmake/VSTConfig.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/VSTConfig.cmake b/cmake/VSTConfig.cmake index e595db5c..26d642d7 100644 --- a/cmake/VSTConfig.cmake +++ b/cmake/VSTConfig.cmake @@ -21,3 +21,6 @@ if(NOT VST3_PACKAGE_ARCHITECTURE) endif() endif() endif() + +message(STATUS "The system architecture is: ${CMAKE_SYSTEM_PROCESSOR}") +message(STATUS "The VST3 architecture is deduced as: ${VST3_PACKAGE_ARCHITECTURE}") From 8fdfc98cc9dce162d454954b427a246d8171da73 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 20:18:35 +0100 Subject: [PATCH 33/42] Try specifying the platform as indicated in cmake-generators(7) --- appveyor.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 8bc4f3f8..294068bb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,9 +19,7 @@ before_build: - cmd: git submodule update --init - cmd: mkdir CMakeBuild - cmd: cd CMakeBuild -- cmd: if %platform%==Win32 set CMAKE_GENERATOR=Visual Studio 15 2017 -- cmd: if %platform%==x64 set CMAKE_GENERATOR=Visual Studio 15 2017 Win64 -- cmd: cmake .. -G"%CMAKE_GENERATOR%" -DSFIZZ_JACK=OFF -DSFIZZ_BENCHMARKS=OFF -DSFIZZ_TESTS=OFF -DSFIZZ_LV2=ON -DSFIZZ_VST=ON -DCMAKE_BUILD_TYPE=Release -DVCPKG_TARGET_TRIPLET=%VCPKG_TRIPLET% -DCMAKE_TOOLCHAIN_FILE=C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake +- cmd: cmake .. -G"Visual Studio 15 2017" -A"%platform%" -DSFIZZ_JACK=OFF -DSFIZZ_BENCHMARKS=OFF -DSFIZZ_TESTS=OFF -DSFIZZ_LV2=ON -DSFIZZ_VST=ON -DCMAKE_BUILD_TYPE=Release -DVCPKG_TARGET_TRIPLET=%VCPKG_TRIPLET% -DCMAKE_TOOLCHAIN_FILE=C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake build_script: - cmd: cmake --build . --config Release -j From 0bb1a34f552edbec104955a3996a00da98cc1f8e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 20:27:06 +0100 Subject: [PATCH 34/42] Try fixing processor detection with MSVC --- cmake/VSTConfig.cmake | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/cmake/VSTConfig.cmake b/cmake/VSTConfig.cmake index 26d642d7..04ded138 100644 --- a/cmake/VSTConfig.cmake +++ b/cmake/VSTConfig.cmake @@ -3,24 +3,34 @@ set (VSTPLUGIN_VENDOR "Paul Ferrand") set (VSTPLUGIN_URL "http://sfztools.github.io/sfizz") set (VSTPLUGIN_EMAIL "paul@ferrand.cc") +# The variable CMAKE_SYSTEM_PROCESSOR is incorrect on Visual studio... +# see https://gitlab.kitware.com/cmake/cmake/issues/15170 + +if(MSVC) + set(VST3_SYSTEM_PROCESSOR "${MSVC_CXX_ARCHITECTURE_ID}") +else() + set(VST3_SYSTEM_PROCESSOR "${CMAKE_SYSTEM_PROCESSOR}") +endif() + +message(STATUS "The system architecture is: ${VST3_SYSTEM_PROCESSOR}") + # --- VST3 Bundle architecture --- if(NOT VST3_PACKAGE_ARCHITECTURE) if(APPLE) # VST3 packages are universal on Apple, architecture string not needed else() - if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64)$") + if(VST3_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64)$") set(VST3_PACKAGE_ARCHITECTURE "x86_64") - elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(i.86|x86)$") + elseif(VST3_SYSTEM_PROCESSOR MATCHES "^(i.86|x86)$") if(WIN32) set(VST3_PACKAGE_ARCHITECTURE "x86") else() set(VST3_PACKAGE_ARCHITECTURE "i386") endif() else() - message(FATAL_ERROR "We don't know this architecture for VST3: ${CMAKE_SYSTEM_PROCESSOR}.") + message(FATAL_ERROR "We don't know this architecture for VST3: ${VST3_SYSTEM_PROCESSOR}.") endif() endif() endif() -message(STATUS "The system architecture is: ${CMAKE_SYSTEM_PROCESSOR}") message(STATUS "The VST3 architecture is deduced as: ${VST3_PACKAGE_ARCHITECTURE}") From 094dde6dd6508c3ca875fc839516add7fdbe7476 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 20:33:40 +0100 Subject: [PATCH 35/42] Add another pattern to detect the CPU for VST --- cmake/VSTConfig.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/VSTConfig.cmake b/cmake/VSTConfig.cmake index 04ded138..dece48ab 100644 --- a/cmake/VSTConfig.cmake +++ b/cmake/VSTConfig.cmake @@ -21,7 +21,7 @@ if(NOT VST3_PACKAGE_ARCHITECTURE) else() if(VST3_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64)$") set(VST3_PACKAGE_ARCHITECTURE "x86_64") - elseif(VST3_SYSTEM_PROCESSOR MATCHES "^(i.86|x86)$") + elseif(VST3_SYSTEM_PROCESSOR MATCHES "^(i.86|x86|X86)$") if(WIN32) set(VST3_PACKAGE_ARCHITECTURE "x86") else() From d9f9d42922f344da2cb6d78111e1c453cac4df45 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 20:47:35 +0100 Subject: [PATCH 36/42] Add more VST matching patterns for CPU.. --- cmake/VSTConfig.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/VSTConfig.cmake b/cmake/VSTConfig.cmake index dece48ab..aa3d52f6 100644 --- a/cmake/VSTConfig.cmake +++ b/cmake/VSTConfig.cmake @@ -19,7 +19,7 @@ if(NOT VST3_PACKAGE_ARCHITECTURE) if(APPLE) # VST3 packages are universal on Apple, architecture string not needed else() - if(VST3_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64)$") + if(VST3_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64|x64|X64)$") set(VST3_PACKAGE_ARCHITECTURE "x86_64") elseif(VST3_SYSTEM_PROCESSOR MATCHES "^(i.86|x86|X86)$") if(WIN32) From ac838e388b2e678dbb7dda27b746d12cae541ed3 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 21:35:57 +0100 Subject: [PATCH 37/42] VST suffix on Windows should be .vst3 --- scripts/innosetup.iss.in | 2 +- vst/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/innosetup.iss.in b/scripts/innosetup.iss.in index 00d5642c..d97d3f2b 100644 --- a/scripts/innosetup.iss.in +++ b/scripts/innosetup.iss.in @@ -54,7 +54,7 @@ Source: "sfizz.lv2\sfizz.ttl"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.l Source: "sfizz.lv2\lgpl-3.0.txt"; Components: main; DestDir: "{app}" Source: "sfizz.lv2\LICENSE.md"; Components: main; DestDir: "{app}" Source: "sfizz.vst3\desktop.ini"; Components: vst3; DestDir: "{commoncf}\VST3\sfizz.vst3" -Source: "sfizz.vst3\Contents\@VST3_PACKAGE_ARCHITECTURE@-win\sfizz.dll"; Components: vst3; DestDir: "{commoncf}\VST3\sfizz.vst3\Contents\@VST3_PACKAGE_ARCHITECTURE@-win"; Flags: ignoreversion +Source: "sfizz.vst3\Contents\@VST3_PACKAGE_ARCHITECTURE@-win\sfizz.vst3"; Components: vst3; DestDir: "{commoncf}\VST3\sfizz.vst3\Contents\@VST3_PACKAGE_ARCHITECTURE@-win"; Flags: ignoreversion Source: "sfizz.vst3\Contents\Resources\logo.png"; Components: vst3; DestDir: "{commoncf}\VST3\sfizz.vst3\Contents\Resources" Source: "sfizz.vst3\Plugin.ico"; Components: vst3; DestDir: "{commoncf}\VST3\sfizz.vst3" Source: "sfizz.vst3\gpl-3.0.txt"; Components: main; DestDir: "{app}" diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 94d924b4..fd98fd12 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -69,6 +69,7 @@ file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/resources/logo.png" DESTINATION "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources") if(WIN32) set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES + SUFFIX ".vst3" LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-win") foreach(config ${CMAKE_CONFIGURATION_TYPES}) string(TOUPPER "${config}" config) From dd8b5d93a5b1e9750e887aa64a713bd835962b47 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 21:48:40 +0100 Subject: [PATCH 38/42] Add the exports file for Windows VST --- vst/CMakeLists.txt | 3 +++ vst/vst3.def | 4 ++++ 2 files changed, 7 insertions(+) create mode 100644 vst/vst3.def diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index fd98fd12..a4e214b3 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -42,6 +42,9 @@ add_library(${VSTPLUGIN_PRJ_NAME} MODULE SfizzVstState.cpp GUIComponents.cpp VstPluginFactory.cpp) +if(WIN32) + target_sources(${VSTPLUGIN_PRJ_NAME} PRIVATE vst3.def) +endif() target_link_libraries(${VSTPLUGIN_PRJ_NAME} PRIVATE ${PROJECT_NAME}::${PROJECT_NAME}) target_include_directories(${VSTPLUGIN_PRJ_NAME} diff --git a/vst/vst3.def b/vst/vst3.def new file mode 100644 index 00000000..279a6a5c --- /dev/null +++ b/vst/vst3.def @@ -0,0 +1,4 @@ +EXPORTS + GetPluginFactory + InitDll + ExitDll From 126dd49e2840daaa470dee7983cd5dcb05025635 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 6 Mar 2020 23:06:18 +0100 Subject: [PATCH 39/42] Fix finding the resource images on Windows OS --- vst/SfizzVstController.cpp | 2 ++ vst/SfizzVstEditor.cpp | 8 +++++++- vst/cmake/Vst3.cmake | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp index 77b71279..cc13b355 100644 --- a/vst/SfizzVstController.cpp +++ b/vst/SfizzVstController.cpp @@ -122,6 +122,8 @@ IPlugView* PLUGIN_API SfizzVstController::createView(FIDString _name) { ConstString name(_name); + fprintf(stderr, "[sfizz] about to create view: %s\n", _name); + if (name != Vst::ViewType::kEditor) return nullptr; diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index 422c1b01..826a8930 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -27,6 +27,8 @@ SfizzVstEditor::~SfizzVstEditor() bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& platformType) { + fprintf(stderr, "[sfizz] about to open view with parent %p\n", parent); + CRect wsize(0, 0, _logo.getWidth(), _logo.getHeight()); CFrame *frame = new CFrame(wsize, this); this->frame = frame; @@ -42,7 +44,11 @@ bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& p createFrameContents(); updateStateDisplay(); - frame->open(parent, platformType, config); + if (!frame->open(parent, platformType, config)) { + fprintf(stderr, "[sfizz] error opening frame\n"); + return false; + } + return true; } diff --git a/vst/cmake/Vst3.cmake b/vst/cmake/Vst3.cmake index fb89987c..a8aa9074 100644 --- a/vst/cmake/Vst3.cmake +++ b/vst/cmake/Vst3.cmake @@ -254,4 +254,6 @@ function(plugin_add_vstgui NAME) target_include_directories("${NAME}" PRIVATE external/steinberg/src) + + target_compile_definitions("${NAME}" PRIVATE "SMTG_MODULE_IS_BUNDLE=1") endfunction() From 41810f9994332c5cae76a19660e5e6567bc959bc Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 7 Mar 2020 13:42:11 +0100 Subject: [PATCH 40/42] Remove the unnecessary try-lock, processing the parameters --- vst/SfizzVstProcessor.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index 580f113e..55877da3 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -119,10 +119,8 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data) { sfz::Sfizz& synth = *_synth; - if (Vst::IParameterChanges* pc = data.inputParameterChanges) { - std::unique_lock lock(_processMutex, std::try_to_lock); + if (Vst::IParameterChanges* pc = data.inputParameterChanges) processParameterChanges(*pc); - } if (data.numOutputs < 1) // flush mode return kResultTrue; From f88364b6b2bdb94d35a54bff1ae643b9621abf84 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Sat, 7 Mar 2020 22:36:47 +0100 Subject: [PATCH 41/42] The library protects itself on this call --- vst/SfizzVstProcessor.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index 55877da3..ff2839fb 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -342,7 +342,6 @@ void SfizzVstProcessor::doBackgroundWork() if (!std::strcmp(id, "LoadSfz")) { std::vector path(maxPathLen + 1); if (attr->getString("File", path.data(), maxPathLen) == kResultTrue) { - std::lock_guard lock(_processMutex); _state.sfzFile = Steinberg::String(path.data()).text8(); _synth->loadSfzFile(_state.sfzFile); } From 65d952a1e61c76151ce44a98d1efb0005a3ee165 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Sat, 7 Mar 2020 23:05:11 +0100 Subject: [PATCH 42/42] Add the development and release flags for VST3 --- vst/CMakeLists.txt | 1 + vst/cmake/Vst3.cmake | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index a4e214b3..83c51154 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -42,6 +42,7 @@ add_library(${VSTPLUGIN_PRJ_NAME} MODULE SfizzVstState.cpp GUIComponents.cpp VstPluginFactory.cpp) + if(WIN32) target_sources(${VSTPLUGIN_PRJ_NAME} PRIVATE vst3.def) endif() diff --git a/vst/cmake/Vst3.cmake b/vst/cmake/Vst3.cmake index a8aa9074..544a34e6 100644 --- a/vst/cmake/Vst3.cmake +++ b/vst/cmake/Vst3.cmake @@ -50,6 +50,14 @@ function(plugin_add_vst3sdk NAME) target_compile_definitions("${NAME}" PRIVATE "_NATIVE_WCHAR_T_DEFINED=1" "__wchar_t=wchar_t") endif() + + if(${CMAKE_BUILD_TYPE} MATCHES "Debug") + target_compile_definitions("${NAME}" PRIVATE "DEVELOPMENT") + endif() + + if(${CMAKE_BUILD_TYPE} MATCHES "Release") + target_compile_definitions("${NAME}" PRIVATE "RELEASE") + endif() endfunction() # --- VSTGUI --- @@ -256,4 +264,12 @@ function(plugin_add_vstgui NAME) external/steinberg/src) target_compile_definitions("${NAME}" PRIVATE "SMTG_MODULE_IS_BUNDLE=1") + + if(${CMAKE_BUILD_TYPE} MATCHES "Debug") + target_compile_definitions("${NAME}" PRIVATE "DEVELOPMENT") + endif() + + if(${CMAKE_BUILD_TYPE} MATCHES "Release") + target_compile_definitions("${NAME}" PRIVATE "RELEASE") + endif() endfunction()