Initial VST plugin

This commit is contained in:
Jean Pierre Cimalando 2020-03-05 11:16:47 +01:00 committed by Paul Fd
parent 53a4cf0ead
commit 2dc41f4503
19 changed files with 1518 additions and 0 deletions

3
.gitignore vendored
View file

@ -32,3 +32,6 @@ node_modules/
*.lock
*.sublime-*
*.code-*
/vst/download
/vst/external/VST_SDK

View file

@ -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()

4
cmake/VSTConfig.cmake Normal file
View file

@ -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")

77
vst/CMakeLists.txt Normal file
View file

@ -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()

167
vst/RTSemaphore.h Normal file
View file

@ -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 <mach/mach.h>
#elif defined(_WIN32)
#include <limits.h>
#include <windows.h>
#else
#include <semaphore.h>
#include <errno.h>
#endif
#include <stdexcept>
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

121
vst/SfizzVstController.cpp Normal file
View file

@ -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<Vst::IEditController*>(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);

69
vst/SfizzVstController.h Normal file
View file

@ -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<StateListener*> _stateListeners;
};

180
vst/SfizzVstEditor.cpp Normal file
View file

@ -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<SfizzVstController*>(getController())->addStateListener(this);
}
SfizzVstEditor::~SfizzVstEditor()
{
static_cast<SfizzVstController*>(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<CNewFileSelector> 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<SfizzVstController*>(getController())->getSfizzState();
_fileLabel->setText(state.sfzFile.c_str());
}

40
vst/SfizzVstEditor.h Normal file
View file

@ -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;
};

284
vst/SfizzVstProcessor.cpp Normal file
View file

@ -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 <cstring>
#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<std::mutex> 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<std::mutex> 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<Vst::IAudioProcessor*>(new SfizzVstProcessor);
}
void SfizzVstProcessor::loadSfzFile(std::string file)
{
std::lock_guard<std::mutex> 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<Vst::TChar> 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);

57
vst/SfizzVstProcessor.h Normal file
View file

@ -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 <sfizz.hpp>
#include <thread>
#include <mutex>
#include <memory>
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<sfz::Sfizz> _synth;
std::thread _worker;
volatile bool _workRunning = false;
Steinberg::OneReaderOneWriter::RingBuffer<Vst::IMessage*> _fifoToWorker;
RTSemaphore _semaToWorker;
std::mutex _processMutex;
// state
std::string _sfzFile;
//
void loadSfzFile(std::string file);
// worker
void doBackgroundWork();
void stopBackgroundWork();
};

42
vst/SfizzVstState.cpp Normal file
View file

@ -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 <mutex>
#include <cstring>
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;
}

21
vst/SfizzVstState.h Normal file
View file

@ -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 <string>
using namespace Steinberg;
class SfizzVstState {
public:
std::string sfzFile;
static constexpr uint64 currentStateVersion = 0;
tresult load(IBStream* state);
tresult store(IBStream* state) const;
};

11
vst/VstPluginDefs.h.in Normal file
View file

@ -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@"

49
vst/VstPluginFactory.cpp Normal file
View file

@ -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;
}

244
vst/cmake/Vst3.cmake Normal file
View file

@ -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()

27
vst/external/steinberg/LICENSE vendored Normal file
View file

@ -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.
//-----------------------------------------------------------------------------

110
vst/external/steinberg/src/x11runloop.h vendored Normal file
View file

@ -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<Steinberg::IPtr<EventHandler>>;
using TimerHandlers = std::vector<Steinberg::IPtr<TimerHandler>>;
EventHandlers eventHandlers;
TimerHandlers timerHandlers;
Steinberg::FUnknownPtr<Steinberg::Linux::IRunLoop> runLoop;
};
} // namespace

7
vst/vst3.version Normal file
View file

@ -0,0 +1,7 @@
VST3ABI_1.0 {
global:
*GetPluginFactory*;
*ModuleEntry*;
*ModuleExit*;
local: *;
};