@@ -0,0 +1,93 @@ | |||
# DPF - DISTRHO Plugin Framework | |||
This file describes the available features for each plugin format. | |||
The limitations could be due to the plugin format itself or within DPF. | |||
If the limitation is within DPF, a link is provided to a description below on the reason for it. | |||
| Feature | JACK/Standalone | LADSPA | DSSI | LV2 | VST2 | VST3 | Feature | | |||
|---------------------|---------------------------------------|-------------------------|---------------------|-------------------------------|--------------------------------|----------------------------------|---------------------| | |||
| Audio port groups | [Yes*](#jack-audio-port-groups) | No | No | Yes | No | [No*](#vst3-is-work-in-progress) | Audio port groups | | |||
| Audio port as CV | Yes | No | No | Yes | No | [No*](#vst3-is-work-in-progress) | Audio port as CV | | |||
| Audio sidechan | Yes | No | No | Yes | [No*](#vst2-potential-support) | [No*](#vst3-is-work-in-progress) | Audio sidechan | | |||
| Bypass control | No | No | No | Yes | [No*](#vst2-potential-support) | [No*](#vst3-is-work-in-progress) | Bypass control | | |||
| MIDI input | Yes | No | Yes | Yes | Yes | Yes | MIDI input | | |||
| MIDI output | Yes | No | No | Yes | Yes | Yes | MIDI output | | |||
| Parameter changes | Yes | No | No | [No*](#lv2-parameter-changes) | Yes | Yes | Parameter changes | | |||
| Parameter groups | No | No | No | Yes | Yes | [No*](#vst3-is-work-in-progress) | Parameter groups | | |||
| Parameter outputs | No | No | No | Yes | No | [No*](#vst3-is-work-in-progress) | Parameter outputs | | |||
| Parameter triggers | Yes | No | No | Yes | [No*](#parameter-triggers) | [No*](#parameter-triggers) | Parameter triggers | | |||
| Programs | [Yes*](#jack-parameters-and-programs) | [No*](#ladspa-programs) | [Yes*](#dssi-state) | Yes | [No*](#vst2-programs) | Yes | Programs | | |||
| States | Yes | No | [Yes*](#dssi-state) | Yes | Yes | Yes | States | | |||
| Full/internal state | Yes | No | No | Yes | Yes | Yes | Full/internal state | | |||
| Time position | Yes | No | No | Yes | Yes | Yes | Time position | | |||
| UI | [Yes*](#jack-custom-ui-only) | No | External only | Yes | Embed only | Embed only | UI | | |||
| UI bg/fg colors | No | No | No | Yes | No | No? | UI bg/fg colors | | |||
| UI direct access | Yes | No | No | Yes | Yes | Yes | UI direct access | | |||
| UI host-filebrowser | No | No | No | Yes | [No*](#vst2-potential-support) | [No*](#vst3-is-work-in-progress) | UI host-filebrowser | | |||
| UI host-resize | Yes | No | Yes | Yes | No | [No*](#vst3-is-work-in-progress) | UI host-resize | | |||
| UI remote control | No | No | Yes | Yes | No | Yes | UI remote control | | |||
| UI send midi note | Yes | No | Yes | Yes | Yes | Yes | UI send midi note | | |||
For things that could be unclear: | |||
- "States" refers to DPF API support, supporting key-value string pairs for internal state saving | |||
- "Full state" refers to plugins updating their state internally without outside intervention (like host or UI) | |||
- "UI direct access" means `DISTRHO_PLUGIN_WANT_DIRECT_ACCESS` is possible, that is, running DSP and UI on the same process | |||
- "UI remote control" means running the UI on a separate machine (for example over the network) | |||
- An external UI on this table means that it cannot be embed into the host window, but the plugin can still provide one | |||
# Special notes | |||
## Parameter triggers | |||
Trigger-style parameters (parameters which value is reset to its default every run) are only supported in JACK and LV2. | |||
For all other plugin formats DPF will simulate the behaviour through a parameter change request. | |||
## JACK audio port groups | |||
DPF will set JACK metadata information for grouping audio ports. | |||
This is not supported by most JACK applications at the moment. | |||
## JACK parameters and programs | |||
Under JACK/Stanlone mode, MIDI input events will trigger program and parameter changes. | |||
MIDI program change events work as expected (that is, MIDI program change 0 will load 1st plugin program). | |||
MIDI CCs are used for parameter changes (matching the `midiCC` value you set on each parameter). | |||
## JACK custom UI only | |||
There is no generic plugin editor view. | |||
If your plugin has no custom UI, the standalone executable will run but not show any window. | |||
## LADSPA programs | |||
Programs for LADSPA could be done via LRDF but this is not supported in DPF. | |||
## DSSI State | |||
DSSI only supports state changes when called via UI, no "full state" possible. | |||
This also makes it impossibe to use programs and state at the same time with DSSI, | |||
because in DPF changing programs can lead to state changes but there is no way to fetch this information on DSSI plugins. | |||
To make it simpler to understand, think of DSSI programs and states as UI properties. | |||
Because in DPF changing the state happens from UI to DSP side, regular DSSI can be supported. | |||
But if we involve programs, they would need to pass through the UI in order to work. Which goes against DPF's design. | |||
## LV2 parameter changes | |||
Although this is already implemented in DPF (through a custom extension), this is not implemented on most hosts. | |||
So for now you can pretty much treat it as if not supported. | |||
## VST2 potential support | |||
Not supported in DPF at the moment. | |||
It could eventually be, but likely not due to VST2 being phased out by Steinberg. | |||
Contact DPF authors if you require such a feature. | |||
## VST2 programs | |||
VST2 program support requires saving state of all programs in memory, which is very expensive and thus not done in DPF. | |||
## VST3 is work in progress | |||
Feature is possible, just not implemented yet in DPF. |
@@ -0,0 +1,47 @@ | |||
# DPF - DISTRHO Plugin Framework | |||
Even though DPF is quite liberally licensed, not all plugin formats follow the same ideals. | |||
This is usually due to plugin APIs/headers being tied to a specific license or having commercial restrictions. | |||
This file describes the licensing that applies to each individual plugin format as a way to make it clear what is possible and compatible. | |||
Note that if you are making GPLv2+ licensed plugins this does not apply to you, as so far everything is GPLv2+ compatible. | |||
Regardless of target format, DPF itself needs to be mentioned in attribution. | |||
See the [LICENSE](LICENSE) file for copyright details. | |||
| Target | License(s) | License restrictions | Additional attribution | | |||
|-----------------|----------------------|-----------------------|------------------------| | |||
| JACK/Standalone | MIT (RtAudio) | Copyright attribution | **RtAudio**: 2001-2019 Gary P. Scavone | | |||
| LADSPA | LGPLv2.1+ | ??? (*) | 2000-2002 Richard W. E. Furse, Paul Barton-Davis, Stefan Westerfeld | | |||
| DSSI | LGPLv2.1+ | ??? (*) | **DSSI**: 2004, 2009 Chris Cannam, Steve Harris and Sean Bolton;<br/> **ALSA**: 1998-2001 Jaroslav Kysela, Abramo Bagnara, Takashi Iwai | | |||
| LV2 | ISC | Copyright attribution | 2006-2020 Steve Harris, David Robillard;<br/> 2000-2002 Richard W.E. Furse, Paul Barton-Davis, Stefan Westerfeld | | |||
| VST2 | GPLv2+ or commercial | Must be GPLv2+ compatible or alternatively use Steinberg VST2 SDK (no longer available for new plugins) | GPLv2+ compatible license or custom agreement with Steinberg | | |||
| VST3 | ISC | Copyright attribution | (none, only DPF files used) | | |||
### LADSPA and DSSI special note | |||
The header files on LADSPA and DSSI are LGPLv2.1+ licensed, which is unusual for pure APIs without libraries. | |||
LADSPA authors mention this on ladspa.org homepage: | |||
> LADSPA has been released under LGPL (GNU Lesser General Public License). | |||
> This is not intended to be the final license for LADSPA. | |||
> In the long term it is hoped that LADSPA will have a public license that is even less restrictive, so that commercial applications can use it (in a protected way) without having to use a derived LGPL library. | |||
> It may be that LGPL is already free enough for this, but we aren't sure. | |||
So the situation for LADSPA/DSSI plugins is unclear for commercial plugins. | |||
These formats are very limited and not much used anymore anyway, feel free to skip them if this situation is a potential issue for you. | |||
### VST2 special note | |||
By default DPF uses the free reverse-engineered [vestige header](distrho/src/vestige/vestige.h) file. | |||
This file is GPLv2+ licensed, so that applies to plugins built with it as well. | |||
You can alternatively build DPF-based VST2 plugins using the official Steinberg VST2 SDK, | |||
simply set the `VESTIGE_HEADER` compiler macro to `0` during build. | |||
You will need to provide your own VST2 SDK files then, as DPF does not ship with them. | |||
Note there are legal issues surrounding releasing new VST2 plugins using the official SDK, as that is no longer supported by Steinberg. | |||
### VST3 special note | |||
Contrary to most plugins, DPF does not use the official VST3 SDK. | |||
Instead, the API definitions are provided by the [travesty](distrho/src/travesty/) sub-project, licensed in the same way as DPF. | |||
This allows us to freely build plugins without being encumbered by restrictive licensing deals. | |||
It makes the internal implementation much harder for DPF, but this is not an issue for external developers. |
@@ -33,7 +33,6 @@ endif | |||
BUILD_C_FLAGS += -I. | |||
BUILD_CXX_FLAGS += -I. -I$(DPF_PATH)/distrho -I$(DPF_PATH)/dgl | |||
BUILD_CXX_FLAGS += -Wno-pmf-conversions | |||
ifeq ($(HAVE_ALSA),true) | |||
BASE_FLAGS += -DHAVE_ALSA | |||
@@ -128,7 +127,7 @@ SYMBOLS_LV2UI = $(DPF_PATH)/utils/symbols/lv2-ui.def | |||
SYMBOLS_LV2 = $(DPF_PATH)/utils/symbols/lv2.def | |||
SYMBOLS_VST2 = $(DPF_PATH)/utils/symbols/vst2.def | |||
SYMBOLS_VST3 = $(DPF_PATH)/utils/symbols/vst3.def | |||
else | |||
else ifneq ($(DEBUG),true) | |||
SYMBOLS_LADSPA = -Wl,--version-script=$(DPF_PATH)/utils/symbols/ladspa.version | |||
SYMBOLS_DSSI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/dssi.version | |||
SYMBOLS_LV2DSP = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2-dsp.version | |||
@@ -224,6 +223,13 @@ endif | |||
# TODO split dsp and ui object build flags | |||
BASE_FLAGS += $(DGL_FLAGS) | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Runtime test build | |||
ifeq ($(DPF_RUNTIME_TESTING),true) | |||
BUILD_CXX_FLAGS += -DDPF_RUNTIME_TESTING -Wno-pmf-conversions | |||
endif | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# all needs to be first | |||
@@ -386,7 +392,11 @@ endif | |||
vst3: $(vst3) | |||
ifeq ($(HAVE_DGL),true) | |||
$(vst3): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.o $(DGL_LIB) | |||
else | |||
$(vst3): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o | |||
endif | |||
-@mkdir -p $(shell dirname $@) | |||
@echo "Creating VST3 plugin for $(NAME)" | |||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_VST3) -o $@ | |||
@@ -19,6 +19,12 @@ Getting time information from the host is possible.<br/> | |||
It uses the same format as the JACK Transport API, making porting some code easier.<br/> | |||
## Licensing | |||
DPF is released under ISC, which basically means you can do whatever you want as long as you credit the original authors. | |||
Some plugin formats may have additional restrictions, see [LICENSING.md](LICENSING.md) for details. | |||
## Help and documentation | |||
Bug reports happen on the [DPF github project](https://github.com/DISTRHO/DPF/issues). | |||
@@ -107,6 +107,7 @@ public: | |||
private: | |||
struct PrivateData; | |||
PrivateData* const pData; | |||
friend class PluginApplication; | |||
friend class Window; | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Application) | |||
@@ -49,16 +49,16 @@ enum Modifier { | |||
/** | |||
Keyboard key codepoints. | |||
All keys are identified by a Unicode code point in PuglEventKey::key. This | |||
enumeration defines constants for special keys that do not have a standard | |||
code point, and some convenience constants for control characters. Note | |||
that all keys are handled in the same way, this enumeration is just for | |||
All keys are identified by a Unicode code point in Widget::KeyboardEvent::key. | |||
This enumeration defines constants for special keys that do not have a standard | |||
code point, and some convenience constants for control characters. | |||
Note that all keys are handled in the same way, this enumeration is just for | |||
convenience when writing hard-coded key bindings. | |||
Keys that do not have a standard code point use values in the Private Use | |||
Area in the Basic Multilingual Plane (`U+E000` to `U+F8FF`). Applications | |||
must take care to not interpret these values beyond key detection, the | |||
mapping used here is arbitrary and specific to DPF. | |||
Area in the Basic Multilingual Plane (`U+E000` to `U+F8FF`). | |||
Applications must take care to not interpret these values beyond key detection, | |||
the mapping used here is arbitrary and specific to DPF. | |||
*/ | |||
enum Key { | |||
// Convenience symbols for ASCII control characters | |||
@@ -116,7 +116,7 @@ enum Key { | |||
/** | |||
Common flags for all events. | |||
*/ | |||
enum Flag { | |||
enum EventFlag { | |||
kFlagSendEvent = 1, ///< Event is synthetic | |||
kFlagIsHint = 2 ///< Event is a hint (not direct user input) | |||
}; | |||
@@ -903,7 +903,7 @@ public: | |||
Constructor for a NanoSubWidget. | |||
@see CreateFlags | |||
*/ | |||
explicit NanoBaseWidget(Widget* const parentGroupWidget, int flags = CREATE_ANTIALIAS); | |||
explicit NanoBaseWidget(Widget* parentGroupWidget, int flags = CREATE_ANTIALIAS); | |||
/** | |||
Constructor for a NanoTopLevelWidget. | |||
@@ -912,16 +912,16 @@ public: | |||
explicit NanoBaseWidget(Window& windowToMapTo, int flags = CREATE_ANTIALIAS); | |||
/** | |||
Constructor for a NanoStandaloneWindow without parent window. | |||
Constructor for a NanoStandaloneWindow without transient parent window. | |||
@see CreateFlags | |||
*/ | |||
explicit NanoBaseWidget(Application& app, int flags = CREATE_ANTIALIAS); | |||
/** | |||
Constructor for a NanoStandaloneWindow with parent window. | |||
Constructor for a NanoStandaloneWindow with transient parent window. | |||
@see CreateFlags | |||
*/ | |||
explicit NanoBaseWidget(Application& app, Window& parentWindow, int flags = CREATE_ANTIALIAS); | |||
explicit NanoBaseWidget(Application& app, Window& transientParentWindow, int flags = CREATE_ANTIALIAS); | |||
/** | |||
Destructor. | |||
@@ -117,7 +117,6 @@ public: | |||
protected: | |||
bool onKeyboard(const KeyboardEvent&) override; | |||
bool onSpecial(const SpecialEvent&) override; | |||
bool onCharacterInput(const CharacterInputEvent&) override; | |||
bool onMouse(const MouseEvent&) override; | |||
bool onMotion(const MotionEvent&) override; | |||
@@ -58,7 +58,7 @@ public: | |||
These are the fields present on all Widget events. | |||
@a mod Currently active keyboard modifiers, @see Modifier. | |||
@a mod Event flags, @see Flag. | |||
@a mod Event flags, @see EventFlag. | |||
@a time Event timestamp (if any). | |||
*/ | |||
struct BaseEvent { | |||
@@ -107,14 +107,10 @@ public: | |||
/** | |||
Special keyboard event. | |||
This event allows the use of keys that do not have unicode points. | |||
Note that some are non-printable keys. | |||
@a press True if the key was pressed, false if released. | |||
@a key The key pressed. | |||
@see onSpecial | |||
DEPRECATED This used to be part of DPF due to pugl, but now deprecated and simply non-functional. | |||
All events go through KeyboardEvent or CharacterInputEvent, use those instead. | |||
*/ | |||
struct SpecialEvent : BaseEvent { | |||
struct DISTRHO_DEPRECATED_BY("KeyboardEvent") SpecialEvent : BaseEvent { | |||
bool press; | |||
Key key; | |||
@@ -398,12 +394,6 @@ protected: | |||
*/ | |||
virtual bool onKeyboard(const KeyboardEvent&); | |||
/** | |||
A function called when a special key is pressed or released. | |||
@return True to stop event propagation, false otherwise. | |||
*/ | |||
virtual bool onSpecial(const SpecialEvent&); | |||
/** | |||
A function called when an UTF-8 character is received. | |||
@return True to stop event propagation, false otherwise. | |||
@@ -433,6 +423,24 @@ protected: | |||
*/ | |||
virtual void onResize(const ResizeEvent&); | |||
/** | |||
A function called when a special key is pressed or released. | |||
DEPRECATED use onKeyboard or onCharacterInput | |||
*/ | |||
#if defined(__clang__) | |||
# pragma clang diagnostic push | |||
# pragma clang diagnostic ignored "-Wdeprecated-declarations" | |||
#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 460 | |||
# pragma GCC diagnostic push | |||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations" | |||
#endif | |||
virtual bool onSpecial(const SpecialEvent&) { return false; } | |||
#if defined(__clang__) | |||
# pragma clang diagnostic pop | |||
#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 460 | |||
# pragma GCC diagnostic pop | |||
#endif | |||
private: | |||
struct PrivateData; | |||
PrivateData* const pData; | |||
@@ -157,10 +157,10 @@ public: | |||
explicit Window(Application& app); | |||
/** | |||
Constructor for a modal window, by having another window as its parent. | |||
Constructor for a modal window, by having another window as its transient parent. | |||
The Application instance must be the same between the 2 windows. | |||
*/ | |||
explicit Window(Application& app, Window& parent); | |||
explicit Window(Application& app, Window& transientParentWindow); | |||
/** | |||
Constructor for an embed Window without known size, | |||
@@ -369,7 +369,7 @@ public: | |||
This function does not block the event loop. | |||
*/ | |||
bool openFileBrowser(const FileBrowserOptions& options); | |||
bool openFileBrowser(const FileBrowserOptions& options = FileBrowserOptions()); | |||
#endif | |||
/** | |||
@@ -0,0 +1 @@ | |||
pugl-upstream/include/ |
@@ -118,6 +118,11 @@ void Application::PrivateData::idle(const uint timeoutInMs) | |||
puglUpdate(world, timeoutInSeconds); | |||
} | |||
triggerIdleCallbacks(); | |||
} | |||
void Application::PrivateData::triggerIdleCallbacks() | |||
{ | |||
for (std::list<IdleCallback*>::iterator it = idleCallbacks.begin(), ite = idleCallbacks.end(); it != ite; ++it) | |||
{ | |||
IdleCallback* const idleCallback(*it); | |||
@@ -84,6 +84,9 @@ struct Application::PrivateData { | |||
/** Run Pugl world update for @a timeoutInMs, and then each idle callback in order of registration. */ | |||
void idle(uint timeoutInMs); | |||
/** Run each idle callback without updating pugl world. */ | |||
void triggerIdleCallbacks(); | |||
/** Set flag indicating application is quitting, and close all windows in reverse order of registration. | |||
For standalone mode only. */ | |||
void quit(); | |||
@@ -100,11 +100,6 @@ bool TopLevelWidget::onKeyboard(const KeyboardEvent&) | |||
return false; | |||
} | |||
bool TopLevelWidget::onSpecial(const SpecialEvent&) | |||
{ | |||
return false; | |||
} | |||
bool TopLevelWidget::onCharacterInput(const CharacterInputEvent&) | |||
{ | |||
return false; | |||
@@ -50,20 +50,6 @@ bool TopLevelWidget::PrivateData::keyboardEvent(const KeyboardEvent& ev) | |||
return selfw->pData->giveKeyboardEventForSubWidgets(ev); | |||
} | |||
bool TopLevelWidget::PrivateData::specialEvent(const SpecialEvent& ev) | |||
{ | |||
// ignore event if we are not visible | |||
if (! selfw->pData->visible) | |||
return false; | |||
// give top-level widget chance to catch this event first | |||
if (self->onSpecial(ev)) | |||
return true; | |||
// propagate event to all subwidgets recursively | |||
return selfw->pData->giveSpecialEventForSubWidgets(ev); | |||
} | |||
bool TopLevelWidget::PrivateData::characterInputEvent(const CharacterInputEvent& ev) | |||
{ | |||
// ignore event if we are not visible | |||
@@ -34,7 +34,6 @@ struct TopLevelWidget::PrivateData { | |||
~PrivateData(); | |||
void display(); | |||
bool keyboardEvent(const KeyboardEvent& ev); | |||
bool specialEvent(const SpecialEvent& ev); | |||
bool characterInputEvent(const CharacterInputEvent& ev); | |||
bool mouseEvent(const MouseEvent& ev); | |||
bool motionEvent(const MotionEvent& ev); | |||
@@ -167,11 +167,6 @@ bool Widget::onKeyboard(const KeyboardEvent& ev) | |||
return pData->giveKeyboardEventForSubWidgets(ev); | |||
} | |||
bool Widget::onSpecial(const SpecialEvent& ev) | |||
{ | |||
return pData->giveSpecialEventForSubWidgets(ev); | |||
} | |||
bool Widget::onCharacterInput(const CharacterInputEvent& ev) | |||
{ | |||
return pData->giveCharacterInputEventForSubWidgets(ev); | |||
@@ -87,24 +87,6 @@ bool Widget::PrivateData::giveKeyboardEventForSubWidgets(const KeyboardEvent& ev | |||
return false; | |||
} | |||
bool Widget::PrivateData::giveSpecialEventForSubWidgets(const SpecialEvent& ev) | |||
{ | |||
if (! visible) | |||
return false; | |||
if (subWidgets.size() == 0) | |||
return false; | |||
FOR_EACH_SUBWIDGET_INV(rit) | |||
{ | |||
SubWidget* const widget(*rit); | |||
if (widget->isVisible() && widget->onSpecial(ev)) | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool Widget::PrivateData::giveCharacterInputEventForSubWidgets(const CharacterInputEvent& ev) | |||
{ | |||
if (! visible) | |||
@@ -44,7 +44,6 @@ struct Widget::PrivateData { | |||
void displaySubWidgets(uint width, uint height, double autoScaleFactor); | |||
bool giveKeyboardEventForSubWidgets(const KeyboardEvent& ev); | |||
bool giveSpecialEventForSubWidgets(const SpecialEvent& ev); | |||
bool giveCharacterInputEventForSubWidgets(const CharacterInputEvent& ev); | |||
bool giveMouseEventForSubWidgets(MouseEvent& ev); | |||
bool giveMotionEventForSubWidgets(MotionEvent& ev); | |||
@@ -66,8 +66,8 @@ Window::Window(Application& app) | |||
pData->initPost(); | |||
} | |||
Window::Window(Application& app, Window& parent) | |||
: pData(new PrivateData(app, this, parent.pData)) | |||
Window::Window(Application& app, Window& transientParentWindow) | |||
: pData(new PrivateData(app, this, transientParentWindow.pData)) | |||
{ | |||
pData->initPost(); | |||
} | |||
@@ -407,22 +407,6 @@ void Window::setTransientWinId(const uintptr_t winId) | |||
{ | |||
puglSetTransientFor(pData->view, winId); | |||
} | |||
// ----------------------------------------------------------------------- | |||
bool Window::handlePluginKeyboard(const bool press, const uint key) | |||
{ | |||
// TODO | |||
return false; | |||
// return pData->handlePluginKeyboard(press, key); | |||
} | |||
bool Window::handlePluginSpecial(const bool press, const Key key) | |||
{ | |||
// TODO | |||
return false; | |||
// return pData->handlePluginSpecial(press, key); | |||
} | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
@@ -33,7 +33,11 @@ | |||
#define DGL_DEBUG_EVENTS | |||
#if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) | |||
# include <cinttypes> | |||
# ifdef DISTRHO_PROPER_CPP11_SUPPORT | |||
# include <cinttypes> | |||
# else | |||
# include <inttypes.h> | |||
# endif | |||
#endif | |||
START_NAMESPACE_DGL | |||
@@ -820,24 +824,6 @@ void Window::PrivateData::onPuglKey(const Widget::KeyboardEvent& ev) | |||
#endif | |||
} | |||
void Window::PrivateData::onPuglSpecial(const Widget::SpecialEvent& ev) | |||
{ | |||
DGL_DBGp("onPuglSpecial : %i %u\n", ev.press, ev.key); | |||
if (modal.child != nullptr) | |||
return modal.child->focus(); | |||
#ifndef DPF_TEST_WINDOW_CPP | |||
FOR_EACH_TOP_LEVEL_WIDGET_INV(rit) | |||
{ | |||
TopLevelWidget* const widget(*rit); | |||
if (widget->isVisible() && widget->pData->specialEvent(ev)) | |||
break; | |||
} | |||
#endif | |||
} | |||
void Window::PrivateData::onPuglText(const Widget::CharacterInputEvent& ev) | |||
{ | |||
DGL_DBGp("onPuglText : %u %u %s\n", ev.keycode, ev.character, ev.string); | |||
@@ -982,7 +968,6 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
case PUGL_KEY_RELEASE: | |||
{ | |||
// unused x, y, xRoot, yRoot (double) | |||
// TODO special keys? | |||
Widget::KeyboardEvent ev; | |||
ev.mod = event->key.state; | |||
ev.flags = event->key.flags; | |||
@@ -990,8 +975,14 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
ev.press = event->type == PUGL_KEY_PRESS; | |||
ev.key = event->key.key; | |||
ev.keycode = event->key.keycode; | |||
if ((ev.mod & kModifierShift) != 0 && ev.key >= 'a' && ev.key <= 'z') | |||
ev.key -= 'a' - 'A'; // a-z -> A-Z | |||
// keyboard events must always be lowercase | |||
if (ev.key >= 'A' && ev.key <= 'Z') | |||
{ | |||
ev.key += 'a' - 'A'; // A-Z -> a-z | |||
ev.mod |= kModifierShift; | |||
} | |||
pData->onPuglKey(ev); | |||
break; | |||
} | |||
@@ -178,7 +178,6 @@ struct Window::PrivateData : IdleCallback { | |||
void onPuglClose(); | |||
void onPuglFocus(bool focus, CrossingMode mode); | |||
void onPuglKey(const Widget::KeyboardEvent& ev); | |||
void onPuglSpecial(const Widget::SpecialEvent& ev); | |||
void onPuglText(const Widget::CharacterInputEvent& ev); | |||
void onPuglMouse(const Widget::MouseEvent& ev); | |||
void onPuglMotion(const Widget::MotionEvent& ev); | |||
@@ -106,13 +106,6 @@ START_NAMESPACE_DISTRHO | |||
return d_cconst('M', 'u', 't', 'e'); | |||
} | |||
/* ---------------------------------------------------------------------------------------- | |||
* This example has no parameters, so skip parameter stuff */ | |||
void initParameter(uint32_t, Parameter&) override {} | |||
float getParameterValue(uint32_t) const override { return 0.0f; } | |||
void setParameterValue(uint32_t, float) override {} | |||
/* ---------------------------------------------------------------------------------------- | |||
* Audio/MIDI Processing */ | |||
@@ -507,6 +500,20 @@ START_NAMESPACE_DISTRHO | |||
*/ | |||
#define DISTRHO_PLUGIN_IS_SYNTH 1 | |||
/** | |||
Request the minimum buffer size for the input and output event ports.@n | |||
Currently only used in LV2, with a default value of 2048 if unset. | |||
*/ | |||
#define DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE 2048 | |||
/** | |||
Whether the plugin has an LV2 modgui. | |||
This will simply add a "rdfs:seeAlso <modgui.ttl>" on the LV2 manifest.@n | |||
It is up to you to create this file. | |||
*/ | |||
#define DISTRHO_PLUGIN_USES_MODGUI 0 | |||
/** | |||
Enable direct access between the %UI and plugin code. | |||
@see UI::getPluginInstancePointer() | |||
@@ -613,6 +620,158 @@ START_NAMESPACE_DISTRHO | |||
*/ | |||
#define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI" | |||
/** | |||
Custom LV2 category for the plugin.@n | |||
This can be one of the following values: | |||
- lv2:Plugin | |||
- lv2:AllpassPlugin | |||
- lv2:AmplifierPlugin | |||
- lv2:AnalyserPlugin | |||
- lv2:BandpassPlugin | |||
- lv2:ChorusPlugin | |||
- lv2:CombPlugin | |||
- lv2:CompressorPlugin | |||
- lv2:ConstantPlugin | |||
- lv2:ConverterPlugin | |||
- lv2:DelayPlugin | |||
- lv2:DistortionPlugin | |||
- lv2:DynamicsPlugin | |||
- lv2:EQPlugin | |||
- lv2:EnvelopePlugin | |||
- lv2:ExpanderPlugin | |||
- lv2:FilterPlugin | |||
- lv2:FlangerPlugin | |||
- lv2:FunctionPlugin | |||
- lv2:GatePlugin | |||
- lv2:GeneratorPlugin | |||
- lv2:HighpassPlugin | |||
- lv2:InstrumentPlugin | |||
- lv2:LimiterPlugin | |||
- lv2:LowpassPlugin | |||
- lv2:MIDIPlugin | |||
- lv2:MixerPlugin | |||
- lv2:ModulatorPlugin | |||
- lv2:MultiEQPlugin | |||
- lv2:OscillatorPlugin | |||
- lv2:ParaEQPlugin | |||
- lv2:PhaserPlugin | |||
- lv2:PitchPlugin | |||
- lv2:ReverbPlugin | |||
- lv2:SimulatorPlugin | |||
- lv2:SpatialPlugin | |||
- lv2:SpectralPlugin | |||
- lv2:UtilityPlugin | |||
- lv2:WaveshaperPlugin | |||
See http://lv2plug.in/ns/lv2core for more information. | |||
*/ | |||
#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:Plugin" | |||
/** | |||
Custom VST3 categories for the plugin.@n | |||
This is a list of categories, separated by a @c |. | |||
Each effect category can be one of the following values: | |||
- Fx | |||
- Fx|Ambisonics | |||
- Fx|Analyzer | |||
- Fx|Delay | |||
- Fx|Distortion | |||
- Fx|Dynamics | |||
- Fx|EQ | |||
- Fx|Filter | |||
- Fx|Instrument | |||
- Fx|Instrument|External | |||
- Fx|Spatial | |||
- Fx|Generator | |||
- Fx|Mastering | |||
- Fx|Modulation | |||
- Fx|Network | |||
- Fx|Pitch Shift | |||
- Fx|Restoration | |||
- Fx|Reverb | |||
- Fx|Surround | |||
- Fx|Tools | |||
Each instrument category can be one of the following values: | |||
- Instrument | |||
- Instrument|Drum | |||
- Instrument|External | |||
- Instrument|Piano | |||
- Instrument|Sampler | |||
- Instrument|Synth | |||
- Instrument|Synth|Sampler | |||
@note DPF will automatically set Mono and Stereo categories when appropriate. | |||
*/ | |||
#define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx" | |||
/** @} */ | |||
/* ------------------------------------------------------------------------------------------------------------ | |||
* Plugin Macros */ | |||
/** | |||
@defgroup ExtraPluginMacros Extra Plugin Macros | |||
C Macros to customize DPF behaviour. | |||
These are macros that do not set plugin features or information, but instead change DPF internals. | |||
They are all optional. | |||
Unless stated otherwise, values are assumed to be a simple/empty define. | |||
@{ | |||
*/ | |||
/** | |||
Whether to enable runtime plugin tests.@n | |||
This will check, during initialization of the plugin, if parameters, programs and states are setup properly.@n | |||
Useful to enable as part of CI, can safely be skipped.@n | |||
Under DPF makefiles this can be enabled by using `make DPF_RUNTIME_TESTING=true`. | |||
@note Some checks are only available with the GCC compiler, | |||
for detecting if a virtual function has been reimplemented. | |||
*/ | |||
#define DPF_RUNTIME_TESTING | |||
/** | |||
Whether to show parameter outputs in the VST2 plugins.@n | |||
This is disabled (unset) by default, as the VST2 format has no notion of read-only parameters. | |||
*/ | |||
#define DPF_VST_SHOW_PARAMETER_OUTPUTS | |||
/** | |||
Disable all file browser related code.@n | |||
Must be set as compiler macro when building DGL. (e.g. `CXXFLAGS="-DDGL_FILE_BROWSER_DISABLED"`) | |||
*/ | |||
#define DGL_FILE_BROWSER_DISABLED | |||
/** | |||
Disable resource files, like internally used fonts.@n | |||
Must be set as compiler macro when building DGL. (e.g. `CXXFLAGS="-DDGL_NO_SHARED_RESOURCES"`) | |||
*/ | |||
#define DGL_NO_SHARED_RESOURCES | |||
/** | |||
Whether to use OpenGL3 instead of the default OpenGL2 compatility profile. | |||
Under DPF makefiles this can be enabled by using `make USE_OPENGL3=true` on the dgl build step. | |||
@note This is experimental and incomplete, contributions are welcome and appreciated. | |||
*/ | |||
#define DGL_USE_OPENGL3 | |||
/** | |||
Whether to use the GPLv2+ vestige header instead of the official Steinberg VST2 SDK.@n | |||
This is a boolean, and enabled (set to 1) by default.@n | |||
Set this to 0 in order to create non-GPL binaries. | |||
(but then at your own discretion in regards to Steinberg licensing)@n | |||
When set to 0, DPF will import the VST2 definitions from `"vst/aeffectx.h"` (not shipped with DPF). | |||
*/ | |||
#define VESTIGE_HEADER 1 | |||
/** @} */ | |||
// ----------------------------------------------------------------------------------------------------------- | |||
@@ -40,7 +40,9 @@ START_NAMESPACE_DISTRHO | |||
static const uint32_t kAudioPortIsCV = 0x1; | |||
/** | |||
Audio port should be used as sidechan (LV2 only). | |||
Audio port should be used as sidechan (LV2 and VST3 only). | |||
This hint should not be used with CV style ports. | |||
@note non-sidechain audio ports must exist in the plugin if this flag is set. | |||
*/ | |||
static const uint32_t kAudioPortIsSidechain = 0x2; | |||
@@ -632,6 +634,9 @@ struct MidiEvent { | |||
/** | |||
MIDI data.@n | |||
If size > kDataSize, dataExt is used (otherwise null). | |||
When dataExt is used, the event holder is responsible for | |||
keeping the pointer valid during the entirety of the run function. | |||
*/ | |||
uint8_t data[kDataSize]; | |||
const uint8_t* dataExt; | |||
@@ -27,7 +27,7 @@ | |||
#elif defined(DISTRHO_PLUGIN_TARGET_VST2) | |||
// nothing | |||
#elif defined(DISTRHO_PLUGIN_TARGET_VST3) | |||
// nothing | |||
# include "src/DistrhoUIVST3.cpp" | |||
#else | |||
# error unsupported format | |||
#endif |
@@ -23,7 +23,25 @@ START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
// The following code was based from juce-core LeakDetector class | |||
// Copyright (C) 2013 Raw Material Software Ltd. | |||
/** | |||
Copyright (C) 2013 Raw Material Software Ltd. | |||
Permission is granted to use this software under the terms of the ISC license | |||
http://www.isc.org/downloads/software-support-policy/isc-license/ | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD | |||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |||
FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, | |||
OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF | |||
USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | |||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | |||
OF THIS SOFTWARE. | |||
*/ | |||
/** A good old-fashioned C macro concatenation helper. | |||
This combines two items (which may themselves be macros) into a single string, | |||
@@ -25,7 +25,25 @@ START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
// The following code was based from juce-core ScopedPointer class | |||
// Copyright (C) 2013 Raw Material Software Ltd. | |||
/** | |||
Copyright (C) 2013 Raw Material Software Ltd. | |||
Permission is granted to use this software under the terms of the ISC license | |||
http://www.isc.org/downloads/software-support-policy/isc-license/ | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD | |||
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND | |||
FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, | |||
OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF | |||
USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | |||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | |||
OF THIS SOFTWARE. | |||
*/ | |||
//============================================================================== | |||
/** | |||
@@ -516,7 +516,7 @@ public: | |||
*/ | |||
String& replace(const char before, const char after) noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(before != '\0' && after != '\0', *this); | |||
DISTRHO_SAFE_ASSERT_RETURN(before != '\0' /* && after != '\0' */, *this); | |||
for (std::size_t i=0; i < fBufferLen; ++i) | |||
{ | |||
@@ -109,7 +109,7 @@ | |||
#define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_CONTINUE(msg, cond) if (! (cond)) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } continue; } | |||
#define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN(msg, cond, ret) if (! (cond)) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } return ret; } | |||
#define DISTRHO_SAFE_ASSERT_INT_BREAK(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value); break; } | |||
#define DISTRHO_SAFE_ASSERT_INT_BREAK(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value)); break; } | |||
#define DISTRHO_SAFE_ASSERT_INT_CONTINUE(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value)); continue; } | |||
#define DISTRHO_SAFE_ASSERT_INT_RETURN(cond, value, ret) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value)); return ret; } | |||
@@ -117,7 +117,7 @@ | |||
#define DISTRHO_SAFE_ASSERT_INT2_CONTINUE(cond, v1, v2) if (! (cond)) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast<int>(v1), static_cast<int>(v2)); continue; } | |||
#define DISTRHO_SAFE_ASSERT_INT2_RETURN(cond, v1, v2, ret) if (! (cond)) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast<int>(v1), static_cast<int>(v2)); return ret; } | |||
#define DISTRHO_SAFE_ASSERT_UINT_BREAK(cond, value) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast<uint>(value); break; } | |||
#define DISTRHO_SAFE_ASSERT_UINT_BREAK(cond, value) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast<uint>(value)); break; } | |||
#define DISTRHO_SAFE_ASSERT_UINT_CONTINUE(cond, value) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast<uint>(value)); continue; } | |||
#define DISTRHO_SAFE_ASSERT_UINT_RETURN(cond, value, ret) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast<uint>(value)); return ret; } | |||
@@ -199,6 +199,9 @@ private: \ | |||
# pragma warning(disable:4244) /* possible loss of data */ | |||
#endif | |||
/* Useful macros */ | |||
#define ARRAY_SIZE(ARRAY) sizeof(ARRAY)/sizeof(ARRAY[0]) | |||
/* Useful typedefs */ | |||
typedef unsigned char uchar; | |||
typedef unsigned short int ushort; | |||
@@ -29,7 +29,7 @@ bool d_lastCanRequestParameterValueChanges = false; | |||
* Static fallback data, see DistrhoPluginInternal.hpp */ | |||
const String PluginExporter::sFallbackString; | |||
const AudioPort PluginExporter::sFallbackAudioPort; | |||
/* */ AudioPortWithBusId PluginExporter::sFallbackAudioPort; | |||
const ParameterRanges PluginExporter::sFallbackRanges; | |||
const ParameterEnumerationValues PluginExporter::sFallbackEnumValues; | |||
const PortGroupWithId PluginExporter::sFallbackPortGroup; | |||
@@ -41,7 +41,7 @@ Plugin::Plugin(uint32_t parameterCount, uint32_t programCount, uint32_t stateCou | |||
: pData(new PrivateData()) | |||
{ | |||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
pData->audioPorts = new AudioPort[DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS]; | |||
pData->audioPorts = new AudioPortWithBusId[DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS]; | |||
#endif | |||
#ifdef DPF_ABORT_ON_ERROR | |||
@@ -173,7 +173,6 @@ | |||
# error DISTRHO_UI_IS_STANDALONE must not be defined | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
#endif // DISTRHO_PLUGIN_CHECKS_H_INCLUDED |
@@ -44,6 +44,14 @@ typedef bool (*requestParameterValueChangeFunc) (void* ptr, uint32_t index, floa | |||
// ----------------------------------------------------------------------- | |||
// Helpers | |||
struct AudioPortWithBusId : AudioPort { | |||
uint32_t busId; | |||
AudioPortWithBusId() | |||
: AudioPort(), | |||
busId(0) {} | |||
}; | |||
struct PortGroupWithId : PortGroup { | |||
uint32_t groupId; | |||
@@ -78,7 +86,7 @@ struct Plugin::PrivateData { | |||
bool isProcessing; | |||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
AudioPort* audioPorts; | |||
AudioPortWithBusId* audioPorts; | |||
#endif | |||
uint32_t parameterCount; | |||
@@ -162,6 +170,15 @@ struct Plugin::PrivateData { | |||
# if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE) | |||
parameterOffset += 1; | |||
# endif | |||
#endif | |||
#ifdef DISTRHO_PLUGIN_TARGET_VST3 | |||
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
parameterOffset += 130 * 16; // all MIDI CCs plus aftertouch and pitchbend | |||
# endif | |||
# if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
parameterOffset += 1; | |||
# endif | |||
#endif | |||
} | |||
@@ -247,30 +264,26 @@ public: | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | |||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); | |||
/* Verify that virtual functions are overriden if parameters, programs or states are in use. | |||
#if defined(DPF_RUNTIME_TESTING) && defined(__GNUC__) && !defined(__clang__) | |||
/* Run-time testing build. | |||
* Verify that virtual functions are overriden if parameters, programs or states are in use. | |||
* This does not work on all compilers, but we use it purely as informational check anyway. */ | |||
#if defined(__GNUC__) && !defined(__clang__) | |||
# ifdef DPF_ABORT_ON_ERROR | |||
# define DPF_ABORT abort(); | |||
# else | |||
# define DPF_ABORT | |||
# endif | |||
if (fData->parameterCount != 0) | |||
{ | |||
if ((void*)(fPlugin->*(&Plugin::initParameter)) == (void*)&Plugin::initParameter) | |||
{ | |||
d_stderr2("DPF warning: Plugins with parameters must implement `initParameter`"); | |||
DPF_ABORT | |||
abort(); | |||
} | |||
if ((void*)(fPlugin->*(&Plugin::getParameterValue)) == (void*)&Plugin::getParameterValue) | |||
{ | |||
d_stderr2("DPF warning: Plugins with parameters must implement `getParameterValue`"); | |||
DPF_ABORT | |||
abort(); | |||
} | |||
if ((void*)(fPlugin->*(&Plugin::setParameterValue)) == (void*)&Plugin::setParameterValue) | |||
{ | |||
d_stderr2("DPF warning: Plugins with parameters must implement `setParameterValue`"); | |||
DPF_ABORT | |||
abort(); | |||
} | |||
} | |||
@@ -280,12 +293,12 @@ public: | |||
if ((void*)(fPlugin->*(&Plugin::initProgramName)) == (void*)&Plugin::initProgramName) | |||
{ | |||
d_stderr2("DPF warning: Plugins with programs must implement `initProgramName`"); | |||
DPF_ABORT | |||
abort(); | |||
} | |||
if ((void*)(fPlugin->*(&Plugin::loadProgram)) == (void*)&Plugin::loadProgram) | |||
{ | |||
d_stderr2("DPF warning: Plugins with programs must implement `loadProgram`"); | |||
DPF_ABORT | |||
abort(); | |||
} | |||
} | |||
# endif | |||
@@ -296,13 +309,13 @@ public: | |||
if ((void*)(fPlugin->*(&Plugin::initState)) == (void*)&Plugin::initState) | |||
{ | |||
d_stderr2("DPF warning: Plugins with state must implement `initState`"); | |||
DPF_ABORT | |||
abort(); | |||
} | |||
if ((void*)(fPlugin->*(&Plugin::setState)) == (void*)&Plugin::setState) | |||
{ | |||
d_stderr2("DPF warning: Plugins with state must implement `setState`"); | |||
DPF_ABORT | |||
abort(); | |||
} | |||
} | |||
# endif | |||
@@ -313,17 +326,15 @@ public: | |||
if ((void*)(fPlugin->*(&Plugin::getState)) == (void*)&Plugin::getState) | |||
{ | |||
d_stderr2("DPF warning: Plugins with full state must implement `getState`"); | |||
DPF_ABORT | |||
abort(); | |||
} | |||
} | |||
else | |||
{ | |||
d_stderr2("DPF warning: Plugins with full state must have at least 1 state"); | |||
DPF_ABORT | |||
abort(); | |||
} | |||
# endif | |||
# undef DPF_ABORT | |||
#endif | |||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
@@ -469,7 +480,7 @@ public: | |||
#endif | |||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
const AudioPort& getAudioPort(const bool input, const uint32_t index) const noexcept | |||
AudioPortWithBusId& getAudioPort(const bool input, const uint32_t index) const noexcept | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackAudioPort); | |||
@@ -488,6 +499,11 @@ public: | |||
return fData->audioPorts[index + (input ? 0 : DISTRHO_PLUGIN_NUM_INPUTS)]; | |||
} | |||
uint32_t getAudioPortHints(const bool input, const uint32_t index) const noexcept | |||
{ | |||
return getAudioPort(input, index).hints; | |||
} | |||
#endif | |||
uint32_t getParameterCount() const noexcept | |||
@@ -528,6 +544,11 @@ public: | |||
return (getParameterHints(index) & kParameterIsOutput) != 0x0; | |||
} | |||
bool isParameterTrigger(const uint32_t index) const noexcept | |||
{ | |||
return (getParameterHints(index) & kParameterIsTrigger) == kParameterIsTrigger; | |||
} | |||
bool isParameterOutputOrTrigger(const uint32_t index) const noexcept | |||
{ | |||
const uint32_t hints = getParameterHints(index); | |||
@@ -603,6 +624,14 @@ public: | |||
return fData->parameters[index].groupId; | |||
} | |||
float getParameterDefault(const uint32_t index) const | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f); | |||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0.0f); | |||
return fData->parameters[index].ranges.def; | |||
} | |||
float getParameterValue(const uint32_t index) const | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f); | |||
@@ -888,7 +917,7 @@ private: | |||
// Static fallback data, see DistrhoPlugin.cpp | |||
static const String sFallbackString; | |||
static const AudioPort sFallbackAudioPort; | |||
static /* */ AudioPortWithBusId sFallbackAudioPort; | |||
static const ParameterRanges sFallbackRanges; | |||
static const ParameterEnumerationValues sFallbackEnumValues; | |||
static const PortGroupWithId sFallbackPortGroup; | |||
@@ -261,7 +261,6 @@ public: | |||
using namespace DGL_NAMESPACE; | |||
int special = 0; | |||
switch (value) | |||
{ | |||
// convert some VST special values to normal keys | |||
@@ -304,37 +303,37 @@ public: | |||
- kKeyCapsLock | |||
- kKeyPrintScreen | |||
*/ | |||
case 40: special = kKeyF1; break; | |||
case 41: special = kKeyF2; break; | |||
case 42: special = kKeyF3; break; | |||
case 43: special = kKeyF4; break; | |||
case 44: special = kKeyF5; break; | |||
case 45: special = kKeyF6; break; | |||
case 46: special = kKeyF7; break; | |||
case 47: special = kKeyF8; break; | |||
case 48: special = kKeyF9; break; | |||
case 49: special = kKeyF10; break; | |||
case 50: special = kKeyF11; break; | |||
case 51: special = kKeyF12; break; | |||
case 11: special = kKeyLeft; break; | |||
case 12: special = kKeyUp; break; | |||
case 13: special = kKeyRight; break; | |||
case 14: special = kKeyDown; break; | |||
case 15: special = kKeyPageUp; break; | |||
case 16: special = kKeyPageDown; break; | |||
case 10: special = kKeyHome; break; | |||
case 9: special = kKeyEnd; break; | |||
case 21: special = kKeyInsert; break; | |||
case 54: special = kKeyShift; break; | |||
case 55: special = kKeyControl; break; | |||
case 56: special = kKeyAlt; break; | |||
case 58: special = kKeyMenu; break; | |||
case 52: special = kKeyNumLock; break; | |||
case 53: special = kKeyScrollLock; break; | |||
case 5: special = kKeyPause; break; | |||
case 40: index = kKeyF1; break; | |||
case 41: index = kKeyF2; break; | |||
case 42: index = kKeyF3; break; | |||
case 43: index = kKeyF4; break; | |||
case 44: index = kKeyF5; break; | |||
case 45: index = kKeyF6; break; | |||
case 46: index = kKeyF7; break; | |||
case 47: index = kKeyF8; break; | |||
case 48: index = kKeyF9; break; | |||
case 49: index = kKeyF10; break; | |||
case 50: index = kKeyF11; break; | |||
case 51: index = kKeyF12; break; | |||
case 11: index = kKeyLeft; break; | |||
case 12: index = kKeyUp; break; | |||
case 13: index = kKeyRight; break; | |||
case 14: index = kKeyDown; break; | |||
case 15: index = kKeyPageUp; break; | |||
case 16: index = kKeyPageDown; break; | |||
case 10: index = kKeyHome; break; | |||
case 9: index = kKeyEnd; break; | |||
case 21: index = kKeyInsert; break; | |||
case 54: index = kKeyShift; break; | |||
case 55: index = kKeyControl; break; | |||
case 56: index = kKeyAlt; break; | |||
case 58: index = kKeyMenu; break; | |||
case 52: index = kKeyNumLock; break; | |||
case 53: index = kKeyScrollLock; break; | |||
case 5: index = kKeyPause; break; | |||
} | |||
switch (special) | |||
switch (index) | |||
{ | |||
case kKeyShift: | |||
if (down) | |||
@@ -356,15 +355,26 @@ public: | |||
break; | |||
} | |||
if (special != 0) | |||
{ | |||
fUI.handlePluginSpecial(down, static_cast<Key>(special), fKeyboardModifiers); | |||
return 1; | |||
} | |||
if (index > 0) | |||
{ | |||
fUI.handlePluginKeyboard(down, static_cast<uint>(index), fKeyboardModifiers); | |||
// keyboard events must always be lowercase | |||
bool needsShiftRevert = false; | |||
if (index >= 'A' && index <= 'Z') | |||
{ | |||
index += 'a' - 'A'; // A-Z -> a-z | |||
if ((fKeyboardModifiers & kModifierShift) == 0x0) | |||
{ | |||
needsShiftRevert = true; | |||
fKeyboardModifiers |= kModifierShift; | |||
} | |||
} | |||
fUI.handlePluginKeyboardVST2(down, static_cast<uint>(index), fKeyboardModifiers); | |||
if (needsShiftRevert) | |||
fKeyboardModifiers &= ~kModifierShift; | |||
return 1; | |||
} | |||
@@ -1056,7 +1066,7 @@ public: | |||
void vst_setParameter(const int32_t index, const float value) | |||
{ | |||
const uint32_t hints(fPlugin.getParameterHints(index)); | |||
const uint32_t hints = fPlugin.getParameterHints(index); | |||
const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); | |||
// TODO figure out how to detect kVstParameterUsesIntegerMinMax host support, and skip normalization | |||
@@ -1104,7 +1114,7 @@ public: | |||
fTimePosition.playing = (vstTimeInfo->flags & kVstTransportPlaying); | |||
fTimePosition.bbt.valid = ((vstTimeInfo->flags & kVstTempoValid) != 0 || (vstTimeInfo->flags & kVstTimeSigValid) != 0); | |||
// ticksPerBeat is not possible with VST | |||
// ticksPerBeat is not possible with VST2 | |||
fTimePosition.bbt.ticksPerBeat = 1920.0; | |||
if (vstTimeInfo->flags & kVstTempoValid) | |||
@@ -91,7 +91,7 @@ public: | |||
g_nextScaleFactor = 0.0; | |||
g_nextBundlePath = nullptr; | |||
#else | |||
// Leave context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp | |||
// enter context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp | |||
uiData->window->leaveContext(); | |||
#endif | |||
UI::PrivateData::s_nextPrivateData = nullptr; | |||
@@ -234,6 +234,28 @@ public: | |||
// ------------------------------------------------------------------- | |||
#if defined(DISTRHO_PLUGIN_TARGET_VST3) && (defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)) | |||
void addIdleCallbackForVST3(IdleCallback* const cb, const uint timerFrequencyInMs) | |||
{ | |||
uiData->window->addIdleCallback(cb, timerFrequencyInMs); | |||
} | |||
void removeIdleCallbackForVST3(IdleCallback* const cb) | |||
{ | |||
uiData->window->removeIdleCallback(cb); | |||
} | |||
void idleForVST3() | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |||
uiData->app.triggerIdleCallbacks(); | |||
ui->uiIdle(); | |||
} | |||
#endif | |||
// ------------------------------------------------------------------- | |||
void setWindowTitle(const char* const uiTitle) | |||
{ | |||
uiData->window->setTitle(uiTitle); | |||
@@ -258,23 +280,25 @@ public: | |||
} | |||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
bool handlePluginKeyboard(const bool press, const uint key, const uint16_t mods) | |||
bool handlePluginKeyboardVST2(const bool press, const uint key, const uint16_t mods) | |||
{ | |||
// TODO also trigger Character input event | |||
DGL_NAMESPACE::Widget::KeyboardEvent ev; | |||
ev.mod = mods; | |||
ev.press = press; | |||
ev.key = key; | |||
ev.mod = mods; | |||
return ui->onKeyboard(ev); | |||
} | |||
ev.key = key; | |||
bool handlePluginSpecial(const bool press, const DGL_NAMESPACE::Key key, const uint16_t mods) | |||
{ | |||
DGL_NAMESPACE::Widget::SpecialEvent ev; | |||
ev.press = press; | |||
ev.key = key; | |||
ev.mod = mods; | |||
return ui->onSpecial(ev); | |||
const bool ret = ui->onKeyboard(ev); | |||
DGL_NAMESPACE::Widget::CharacterInputEvent cev; | |||
cev.mod = mods; | |||
cev.character = key; | |||
// if shift modifier is on, convert a-z -> A-Z for character input | |||
if (key >= 'a' && key <= 'z' && (mods & DGL_NAMESPACE::kModifierShift) != 0) | |||
cev.character -= 'a' - 'A'; | |||
ui->onCharacterInput(cev); | |||
return ret; | |||
} | |||
#endif | |||
@@ -287,6 +311,15 @@ public: | |||
ui->uiScaleFactorChanged(scaleFactor); | |||
} | |||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
void notifyFocusChanged(const bool focus) | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |||
ui->uiFocus(focus, DGL_NAMESPACE::kCrossingNormal); | |||
} | |||
#endif | |||
void setSampleRate(const double sampleRate, const bool doCallback = false) | |||
{ | |||
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | |||
@@ -22,7 +22,7 @@ | |||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||
# include "../extra/Sleep.hpp" | |||
#else | |||
# include "../../dgl/Application.hpp" | |||
# include "../../dgl/src/ApplicationPrivateData.hpp" | |||
# include "../../dgl/src/WindowPrivateData.hpp" | |||
# include "../../dgl/src/pugl.hpp" | |||
#endif | |||
@@ -33,7 +33,13 @@ | |||
# define DISTRHO_UI_IS_STANDALONE 0 | |||
#endif | |||
#if defined(DISTRHO_PLUGIN_TARGET_VST2) || defined(DISTRHO_PLUGIN_TARGET_VST3) | |||
#if defined(DISTRHO_PLUGIN_TARGET_VST2) | |||
# undef DISTRHO_UI_USER_RESIZABLE | |||
# define DISTRHO_UI_USER_RESIZABLE 0 | |||
#endif | |||
// TODO figure out how to detect host support | |||
#if defined(DISTRHO_PLUGIN_TARGET_VST3) | |||
# undef DISTRHO_UI_USER_RESIZABLE | |||
# define DISTRHO_UI_USER_RESIZABLE 0 | |||
#endif | |||
@@ -92,6 +98,7 @@ struct PluginApplication | |||
// these are not needed | |||
void idle() {} | |||
void quit() {} | |||
void triggerIdleCallbacks() {} | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) | |||
}; | |||
@@ -113,6 +120,11 @@ public: | |||
setClassName(className); | |||
} | |||
void triggerIdleCallbacks() | |||
{ | |||
pData->triggerIdleCallbacks(); | |||
} | |||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) | |||
}; | |||
#endif | |||
@@ -325,6 +337,15 @@ struct UI::PrivateData { | |||
# if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE) | |||
parameterOffset += 1; | |||
# endif | |||
#endif | |||
#ifdef DISTRHO_PLUGIN_TARGET_VST3 | |||
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
parameterOffset += 130 * 16; // all MIDI CCs plus aftertouch and pitchbend | |||
# endif | |||
# if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
parameterOffset += 1; | |||
# endif | |||
#endif | |||
} | |||
@@ -1,3 +1,13 @@ | |||
/** | |||
* \file include/seq_event.h | |||
* \brief Application interface library for the ALSA driver | |||
* \author Jaroslav Kysela <perex@perex.cz> | |||
* \author Abramo Bagnara <abramo@alsa-project.org> | |||
* \author Takashi Iwai <tiwai@suse.de> | |||
* \date 1998-2001 | |||
* | |||
* Application interface library for the ALSA driver | |||
*/ | |||
/* | |||
* This library is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU Lesser General Public License as | |||
@@ -1,249 +0,0 @@ | |||
// lv2_atom_helpers.h | |||
// | |||
/**************************************************************************** | |||
Copyright (C) 2005-2013, rncbc aka Rui Nuno Capela. All rights reserved. | |||
This program is free software; you can redistribute it and/or | |||
modify it under the terms of the GNU General Public License | |||
as published by the Free Software Foundation; either version 2 | |||
of the License, or (at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU General Public License for more details. | |||
You should have received a copy of the GNU General Public License along | |||
with this program; if not, write to the Free Software Foundation, Inc., | |||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
*****************************************************************************/ | |||
/* Helper functions for LV2 atom:Sequence event buffer. | |||
* | |||
* tentatively adapted from: | |||
* | |||
* - lv2_evbuf.h,c - An abstract/opaque LV2 event buffer implementation. | |||
* | |||
* - event-helpers.h - Helper functions for the LV2 Event extension. | |||
* <http://lv2plug.in/ns/ext/event> | |||
* | |||
* Copyright 2008-2012 David Robillard <http://drobilla.net> | |||
*/ | |||
#ifndef LV2_ATOM_HELPERS_H | |||
#define LV2_ATOM_HELPERS_H | |||
#include <stdint.h> | |||
#include <stdbool.h> | |||
#include <string.h> | |||
#include <stdlib.h> | |||
#include <assert.h> | |||
#include "atom-util.h" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
// An abstract/opaque LV2 atom:Sequence buffer. | |||
// | |||
typedef | |||
struct _LV2_Atom_Buffer | |||
{ | |||
uint32_t capacity; | |||
uint32_t chunk_type; | |||
uint32_t sequence_type; | |||
LV2_Atom_Sequence atoms; | |||
} LV2_Atom_Buffer; | |||
// Clear and initialize an existing LV2 atom:Sequenece buffer. | |||
// | |||
static inline | |||
void lv2_atom_buffer_reset ( LV2_Atom_Buffer *buf, bool input ) | |||
{ | |||
if (input) { | |||
buf->atoms.atom.size = sizeof(LV2_Atom_Sequence_Body); | |||
buf->atoms.atom.type = buf->sequence_type; | |||
} else { | |||
buf->atoms.atom.size = buf->capacity; | |||
buf->atoms.atom.type = buf->chunk_type; | |||
} | |||
} | |||
// Allocate a new, empty LV2 atom:Sequence buffer. | |||
// | |||
static inline | |||
LV2_Atom_Buffer *lv2_atom_buffer_new ( | |||
uint32_t capacity, uint32_t chunk_type, uint32_t sequence_type, bool input ) | |||
{ | |||
LV2_Atom_Buffer *buf = (LV2_Atom_Buffer *) | |||
malloc(sizeof(LV2_Atom_Buffer) + sizeof(LV2_Atom_Sequence) + capacity); | |||
buf->capacity = capacity; | |||
buf->chunk_type = chunk_type; | |||
buf->sequence_type = sequence_type; | |||
lv2_atom_buffer_reset(buf, input); | |||
return buf; | |||
} | |||
// Free an LV2 atom:Sequenece buffer allocated with lv2_atome_buffer_new. | |||
// | |||
static inline | |||
void lv2_atom_buffer_free ( LV2_Atom_Buffer *buf ) | |||
{ | |||
free(buf); | |||
} | |||
// Return the total padded size of events stored in a LV2 atom:Sequence buffer. | |||
// | |||
static inline | |||
uint32_t lv2_atom_buffer_get_size ( LV2_Atom_Buffer *buf ) | |||
{ | |||
if (buf->atoms.atom.type == buf->sequence_type) | |||
return buf->atoms.atom.size - uint32_t(sizeof(LV2_Atom_Sequence_Body)); | |||
else | |||
return 0; | |||
} | |||
// Return the actual LV2 atom:Sequence implementation. | |||
// | |||
static inline | |||
LV2_Atom_Sequence *lv2_atom_buffer_get_sequence ( LV2_Atom_Buffer *buf ) | |||
{ | |||
return &buf->atoms; | |||
} | |||
// An iterator over an atom:Sequence buffer. | |||
// | |||
typedef | |||
struct _LV2_Atom_Buffer_Iterator | |||
{ | |||
LV2_Atom_Buffer *buf; | |||
uint32_t offset; | |||
} LV2_Atom_Buffer_Iterator; | |||
// Reset an iterator to point to the start of an LV2 atom:Sequence buffer. | |||
// | |||
static inline | |||
bool lv2_atom_buffer_begin ( | |||
LV2_Atom_Buffer_Iterator *iter, LV2_Atom_Buffer *buf ) | |||
{ | |||
iter->buf = buf; | |||
iter->offset = 0; | |||
return (buf->atoms.atom.size > 0); | |||
} | |||
// Reset an iterator to point to the end of an LV2 atom:Sequence buffer. | |||
// | |||
static inline | |||
bool lv2_atom_buffer_end ( | |||
LV2_Atom_Buffer_Iterator *iter, LV2_Atom_Buffer *buf ) | |||
{ | |||
iter->buf = buf; | |||
iter->offset = lv2_atom_pad_size(lv2_atom_buffer_get_size(buf)); | |||
return (iter->offset < buf->capacity - sizeof(LV2_Atom_Event)); | |||
} | |||
// Check if a LV2 atom:Sequenece buffer iterator is valid. | |||
// | |||
static inline | |||
bool lv2_atom_buffer_is_valid ( LV2_Atom_Buffer_Iterator *iter ) | |||
{ | |||
return iter->offset < lv2_atom_buffer_get_size(iter->buf); | |||
} | |||
// Advance a LV2 atom:Sequenece buffer iterator forward one event. | |||
// | |||
static inline | |||
bool lv2_atom_buffer_increment ( LV2_Atom_Buffer_Iterator *iter ) | |||
{ | |||
if (!lv2_atom_buffer_is_valid(iter)) | |||
return false; | |||
LV2_Atom_Buffer *buf = iter->buf; | |||
LV2_Atom_Sequence *atoms = &buf->atoms; | |||
uint32_t size = ((LV2_Atom_Event *) ((char *) | |||
LV2_ATOM_CONTENTS(LV2_Atom_Sequence, atoms) + iter->offset))->body.size; | |||
iter->offset += lv2_atom_pad_size(uint32_t(sizeof(LV2_Atom_Event)) + size); | |||
return true; | |||
} | |||
// Get the event currently pointed at a LV2 atom:Sequence buffer iterator. | |||
// | |||
static inline | |||
LV2_Atom_Event *lv2_atom_buffer_get ( | |||
LV2_Atom_Buffer_Iterator *iter, uint8_t **data ) | |||
{ | |||
if (!lv2_atom_buffer_is_valid(iter)) | |||
return NULL; | |||
LV2_Atom_Buffer *buf = iter->buf; | |||
LV2_Atom_Sequence *atoms = &buf->atoms; | |||
LV2_Atom_Event *ev = (LV2_Atom_Event *) ((char *) | |||
LV2_ATOM_CONTENTS(LV2_Atom_Sequence, atoms) + iter->offset); | |||
*data = (uint8_t *) LV2_ATOM_BODY(&ev->body); | |||
return ev; | |||
} | |||
// Write an event at a LV2 atom:Sequence buffer iterator. | |||
static inline | |||
bool lv2_atom_buffer_write ( | |||
LV2_Atom_Buffer_Iterator *iter, | |||
uint32_t frames, | |||
uint32_t /*subframes*/, | |||
uint32_t type, | |||
uint32_t size, | |||
const uint8_t *data ) | |||
{ | |||
LV2_Atom_Buffer *buf = iter->buf; | |||
LV2_Atom_Sequence *atoms = &buf->atoms; | |||
if (buf->capacity - sizeof(LV2_Atom) - atoms->atom.size | |||
< sizeof(LV2_Atom_Event) + size) | |||
return false; | |||
LV2_Atom_Event *ev = (LV2_Atom_Event*) ((char *) | |||
LV2_ATOM_CONTENTS(LV2_Atom_Sequence, atoms) + iter->offset); | |||
ev->time.frames = frames; | |||
ev->body.type = type; | |||
ev->body.size = size; | |||
memcpy(LV2_ATOM_BODY(&ev->body), data, size); | |||
size = lv2_atom_pad_size(uint32_t(sizeof(LV2_Atom_Event)) + size); | |||
atoms->atom.size += size; | |||
iter->offset += size; | |||
return true; | |||
} | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif // LV2_ATOM_HELPERS_H | |||
// end of lv2_atom_helpers.h |
@@ -1,98 +0,0 @@ | |||
/**************************************************************************** | |||
lv2-midifunctions.h - support file for using MIDI in LV2 plugins | |||
Copyright (C) 2006 Lars Luthman <lars.luthman@gmail.com> | |||
This program is free software; you can redistribute it and/or modify | |||
it under the terms of the GNU Lesser General Public License as published by | |||
the Free Software Foundation; either version 2 of the License, or | |||
(at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 01222-1307 USA | |||
****************************************************************************/ | |||
#ifndef LV2_MIDIFUNCTIONS | |||
#define LV2_MIDIFUNCTIONS | |||
#include "lv2-miditype.h" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
typedef struct { | |||
LV2_MIDI* midi; | |||
uint32_t frame_count; | |||
uint32_t position; | |||
} LV2_MIDIState; | |||
inline double lv2midi_get_event(LV2_MIDIState* state, | |||
double* timestamp, | |||
uint32_t* size, | |||
unsigned char** data) { | |||
if (state->position >= state->midi->size) { | |||
state->position = state->midi->size; | |||
*timestamp = state->frame_count; | |||
*size = 0; | |||
*data = NULL; | |||
return *timestamp; | |||
} | |||
*timestamp = *(double*)(state->midi->data + state->position); | |||
*size = (uint32_t)*(size_t*)(state->midi->data + state->position + sizeof(double)); | |||
*data = state->midi->data + state->position + | |||
sizeof(double) + sizeof(size_t); | |||
return *timestamp; | |||
} | |||
inline double lv2midi_step(LV2_MIDIState* state) { | |||
if (state->position >= state->midi->size) { | |||
state->position = state->midi->size; | |||
return state->frame_count; | |||
} | |||
state->position += (uint32_t)sizeof(double); | |||
size_t size = *(size_t*)(state->midi->data + state->position); | |||
state->position += (uint32_t)sizeof(size_t); | |||
state->position += (uint32_t)size; | |||
return *(double*)(state->midi->data + state->position); | |||
} | |||
inline void lv2midi_put_event(LV2_MIDIState* state, | |||
double timestamp, | |||
uint32_t size, | |||
const unsigned char* data) { | |||
if (state->midi->size + sizeof(double) + sizeof(size_t) + size < state->midi->capacity) | |||
{ | |||
*((double*)(state->midi->data + state->midi->size)) = timestamp; | |||
state->midi->size += (uint32_t)sizeof(double); | |||
*((size_t*)(state->midi->data + state->midi->size)) = size; | |||
state->midi->size += (uint32_t)sizeof(size_t); | |||
memcpy(state->midi->data + state->midi->size, data, size); | |||
state->midi->size += size; | |||
state->midi->event_count++; | |||
} | |||
} | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif | |||
@@ -1,175 +0,0 @@ | |||
/**************************************************************************** | |||
lv2-miditype.h - header file for using MIDI in LV2 plugins | |||
Copyright (C) 2006 Lars Luthman <lars.luthman@gmail.com> | |||
This program is free software; you can redistribute it and/or modify | |||
it under the terms of the GNU Lesser General Public License as published by | |||
the Free Software Foundation; either version 2 of the License, or | |||
(at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 01222-1307 USA | |||
****************************************************************************/ | |||
#ifndef LV2_MIDITYPE_H | |||
#define LV2_MIDITYPE_H | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** This data structure is used to contain the MIDI events for one run() | |||
cycle. The port buffer for a LV2 port that has the datatype | |||
<http://ll-plugins.nongnu.org/lv2/ext/miditype> should be a pointer | |||
to an instance of this struct. | |||
To store two Note On events on MIDI channel 0 in a buffer, with timestamps | |||
12 and 35.5, you could use something like this code (assuming that | |||
midi_data is a variable of type LV2_MIDI): | |||
@code | |||
size_t buffer_offset = 0; | |||
*(double*)(midi_data->data + buffer_offset) = 12; | |||
buffer_offset += sizeof(double); | |||
*(size_t*)(midi_data->data + buffer_offset) = 3; | |||
buffer_offset += sizeof(size_t); | |||
midi_data->data[buffer_offset++] = 0x90; | |||
midi_data->data[buffer_offset++] = 0x48; | |||
midi_data->data[buffer_offset++] = 0x64; | |||
++midi_data->event_count; | |||
*(double*)(midi_data->data + buffer_offset) = 35.5; | |||
buffer_offset += sizeof(double); | |||
*(size_t*)(midi_data->data + buffer_offset) = 3; | |||
buffer_offset += sizeof(size_t); | |||
midi_data->data[buffer_offset++] = 0x90; | |||
midi_data->data[buffer_offset++] = 0x55; | |||
midi_data->data[buffer_offset++] = 0x64; | |||
++midi_data->event_count; | |||
midi_data->size = buffer_offset; | |||
@endcode | |||
This would be done by the host in the case of an input port, and by the | |||
plugin in the case of an output port. Whoever is writing events to the | |||
buffer must also take care not to exceed the capacity of the data buffer. | |||
To read events from a buffer, you could do something like this: | |||
@code | |||
size_t buffer_offset = 0; | |||
uint32_t i; | |||
for (i = 0; i < midi_data->event_count; ++i) { | |||
double timestamp = *(double*)(midi_data->data + buffer_offset); | |||
buffer_offset += sizeof(double); | |||
size_t size = *(size_t*)(midi_data->data + buffer_offset); | |||
buffer_offset += sizeof(size_t); | |||
do_something_with_event(timestamp, size, | |||
midi_data->data + buffer_offset); | |||
buffer_offset += size; | |||
} | |||
@endcode | |||
*/ | |||
typedef struct { | |||
/** The number of MIDI events in the data buffer. | |||
INPUT PORTS: It's the host's responsibility to set this field to the | |||
number of MIDI events contained in the data buffer before calling the | |||
plugin's run() function. The plugin may not change this field. | |||
OUTPUT PORTS: It's the plugin's responsibility to set this field to the | |||
number of MIDI events it has stored in the data buffer before returning | |||
from the run() function. Any initial value should be ignored by the | |||
plugin. | |||
*/ | |||
uint32_t event_count; | |||
/** The size of the data buffer in bytes. It is set by the host and may not | |||
be changed by the plugin. The host is allowed to change this between | |||
run() calls. | |||
*/ | |||
uint32_t capacity; | |||
/** The size of the initial part of the data buffer that actually contains | |||
data. | |||
INPUT PORTS: It's the host's responsibility to set this field to the | |||
number of bytes used by all MIDI events it has written to the buffer | |||
(including timestamps and size fields) before calling the plugin's | |||
run() function. The plugin may not change this field. | |||
OUTPUT PORTS: It's the plugin's responsibility to set this field to | |||
the number of bytes used by all MIDI events it has written to the | |||
buffer (including timestamps and size fields) before returning from | |||
the run() function. Any initial value should be ignored by the plugin. | |||
*/ | |||
uint32_t size; | |||
/** The data buffer that is used to store MIDI events. The events are packed | |||
after each other, and the format of each event is as follows: | |||
First there is a timestamp, which should have the type "double", | |||
i.e. have the same bit size as a double and the same bit layout as a | |||
double (whatever that is on the current platform). This timestamp gives | |||
the offset from the beginning of the current cycle, in frames, that | |||
the MIDI event occurs on. It must be strictly smaller than the 'nframes' | |||
parameter to the current run() call. The MIDI events in the buffer must | |||
be ordered by their timestamp, e.g. an event with a timestamp of 123.23 | |||
must be stored after an event with a timestamp of 65.0. | |||
The second part of the event is a size field, which should have the type | |||
"size_t" (as defined in the standard C header stddef.h). It should | |||
contain the size of the MIDI data for this event, i.e. the number of | |||
bytes used to store the actual MIDI event. The bytes used by the | |||
timestamp and the size field should not be counted. | |||
The third part of the event is the actual MIDI data. There are some | |||
requirements that must be followed: | |||
* Running status is not allowed. Every event must have its own status | |||
byte. | |||
* Note On events with velocity 0 are not allowed. These events are | |||
equivalent to Note Off in standard MIDI streams, but in order to make | |||
plugins and hosts easier to write, as well as more efficient, only | |||
proper Note Off events are allowed as Note Off. | |||
* "Realtime events" (status bytes 0xF8 to 0xFF) are allowed, but may not | |||
occur inside other events like they are allowed to in hardware MIDI | |||
streams. | |||
* All events must be fully contained in a single data buffer, i.e. events | |||
may not "wrap around" by storing the first few bytes in one buffer and | |||
then wait for the next run() call to store the rest of the event. If | |||
there isn't enough space in the current data buffer to store an event, | |||
the event will either have to wait until next run() call, be ignored, | |||
or compensated for in some more clever way. | |||
* All events must be valid MIDI events. This means for example that | |||
only the first byte in each event (the status byte) may have the eighth | |||
bit set, that Note On and Note Off events are always 3 bytes long etc. | |||
The MIDI writer (host or plugin) is responsible for writing valid MIDI | |||
events to the buffer, and the MIDI reader (plugin or host) can assume | |||
that all events are valid. | |||
On a platform where double is 8 bytes and size_t is 4 bytes, the data | |||
buffer layout for a 3-byte event followed by a 4-byte event may look | |||
something like this: | |||
_______________________________________________________________ | |||
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ... | |||
|TIMESTAMP 1 |SIZE 1 |DATA |TIMESTAMP 2 |SIZE 2 |DATA | ... | |||
*/ | |||
unsigned char* data; | |||
} LV2_MIDI; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif |
@@ -1,9 +1,9 @@ | |||
This folder contains a pure C interface to Steinberg VST3 SDK, codenamed "travesty". | |||
This folder contains a pure C VST3-compatible interface, codenamed "travesty". | |||
Name is a play on words from morphing "vestige" (the good old free VST2 reverse-engineered header file) and "three". | |||
The main target is to be able to create VST3-compatible plugins without a bloated SDK. | |||
Everything that is required for plugins fits in a few small header files. | |||
Also, being able to build VST3-compatible plugins in pure C code, something not possible with the original SDK. | |||
Everything that is required for plugins fits in a few small header files as presented here. | |||
Also being able to build VST3-compatible plugins in pure C code, something not possible with the original SDK. | |||
Please note this project is still a work in progress. | |||
Use at your own risk, and please report any issues to https://github.com/DISTRHO/DPF/. |
@@ -1,5 +1,5 @@ | |||
/* | |||
* travesty, pure C interface to steinberg VST3 SDK | |||
* travesty, pure C VST3-compatible interface | |||
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
@@ -14,10 +14,25 @@ | |||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#if defined(__APPLE__) | |||
# if defined(__clang__) | |||
# pragma clang diagnostic push | |||
# pragma clang diagnostic ignored "-Wpragma-pack" | |||
# elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 460 | |||
# pragma GCC diagnostic push | |||
# pragma GCC diagnostic ignored "-Wunknown-warning-option" | |||
# pragma GCC diagnostic ignored "-Wpragma-pack" | |||
# endif | |||
#endif | |||
#if defined(__APPLE__) || defined(_WIN32) | |||
# pragma pack(pop) | |||
#endif | |||
#if defined(__APPLE__) | |||
# pragma GCC diagnostic pop | |||
# if defined(__clang__) | |||
# pragma clang diagnostic pop | |||
# elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 460 | |||
# pragma GCC diagnostic pop | |||
# endif | |||
#endif |
@@ -1,5 +1,5 @@ | |||
/* | |||
* travesty, pure C interface to steinberg VST3 SDK | |||
* travesty, pure C VST3-compatible interface | |||
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
@@ -16,9 +16,16 @@ | |||
#if defined(__APPLE__) | |||
# pragma GCC diagnostic push | |||
# pragma GCC diagnostic ignored "-Wunknown-warning-option" | |||
# pragma GCC diagnostic ignored "-Wpragma-pack" | |||
# if defined(__clang__) | |||
# pragma clang diagnostic push | |||
# pragma clang diagnostic ignored "-Wunknown-warning-option" | |||
# pragma clang diagnostic ignored "-Wpragma-pack" | |||
# elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 460 | |||
# pragma GCC diagnostic push | |||
# pragma GCC diagnostic ignored "-Wunknown-warning-option" | |||
# pragma GCC diagnostic ignored "-Wpragma-pack" | |||
# endif | |||
# if defined(__LP64__) || defined(_LP64) | |||
# pragma pack(push, 16) | |||
# else | |||
@@ -1,5 +1,5 @@ | |||
/* | |||
* travesty, pure C interface to steinberg VST3 SDK | |||
* travesty, pure C VST3-compatible interface | |||
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
@@ -28,8 +28,9 @@ | |||
typedef uint64_t v3_speaker_arrangement; | |||
enum { | |||
V3_SPEAKER_L = 1, | |||
V3_SPEAKER_R = 1 << 1 | |||
V3_SPEAKER_L = 1 << 0, | |||
V3_SPEAKER_R = 1 << 1, | |||
V3_SPEAKER_M = 1 << 19 | |||
}; | |||
/** | |||
@@ -42,14 +43,19 @@ enum v3_process_mode { | |||
V3_OFFLINE | |||
}; | |||
inline static const char * | |||
v3_process_mode_str(int32_t d) | |||
static inline | |||
const char* v3_process_mode_str(int32_t d) | |||
{ | |||
switch (d) { | |||
case V3_REALTIME: return "V3_REALTIME"; | |||
case V3_PREFETCH: return "V3_PREFETCH"; | |||
case V3_OFFLINE: return "V3_OFFLINE"; | |||
default: return "[unknown]"; | |||
switch (d) | |||
{ | |||
case V3_REALTIME: | |||
return "V3_REALTIME"; | |||
case V3_PREFETCH: | |||
return "V3_PREFETCH"; | |||
case V3_OFFLINE: | |||
return "V3_OFFLINE"; | |||
default: | |||
return "[unknown]"; | |||
} | |||
} | |||
@@ -58,13 +64,17 @@ enum { | |||
V3_SAMPLE_64 | |||
}; | |||
inline static const char * | |||
v3_sample_size_str(int32_t d) | |||
static inline | |||
const char* v3_sample_size_str(int32_t d) | |||
{ | |||
switch (d) { | |||
case V3_SAMPLE_32: return "V3_SAMPLE_32"; | |||
case V3_SAMPLE_64: return "V3_SAMPLE_64"; | |||
default: return "[unknown]"; | |||
switch (d) | |||
{ | |||
case V3_SAMPLE_32: | |||
return "V3_SAMPLE_32"; | |||
case V3_SAMPLE_64: | |||
return "V3_SAMPLE_64"; | |||
default: | |||
return "[unknown]"; | |||
} | |||
} | |||
@@ -82,31 +92,24 @@ struct v3_process_setup { | |||
struct v3_param_value_queue { | |||
struct v3_funknown; | |||
V3_API v3_param_id (*get_param_id)(void *self); | |||
V3_API int32_t (*get_point_count)(void *self); | |||
V3_API v3_result (*get_point) | |||
(void *self, int32_t idx, int32_t *sample_offset, double *value); | |||
V3_API v3_result (*add_point) | |||
(void *self, int32_t sample_offset, double value, int32_t *idx); | |||
v3_param_id (V3_API* get_param_id)(void* self); | |||
int32_t (V3_API* get_point_count)(void* self); | |||
v3_result (V3_API* get_point)(void* self, int32_t idx, int32_t* sample_offset, double* value); | |||
v3_result (V3_API* add_point)(void* self, int32_t sample_offset, double value, int32_t* idx); | |||
}; | |||
static const v3_tuid v3_param_value_queue_iid = | |||
static constexpr const v3_tuid v3_param_value_queue_iid = | |||
V3_ID(0x01263A18, 0xED074F6F, 0x98C9D356, 0x4686F9BA); | |||
struct v3_param_changes { | |||
struct v3_funknown; | |||
V3_API int32_t (*get_param_count)(void *self); | |||
V3_API struct v3_param_value_queue **(*get_param_data) | |||
(void *self, int32_t idx); | |||
V3_API struct v3_param_value_queue **(*add_param_data) | |||
(void *self, v3_param_id *id, int32_t *index); | |||
int32_t (V3_API* get_param_count)(void* self); | |||
struct v3_param_value_queue** (V3_API* get_param_data)(void* self, int32_t idx); | |||
struct v3_param_value_queue** (V3_API* add_param_data)(void* self, v3_param_id* id, int32_t* index); | |||
}; | |||
static const v3_tuid v3_param_changes_iid = | |||
static constexpr const v3_tuid v3_param_changes_iid = | |||
V3_ID(0xA4779663, 0x0BB64A56, 0xB44384A8, 0x466FEB9D); | |||
/** | |||
@@ -121,55 +124,41 @@ struct v3_frame_rate { | |||
struct v3_chord { | |||
uint8_t key_note; | |||
uint8_t root_note; | |||
int16_t chord_mask; | |||
}; | |||
enum { | |||
V3_PROCESS_CTX_PLAYING = 1 << 1, | |||
V3_PROCESS_CTX_CYCLE_ACTIVE = 1 << 2, | |||
V3_PROCESS_CTX_RECORDING = 1 << 3, | |||
V3_PROCESS_CTX_PLAYING = 1 << 1, | |||
V3_PROCESS_CTX_CYCLE_ACTIVE = 1 << 2, | |||
V3_PROCESS_CTX_RECORDING = 1 << 3, | |||
V3_PROCESS_CTX_SYSTEM_TIME_VALID = 1 << 8, | |||
V3_PROCESS_CTX_CONT_TIME_VALID = 1 << 17, | |||
V3_PROCESS_CTX_PROJECT_TIME_VALID = 1 << 9, | |||
V3_PROCESS_CTX_TEMPO_VALID = 1 << 10, | |||
V3_PROCESS_CTX_BAR_POSITION_VALID = 1 << 11, | |||
V3_PROCESS_CTX_CYCLE_VALID = 1 << 12, | |||
V3_PROCESS_CTX_TEMPO_VALID = 1 << 10, | |||
V3_PROCESS_CTX_TIME_SIG_VALID = 1 << 13, | |||
V3_PROCESS_CTX_CHORD_VALID = 1 << 18, | |||
V3_PROCESS_CTX_SMPTE_VALID = 1 << 14, | |||
V3_PROCESS_CTX_NEXT_CLOCK_VALID = 1 << 15 | |||
V3_PROCESS_CTX_NEXT_CLOCK_VALID = 1 << 15, | |||
V3_PROCESS_CTX_CONT_TIME_VALID = 1 << 17, | |||
V3_PROCESS_CTX_CHORD_VALID = 1 << 18 | |||
}; | |||
struct v3_process_context { | |||
uint32_t state; | |||
double sample_rate; | |||
int64_t project_time_in_samples; // with loop | |||
int64_t system_time_ns; | |||
int64_t continuous_time_in_samples; // without loop? unclear | |||
int64_t continuous_time_in_samples; // without loop | |||
double project_time_quarters; | |||
double bar_position_quarters; | |||
double cycle_start_quarters; | |||
double cycle_end_quarters; | |||
double bpm; | |||
int32_t time_sig_numerator; | |||
int32_t time_sig_denom; | |||
struct v3_chord chord; | |||
int32_t smpte_offset_subframes; | |||
struct v3_frame_rate frame_rate; | |||
int32_t samples_to_next_clock; | |||
}; | |||
@@ -194,10 +183,10 @@ enum { | |||
struct v3_process_context_requirements { | |||
struct v3_funknown; | |||
V3_API uint32_t (*get_process_context_requirements)(void *self); | |||
uint32_t (V3_API* get_process_context_requirements)(void* self); | |||
}; | |||
static const v3_tuid v3_process_context_requirements_iid = | |||
static constexpr const v3_tuid v3_process_context_requirements_iid = | |||
V3_ID(0x2A654303, 0xEF764E3D, 0x95B5FE83, 0x730EF6D0); | |||
/** | |||
@@ -207,32 +196,25 @@ static const v3_tuid v3_process_context_requirements_iid = | |||
struct v3_audio_bus_buffers { | |||
int32_t num_channels; | |||
uint64_t channel_silence_bitset; | |||
union { | |||
float **channel_buffers_32; | |||
double **channel_buffers_64; | |||
float** channel_buffers_32; | |||
double** channel_buffers_64; | |||
}; | |||
}; | |||
struct v3_process_data { | |||
int32_t process_mode; | |||
int32_t symbolic_sample_size; | |||
int32_t nframes; | |||
int32_t num_input_buses; | |||
int32_t num_output_buses; | |||
struct v3_audio_bus_buffers *inputs; | |||
struct v3_audio_bus_buffers *outputs; | |||
struct v3_param_changes **input_params; | |||
struct v3_param_changes **output_params; | |||
struct v3_event_list **input_events; | |||
struct v3_event_list **output_events; | |||
struct v3_process_context *ctx; | |||
struct v3_audio_bus_buffers* inputs; | |||
struct v3_audio_bus_buffers* outputs; | |||
struct v3_param_changes** input_params; | |||
struct v3_param_changes** output_params; | |||
struct v3_event_list** input_events; | |||
struct v3_event_list** output_events; | |||
struct v3_process_context* ctx; | |||
}; | |||
/** | |||
@@ -242,29 +224,42 @@ struct v3_process_data { | |||
struct v3_audio_processor { | |||
struct v3_funknown; | |||
V3_API v3_result (*set_bus_arrangements) | |||
(void *self, v3_speaker_arrangement *inputs, int32_t num_inputs, | |||
v3_speaker_arrangement *outputs, int32_t num_outputs); | |||
V3_API v3_result (*get_bus_arrangement) | |||
(void *self, int32_t bus_direction, int32_t idx, v3_speaker_arrangement *); | |||
v3_result (V3_API* set_bus_arrangements)(void* self, v3_speaker_arrangement* inputs, int32_t num_inputs, | |||
v3_speaker_arrangement* outputs, int32_t num_outputs); | |||
v3_result (V3_API* get_bus_arrangement)(void* self, int32_t bus_direction, int32_t idx, v3_speaker_arrangement*); | |||
v3_result (V3_API* can_process_sample_size)(void* self, int32_t symbolic_sample_size); | |||
uint32_t (V3_API* get_latency_samples)(void* self); | |||
v3_result (V3_API* setup_processing)(void* self, struct v3_process_setup* setup); | |||
v3_result (V3_API* set_processing)(void* self, v3_bool state); | |||
v3_result (V3_API* process)(void* self, struct v3_process_data* data); | |||
uint32_t (V3_API* get_tail_samples)(void* self); | |||
}; | |||
V3_API v3_result (*can_process_sample_size) | |||
(void *self, int32_t symbolic_sample_size); | |||
static constexpr const v3_tuid v3_audio_processor_iid = | |||
V3_ID(0x42043F99, 0xB7DA453C, 0xA569E79D, 0x9AAEC33D); | |||
V3_API uint32_t (*get_latency_samples)(void *self); | |||
#ifdef __cplusplus | |||
V3_API v3_result (*setup_processing) | |||
(void *self, struct v3_process_setup *); | |||
V3_API v3_result (*set_processing) | |||
(void *self, v3_bool state); | |||
/** | |||
* C++ variants | |||
*/ | |||
V3_API v3_result (*process) | |||
(void *self, struct v3_process_data *); | |||
struct v3_param_value_queue_cpp : v3_funknown { | |||
v3_param_value_queue queue; | |||
}; | |||
V3_API uint32_t (*get_tail_samples)(void *self); | |||
struct v3_param_changes_cpp : v3_funknown { | |||
v3_param_changes changes; | |||
}; | |||
static const v3_tuid v3_audio_processor_iid = | |||
V3_ID(0x42043F99, 0xB7DA453C, 0xA569E79D, 0x9AAEC33D); | |||
struct v3_process_context_requirements_cpp : v3_funknown { | |||
v3_process_context_requirements req; | |||
}; | |||
struct v3_audio_processor_cpp : v3_funknown { | |||
v3_audio_processor proc; | |||
}; | |||
#endif | |||
#include "align_pop.h" |
@@ -1,5 +1,5 @@ | |||
/* | |||
* travesty, pure C interface to steinberg VST3 SDK | |||
* travesty, pure C VST3-compatible interface | |||
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
@@ -20,6 +20,39 @@ | |||
#include <stdint.h> | |||
#include <string.h> | |||
/** | |||
* deal with C vs C++ differences | |||
*/ | |||
#ifdef __cplusplus | |||
/** | |||
* cast object into its proper C++ type. | |||
* this is needed because `struct v3_funknown;` on a C++ class does not inherit `v3_funknown`'s fields. | |||
* we can use this as a little helper for keeping both C and C++ compatiblity. | |||
* specialized templated calls are defined where required | |||
* (that is, object inherits from something other than `v3_funknown`) | |||
* | |||
* example usage: `v3_cpp_obj(obj)->method(obj, args...);` | |||
*/ | |||
template<class T> static inline | |||
constexpr T* v3_cpp_obj(T** obj) | |||
{ | |||
/** | |||
* this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default, | |||
* but we need everything to be `static_cast` for it to be `constexpr` compatible. | |||
*/ | |||
return static_cast<T*>(static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*3)); | |||
} | |||
#else | |||
# ifndef constexpr | |||
# define constexpr | |||
# endif | |||
#endif | |||
/** | |||
* various types | |||
*/ | |||
@@ -31,15 +64,14 @@ typedef uint8_t v3_bool; | |||
typedef uint32_t v3_param_id; | |||
/** | |||
* low-level ABI nonsense | |||
*/ | |||
typedef uint8_t v3_tuid[16]; | |||
inline static bool | |||
v3_tuid_match(const v3_tuid a, const v3_tuid b) | |||
static inline | |||
bool v3_tuid_match(const v3_tuid a, const v3_tuid b) | |||
{ | |||
return memcmp(a, b, sizeof(v3_tuid)) == 0; | |||
} | |||
@@ -54,88 +86,90 @@ v3_tuid_match(const v3_tuid a, const v3_tuid b) | |||
#if V3_COM_COMPAT | |||
enum { | |||
V3_NO_INTERFACE = 0x80004002L, | |||
V3_OK = 0, | |||
V3_TRUE = 0, | |||
V3_FALSE = 1, | |||
V3_INVALID_ARG = 0x80070057L, | |||
V3_NOT_IMPLEMENTED = 0x80004001L, | |||
V3_INTERNAL_ERR = 0x80004005L, | |||
V3_NOT_INITIALISED = 0x8000FFFFL, | |||
V3_NOMEM = 0x8007000EL | |||
V3_NO_INTERFACE = 0x80004002L, | |||
V3_OK = 0, | |||
V3_TRUE = 0, | |||
V3_FALSE = 1, | |||
V3_INVALID_ARG = 0x80070057L, | |||
V3_NOT_IMPLEMENTED = 0x80004001L, | |||
V3_INTERNAL_ERR = 0x80004005L, | |||
V3_NOT_INITIALIZED = 0x8000FFFFL, | |||
V3_NOMEM = 0x8007000EL | |||
}; | |||
# define V3_ID(a, b, c, d) { \ | |||
((a) & 0x000000FF), \ | |||
((a) & 0x0000FF00) >> 8, \ | |||
((a) & 0x00FF0000) >> 16, \ | |||
((a) & 0xFF000000) >> 24, \ | |||
\ | |||
((b) & 0x00FF0000) >> 16, \ | |||
((b) & 0xFF000000) >> 24, \ | |||
((b) & 0x000000FF), \ | |||
((b) & 0x0000FF00) >> 8, \ | |||
\ | |||
((c) & 0xFF000000) >> 24, \ | |||
((c) & 0x00FF0000) >> 16, \ | |||
((c) & 0x0000FF00) >> 8, \ | |||
((c) & 0x000000FF), \ | |||
\ | |||
((d) & 0xFF000000) >> 24, \ | |||
((d) & 0x00FF0000) >> 16, \ | |||
((d) & 0x0000FF00) >> 8, \ | |||
((d) & 0x000000FF), \ | |||
# define V3_ID(a, b, c, d) { \ | |||
((a) & 0x000000FF), \ | |||
((a) & 0x0000FF00) >> 8, \ | |||
((a) & 0x00FF0000) >> 16, \ | |||
((a) & 0xFF000000) >> 24, \ | |||
\ | |||
((b) & 0x00FF0000) >> 16, \ | |||
((b) & 0xFF000000) >> 24, \ | |||
((b) & 0x000000FF), \ | |||
((b) & 0x0000FF00) >> 8, \ | |||
\ | |||
((c) & 0xFF000000) >> 24, \ | |||
((c) & 0x00FF0000) >> 16, \ | |||
((c) & 0x0000FF00) >> 8, \ | |||
((c) & 0x000000FF), \ | |||
\ | |||
((d) & 0xFF000000) >> 24, \ | |||
((d) & 0x00FF0000) >> 16, \ | |||
((d) & 0x0000FF00) >> 8, \ | |||
((d) & 0x000000FF), \ | |||
} | |||
#else // V3_COM_COMPAT | |||
enum { | |||
V3_NO_INTERFACE = -1, | |||
V3_NO_INTERFACE = -1, | |||
V3_OK, | |||
V3_TRUE = V3_OK, | |||
V3_FALSE, | |||
V3_INVALID_ARG, | |||
V3_NOT_IMPLEMENTED, | |||
V3_INTERNAL_ERR, | |||
V3_NOT_INITIALISED, | |||
V3_NOT_INITIALIZED, | |||
V3_NOMEM | |||
}; | |||
# define V3_ID(a, b, c, d) { \ | |||
((a) & 0xFF000000) >> 24, \ | |||
((a) & 0x00FF0000) >> 16, \ | |||
((a) & 0x0000FF00) >> 8, \ | |||
((a) & 0x000000FF), \ | |||
\ | |||
((b) & 0xFF000000) >> 24, \ | |||
((b) & 0x00FF0000) >> 16, \ | |||
((b) & 0x0000FF00) >> 8, \ | |||
((b) & 0x000000FF), \ | |||
\ | |||
((c) & 0xFF000000) >> 24, \ | |||
((c) & 0x00FF0000) >> 16, \ | |||
((c) & 0x0000FF00) >> 8, \ | |||
((c) & 0x000000FF), \ | |||
\ | |||
((d) & 0xFF000000) >> 24, \ | |||
((d) & 0x00FF0000) >> 16, \ | |||
((d) & 0x0000FF00) >> 8, \ | |||
((d) & 0x000000FF), \ | |||
# define V3_ID(a, b, c, d) { \ | |||
((a) & 0xFF000000) >> 24, \ | |||
((a) & 0x00FF0000) >> 16, \ | |||
((a) & 0x0000FF00) >> 8, \ | |||
((a) & 0x000000FF), \ | |||
\ | |||
((b) & 0xFF000000) >> 24, \ | |||
((b) & 0x00FF0000) >> 16, \ | |||
((b) & 0x0000FF00) >> 8, \ | |||
((b) & 0x000000FF), \ | |||
\ | |||
((c) & 0xFF000000) >> 24, \ | |||
((c) & 0x00FF0000) >> 16, \ | |||
((c) & 0x0000FF00) >> 8, \ | |||
((c) & 0x000000FF), \ | |||
\ | |||
((d) & 0xFF000000) >> 24, \ | |||
((d) & 0x00FF0000) >> 16, \ | |||
((d) & 0x0000FF00) >> 8, \ | |||
((d) & 0x000000FF), \ | |||
} | |||
#endif // V3_COM_COMPAT | |||
#define V3_ID_COPY(iid) \ | |||
{ iid[0], iid[1], iid[ 2], iid[ 3], iid[ 4], iid[ 5], iid[ 6], iid[ 7], \ | |||
iid[8], iid[9], iid[10], iid[11], iid[12], iid[13], iid[14], iid[15] } | |||
/** | |||
* funknown | |||
*/ | |||
struct v3_funknown { | |||
V3_API v3_result (*query_interface) | |||
(void *self, const v3_tuid iid, void **obj); | |||
V3_API uint32_t (*ref)(void *self); | |||
V3_API uint32_t (*unref)(void *self); | |||
v3_result (V3_API* query_interface)(void* self, const v3_tuid iid, void** obj); | |||
uint32_t (V3_API* ref)(void* self); | |||
uint32_t (V3_API* unref)(void* self); | |||
}; | |||
static const v3_tuid v3_funknown_iid = | |||
static constexpr const v3_tuid v3_funknown_iid = | |||
V3_ID(0x00000000, 0x00000000, 0xC0000000, 0x00000046); | |||
/** | |||
@@ -145,10 +179,35 @@ static const v3_tuid v3_funknown_iid = | |||
struct v3_plugin_base { | |||
struct v3_funknown; | |||
V3_API v3_result (*initialise) | |||
(void *self, struct v3_funknown *context); | |||
V3_API v3_result (*terminate)(void *self); | |||
v3_result (V3_API* initialize)(void* self, struct v3_funknown** context); | |||
v3_result (V3_API* terminate)(void* self); | |||
}; | |||
static const v3_tuid v3_plugin_base_iid = | |||
static constexpr const v3_tuid v3_plugin_base_iid = | |||
V3_ID(0x22888DDB, 0x156E45AE, 0x8358B348, 0x08190625); | |||
#ifdef __cplusplus | |||
/** | |||
* helper C++ functions to manually call v3_funknown methods on an object. | |||
*/ | |||
template<class T, class M> static inline | |||
v3_result v3_cpp_obj_query_interface(T** obj, const v3_tuid iid, M*** obj2) | |||
{ | |||
return static_cast<v3_funknown*>(static_cast<void*>(*obj))->query_interface(obj, iid, (void**)obj2); | |||
} | |||
template<class T> static inline | |||
uint32_t v3_cpp_obj_ref(T** obj) | |||
{ | |||
return static_cast<v3_funknown*>(static_cast<void*>(*obj))->ref(obj); | |||
} | |||
template<class T> static inline | |||
uint32_t v3_cpp_obj_unref(T** obj) | |||
{ | |||
return static_cast<v3_funknown*>(static_cast<void*>(*obj))->unref(obj); | |||
} | |||
#endif |
@@ -1,5 +1,5 @@ | |||
/* | |||
* travesty, pure C interface to steinberg VST3 SDK | |||
* travesty, pure C VST3-compatible interface | |||
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
@@ -27,15 +27,11 @@ enum v3_seek_mode { | |||
struct v3_bstream { | |||
struct v3_funknown; | |||
V3_API v3_result (*read) | |||
(void *self, void *buffer, int32_t num_bytes, int32_t *bytes_read); | |||
V3_API v3_result (*write) | |||
(void *self, void *buffer, int32_t num_bytes, int32_t *bytes_written); | |||
V3_API v3_result (*seek) | |||
(void *self, int64_t pos, int32_t seek_mode, int64_t *result); | |||
V3_API v3_result (*tell) | |||
(void *self, int64_t *pos); | |||
v3_result (V3_API *read)(void* self, void* buffer, int32_t num_bytes, int32_t* bytes_read); | |||
v3_result (V3_API *write)(void* self, void* buffer, int32_t num_bytes, int32_t* bytes_written); | |||
v3_result (V3_API *seek)(void* self, int64_t pos, int32_t seek_mode, int64_t* result); | |||
v3_result (V3_API *tell)(void* self, int64_t* pos); | |||
}; | |||
static const v3_tuid v3_bstream_iid = | |||
static constexpr const v3_tuid v3_bstream_iid = | |||
V3_ID(0xC3BF6EA2, 0x30994752, 0x9B6BF990, 0x1EE33E9B); |
@@ -1,5 +1,5 @@ | |||
/* | |||
* travesty, pure C interface to steinberg VST3 SDK | |||
* travesty, pure C VST3-compatible interface | |||
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
@@ -30,13 +30,17 @@ enum v3_media_types { | |||
V3_EVENT | |||
}; | |||
inline static const char * | |||
v3_media_type_str(int32_t type) | |||
static inline | |||
const char* v3_media_type_str(int32_t type) | |||
{ | |||
switch (type) { | |||
case V3_AUDIO: return "V3_AUDIO"; | |||
case V3_EVENT: return "V3_EVENT"; | |||
default: return "[unknown]"; | |||
switch (type) | |||
{ | |||
case V3_AUDIO: | |||
return "V3_AUDIO"; | |||
case V3_EVENT: | |||
return "V3_EVENT"; | |||
default: | |||
return "[unknown]"; | |||
} | |||
} | |||
@@ -45,13 +49,17 @@ enum v3_bus_direction { | |||
V3_OUTPUT | |||
}; | |||
inline static const char * | |||
v3_bus_direction_str(int32_t d) | |||
static inline | |||
const char* v3_bus_direction_str(int32_t d) | |||
{ | |||
switch (d) { | |||
case V3_INPUT: return "V3_INPUT"; | |||
case V3_OUTPUT: return "V3_OUTPUT"; | |||
default: return "[unknown]"; | |||
switch (d) | |||
{ | |||
case V3_INPUT: | |||
return "V3_INPUT"; | |||
case V3_OUTPUT: | |||
return "V3_OUTPUT"; | |||
default: | |||
return "[unknown]"; | |||
} | |||
} | |||
@@ -61,7 +69,7 @@ enum v3_bus_types { | |||
}; | |||
enum v3_bus_flags { | |||
V3_DEFAULT_ACTIVE = 1, | |||
V3_DEFAULT_ACTIVE = 1 << 0, | |||
V3_IS_CONTROL_VOLTAGE = 1 << 1 | |||
}; | |||
@@ -69,7 +77,6 @@ struct v3_bus_info { | |||
int32_t media_type; | |||
int32_t direction; | |||
int32_t channel_count; | |||
v3_str_128 bus_name; | |||
int32_t bus_type; | |||
uint32_t flags; | |||
@@ -84,34 +91,44 @@ struct v3_routing_info; | |||
struct v3_component { | |||
struct v3_plugin_base; | |||
V3_API v3_result (*get_controller_class_id) | |||
(void *self, v3_tuid class_id); | |||
V3_API v3_result (*set_io_mode) | |||
(void *self, int32_t io_mode); | |||
V3_API int32_t (*get_bus_count) | |||
(void *self, int32_t media_type, int32_t bus_direction); | |||
V3_API v3_result (*get_bus_info) | |||
(void *self, int32_t media_type, int32_t bus_direction, | |||
int32_t bus_idx, struct v3_bus_info *bus_info); | |||
V3_API v3_result (*get_routing_info) | |||
(void *self, struct v3_routing_info *input, | |||
struct v3_routing_info *output); | |||
V3_API v3_result (*activate_bus) | |||
(void *self, int32_t media_type, int32_t bus_direction, | |||
int32_t bus_idx, v3_bool state); | |||
V3_API v3_result (*set_active) | |||
(void *self, v3_bool state); | |||
V3_API v3_result (*set_state) | |||
(void *self, struct v3_bstream **); | |||
V3_API v3_result (*get_state) | |||
(void *self, struct v3_bstream **); | |||
v3_result (V3_API *get_controller_class_id)(void* self, v3_tuid class_id); | |||
v3_result (V3_API *set_io_mode)(void* self, int32_t io_mode); | |||
int32_t (V3_API *get_bus_count)(void* self, int32_t media_type, int32_t bus_direction); | |||
v3_result (V3_API *get_bus_info)(void* self, int32_t media_type, int32_t bus_direction, | |||
int32_t bus_idx, struct v3_bus_info* bus_info); | |||
v3_result (V3_API *get_routing_info)(void* self, struct v3_routing_info* input, struct v3_routing_info* output); | |||
v3_result (V3_API *activate_bus)(void* self, int32_t media_type, int32_t bus_direction, | |||
int32_t bus_idx, v3_bool state); | |||
v3_result (V3_API *set_active)(void* self, v3_bool state); | |||
v3_result (V3_API *set_state)(void* self, struct v3_bstream **); | |||
v3_result (V3_API *get_state)(void* self, struct v3_bstream **); | |||
}; | |||
static const v3_tuid v3_component_iid = | |||
static constexpr const v3_tuid v3_component_iid = | |||
V3_ID(0xE831FF31, 0xF2D54301, 0x928EBBEE, 0x25697802); | |||
#ifdef __cplusplus | |||
/** | |||
* C++ variants | |||
*/ | |||
struct v3_component_cpp : v3_funknown { | |||
v3_plugin_base base; | |||
v3_component comp; | |||
}; | |||
template<> inline | |||
constexpr v3_component* v3_cpp_obj(v3_component** obj) | |||
{ | |||
/** | |||
* this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default, | |||
* but we need everything to be `static_cast` for it to be `constexpr` compatible. | |||
*/ | |||
return static_cast<v3_component*>( | |||
static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*5)); | |||
} | |||
#endif | |||
#include "align_pop.h" |
@@ -1,5 +1,5 @@ | |||
/* | |||
* travesty, pure C interface to steinberg VST3 SDK | |||
* travesty, pure C VST3-compatible interface | |||
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
@@ -26,21 +26,29 @@ | |||
* component handler | |||
*/ | |||
enum { | |||
V3_RESTART_RELOAD_COMPONENT = 1 << 0, | |||
V3_RESTART_IO_CHANGED = 1 << 1, | |||
V3_RESTART_PARAM_VALUES_CHANGED = 1 << 2, | |||
V3_RESTART_LATENCY_CHANGED = 1 << 3, | |||
V3_RESTART_PARAM_TITLES_CHANGED = 1 << 4, | |||
V3_RESTART_MIDI_CC_ASSIGNMENT_CHANGED = 1 << 5, | |||
V3_RESTART_NOTE_EXPRESSION_CHANGED = 1 << 6, | |||
V3_RESTART_IO_TITLES_CHANGED = 1 << 7, | |||
V3_RESTART_PREFETCHABLE_SUPPORT_CHANGED = 1 << 8, | |||
V3_RESTART_ROUTING_INFO_CHANGED = 1 << 9 | |||
}; | |||
struct v3_component_handler { | |||
struct v3_funknown; | |||
V3_API v3_result (*begin_edit) | |||
(void *self, v3_param_id); | |||
V3_API v3_result (*perform_edit) | |||
(void *self, v3_param_id, double value_normalised); | |||
V3_API v3_result (*end_edit) | |||
(void *self, v3_param_id); | |||
V3_API v3_result (*restart_component) | |||
(void *self, int32_t flags); | |||
v3_result (V3_API* begin_edit)(void* self, v3_param_id); | |||
v3_result (V3_API* perform_edit)(void* self, v3_param_id, double value_normalised); | |||
v3_result (V3_API* end_edit)(void* self, v3_param_id); | |||
v3_result (V3_API* restart_component)(void* self, int32_t flags); | |||
}; | |||
static const v3_tuid v3_component_handler_iid = | |||
static constexpr const v3_tuid v3_component_handler_iid = | |||
V3_ID(0x93A0BEA3, 0x0BD045DB, 0x8E890B0C, 0xC1E46AC6); | |||
/** | |||
@@ -48,7 +56,7 @@ static const v3_tuid v3_component_handler_iid = | |||
*/ | |||
enum { | |||
V3_PARAM_CAN_AUTOMATE = 1, | |||
V3_PARAM_CAN_AUTOMATE = 1 << 0, | |||
V3_PARAM_READ_ONLY = 1 << 1, | |||
V3_PARAM_WRAP_AROUND = 1 << 2, | |||
V3_PARAM_IS_LIST = 1 << 3, | |||
@@ -59,15 +67,11 @@ enum { | |||
struct v3_param_info { | |||
v3_param_id param_id; | |||
v3_str_128 title; | |||
v3_str_128 short_title; | |||
v3_str_128 units; | |||
int32_t step_count; | |||
double default_normalised_value; | |||
int32_t unit_id; | |||
int32_t flags; | |||
}; | |||
@@ -75,39 +79,63 @@ struct v3_param_info { | |||
struct v3_edit_controller { | |||
struct v3_plugin_base; | |||
V3_API v3_result (*set_component_state) | |||
(void *self, struct v3_bstream *); | |||
V3_API v3_result (*set_state) | |||
(void *self, struct v3_bstream *); | |||
V3_API v3_result (*get_state) | |||
(void *self, struct v3_bstream *); | |||
v3_result (V3_API* set_component_state)(void* self, struct v3_bstream*); | |||
v3_result (V3_API* set_state)(void* self, struct v3_bstream*); | |||
v3_result (V3_API* get_state)(void* self, struct v3_bstream*); | |||
int32_t (V3_API* get_parameter_count)(void* self); | |||
v3_result (V3_API* get_parameter_info)(void* self, int32_t param_idx, struct v3_param_info*); | |||
v3_result (V3_API* get_parameter_string_for_value)(void* self, v3_param_id, double normalised, v3_str_128 output); | |||
v3_result (V3_API* get_parameter_value_for_string)(void* self, v3_param_id, int16_t* input, double* output); | |||
double (V3_API* normalised_parameter_to_plain)(void* self, v3_param_id, double normalised); | |||
double (V3_API* plain_parameter_to_normalised)(void* self, v3_param_id, double plain); | |||
double (V3_API* get_parameter_normalised)(void* self, v3_param_id); | |||
v3_result (V3_API* set_parameter_normalised)(void* self, v3_param_id, double normalised); | |||
v3_result (V3_API* set_component_handler)(void* self, struct v3_component_handler**); | |||
struct v3_plugin_view** (V3_API* create_view)(void* self, const char* name); | |||
}; | |||
V3_API int32_t (*get_parameter_count)(void *self); | |||
V3_API v3_result (*get_param_info) | |||
(void *self, int32_t param_idx, struct v3_param_info *); | |||
static constexpr const v3_tuid v3_edit_controller_iid = | |||
V3_ID(0xDCD7BBE3, 0x7742448D, 0xA874AACC, 0x979C759E); | |||
V3_API v3_result (*get_param_string_for_value) | |||
(void *self, v3_param_id, double normalised, v3_str_128 output); | |||
V3_API v3_result (*get_param_value_for_string) | |||
(void *self, v3_param_id, int16_t *input, double *output); | |||
/** | |||
* midi mapping | |||
*/ | |||
struct v3_midi_mapping { | |||
struct v3_funknown; | |||
v3_result (V3_API* get_midi_controller_assignment)(void* self, int32_t bus, int16_t channel, int16_t cc, v3_param_id* id); | |||
}; | |||
V3_API double (*normalised_param_to_plain) | |||
(void *self, v3_param_id, double normalised); | |||
V3_API double (*plain_param_to_normalised) | |||
(void *self, v3_param_id, double normalised); | |||
static constexpr const v3_tuid v3_midi_mapping_iid = | |||
V3_ID(0xDF0FF9F7, 0x49B74669, 0xB63AB732, 0x7ADBF5E5); | |||
V3_API double (*get_param_normalised)(void *self, v3_param_id); | |||
V3_API v3_result (*set_param_normalised) | |||
(void *self, v3_param_id, double normalised); | |||
#ifdef __cplusplus | |||
V3_API v3_result (*set_component_handler) | |||
(void *self, struct v3_component_handler **); | |||
/** | |||
* C++ variants | |||
*/ | |||
V3_API struct v3_plug_view **(*create_view) | |||
(void *self, const char *name); | |||
struct v3_edit_controller_cpp : v3_funknown { | |||
v3_plugin_base base; | |||
v3_edit_controller ctrl; | |||
}; | |||
static const v3_tuid v3_edit_controller_iid = | |||
V3_ID(0xDCD7BBE3, 0x7742448D, 0xA874AACC, 0x979C759E); | |||
struct v3_midi_mapping_cpp : v3_funknown { | |||
v3_midi_mapping map; | |||
}; | |||
template<> inline | |||
constexpr v3_edit_controller* v3_cpp_obj(v3_edit_controller** obj) | |||
{ | |||
/** | |||
* this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default, | |||
* but we need everything to be `static_cast` for it to be `constexpr` compatible. | |||
*/ | |||
return static_cast<v3_edit_controller*>( | |||
static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*5)); | |||
} | |||
#endif | |||
#include "align_pop.h" |
@@ -1,5 +1,5 @@ | |||
/* | |||
* travesty, pure C interface to steinberg VST3 SDK | |||
* travesty, pure C VST3-compatible interface | |||
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
@@ -22,18 +22,13 @@ | |||
/** | |||
* note events | |||
* | |||
* i know there's others, but we don't need them right now. whatever. | |||
* handle them later. | |||
*/ | |||
struct v3_event_note_on { | |||
int16_t channel; | |||
int16_t pitch; // MIDI note number | |||
float tuning; | |||
float velocity; | |||
int32_t length; | |||
int32_t note_id; | |||
}; | |||
@@ -41,9 +36,7 @@ struct v3_event_note_on { | |||
struct v3_event_note_off { | |||
int16_t channel; | |||
int16_t pitch; // MIDI note number | |||
float velocity; | |||
int32_t note_id; | |||
float tuning; | |||
}; | |||
@@ -51,14 +44,12 @@ struct v3_event_note_off { | |||
struct v3_event_data { | |||
uint32_t size; | |||
uint32_t type; | |||
const uint8_t *bytes; | |||
const uint8_t* bytes; | |||
}; | |||
struct v3_event_poly_pressure { | |||
int16_t channel; | |||
int16_t pitch; | |||
float pressure; | |||
int32_t note_id; | |||
}; | |||
@@ -67,22 +58,19 @@ struct v3_event_chord { | |||
int16_t root; | |||
int16_t bass_note; | |||
int16_t mask; | |||
uint16_t text_len; | |||
const int16_t *text; | |||
const int16_t* text; | |||
}; | |||
struct v3_event_scale { | |||
int16_t root; | |||
int16_t mask; | |||
uint16_t text_len; | |||
const int16_t *text; | |||
const int16_t* text; | |||
}; | |||
struct v3_event_legacy_midi_cc_out { | |||
uint8_t cc_number; | |||
int8_t channel; | |||
int8_t value; | |||
int8_t value2; | |||
@@ -96,9 +84,8 @@ struct v3_event_note_expression_value { | |||
struct v3_event_note_expression_text { | |||
int32_t note_id; | |||
uint32_t text_len; | |||
const int16_t *text; | |||
const int16_t* text; | |||
}; | |||
/** | |||
@@ -106,7 +93,7 @@ struct v3_event_note_expression_text { | |||
*/ | |||
enum v3_event_flags { | |||
V3_EVENT_IS_LIVE = 1 | |||
V3_EVENT_IS_LIVE = 1 << 0 | |||
}; | |||
enum v3_event_type { | |||
@@ -118,19 +105,15 @@ enum v3_event_type { | |||
V3_EVENT_NOTE_EXP_TEXT = 5, | |||
V3_EVENT_CHORD = 6, | |||
V3_EVENT_SCALE = 7, | |||
V3_EVENT_LEGACY_MIDI_CC_OUT = 65535 | |||
}; | |||
struct v3_event { | |||
int32_t bus_index; | |||
int32_t sample_offset; | |||
double ppq_position; | |||
uint16_t flags; | |||
uint16_t type; | |||
union { | |||
struct v3_event_note_on note_on; | |||
struct v3_event_note_off note_off; | |||
@@ -151,14 +134,12 @@ struct v3_event { | |||
struct v3_event_list { | |||
struct v3_funknown; | |||
V3_API uint32_t (*get_event_count)(void *self); | |||
V3_API v3_result (*get_event) | |||
(void *self, int32_t idx, struct v3_event *); | |||
V3_API v3_result (*add_event) | |||
(void *self, struct v3_event *); | |||
uint32_t (V3_API* get_event_count)(void* self); | |||
v3_result (V3_API* get_event)(void* self, int32_t idx, struct v3_event* event); | |||
v3_result (V3_API* add_event)(void* self, struct v3_event* event); | |||
}; | |||
static const v3_tuid v3_event_list_iid = | |||
static constexpr const v3_tuid v3_event_list_iid = | |||
V3_ID(0x3A2C4214, 0x346349FE, 0xB2C4F397, 0xB9695A44); | |||
#include "align_pop.h" |
@@ -1,5 +1,5 @@ | |||
/* | |||
* travesty, pure C interface to steinberg VST3 SDK | |||
* travesty, pure C VST3-compatible interface | |||
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
@@ -26,12 +26,12 @@ struct v3_factory_info { | |||
char vendor[64]; | |||
char url[256]; | |||
char email[128]; | |||
int32_t flags; | |||
int32_t flags; // set to 0x10 (unicode) | |||
}; | |||
struct v3_class_info { | |||
v3_tuid class_id; | |||
int32_t cardinality; // set to 0x7FFFFFFF | |||
int32_t cardinality; // set to 0x7FFFFFFF (many instances) | |||
char category[32]; | |||
char name[64]; | |||
}; | |||
@@ -39,31 +39,29 @@ struct v3_class_info { | |||
struct v3_plugin_factory { | |||
struct v3_funknown; | |||
V3_API v3_result (*get_factory_info) | |||
(void *self, struct v3_factory_info *); | |||
V3_API int32_t (*num_classes)(void *self); | |||
V3_API v3_result (*get_class_info) | |||
(void *self, int32_t idx, struct v3_class_info *); | |||
V3_API v3_result (*create_instance) | |||
(void *self, const v3_tuid class_id, const v3_tuid iid, void **instance); | |||
v3_result (V3_API *get_factory_info)(void* self, struct v3_factory_info*); | |||
int32_t (V3_API *num_classes)(void* self); | |||
v3_result (V3_API *get_class_info)(void* self, int32_t idx, struct v3_class_info*); | |||
v3_result (V3_API *create_instance)(void* self, const v3_tuid class_id, const v3_tuid iid, void** instance); | |||
}; | |||
static const v3_tuid v3_plugin_factory_iid = | |||
static constexpr const v3_tuid v3_plugin_factory_iid = | |||
V3_ID(0x7A4D811C, 0x52114A1F, 0xAED9D2EE, 0x0B43BF9F); | |||
/** | |||
* plugin factory v2 | |||
*/ | |||
enum { | |||
V3_DISTRIBUTABLE = 1 << 0, | |||
V3_SIMPLE_MODE = 1 << 1 | |||
}; | |||
struct v3_class_info_2 { | |||
v3_tuid class_id; | |||
int32_t cardinality; // set to 0x7FFFFFFF | |||
char category[32]; | |||
char name[64]; | |||
uint32_t class_flags; | |||
char sub_categories[128]; | |||
char vendor[64]; | |||
@@ -74,11 +72,10 @@ struct v3_class_info_2 { | |||
struct v3_plugin_factory_2 { | |||
struct v3_plugin_factory; | |||
V3_API v3_result (*get_class_info_2) | |||
(void *self, int32_t idx, struct v3_class_info_2 *); | |||
v3_result (V3_API *get_class_info_2)(void* self, int32_t idx, struct v3_class_info_2*); | |||
}; | |||
static const v3_tuid v3_plugin_factory_2_iid = | |||
static constexpr const v3_tuid v3_plugin_factory_2_iid = | |||
V3_ID(0x0007B650, 0xF24B4C0B, 0xA464EDB9, 0xF00B2ABB); | |||
/** | |||
@@ -93,7 +90,6 @@ struct v3_class_info_3 { | |||
int32_t cardinality; // set to 0x7FFFFFFF | |||
char category[32]; | |||
int16_t name[64]; | |||
uint32_t class_flags; | |||
char sub_categories[128]; | |||
int16_t vendor[64]; | |||
@@ -104,12 +100,23 @@ struct v3_class_info_3 { | |||
struct v3_plugin_factory_3 { | |||
struct v3_plugin_factory_2; | |||
V3_API v3_result (*get_class_info_utf16) | |||
(void *self, int32_t idx, struct v3_class_info_3 *); | |||
V3_API v3_result (*set_host_context) | |||
(void *self, struct v3_funknown *host); | |||
v3_result (V3_API *get_class_info_utf16)(void* self, int32_t idx, struct v3_class_info_3*); | |||
v3_result (V3_API *set_host_context)(void* self, struct v3_funknown** host); | |||
}; | |||
static const v3_tuid v3_plugin_factory_3_iid = | |||
static constexpr const v3_tuid v3_plugin_factory_3_iid = | |||
V3_ID(0x4555A2AB, 0xC1234E57, 0x9B122910, 0x36878931); | |||
#ifdef __cplusplus | |||
/** | |||
* C++ variants | |||
*/ | |||
struct v3_plugin_factory_cpp : v3_funknown { | |||
v3_plugin_factory v1; | |||
v3_plugin_factory_2 v2; | |||
v3_plugin_factory_3 v3; | |||
}; | |||
#endif |
@@ -0,0 +1,49 @@ | |||
/* | |||
* travesty, pure C VST3-compatible interface | |||
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
* or without fee is hereby granted, provided that the above copyright notice and this | |||
* permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#pragma once | |||
#include "message.h" | |||
#include "align_push.h" | |||
/** | |||
* connection point | |||
*/ | |||
struct v3_host_application { | |||
struct v3_funknown; | |||
v3_result (V3_API* get_name)(void* self, v3_str_128 name); // wtf? | |||
v3_result (V3_API* create_instance)(void* self, v3_tuid cid, v3_tuid iid, void** obj); | |||
}; | |||
static constexpr const v3_tuid v3_host_application_iid = | |||
V3_ID(0x58E595CC, 0xDB2D4969, 0x8B6AAF8C, 0x36A664E5); | |||
#ifdef __cplusplus | |||
/** | |||
* C++ variants | |||
*/ | |||
struct v3_host_application_cpp : v3_funknown { | |||
v3_host_application app; | |||
}; | |||
#endif | |||
#include "align_pop.h" |
@@ -0,0 +1,93 @@ | |||
/* | |||
* travesty, pure C VST3-compatible interface | |||
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
* or without fee is hereby granted, provided that the above copyright notice and this | |||
* permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#pragma once | |||
#include "base.h" | |||
#include "align_push.h" | |||
/** | |||
* attribute list | |||
*/ | |||
struct v3_attribute_list { | |||
struct v3_funknown; | |||
v3_result (V3_API* set_int)(void* self, const char* id, int64_t value); | |||
v3_result (V3_API* get_int)(void* self, const char* id, int64_t* value); | |||
v3_result (V3_API* set_float)(void* self, const char* id, double value); | |||
v3_result (V3_API* get_float)(void* self, const char* id, double* value); | |||
v3_result (V3_API* set_string)(void* self, const char* id, const int16_t* string); | |||
v3_result (V3_API* get_string)(void* self, const char* id, int16_t* string, uint32_t size); | |||
v3_result (V3_API* set_binary)(void* self, const char* id, const void* data, uint32_t size); | |||
v3_result (V3_API* get_binary)(void* self, const char* id, const void** data, uint32_t* size); | |||
}; | |||
static constexpr const v3_tuid v3_attribute_list_iid = | |||
V3_ID(0x1E5F0AEB, 0xCC7F4533, 0xA2544011, 0x38AD5EE4); | |||
/** | |||
* message | |||
*/ | |||
struct v3_message { | |||
struct v3_funknown; | |||
const char* (V3_API* get_message_id)(void* self); | |||
void (V3_API* set_message_id)(void* self, const char* id); | |||
v3_attribute_list** (V3_API* get_attributes)(void* self); | |||
}; | |||
static constexpr const v3_tuid v3_message_iid = | |||
V3_ID(0x936F033B, 0xC6C047DB, 0xBB0882F8, 0x13C1E613); | |||
/** | |||
* connection point | |||
*/ | |||
struct v3_connection_point { | |||
struct v3_funknown; | |||
v3_result (V3_API* connect)(void* self, struct v3_connection_point** other); | |||
v3_result (V3_API* disconnect)(void* self, struct v3_connection_point** other); | |||
v3_result (V3_API* notify)(void* self, struct v3_message** message); | |||
}; | |||
static constexpr const v3_tuid v3_connection_point_iid = | |||
V3_ID(0x70A4156F, 0x6E6E4026, 0x989148BF, 0xAA60D8D1); | |||
#ifdef __cplusplus | |||
/** | |||
* C++ variants | |||
*/ | |||
struct v3_attribute_list_cpp : v3_funknown { | |||
v3_attribute_list attrlist; | |||
}; | |||
struct v3_message_cpp : v3_funknown { | |||
v3_message msg; | |||
}; | |||
struct v3_connection_point_cpp : v3_funknown { | |||
v3_connection_point point; | |||
}; | |||
#endif | |||
#include "align_pop.h" |
@@ -1,5 +1,5 @@ | |||
/* | |||
* travesty, pure C interface to steinberg VST3 SDK | |||
* travesty, pure C VST3-compatible interface | |||
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
@@ -19,7 +19,7 @@ | |||
#include "base.h" | |||
/** | |||
* base IPlugFrame stuff | |||
* base view stuff | |||
*/ | |||
struct v3_view_rect { | |||
@@ -41,50 +41,43 @@ struct v3_view_rect { | |||
# define V3_VIEW_PLATFORM_TYPE_NATIVE V3_VIEW_PLATFORM_TYPE_X11 | |||
#endif | |||
struct v3_plug_frame; | |||
struct v3_plug_view { | |||
struct v3_funknown; | |||
V3_API v3_result (*is_platform_type_supported) | |||
(void *self, const char *platform_type); | |||
V3_API v3_result (*attached) | |||
(void *self, void *parent, const char *platform_type); | |||
V3_API v3_result (*removed)(void *self); | |||
V3_API v3_result (*on_wheel)(void *self, float distance); | |||
V3_API v3_result (*on_key_down) | |||
(void *self, int16_t key_char, int16_t key_code, int16_t modifiers); | |||
V3_API v3_result (*on_key_up) | |||
(void *self, int16_t key_char, int16_t key_code, int16_t modifiers); | |||
/** | |||
* plugin view | |||
*/ | |||
V3_API v3_result (*get_size) | |||
(void *self, struct v3_view_rect *); | |||
V3_API v3_result (*set_size) | |||
(void *self, struct v3_view_rect *); | |||
struct v3_plugin_frame; | |||
V3_API v3_result (*on_focus) | |||
(void *self, v3_bool state); | |||
struct v3_plugin_view { | |||
struct v3_funknown; | |||
V3_API v3_result (*set_frame) | |||
(void *self, struct v3_plug_frame *); | |||
V3_API v3_result (*can_resize)(void *self); | |||
V3_API v3_result (*check_size_constraint) | |||
(void *self, struct v3_view_rect *); | |||
v3_result (V3_API* is_platform_type_supported)(void* self, const char* platform_type); | |||
v3_result (V3_API* attached)(void* self, void* parent, const char* platform_type); | |||
v3_result (V3_API* removed)(void* self); | |||
v3_result (V3_API* on_wheel)(void* self, float distance); | |||
v3_result (V3_API* on_key_down)(void* self, int16_t key_char, int16_t key_code, int16_t modifiers); | |||
v3_result (V3_API* on_key_up)(void* self, int16_t key_char, int16_t key_code, int16_t modifiers); | |||
v3_result (V3_API* get_size)(void* self, struct v3_view_rect*); | |||
v3_result (V3_API* on_size)(void* self, struct v3_view_rect*); | |||
v3_result (V3_API* on_focus)(void* self, v3_bool state); | |||
v3_result (V3_API* set_frame)(void* self, struct v3_plugin_frame**); | |||
v3_result (V3_API* can_resize)(void* self); | |||
v3_result (V3_API* check_size_constraint)(void* self, struct v3_view_rect*); | |||
}; | |||
static const v3_tuid v3_plug_view_iid = | |||
static constexpr const v3_tuid v3_plugin_view_iid = | |||
V3_ID(0x5BC32507, 0xD06049EA, 0xA6151B52, 0x2B755B29); | |||
struct v3_plug_frame { | |||
/** | |||
* plugin frame | |||
*/ | |||
struct v3_plugin_frame { | |||
struct v3_funknown; | |||
V3_API v3_result (*resize_view) | |||
(void *self, struct v3_plug_view *, struct v3_view_rect *); | |||
v3_result (V3_API* resize_view)(void* self, struct v3_plugin_view**, struct v3_view_rect*); | |||
}; | |||
static const v3_tuid v3_plug_frame_iid = | |||
static constexpr const v3_tuid v3_plugin_frame_iid = | |||
V3_ID(0x367FAF01, 0xAFA94693, 0x8D4DA2A0, 0xED0882A3); | |||
/** | |||
@@ -92,26 +85,102 @@ static const v3_tuid v3_plug_frame_iid = | |||
* (same IID/iface as presonus view scaling) | |||
*/ | |||
struct v3_plug_view_content_scale_steinberg { | |||
struct v3_plugin_view_content_scale { | |||
struct v3_funknown; | |||
V3_API v3_result (*set_content_scale_factor) | |||
(void *self, float factor); | |||
v3_result (V3_API* set_content_scale_factor)(void* self, float factor); | |||
}; | |||
static const v3_tuid v3_plug_view_content_scale_steinberg_iid = | |||
static constexpr const v3_tuid v3_plugin_view_content_scale_iid = | |||
V3_ID(0x65ED9690, 0x8AC44525, 0x8AADEF7A, 0x72EA703F); | |||
/** | |||
* support for querying the view to find what control is underneath the mouse | |||
*/ | |||
struct v3_plug_view_param_finder { | |||
struct v3_plugin_view_parameter_finder { | |||
struct v3_funknown; | |||
V3_API v3_result (*find_parameter) | |||
(void *self, int32_t x, int32_t y, v3_param_id *); | |||
v3_result (V3_API* find_parameter)(void* self, int32_t x, int32_t y, v3_param_id *); | |||
}; | |||
static const v3_tuid v3_plug_view_param_finder_iid = | |||
static constexpr const v3_tuid v3_plugin_view_parameter_finder_iid = | |||
V3_ID(0x0F618302, 0x215D4587, 0xA512073C, 0x77B9D383); | |||
/** | |||
* linux event handler | |||
*/ | |||
struct v3_event_handler { | |||
struct v3_funknown; | |||
void (V3_API* on_fd_is_set)(void* self, int fd); | |||
}; | |||
static constexpr const v3_tuid v3_event_handler_iid = | |||
V3_ID(0x561E65C9, 0x13A0496F, 0x813A2C35, 0x654D7983); | |||
/** | |||
* linux timer handler | |||
*/ | |||
struct v3_timer_handler { | |||
struct v3_funknown; | |||
void (V3_API* on_timer)(void* self); | |||
}; | |||
static constexpr const v3_tuid v3_timer_handler_iid = | |||
V3_ID(0x10BDD94F, 0x41424774, 0x821FAD8F, 0xECA72CA9); | |||
/** | |||
* linux host run loop | |||
*/ | |||
struct v3_run_loop { | |||
struct v3_funknown; | |||
v3_result (V3_API* register_event_handler)(void* self, v3_event_handler** handler, int fd); | |||
v3_result (V3_API* unregister_event_handler)(void* self, v3_event_handler** handler); | |||
v3_result (V3_API* register_timer)(void* self, v3_timer_handler** handler, uint64_t ms); | |||
v3_result (V3_API* unregister_timer)(void* self, v3_timer_handler** handler); | |||
}; | |||
static constexpr const v3_tuid v3_run_loop_iid = | |||
V3_ID(0x18C35366, 0x97764F1A, 0x9C5B8385, 0x7A871389); | |||
#ifdef __cplusplus | |||
/** | |||
* C++ variants | |||
*/ | |||
struct v3_plugin_view_cpp : v3_funknown { | |||
v3_plugin_view view; | |||
}; | |||
struct v3_plugin_frame_cpp : v3_funknown { | |||
v3_plugin_frame frame; | |||
}; | |||
struct v3_plugin_view_content_scale_cpp : v3_funknown { | |||
v3_plugin_view_content_scale scale; | |||
}; | |||
struct v3_plugin_view_parameter_finder_cpp : v3_funknown { | |||
v3_plugin_view_parameter_finder finder; | |||
}; | |||
struct v3_event_handler_cpp : v3_funknown { | |||
v3_event_handler handler; | |||
}; | |||
struct v3_timer_handler_cpp : v3_funknown { | |||
v3_timer_handler handler; | |||
}; | |||
struct v3_run_loop_cpp : v3_funknown { | |||
v3_run_loop loop; | |||
}; | |||
#endif |
@@ -63,7 +63,14 @@ int main(int argc, char* argv[]) | |||
} | |||
#ifdef TTL_GENERATOR_WINDOWS | |||
# if defined(__GNUC__) && (__GNUC__ >= 9) | |||
# pragma GCC diagnostic push | |||
# pragma GCC diagnostic ignored "-Wcast-function-type" | |||
# endif | |||
const TTL_Generator_Function ttlFn = (TTL_Generator_Function)GetProcAddress(handle, "lv2_generate_ttl"); | |||
# if defined(__GNUC__) && (__GNUC__ >= 9) | |||
# pragma GCC diagnostic pop | |||
# endif | |||
#else | |||
const TTL_Generator_Function ttlFn = (TTL_Generator_Function)dlsym(handle, "lv2_generate_ttl"); | |||
#endif | |||
@@ -14,10 +14,12 @@ SNAME="$(echo ${NAME} | tr -d ' ' | tr '/' '-')" | |||
rm -rf lv2 | |||
rm -rf vst2 | |||
rm -rf vst3 | |||
mkdir lv2 vst2 | |||
mkdir lv2 vst2 vst3 | |||
mv *.lv2 lv2/ | |||
mv *.vst vst2/ | |||
mv *.vst3 vst3/ | |||
pkgbuild \ | |||
--identifier "studio.kx.distrho.plugins.${SNAME}.lv2bundles" \ | |||
@@ -31,6 +33,12 @@ pkgbuild \ | |||
--root "${PWD}/vst2/" \ | |||
../dpf-${SNAME}-vst2bundles.pkg | |||
pkgbuild \ | |||
--identifier "studio.kx.distrho.plugins.${SNAME}.vst3bundles" \ | |||
--install-location "/Library/Audio/Plug-Ins/VST3/" \ | |||
--root "${PWD}/vst3/" \ | |||
../dpf-${SNAME}-vst3bundles.pkg | |||
cd .. | |||
DPF_UTILS_DIR=$(dirname ${0}) | |||
@@ -39,6 +47,7 @@ sed -e "s|@name@|${NAME}|" ${DPF_UTILS_DIR}/plugin.pkg/welcome.txt.in > build/we | |||
sed -e "s|@builddir@|${PWD}/build|" \ | |||
-e "s|@lv2bundleref@|dpf-${SNAME}-lv2bundles.pkg|" \ | |||
-e "s|@vst2bundleref@|dpf-${SNAME}-vst2bundles.pkg|" \ | |||
-e "s|@vst3bundleref@|dpf-${SNAME}-vst3bundles.pkg|" \ | |||
-e "s|@name@|${NAME}|g" \ | |||
-e "s|@sname@|${SNAME}|g" \ | |||
${DPF_UTILS_DIR}/plugin.pkg/package.xml.in > build/package.xml | |||
@@ -11,8 +11,12 @@ | |||
<choice id="studio.kx.distrho.@sname@-vst2" title="VST2" description="Install VST2 plugins" visible="true"> | |||
<pkg-ref id="studio.kx.distrho.@sname@-vst2bundles" version="0">@vst2bundleref@</pkg-ref> | |||
</choice> | |||
<choice id="studio.kx.distrho.@sname@-vst3" title="VST3" description="Install VST3 plugins" visible="true"> | |||
<pkg-ref id="studio.kx.distrho.@sname@-vst3bundles" version="0">@vst3bundleref@</pkg-ref> | |||
</choice> | |||
<choices-outline> | |||
<line choice="studio.kx.distrho.@sname@-lv2"/> | |||
<line choice="studio.kx.distrho.@sname@-vst2"/> | |||
<line choice="studio.kx.distrho.@sname@-vst3"/> | |||
</choices-outline> | |||
</installer-gui-script> |
@@ -39,3 +39,10 @@ | |||
fun:XInitThreads | |||
... | |||
} | |||
{ | |||
ignore XrmGetStringDatabase | |||
Memcheck:Leak | |||
... | |||
fun:XrmGetStringDatabase | |||
... | |||
} |