Initial VST plugin
This commit is contained in:
parent
53a4cf0ead
commit
2dc41f4503
19 changed files with 1518 additions and 0 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -32,3 +32,6 @@ node_modules/
|
||||||
*.lock
|
*.lock
|
||||||
*.sublime-*
|
*.sublime-*
|
||||||
*.code-*
|
*.code-*
|
||||||
|
|
||||||
|
/vst/download
|
||||||
|
/vst/external/VST_SDK
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ endif()
|
||||||
option (ENABLE_LTO "Enable Link Time Optimization [default: ON]" ON)
|
option (ENABLE_LTO "Enable Link Time Optimization [default: ON]" ON)
|
||||||
option (SFIZZ_JACK "Enable JACK stand-alone build [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_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_BENCHMARKS "Enable benchmarks build [default: OFF]" OFF)
|
||||||
option (SFIZZ_TESTS "Enable tests build [default: OFF]" OFF)
|
option (SFIZZ_TESTS "Enable tests build [default: OFF]" OFF)
|
||||||
option (SFIZZ_SHARED "Enable shared library build [default: ON]" ON)
|
option (SFIZZ_SHARED "Enable shared library build [default: ON]" ON)
|
||||||
|
|
@ -51,6 +52,10 @@ if (SFIZZ_LV2)
|
||||||
add_subdirectory (lv2)
|
add_subdirectory (lv2)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (SFIZZ_VST)
|
||||||
|
add_subdirectory (vst)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (SFIZZ_BENCHMARKS)
|
if (SFIZZ_BENCHMARKS)
|
||||||
add_subdirectory (benchmarks)
|
add_subdirectory (benchmarks)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
4
cmake/VSTConfig.cmake
Normal file
4
cmake/VSTConfig.cmake
Normal 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
77
vst/CMakeLists.txt
Normal 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
167
vst/RTSemaphore.h
Normal 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
121
vst/SfizzVstController.cpp
Normal 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
69
vst/SfizzVstController.h
Normal 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
180
vst/SfizzVstEditor.cpp
Normal 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
40
vst/SfizzVstEditor.h
Normal 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
284
vst/SfizzVstProcessor.cpp
Normal 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
57
vst/SfizzVstProcessor.h
Normal 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
42
vst/SfizzVstState.cpp
Normal 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
21
vst/SfizzVstState.h
Normal 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
11
vst/VstPluginDefs.h.in
Normal 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
49
vst/VstPluginFactory.cpp
Normal 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
244
vst/cmake/Vst3.cmake
Normal 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
27
vst/external/steinberg/LICENSE
vendored
Normal 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
110
vst/external/steinberg/src/x11runloop.h
vendored
Normal 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
7
vst/vst3.version
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
VST3ABI_1.0 {
|
||||||
|
global:
|
||||||
|
*GetPluginFactory*;
|
||||||
|
*ModuleEntry*;
|
||||||
|
*ModuleExit*;
|
||||||
|
local: *;
|
||||||
|
};
|
||||||
Loading…
Add table
Reference in a new issue