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