@@ -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_C_FLAGS += -I. | ||||
BUILD_CXX_FLAGS += -I. -I$(DPF_PATH)/distrho -I$(DPF_PATH)/dgl | BUILD_CXX_FLAGS += -I. -I$(DPF_PATH)/distrho -I$(DPF_PATH)/dgl | ||||
BUILD_CXX_FLAGS += -Wno-pmf-conversions | |||||
ifeq ($(HAVE_ALSA),true) | ifeq ($(HAVE_ALSA),true) | ||||
BASE_FLAGS += -DHAVE_ALSA | 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_LV2 = $(DPF_PATH)/utils/symbols/lv2.def | ||||
SYMBOLS_VST2 = $(DPF_PATH)/utils/symbols/vst2.def | SYMBOLS_VST2 = $(DPF_PATH)/utils/symbols/vst2.def | ||||
SYMBOLS_VST3 = $(DPF_PATH)/utils/symbols/vst3.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_LADSPA = -Wl,--version-script=$(DPF_PATH)/utils/symbols/ladspa.version | ||||
SYMBOLS_DSSI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/dssi.version | SYMBOLS_DSSI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/dssi.version | ||||
SYMBOLS_LV2DSP = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2-dsp.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 | # TODO split dsp and ui object build flags | ||||
BASE_FLAGS += $(DGL_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 | # all needs to be first | ||||
@@ -386,7 +392,11 @@ endif | |||||
vst3: $(vst3) | 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 | $(vst3): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o | ||||
endif | |||||
-@mkdir -p $(shell dirname $@) | -@mkdir -p $(shell dirname $@) | ||||
@echo "Creating VST3 plugin for $(NAME)" | @echo "Creating VST3 plugin for $(NAME)" | ||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_VST3) -o $@ | $(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/> | 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 | ## Help and documentation | ||||
Bug reports happen on the [DPF github project](https://github.com/DISTRHO/DPF/issues). | Bug reports happen on the [DPF github project](https://github.com/DISTRHO/DPF/issues). | ||||
@@ -107,6 +107,7 @@ public: | |||||
private: | private: | ||||
struct PrivateData; | struct PrivateData; | ||||
PrivateData* const pData; | PrivateData* const pData; | ||||
friend class PluginApplication; | |||||
friend class Window; | friend class Window; | ||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Application) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Application) | ||||
@@ -49,16 +49,16 @@ enum Modifier { | |||||
/** | /** | ||||
Keyboard key codepoints. | 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. | convenience when writing hard-coded key bindings. | ||||
Keys that do not have a standard code point use values in the Private Use | 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 { | enum Key { | ||||
// Convenience symbols for ASCII control characters | // Convenience symbols for ASCII control characters | ||||
@@ -116,7 +116,7 @@ enum Key { | |||||
/** | /** | ||||
Common flags for all events. | Common flags for all events. | ||||
*/ | */ | ||||
enum Flag { | |||||
enum EventFlag { | |||||
kFlagSendEvent = 1, ///< Event is synthetic | kFlagSendEvent = 1, ///< Event is synthetic | ||||
kFlagIsHint = 2 ///< Event is a hint (not direct user input) | kFlagIsHint = 2 ///< Event is a hint (not direct user input) | ||||
}; | }; | ||||
@@ -903,7 +903,7 @@ public: | |||||
Constructor for a NanoSubWidget. | Constructor for a NanoSubWidget. | ||||
@see CreateFlags | @see CreateFlags | ||||
*/ | */ | ||||
explicit NanoBaseWidget(Widget* const parentGroupWidget, int flags = CREATE_ANTIALIAS); | |||||
explicit NanoBaseWidget(Widget* parentGroupWidget, int flags = CREATE_ANTIALIAS); | |||||
/** | /** | ||||
Constructor for a NanoTopLevelWidget. | Constructor for a NanoTopLevelWidget. | ||||
@@ -912,16 +912,16 @@ public: | |||||
explicit NanoBaseWidget(Window& windowToMapTo, int flags = CREATE_ANTIALIAS); | 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 | @see CreateFlags | ||||
*/ | */ | ||||
explicit NanoBaseWidget(Application& app, int flags = CREATE_ANTIALIAS); | 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 | @see CreateFlags | ||||
*/ | */ | ||||
explicit NanoBaseWidget(Application& app, Window& parentWindow, int flags = CREATE_ANTIALIAS); | |||||
explicit NanoBaseWidget(Application& app, Window& transientParentWindow, int flags = CREATE_ANTIALIAS); | |||||
/** | /** | ||||
Destructor. | Destructor. | ||||
@@ -117,7 +117,6 @@ public: | |||||
protected: | protected: | ||||
bool onKeyboard(const KeyboardEvent&) override; | bool onKeyboard(const KeyboardEvent&) override; | ||||
bool onSpecial(const SpecialEvent&) override; | |||||
bool onCharacterInput(const CharacterInputEvent&) override; | bool onCharacterInput(const CharacterInputEvent&) override; | ||||
bool onMouse(const MouseEvent&) override; | bool onMouse(const MouseEvent&) override; | ||||
bool onMotion(const MotionEvent&) override; | bool onMotion(const MotionEvent&) override; | ||||
@@ -58,7 +58,7 @@ public: | |||||
These are the fields present on all Widget events. | These are the fields present on all Widget events. | ||||
@a mod Currently active keyboard modifiers, @see Modifier. | @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). | @a time Event timestamp (if any). | ||||
*/ | */ | ||||
struct BaseEvent { | struct BaseEvent { | ||||
@@ -107,14 +107,10 @@ public: | |||||
/** | /** | ||||
Special keyboard event. | 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; | bool press; | ||||
Key key; | Key key; | ||||
@@ -398,12 +394,6 @@ protected: | |||||
*/ | */ | ||||
virtual bool onKeyboard(const KeyboardEvent&); | 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. | A function called when an UTF-8 character is received. | ||||
@return True to stop event propagation, false otherwise. | @return True to stop event propagation, false otherwise. | ||||
@@ -433,6 +423,24 @@ protected: | |||||
*/ | */ | ||||
virtual void onResize(const ResizeEvent&); | 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: | private: | ||||
struct PrivateData; | struct PrivateData; | ||||
PrivateData* const pData; | PrivateData* const pData; | ||||
@@ -157,10 +157,10 @@ public: | |||||
explicit Window(Application& app); | 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. | 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, | Constructor for an embed Window without known size, | ||||
@@ -369,7 +369,7 @@ public: | |||||
This function does not block the event loop. | This function does not block the event loop. | ||||
*/ | */ | ||||
bool openFileBrowser(const FileBrowserOptions& options); | |||||
bool openFileBrowser(const FileBrowserOptions& options = FileBrowserOptions()); | |||||
#endif | #endif | ||||
/** | /** | ||||
@@ -0,0 +1 @@ | |||||
pugl-upstream/include/ |
@@ -118,6 +118,11 @@ void Application::PrivateData::idle(const uint timeoutInMs) | |||||
puglUpdate(world, timeoutInSeconds); | puglUpdate(world, timeoutInSeconds); | ||||
} | } | ||||
triggerIdleCallbacks(); | |||||
} | |||||
void Application::PrivateData::triggerIdleCallbacks() | |||||
{ | |||||
for (std::list<IdleCallback*>::iterator it = idleCallbacks.begin(), ite = idleCallbacks.end(); it != ite; ++it) | for (std::list<IdleCallback*>::iterator it = idleCallbacks.begin(), ite = idleCallbacks.end(); it != ite; ++it) | ||||
{ | { | ||||
IdleCallback* const idleCallback(*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. */ | /** Run Pugl world update for @a timeoutInMs, and then each idle callback in order of registration. */ | ||||
void idle(uint timeoutInMs); | 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. | /** Set flag indicating application is quitting, and close all windows in reverse order of registration. | ||||
For standalone mode only. */ | For standalone mode only. */ | ||||
void quit(); | void quit(); | ||||
@@ -100,11 +100,6 @@ bool TopLevelWidget::onKeyboard(const KeyboardEvent&) | |||||
return false; | return false; | ||||
} | } | ||||
bool TopLevelWidget::onSpecial(const SpecialEvent&) | |||||
{ | |||||
return false; | |||||
} | |||||
bool TopLevelWidget::onCharacterInput(const CharacterInputEvent&) | bool TopLevelWidget::onCharacterInput(const CharacterInputEvent&) | ||||
{ | { | ||||
return false; | return false; | ||||
@@ -50,20 +50,6 @@ bool TopLevelWidget::PrivateData::keyboardEvent(const KeyboardEvent& ev) | |||||
return selfw->pData->giveKeyboardEventForSubWidgets(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) | bool TopLevelWidget::PrivateData::characterInputEvent(const CharacterInputEvent& ev) | ||||
{ | { | ||||
// ignore event if we are not visible | // ignore event if we are not visible | ||||
@@ -34,7 +34,6 @@ struct TopLevelWidget::PrivateData { | |||||
~PrivateData(); | ~PrivateData(); | ||||
void display(); | void display(); | ||||
bool keyboardEvent(const KeyboardEvent& ev); | bool keyboardEvent(const KeyboardEvent& ev); | ||||
bool specialEvent(const SpecialEvent& ev); | |||||
bool characterInputEvent(const CharacterInputEvent& ev); | bool characterInputEvent(const CharacterInputEvent& ev); | ||||
bool mouseEvent(const MouseEvent& ev); | bool mouseEvent(const MouseEvent& ev); | ||||
bool motionEvent(const MotionEvent& ev); | bool motionEvent(const MotionEvent& ev); | ||||
@@ -167,11 +167,6 @@ bool Widget::onKeyboard(const KeyboardEvent& ev) | |||||
return pData->giveKeyboardEventForSubWidgets(ev); | return pData->giveKeyboardEventForSubWidgets(ev); | ||||
} | } | ||||
bool Widget::onSpecial(const SpecialEvent& ev) | |||||
{ | |||||
return pData->giveSpecialEventForSubWidgets(ev); | |||||
} | |||||
bool Widget::onCharacterInput(const CharacterInputEvent& ev) | bool Widget::onCharacterInput(const CharacterInputEvent& ev) | ||||
{ | { | ||||
return pData->giveCharacterInputEventForSubWidgets(ev); | return pData->giveCharacterInputEventForSubWidgets(ev); | ||||
@@ -87,24 +87,6 @@ bool Widget::PrivateData::giveKeyboardEventForSubWidgets(const KeyboardEvent& ev | |||||
return false; | 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) | bool Widget::PrivateData::giveCharacterInputEventForSubWidgets(const CharacterInputEvent& ev) | ||||
{ | { | ||||
if (! visible) | if (! visible) | ||||
@@ -44,7 +44,6 @@ struct Widget::PrivateData { | |||||
void displaySubWidgets(uint width, uint height, double autoScaleFactor); | void displaySubWidgets(uint width, uint height, double autoScaleFactor); | ||||
bool giveKeyboardEventForSubWidgets(const KeyboardEvent& ev); | bool giveKeyboardEventForSubWidgets(const KeyboardEvent& ev); | ||||
bool giveSpecialEventForSubWidgets(const SpecialEvent& ev); | |||||
bool giveCharacterInputEventForSubWidgets(const CharacterInputEvent& ev); | bool giveCharacterInputEventForSubWidgets(const CharacterInputEvent& ev); | ||||
bool giveMouseEventForSubWidgets(MouseEvent& ev); | bool giveMouseEventForSubWidgets(MouseEvent& ev); | ||||
bool giveMotionEventForSubWidgets(MotionEvent& ev); | bool giveMotionEventForSubWidgets(MotionEvent& ev); | ||||
@@ -66,8 +66,8 @@ Window::Window(Application& app) | |||||
pData->initPost(); | 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(); | pData->initPost(); | ||||
} | } | ||||
@@ -407,22 +407,6 @@ void Window::setTransientWinId(const uintptr_t winId) | |||||
{ | { | ||||
puglSetTransientFor(pData->view, 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 | #endif | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -33,7 +33,11 @@ | |||||
#define DGL_DEBUG_EVENTS | #define DGL_DEBUG_EVENTS | ||||
#if defined(DEBUG) && defined(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 | #endif | ||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
@@ -820,24 +824,6 @@ void Window::PrivateData::onPuglKey(const Widget::KeyboardEvent& ev) | |||||
#endif | #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) | void Window::PrivateData::onPuglText(const Widget::CharacterInputEvent& ev) | ||||
{ | { | ||||
DGL_DBGp("onPuglText : %u %u %s\n", ev.keycode, ev.character, ev.string); | 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: | case PUGL_KEY_RELEASE: | ||||
{ | { | ||||
// unused x, y, xRoot, yRoot (double) | // unused x, y, xRoot, yRoot (double) | ||||
// TODO special keys? | |||||
Widget::KeyboardEvent ev; | Widget::KeyboardEvent ev; | ||||
ev.mod = event->key.state; | ev.mod = event->key.state; | ||||
ev.flags = event->key.flags; | 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.press = event->type == PUGL_KEY_PRESS; | ||||
ev.key = event->key.key; | ev.key = event->key.key; | ||||
ev.keycode = event->key.keycode; | 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); | pData->onPuglKey(ev); | ||||
break; | break; | ||||
} | } | ||||
@@ -178,7 +178,6 @@ struct Window::PrivateData : IdleCallback { | |||||
void onPuglClose(); | void onPuglClose(); | ||||
void onPuglFocus(bool focus, CrossingMode mode); | void onPuglFocus(bool focus, CrossingMode mode); | ||||
void onPuglKey(const Widget::KeyboardEvent& ev); | void onPuglKey(const Widget::KeyboardEvent& ev); | ||||
void onPuglSpecial(const Widget::SpecialEvent& ev); | |||||
void onPuglText(const Widget::CharacterInputEvent& ev); | void onPuglText(const Widget::CharacterInputEvent& ev); | ||||
void onPuglMouse(const Widget::MouseEvent& ev); | void onPuglMouse(const Widget::MouseEvent& ev); | ||||
void onPuglMotion(const Widget::MotionEvent& ev); | void onPuglMotion(const Widget::MotionEvent& ev); | ||||
@@ -106,13 +106,6 @@ START_NAMESPACE_DISTRHO | |||||
return d_cconst('M', 'u', 't', 'e'); | 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 */ | * Audio/MIDI Processing */ | ||||
@@ -507,6 +500,20 @@ START_NAMESPACE_DISTRHO | |||||
*/ | */ | ||||
#define DISTRHO_PLUGIN_IS_SYNTH 1 | #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. | Enable direct access between the %UI and plugin code. | ||||
@see UI::getPluginInstancePointer() | @see UI::getPluginInstancePointer() | ||||
@@ -613,6 +620,158 @@ START_NAMESPACE_DISTRHO | |||||
*/ | */ | ||||
#define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI" | #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; | 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; | static const uint32_t kAudioPortIsSidechain = 0x2; | ||||
@@ -632,6 +634,9 @@ struct MidiEvent { | |||||
/** | /** | ||||
MIDI data.@n | MIDI data.@n | ||||
If size > kDataSize, dataExt is used (otherwise null). | 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]; | uint8_t data[kDataSize]; | ||||
const uint8_t* dataExt; | const uint8_t* dataExt; | ||||
@@ -27,7 +27,7 @@ | |||||
#elif defined(DISTRHO_PLUGIN_TARGET_VST2) | #elif defined(DISTRHO_PLUGIN_TARGET_VST2) | ||||
// nothing | // nothing | ||||
#elif defined(DISTRHO_PLUGIN_TARGET_VST3) | #elif defined(DISTRHO_PLUGIN_TARGET_VST3) | ||||
// nothing | |||||
# include "src/DistrhoUIVST3.cpp" | |||||
#else | #else | ||||
# error unsupported format | # error unsupported format | ||||
#endif | #endif |
@@ -23,7 +23,25 @@ START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// The following code was based from juce-core LeakDetector class | // 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. | /** A good old-fashioned C macro concatenation helper. | ||||
This combines two items (which may themselves be macros) into a single string, | 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 | // 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 | 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) | 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_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_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_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; } | #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_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_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_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; } | #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 */ | # pragma warning(disable:4244) /* possible loss of data */ | ||||
#endif | #endif | ||||
/* Useful macros */ | |||||
#define ARRAY_SIZE(ARRAY) sizeof(ARRAY)/sizeof(ARRAY[0]) | |||||
/* Useful typedefs */ | /* Useful typedefs */ | ||||
typedef unsigned char uchar; | typedef unsigned char uchar; | ||||
typedef unsigned short int ushort; | typedef unsigned short int ushort; | ||||
@@ -29,7 +29,7 @@ bool d_lastCanRequestParameterValueChanges = false; | |||||
* Static fallback data, see DistrhoPluginInternal.hpp */ | * Static fallback data, see DistrhoPluginInternal.hpp */ | ||||
const String PluginExporter::sFallbackString; | const String PluginExporter::sFallbackString; | ||||
const AudioPort PluginExporter::sFallbackAudioPort; | |||||
/* */ AudioPortWithBusId PluginExporter::sFallbackAudioPort; | |||||
const ParameterRanges PluginExporter::sFallbackRanges; | const ParameterRanges PluginExporter::sFallbackRanges; | ||||
const ParameterEnumerationValues PluginExporter::sFallbackEnumValues; | const ParameterEnumerationValues PluginExporter::sFallbackEnumValues; | ||||
const PortGroupWithId PluginExporter::sFallbackPortGroup; | const PortGroupWithId PluginExporter::sFallbackPortGroup; | ||||
@@ -41,7 +41,7 @@ Plugin::Plugin(uint32_t parameterCount, uint32_t programCount, uint32_t stateCou | |||||
: pData(new PrivateData()) | : pData(new PrivateData()) | ||||
{ | { | ||||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | #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 | #endif | ||||
#ifdef DPF_ABORT_ON_ERROR | #ifdef DPF_ABORT_ON_ERROR | ||||
@@ -173,7 +173,6 @@ | |||||
# error DISTRHO_UI_IS_STANDALONE must not be defined | # error DISTRHO_UI_IS_STANDALONE must not be defined | ||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
#endif // DISTRHO_PLUGIN_CHECKS_H_INCLUDED | #endif // DISTRHO_PLUGIN_CHECKS_H_INCLUDED |
@@ -44,6 +44,14 @@ typedef bool (*requestParameterValueChangeFunc) (void* ptr, uint32_t index, floa | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Helpers | // Helpers | ||||
struct AudioPortWithBusId : AudioPort { | |||||
uint32_t busId; | |||||
AudioPortWithBusId() | |||||
: AudioPort(), | |||||
busId(0) {} | |||||
}; | |||||
struct PortGroupWithId : PortGroup { | struct PortGroupWithId : PortGroup { | ||||
uint32_t groupId; | uint32_t groupId; | ||||
@@ -78,7 +86,7 @@ struct Plugin::PrivateData { | |||||
bool isProcessing; | bool isProcessing; | ||||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | ||||
AudioPort* audioPorts; | |||||
AudioPortWithBusId* audioPorts; | |||||
#endif | #endif | ||||
uint32_t parameterCount; | uint32_t parameterCount; | ||||
@@ -162,6 +170,15 @@ struct Plugin::PrivateData { | |||||
# if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE) | # if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE) | ||||
parameterOffset += 1; | parameterOffset += 1; | ||||
# endif | # 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 | #endif | ||||
} | } | ||||
@@ -247,30 +264,26 @@ public: | |||||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | ||||
DISTRHO_SAFE_ASSERT_RETURN(fData != 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. */ | * 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 (fData->parameterCount != 0) | ||||
{ | { | ||||
if ((void*)(fPlugin->*(&Plugin::initParameter)) == (void*)&Plugin::initParameter) | if ((void*)(fPlugin->*(&Plugin::initParameter)) == (void*)&Plugin::initParameter) | ||||
{ | { | ||||
d_stderr2("DPF warning: Plugins with parameters must implement `initParameter`"); | d_stderr2("DPF warning: Plugins with parameters must implement `initParameter`"); | ||||
DPF_ABORT | |||||
abort(); | |||||
} | } | ||||
if ((void*)(fPlugin->*(&Plugin::getParameterValue)) == (void*)&Plugin::getParameterValue) | if ((void*)(fPlugin->*(&Plugin::getParameterValue)) == (void*)&Plugin::getParameterValue) | ||||
{ | { | ||||
d_stderr2("DPF warning: Plugins with parameters must implement `getParameterValue`"); | d_stderr2("DPF warning: Plugins with parameters must implement `getParameterValue`"); | ||||
DPF_ABORT | |||||
abort(); | |||||
} | } | ||||
if ((void*)(fPlugin->*(&Plugin::setParameterValue)) == (void*)&Plugin::setParameterValue) | if ((void*)(fPlugin->*(&Plugin::setParameterValue)) == (void*)&Plugin::setParameterValue) | ||||
{ | { | ||||
d_stderr2("DPF warning: Plugins with parameters must implement `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) | if ((void*)(fPlugin->*(&Plugin::initProgramName)) == (void*)&Plugin::initProgramName) | ||||
{ | { | ||||
d_stderr2("DPF warning: Plugins with programs must implement `initProgramName`"); | d_stderr2("DPF warning: Plugins with programs must implement `initProgramName`"); | ||||
DPF_ABORT | |||||
abort(); | |||||
} | } | ||||
if ((void*)(fPlugin->*(&Plugin::loadProgram)) == (void*)&Plugin::loadProgram) | if ((void*)(fPlugin->*(&Plugin::loadProgram)) == (void*)&Plugin::loadProgram) | ||||
{ | { | ||||
d_stderr2("DPF warning: Plugins with programs must implement `loadProgram`"); | d_stderr2("DPF warning: Plugins with programs must implement `loadProgram`"); | ||||
DPF_ABORT | |||||
abort(); | |||||
} | } | ||||
} | } | ||||
# endif | # endif | ||||
@@ -296,13 +309,13 @@ public: | |||||
if ((void*)(fPlugin->*(&Plugin::initState)) == (void*)&Plugin::initState) | if ((void*)(fPlugin->*(&Plugin::initState)) == (void*)&Plugin::initState) | ||||
{ | { | ||||
d_stderr2("DPF warning: Plugins with state must implement `initState`"); | d_stderr2("DPF warning: Plugins with state must implement `initState`"); | ||||
DPF_ABORT | |||||
abort(); | |||||
} | } | ||||
if ((void*)(fPlugin->*(&Plugin::setState)) == (void*)&Plugin::setState) | if ((void*)(fPlugin->*(&Plugin::setState)) == (void*)&Plugin::setState) | ||||
{ | { | ||||
d_stderr2("DPF warning: Plugins with state must implement `setState`"); | d_stderr2("DPF warning: Plugins with state must implement `setState`"); | ||||
DPF_ABORT | |||||
abort(); | |||||
} | } | ||||
} | } | ||||
# endif | # endif | ||||
@@ -313,17 +326,15 @@ public: | |||||
if ((void*)(fPlugin->*(&Plugin::getState)) == (void*)&Plugin::getState) | if ((void*)(fPlugin->*(&Plugin::getState)) == (void*)&Plugin::getState) | ||||
{ | { | ||||
d_stderr2("DPF warning: Plugins with full state must implement `getState`"); | d_stderr2("DPF warning: Plugins with full state must implement `getState`"); | ||||
DPF_ABORT | |||||
abort(); | |||||
} | } | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
d_stderr2("DPF warning: Plugins with full state must have at least 1 state"); | d_stderr2("DPF warning: Plugins with full state must have at least 1 state"); | ||||
DPF_ABORT | |||||
abort(); | |||||
} | } | ||||
# endif | # endif | ||||
# undef DPF_ABORT | |||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | ||||
@@ -469,7 +480,7 @@ public: | |||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | #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); | DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackAudioPort); | ||||
@@ -488,6 +499,11 @@ public: | |||||
return fData->audioPorts[index + (input ? 0 : DISTRHO_PLUGIN_NUM_INPUTS)]; | 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 | #endif | ||||
uint32_t getParameterCount() const noexcept | uint32_t getParameterCount() const noexcept | ||||
@@ -528,6 +544,11 @@ public: | |||||
return (getParameterHints(index) & kParameterIsOutput) != 0x0; | 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 | bool isParameterOutputOrTrigger(const uint32_t index) const noexcept | ||||
{ | { | ||||
const uint32_t hints = getParameterHints(index); | const uint32_t hints = getParameterHints(index); | ||||
@@ -603,6 +624,14 @@ public: | |||||
return fData->parameters[index].groupId; | 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 | float getParameterValue(const uint32_t index) const | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f); | DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f); | ||||
@@ -888,7 +917,7 @@ private: | |||||
// Static fallback data, see DistrhoPlugin.cpp | // Static fallback data, see DistrhoPlugin.cpp | ||||
static const String sFallbackString; | static const String sFallbackString; | ||||
static const AudioPort sFallbackAudioPort; | |||||
static /* */ AudioPortWithBusId sFallbackAudioPort; | |||||
static const ParameterRanges sFallbackRanges; | static const ParameterRanges sFallbackRanges; | ||||
static const ParameterEnumerationValues sFallbackEnumValues; | static const ParameterEnumerationValues sFallbackEnumValues; | ||||
static const PortGroupWithId sFallbackPortGroup; | static const PortGroupWithId sFallbackPortGroup; | ||||
@@ -261,7 +261,6 @@ public: | |||||
using namespace DGL_NAMESPACE; | using namespace DGL_NAMESPACE; | ||||
int special = 0; | |||||
switch (value) | switch (value) | ||||
{ | { | ||||
// convert some VST special values to normal keys | // convert some VST special values to normal keys | ||||
@@ -304,37 +303,37 @@ public: | |||||
- kKeyCapsLock | - kKeyCapsLock | ||||
- kKeyPrintScreen | - 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: | case kKeyShift: | ||||
if (down) | if (down) | ||||
@@ -356,15 +355,26 @@ public: | |||||
break; | break; | ||||
} | } | ||||
if (special != 0) | |||||
{ | |||||
fUI.handlePluginSpecial(down, static_cast<Key>(special), fKeyboardModifiers); | |||||
return 1; | |||||
} | |||||
if (index > 0) | 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; | return 1; | ||||
} | } | ||||
@@ -1056,7 +1066,7 @@ public: | |||||
void vst_setParameter(const int32_t index, const float value) | 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)); | const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); | ||||
// TODO figure out how to detect kVstParameterUsesIntegerMinMax host support, and skip normalization | // TODO figure out how to detect kVstParameterUsesIntegerMinMax host support, and skip normalization | ||||
@@ -1104,7 +1114,7 @@ public: | |||||
fTimePosition.playing = (vstTimeInfo->flags & kVstTransportPlaying); | fTimePosition.playing = (vstTimeInfo->flags & kVstTransportPlaying); | ||||
fTimePosition.bbt.valid = ((vstTimeInfo->flags & kVstTempoValid) != 0 || (vstTimeInfo->flags & kVstTimeSigValid) != 0); | 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; | fTimePosition.bbt.ticksPerBeat = 1920.0; | ||||
if (vstTimeInfo->flags & kVstTempoValid) | if (vstTimeInfo->flags & kVstTempoValid) | ||||
@@ -91,7 +91,7 @@ public: | |||||
g_nextScaleFactor = 0.0; | g_nextScaleFactor = 0.0; | ||||
g_nextBundlePath = nullptr; | g_nextBundlePath = nullptr; | ||||
#else | #else | ||||
// Leave context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp | |||||
// enter context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp | |||||
uiData->window->leaveContext(); | uiData->window->leaveContext(); | ||||
#endif | #endif | ||||
UI::PrivateData::s_nextPrivateData = nullptr; | 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) | void setWindowTitle(const char* const uiTitle) | ||||
{ | { | ||||
uiData->window->setTitle(uiTitle); | uiData->window->setTitle(uiTitle); | ||||
@@ -258,23 +280,25 @@ public: | |||||
} | } | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #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; | DGL_NAMESPACE::Widget::KeyboardEvent ev; | ||||
ev.mod = mods; | |||||
ev.press = press; | 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 | #endif | ||||
@@ -287,6 +311,15 @@ public: | |||||
ui->uiScaleFactorChanged(scaleFactor); | 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) | void setSampleRate(const double sampleRate, const bool doCallback = false) | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); | ||||
@@ -22,7 +22,7 @@ | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
# include "../extra/Sleep.hpp" | # include "../extra/Sleep.hpp" | ||||
#else | #else | ||||
# include "../../dgl/Application.hpp" | |||||
# include "../../dgl/src/ApplicationPrivateData.hpp" | |||||
# include "../../dgl/src/WindowPrivateData.hpp" | # include "../../dgl/src/WindowPrivateData.hpp" | ||||
# include "../../dgl/src/pugl.hpp" | # include "../../dgl/src/pugl.hpp" | ||||
#endif | #endif | ||||
@@ -33,7 +33,13 @@ | |||||
# define DISTRHO_UI_IS_STANDALONE 0 | # define DISTRHO_UI_IS_STANDALONE 0 | ||||
#endif | #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 | # undef DISTRHO_UI_USER_RESIZABLE | ||||
# define DISTRHO_UI_USER_RESIZABLE 0 | # define DISTRHO_UI_USER_RESIZABLE 0 | ||||
#endif | #endif | ||||
@@ -92,6 +98,7 @@ struct PluginApplication | |||||
// these are not needed | // these are not needed | ||||
void idle() {} | void idle() {} | ||||
void quit() {} | void quit() {} | ||||
void triggerIdleCallbacks() {} | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) | ||||
}; | }; | ||||
@@ -113,6 +120,11 @@ public: | |||||
setClassName(className); | setClassName(className); | ||||
} | } | ||||
void triggerIdleCallbacks() | |||||
{ | |||||
pData->triggerIdleCallbacks(); | |||||
} | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) | ||||
}; | }; | ||||
#endif | #endif | ||||
@@ -325,6 +337,15 @@ struct UI::PrivateData { | |||||
# if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE) | # if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE) | ||||
parameterOffset += 1; | parameterOffset += 1; | ||||
# endif | # 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 | #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 | * This library is free software; you can redistribute it and/or modify | ||||
* it under the terms of the GNU Lesser General Public License as | * 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". | 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. | 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. | 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/. | 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> | * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | ||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * 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. | * 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) | #if defined(__APPLE__) || defined(_WIN32) | ||||
# pragma pack(pop) | # pragma pack(pop) | ||||
#endif | #endif | ||||
#if defined(__APPLE__) | #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 | #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> | * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | ||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
@@ -16,9 +16,16 @@ | |||||
#if defined(__APPLE__) | #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) | # if defined(__LP64__) || defined(_LP64) | ||||
# pragma pack(push, 16) | # pragma pack(push, 16) | ||||
# else | # 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> | * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | ||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
@@ -28,8 +28,9 @@ | |||||
typedef uint64_t v3_speaker_arrangement; | typedef uint64_t v3_speaker_arrangement; | ||||
enum { | 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 | 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 | 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_param_value_queue { | ||||
struct v3_funknown; | 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); | V3_ID(0x01263A18, 0xED074F6F, 0x98C9D356, 0x4686F9BA); | ||||
struct v3_param_changes { | struct v3_param_changes { | ||||
struct v3_funknown; | 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); | V3_ID(0xA4779663, 0x0BB64A56, 0xB44384A8, 0x466FEB9D); | ||||
/** | /** | ||||
@@ -121,55 +124,41 @@ struct v3_frame_rate { | |||||
struct v3_chord { | struct v3_chord { | ||||
uint8_t key_note; | uint8_t key_note; | ||||
uint8_t root_note; | uint8_t root_note; | ||||
int16_t chord_mask; | int16_t chord_mask; | ||||
}; | }; | ||||
enum { | 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_SYSTEM_TIME_VALID = 1 << 8, | ||||
V3_PROCESS_CTX_CONT_TIME_VALID = 1 << 17, | |||||
V3_PROCESS_CTX_PROJECT_TIME_VALID = 1 << 9, | 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_BAR_POSITION_VALID = 1 << 11, | ||||
V3_PROCESS_CTX_CYCLE_VALID = 1 << 12, | 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_TIME_SIG_VALID = 1 << 13, | ||||
V3_PROCESS_CTX_CHORD_VALID = 1 << 18, | |||||
V3_PROCESS_CTX_SMPTE_VALID = 1 << 14, | 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 { | struct v3_process_context { | ||||
uint32_t state; | uint32_t state; | ||||
double sample_rate; | double sample_rate; | ||||
int64_t project_time_in_samples; // with loop | int64_t project_time_in_samples; // with loop | ||||
int64_t system_time_ns; | 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 project_time_quarters; | ||||
double bar_position_quarters; | double bar_position_quarters; | ||||
double cycle_start_quarters; | double cycle_start_quarters; | ||||
double cycle_end_quarters; | double cycle_end_quarters; | ||||
double bpm; | double bpm; | ||||
int32_t time_sig_numerator; | int32_t time_sig_numerator; | ||||
int32_t time_sig_denom; | int32_t time_sig_denom; | ||||
struct v3_chord chord; | struct v3_chord chord; | ||||
int32_t smpte_offset_subframes; | int32_t smpte_offset_subframes; | ||||
struct v3_frame_rate frame_rate; | struct v3_frame_rate frame_rate; | ||||
int32_t samples_to_next_clock; | int32_t samples_to_next_clock; | ||||
}; | }; | ||||
@@ -194,10 +183,10 @@ enum { | |||||
struct v3_process_context_requirements { | struct v3_process_context_requirements { | ||||
struct v3_funknown; | 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); | V3_ID(0x2A654303, 0xEF764E3D, 0x95B5FE83, 0x730EF6D0); | ||||
/** | /** | ||||
@@ -207,32 +196,25 @@ static const v3_tuid v3_process_context_requirements_iid = | |||||
struct v3_audio_bus_buffers { | struct v3_audio_bus_buffers { | ||||
int32_t num_channels; | int32_t num_channels; | ||||
uint64_t channel_silence_bitset; | uint64_t channel_silence_bitset; | ||||
union { | union { | ||||
float **channel_buffers_32; | |||||
double **channel_buffers_64; | |||||
float** channel_buffers_32; | |||||
double** channel_buffers_64; | |||||
}; | }; | ||||
}; | }; | ||||
struct v3_process_data { | struct v3_process_data { | ||||
int32_t process_mode; | int32_t process_mode; | ||||
int32_t symbolic_sample_size; | int32_t symbolic_sample_size; | ||||
int32_t nframes; | int32_t nframes; | ||||
int32_t num_input_buses; | int32_t num_input_buses; | ||||
int32_t num_output_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_audio_processor { | ||||
struct v3_funknown; | 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" | #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> | * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | ||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
@@ -20,6 +20,39 @@ | |||||
#include <stdint.h> | #include <stdint.h> | ||||
#include <string.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 | * various types | ||||
*/ | */ | ||||
@@ -31,15 +64,14 @@ typedef uint8_t v3_bool; | |||||
typedef uint32_t v3_param_id; | typedef uint32_t v3_param_id; | ||||
/** | /** | ||||
* low-level ABI nonsense | * low-level ABI nonsense | ||||
*/ | */ | ||||
typedef uint8_t v3_tuid[16]; | 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; | 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 | #if V3_COM_COMPAT | ||||
enum { | 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 | #else // V3_COM_COMPAT | ||||
enum { | enum { | ||||
V3_NO_INTERFACE = -1, | |||||
V3_NO_INTERFACE = -1, | |||||
V3_OK, | V3_OK, | ||||
V3_TRUE = V3_OK, | V3_TRUE = V3_OK, | ||||
V3_FALSE, | V3_FALSE, | ||||
V3_INVALID_ARG, | V3_INVALID_ARG, | ||||
V3_NOT_IMPLEMENTED, | V3_NOT_IMPLEMENTED, | ||||
V3_INTERNAL_ERR, | V3_INTERNAL_ERR, | ||||
V3_NOT_INITIALISED, | |||||
V3_NOT_INITIALIZED, | |||||
V3_NOMEM | 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 | #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 | * funknown | ||||
*/ | */ | ||||
struct v3_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); | V3_ID(0x00000000, 0x00000000, 0xC0000000, 0x00000046); | ||||
/** | /** | ||||
@@ -145,10 +179,35 @@ static const v3_tuid v3_funknown_iid = | |||||
struct v3_plugin_base { | struct v3_plugin_base { | ||||
struct v3_funknown; | 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); | 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> | * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | ||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * 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_bstream { | ||||
struct v3_funknown; | 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); | 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> | * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | ||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
@@ -30,13 +30,17 @@ enum v3_media_types { | |||||
V3_EVENT | 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 | 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 { | enum v3_bus_flags { | ||||
V3_DEFAULT_ACTIVE = 1, | |||||
V3_DEFAULT_ACTIVE = 1 << 0, | |||||
V3_IS_CONTROL_VOLTAGE = 1 << 1 | V3_IS_CONTROL_VOLTAGE = 1 << 1 | ||||
}; | }; | ||||
@@ -69,7 +77,6 @@ struct v3_bus_info { | |||||
int32_t media_type; | int32_t media_type; | ||||
int32_t direction; | int32_t direction; | ||||
int32_t channel_count; | int32_t channel_count; | ||||
v3_str_128 bus_name; | v3_str_128 bus_name; | ||||
int32_t bus_type; | int32_t bus_type; | ||||
uint32_t flags; | uint32_t flags; | ||||
@@ -84,34 +91,44 @@ struct v3_routing_info; | |||||
struct v3_component { | struct v3_component { | ||||
struct v3_plugin_base; | 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); | 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" | #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> | * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | ||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
@@ -26,21 +26,29 @@ | |||||
* component handler | * 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_component_handler { | ||||
struct v3_funknown; | 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); | V3_ID(0x93A0BEA3, 0x0BD045DB, 0x8E890B0C, 0xC1E46AC6); | ||||
/** | /** | ||||
@@ -48,7 +56,7 @@ static const v3_tuid v3_component_handler_iid = | |||||
*/ | */ | ||||
enum { | enum { | ||||
V3_PARAM_CAN_AUTOMATE = 1, | |||||
V3_PARAM_CAN_AUTOMATE = 1 << 0, | |||||
V3_PARAM_READ_ONLY = 1 << 1, | V3_PARAM_READ_ONLY = 1 << 1, | ||||
V3_PARAM_WRAP_AROUND = 1 << 2, | V3_PARAM_WRAP_AROUND = 1 << 2, | ||||
V3_PARAM_IS_LIST = 1 << 3, | V3_PARAM_IS_LIST = 1 << 3, | ||||
@@ -59,15 +67,11 @@ enum { | |||||
struct v3_param_info { | struct v3_param_info { | ||||
v3_param_id param_id; | v3_param_id param_id; | ||||
v3_str_128 title; | v3_str_128 title; | ||||
v3_str_128 short_title; | v3_str_128 short_title; | ||||
v3_str_128 units; | v3_str_128 units; | ||||
int32_t step_count; | int32_t step_count; | ||||
double default_normalised_value; | double default_normalised_value; | ||||
int32_t unit_id; | int32_t unit_id; | ||||
int32_t flags; | int32_t flags; | ||||
}; | }; | ||||
@@ -75,39 +79,63 @@ struct v3_param_info { | |||||
struct v3_edit_controller { | struct v3_edit_controller { | ||||
struct v3_plugin_base; | 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" | #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> | * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | ||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
@@ -22,18 +22,13 @@ | |||||
/** | /** | ||||
* note events | * note events | ||||
* | |||||
* i know there's others, but we don't need them right now. whatever. | |||||
* handle them later. | |||||
*/ | */ | ||||
struct v3_event_note_on { | struct v3_event_note_on { | ||||
int16_t channel; | int16_t channel; | ||||
int16_t pitch; // MIDI note number | int16_t pitch; // MIDI note number | ||||
float tuning; | float tuning; | ||||
float velocity; | float velocity; | ||||
int32_t length; | int32_t length; | ||||
int32_t note_id; | int32_t note_id; | ||||
}; | }; | ||||
@@ -41,9 +36,7 @@ struct v3_event_note_on { | |||||
struct v3_event_note_off { | struct v3_event_note_off { | ||||
int16_t channel; | int16_t channel; | ||||
int16_t pitch; // MIDI note number | int16_t pitch; // MIDI note number | ||||
float velocity; | float velocity; | ||||
int32_t note_id; | int32_t note_id; | ||||
float tuning; | float tuning; | ||||
}; | }; | ||||
@@ -51,14 +44,12 @@ struct v3_event_note_off { | |||||
struct v3_event_data { | struct v3_event_data { | ||||
uint32_t size; | uint32_t size; | ||||
uint32_t type; | uint32_t type; | ||||
const uint8_t *bytes; | |||||
const uint8_t* bytes; | |||||
}; | }; | ||||
struct v3_event_poly_pressure { | struct v3_event_poly_pressure { | ||||
int16_t channel; | int16_t channel; | ||||
int16_t pitch; | int16_t pitch; | ||||
float pressure; | float pressure; | ||||
int32_t note_id; | int32_t note_id; | ||||
}; | }; | ||||
@@ -67,22 +58,19 @@ struct v3_event_chord { | |||||
int16_t root; | int16_t root; | ||||
int16_t bass_note; | int16_t bass_note; | ||||
int16_t mask; | int16_t mask; | ||||
uint16_t text_len; | uint16_t text_len; | ||||
const int16_t *text; | |||||
const int16_t* text; | |||||
}; | }; | ||||
struct v3_event_scale { | struct v3_event_scale { | ||||
int16_t root; | int16_t root; | ||||
int16_t mask; | int16_t mask; | ||||
uint16_t text_len; | uint16_t text_len; | ||||
const int16_t *text; | |||||
const int16_t* text; | |||||
}; | }; | ||||
struct v3_event_legacy_midi_cc_out { | struct v3_event_legacy_midi_cc_out { | ||||
uint8_t cc_number; | uint8_t cc_number; | ||||
int8_t channel; | int8_t channel; | ||||
int8_t value; | int8_t value; | ||||
int8_t value2; | int8_t value2; | ||||
@@ -96,9 +84,8 @@ struct v3_event_note_expression_value { | |||||
struct v3_event_note_expression_text { | struct v3_event_note_expression_text { | ||||
int32_t note_id; | int32_t note_id; | ||||
uint32_t text_len; | 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 { | enum v3_event_flags { | ||||
V3_EVENT_IS_LIVE = 1 | |||||
V3_EVENT_IS_LIVE = 1 << 0 | |||||
}; | }; | ||||
enum v3_event_type { | enum v3_event_type { | ||||
@@ -118,19 +105,15 @@ enum v3_event_type { | |||||
V3_EVENT_NOTE_EXP_TEXT = 5, | V3_EVENT_NOTE_EXP_TEXT = 5, | ||||
V3_EVENT_CHORD = 6, | V3_EVENT_CHORD = 6, | ||||
V3_EVENT_SCALE = 7, | V3_EVENT_SCALE = 7, | ||||
V3_EVENT_LEGACY_MIDI_CC_OUT = 65535 | V3_EVENT_LEGACY_MIDI_CC_OUT = 65535 | ||||
}; | }; | ||||
struct v3_event { | struct v3_event { | ||||
int32_t bus_index; | int32_t bus_index; | ||||
int32_t sample_offset; | int32_t sample_offset; | ||||
double ppq_position; | double ppq_position; | ||||
uint16_t flags; | uint16_t flags; | ||||
uint16_t type; | uint16_t type; | ||||
union { | union { | ||||
struct v3_event_note_on note_on; | struct v3_event_note_on note_on; | ||||
struct v3_event_note_off note_off; | struct v3_event_note_off note_off; | ||||
@@ -151,14 +134,12 @@ struct v3_event { | |||||
struct v3_event_list { | struct v3_event_list { | ||||
struct v3_funknown; | 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); | V3_ID(0x3A2C4214, 0x346349FE, 0xB2C4F397, 0xB9695A44); | ||||
#include "align_pop.h" | #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> | * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | ||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * 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 vendor[64]; | ||||
char url[256]; | char url[256]; | ||||
char email[128]; | char email[128]; | ||||
int32_t flags; | |||||
int32_t flags; // set to 0x10 (unicode) | |||||
}; | }; | ||||
struct v3_class_info { | struct v3_class_info { | ||||
v3_tuid class_id; | v3_tuid class_id; | ||||
int32_t cardinality; // set to 0x7FFFFFFF | |||||
int32_t cardinality; // set to 0x7FFFFFFF (many instances) | |||||
char category[32]; | char category[32]; | ||||
char name[64]; | char name[64]; | ||||
}; | }; | ||||
@@ -39,31 +39,29 @@ struct v3_class_info { | |||||
struct v3_plugin_factory { | struct v3_plugin_factory { | ||||
struct v3_funknown; | 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); | V3_ID(0x7A4D811C, 0x52114A1F, 0xAED9D2EE, 0x0B43BF9F); | ||||
/** | /** | ||||
* plugin factory v2 | * plugin factory v2 | ||||
*/ | */ | ||||
enum { | |||||
V3_DISTRIBUTABLE = 1 << 0, | |||||
V3_SIMPLE_MODE = 1 << 1 | |||||
}; | |||||
struct v3_class_info_2 { | struct v3_class_info_2 { | ||||
v3_tuid class_id; | v3_tuid class_id; | ||||
int32_t cardinality; // set to 0x7FFFFFFF | int32_t cardinality; // set to 0x7FFFFFFF | ||||
char category[32]; | char category[32]; | ||||
char name[64]; | char name[64]; | ||||
uint32_t class_flags; | uint32_t class_flags; | ||||
char sub_categories[128]; | char sub_categories[128]; | ||||
char vendor[64]; | char vendor[64]; | ||||
@@ -74,11 +72,10 @@ struct v3_class_info_2 { | |||||
struct v3_plugin_factory_2 { | struct v3_plugin_factory_2 { | ||||
struct v3_plugin_factory; | 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); | V3_ID(0x0007B650, 0xF24B4C0B, 0xA464EDB9, 0xF00B2ABB); | ||||
/** | /** | ||||
@@ -93,7 +90,6 @@ struct v3_class_info_3 { | |||||
int32_t cardinality; // set to 0x7FFFFFFF | int32_t cardinality; // set to 0x7FFFFFFF | ||||
char category[32]; | char category[32]; | ||||
int16_t name[64]; | int16_t name[64]; | ||||
uint32_t class_flags; | uint32_t class_flags; | ||||
char sub_categories[128]; | char sub_categories[128]; | ||||
int16_t vendor[64]; | int16_t vendor[64]; | ||||
@@ -104,12 +100,23 @@ struct v3_class_info_3 { | |||||
struct v3_plugin_factory_3 { | struct v3_plugin_factory_3 { | ||||
struct v3_plugin_factory_2; | 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); | 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> | * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> | ||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
@@ -19,7 +19,7 @@ | |||||
#include "base.h" | #include "base.h" | ||||
/** | /** | ||||
* base IPlugFrame stuff | |||||
* base view stuff | |||||
*/ | */ | ||||
struct v3_view_rect { | struct v3_view_rect { | ||||
@@ -41,50 +41,43 @@ struct v3_view_rect { | |||||
# define V3_VIEW_PLATFORM_TYPE_NATIVE V3_VIEW_PLATFORM_TYPE_X11 | # define V3_VIEW_PLATFORM_TYPE_NATIVE V3_VIEW_PLATFORM_TYPE_X11 | ||||
#endif | #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); | V3_ID(0x5BC32507, 0xD06049EA, 0xA6151B52, 0x2B755B29); | ||||
struct v3_plug_frame { | |||||
/** | |||||
* plugin frame | |||||
*/ | |||||
struct v3_plugin_frame { | |||||
struct v3_funknown; | 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); | 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) | * (same IID/iface as presonus view scaling) | ||||
*/ | */ | ||||
struct v3_plug_view_content_scale_steinberg { | |||||
struct v3_plugin_view_content_scale { | |||||
struct v3_funknown; | 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); | V3_ID(0x65ED9690, 0x8AC44525, 0x8AADEF7A, 0x72EA703F); | ||||
/** | /** | ||||
* support for querying the view to find what control is underneath the mouse | * 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; | 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); | 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 | #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"); | const TTL_Generator_Function ttlFn = (TTL_Generator_Function)GetProcAddress(handle, "lv2_generate_ttl"); | ||||
# if defined(__GNUC__) && (__GNUC__ >= 9) | |||||
# pragma GCC diagnostic pop | |||||
# endif | |||||
#else | #else | ||||
const TTL_Generator_Function ttlFn = (TTL_Generator_Function)dlsym(handle, "lv2_generate_ttl"); | const TTL_Generator_Function ttlFn = (TTL_Generator_Function)dlsym(handle, "lv2_generate_ttl"); | ||||
#endif | #endif | ||||
@@ -14,10 +14,12 @@ SNAME="$(echo ${NAME} | tr -d ' ' | tr '/' '-')" | |||||
rm -rf lv2 | rm -rf lv2 | ||||
rm -rf vst2 | rm -rf vst2 | ||||
rm -rf vst3 | |||||
mkdir lv2 vst2 | |||||
mkdir lv2 vst2 vst3 | |||||
mv *.lv2 lv2/ | mv *.lv2 lv2/ | ||||
mv *.vst vst2/ | mv *.vst vst2/ | ||||
mv *.vst3 vst3/ | |||||
pkgbuild \ | pkgbuild \ | ||||
--identifier "studio.kx.distrho.plugins.${SNAME}.lv2bundles" \ | --identifier "studio.kx.distrho.plugins.${SNAME}.lv2bundles" \ | ||||
@@ -31,6 +33,12 @@ pkgbuild \ | |||||
--root "${PWD}/vst2/" \ | --root "${PWD}/vst2/" \ | ||||
../dpf-${SNAME}-vst2bundles.pkg | ../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 .. | cd .. | ||||
DPF_UTILS_DIR=$(dirname ${0}) | 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|" \ | sed -e "s|@builddir@|${PWD}/build|" \ | ||||
-e "s|@lv2bundleref@|dpf-${SNAME}-lv2bundles.pkg|" \ | -e "s|@lv2bundleref@|dpf-${SNAME}-lv2bundles.pkg|" \ | ||||
-e "s|@vst2bundleref@|dpf-${SNAME}-vst2bundles.pkg|" \ | -e "s|@vst2bundleref@|dpf-${SNAME}-vst2bundles.pkg|" \ | ||||
-e "s|@vst3bundleref@|dpf-${SNAME}-vst3bundles.pkg|" \ | |||||
-e "s|@name@|${NAME}|g" \ | -e "s|@name@|${NAME}|g" \ | ||||
-e "s|@sname@|${SNAME}|g" \ | -e "s|@sname@|${SNAME}|g" \ | ||||
${DPF_UTILS_DIR}/plugin.pkg/package.xml.in > build/package.xml | ${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"> | <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> | <pkg-ref id="studio.kx.distrho.@sname@-vst2bundles" version="0">@vst2bundleref@</pkg-ref> | ||||
</choice> | </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> | <choices-outline> | ||||
<line choice="studio.kx.distrho.@sname@-lv2"/> | <line choice="studio.kx.distrho.@sname@-lv2"/> | ||||
<line choice="studio.kx.distrho.@sname@-vst2"/> | <line choice="studio.kx.distrho.@sname@-vst2"/> | ||||
<line choice="studio.kx.distrho.@sname@-vst3"/> | |||||
</choices-outline> | </choices-outline> | ||||
</installer-gui-script> | </installer-gui-script> |
@@ -39,3 +39,10 @@ | |||||
fun:XInitThreads | fun:XInitThreads | ||||
... | ... | ||||
} | } | ||||
{ | |||||
ignore XrmGetStringDatabase | |||||
Memcheck:Leak | |||||
... | |||||
fun:XrmGetStringDatabase | |||||
... | |||||
} |