Browse Source

Update DPF

Signed-off-by: falkTX <falktx@falktx.com>
tags/v1.5
falkTX 3 years ago
parent
commit
64e02a25d3
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
58 changed files with 6098 additions and 1272 deletions
  1. +93
    -0
      dpf/FEATURES.md
  2. +47
    -0
      dpf/LICENSING.md
  3. +12
    -2
      dpf/Makefile.plugins.mk
  4. +6
    -0
      dpf/README.md
  5. +1
    -0
      dpf/dgl/Application.hpp
  6. +8
    -8
      dpf/dgl/Base.hpp
  7. +4
    -4
      dpf/dgl/NanoVG.hpp
  8. +0
    -1
      dpf/dgl/TopLevelWidget.hpp
  9. +22
    -14
      dpf/dgl/Widget.hpp
  10. +3
    -3
      dpf/dgl/Window.hpp
  11. +1
    -0
      dpf/dgl/src/.kdev_include_paths
  12. +5
    -0
      dpf/dgl/src/ApplicationPrivateData.cpp
  13. +3
    -0
      dpf/dgl/src/ApplicationPrivateData.hpp
  14. +0
    -5
      dpf/dgl/src/TopLevelWidget.cpp
  15. +0
    -14
      dpf/dgl/src/TopLevelWidgetPrivateData.cpp
  16. +0
    -1
      dpf/dgl/src/TopLevelWidgetPrivateData.hpp
  17. +0
    -5
      dpf/dgl/src/Widget.cpp
  18. +0
    -18
      dpf/dgl/src/WidgetPrivateData.cpp
  19. +0
    -1
      dpf/dgl/src/WidgetPrivateData.hpp
  20. +2
    -18
      dpf/dgl/src/Window.cpp
  21. +13
    -22
      dpf/dgl/src/WindowPrivateData.cpp
  22. +0
    -1
      dpf/dgl/src/WindowPrivateData.hpp
  23. +166
    -7
      dpf/distrho/DistrhoInfo.hpp
  24. +6
    -1
      dpf/distrho/DistrhoPlugin.hpp
  25. +1
    -1
      dpf/distrho/DistrhoUIMain.cpp
  26. +19
    -1
      dpf/distrho/extra/LeakDetector.hpp
  27. +19
    -1
      dpf/distrho/extra/ScopedPointer.hpp
  28. +1
    -1
      dpf/distrho/extra/String.hpp
  29. +5
    -2
      dpf/distrho/src/DistrhoDefines.h
  30. +2
    -2
      dpf/distrho/src/DistrhoPlugin.cpp
  31. +0
    -1
      dpf/distrho/src/DistrhoPluginChecks.h
  32. +50
    -21
      dpf/distrho/src/DistrhoPluginInternal.hpp
  33. +49
    -39
      dpf/distrho/src/DistrhoPluginVST2.cpp
  34. +3594
    -186
      dpf/distrho/src/DistrhoPluginVST3.cpp
  35. +47
    -14
      dpf/distrho/src/DistrhoUIInternal.hpp
  36. +23
    -2
      dpf/distrho/src/DistrhoUIPrivateData.hpp
  37. +1189
    -0
      dpf/distrho/src/DistrhoUIVST3.cpp
  38. +10
    -0
      dpf/distrho/src/dssi/seq_event-compat.h
  39. +0
    -249
      dpf/distrho/src/lv2/atom-helpers.h
  40. +0
    -98
      dpf/distrho/src/lv2/lv2-midifunctions.h
  41. +0
    -175
      dpf/distrho/src/lv2/lv2-miditype.h
  42. +3
    -3
      dpf/distrho/src/travesty/README.txt
  43. +17
    -2
      dpf/distrho/src/travesty/align_pop.h
  44. +11
    -4
      dpf/distrho/src/travesty/align_push.h
  45. +84
    -89
      dpf/distrho/src/travesty/audio_processor.h
  46. +124
    -65
      dpf/distrho/src/travesty/base.h
  47. +6
    -10
      dpf/distrho/src/travesty/bstream.h
  48. +58
    -41
      dpf/distrho/src/travesty/component.h
  49. +70
    -42
      dpf/distrho/src/travesty/edit_controller.h
  50. +10
    -29
      dpf/distrho/src/travesty/events.h
  51. +32
    -25
      dpf/distrho/src/travesty/factory.h
  52. +49
    -0
      dpf/distrho/src/travesty/host.h
  53. +93
    -0
      dpf/distrho/src/travesty/message.h
  54. +112
    -43
      dpf/distrho/src/travesty/view.h
  55. +7
    -0
      dpf/utils/lv2-ttl-generator/lv2_ttl_generator.c
  56. +10
    -1
      dpf/utils/package-osx-bundles.sh
  57. +4
    -0
      dpf/utils/plugin.pkg/package.xml.in
  58. +7
    -0
      dpf/utils/valgrind-dpf.supp

+ 93
- 0
dpf/FEATURES.md View File

@@ -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.

+ 47
- 0
dpf/LICENSING.md View File

@@ -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.

+ 12
- 2
dpf/Makefile.plugins.mk View File

@@ -33,7 +33,6 @@ endif


BUILD_C_FLAGS += -I. BUILD_C_FLAGS += -I.
BUILD_CXX_FLAGS += -I. -I$(DPF_PATH)/distrho -I$(DPF_PATH)/dgl BUILD_CXX_FLAGS += -I. -I$(DPF_PATH)/distrho -I$(DPF_PATH)/dgl
BUILD_CXX_FLAGS += -Wno-pmf-conversions


ifeq ($(HAVE_ALSA),true) ifeq ($(HAVE_ALSA),true)
BASE_FLAGS += -DHAVE_ALSA BASE_FLAGS += -DHAVE_ALSA
@@ -128,7 +127,7 @@ SYMBOLS_LV2UI = $(DPF_PATH)/utils/symbols/lv2-ui.def
SYMBOLS_LV2 = $(DPF_PATH)/utils/symbols/lv2.def SYMBOLS_LV2 = $(DPF_PATH)/utils/symbols/lv2.def
SYMBOLS_VST2 = $(DPF_PATH)/utils/symbols/vst2.def SYMBOLS_VST2 = $(DPF_PATH)/utils/symbols/vst2.def
SYMBOLS_VST3 = $(DPF_PATH)/utils/symbols/vst3.def SYMBOLS_VST3 = $(DPF_PATH)/utils/symbols/vst3.def
else
else ifneq ($(DEBUG),true)
SYMBOLS_LADSPA = -Wl,--version-script=$(DPF_PATH)/utils/symbols/ladspa.version SYMBOLS_LADSPA = -Wl,--version-script=$(DPF_PATH)/utils/symbols/ladspa.version
SYMBOLS_DSSI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/dssi.version SYMBOLS_DSSI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/dssi.version
SYMBOLS_LV2DSP = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2-dsp.version SYMBOLS_LV2DSP = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2-dsp.version
@@ -224,6 +223,13 @@ endif
# TODO split dsp and ui object build flags # TODO split dsp and ui object build flags
BASE_FLAGS += $(DGL_FLAGS) BASE_FLAGS += $(DGL_FLAGS)


# ---------------------------------------------------------------------------------------------------------------------
# Runtime test build

ifeq ($(DPF_RUNTIME_TESTING),true)
BUILD_CXX_FLAGS += -DDPF_RUNTIME_TESTING -Wno-pmf-conversions
endif

# --------------------------------------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------------------------------------
# all needs to be first # all needs to be first


@@ -386,7 +392,11 @@ endif


vst3: $(vst3) vst3: $(vst3)


ifeq ($(HAVE_DGL),true)
$(vst3): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.o $(DGL_LIB)
else
$(vst3): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o $(vst3): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o
endif
-@mkdir -p $(shell dirname $@) -@mkdir -p $(shell dirname $@)
@echo "Creating VST3 plugin for $(NAME)" @echo "Creating VST3 plugin for $(NAME)"
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_VST3) -o $@ $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_VST3) -o $@


+ 6
- 0
dpf/README.md View File

@@ -19,6 +19,12 @@ Getting time information from the host is possible.<br/>
It uses the same format as the JACK Transport API, making porting some code easier.<br/> It uses the same format as the JACK Transport API, making porting some code easier.<br/>




## Licensing

DPF is released under ISC, which basically means you can do whatever you want as long as you credit the original authors.
Some plugin formats may have additional restrictions, see [LICENSING.md](LICENSING.md) for details.


## Help and documentation ## Help and documentation


Bug reports happen on the [DPF github project](https://github.com/DISTRHO/DPF/issues). Bug reports happen on the [DPF github project](https://github.com/DISTRHO/DPF/issues).


+ 1
- 0
dpf/dgl/Application.hpp View File

@@ -107,6 +107,7 @@ public:
private: private:
struct PrivateData; struct PrivateData;
PrivateData* const pData; PrivateData* const pData;
friend class PluginApplication;
friend class Window; friend class Window;


DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Application) DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Application)


+ 8
- 8
dpf/dgl/Base.hpp View File

@@ -49,16 +49,16 @@ enum Modifier {
/** /**
Keyboard key codepoints. Keyboard key codepoints.


All keys are identified by a Unicode code point in PuglEventKey::key. This
enumeration defines constants for special keys that do not have a standard
code point, and some convenience constants for control characters. Note
that all keys are handled in the same way, this enumeration is just for
All keys are identified by a Unicode code point in Widget::KeyboardEvent::key.
This enumeration defines constants for special keys that do not have a standard
code point, and some convenience constants for control characters.
Note that all keys are handled in the same way, this enumeration is just for
convenience when writing hard-coded key bindings. convenience when writing hard-coded key bindings.


Keys that do not have a standard code point use values in the Private Use Keys that do not have a standard code point use values in the Private Use
Area in the Basic Multilingual Plane (`U+E000` to `U+F8FF`). Applications
must take care to not interpret these values beyond key detection, the
mapping used here is arbitrary and specific to DPF.
Area in the Basic Multilingual Plane (`U+E000` to `U+F8FF`).
Applications must take care to not interpret these values beyond key detection,
the mapping used here is arbitrary and specific to DPF.
*/ */
enum Key { enum Key {
// Convenience symbols for ASCII control characters // Convenience symbols for ASCII control characters
@@ -116,7 +116,7 @@ enum Key {
/** /**
Common flags for all events. Common flags for all events.
*/ */
enum Flag {
enum EventFlag {
kFlagSendEvent = 1, ///< Event is synthetic kFlagSendEvent = 1, ///< Event is synthetic
kFlagIsHint = 2 ///< Event is a hint (not direct user input) kFlagIsHint = 2 ///< Event is a hint (not direct user input)
}; };


+ 4
- 4
dpf/dgl/NanoVG.hpp View File

@@ -903,7 +903,7 @@ public:
Constructor for a NanoSubWidget. Constructor for a NanoSubWidget.
@see CreateFlags @see CreateFlags
*/ */
explicit NanoBaseWidget(Widget* const parentGroupWidget, int flags = CREATE_ANTIALIAS);
explicit NanoBaseWidget(Widget* parentGroupWidget, int flags = CREATE_ANTIALIAS);


/** /**
Constructor for a NanoTopLevelWidget. Constructor for a NanoTopLevelWidget.
@@ -912,16 +912,16 @@ public:
explicit NanoBaseWidget(Window& windowToMapTo, int flags = CREATE_ANTIALIAS); explicit NanoBaseWidget(Window& windowToMapTo, int flags = CREATE_ANTIALIAS);


/** /**
Constructor for a NanoStandaloneWindow without parent window.
Constructor for a NanoStandaloneWindow without transient parent window.
@see CreateFlags @see CreateFlags
*/ */
explicit NanoBaseWidget(Application& app, int flags = CREATE_ANTIALIAS); explicit NanoBaseWidget(Application& app, int flags = CREATE_ANTIALIAS);


/** /**
Constructor for a NanoStandaloneWindow with parent window.
Constructor for a NanoStandaloneWindow with transient parent window.
@see CreateFlags @see CreateFlags
*/ */
explicit NanoBaseWidget(Application& app, Window& parentWindow, int flags = CREATE_ANTIALIAS);
explicit NanoBaseWidget(Application& app, Window& transientParentWindow, int flags = CREATE_ANTIALIAS);


/** /**
Destructor. Destructor.


+ 0
- 1
dpf/dgl/TopLevelWidget.hpp View File

@@ -117,7 +117,6 @@ public:


protected: protected:
bool onKeyboard(const KeyboardEvent&) override; bool onKeyboard(const KeyboardEvent&) override;
bool onSpecial(const SpecialEvent&) override;
bool onCharacterInput(const CharacterInputEvent&) override; bool onCharacterInput(const CharacterInputEvent&) override;
bool onMouse(const MouseEvent&) override; bool onMouse(const MouseEvent&) override;
bool onMotion(const MotionEvent&) override; bool onMotion(const MotionEvent&) override;


+ 22
- 14
dpf/dgl/Widget.hpp View File

@@ -58,7 +58,7 @@ public:
These are the fields present on all Widget events. These are the fields present on all Widget events.


@a mod Currently active keyboard modifiers, @see Modifier. @a mod Currently active keyboard modifiers, @see Modifier.
@a mod Event flags, @see Flag.
@a mod Event flags, @see EventFlag.
@a time Event timestamp (if any). @a time Event timestamp (if any).
*/ */
struct BaseEvent { struct BaseEvent {
@@ -107,14 +107,10 @@ public:
/** /**
Special keyboard event. Special keyboard event.


This event allows the use of keys that do not have unicode points.
Note that some are non-printable keys.

@a press True if the key was pressed, false if released.
@a key The key pressed.
@see onSpecial
DEPRECATED This used to be part of DPF due to pugl, but now deprecated and simply non-functional.
All events go through KeyboardEvent or CharacterInputEvent, use those instead.
*/ */
struct SpecialEvent : BaseEvent {
struct DISTRHO_DEPRECATED_BY("KeyboardEvent") SpecialEvent : BaseEvent {
bool press; bool press;
Key key; Key key;


@@ -398,12 +394,6 @@ protected:
*/ */
virtual bool onKeyboard(const KeyboardEvent&); virtual bool onKeyboard(const KeyboardEvent&);


/**
A function called when a special key is pressed or released.
@return True to stop event propagation, false otherwise.
*/
virtual bool onSpecial(const SpecialEvent&);

/** /**
A function called when an UTF-8 character is received. A function called when an UTF-8 character is received.
@return True to stop event propagation, false otherwise. @return True to stop event propagation, false otherwise.
@@ -433,6 +423,24 @@ protected:
*/ */
virtual void onResize(const ResizeEvent&); virtual void onResize(const ResizeEvent&);


/**
A function called when a special key is pressed or released.
DEPRECATED use onKeyboard or onCharacterInput
*/
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 460
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
virtual bool onSpecial(const SpecialEvent&) { return false; }
#if defined(__clang__)
# pragma clang diagnostic pop
#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 460
# pragma GCC diagnostic pop
#endif

private: private:
struct PrivateData; struct PrivateData;
PrivateData* const pData; PrivateData* const pData;


+ 3
- 3
dpf/dgl/Window.hpp View File

@@ -157,10 +157,10 @@ public:
explicit Window(Application& app); explicit Window(Application& app);


/** /**
Constructor for a modal window, by having another window as its parent.
Constructor for a modal window, by having another window as its transient parent.
The Application instance must be the same between the 2 windows. The Application instance must be the same between the 2 windows.
*/ */
explicit Window(Application& app, Window& parent);
explicit Window(Application& app, Window& transientParentWindow);


/** /**
Constructor for an embed Window without known size, Constructor for an embed Window without known size,
@@ -369,7 +369,7 @@ public:


This function does not block the event loop. This function does not block the event loop.
*/ */
bool openFileBrowser(const FileBrowserOptions& options);
bool openFileBrowser(const FileBrowserOptions& options = FileBrowserOptions());
#endif #endif


/** /**


+ 1
- 0
dpf/dgl/src/.kdev_include_paths View File

@@ -0,0 +1 @@
pugl-upstream/include/

+ 5
- 0
dpf/dgl/src/ApplicationPrivateData.cpp View File

@@ -118,6 +118,11 @@ void Application::PrivateData::idle(const uint timeoutInMs)
puglUpdate(world, timeoutInSeconds); puglUpdate(world, timeoutInSeconds);
} }


triggerIdleCallbacks();
}

void Application::PrivateData::triggerIdleCallbacks()
{
for (std::list<IdleCallback*>::iterator it = idleCallbacks.begin(), ite = idleCallbacks.end(); it != ite; ++it) for (std::list<IdleCallback*>::iterator it = idleCallbacks.begin(), ite = idleCallbacks.end(); it != ite; ++it)
{ {
IdleCallback* const idleCallback(*it); IdleCallback* const idleCallback(*it);


+ 3
- 0
dpf/dgl/src/ApplicationPrivateData.hpp View File

@@ -84,6 +84,9 @@ struct Application::PrivateData {
/** Run Pugl world update for @a timeoutInMs, and then each idle callback in order of registration. */ /** Run Pugl world update for @a timeoutInMs, and then each idle callback in order of registration. */
void idle(uint timeoutInMs); void idle(uint timeoutInMs);


/** Run each idle callback without updating pugl world. */
void triggerIdleCallbacks();

/** Set flag indicating application is quitting, and close all windows in reverse order of registration. /** Set flag indicating application is quitting, and close all windows in reverse order of registration.
For standalone mode only. */ For standalone mode only. */
void quit(); void quit();


+ 0
- 5
dpf/dgl/src/TopLevelWidget.cpp View File

@@ -100,11 +100,6 @@ bool TopLevelWidget::onKeyboard(const KeyboardEvent&)
return false; return false;
} }


bool TopLevelWidget::onSpecial(const SpecialEvent&)
{
return false;
}

bool TopLevelWidget::onCharacterInput(const CharacterInputEvent&) bool TopLevelWidget::onCharacterInput(const CharacterInputEvent&)
{ {
return false; return false;


+ 0
- 14
dpf/dgl/src/TopLevelWidgetPrivateData.cpp View File

@@ -50,20 +50,6 @@ bool TopLevelWidget::PrivateData::keyboardEvent(const KeyboardEvent& ev)
return selfw->pData->giveKeyboardEventForSubWidgets(ev); return selfw->pData->giveKeyboardEventForSubWidgets(ev);
} }


bool TopLevelWidget::PrivateData::specialEvent(const SpecialEvent& ev)
{
// ignore event if we are not visible
if (! selfw->pData->visible)
return false;

// give top-level widget chance to catch this event first
if (self->onSpecial(ev))
return true;

// propagate event to all subwidgets recursively
return selfw->pData->giveSpecialEventForSubWidgets(ev);
}

bool TopLevelWidget::PrivateData::characterInputEvent(const CharacterInputEvent& ev) bool TopLevelWidget::PrivateData::characterInputEvent(const CharacterInputEvent& ev)
{ {
// ignore event if we are not visible // ignore event if we are not visible


+ 0
- 1
dpf/dgl/src/TopLevelWidgetPrivateData.hpp View File

@@ -34,7 +34,6 @@ struct TopLevelWidget::PrivateData {
~PrivateData(); ~PrivateData();
void display(); void display();
bool keyboardEvent(const KeyboardEvent& ev); bool keyboardEvent(const KeyboardEvent& ev);
bool specialEvent(const SpecialEvent& ev);
bool characterInputEvent(const CharacterInputEvent& ev); bool characterInputEvent(const CharacterInputEvent& ev);
bool mouseEvent(const MouseEvent& ev); bool mouseEvent(const MouseEvent& ev);
bool motionEvent(const MotionEvent& ev); bool motionEvent(const MotionEvent& ev);


+ 0
- 5
dpf/dgl/src/Widget.cpp View File

@@ -167,11 +167,6 @@ bool Widget::onKeyboard(const KeyboardEvent& ev)
return pData->giveKeyboardEventForSubWidgets(ev); return pData->giveKeyboardEventForSubWidgets(ev);
} }


bool Widget::onSpecial(const SpecialEvent& ev)
{
return pData->giveSpecialEventForSubWidgets(ev);
}

bool Widget::onCharacterInput(const CharacterInputEvent& ev) bool Widget::onCharacterInput(const CharacterInputEvent& ev)
{ {
return pData->giveCharacterInputEventForSubWidgets(ev); return pData->giveCharacterInputEventForSubWidgets(ev);


+ 0
- 18
dpf/dgl/src/WidgetPrivateData.cpp View File

@@ -87,24 +87,6 @@ bool Widget::PrivateData::giveKeyboardEventForSubWidgets(const KeyboardEvent& ev
return false; return false;
} }


bool Widget::PrivateData::giveSpecialEventForSubWidgets(const SpecialEvent& ev)
{
if (! visible)
return false;
if (subWidgets.size() == 0)
return false;

FOR_EACH_SUBWIDGET_INV(rit)
{
SubWidget* const widget(*rit);

if (widget->isVisible() && widget->onSpecial(ev))
return true;
}

return false;
}

bool Widget::PrivateData::giveCharacterInputEventForSubWidgets(const CharacterInputEvent& ev) bool Widget::PrivateData::giveCharacterInputEventForSubWidgets(const CharacterInputEvent& ev)
{ {
if (! visible) if (! visible)


+ 0
- 1
dpf/dgl/src/WidgetPrivateData.hpp View File

@@ -44,7 +44,6 @@ struct Widget::PrivateData {
void displaySubWidgets(uint width, uint height, double autoScaleFactor); void displaySubWidgets(uint width, uint height, double autoScaleFactor);


bool giveKeyboardEventForSubWidgets(const KeyboardEvent& ev); bool giveKeyboardEventForSubWidgets(const KeyboardEvent& ev);
bool giveSpecialEventForSubWidgets(const SpecialEvent& ev);
bool giveCharacterInputEventForSubWidgets(const CharacterInputEvent& ev); bool giveCharacterInputEventForSubWidgets(const CharacterInputEvent& ev);
bool giveMouseEventForSubWidgets(MouseEvent& ev); bool giveMouseEventForSubWidgets(MouseEvent& ev);
bool giveMotionEventForSubWidgets(MotionEvent& ev); bool giveMotionEventForSubWidgets(MotionEvent& ev);


+ 2
- 18
dpf/dgl/src/Window.cpp View File

@@ -66,8 +66,8 @@ Window::Window(Application& app)
pData->initPost(); pData->initPost();
} }


Window::Window(Application& app, Window& parent)
: pData(new PrivateData(app, this, parent.pData))
Window::Window(Application& app, Window& transientParentWindow)
: pData(new PrivateData(app, this, transientParentWindow.pData))
{ {
pData->initPost(); pData->initPost();
} }
@@ -407,22 +407,6 @@ void Window::setTransientWinId(const uintptr_t winId)
{ {
puglSetTransientFor(pData->view, winId); puglSetTransientFor(pData->view, winId);
} }

// -----------------------------------------------------------------------

bool Window::handlePluginKeyboard(const bool press, const uint key)
{
// TODO
return false;
// return pData->handlePluginKeyboard(press, key);
}

bool Window::handlePluginSpecial(const bool press, const Key key)
{
// TODO
return false;
// return pData->handlePluginSpecial(press, key);
}
#endif #endif


// ----------------------------------------------------------------------- // -----------------------------------------------------------------------


+ 13
- 22
dpf/dgl/src/WindowPrivateData.cpp View File

@@ -33,7 +33,11 @@
#define DGL_DEBUG_EVENTS #define DGL_DEBUG_EVENTS


#if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS)
# include <cinttypes>
# ifdef DISTRHO_PROPER_CPP11_SUPPORT
# include <cinttypes>
# else
# include <inttypes.h>
# endif
#endif #endif


START_NAMESPACE_DGL START_NAMESPACE_DGL
@@ -820,24 +824,6 @@ void Window::PrivateData::onPuglKey(const Widget::KeyboardEvent& ev)
#endif #endif
} }


void Window::PrivateData::onPuglSpecial(const Widget::SpecialEvent& ev)
{
DGL_DBGp("onPuglSpecial : %i %u\n", ev.press, ev.key);

if (modal.child != nullptr)
return modal.child->focus();

#ifndef DPF_TEST_WINDOW_CPP
FOR_EACH_TOP_LEVEL_WIDGET_INV(rit)
{
TopLevelWidget* const widget(*rit);

if (widget->isVisible() && widget->pData->specialEvent(ev))
break;
}
#endif
}

void Window::PrivateData::onPuglText(const Widget::CharacterInputEvent& ev) void Window::PrivateData::onPuglText(const Widget::CharacterInputEvent& ev)
{ {
DGL_DBGp("onPuglText : %u %u %s\n", ev.keycode, ev.character, ev.string); DGL_DBGp("onPuglText : %u %u %s\n", ev.keycode, ev.character, ev.string);
@@ -982,7 +968,6 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu
case PUGL_KEY_RELEASE: case PUGL_KEY_RELEASE:
{ {
// unused x, y, xRoot, yRoot (double) // unused x, y, xRoot, yRoot (double)
// TODO special keys?
Widget::KeyboardEvent ev; Widget::KeyboardEvent ev;
ev.mod = event->key.state; ev.mod = event->key.state;
ev.flags = event->key.flags; ev.flags = event->key.flags;
@@ -990,8 +975,14 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu
ev.press = event->type == PUGL_KEY_PRESS; ev.press = event->type == PUGL_KEY_PRESS;
ev.key = event->key.key; ev.key = event->key.key;
ev.keycode = event->key.keycode; ev.keycode = event->key.keycode;
if ((ev.mod & kModifierShift) != 0 && ev.key >= 'a' && ev.key <= 'z')
ev.key -= 'a' - 'A'; // a-z -> A-Z

// keyboard events must always be lowercase
if (ev.key >= 'A' && ev.key <= 'Z')
{
ev.key += 'a' - 'A'; // A-Z -> a-z
ev.mod |= kModifierShift;
}

pData->onPuglKey(ev); pData->onPuglKey(ev);
break; break;
} }


+ 0
- 1
dpf/dgl/src/WindowPrivateData.hpp View File

@@ -178,7 +178,6 @@ struct Window::PrivateData : IdleCallback {
void onPuglClose(); void onPuglClose();
void onPuglFocus(bool focus, CrossingMode mode); void onPuglFocus(bool focus, CrossingMode mode);
void onPuglKey(const Widget::KeyboardEvent& ev); void onPuglKey(const Widget::KeyboardEvent& ev);
void onPuglSpecial(const Widget::SpecialEvent& ev);
void onPuglText(const Widget::CharacterInputEvent& ev); void onPuglText(const Widget::CharacterInputEvent& ev);
void onPuglMouse(const Widget::MouseEvent& ev); void onPuglMouse(const Widget::MouseEvent& ev);
void onPuglMotion(const Widget::MotionEvent& ev); void onPuglMotion(const Widget::MotionEvent& ev);


+ 166
- 7
dpf/distrho/DistrhoInfo.hpp View File

@@ -106,13 +106,6 @@ START_NAMESPACE_DISTRHO
return d_cconst('M', 'u', 't', 'e'); return d_cconst('M', 'u', 't', 'e');
} }


/* ----------------------------------------------------------------------------------------
* This example has no parameters, so skip parameter stuff */

void initParameter(uint32_t, Parameter&) override {}
float getParameterValue(uint32_t) const override { return 0.0f; }
void setParameterValue(uint32_t, float) override {}

/* ---------------------------------------------------------------------------------------- /* ----------------------------------------------------------------------------------------
* Audio/MIDI Processing */ * Audio/MIDI Processing */


@@ -507,6 +500,20 @@ START_NAMESPACE_DISTRHO
*/ */
#define DISTRHO_PLUGIN_IS_SYNTH 1 #define DISTRHO_PLUGIN_IS_SYNTH 1


/**
Request the minimum buffer size for the input and output event ports.@n
Currently only used in LV2, with a default value of 2048 if unset.
*/
#define DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE 2048

/**
Whether the plugin has an LV2 modgui.

This will simply add a "rdfs:seeAlso <modgui.ttl>" on the LV2 manifest.@n
It is up to you to create this file.
*/
#define DISTRHO_PLUGIN_USES_MODGUI 0

/** /**
Enable direct access between the %UI and plugin code. Enable direct access between the %UI and plugin code.
@see UI::getPluginInstancePointer() @see UI::getPluginInstancePointer()
@@ -613,6 +620,158 @@ START_NAMESPACE_DISTRHO
*/ */
#define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI" #define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI"


/**
Custom LV2 category for the plugin.@n
This can be one of the following values:

- lv2:Plugin
- lv2:AllpassPlugin
- lv2:AmplifierPlugin
- lv2:AnalyserPlugin
- lv2:BandpassPlugin
- lv2:ChorusPlugin
- lv2:CombPlugin
- lv2:CompressorPlugin
- lv2:ConstantPlugin
- lv2:ConverterPlugin
- lv2:DelayPlugin
- lv2:DistortionPlugin
- lv2:DynamicsPlugin
- lv2:EQPlugin
- lv2:EnvelopePlugin
- lv2:ExpanderPlugin
- lv2:FilterPlugin
- lv2:FlangerPlugin
- lv2:FunctionPlugin
- lv2:GatePlugin
- lv2:GeneratorPlugin
- lv2:HighpassPlugin
- lv2:InstrumentPlugin
- lv2:LimiterPlugin
- lv2:LowpassPlugin
- lv2:MIDIPlugin
- lv2:MixerPlugin
- lv2:ModulatorPlugin
- lv2:MultiEQPlugin
- lv2:OscillatorPlugin
- lv2:ParaEQPlugin
- lv2:PhaserPlugin
- lv2:PitchPlugin
- lv2:ReverbPlugin
- lv2:SimulatorPlugin
- lv2:SpatialPlugin
- lv2:SpectralPlugin
- lv2:UtilityPlugin
- lv2:WaveshaperPlugin

See http://lv2plug.in/ns/lv2core for more information.
*/
#define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:Plugin"

/**
Custom VST3 categories for the plugin.@n
This is a list of categories, separated by a @c |.

Each effect category can be one of the following values:

- Fx
- Fx|Ambisonics
- Fx|Analyzer
- Fx|Delay
- Fx|Distortion
- Fx|Dynamics
- Fx|EQ
- Fx|Filter
- Fx|Instrument
- Fx|Instrument|External
- Fx|Spatial
- Fx|Generator
- Fx|Mastering
- Fx|Modulation
- Fx|Network
- Fx|Pitch Shift
- Fx|Restoration
- Fx|Reverb
- Fx|Surround
- Fx|Tools

Each instrument category can be one of the following values:

- Instrument
- Instrument|Drum
- Instrument|External
- Instrument|Piano
- Instrument|Sampler
- Instrument|Synth
- Instrument|Synth|Sampler

@note DPF will automatically set Mono and Stereo categories when appropriate.
*/
#define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx"

/** @} */

/* ------------------------------------------------------------------------------------------------------------
* Plugin Macros */

/**
@defgroup ExtraPluginMacros Extra Plugin Macros

C Macros to customize DPF behaviour.

These are macros that do not set plugin features or information, but instead change DPF internals.
They are all optional.

Unless stated otherwise, values are assumed to be a simple/empty define.
@{
*/

/**
Whether to enable runtime plugin tests.@n
This will check, during initialization of the plugin, if parameters, programs and states are setup properly.@n
Useful to enable as part of CI, can safely be skipped.@n
Under DPF makefiles this can be enabled by using `make DPF_RUNTIME_TESTING=true`.

@note Some checks are only available with the GCC compiler,
for detecting if a virtual function has been reimplemented.
*/
#define DPF_RUNTIME_TESTING

/**
Whether to show parameter outputs in the VST2 plugins.@n
This is disabled (unset) by default, as the VST2 format has no notion of read-only parameters.
*/
#define DPF_VST_SHOW_PARAMETER_OUTPUTS

/**
Disable all file browser related code.@n
Must be set as compiler macro when building DGL. (e.g. `CXXFLAGS="-DDGL_FILE_BROWSER_DISABLED"`)
*/
#define DGL_FILE_BROWSER_DISABLED

/**
Disable resource files, like internally used fonts.@n
Must be set as compiler macro when building DGL. (e.g. `CXXFLAGS="-DDGL_NO_SHARED_RESOURCES"`)
*/
#define DGL_NO_SHARED_RESOURCES

/**
Whether to use OpenGL3 instead of the default OpenGL2 compatility profile.
Under DPF makefiles this can be enabled by using `make USE_OPENGL3=true` on the dgl build step.

@note This is experimental and incomplete, contributions are welcome and appreciated.
*/
#define DGL_USE_OPENGL3

/**
Whether to use the GPLv2+ vestige header instead of the official Steinberg VST2 SDK.@n
This is a boolean, and enabled (set to 1) by default.@n
Set this to 0 in order to create non-GPL binaries.
(but then at your own discretion in regards to Steinberg licensing)@n
When set to 0, DPF will import the VST2 definitions from `"vst/aeffectx.h"` (not shipped with DPF).
*/
#define VESTIGE_HEADER 1

/** @} */ /** @} */


// ----------------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------------


+ 6
- 1
dpf/distrho/DistrhoPlugin.hpp View File

@@ -40,7 +40,9 @@ START_NAMESPACE_DISTRHO
static const uint32_t kAudioPortIsCV = 0x1; static const uint32_t kAudioPortIsCV = 0x1;


/** /**
Audio port should be used as sidechan (LV2 only).
Audio port should be used as sidechan (LV2 and VST3 only).
This hint should not be used with CV style ports.
@note non-sidechain audio ports must exist in the plugin if this flag is set.
*/ */
static const uint32_t kAudioPortIsSidechain = 0x2; static const uint32_t kAudioPortIsSidechain = 0x2;


@@ -632,6 +634,9 @@ struct MidiEvent {
/** /**
MIDI data.@n MIDI data.@n
If size > kDataSize, dataExt is used (otherwise null). If size > kDataSize, dataExt is used (otherwise null).

When dataExt is used, the event holder is responsible for
keeping the pointer valid during the entirety of the run function.
*/ */
uint8_t data[kDataSize]; uint8_t data[kDataSize];
const uint8_t* dataExt; const uint8_t* dataExt;


+ 1
- 1
dpf/distrho/DistrhoUIMain.cpp View File

@@ -27,7 +27,7 @@
#elif defined(DISTRHO_PLUGIN_TARGET_VST2) #elif defined(DISTRHO_PLUGIN_TARGET_VST2)
// nothing // nothing
#elif defined(DISTRHO_PLUGIN_TARGET_VST3) #elif defined(DISTRHO_PLUGIN_TARGET_VST3)
// nothing
# include "src/DistrhoUIVST3.cpp"
#else #else
# error unsupported format # error unsupported format
#endif #endif

+ 19
- 1
dpf/distrho/extra/LeakDetector.hpp View File

@@ -23,7 +23,25 @@ START_NAMESPACE_DISTRHO


// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// The following code was based from juce-core LeakDetector class // The following code was based from juce-core LeakDetector class
// Copyright (C) 2013 Raw Material Software Ltd.

/**
Copyright (C) 2013 Raw Material Software Ltd.

Permission is granted to use this software under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license/

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
OF THIS SOFTWARE.
*/


/** A good old-fashioned C macro concatenation helper. /** A good old-fashioned C macro concatenation helper.
This combines two items (which may themselves be macros) into a single string, This combines two items (which may themselves be macros) into a single string,


+ 19
- 1
dpf/distrho/extra/ScopedPointer.hpp View File

@@ -25,7 +25,25 @@ START_NAMESPACE_DISTRHO


// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// The following code was based from juce-core ScopedPointer class // The following code was based from juce-core ScopedPointer class
// Copyright (C) 2013 Raw Material Software Ltd.

/**
Copyright (C) 2013 Raw Material Software Ltd.

Permission is granted to use this software under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license/

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
OF THIS SOFTWARE.
*/


//============================================================================== //==============================================================================
/** /**


+ 1
- 1
dpf/distrho/extra/String.hpp View File

@@ -516,7 +516,7 @@ public:
*/ */
String& replace(const char before, const char after) noexcept String& replace(const char before, const char after) noexcept
{ {
DISTRHO_SAFE_ASSERT_RETURN(before != '\0' && after != '\0', *this);
DISTRHO_SAFE_ASSERT_RETURN(before != '\0' /* && after != '\0' */, *this);


for (std::size_t i=0; i < fBufferLen; ++i) for (std::size_t i=0; i < fBufferLen; ++i)
{ {


+ 5
- 2
dpf/distrho/src/DistrhoDefines.h View File

@@ -109,7 +109,7 @@
#define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_CONTINUE(msg, cond) if (! (cond)) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } continue; } #define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_CONTINUE(msg, cond) if (! (cond)) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } continue; }
#define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN(msg, cond, ret) if (! (cond)) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } return ret; } #define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN(msg, cond, ret) if (! (cond)) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } return ret; }


#define DISTRHO_SAFE_ASSERT_INT_BREAK(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value); break; }
#define DISTRHO_SAFE_ASSERT_INT_BREAK(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value)); break; }
#define DISTRHO_SAFE_ASSERT_INT_CONTINUE(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value)); continue; } #define DISTRHO_SAFE_ASSERT_INT_CONTINUE(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value)); continue; }
#define DISTRHO_SAFE_ASSERT_INT_RETURN(cond, value, ret) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value)); return ret; } #define DISTRHO_SAFE_ASSERT_INT_RETURN(cond, value, ret) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value)); return ret; }


@@ -117,7 +117,7 @@
#define DISTRHO_SAFE_ASSERT_INT2_CONTINUE(cond, v1, v2) if (! (cond)) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast<int>(v1), static_cast<int>(v2)); continue; } #define DISTRHO_SAFE_ASSERT_INT2_CONTINUE(cond, v1, v2) if (! (cond)) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast<int>(v1), static_cast<int>(v2)); continue; }
#define DISTRHO_SAFE_ASSERT_INT2_RETURN(cond, v1, v2, ret) if (! (cond)) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast<int>(v1), static_cast<int>(v2)); return ret; } #define DISTRHO_SAFE_ASSERT_INT2_RETURN(cond, v1, v2, ret) if (! (cond)) { d_safe_assert_int2(#cond, __FILE__, __LINE__, static_cast<int>(v1), static_cast<int>(v2)); return ret; }


#define DISTRHO_SAFE_ASSERT_UINT_BREAK(cond, value) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast<uint>(value); break; }
#define DISTRHO_SAFE_ASSERT_UINT_BREAK(cond, value) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast<uint>(value)); break; }
#define DISTRHO_SAFE_ASSERT_UINT_CONTINUE(cond, value) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast<uint>(value)); continue; } #define DISTRHO_SAFE_ASSERT_UINT_CONTINUE(cond, value) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast<uint>(value)); continue; }
#define DISTRHO_SAFE_ASSERT_UINT_RETURN(cond, value, ret) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast<uint>(value)); return ret; } #define DISTRHO_SAFE_ASSERT_UINT_RETURN(cond, value, ret) if (! (cond)) { d_safe_assert_uint(#cond, __FILE__, __LINE__, static_cast<uint>(value)); return ret; }


@@ -199,6 +199,9 @@ private: \
# pragma warning(disable:4244) /* possible loss of data */ # pragma warning(disable:4244) /* possible loss of data */
#endif #endif


/* Useful macros */
#define ARRAY_SIZE(ARRAY) sizeof(ARRAY)/sizeof(ARRAY[0])

/* Useful typedefs */ /* Useful typedefs */
typedef unsigned char uchar; typedef unsigned char uchar;
typedef unsigned short int ushort; typedef unsigned short int ushort;


+ 2
- 2
dpf/distrho/src/DistrhoPlugin.cpp View File

@@ -29,7 +29,7 @@ bool d_lastCanRequestParameterValueChanges = false;
* Static fallback data, see DistrhoPluginInternal.hpp */ * Static fallback data, see DistrhoPluginInternal.hpp */


const String PluginExporter::sFallbackString; const String PluginExporter::sFallbackString;
const AudioPort PluginExporter::sFallbackAudioPort;
/* */ AudioPortWithBusId PluginExporter::sFallbackAudioPort;
const ParameterRanges PluginExporter::sFallbackRanges; const ParameterRanges PluginExporter::sFallbackRanges;
const ParameterEnumerationValues PluginExporter::sFallbackEnumValues; const ParameterEnumerationValues PluginExporter::sFallbackEnumValues;
const PortGroupWithId PluginExporter::sFallbackPortGroup; const PortGroupWithId PluginExporter::sFallbackPortGroup;
@@ -41,7 +41,7 @@ Plugin::Plugin(uint32_t parameterCount, uint32_t programCount, uint32_t stateCou
: pData(new PrivateData()) : pData(new PrivateData())
{ {
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
pData->audioPorts = new AudioPort[DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS];
pData->audioPorts = new AudioPortWithBusId[DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS];
#endif #endif


#ifdef DPF_ABORT_ON_ERROR #ifdef DPF_ABORT_ON_ERROR


+ 0
- 1
dpf/distrho/src/DistrhoPluginChecks.h View File

@@ -173,7 +173,6 @@
# error DISTRHO_UI_IS_STANDALONE must not be defined # error DISTRHO_UI_IS_STANDALONE must not be defined
#endif #endif



// ----------------------------------------------------------------------- // -----------------------------------------------------------------------


#endif // DISTRHO_PLUGIN_CHECKS_H_INCLUDED #endif // DISTRHO_PLUGIN_CHECKS_H_INCLUDED

+ 50
- 21
dpf/distrho/src/DistrhoPluginInternal.hpp View File

@@ -44,6 +44,14 @@ typedef bool (*requestParameterValueChangeFunc) (void* ptr, uint32_t index, floa
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Helpers // Helpers


struct AudioPortWithBusId : AudioPort {
uint32_t busId;

AudioPortWithBusId()
: AudioPort(),
busId(0) {}
};

struct PortGroupWithId : PortGroup { struct PortGroupWithId : PortGroup {
uint32_t groupId; uint32_t groupId;


@@ -78,7 +86,7 @@ struct Plugin::PrivateData {
bool isProcessing; bool isProcessing;


#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
AudioPort* audioPorts;
AudioPortWithBusId* audioPorts;
#endif #endif


uint32_t parameterCount; uint32_t parameterCount;
@@ -162,6 +170,15 @@ struct Plugin::PrivateData {
# if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE) # if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE)
parameterOffset += 1; parameterOffset += 1;
# endif # endif
#endif

#ifdef DISTRHO_PLUGIN_TARGET_VST3
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT
parameterOffset += 130 * 16; // all MIDI CCs plus aftertouch and pitchbend
# endif
# if DISTRHO_PLUGIN_WANT_PROGRAMS
parameterOffset += 1;
# endif
#endif #endif
} }


@@ -247,30 +264,26 @@ public:
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);


/* Verify that virtual functions are overriden if parameters, programs or states are in use.
#if defined(DPF_RUNTIME_TESTING) && defined(__GNUC__) && !defined(__clang__)
/* Run-time testing build.
* Verify that virtual functions are overriden if parameters, programs or states are in use.
* This does not work on all compilers, but we use it purely as informational check anyway. */ * This does not work on all compilers, but we use it purely as informational check anyway. */
#if defined(__GNUC__) && !defined(__clang__)
# ifdef DPF_ABORT_ON_ERROR
# define DPF_ABORT abort();
# else
# define DPF_ABORT
# endif
if (fData->parameterCount != 0) if (fData->parameterCount != 0)
{ {
if ((void*)(fPlugin->*(&Plugin::initParameter)) == (void*)&Plugin::initParameter) if ((void*)(fPlugin->*(&Plugin::initParameter)) == (void*)&Plugin::initParameter)
{ {
d_stderr2("DPF warning: Plugins with parameters must implement `initParameter`"); d_stderr2("DPF warning: Plugins with parameters must implement `initParameter`");
DPF_ABORT
abort();
} }
if ((void*)(fPlugin->*(&Plugin::getParameterValue)) == (void*)&Plugin::getParameterValue) if ((void*)(fPlugin->*(&Plugin::getParameterValue)) == (void*)&Plugin::getParameterValue)
{ {
d_stderr2("DPF warning: Plugins with parameters must implement `getParameterValue`"); d_stderr2("DPF warning: Plugins with parameters must implement `getParameterValue`");
DPF_ABORT
abort();
} }
if ((void*)(fPlugin->*(&Plugin::setParameterValue)) == (void*)&Plugin::setParameterValue) if ((void*)(fPlugin->*(&Plugin::setParameterValue)) == (void*)&Plugin::setParameterValue)
{ {
d_stderr2("DPF warning: Plugins with parameters must implement `setParameterValue`"); d_stderr2("DPF warning: Plugins with parameters must implement `setParameterValue`");
DPF_ABORT
abort();
} }
} }


@@ -280,12 +293,12 @@ public:
if ((void*)(fPlugin->*(&Plugin::initProgramName)) == (void*)&Plugin::initProgramName) if ((void*)(fPlugin->*(&Plugin::initProgramName)) == (void*)&Plugin::initProgramName)
{ {
d_stderr2("DPF warning: Plugins with programs must implement `initProgramName`"); d_stderr2("DPF warning: Plugins with programs must implement `initProgramName`");
DPF_ABORT
abort();
} }
if ((void*)(fPlugin->*(&Plugin::loadProgram)) == (void*)&Plugin::loadProgram) if ((void*)(fPlugin->*(&Plugin::loadProgram)) == (void*)&Plugin::loadProgram)
{ {
d_stderr2("DPF warning: Plugins with programs must implement `loadProgram`"); d_stderr2("DPF warning: Plugins with programs must implement `loadProgram`");
DPF_ABORT
abort();
} }
} }
# endif # endif
@@ -296,13 +309,13 @@ public:
if ((void*)(fPlugin->*(&Plugin::initState)) == (void*)&Plugin::initState) if ((void*)(fPlugin->*(&Plugin::initState)) == (void*)&Plugin::initState)
{ {
d_stderr2("DPF warning: Plugins with state must implement `initState`"); d_stderr2("DPF warning: Plugins with state must implement `initState`");
DPF_ABORT
abort();
} }


if ((void*)(fPlugin->*(&Plugin::setState)) == (void*)&Plugin::setState) if ((void*)(fPlugin->*(&Plugin::setState)) == (void*)&Plugin::setState)
{ {
d_stderr2("DPF warning: Plugins with state must implement `setState`"); d_stderr2("DPF warning: Plugins with state must implement `setState`");
DPF_ABORT
abort();
} }
} }
# endif # endif
@@ -313,17 +326,15 @@ public:
if ((void*)(fPlugin->*(&Plugin::getState)) == (void*)&Plugin::getState) if ((void*)(fPlugin->*(&Plugin::getState)) == (void*)&Plugin::getState)
{ {
d_stderr2("DPF warning: Plugins with full state must implement `getState`"); d_stderr2("DPF warning: Plugins with full state must implement `getState`");
DPF_ABORT
abort();
} }
} }
else else
{ {
d_stderr2("DPF warning: Plugins with full state must have at least 1 state"); d_stderr2("DPF warning: Plugins with full state must have at least 1 state");
DPF_ABORT
abort();
} }
# endif # endif

# undef DPF_ABORT
#endif #endif


#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
@@ -469,7 +480,7 @@ public:
#endif #endif


#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
const AudioPort& getAudioPort(const bool input, const uint32_t index) const noexcept
AudioPortWithBusId& getAudioPort(const bool input, const uint32_t index) const noexcept
{ {
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackAudioPort); DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackAudioPort);


@@ -488,6 +499,11 @@ public:


return fData->audioPorts[index + (input ? 0 : DISTRHO_PLUGIN_NUM_INPUTS)]; return fData->audioPorts[index + (input ? 0 : DISTRHO_PLUGIN_NUM_INPUTS)];
} }

uint32_t getAudioPortHints(const bool input, const uint32_t index) const noexcept
{
return getAudioPort(input, index).hints;
}
#endif #endif


uint32_t getParameterCount() const noexcept uint32_t getParameterCount() const noexcept
@@ -528,6 +544,11 @@ public:
return (getParameterHints(index) & kParameterIsOutput) != 0x0; return (getParameterHints(index) & kParameterIsOutput) != 0x0;
} }


bool isParameterTrigger(const uint32_t index) const noexcept
{
return (getParameterHints(index) & kParameterIsTrigger) == kParameterIsTrigger;
}

bool isParameterOutputOrTrigger(const uint32_t index) const noexcept bool isParameterOutputOrTrigger(const uint32_t index) const noexcept
{ {
const uint32_t hints = getParameterHints(index); const uint32_t hints = getParameterHints(index);
@@ -603,6 +624,14 @@ public:
return fData->parameters[index].groupId; return fData->parameters[index].groupId;
} }


float getParameterDefault(const uint32_t index) const
{
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f);
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr && index < fData->parameterCount, 0.0f);

return fData->parameters[index].ranges.def;
}

float getParameterValue(const uint32_t index) const float getParameterValue(const uint32_t index) const
{ {
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f); DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.0f);
@@ -888,7 +917,7 @@ private:
// Static fallback data, see DistrhoPlugin.cpp // Static fallback data, see DistrhoPlugin.cpp


static const String sFallbackString; static const String sFallbackString;
static const AudioPort sFallbackAudioPort;
static /* */ AudioPortWithBusId sFallbackAudioPort;
static const ParameterRanges sFallbackRanges; static const ParameterRanges sFallbackRanges;
static const ParameterEnumerationValues sFallbackEnumValues; static const ParameterEnumerationValues sFallbackEnumValues;
static const PortGroupWithId sFallbackPortGroup; static const PortGroupWithId sFallbackPortGroup;


+ 49
- 39
dpf/distrho/src/DistrhoPluginVST2.cpp View File

@@ -261,7 +261,6 @@ public:


using namespace DGL_NAMESPACE; using namespace DGL_NAMESPACE;


int special = 0;
switch (value) switch (value)
{ {
// convert some VST special values to normal keys // convert some VST special values to normal keys
@@ -304,37 +303,37 @@ public:
- kKeyCapsLock - kKeyCapsLock
- kKeyPrintScreen - kKeyPrintScreen
*/ */
case 40: special = kKeyF1; break;
case 41: special = kKeyF2; break;
case 42: special = kKeyF3; break;
case 43: special = kKeyF4; break;
case 44: special = kKeyF5; break;
case 45: special = kKeyF6; break;
case 46: special = kKeyF7; break;
case 47: special = kKeyF8; break;
case 48: special = kKeyF9; break;
case 49: special = kKeyF10; break;
case 50: special = kKeyF11; break;
case 51: special = kKeyF12; break;
case 11: special = kKeyLeft; break;
case 12: special = kKeyUp; break;
case 13: special = kKeyRight; break;
case 14: special = kKeyDown; break;
case 15: special = kKeyPageUp; break;
case 16: special = kKeyPageDown; break;
case 10: special = kKeyHome; break;
case 9: special = kKeyEnd; break;
case 21: special = kKeyInsert; break;
case 54: special = kKeyShift; break;
case 55: special = kKeyControl; break;
case 56: special = kKeyAlt; break;
case 58: special = kKeyMenu; break;
case 52: special = kKeyNumLock; break;
case 53: special = kKeyScrollLock; break;
case 5: special = kKeyPause; break;
case 40: index = kKeyF1; break;
case 41: index = kKeyF2; break;
case 42: index = kKeyF3; break;
case 43: index = kKeyF4; break;
case 44: index = kKeyF5; break;
case 45: index = kKeyF6; break;
case 46: index = kKeyF7; break;
case 47: index = kKeyF8; break;
case 48: index = kKeyF9; break;
case 49: index = kKeyF10; break;
case 50: index = kKeyF11; break;
case 51: index = kKeyF12; break;
case 11: index = kKeyLeft; break;
case 12: index = kKeyUp; break;
case 13: index = kKeyRight; break;
case 14: index = kKeyDown; break;
case 15: index = kKeyPageUp; break;
case 16: index = kKeyPageDown; break;
case 10: index = kKeyHome; break;
case 9: index = kKeyEnd; break;
case 21: index = kKeyInsert; break;
case 54: index = kKeyShift; break;
case 55: index = kKeyControl; break;
case 56: index = kKeyAlt; break;
case 58: index = kKeyMenu; break;
case 52: index = kKeyNumLock; break;
case 53: index = kKeyScrollLock; break;
case 5: index = kKeyPause; break;
} }


switch (special)
switch (index)
{ {
case kKeyShift: case kKeyShift:
if (down) if (down)
@@ -356,15 +355,26 @@ public:
break; break;
} }


if (special != 0)
{
fUI.handlePluginSpecial(down, static_cast<Key>(special), fKeyboardModifiers);
return 1;
}

if (index > 0) if (index > 0)
{ {
fUI.handlePluginKeyboard(down, static_cast<uint>(index), fKeyboardModifiers);
// keyboard events must always be lowercase
bool needsShiftRevert = false;
if (index >= 'A' && index <= 'Z')
{
index += 'a' - 'A'; // A-Z -> a-z

if ((fKeyboardModifiers & kModifierShift) == 0x0)
{
needsShiftRevert = true;
fKeyboardModifiers |= kModifierShift;
}
}

fUI.handlePluginKeyboardVST2(down, static_cast<uint>(index), fKeyboardModifiers);

if (needsShiftRevert)
fKeyboardModifiers &= ~kModifierShift;

return 1; return 1;
} }


@@ -1056,7 +1066,7 @@ public:


void vst_setParameter(const int32_t index, const float value) void vst_setParameter(const int32_t index, const float value)
{ {
const uint32_t hints(fPlugin.getParameterHints(index));
const uint32_t hints = fPlugin.getParameterHints(index);
const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); const ParameterRanges& ranges(fPlugin.getParameterRanges(index));


// TODO figure out how to detect kVstParameterUsesIntegerMinMax host support, and skip normalization // TODO figure out how to detect kVstParameterUsesIntegerMinMax host support, and skip normalization
@@ -1104,7 +1114,7 @@ public:
fTimePosition.playing = (vstTimeInfo->flags & kVstTransportPlaying); fTimePosition.playing = (vstTimeInfo->flags & kVstTransportPlaying);
fTimePosition.bbt.valid = ((vstTimeInfo->flags & kVstTempoValid) != 0 || (vstTimeInfo->flags & kVstTimeSigValid) != 0); fTimePosition.bbt.valid = ((vstTimeInfo->flags & kVstTempoValid) != 0 || (vstTimeInfo->flags & kVstTimeSigValid) != 0);


// ticksPerBeat is not possible with VST
// ticksPerBeat is not possible with VST2
fTimePosition.bbt.ticksPerBeat = 1920.0; fTimePosition.bbt.ticksPerBeat = 1920.0;


if (vstTimeInfo->flags & kVstTempoValid) if (vstTimeInfo->flags & kVstTempoValid)


+ 3594
- 186
dpf/distrho/src/DistrhoPluginVST3.cpp
File diff suppressed because it is too large
View File


+ 47
- 14
dpf/distrho/src/DistrhoUIInternal.hpp View File

@@ -91,7 +91,7 @@ public:
g_nextScaleFactor = 0.0; g_nextScaleFactor = 0.0;
g_nextBundlePath = nullptr; g_nextBundlePath = nullptr;
#else #else
// Leave context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp
// enter context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp
uiData->window->leaveContext(); uiData->window->leaveContext();
#endif #endif
UI::PrivateData::s_nextPrivateData = nullptr; UI::PrivateData::s_nextPrivateData = nullptr;
@@ -234,6 +234,28 @@ public:


// ------------------------------------------------------------------- // -------------------------------------------------------------------


#if defined(DISTRHO_PLUGIN_TARGET_VST3) && (defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS))
void addIdleCallbackForVST3(IdleCallback* const cb, const uint timerFrequencyInMs)
{
uiData->window->addIdleCallback(cb, timerFrequencyInMs);
}

void removeIdleCallbackForVST3(IdleCallback* const cb)
{
uiData->window->removeIdleCallback(cb);
}

void idleForVST3()
{
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

uiData->app.triggerIdleCallbacks();
ui->uiIdle();
}
#endif

// -------------------------------------------------------------------

void setWindowTitle(const char* const uiTitle) void setWindowTitle(const char* const uiTitle)
{ {
uiData->window->setTitle(uiTitle); uiData->window->setTitle(uiTitle);
@@ -258,23 +280,25 @@ public:
} }


#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
bool handlePluginKeyboard(const bool press, const uint key, const uint16_t mods)
bool handlePluginKeyboardVST2(const bool press, const uint key, const uint16_t mods)
{ {
// TODO also trigger Character input event
DGL_NAMESPACE::Widget::KeyboardEvent ev; DGL_NAMESPACE::Widget::KeyboardEvent ev;
ev.mod = mods;
ev.press = press; ev.press = press;
ev.key = key;
ev.mod = mods;
return ui->onKeyboard(ev);
}
ev.key = key;


bool handlePluginSpecial(const bool press, const DGL_NAMESPACE::Key key, const uint16_t mods)
{
DGL_NAMESPACE::Widget::SpecialEvent ev;
ev.press = press;
ev.key = key;
ev.mod = mods;
return ui->onSpecial(ev);
const bool ret = ui->onKeyboard(ev);

DGL_NAMESPACE::Widget::CharacterInputEvent cev;
cev.mod = mods;
cev.character = key;

// if shift modifier is on, convert a-z -> A-Z for character input
if (key >= 'a' && key <= 'z' && (mods & DGL_NAMESPACE::kModifierShift) != 0)
cev.character -= 'a' - 'A';

ui->onCharacterInput(cev);
return ret;
} }
#endif #endif


@@ -287,6 +311,15 @@ public:
ui->uiScaleFactorChanged(scaleFactor); ui->uiScaleFactorChanged(scaleFactor);
} }


#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
void notifyFocusChanged(const bool focus)
{
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

ui->uiFocus(focus, DGL_NAMESPACE::kCrossingNormal);
}
#endif

void setSampleRate(const double sampleRate, const bool doCallback = false) void setSampleRate(const double sampleRate, const bool doCallback = false)
{ {
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,); DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);


+ 23
- 2
dpf/distrho/src/DistrhoUIPrivateData.hpp View File

@@ -22,7 +22,7 @@
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
# include "../extra/Sleep.hpp" # include "../extra/Sleep.hpp"
#else #else
# include "../../dgl/Application.hpp"
# include "../../dgl/src/ApplicationPrivateData.hpp"
# include "../../dgl/src/WindowPrivateData.hpp" # include "../../dgl/src/WindowPrivateData.hpp"
# include "../../dgl/src/pugl.hpp" # include "../../dgl/src/pugl.hpp"
#endif #endif
@@ -33,7 +33,13 @@
# define DISTRHO_UI_IS_STANDALONE 0 # define DISTRHO_UI_IS_STANDALONE 0
#endif #endif


#if defined(DISTRHO_PLUGIN_TARGET_VST2) || defined(DISTRHO_PLUGIN_TARGET_VST3)
#if defined(DISTRHO_PLUGIN_TARGET_VST2)
# undef DISTRHO_UI_USER_RESIZABLE
# define DISTRHO_UI_USER_RESIZABLE 0
#endif

// TODO figure out how to detect host support
#if defined(DISTRHO_PLUGIN_TARGET_VST3)
# undef DISTRHO_UI_USER_RESIZABLE # undef DISTRHO_UI_USER_RESIZABLE
# define DISTRHO_UI_USER_RESIZABLE 0 # define DISTRHO_UI_USER_RESIZABLE 0
#endif #endif
@@ -92,6 +98,7 @@ struct PluginApplication
// these are not needed // these are not needed
void idle() {} void idle() {}
void quit() {} void quit() {}
void triggerIdleCallbacks() {}


DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication)
}; };
@@ -113,6 +120,11 @@ public:
setClassName(className); setClassName(className);
} }


void triggerIdleCallbacks()
{
pData->triggerIdleCallbacks();
}

DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication)
}; };
#endif #endif
@@ -325,6 +337,15 @@ struct UI::PrivateData {
# if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE) # if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE)
parameterOffset += 1; parameterOffset += 1;
# endif # endif
#endif

#ifdef DISTRHO_PLUGIN_TARGET_VST3
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT
parameterOffset += 130 * 16; // all MIDI CCs plus aftertouch and pitchbend
# endif
# if DISTRHO_PLUGIN_WANT_PROGRAMS
parameterOffset += 1;
# endif
#endif #endif
} }




+ 1189
- 0
dpf/distrho/src/DistrhoUIVST3.cpp
File diff suppressed because it is too large
View File


+ 10
- 0
dpf/distrho/src/dssi/seq_event-compat.h View File

@@ -1,3 +1,13 @@
/**
* \file include/seq_event.h
* \brief Application interface library for the ALSA driver
* \author Jaroslav Kysela <perex@perex.cz>
* \author Abramo Bagnara <abramo@alsa-project.org>
* \author Takashi Iwai <tiwai@suse.de>
* \date 1998-2001
*
* Application interface library for the ALSA driver
*/
/* /*
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as * it under the terms of the GNU Lesser General Public License as


+ 0
- 249
dpf/distrho/src/lv2/atom-helpers.h View File

@@ -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

+ 0
- 98
dpf/distrho/src/lv2/lv2-midifunctions.h View File

@@ -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


+ 0
- 175
dpf/distrho/src/lv2/lv2-miditype.h View File

@@ -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

+ 3
- 3
dpf/distrho/src/travesty/README.txt View File

@@ -1,9 +1,9 @@
This folder contains a pure C interface to Steinberg VST3 SDK, codenamed "travesty".
This folder contains a pure C VST3-compatible interface, codenamed "travesty".
Name is a play on words from morphing "vestige" (the good old free VST2 reverse-engineered header file) and "three". Name is a play on words from morphing "vestige" (the good old free VST2 reverse-engineered header file) and "three".


The main target is to be able to create VST3-compatible plugins without a bloated SDK. The main target is to be able to create VST3-compatible plugins without a bloated SDK.
Everything that is required for plugins fits in a few small header files.
Also, being able to build VST3-compatible plugins in pure C code, something not possible with the original SDK.
Everything that is required for plugins fits in a few small header files as presented here.
Also being able to build VST3-compatible plugins in pure C code, something not possible with the original SDK.


Please note this project is still a work in progress. Please note this project is still a work in progress.
Use at your own risk, and please report any issues to https://github.com/DISTRHO/DPF/. Use at your own risk, and please report any issues to https://github.com/DISTRHO/DPF/.

+ 17
- 2
dpf/distrho/src/travesty/align_pop.h View File

@@ -1,5 +1,5 @@
/* /*
* travesty, pure C interface to steinberg VST3 SDK
* travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * Permission to use, copy, modify, and/or distribute this software for any purpose with
@@ -14,10 +14,25 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */


#if defined(__APPLE__)
# if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wpragma-pack"
# elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 460
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunknown-warning-option"
# pragma GCC diagnostic ignored "-Wpragma-pack"
# endif
#endif

#if defined(__APPLE__) || defined(_WIN32) #if defined(__APPLE__) || defined(_WIN32)
# pragma pack(pop) # pragma pack(pop)
#endif #endif


#if defined(__APPLE__) #if defined(__APPLE__)
# pragma GCC diagnostic pop
# if defined(__clang__)
# pragma clang diagnostic pop
# elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 460
# pragma GCC diagnostic pop
# endif
#endif #endif

+ 11
- 4
dpf/distrho/src/travesty/align_push.h View File

@@ -1,5 +1,5 @@
/* /*
* travesty, pure C interface to steinberg VST3 SDK
* travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * Permission to use, copy, modify, and/or distribute this software for any purpose with
@@ -16,9 +16,16 @@


#if defined(__APPLE__) #if defined(__APPLE__)


# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunknown-warning-option"
# pragma GCC diagnostic ignored "-Wpragma-pack"
# if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunknown-warning-option"
# pragma clang diagnostic ignored "-Wpragma-pack"
# elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 460
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunknown-warning-option"
# pragma GCC diagnostic ignored "-Wpragma-pack"
# endif

# if defined(__LP64__) || defined(_LP64) # if defined(__LP64__) || defined(_LP64)
# pragma pack(push, 16) # pragma pack(push, 16)
# else # else


+ 84
- 89
dpf/distrho/src/travesty/audio_processor.h View File

@@ -1,5 +1,5 @@
/* /*
* travesty, pure C interface to steinberg VST3 SDK
* travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * Permission to use, copy, modify, and/or distribute this software for any purpose with
@@ -28,8 +28,9 @@
typedef uint64_t v3_speaker_arrangement; typedef uint64_t v3_speaker_arrangement;


enum { enum {
V3_SPEAKER_L = 1,
V3_SPEAKER_R = 1 << 1
V3_SPEAKER_L = 1 << 0,
V3_SPEAKER_R = 1 << 1,
V3_SPEAKER_M = 1 << 19
}; };


/** /**
@@ -42,14 +43,19 @@ enum v3_process_mode {
V3_OFFLINE V3_OFFLINE
}; };


inline static const char *
v3_process_mode_str(int32_t d)
static inline
const char* v3_process_mode_str(int32_t d)
{ {
switch (d) {
case V3_REALTIME: return "V3_REALTIME";
case V3_PREFETCH: return "V3_PREFETCH";
case V3_OFFLINE: return "V3_OFFLINE";
default: return "[unknown]";
switch (d)
{
case V3_REALTIME:
return "V3_REALTIME";
case V3_PREFETCH:
return "V3_PREFETCH";
case V3_OFFLINE:
return "V3_OFFLINE";
default:
return "[unknown]";
} }
} }


@@ -58,13 +64,17 @@ enum {
V3_SAMPLE_64 V3_SAMPLE_64
}; };


inline static const char *
v3_sample_size_str(int32_t d)
static inline
const char* v3_sample_size_str(int32_t d)
{ {
switch (d) {
case V3_SAMPLE_32: return "V3_SAMPLE_32";
case V3_SAMPLE_64: return "V3_SAMPLE_64";
default: return "[unknown]";
switch (d)
{
case V3_SAMPLE_32:
return "V3_SAMPLE_32";
case V3_SAMPLE_64:
return "V3_SAMPLE_64";
default:
return "[unknown]";
} }
} }


@@ -82,31 +92,24 @@ struct v3_process_setup {
struct v3_param_value_queue { struct v3_param_value_queue {
struct v3_funknown; struct v3_funknown;


V3_API v3_param_id (*get_param_id)(void *self);
V3_API int32_t (*get_point_count)(void *self);

V3_API v3_result (*get_point)
(void *self, int32_t idx, int32_t *sample_offset, double *value);
V3_API v3_result (*add_point)
(void *self, int32_t sample_offset, double value, int32_t *idx);
v3_param_id (V3_API* get_param_id)(void* self);
int32_t (V3_API* get_point_count)(void* self);
v3_result (V3_API* get_point)(void* self, int32_t idx, int32_t* sample_offset, double* value);
v3_result (V3_API* add_point)(void* self, int32_t sample_offset, double value, int32_t* idx);
}; };


static const v3_tuid v3_param_value_queue_iid =
static constexpr const v3_tuid v3_param_value_queue_iid =
V3_ID(0x01263A18, 0xED074F6F, 0x98C9D356, 0x4686F9BA); V3_ID(0x01263A18, 0xED074F6F, 0x98C9D356, 0x4686F9BA);


struct v3_param_changes { struct v3_param_changes {
struct v3_funknown; struct v3_funknown;


V3_API int32_t (*get_param_count)(void *self);

V3_API struct v3_param_value_queue **(*get_param_data)
(void *self, int32_t idx);

V3_API struct v3_param_value_queue **(*add_param_data)
(void *self, v3_param_id *id, int32_t *index);
int32_t (V3_API* get_param_count)(void* self);
struct v3_param_value_queue** (V3_API* get_param_data)(void* self, int32_t idx);
struct v3_param_value_queue** (V3_API* add_param_data)(void* self, v3_param_id* id, int32_t* index);
}; };


static const v3_tuid v3_param_changes_iid =
static constexpr const v3_tuid v3_param_changes_iid =
V3_ID(0xA4779663, 0x0BB64A56, 0xB44384A8, 0x466FEB9D); V3_ID(0xA4779663, 0x0BB64A56, 0xB44384A8, 0x466FEB9D);


/** /**
@@ -121,55 +124,41 @@ struct v3_frame_rate {
struct v3_chord { struct v3_chord {
uint8_t key_note; uint8_t key_note;
uint8_t root_note; uint8_t root_note;

int16_t chord_mask; int16_t chord_mask;
}; };


enum { enum {
V3_PROCESS_CTX_PLAYING = 1 << 1,
V3_PROCESS_CTX_CYCLE_ACTIVE = 1 << 2,
V3_PROCESS_CTX_RECORDING = 1 << 3,

V3_PROCESS_CTX_PLAYING = 1 << 1,
V3_PROCESS_CTX_CYCLE_ACTIVE = 1 << 2,
V3_PROCESS_CTX_RECORDING = 1 << 3,
V3_PROCESS_CTX_SYSTEM_TIME_VALID = 1 << 8, V3_PROCESS_CTX_SYSTEM_TIME_VALID = 1 << 8,
V3_PROCESS_CTX_CONT_TIME_VALID = 1 << 17,
V3_PROCESS_CTX_PROJECT_TIME_VALID = 1 << 9, V3_PROCESS_CTX_PROJECT_TIME_VALID = 1 << 9,
V3_PROCESS_CTX_TEMPO_VALID = 1 << 10,
V3_PROCESS_CTX_BAR_POSITION_VALID = 1 << 11, V3_PROCESS_CTX_BAR_POSITION_VALID = 1 << 11,
V3_PROCESS_CTX_CYCLE_VALID = 1 << 12, V3_PROCESS_CTX_CYCLE_VALID = 1 << 12,

V3_PROCESS_CTX_TEMPO_VALID = 1 << 10,
V3_PROCESS_CTX_TIME_SIG_VALID = 1 << 13, V3_PROCESS_CTX_TIME_SIG_VALID = 1 << 13,
V3_PROCESS_CTX_CHORD_VALID = 1 << 18,

V3_PROCESS_CTX_SMPTE_VALID = 1 << 14, V3_PROCESS_CTX_SMPTE_VALID = 1 << 14,

V3_PROCESS_CTX_NEXT_CLOCK_VALID = 1 << 15
V3_PROCESS_CTX_NEXT_CLOCK_VALID = 1 << 15,
V3_PROCESS_CTX_CONT_TIME_VALID = 1 << 17,
V3_PROCESS_CTX_CHORD_VALID = 1 << 18
}; };


struct v3_process_context { struct v3_process_context {
uint32_t state; uint32_t state;

double sample_rate; double sample_rate;
int64_t project_time_in_samples; // with loop int64_t project_time_in_samples; // with loop

int64_t system_time_ns; int64_t system_time_ns;
int64_t continuous_time_in_samples; // without loop? unclear

int64_t continuous_time_in_samples; // without loop
double project_time_quarters; double project_time_quarters;
double bar_position_quarters; double bar_position_quarters;
double cycle_start_quarters; double cycle_start_quarters;
double cycle_end_quarters; double cycle_end_quarters;

double bpm; double bpm;

int32_t time_sig_numerator; int32_t time_sig_numerator;
int32_t time_sig_denom; int32_t time_sig_denom;

struct v3_chord chord; struct v3_chord chord;

int32_t smpte_offset_subframes; int32_t smpte_offset_subframes;
struct v3_frame_rate frame_rate; struct v3_frame_rate frame_rate;

int32_t samples_to_next_clock; int32_t samples_to_next_clock;
}; };


@@ -194,10 +183,10 @@ enum {
struct v3_process_context_requirements { struct v3_process_context_requirements {
struct v3_funknown; struct v3_funknown;


V3_API uint32_t (*get_process_context_requirements)(void *self);
uint32_t (V3_API* get_process_context_requirements)(void* self);
}; };


static const v3_tuid v3_process_context_requirements_iid =
static constexpr const v3_tuid v3_process_context_requirements_iid =
V3_ID(0x2A654303, 0xEF764E3D, 0x95B5FE83, 0x730EF6D0); V3_ID(0x2A654303, 0xEF764E3D, 0x95B5FE83, 0x730EF6D0);


/** /**
@@ -207,32 +196,25 @@ static const v3_tuid v3_process_context_requirements_iid =
struct v3_audio_bus_buffers { struct v3_audio_bus_buffers {
int32_t num_channels; int32_t num_channels;
uint64_t channel_silence_bitset; uint64_t channel_silence_bitset;

union { union {
float **channel_buffers_32;
double **channel_buffers_64;
float** channel_buffers_32;
double** channel_buffers_64;
}; };
}; };


struct v3_process_data { struct v3_process_data {
int32_t process_mode; int32_t process_mode;
int32_t symbolic_sample_size; int32_t symbolic_sample_size;

int32_t nframes; int32_t nframes;

int32_t num_input_buses; int32_t num_input_buses;
int32_t num_output_buses; int32_t num_output_buses;

struct v3_audio_bus_buffers *inputs;
struct v3_audio_bus_buffers *outputs;

struct v3_param_changes **input_params;
struct v3_param_changes **output_params;

struct v3_event_list **input_events;
struct v3_event_list **output_events;

struct v3_process_context *ctx;
struct v3_audio_bus_buffers* inputs;
struct v3_audio_bus_buffers* outputs;
struct v3_param_changes** input_params;
struct v3_param_changes** output_params;
struct v3_event_list** input_events;
struct v3_event_list** output_events;
struct v3_process_context* ctx;
}; };


/** /**
@@ -242,29 +224,42 @@ struct v3_process_data {
struct v3_audio_processor { struct v3_audio_processor {
struct v3_funknown; struct v3_funknown;


V3_API v3_result (*set_bus_arrangements)
(void *self, v3_speaker_arrangement *inputs, int32_t num_inputs,
v3_speaker_arrangement *outputs, int32_t num_outputs);
V3_API v3_result (*get_bus_arrangement)
(void *self, int32_t bus_direction, int32_t idx, v3_speaker_arrangement *);
v3_result (V3_API* set_bus_arrangements)(void* self, v3_speaker_arrangement* inputs, int32_t num_inputs,
v3_speaker_arrangement* outputs, int32_t num_outputs);
v3_result (V3_API* get_bus_arrangement)(void* self, int32_t bus_direction, int32_t idx, v3_speaker_arrangement*);
v3_result (V3_API* can_process_sample_size)(void* self, int32_t symbolic_sample_size);
uint32_t (V3_API* get_latency_samples)(void* self);
v3_result (V3_API* setup_processing)(void* self, struct v3_process_setup* setup);
v3_result (V3_API* set_processing)(void* self, v3_bool state);
v3_result (V3_API* process)(void* self, struct v3_process_data* data);
uint32_t (V3_API* get_tail_samples)(void* self);
};


V3_API v3_result (*can_process_sample_size)
(void *self, int32_t symbolic_sample_size);
static constexpr const v3_tuid v3_audio_processor_iid =
V3_ID(0x42043F99, 0xB7DA453C, 0xA569E79D, 0x9AAEC33D);


V3_API uint32_t (*get_latency_samples)(void *self);
#ifdef __cplusplus


V3_API v3_result (*setup_processing)
(void *self, struct v3_process_setup *);
V3_API v3_result (*set_processing)
(void *self, v3_bool state);
/**
* C++ variants
*/


V3_API v3_result (*process)
(void *self, struct v3_process_data *);
struct v3_param_value_queue_cpp : v3_funknown {
v3_param_value_queue queue;
};


V3_API uint32_t (*get_tail_samples)(void *self);
struct v3_param_changes_cpp : v3_funknown {
v3_param_changes changes;
}; };


static const v3_tuid v3_audio_processor_iid =
V3_ID(0x42043F99, 0xB7DA453C, 0xA569E79D, 0x9AAEC33D);
struct v3_process_context_requirements_cpp : v3_funknown {
v3_process_context_requirements req;
};

struct v3_audio_processor_cpp : v3_funknown {
v3_audio_processor proc;
};

#endif


#include "align_pop.h" #include "align_pop.h"

+ 124
- 65
dpf/distrho/src/travesty/base.h View File

@@ -1,5 +1,5 @@
/* /*
* travesty, pure C interface to steinberg VST3 SDK
* travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * Permission to use, copy, modify, and/or distribute this software for any purpose with
@@ -20,6 +20,39 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>


/**
* deal with C vs C++ differences
*/

#ifdef __cplusplus

/**
* cast object into its proper C++ type.
* this is needed because `struct v3_funknown;` on a C++ class does not inherit `v3_funknown`'s fields.
* we can use this as a little helper for keeping both C and C++ compatiblity.
* specialized templated calls are defined where required
* (that is, object inherits from something other than `v3_funknown`)
*
* example usage: `v3_cpp_obj(obj)->method(obj, args...);`
*/
template<class T> static inline
constexpr T* v3_cpp_obj(T** obj)
{
/**
* this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default,
* but we need everything to be `static_cast` for it to be `constexpr` compatible.
*/
return static_cast<T*>(static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*3));
}

#else

# ifndef constexpr
# define constexpr
# endif

#endif

/** /**
* various types * various types
*/ */
@@ -31,15 +64,14 @@ typedef uint8_t v3_bool;


typedef uint32_t v3_param_id; typedef uint32_t v3_param_id;



/** /**
* low-level ABI nonsense * low-level ABI nonsense
*/ */


typedef uint8_t v3_tuid[16]; typedef uint8_t v3_tuid[16];


inline static bool
v3_tuid_match(const v3_tuid a, const v3_tuid b)
static inline
bool v3_tuid_match(const v3_tuid a, const v3_tuid b)
{ {
return memcmp(a, b, sizeof(v3_tuid)) == 0; return memcmp(a, b, sizeof(v3_tuid)) == 0;
} }
@@ -54,88 +86,90 @@ v3_tuid_match(const v3_tuid a, const v3_tuid b)


#if V3_COM_COMPAT #if V3_COM_COMPAT
enum { enum {
V3_NO_INTERFACE = 0x80004002L,
V3_OK = 0,
V3_TRUE = 0,
V3_FALSE = 1,
V3_INVALID_ARG = 0x80070057L,
V3_NOT_IMPLEMENTED = 0x80004001L,
V3_INTERNAL_ERR = 0x80004005L,
V3_NOT_INITIALISED = 0x8000FFFFL,
V3_NOMEM = 0x8007000EL
V3_NO_INTERFACE = 0x80004002L,
V3_OK = 0,
V3_TRUE = 0,
V3_FALSE = 1,
V3_INVALID_ARG = 0x80070057L,
V3_NOT_IMPLEMENTED = 0x80004001L,
V3_INTERNAL_ERR = 0x80004005L,
V3_NOT_INITIALIZED = 0x8000FFFFL,
V3_NOMEM = 0x8007000EL
}; };


# define V3_ID(a, b, c, d) { \
((a) & 0x000000FF), \
((a) & 0x0000FF00) >> 8, \
((a) & 0x00FF0000) >> 16, \
((a) & 0xFF000000) >> 24, \
\
((b) & 0x00FF0000) >> 16, \
((b) & 0xFF000000) >> 24, \
((b) & 0x000000FF), \
((b) & 0x0000FF00) >> 8, \
\
((c) & 0xFF000000) >> 24, \
((c) & 0x00FF0000) >> 16, \
((c) & 0x0000FF00) >> 8, \
((c) & 0x000000FF), \
\
((d) & 0xFF000000) >> 24, \
((d) & 0x00FF0000) >> 16, \
((d) & 0x0000FF00) >> 8, \
((d) & 0x000000FF), \
# define V3_ID(a, b, c, d) { \
((a) & 0x000000FF), \
((a) & 0x0000FF00) >> 8, \
((a) & 0x00FF0000) >> 16, \
((a) & 0xFF000000) >> 24, \
\
((b) & 0x00FF0000) >> 16, \
((b) & 0xFF000000) >> 24, \
((b) & 0x000000FF), \
((b) & 0x0000FF00) >> 8, \
\
((c) & 0xFF000000) >> 24, \
((c) & 0x00FF0000) >> 16, \
((c) & 0x0000FF00) >> 8, \
((c) & 0x000000FF), \
\
((d) & 0xFF000000) >> 24, \
((d) & 0x00FF0000) >> 16, \
((d) & 0x0000FF00) >> 8, \
((d) & 0x000000FF), \
} }


#else // V3_COM_COMPAT #else // V3_COM_COMPAT
enum { enum {
V3_NO_INTERFACE = -1,
V3_NO_INTERFACE = -1,
V3_OK, V3_OK,
V3_TRUE = V3_OK, V3_TRUE = V3_OK,
V3_FALSE, V3_FALSE,
V3_INVALID_ARG, V3_INVALID_ARG,
V3_NOT_IMPLEMENTED, V3_NOT_IMPLEMENTED,
V3_INTERNAL_ERR, V3_INTERNAL_ERR,
V3_NOT_INITIALISED,
V3_NOT_INITIALIZED,
V3_NOMEM V3_NOMEM
}; };


# define V3_ID(a, b, c, d) { \
((a) & 0xFF000000) >> 24, \
((a) & 0x00FF0000) >> 16, \
((a) & 0x0000FF00) >> 8, \
((a) & 0x000000FF), \
\
((b) & 0xFF000000) >> 24, \
((b) & 0x00FF0000) >> 16, \
((b) & 0x0000FF00) >> 8, \
((b) & 0x000000FF), \
\
((c) & 0xFF000000) >> 24, \
((c) & 0x00FF0000) >> 16, \
((c) & 0x0000FF00) >> 8, \
((c) & 0x000000FF), \
\
((d) & 0xFF000000) >> 24, \
((d) & 0x00FF0000) >> 16, \
((d) & 0x0000FF00) >> 8, \
((d) & 0x000000FF), \
# define V3_ID(a, b, c, d) { \
((a) & 0xFF000000) >> 24, \
((a) & 0x00FF0000) >> 16, \
((a) & 0x0000FF00) >> 8, \
((a) & 0x000000FF), \
\
((b) & 0xFF000000) >> 24, \
((b) & 0x00FF0000) >> 16, \
((b) & 0x0000FF00) >> 8, \
((b) & 0x000000FF), \
\
((c) & 0xFF000000) >> 24, \
((c) & 0x00FF0000) >> 16, \
((c) & 0x0000FF00) >> 8, \
((c) & 0x000000FF), \
\
((d) & 0xFF000000) >> 24, \
((d) & 0x00FF0000) >> 16, \
((d) & 0x0000FF00) >> 8, \
((d) & 0x000000FF), \
} }
#endif // V3_COM_COMPAT #endif // V3_COM_COMPAT


#define V3_ID_COPY(iid) \
{ iid[0], iid[1], iid[ 2], iid[ 3], iid[ 4], iid[ 5], iid[ 6], iid[ 7], \
iid[8], iid[9], iid[10], iid[11], iid[12], iid[13], iid[14], iid[15] }

/** /**
* funknown * funknown
*/ */


struct v3_funknown { struct v3_funknown {
V3_API v3_result (*query_interface)
(void *self, const v3_tuid iid, void **obj);

V3_API uint32_t (*ref)(void *self);
V3_API uint32_t (*unref)(void *self);
v3_result (V3_API* query_interface)(void* self, const v3_tuid iid, void** obj);
uint32_t (V3_API* ref)(void* self);
uint32_t (V3_API* unref)(void* self);
}; };


static const v3_tuid v3_funknown_iid =
static constexpr const v3_tuid v3_funknown_iid =
V3_ID(0x00000000, 0x00000000, 0xC0000000, 0x00000046); V3_ID(0x00000000, 0x00000000, 0xC0000000, 0x00000046);


/** /**
@@ -145,10 +179,35 @@ static const v3_tuid v3_funknown_iid =
struct v3_plugin_base { struct v3_plugin_base {
struct v3_funknown; struct v3_funknown;


V3_API v3_result (*initialise)
(void *self, struct v3_funknown *context);
V3_API v3_result (*terminate)(void *self);
v3_result (V3_API* initialize)(void* self, struct v3_funknown** context);
v3_result (V3_API* terminate)(void* self);
}; };


static const v3_tuid v3_plugin_base_iid =
static constexpr const v3_tuid v3_plugin_base_iid =
V3_ID(0x22888DDB, 0x156E45AE, 0x8358B348, 0x08190625); V3_ID(0x22888DDB, 0x156E45AE, 0x8358B348, 0x08190625);

#ifdef __cplusplus

/**
* helper C++ functions to manually call v3_funknown methods on an object.
*/

template<class T, class M> static inline
v3_result v3_cpp_obj_query_interface(T** obj, const v3_tuid iid, M*** obj2)
{
return static_cast<v3_funknown*>(static_cast<void*>(*obj))->query_interface(obj, iid, (void**)obj2);
}

template<class T> static inline
uint32_t v3_cpp_obj_ref(T** obj)
{
return static_cast<v3_funknown*>(static_cast<void*>(*obj))->ref(obj);
}

template<class T> static inline
uint32_t v3_cpp_obj_unref(T** obj)
{
return static_cast<v3_funknown*>(static_cast<void*>(*obj))->unref(obj);
}

#endif

+ 6
- 10
dpf/distrho/src/travesty/bstream.h View File

@@ -1,5 +1,5 @@
/* /*
* travesty, pure C interface to steinberg VST3 SDK
* travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * Permission to use, copy, modify, and/or distribute this software for any purpose with
@@ -27,15 +27,11 @@ enum v3_seek_mode {
struct v3_bstream { struct v3_bstream {
struct v3_funknown; struct v3_funknown;


V3_API v3_result (*read)
(void *self, void *buffer, int32_t num_bytes, int32_t *bytes_read);
V3_API v3_result (*write)
(void *self, void *buffer, int32_t num_bytes, int32_t *bytes_written);
V3_API v3_result (*seek)
(void *self, int64_t pos, int32_t seek_mode, int64_t *result);
V3_API v3_result (*tell)
(void *self, int64_t *pos);
v3_result (V3_API *read)(void* self, void* buffer, int32_t num_bytes, int32_t* bytes_read);
v3_result (V3_API *write)(void* self, void* buffer, int32_t num_bytes, int32_t* bytes_written);
v3_result (V3_API *seek)(void* self, int64_t pos, int32_t seek_mode, int64_t* result);
v3_result (V3_API *tell)(void* self, int64_t* pos);
}; };


static const v3_tuid v3_bstream_iid =
static constexpr const v3_tuid v3_bstream_iid =
V3_ID(0xC3BF6EA2, 0x30994752, 0x9B6BF990, 0x1EE33E9B); V3_ID(0xC3BF6EA2, 0x30994752, 0x9B6BF990, 0x1EE33E9B);

+ 58
- 41
dpf/distrho/src/travesty/component.h View File

@@ -1,5 +1,5 @@
/* /*
* travesty, pure C interface to steinberg VST3 SDK
* travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * Permission to use, copy, modify, and/or distribute this software for any purpose with
@@ -30,13 +30,17 @@ enum v3_media_types {
V3_EVENT V3_EVENT
}; };


inline static const char *
v3_media_type_str(int32_t type)
static inline
const char* v3_media_type_str(int32_t type)
{ {
switch (type) {
case V3_AUDIO: return "V3_AUDIO";
case V3_EVENT: return "V3_EVENT";
default: return "[unknown]";
switch (type)
{
case V3_AUDIO:
return "V3_AUDIO";
case V3_EVENT:
return "V3_EVENT";
default:
return "[unknown]";
} }
} }


@@ -45,13 +49,17 @@ enum v3_bus_direction {
V3_OUTPUT V3_OUTPUT
}; };


inline static const char *
v3_bus_direction_str(int32_t d)
static inline
const char* v3_bus_direction_str(int32_t d)
{ {
switch (d) {
case V3_INPUT: return "V3_INPUT";
case V3_OUTPUT: return "V3_OUTPUT";
default: return "[unknown]";
switch (d)
{
case V3_INPUT:
return "V3_INPUT";
case V3_OUTPUT:
return "V3_OUTPUT";
default:
return "[unknown]";
} }
} }


@@ -61,7 +69,7 @@ enum v3_bus_types {
}; };


enum v3_bus_flags { enum v3_bus_flags {
V3_DEFAULT_ACTIVE = 1,
V3_DEFAULT_ACTIVE = 1 << 0,
V3_IS_CONTROL_VOLTAGE = 1 << 1 V3_IS_CONTROL_VOLTAGE = 1 << 1
}; };


@@ -69,7 +77,6 @@ struct v3_bus_info {
int32_t media_type; int32_t media_type;
int32_t direction; int32_t direction;
int32_t channel_count; int32_t channel_count;

v3_str_128 bus_name; v3_str_128 bus_name;
int32_t bus_type; int32_t bus_type;
uint32_t flags; uint32_t flags;
@@ -84,34 +91,44 @@ struct v3_routing_info;
struct v3_component { struct v3_component {
struct v3_plugin_base; struct v3_plugin_base;


V3_API v3_result (*get_controller_class_id)
(void *self, v3_tuid class_id);

V3_API v3_result (*set_io_mode)
(void *self, int32_t io_mode);

V3_API int32_t (*get_bus_count)
(void *self, int32_t media_type, int32_t bus_direction);
V3_API v3_result (*get_bus_info)
(void *self, int32_t media_type, int32_t bus_direction,
int32_t bus_idx, struct v3_bus_info *bus_info);
V3_API v3_result (*get_routing_info)
(void *self, struct v3_routing_info *input,
struct v3_routing_info *output);
V3_API v3_result (*activate_bus)
(void *self, int32_t media_type, int32_t bus_direction,
int32_t bus_idx, v3_bool state);

V3_API v3_result (*set_active)
(void *self, v3_bool state);

V3_API v3_result (*set_state)
(void *self, struct v3_bstream **);
V3_API v3_result (*get_state)
(void *self, struct v3_bstream **);
v3_result (V3_API *get_controller_class_id)(void* self, v3_tuid class_id);
v3_result (V3_API *set_io_mode)(void* self, int32_t io_mode);
int32_t (V3_API *get_bus_count)(void* self, int32_t media_type, int32_t bus_direction);
v3_result (V3_API *get_bus_info)(void* self, int32_t media_type, int32_t bus_direction,
int32_t bus_idx, struct v3_bus_info* bus_info);
v3_result (V3_API *get_routing_info)(void* self, struct v3_routing_info* input, struct v3_routing_info* output);
v3_result (V3_API *activate_bus)(void* self, int32_t media_type, int32_t bus_direction,
int32_t bus_idx, v3_bool state);
v3_result (V3_API *set_active)(void* self, v3_bool state);
v3_result (V3_API *set_state)(void* self, struct v3_bstream **);
v3_result (V3_API *get_state)(void* self, struct v3_bstream **);
}; };


static const v3_tuid v3_component_iid =
static constexpr const v3_tuid v3_component_iid =
V3_ID(0xE831FF31, 0xF2D54301, 0x928EBBEE, 0x25697802); V3_ID(0xE831FF31, 0xF2D54301, 0x928EBBEE, 0x25697802);


#ifdef __cplusplus

/**
* C++ variants
*/

struct v3_component_cpp : v3_funknown {
v3_plugin_base base;
v3_component comp;
};

template<> inline
constexpr v3_component* v3_cpp_obj(v3_component** obj)
{
/**
* this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default,
* but we need everything to be `static_cast` for it to be `constexpr` compatible.
*/
return static_cast<v3_component*>(
static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*5));
}

#endif

#include "align_pop.h" #include "align_pop.h"

+ 70
- 42
dpf/distrho/src/travesty/edit_controller.h View File

@@ -1,5 +1,5 @@
/* /*
* travesty, pure C interface to steinberg VST3 SDK
* travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * Permission to use, copy, modify, and/or distribute this software for any purpose with
@@ -26,21 +26,29 @@
* component handler * component handler
*/ */


enum {
V3_RESTART_RELOAD_COMPONENT = 1 << 0,
V3_RESTART_IO_CHANGED = 1 << 1,
V3_RESTART_PARAM_VALUES_CHANGED = 1 << 2,
V3_RESTART_LATENCY_CHANGED = 1 << 3,
V3_RESTART_PARAM_TITLES_CHANGED = 1 << 4,
V3_RESTART_MIDI_CC_ASSIGNMENT_CHANGED = 1 << 5,
V3_RESTART_NOTE_EXPRESSION_CHANGED = 1 << 6,
V3_RESTART_IO_TITLES_CHANGED = 1 << 7,
V3_RESTART_PREFETCHABLE_SUPPORT_CHANGED = 1 << 8,
V3_RESTART_ROUTING_INFO_CHANGED = 1 << 9
};

struct v3_component_handler { struct v3_component_handler {
struct v3_funknown; struct v3_funknown;


V3_API v3_result (*begin_edit)
(void *self, v3_param_id);
V3_API v3_result (*perform_edit)
(void *self, v3_param_id, double value_normalised);
V3_API v3_result (*end_edit)
(void *self, v3_param_id);

V3_API v3_result (*restart_component)
(void *self, int32_t flags);
v3_result (V3_API* begin_edit)(void* self, v3_param_id);
v3_result (V3_API* perform_edit)(void* self, v3_param_id, double value_normalised);
v3_result (V3_API* end_edit)(void* self, v3_param_id);
v3_result (V3_API* restart_component)(void* self, int32_t flags);
}; };


static const v3_tuid v3_component_handler_iid =
static constexpr const v3_tuid v3_component_handler_iid =
V3_ID(0x93A0BEA3, 0x0BD045DB, 0x8E890B0C, 0xC1E46AC6); V3_ID(0x93A0BEA3, 0x0BD045DB, 0x8E890B0C, 0xC1E46AC6);


/** /**
@@ -48,7 +56,7 @@ static const v3_tuid v3_component_handler_iid =
*/ */


enum { enum {
V3_PARAM_CAN_AUTOMATE = 1,
V3_PARAM_CAN_AUTOMATE = 1 << 0,
V3_PARAM_READ_ONLY = 1 << 1, V3_PARAM_READ_ONLY = 1 << 1,
V3_PARAM_WRAP_AROUND = 1 << 2, V3_PARAM_WRAP_AROUND = 1 << 2,
V3_PARAM_IS_LIST = 1 << 3, V3_PARAM_IS_LIST = 1 << 3,
@@ -59,15 +67,11 @@ enum {


struct v3_param_info { struct v3_param_info {
v3_param_id param_id; v3_param_id param_id;

v3_str_128 title; v3_str_128 title;
v3_str_128 short_title; v3_str_128 short_title;
v3_str_128 units; v3_str_128 units;

int32_t step_count; int32_t step_count;

double default_normalised_value; double default_normalised_value;

int32_t unit_id; int32_t unit_id;
int32_t flags; int32_t flags;
}; };
@@ -75,39 +79,63 @@ struct v3_param_info {
struct v3_edit_controller { struct v3_edit_controller {
struct v3_plugin_base; struct v3_plugin_base;


V3_API v3_result (*set_component_state)
(void *self, struct v3_bstream *);
V3_API v3_result (*set_state)
(void *self, struct v3_bstream *);
V3_API v3_result (*get_state)
(void *self, struct v3_bstream *);
v3_result (V3_API* set_component_state)(void* self, struct v3_bstream*);
v3_result (V3_API* set_state)(void* self, struct v3_bstream*);
v3_result (V3_API* get_state)(void* self, struct v3_bstream*);
int32_t (V3_API* get_parameter_count)(void* self);
v3_result (V3_API* get_parameter_info)(void* self, int32_t param_idx, struct v3_param_info*);
v3_result (V3_API* get_parameter_string_for_value)(void* self, v3_param_id, double normalised, v3_str_128 output);
v3_result (V3_API* get_parameter_value_for_string)(void* self, v3_param_id, int16_t* input, double* output);
double (V3_API* normalised_parameter_to_plain)(void* self, v3_param_id, double normalised);
double (V3_API* plain_parameter_to_normalised)(void* self, v3_param_id, double plain);
double (V3_API* get_parameter_normalised)(void* self, v3_param_id);
v3_result (V3_API* set_parameter_normalised)(void* self, v3_param_id, double normalised);
v3_result (V3_API* set_component_handler)(void* self, struct v3_component_handler**);
struct v3_plugin_view** (V3_API* create_view)(void* self, const char* name);
};


V3_API int32_t (*get_parameter_count)(void *self);
V3_API v3_result (*get_param_info)
(void *self, int32_t param_idx, struct v3_param_info *);
static constexpr const v3_tuid v3_edit_controller_iid =
V3_ID(0xDCD7BBE3, 0x7742448D, 0xA874AACC, 0x979C759E);


V3_API v3_result (*get_param_string_for_value)
(void *self, v3_param_id, double normalised, v3_str_128 output);
V3_API v3_result (*get_param_value_for_string)
(void *self, v3_param_id, int16_t *input, double *output);
/**
* midi mapping
*/

struct v3_midi_mapping {
struct v3_funknown;

v3_result (V3_API* get_midi_controller_assignment)(void* self, int32_t bus, int16_t channel, int16_t cc, v3_param_id* id);
};


V3_API double (*normalised_param_to_plain)
(void *self, v3_param_id, double normalised);
V3_API double (*plain_param_to_normalised)
(void *self, v3_param_id, double normalised);
static constexpr const v3_tuid v3_midi_mapping_iid =
V3_ID(0xDF0FF9F7, 0x49B74669, 0xB63AB732, 0x7ADBF5E5);


V3_API double (*get_param_normalised)(void *self, v3_param_id);
V3_API v3_result (*set_param_normalised)
(void *self, v3_param_id, double normalised);
#ifdef __cplusplus


V3_API v3_result (*set_component_handler)
(void *self, struct v3_component_handler **);
/**
* C++ variants
*/


V3_API struct v3_plug_view **(*create_view)
(void *self, const char *name);
struct v3_edit_controller_cpp : v3_funknown {
v3_plugin_base base;
v3_edit_controller ctrl;
}; };


static const v3_tuid v3_edit_controller_iid =
V3_ID(0xDCD7BBE3, 0x7742448D, 0xA874AACC, 0x979C759E);
struct v3_midi_mapping_cpp : v3_funknown {
v3_midi_mapping map;
};

template<> inline
constexpr v3_edit_controller* v3_cpp_obj(v3_edit_controller** obj)
{
/**
* this ugly piece of code is required due to C++ assuming `reinterpret_cast` by default,
* but we need everything to be `static_cast` for it to be `constexpr` compatible.
*/
return static_cast<v3_edit_controller*>(
static_cast<void*>(static_cast<uint8_t*>(static_cast<void*>(*obj)) + sizeof(void*)*5));
}

#endif


#include "align_pop.h" #include "align_pop.h"

+ 10
- 29
dpf/distrho/src/travesty/events.h View File

@@ -1,5 +1,5 @@
/* /*
* travesty, pure C interface to steinberg VST3 SDK
* travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * Permission to use, copy, modify, and/or distribute this software for any purpose with
@@ -22,18 +22,13 @@


/** /**
* note events * note events
*
* i know there's others, but we don't need them right now. whatever.
* handle them later.
*/ */


struct v3_event_note_on { struct v3_event_note_on {
int16_t channel; int16_t channel;
int16_t pitch; // MIDI note number int16_t pitch; // MIDI note number

float tuning; float tuning;
float velocity; float velocity;

int32_t length; int32_t length;
int32_t note_id; int32_t note_id;
}; };
@@ -41,9 +36,7 @@ struct v3_event_note_on {
struct v3_event_note_off { struct v3_event_note_off {
int16_t channel; int16_t channel;
int16_t pitch; // MIDI note number int16_t pitch; // MIDI note number

float velocity; float velocity;

int32_t note_id; int32_t note_id;
float tuning; float tuning;
}; };
@@ -51,14 +44,12 @@ struct v3_event_note_off {
struct v3_event_data { struct v3_event_data {
uint32_t size; uint32_t size;
uint32_t type; uint32_t type;

const uint8_t *bytes;
const uint8_t* bytes;
}; };


struct v3_event_poly_pressure { struct v3_event_poly_pressure {
int16_t channel; int16_t channel;
int16_t pitch; int16_t pitch;

float pressure; float pressure;
int32_t note_id; int32_t note_id;
}; };
@@ -67,22 +58,19 @@ struct v3_event_chord {
int16_t root; int16_t root;
int16_t bass_note; int16_t bass_note;
int16_t mask; int16_t mask;

uint16_t text_len; uint16_t text_len;
const int16_t *text;
const int16_t* text;
}; };


struct v3_event_scale { struct v3_event_scale {
int16_t root; int16_t root;
int16_t mask; int16_t mask;

uint16_t text_len; uint16_t text_len;
const int16_t *text;
const int16_t* text;
}; };


struct v3_event_legacy_midi_cc_out { struct v3_event_legacy_midi_cc_out {
uint8_t cc_number; uint8_t cc_number;

int8_t channel; int8_t channel;
int8_t value; int8_t value;
int8_t value2; int8_t value2;
@@ -96,9 +84,8 @@ struct v3_event_note_expression_value {


struct v3_event_note_expression_text { struct v3_event_note_expression_text {
int32_t note_id; int32_t note_id;

uint32_t text_len; uint32_t text_len;
const int16_t *text;
const int16_t* text;
}; };


/** /**
@@ -106,7 +93,7 @@ struct v3_event_note_expression_text {
*/ */


enum v3_event_flags { enum v3_event_flags {
V3_EVENT_IS_LIVE = 1
V3_EVENT_IS_LIVE = 1 << 0
}; };


enum v3_event_type { enum v3_event_type {
@@ -118,19 +105,15 @@ enum v3_event_type {
V3_EVENT_NOTE_EXP_TEXT = 5, V3_EVENT_NOTE_EXP_TEXT = 5,
V3_EVENT_CHORD = 6, V3_EVENT_CHORD = 6,
V3_EVENT_SCALE = 7, V3_EVENT_SCALE = 7,

V3_EVENT_LEGACY_MIDI_CC_OUT = 65535 V3_EVENT_LEGACY_MIDI_CC_OUT = 65535
}; };


struct v3_event { struct v3_event {
int32_t bus_index; int32_t bus_index;
int32_t sample_offset; int32_t sample_offset;

double ppq_position; double ppq_position;
uint16_t flags; uint16_t flags;

uint16_t type; uint16_t type;

union { union {
struct v3_event_note_on note_on; struct v3_event_note_on note_on;
struct v3_event_note_off note_off; struct v3_event_note_off note_off;
@@ -151,14 +134,12 @@ struct v3_event {
struct v3_event_list { struct v3_event_list {
struct v3_funknown; struct v3_funknown;


V3_API uint32_t (*get_event_count)(void *self);
V3_API v3_result (*get_event)
(void *self, int32_t idx, struct v3_event *);
V3_API v3_result (*add_event)
(void *self, struct v3_event *);
uint32_t (V3_API* get_event_count)(void* self);
v3_result (V3_API* get_event)(void* self, int32_t idx, struct v3_event* event);
v3_result (V3_API* add_event)(void* self, struct v3_event* event);
}; };


static const v3_tuid v3_event_list_iid =
static constexpr const v3_tuid v3_event_list_iid =
V3_ID(0x3A2C4214, 0x346349FE, 0xB2C4F397, 0xB9695A44); V3_ID(0x3A2C4214, 0x346349FE, 0xB2C4F397, 0xB9695A44);


#include "align_pop.h" #include "align_pop.h"

+ 32
- 25
dpf/distrho/src/travesty/factory.h View File

@@ -1,5 +1,5 @@
/* /*
* travesty, pure C interface to steinberg VST3 SDK
* travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * Permission to use, copy, modify, and/or distribute this software for any purpose with
@@ -26,12 +26,12 @@ struct v3_factory_info {
char vendor[64]; char vendor[64];
char url[256]; char url[256];
char email[128]; char email[128];
int32_t flags;
int32_t flags; // set to 0x10 (unicode)
}; };


struct v3_class_info { struct v3_class_info {
v3_tuid class_id; v3_tuid class_id;
int32_t cardinality; // set to 0x7FFFFFFF
int32_t cardinality; // set to 0x7FFFFFFF (many instances)
char category[32]; char category[32];
char name[64]; char name[64];
}; };
@@ -39,31 +39,29 @@ struct v3_class_info {
struct v3_plugin_factory { struct v3_plugin_factory {
struct v3_funknown; struct v3_funknown;


V3_API v3_result (*get_factory_info)
(void *self, struct v3_factory_info *);

V3_API int32_t (*num_classes)(void *self);

V3_API v3_result (*get_class_info)
(void *self, int32_t idx, struct v3_class_info *);

V3_API v3_result (*create_instance)
(void *self, const v3_tuid class_id, const v3_tuid iid, void **instance);
v3_result (V3_API *get_factory_info)(void* self, struct v3_factory_info*);
int32_t (V3_API *num_classes)(void* self);
v3_result (V3_API *get_class_info)(void* self, int32_t idx, struct v3_class_info*);
v3_result (V3_API *create_instance)(void* self, const v3_tuid class_id, const v3_tuid iid, void** instance);
}; };


static const v3_tuid v3_plugin_factory_iid =
static constexpr const v3_tuid v3_plugin_factory_iid =
V3_ID(0x7A4D811C, 0x52114A1F, 0xAED9D2EE, 0x0B43BF9F); V3_ID(0x7A4D811C, 0x52114A1F, 0xAED9D2EE, 0x0B43BF9F);


/** /**
* plugin factory v2 * plugin factory v2
*/ */


enum {
V3_DISTRIBUTABLE = 1 << 0,
V3_SIMPLE_MODE = 1 << 1
};

struct v3_class_info_2 { struct v3_class_info_2 {
v3_tuid class_id; v3_tuid class_id;
int32_t cardinality; // set to 0x7FFFFFFF int32_t cardinality; // set to 0x7FFFFFFF
char category[32]; char category[32];
char name[64]; char name[64];

uint32_t class_flags; uint32_t class_flags;
char sub_categories[128]; char sub_categories[128];
char vendor[64]; char vendor[64];
@@ -74,11 +72,10 @@ struct v3_class_info_2 {
struct v3_plugin_factory_2 { struct v3_plugin_factory_2 {
struct v3_plugin_factory; struct v3_plugin_factory;


V3_API v3_result (*get_class_info_2)
(void *self, int32_t idx, struct v3_class_info_2 *);
v3_result (V3_API *get_class_info_2)(void* self, int32_t idx, struct v3_class_info_2*);
}; };


static const v3_tuid v3_plugin_factory_2_iid =
static constexpr const v3_tuid v3_plugin_factory_2_iid =
V3_ID(0x0007B650, 0xF24B4C0B, 0xA464EDB9, 0xF00B2ABB); V3_ID(0x0007B650, 0xF24B4C0B, 0xA464EDB9, 0xF00B2ABB);


/** /**
@@ -93,7 +90,6 @@ struct v3_class_info_3 {
int32_t cardinality; // set to 0x7FFFFFFF int32_t cardinality; // set to 0x7FFFFFFF
char category[32]; char category[32];
int16_t name[64]; int16_t name[64];

uint32_t class_flags; uint32_t class_flags;
char sub_categories[128]; char sub_categories[128];
int16_t vendor[64]; int16_t vendor[64];
@@ -104,12 +100,23 @@ struct v3_class_info_3 {
struct v3_plugin_factory_3 { struct v3_plugin_factory_3 {
struct v3_plugin_factory_2; struct v3_plugin_factory_2;


V3_API v3_result (*get_class_info_utf16)
(void *self, int32_t idx, struct v3_class_info_3 *);

V3_API v3_result (*set_host_context)
(void *self, struct v3_funknown *host);
v3_result (V3_API *get_class_info_utf16)(void* self, int32_t idx, struct v3_class_info_3*);
v3_result (V3_API *set_host_context)(void* self, struct v3_funknown** host);
}; };


static const v3_tuid v3_plugin_factory_3_iid =
static constexpr const v3_tuid v3_plugin_factory_3_iid =
V3_ID(0x4555A2AB, 0xC1234E57, 0x9B122910, 0x36878931); V3_ID(0x4555A2AB, 0xC1234E57, 0x9B122910, 0x36878931);

#ifdef __cplusplus

/**
* C++ variants
*/

struct v3_plugin_factory_cpp : v3_funknown {
v3_plugin_factory v1;
v3_plugin_factory_2 v2;
v3_plugin_factory_3 v3;
};

#endif

+ 49
- 0
dpf/distrho/src/travesty/host.h View File

@@ -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"

+ 93
- 0
dpf/distrho/src/travesty/message.h View File

@@ -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"

+ 112
- 43
dpf/distrho/src/travesty/view.h View File

@@ -1,5 +1,5 @@
/* /*
* travesty, pure C interface to steinberg VST3 SDK
* travesty, pure C VST3-compatible interface
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.com> * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
* *
* Permission to use, copy, modify, and/or distribute this software for any purpose with * Permission to use, copy, modify, and/or distribute this software for any purpose with
@@ -19,7 +19,7 @@
#include "base.h" #include "base.h"


/** /**
* base IPlugFrame stuff
* base view stuff
*/ */


struct v3_view_rect { struct v3_view_rect {
@@ -41,50 +41,43 @@ struct v3_view_rect {
# define V3_VIEW_PLATFORM_TYPE_NATIVE V3_VIEW_PLATFORM_TYPE_X11 # define V3_VIEW_PLATFORM_TYPE_NATIVE V3_VIEW_PLATFORM_TYPE_X11
#endif #endif


struct v3_plug_frame;

struct v3_plug_view {
struct v3_funknown;

V3_API v3_result (*is_platform_type_supported)
(void *self, const char *platform_type);

V3_API v3_result (*attached)
(void *self, void *parent, const char *platform_type);
V3_API v3_result (*removed)(void *self);

V3_API v3_result (*on_wheel)(void *self, float distance);
V3_API v3_result (*on_key_down)
(void *self, int16_t key_char, int16_t key_code, int16_t modifiers);
V3_API v3_result (*on_key_up)
(void *self, int16_t key_char, int16_t key_code, int16_t modifiers);
/**
* plugin view
*/


V3_API v3_result (*get_size)
(void *self, struct v3_view_rect *);
V3_API v3_result (*set_size)
(void *self, struct v3_view_rect *);
struct v3_plugin_frame;


V3_API v3_result (*on_focus)
(void *self, v3_bool state);
struct v3_plugin_view {
struct v3_funknown;


V3_API v3_result (*set_frame)
(void *self, struct v3_plug_frame *);
V3_API v3_result (*can_resize)(void *self);
V3_API v3_result (*check_size_constraint)
(void *self, struct v3_view_rect *);
v3_result (V3_API* is_platform_type_supported)(void* self, const char* platform_type);
v3_result (V3_API* attached)(void* self, void* parent, const char* platform_type);
v3_result (V3_API* removed)(void* self);
v3_result (V3_API* on_wheel)(void* self, float distance);
v3_result (V3_API* on_key_down)(void* self, int16_t key_char, int16_t key_code, int16_t modifiers);
v3_result (V3_API* on_key_up)(void* self, int16_t key_char, int16_t key_code, int16_t modifiers);
v3_result (V3_API* get_size)(void* self, struct v3_view_rect*);
v3_result (V3_API* on_size)(void* self, struct v3_view_rect*);
v3_result (V3_API* on_focus)(void* self, v3_bool state);
v3_result (V3_API* set_frame)(void* self, struct v3_plugin_frame**);
v3_result (V3_API* can_resize)(void* self);
v3_result (V3_API* check_size_constraint)(void* self, struct v3_view_rect*);
}; };


static const v3_tuid v3_plug_view_iid =
static constexpr const v3_tuid v3_plugin_view_iid =
V3_ID(0x5BC32507, 0xD06049EA, 0xA6151B52, 0x2B755B29); V3_ID(0x5BC32507, 0xD06049EA, 0xA6151B52, 0x2B755B29);


struct v3_plug_frame {
/**
* plugin frame
*/

struct v3_plugin_frame {
struct v3_funknown; struct v3_funknown;


V3_API v3_result (*resize_view)
(void *self, struct v3_plug_view *, struct v3_view_rect *);
v3_result (V3_API* resize_view)(void* self, struct v3_plugin_view**, struct v3_view_rect*);
}; };


static const v3_tuid v3_plug_frame_iid =
static constexpr const v3_tuid v3_plugin_frame_iid =
V3_ID(0x367FAF01, 0xAFA94693, 0x8D4DA2A0, 0xED0882A3); V3_ID(0x367FAF01, 0xAFA94693, 0x8D4DA2A0, 0xED0882A3);


/** /**
@@ -92,26 +85,102 @@ static const v3_tuid v3_plug_frame_iid =
* (same IID/iface as presonus view scaling) * (same IID/iface as presonus view scaling)
*/ */


struct v3_plug_view_content_scale_steinberg {
struct v3_plugin_view_content_scale {
struct v3_funknown; struct v3_funknown;


V3_API v3_result (*set_content_scale_factor)
(void *self, float factor);
v3_result (V3_API* set_content_scale_factor)(void* self, float factor);
}; };


static const v3_tuid v3_plug_view_content_scale_steinberg_iid =
static constexpr const v3_tuid v3_plugin_view_content_scale_iid =
V3_ID(0x65ED9690, 0x8AC44525, 0x8AADEF7A, 0x72EA703F); V3_ID(0x65ED9690, 0x8AC44525, 0x8AADEF7A, 0x72EA703F);


/** /**
* support for querying the view to find what control is underneath the mouse * support for querying the view to find what control is underneath the mouse
*/ */


struct v3_plug_view_param_finder {
struct v3_plugin_view_parameter_finder {
struct v3_funknown; struct v3_funknown;


V3_API v3_result (*find_parameter)
(void *self, int32_t x, int32_t y, v3_param_id *);
v3_result (V3_API* find_parameter)(void* self, int32_t x, int32_t y, v3_param_id *);
}; };


static const v3_tuid v3_plug_view_param_finder_iid =
static constexpr const v3_tuid v3_plugin_view_parameter_finder_iid =
V3_ID(0x0F618302, 0x215D4587, 0xA512073C, 0x77B9D383); V3_ID(0x0F618302, 0x215D4587, 0xA512073C, 0x77B9D383);

/**
* linux event handler
*/

struct v3_event_handler {
struct v3_funknown;

void (V3_API* on_fd_is_set)(void* self, int fd);
};

static constexpr const v3_tuid v3_event_handler_iid =
V3_ID(0x561E65C9, 0x13A0496F, 0x813A2C35, 0x654D7983);

/**
* linux timer handler
*/

struct v3_timer_handler {
struct v3_funknown;

void (V3_API* on_timer)(void* self);
};

static constexpr const v3_tuid v3_timer_handler_iid =
V3_ID(0x10BDD94F, 0x41424774, 0x821FAD8F, 0xECA72CA9);

/**
* linux host run loop
*/

struct v3_run_loop {
struct v3_funknown;

v3_result (V3_API* register_event_handler)(void* self, v3_event_handler** handler, int fd);
v3_result (V3_API* unregister_event_handler)(void* self, v3_event_handler** handler);
v3_result (V3_API* register_timer)(void* self, v3_timer_handler** handler, uint64_t ms);
v3_result (V3_API* unregister_timer)(void* self, v3_timer_handler** handler);
};

static constexpr const v3_tuid v3_run_loop_iid =
V3_ID(0x18C35366, 0x97764F1A, 0x9C5B8385, 0x7A871389);

#ifdef __cplusplus

/**
* C++ variants
*/

struct v3_plugin_view_cpp : v3_funknown {
v3_plugin_view view;
};

struct v3_plugin_frame_cpp : v3_funknown {
v3_plugin_frame frame;
};

struct v3_plugin_view_content_scale_cpp : v3_funknown {
v3_plugin_view_content_scale scale;
};

struct v3_plugin_view_parameter_finder_cpp : v3_funknown {
v3_plugin_view_parameter_finder finder;
};

struct v3_event_handler_cpp : v3_funknown {
v3_event_handler handler;
};

struct v3_timer_handler_cpp : v3_funknown {
v3_timer_handler handler;
};

struct v3_run_loop_cpp : v3_funknown {
v3_run_loop loop;
};

#endif

+ 7
- 0
dpf/utils/lv2-ttl-generator/lv2_ttl_generator.c View File

@@ -63,7 +63,14 @@ int main(int argc, char* argv[])
} }


#ifdef TTL_GENERATOR_WINDOWS #ifdef TTL_GENERATOR_WINDOWS
# if defined(__GNUC__) && (__GNUC__ >= 9)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-function-type"
# endif
const TTL_Generator_Function ttlFn = (TTL_Generator_Function)GetProcAddress(handle, "lv2_generate_ttl"); const TTL_Generator_Function ttlFn = (TTL_Generator_Function)GetProcAddress(handle, "lv2_generate_ttl");
# if defined(__GNUC__) && (__GNUC__ >= 9)
# pragma GCC diagnostic pop
# endif
#else #else
const TTL_Generator_Function ttlFn = (TTL_Generator_Function)dlsym(handle, "lv2_generate_ttl"); const TTL_Generator_Function ttlFn = (TTL_Generator_Function)dlsym(handle, "lv2_generate_ttl");
#endif #endif


+ 10
- 1
dpf/utils/package-osx-bundles.sh View File

@@ -14,10 +14,12 @@ SNAME="$(echo ${NAME} | tr -d ' ' | tr '/' '-')"


rm -rf lv2 rm -rf lv2
rm -rf vst2 rm -rf vst2
rm -rf vst3


mkdir lv2 vst2
mkdir lv2 vst2 vst3
mv *.lv2 lv2/ mv *.lv2 lv2/
mv *.vst vst2/ mv *.vst vst2/
mv *.vst3 vst3/


pkgbuild \ pkgbuild \
--identifier "studio.kx.distrho.plugins.${SNAME}.lv2bundles" \ --identifier "studio.kx.distrho.plugins.${SNAME}.lv2bundles" \
@@ -31,6 +33,12 @@ pkgbuild \
--root "${PWD}/vst2/" \ --root "${PWD}/vst2/" \
../dpf-${SNAME}-vst2bundles.pkg ../dpf-${SNAME}-vst2bundles.pkg


pkgbuild \
--identifier "studio.kx.distrho.plugins.${SNAME}.vst3bundles" \
--install-location "/Library/Audio/Plug-Ins/VST3/" \
--root "${PWD}/vst3/" \
../dpf-${SNAME}-vst3bundles.pkg

cd .. cd ..


DPF_UTILS_DIR=$(dirname ${0}) DPF_UTILS_DIR=$(dirname ${0})
@@ -39,6 +47,7 @@ sed -e "s|@name@|${NAME}|" ${DPF_UTILS_DIR}/plugin.pkg/welcome.txt.in > build/we
sed -e "s|@builddir@|${PWD}/build|" \ sed -e "s|@builddir@|${PWD}/build|" \
-e "s|@lv2bundleref@|dpf-${SNAME}-lv2bundles.pkg|" \ -e "s|@lv2bundleref@|dpf-${SNAME}-lv2bundles.pkg|" \
-e "s|@vst2bundleref@|dpf-${SNAME}-vst2bundles.pkg|" \ -e "s|@vst2bundleref@|dpf-${SNAME}-vst2bundles.pkg|" \
-e "s|@vst3bundleref@|dpf-${SNAME}-vst3bundles.pkg|" \
-e "s|@name@|${NAME}|g" \ -e "s|@name@|${NAME}|g" \
-e "s|@sname@|${SNAME}|g" \ -e "s|@sname@|${SNAME}|g" \
${DPF_UTILS_DIR}/plugin.pkg/package.xml.in > build/package.xml ${DPF_UTILS_DIR}/plugin.pkg/package.xml.in > build/package.xml


+ 4
- 0
dpf/utils/plugin.pkg/package.xml.in View File

@@ -11,8 +11,12 @@
<choice id="studio.kx.distrho.@sname@-vst2" title="VST2" description="Install VST2 plugins" visible="true"> <choice id="studio.kx.distrho.@sname@-vst2" title="VST2" description="Install VST2 plugins" visible="true">
<pkg-ref id="studio.kx.distrho.@sname@-vst2bundles" version="0">@vst2bundleref@</pkg-ref> <pkg-ref id="studio.kx.distrho.@sname@-vst2bundles" version="0">@vst2bundleref@</pkg-ref>
</choice> </choice>
<choice id="studio.kx.distrho.@sname@-vst3" title="VST3" description="Install VST3 plugins" visible="true">
<pkg-ref id="studio.kx.distrho.@sname@-vst3bundles" version="0">@vst3bundleref@</pkg-ref>
</choice>
<choices-outline> <choices-outline>
<line choice="studio.kx.distrho.@sname@-lv2"/> <line choice="studio.kx.distrho.@sname@-lv2"/>
<line choice="studio.kx.distrho.@sname@-vst2"/> <line choice="studio.kx.distrho.@sname@-vst2"/>
<line choice="studio.kx.distrho.@sname@-vst3"/>
</choices-outline> </choices-outline>
</installer-gui-script> </installer-gui-script>

+ 7
- 0
dpf/utils/valgrind-dpf.supp View File

@@ -39,3 +39,10 @@
fun:XInitThreads fun:XInitThreads
... ...
} }
{
ignore XrmGetStringDatabase
Memcheck:Leak
...
fun:XrmGetStringDatabase
...
}

Loading…
Cancel
Save