Merge pull request #636 from jpcima/vst-bits

Misc VST and plugin things
This commit is contained in:
JP Cimalando 2021-02-08 21:05:46 +01:00 committed by GitHub
commit 02c5de1237
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 162 additions and 99 deletions

4
.gitignore vendored
View file

@ -19,9 +19,9 @@ compile_commands.json
clients/sfizz_jack clients/sfizz_jack
clients/sfzprint clients/sfzprint
/vst/download/ /plugins/vst/download/
/editor/external/fluentui-system-icons/ /plugins/editor/external/fluentui-system-icons/
*.sublime-* *.sublime-*
*.code-* *.code-*

View file

@ -54,22 +54,7 @@ add_subdirectory (src)
# Optional targets # Optional targets
add_subdirectory (clients) add_subdirectory (clients)
add_subdirectory (plugins)
if ((SFIZZ_LV2 AND SFIZZ_LV2_UI) OR SFIZZ_VST)
add_subdirectory (plugins/editor)
endif()
if (SFIZZ_LV2)
add_subdirectory (plugins/lv2)
endif()
if (SFIZZ_VST)
add_subdirectory (plugins/vst)
else()
if (SFIZZ_AU)
message(WARNING "Audio Unit requires VST to be enabled")
endif()
endif()
if (SFIZZ_BENCHMARKS) if (SFIZZ_BENCHMARKS)
add_subdirectory (benchmarks) add_subdirectory (benchmarks)

24
plugins/CMakeLists.txt Normal file
View file

@ -0,0 +1,24 @@
add_library(plugins-common STATIC EXCLUDE_FROM_ALL
"common/plugin/MessageUtils.h"
"common/plugin/MessageUtils.cpp")
target_include_directories(plugins-common PUBLIC "common")
target_link_libraries(plugins-common
PUBLIC sfizz::spin_mutex
PUBLIC absl::strings)
add_library(sfizz::plugins-common ALIAS plugins-common)
if((SFIZZ_LV2 AND SFIZZ_LV2_UI) OR SFIZZ_VST)
add_subdirectory(editor)
endif()
if(SFIZZ_LV2)
add_subdirectory(lv2)
endif()
if(SFIZZ_VST)
add_subdirectory(vst)
else()
if(SFIZZ_AU)
message(WARNING "Audio Unit requires VST to be enabled")
endif()
endif()

View file

@ -0,0 +1,39 @@
// 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 "MessageUtils.h"
#include <absl/strings/ascii.h>
#include <absl/strings/numbers.h>
#include <cstring>
namespace Messages {
bool matchOSC(const char* pattern, const char* path, unsigned* indices)
{
unsigned nthIndex = 0;
while (const char *endp = std::strchr(pattern, '&')) {
size_t length = endp - pattern;
if (std::strncmp(pattern, path, length))
return false;
pattern += length;
path += length;
length = 0;
while (absl::ascii_isdigit(path[length]))
++length;
if (!absl::SimpleAtoi(absl::string_view(path, length), &indices[nthIndex++]))
return false;
pattern += 1;
path += length;
}
return !std::strcmp(path, pattern);
}
} // namespace Messages

View file

@ -0,0 +1,19 @@
// 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
namespace Messages {
/**
* Simple matcher for message handling in O(N)
* @param[in] pattern Pattern to match, where '&' characters match positive integer numbers
* @param[in] path Path to match against the pattern
* @param[out] indices Table which received the indices, with size >= the number of '&' in the pattern
*/
bool matchOSC(const char* pattern, const char* path, unsigned* indices);
} // namespace Messages

View file

@ -43,9 +43,8 @@ add_library(sfizz_editor STATIC EXCLUDE_FROM_ALL
src/editor/utility/vstgui_before.h) src/editor/utility/vstgui_before.h)
add_library(sfizz::editor ALIAS sfizz_editor) add_library(sfizz::editor ALIAS sfizz_editor)
target_include_directories(sfizz_editor PUBLIC "src") target_include_directories(sfizz_editor PUBLIC "src")
target_link_libraries(sfizz_editor PUBLIC sfizz::messaging) target_link_libraries(sfizz_editor PUBLIC sfizz::messaging sfizz::plugins-common)
target_link_libraries(sfizz_editor PRIVATE sfizz::vstgui) target_link_libraries(sfizz_editor PRIVATE sfizz::vstgui)
target_link_libraries(sfizz_editor PUBLIC absl::strings)
if(APPLE) if(APPLE)
find_library(APPLE_APPKIT_LIBRARY "AppKit") find_library(APPLE_APPKIT_LIBRARY "AppKit")
find_library(APPLE_CORESERVICES_LIBRARY "CoreServices") find_library(APPLE_CORESERVICES_LIBRARY "CoreServices")

View file

@ -5,6 +5,7 @@
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#pragma once #pragma once
#include "sfizz/Config.h"
#include <cassert> #include <cassert>
enum class EditId : int { enum class EditId : int {
@ -19,6 +20,10 @@ enum class EditId : int {
StretchTuning, StretchTuning,
CanEditUserFilesDir, CanEditUserFilesDir,
UserFilesDir, UserFilesDir,
//
Controller0,
ControllerLast = Controller0 + sfz::config::numCCs - 1,
//
UINumCurves, UINumCurves,
UINumMasters, UINumMasters,
UINumGroups, UINumGroups,
@ -38,3 +43,17 @@ struct EditRange {
float extent() const noexcept { return max - min; } float extent() const noexcept { return max - min; }
static EditRange get(EditId id); static EditRange get(EditId id);
}; };
inline EditId editIdForCC(int cc)
{
return EditId(int(EditId::Controller0) + cc);
}
inline int ccForEditId(EditId id)
{
return int(id) - int(EditId::Controller0);
}
inline bool editIdIsCC(EditId id)
{
return int(id) >= int(EditId::Controller0) &&
int(id) <= int(EditId::ControllerLast);
}

View file

@ -10,6 +10,7 @@
#include "GUIComponents.h" #include "GUIComponents.h"
#include "GUIPiano.h" #include "GUIPiano.h"
#include "NativeHelpers.h" #include "NativeHelpers.h"
#include "plugin/MessageUtils.h"
#include <absl/strings/string_view.h> #include <absl/strings/string_view.h>
#include <absl/strings/match.h> #include <absl/strings/match.h>
#include <absl/strings/ascii.h> #include <absl/strings/ascii.h>
@ -372,43 +373,11 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v)
} }
} }
///
static constexpr unsigned kMessageMaxIndices = 8;
static bool matchMessage(const char* pattern, const char* path, unsigned* indices)
{
unsigned nthIndex = 0;
while (const char *endp = strchr(pattern, '&')) {
if (nthIndex == kMessageMaxIndices)
return false;
size_t length = endp - pattern;
if (strncmp(pattern, path, length))
return false;
pattern += length;
path += length;
length = 0;
while (absl::ascii_isdigit(path[length]))
++length;
if (!absl::SimpleAtoi(absl::string_view(path, length), &indices[nthIndex++]))
return false;
pattern += 1;
path += length;
}
return !strcmp(path, pattern);
}
///
void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfizz_arg_t* args) void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfizz_arg_t* args)
{ {
unsigned indices[kMessageMaxIndices]; unsigned indices[8];
if (!strcmp(path, "/cc/slots") && !strcmp(sig, "b")) { if (Messages::matchOSC("/cc/slots", path, indices) && !strcmp(sig, "b")) {
const uint8_t* bitChunks = args[0].b->data; const uint8_t* bitChunks = args[0].b->data;
uint32_t byteSize = args[0].b->size; uint32_t byteSize = args[0].b->size;
@ -426,7 +395,7 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi
} }
} }
} }
else if (!strcmp(path, "/cc/changed") && !strcmp(sig, "b")) { else if (Messages::matchOSC("/cc/changed", path, indices) && !strcmp(sig, "b")) {
const uint8_t* bitChunks = args[0].b->data; const uint8_t* bitChunks = args[0].b->data;
uint32_t byteSize = args[0].b->size; uint32_t byteSize = args[0].b->size;
for (unsigned cc = 0; cc < 8 * byteSize; ++cc) { for (unsigned cc = 0; cc < 8 * byteSize; ++cc) {
@ -438,13 +407,13 @@ void Editor::Impl::uiReceiveMessage(const char* path, const char* sig, const sfi
} }
} }
} }
else if (matchMessage("/cc&/value", path, indices) && !strcmp(sig, "f")) { else if (Messages::matchOSC("/cc&/value", path, indices) && !strcmp(sig, "f")) {
updateCCValue(indices[0], args[0].f); updateCCValue(indices[0], args[0].f);
} }
else if (matchMessage("/cc&/default", path, indices) && !strcmp(sig, "f")) { else if (Messages::matchOSC("/cc&/default", path, indices) && !strcmp(sig, "f")) {
updateCCDefaultValue(indices[0], args[0].f); updateCCDefaultValue(indices[0], args[0].f);
} }
else if (matchMessage("/cc&/label", path, indices) && !strcmp(sig, "s")) { else if (Messages::matchOSC("/cc&/label", path, indices) && !strcmp(sig, "s")) {
updateCCLabel(indices[0], args[0].s); updateCCLabel(indices[0], args[0].s);
} }
else { else {

View file

@ -21,14 +21,14 @@ source_group("Turtle Files" FILES
add_library(${LV2PLUGIN_PRJ_NAME} MODULE add_library(${LV2PLUGIN_PRJ_NAME} MODULE
${PROJECT_NAME}.cpp ${PROJECT_NAME}.cpp
${LV2PLUGIN_TTL_SRC_FILES}) ${LV2PLUGIN_TTL_SRC_FILES})
target_link_libraries(${LV2PLUGIN_PRJ_NAME} PRIVATE sfizz::sfizz sfizz::spin_mutex) target_link_libraries(${LV2PLUGIN_PRJ_NAME} PRIVATE sfizz::sfizz sfizz::plugins-common)
if(SFIZZ_LV2_UI) if(SFIZZ_LV2_UI)
add_library(${LV2PLUGIN_PRJ_NAME}_ui MODULE add_library(${LV2PLUGIN_PRJ_NAME}_ui MODULE
${PROJECT_NAME}_ui.cpp ${PROJECT_NAME}_ui.cpp
vstgui_helpers.h vstgui_helpers.h
vstgui_helpers.cpp) vstgui_helpers.cpp)
target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui PRIVATE sfizz::editor sfizz::vstgui) target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui PRIVATE sfizz::editor sfizz::vstgui sfizz::plugins-common)
endif() endif()
# Explicitely strip all symbols on Linux but lv2_descriptor() # Explicitely strip all symbols on Linux but lv2_descriptor()

View file

@ -63,7 +63,7 @@ endif()
target_link_libraries(${VSTPLUGIN_PRJ_NAME} target_link_libraries(${VSTPLUGIN_PRJ_NAME}
PRIVATE sfizz::sfizz PRIVATE sfizz::sfizz
PRIVATE sfizz::editor PRIVATE sfizz::editor
PRIVATE sfizz::spin_mutex PRIVATE sfizz::plugins-common
PRIVATE sfizz::pugixml sfizz::filesystem) PRIVATE sfizz::pugixml sfizz::filesystem)
target_include_directories(${VSTPLUGIN_PRJ_NAME} target_include_directories(${VSTPLUGIN_PRJ_NAME}
PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
@ -202,7 +202,7 @@ elseif(SFIZZ_AU)
target_link_libraries(${AUPLUGIN_PRJ_NAME} target_link_libraries(${AUPLUGIN_PRJ_NAME}
PRIVATE ${PROJECT_NAME}::${PROJECT_NAME} PRIVATE ${PROJECT_NAME}::${PROJECT_NAME}
PRIVATE sfizz::editor PRIVATE sfizz::editor
PRIVATE sfizz::spin_mutex PRIVATE sfizz::plugins-common
PRIVATE sfizz::pugixml sfizz::filesystem) PRIVATE sfizz::pugixml sfizz::filesystem)
target_include_directories(${AUPLUGIN_PRJ_NAME} target_include_directories(${AUPLUGIN_PRJ_NAME}
PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")

View file

@ -9,7 +9,6 @@
#include "SfizzVstParameters.h" #include "SfizzVstParameters.h"
#include "base/source/fstreamer.h" #include "base/source/fstreamer.h"
#include "base/source/updatehandler.h" #include "base/source/updatehandler.h"
#include "pluginterfaces/vst/ivstmidicontrollers.h"
tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context)
{ {
@ -65,7 +64,7 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context)
parameters.addParameter(Steinberg::String("Pitch bend"), nullptr, 0, 0.5, 0, pid++, Vst::kRootUnitId); parameters.addParameter(Steinberg::String("Pitch bend"), nullptr, 0, 0.5, 0, pid++, Vst::kRootUnitId);
// MIDI controllers // MIDI controllers
for (unsigned i = 0; i < kNumControllerParams; ++i) { for (unsigned i = 0; i < sfz::config::numCCs; ++i) {
Steinberg::String title; Steinberg::String title;
Steinberg::String shortTitle; Steinberg::String shortTitle;
title.printf("Controller %u", i); title.printf("Controller %u", i);
@ -76,6 +75,24 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context)
pid++, Vst::kRootUnitId, shortTitle); pid++, Vst::kRootUnitId, shortTitle);
} }
// Initial MIDI mapping
for (int32 i = 0; i < Vst::kCountCtrlNumber; ++i) {
Vst::ParamID id = Vst::kNoParamId;
switch (i) {
case Vst::kAfterTouch:
id = kPidAftertouch;
break;
case Vst::kPitchBend:
id = kPidPitchBend;
break;
default:
if (i < 128)
id = kPidCC0 + i;
break;
}
midiMapping_[i] = id;
}
return kResultTrue; return kResultTrue;
} }
@ -86,22 +103,16 @@ tresult PLUGIN_API SfizzVstControllerNoUi::terminate()
tresult PLUGIN_API SfizzVstControllerNoUi::getMidiControllerAssignment(int32 busIndex, int16 channel, Vst::CtrlNumber midiControllerNumber, Vst::ParamID& id) tresult PLUGIN_API SfizzVstControllerNoUi::getMidiControllerAssignment(int32 busIndex, int16 channel, Vst::CtrlNumber midiControllerNumber, Vst::ParamID& id)
{ {
switch (midiControllerNumber) { if (midiControllerNumber < 0 || midiControllerNumber >= Vst::kCountCtrlNumber) {
case Vst::kAfterTouch: id = Vst::kNoParamId;
id = kPidMidiAftertouch; return kResultFalse;
return kResultTrue;
case Vst::kPitchBend:
id = kPidMidiPitchBend;
return kResultTrue;
default:
if (midiControllerNumber < 0 || midiControllerNumber >= kNumControllerParams)
return kResultFalse;
id = kPidMidiCC0 + midiControllerNumber;
return kResultTrue;
} }
id = midiMapping_[midiControllerNumber];
if (id == Vst::kNoParamId)
return kResultFalse;
return kResultTrue;
} }
tresult PLUGIN_API SfizzVstControllerNoUi::getParamStringByValue(Vst::ParamID tag, Vst::ParamValue valueNormalized, Vst::String128 string) tresult PLUGIN_API SfizzVstControllerNoUi::getParamStringByValue(Vst::ParamID tag, Vst::ParamValue valueNormalized, Vst::String128 string)

View file

@ -9,6 +9,7 @@
#include "SfizzVstUpdates.h" #include "SfizzVstUpdates.h"
#include "public.sdk/source/vst/vsteditcontroller.h" #include "public.sdk/source/vst/vsteditcontroller.h"
#include "public.sdk/source/vst/vstparameters.h" #include "public.sdk/source/vst/vstparameters.h"
#include "pluginterfaces/vst/ivstmidicontrollers.h"
#include "vstgui/plugin-bindings/vst3editor.h" #include "vstgui/plugin-bindings/vst3editor.h"
#include <sfizz_message.h> #include <sfizz_message.h>
#include <mutex> #include <mutex>
@ -49,6 +50,7 @@ protected:
Steinberg::IPtr<FilePathUpdate> scalaPathUpdate_; Steinberg::IPtr<FilePathUpdate> scalaPathUpdate_;
Steinberg::IPtr<ProcessorStateUpdate> processorStateUpdate_; Steinberg::IPtr<ProcessorStateUpdate> processorStateUpdate_;
Steinberg::IPtr<PlayStateUpdate> playStateUpdate_; Steinberg::IPtr<PlayStateUpdate> playStateUpdate_;
Vst::ParamID midiMapping_[Vst::kCountCtrlNumber] {};
}; };
class SfizzVstController : public SfizzVstControllerNoUi, public VSTGUI::VST3EditorDelegate { class SfizzVstController : public SfizzVstControllerNoUi, public VSTGUI::VST3EditorDelegate {

View file

@ -313,14 +313,14 @@ void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v)
void SfizzVstEditor::uiBeginSend(EditId id) void SfizzVstEditor::uiBeginSend(EditId id)
{ {
Vst::ParamID pid = parameterOfEditId(id); Vst::ParamID pid = parameterOfEditId(id);
if (pid != -1) if (pid != Vst::kNoParamId)
getController()->beginEdit(pid); getController()->beginEdit(pid);
} }
void SfizzVstEditor::uiEndSend(EditId id) void SfizzVstEditor::uiEndSend(EditId id)
{ {
Vst::ParamID pid = parameterOfEditId(id); Vst::ParamID pid = parameterOfEditId(id);
if (pid != -1) if (pid != Vst::kNoParamId)
getController()->endEdit(pid); getController()->endEdit(pid);
} }
@ -403,6 +403,6 @@ Vst::ParamID SfizzVstEditor::parameterOfEditId(EditId id)
case EditId::ScalaRootKey: return kPidScalaRootKey; case EditId::ScalaRootKey: return kPidScalaRootKey;
case EditId::TuningFrequency: return kPidTuningFrequency; case EditId::TuningFrequency: return kPidTuningFrequency;
case EditId::StretchTuning: return kPidStretchedTuning; case EditId::StretchTuning: return kPidStretchedTuning;
default: return -1; default: return Vst::kNoParamId;
} }
} }

View file

@ -5,16 +5,12 @@
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#pragma once #pragma once
#include "sfizz/Config.h"
#include "public.sdk/source/vst/vstparameters.h" #include "public.sdk/source/vst/vstparameters.h"
#include <stdexcept> #include <stdexcept>
using namespace Steinberg; using namespace Steinberg;
// number of MIDI CC
enum {
kNumControllerParams = 128,
};
// parameters // parameters
enum { enum {
kPidVolume, kPidVolume,
@ -24,10 +20,10 @@ enum {
kPidScalaRootKey, kPidScalaRootKey,
kPidTuningFrequency, kPidTuningFrequency,
kPidStretchedTuning, kPidStretchedTuning,
kPidMidiAftertouch, kPidAftertouch,
kPidMidiPitchBend, kPidPitchBend,
kPidMidiCC0, kPidCC0,
kPidMidiCCLast = kPidMidiCC0 + kNumControllerParams - 1, kPidCCLast = kPidCC0 + sfz::config::numCCs - 1,
/* Reserved */ /* Reserved */
}; };
@ -71,12 +67,12 @@ struct SfizzRange {
return {440.0, 300.0, 500.0}; return {440.0, 300.0, 500.0};
case kPidStretchedTuning: case kPidStretchedTuning:
return {0.0, 0.0, 1.0}; return {0.0, 0.0, 1.0};
case kPidMidiAftertouch: case kPidAftertouch:
return {0.0, 0.0, 1.0}; return {0.0, 0.0, 1.0};
case kPidMidiPitchBend: case kPidPitchBend:
return {0.5, 0.0, 1.0}; return {0.5, 0.0, 1.0};
default: default:
if (id >= kPidMidiCC0 && id <= kPidMidiCCLast) if (id >= kPidCC0 && id <= kPidCCLast)
return {0.0, 0.0, 1.0}; return {0.0, 0.0, 1.0};
throw std::runtime_error("Bad parameter ID"); throw std::runtime_error("Bad parameter ID");
} }

View file

@ -385,23 +385,23 @@ void SfizzVstProcessor::processControllerChanges(Vst::IParameterChanges& pc)
switch (id) { switch (id) {
default: default:
if (id >= kPidMidiCC0 && id <= kPidMidiCCLast) { if (id >= kPidCC0 && id <= kPidCCLast) {
auto ccNumber = static_cast<int>(id - kPidMidiCC0); auto ccNumber = static_cast<int>(id - kPidCC0);
for (uint32 pointIndex = 0; pointIndex < pointCount; ++pointIndex) { for (uint32 pointIndex = 0; pointIndex < pointCount; ++pointIndex) {
if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue) if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue)
synth.cc(sampleOffset, ccNumber, fastRound(value * 127.0)); synth.hdcc(sampleOffset, ccNumber, value);
} }
} }
break; break;
case kPidMidiAftertouch: case kPidAftertouch:
for (uint32 pointIndex = 0; pointIndex < pointCount; ++pointIndex) { for (uint32 pointIndex = 0; pointIndex < pointCount; ++pointIndex) {
if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue) if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue)
synth.aftertouch(sampleOffset, fastRound(value * 127.0)); synth.aftertouch(sampleOffset, fastRound(value * 127.0));
} }
break; break;
case kPidMidiPitchBend: case kPidPitchBend:
for (uint32 pointIndex = 0; pointIndex < pointCount; ++pointIndex) { for (uint32 pointIndex = 0; pointIndex < pointCount; ++pointIndex) {
if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue) if (vq->getPoint(pointIndex, sampleOffset, value) == kResultTrue)
synth.pitchWheel(sampleOffset, fastRound(value * 16383) - 8192); synth.pitchWheel(sampleOffset, fastRound(value * 16383) - 8192);