127 changes: 127 additions & 0 deletions dpf/distrho/src/DistrhoUIStub.cpp
@@ -0,0 +1,127 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 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.
*/

#include "DistrhoUIInternal.hpp"

START_NAMESPACE_DISTRHO

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

#if ! DISTRHO_PLUGIN_WANT_STATE
static constexpr const setStateFunc setStateCallback = nullptr;
#endif
#if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT
static constexpr const sendNoteFunc sendNoteCallback = nullptr;
#endif

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

/**
* Stub UI class, does nothing but serving as example code for other implementations.
*/
class UIStub
{
public:
UIStub(const intptr_t winId,
const double sampleRate,
const char* const bundlePath,
void* const dspPtr,
const float scaleFactor)
: fUI(this, winId, sampleRate,
editParameterCallback,
setParameterCallback,
setStateCallback,
sendNoteCallback,
setSizeCallback,
fileRequestCallback,
bundlePath, dspPtr, scaleFactor)
{
}

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

private:
// Stub stuff here

// Plugin UI (after Stub stuff so the UI can call into us during its constructor)
UIExporter fUI;

// ----------------------------------------------------------------------------------------------------------------
// DPF callbacks

void editParameter(uint32_t, bool) const
{
}

static void editParameterCallback(void* const ptr, const uint32_t rindex, const bool started)
{
static_cast<UIStub*>(ptr)->editParameter(rindex, started);
}

void setParameterValue(uint32_t, float)
{
}

static void setParameterCallback(void* const ptr, const uint32_t rindex, const float value)
{
static_cast<UIStub*>(ptr)->setParameterValue(rindex, value);
}

void setSize(uint, uint)
{
}

static void setSizeCallback(void* const ptr, const uint width, const uint height)
{
static_cast<UIStub*>(ptr)->setSize(width, height);
}

#if DISTRHO_PLUGIN_WANT_STATE
void setState(const char*, const char*)
{
}

static void setStateCallback(void* const ptr, const char* key, const char* value)
{
static_cast<UIStub*>(ptr)->setState(key, value);
}
#endif

#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity)
{
}

static void sendNoteCallback(void* const ptr, const uint8_t channel, const uint8_t note, const uint8_t velocity)
{
static_cast<UIStub*>(ptr)->sendNote(channel, note, velocity);
}
#endif

bool fileRequest(const char*)
{
return true;
}

static bool fileRequestCallback(void* const ptr, const char* const key)
{
return static_cast<UIStub*>(ptr)->fileRequest(key);
}
};

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

END_NAMESPACE_DISTRHO
373 changes: 223 additions & 150 deletions dpf/distrho/src/DistrhoUIVST3.cpp

Large diffs are not rendered by default.

37 changes: 37 additions & 0 deletions dpf/distrho/src/clap/audio-buffer.h
@@ -0,0 +1,37 @@
#pragma once

#include "private/std.h"

#ifdef __cplusplus
extern "C" {
#endif

// Sample code for reading a stereo buffer:
//
// bool isLeftConstant = (buffer->constant_mask & (1 << 0)) != 0;
// bool isRightConstant = (buffer->constant_mask & (1 << 1)) != 0;
//
// for (int i = 0; i < N; ++i) {
// float l = data32[0][isLeftConstant ? 0 : i];
// float r = data32[1][isRightConstant ? 0 : i];
// }
//
// Note: checking the constant mask is optional, and this implies that
// the buffer must be filled with the constant value.
// Rationale: if a buffer reader doesn't check the constant mask, then it may
// process garbage samples and in result, garbage samples may be transmitted
// to the audio interface with all the bad consequences it can have.
//
// The constant mask is a hint.
typedef struct clap_audio_buffer {
// Either data32 or data64 pointer will be set.
float **data32;
double **data64;
uint32_t channel_count;
uint32_t latency; // latency from/to the audio interface
uint64_t constant_mask;
} clap_audio_buffer_t;

#ifdef __cplusplus
}
#endif
68 changes: 68 additions & 0 deletions dpf/distrho/src/clap/entry.h
@@ -0,0 +1,68 @@
#pragma once

#include "version.h"
#include "private/macros.h"

#ifdef __cplusplus
extern "C" {
#endif

// This interface is the entry point of the dynamic library.
//
// CLAP plugins standard search path:
//
// Linux
// - ~/.clap
// - /usr/lib/clap
//
// Windows
// - %CommonFilesFolder%/CLAP/
// - %LOCALAPPDATA%/Programs/Common/CLAP/
//
// MacOS
// - /Library/Audio/Plug-Ins/CLAP
// - ~/Library/Audio/Plug-Ins/CLAP
//
// In addition to the OS-specific default locations above, a CLAP host must query the environment
// for a CLAP_PATH variable, which is a list of directories formatted in the same manner as the host
// OS binary search path (PATH on Unix, separated by `:` and Path on Windows, separated by ';', as
// of this writing).
//
// Each directory should be recursively searched for files and/or bundles as appropriate in your OS
// ending with the extension `.clap`.
//
// Every method must be thread-safe.
typedef struct clap_plugin_entry {
clap_version_t clap_version; // initialized to CLAP_VERSION

// This function must be called first, and can only be called once.
//
// It should be as fast as possible, in order to perform a very quick scan of the plugin
// descriptors.
//
// It is forbidden to display graphical user interface in this call.
// It is forbidden to perform user interaction in this call.
//
// If the initialization depends upon expensive computation, maybe try to do them ahead of time
// and cache the result.
//
// If init() returns false, then the host must not call deinit() nor any other clap
// related symbols from the DSO.
bool (*init)(const char *plugin_path);

// No more calls into the DSO must be made after calling deinit().
void (*deinit)(void);

// Get the pointer to a factory. See plugin-factory.h for an example.
//
// Returns null if the factory is not provided.
// The returned pointer must *not* be freed by the caller.
const void *(*get_factory)(const char *factory_id);
} clap_plugin_entry_t;

/* Entry point */
CLAP_EXPORT extern const clap_plugin_entry_t clap_entry;

#ifdef __cplusplus
}
#endif
283 changes: 283 additions & 0 deletions dpf/distrho/src/clap/events.h
@@ -0,0 +1,283 @@
#pragma once

#include "private/std.h"
#include "fixedpoint.h"
#include "id.h"

#ifdef __cplusplus
extern "C" {
#endif

// event header
// must be the first attribute of the event
typedef struct clap_event_header {
uint32_t size; // event size including this header, eg: sizeof (clap_event_note)
uint32_t time; // sample offset within the buffer for this event
uint16_t space_id; // event space, see clap_host_event_registry
uint16_t type; // event type
uint32_t flags; // see clap_event_flags
} clap_event_header_t;

// The clap core event space
static const CLAP_CONSTEXPR uint16_t CLAP_CORE_EVENT_SPACE_ID = 0;

enum clap_event_flags {
// Indicate a live user event, for example a user turning a physical knob
// or playing a physical key.
CLAP_EVENT_IS_LIVE = 1 << 0,

// Indicate that the event should not be recorded.
// For example this is useful when a parameter changes because of a MIDI CC,
// because if the host records both the MIDI CC automation and the parameter
// automation there will be a conflict.
CLAP_EVENT_DONT_RECORD = 1 << 1,
};

// Some of the following events overlap, a note on can be expressed with:
// - CLAP_EVENT_NOTE_ON
// - CLAP_EVENT_MIDI
// - CLAP_EVENT_MIDI2
//
// The preferred way of sending a note event is to use CLAP_EVENT_NOTE_*.
//
// The same event must not be sent twice: it is forbidden to send a the same note on
// encoded with both CLAP_EVENT_NOTE_ON and CLAP_EVENT_MIDI.
//
// The plugins are encouraged to be able to handle note events encoded as raw midi or midi2,
// or implement clap_plugin_event_filter and reject raw midi and midi2 events.
enum {
// NOTE_ON and NOTE_OFF represent a key pressed and key released event, respectively.
// A NOTE_ON with a velocity of 0 is valid and should not be interpreted as a NOTE_OFF.
//
// NOTE_CHOKE is meant to choke the voice(s), like in a drum machine when a closed hihat
// chokes an open hihat. This event can be sent by the host to the plugin. Here are two use cases:
// - a plugin is inside a drum pad in Bitwig Studio's drum machine, and this pad is choked by
// another one
// - the user double clicks the DAW's stop button in the transport which then stops the sound on
// every tracks
//
// NOTE_END is sent by the plugin to the host. The port, channel, key and note_id are those given
// by the host in the NOTE_ON event. In other words, this event is matched against the
// plugin's note input port.
// NOTE_END is useful to help the host to match the plugin's voice life time.
//
// When using polyphonic modulations, the host has to allocate and release voices for its
// polyphonic modulator. Yet only the plugin effectively knows when the host should terminate
// a voice. NOTE_END solves that issue in a non-intrusive and cooperative way.
//
// CLAP assumes that the host will allocate a unique voice on NOTE_ON event for a given port,
// channel and key. This voice will run until the plugin will instruct the host to terminate
// it by sending a NOTE_END event.
//
// Consider the following sequence:
// - process()
// Host->Plugin NoteOn(port:0, channel:0, key:16, time:t0)
// Host->Plugin NoteOn(port:0, channel:0, key:64, time:t0)
// Host->Plugin NoteOff(port:0, channel:0, key:16, t1)
// Host->Plugin NoteOff(port:0, channel:0, key:64, t1)
// # on t2, both notes did terminate
// Host->Plugin NoteOn(port:0, channel:0, key:64, t3)
// # Here the plugin finished processing all the frames and will tell the host
// # to terminate the voice on key 16 but not 64, because a note has been started at t3
// Plugin->Host NoteEnd(port:0, channel:0, key:16, time:ignored)
//
// These four events use clap_event_note.
CLAP_EVENT_NOTE_ON,
CLAP_EVENT_NOTE_OFF,
CLAP_EVENT_NOTE_CHOKE,
CLAP_EVENT_NOTE_END,

// Represents a note expression.
// Uses clap_event_note_expression.
CLAP_EVENT_NOTE_EXPRESSION,

// PARAM_VALUE sets the parameter's value; uses clap_event_param_value.
// PARAM_MOD sets the parameter's modulation amount; uses clap_event_param_mod.
//
// The value heard is: param_value + param_mod.
//
// In case of a concurrent global value/modulation versus a polyphonic one,
// the voice should only use the polyphonic one and the polyphonic modulation
// amount will already include the monophonic signal.
CLAP_EVENT_PARAM_VALUE,
CLAP_EVENT_PARAM_MOD,

// Indicates that the user started or finished adjusting a knob.
// This is not mandatory to wrap parameter changes with gesture events, but this improves
// the user experience a lot when recording automation or overriding automation playback.
// Uses clap_event_param_gesture.
CLAP_EVENT_PARAM_GESTURE_BEGIN,
CLAP_EVENT_PARAM_GESTURE_END,

CLAP_EVENT_TRANSPORT, // update the transport info; clap_event_transport
CLAP_EVENT_MIDI, // raw midi event; clap_event_midi
CLAP_EVENT_MIDI_SYSEX, // raw midi sysex event; clap_event_midi_sysex
CLAP_EVENT_MIDI2, // raw midi 2 event; clap_event_midi2
};

// Note on, off, end and choke events.
// In the case of note choke or end events:
// - the velocity is ignored.
// - key and channel are used to match active notes, a value of -1 matches all.
typedef struct clap_event_note {
clap_event_header_t header;

int32_t note_id; // -1 if unspecified, otherwise >=0
int16_t port_index;
int16_t channel; // 0..15
int16_t key; // 0..127
double velocity; // 0..1
} clap_event_note_t;

enum {
// with 0 < x <= 4, plain = 20 * log(x)
CLAP_NOTE_EXPRESSION_VOLUME,

// pan, 0 left, 0.5 center, 1 right
CLAP_NOTE_EXPRESSION_PAN,

// relative tuning in semitone, from -120 to +120
CLAP_NOTE_EXPRESSION_TUNING,

// 0..1
CLAP_NOTE_EXPRESSION_VIBRATO,
CLAP_NOTE_EXPRESSION_EXPRESSION,
CLAP_NOTE_EXPRESSION_BRIGHTNESS,
CLAP_NOTE_EXPRESSION_PRESSURE,
};
typedef int32_t clap_note_expression;

typedef struct clap_event_note_expression {
clap_event_header_t header;

clap_note_expression expression_id;

// target a specific note_id, port, key and channel, -1 for global
int32_t note_id;
int16_t port_index;
int16_t channel;
int16_t key;

double value; // see expression for the range
} clap_event_note_expression_t;

typedef struct clap_event_param_value {
clap_event_header_t header;

// target parameter
clap_id param_id; // @ref clap_param_info.id
void *cookie; // @ref clap_param_info.cookie

// target a specific note_id, port, key and channel, -1 for global
int32_t note_id;
int16_t port_index;
int16_t channel;
int16_t key;

double value;
} clap_event_param_value_t;

typedef struct clap_event_param_mod {
clap_event_header_t header;

// target parameter
clap_id param_id; // @ref clap_param_info.id
void *cookie; // @ref clap_param_info.cookie

// target a specific note_id, port, key and channel, -1 for global
int32_t note_id;
int16_t port_index;
int16_t channel;
int16_t key;

double amount; // modulation amount
} clap_event_param_mod_t;

typedef struct clap_event_param_gesture {
clap_event_header_t header;

// target parameter
clap_id param_id; // @ref clap_param_info.id
} clap_event_param_gesture_t;

enum clap_transport_flags {
CLAP_TRANSPORT_HAS_TEMPO = 1 << 0,
CLAP_TRANSPORT_HAS_BEATS_TIMELINE = 1 << 1,
CLAP_TRANSPORT_HAS_SECONDS_TIMELINE = 1 << 2,
CLAP_TRANSPORT_HAS_TIME_SIGNATURE = 1 << 3,
CLAP_TRANSPORT_IS_PLAYING = 1 << 4,
CLAP_TRANSPORT_IS_RECORDING = 1 << 5,
CLAP_TRANSPORT_IS_LOOP_ACTIVE = 1 << 6,
CLAP_TRANSPORT_IS_WITHIN_PRE_ROLL = 1 << 7,
};

typedef struct clap_event_transport {
clap_event_header_t header;

uint32_t flags; // see clap_transport_flags

clap_beattime song_pos_beats; // position in beats
clap_sectime song_pos_seconds; // position in seconds

double tempo; // in bpm
double tempo_inc; // tempo increment for each samples and until the next
// time info event

clap_beattime loop_start_beats;
clap_beattime loop_end_beats;
clap_sectime loop_start_seconds;
clap_sectime loop_end_seconds;

clap_beattime bar_start; // start pos of the current bar
int32_t bar_number; // bar at song pos 0 has the number 0

uint16_t tsig_num; // time signature numerator
uint16_t tsig_denom; // time signature denominator
} clap_event_transport_t;

typedef struct clap_event_midi {
clap_event_header_t header;

uint16_t port_index;
uint8_t data[3];
} clap_event_midi_t;

typedef struct clap_event_midi_sysex {
clap_event_header_t header;

uint16_t port_index;
const uint8_t *buffer; // midi buffer
uint32_t size;
} clap_event_midi_sysex_t;

// While it is possible to use a series of midi2 event to send a sysex,
// prefer clap_event_midi_sysex if possible for efficiency.
typedef struct clap_event_midi2 {
clap_event_header_t header;

uint16_t port_index;
uint32_t data[4];
} clap_event_midi2_t;

// Input event list, events must be sorted by time.
typedef struct clap_input_events {
void *ctx; // reserved pointer for the list

uint32_t (*size)(const struct clap_input_events *list);

// Don't free the returned event, it belongs to the list
const clap_event_header_t *(*get)(const struct clap_input_events *list, uint32_t index);
} clap_input_events_t;

// Output event list, events must be sorted by time.
typedef struct clap_output_events {
void *ctx; // reserved pointer for the list

// Pushes a copy of the event
// returns false if the event could not be pushed to the queue (out of memory?)
bool (*try_push)(const struct clap_output_events *list, const clap_event_header_t *event);
} clap_output_events_t;

#ifdef __cplusplus
}
#endif
116 changes: 116 additions & 0 deletions dpf/distrho/src/clap/ext/audio-ports.h
@@ -0,0 +1,116 @@
#pragma once

#include "../plugin.h"
#include "../string-sizes.h"

/// @page Audio Ports
///
/// This extension provides a way for the plugin to describe its current audio ports.
///
/// If the plugin does not implement this extension, it won't have audio ports.
///
/// 32 bits support is required for both host and plugins. 64 bits audio is optional.
///
/// The plugin is only allowed to change its ports configuration while it is deactivated.

static CLAP_CONSTEXPR const char CLAP_EXT_AUDIO_PORTS[] = "clap.audio-ports";
static CLAP_CONSTEXPR const char CLAP_PORT_MONO[] = "mono";
static CLAP_CONSTEXPR const char CLAP_PORT_STEREO[] = "stereo";

#ifdef __cplusplus
extern "C" {
#endif

enum {
// This port is the main audio input or output.
// There can be only one main input and main output.
// Main port must be at index 0.
CLAP_AUDIO_PORT_IS_MAIN = 1 << 0,

// This port can be used with 64 bits audio
CLAP_AUDIO_PORT_SUPPORTS_64BITS = 1 << 1,

// 64 bits audio is preferred with this port
CLAP_AUDIO_PORT_PREFERS_64BITS = 1 << 2,

// This port must be used with the same sample size as all the other ports which have this flag.
// In other words if all ports have this flag then the plugin may either be used entirely with
// 64 bits audio or 32 bits audio, but it can't be mixed.
CLAP_AUDIO_PORT_REQUIRES_COMMON_SAMPLE_SIZE = 1 << 3,
};

typedef struct clap_audio_port_info {
// id identifies a port and must be stable.
// id may overlap between input and output ports.
clap_id id;
char name[CLAP_NAME_SIZE]; // displayable name

uint32_t flags;
uint32_t channel_count;

// If null or empty then it is unspecified (arbitrary audio).
// This filed can be compared against:
// - CLAP_PORT_MONO
// - CLAP_PORT_STEREO
// - CLAP_PORT_SURROUND (defined in the surround extension)
// - CLAP_PORT_AMBISONIC (defined in the ambisonic extension)
// - CLAP_PORT_CV (defined in the cv extension)
//
// An extension can provide its own port type and way to inspect the channels.
const char *port_type;

// in-place processing: allow the host to use the same buffer for input and output
// if supported set the pair port id.
// if not supported set to CLAP_INVALID_ID
clap_id in_place_pair;
} clap_audio_port_info_t;

// The audio ports scan has to be done while the plugin is deactivated.
typedef struct clap_plugin_audio_ports {
// number of ports, for either input or output
// [main-thread]
uint32_t (*count)(const clap_plugin_t *plugin, bool is_input);

// get info about about an audio port.
// [main-thread]
bool (*get)(const clap_plugin_t *plugin,
uint32_t index,
bool is_input,
clap_audio_port_info_t *info);
} clap_plugin_audio_ports_t;

enum {
// The ports name did change, the host can scan them right away.
CLAP_AUDIO_PORTS_RESCAN_NAMES = 1 << 0,

// [!active] The flags did change
CLAP_AUDIO_PORTS_RESCAN_FLAGS = 1 << 1,

// [!active] The channel_count did change
CLAP_AUDIO_PORTS_RESCAN_CHANNEL_COUNT = 1 << 2,

// [!active] The port type did change
CLAP_AUDIO_PORTS_RESCAN_PORT_TYPE = 1 << 3,

// [!active] The in-place pair did change, this requires.
CLAP_AUDIO_PORTS_RESCAN_IN_PLACE_PAIR = 1 << 4,

// [!active] The list of ports have changed: entries have been removed/added.
CLAP_AUDIO_PORTS_RESCAN_LIST = 1 << 5,
};

typedef struct clap_host_audio_ports {
// Checks if the host allows a plugin to change a given aspect of the audio ports definition.
// [main-thread]
bool (*is_rescan_flag_supported)(const clap_host_t *host, uint32_t flag);

// Rescan the full list of audio ports according to the flags.
// It is illegal to ask the host to rescan with a flag that is not supported.
// Certain flags require the plugin to be de-activated.
// [main-thread]
void (*rescan)(const clap_host_t *host, uint32_t flags);
} clap_host_audio_ports_t;

#ifdef __cplusplus
}
#endif
219 changes: 219 additions & 0 deletions dpf/distrho/src/clap/ext/gui.h
@@ -0,0 +1,219 @@
#pragma once

#include "../plugin.h"

/// @page GUI
///
/// This extension defines how the plugin will present its GUI.
///
/// There are two approaches:
/// 1. the plugin creates a window and embeds it into the host's window
/// 2. the plugin creates a floating window
///
/// Embedding the window gives more control to the host, and feels more integrated.
/// Floating window are sometimes the only option due to technical limitations.
///
/// Showing the GUI works as follow:
/// 1. clap_plugin_gui->is_api_supported(), check what can work
/// 2. clap_plugin_gui->create(), allocates gui resources
/// 3. if the plugin window is floating
/// 4. -> clap_plugin_gui->set_transient()
/// 5. -> clap_plugin_gui->suggest_title()
/// 6. else
/// 7. -> clap_plugin_gui->set_scale()
/// 8. -> clap_plugin_gui->can_resize()
/// 9. -> if resizable and has known size from previous session, clap_plugin_gui->set_size()
/// 10. -> else clap_plugin_gui->get_size(), gets initial size
/// 11. -> clap_plugin_gui->set_parent()
/// 12. clap_plugin_gui->show()
/// 13. clap_plugin_gui->hide()/show() ...
/// 14. clap_plugin_gui->destroy() when done with the gui
///
/// Resizing the window (initiated by the plugin, if embedded):
/// 1. Plugins calls clap_host_gui->request_resize()
/// 2. If the host returns true the new size is accepted,
/// the host doesn't have to call clap_plugin_gui->set_size().
/// If the host returns false, the new size is rejected.
///
/// Resizing the window (drag, if embedded)):
/// 1. Only possible if clap_plugin_gui->can_resize() returns true
/// 2. Mouse drag -> new_size
/// 3. clap_plugin_gui->adjust_size(new_size) -> working_size
/// 4. clap_plugin_gui->set_size(working_size)

static CLAP_CONSTEXPR const char CLAP_EXT_GUI[] = "clap.gui";

// If your windowing API is not listed here, please open an issue and we'll figure it out.
// https://github.com/free-audio/clap/issues/new

// uses physical size
// embed using https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setparent
static const CLAP_CONSTEXPR char CLAP_WINDOW_API_WIN32[] = "win32";

// uses logical size, don't call clap_plugin_gui->set_scale()
static const CLAP_CONSTEXPR char CLAP_WINDOW_API_COCOA[] = "cocoa";

// uses physical size
// embed using https://specifications.freedesktop.org/xembed-spec/xembed-spec-latest.html
static const CLAP_CONSTEXPR char CLAP_WINDOW_API_X11[] = "x11";

// uses physical size
// embed is currently not supported, use floating windows
static const CLAP_CONSTEXPR char CLAP_WINDOW_API_WAYLAND[] = "wayland";

#ifdef __cplusplus
extern "C" {
#endif

typedef void *clap_hwnd;
typedef void *clap_nsview;
typedef unsigned long clap_xwnd;

// Represent a window reference.
typedef struct clap_window {
const char *api; // one of CLAP_WINDOW_API_XXX
union {
clap_nsview cocoa;
clap_xwnd x11;
clap_hwnd win32;
void *ptr; // for anything defined outside of clap
uintptr_t uptr;
};
} clap_window_t;

// Information to improve window resizing when initiated by the host or window manager.
typedef struct clap_gui_resize_hints {
bool can_resize_horizontally;
bool can_resize_vertically;

// only if can resize horizontally and vertically
bool preserve_aspect_ratio;
uint32_t aspect_ratio_width;
uint32_t aspect_ratio_height;
} clap_gui_resize_hints_t;

// Size (width, height) is in pixels; the corresponding windowing system extension is
// responsible for defining if it is physical pixels or logical pixels.
typedef struct clap_plugin_gui {
// Returns true if the requested gui api is supported
// [main-thread]
bool (*is_api_supported)(const clap_plugin_t *plugin, const char *api, bool is_floating);

// Returns true if the plugin has a preferred api.
// The host has no obligation to honor the plugin preferrence, this is just a hint.
// [main-thread]
bool (*get_preferred_api)(const clap_plugin_t *plugin, const char **api, bool *is_floating);

// Create and allocate all resources necessary for the gui.
//
// If is_floating is true, then the window will not be managed by the host. The plugin
// can set its window to stays above the parent window, see set_transient().
// api may be null or blank for floating window.
//
// If is_floating is false, then the plugin has to embbed its window into the parent window, see
// set_parent().
//
// After this call, the GUI may not be visible yet; don't forget to call show().
// [main-thread]
bool (*create)(const clap_plugin_t *plugin, const char *api, bool is_floating);

// Free all resources associated with the gui.
// [main-thread]
void (*destroy)(const clap_plugin_t *plugin);

// Set the absolute GUI scaling factor, and override any OS info.
// Should not be used if the windowing api relies upon logical pixels.
//
// If the plugin prefers to work out the scaling factor itself by querying the OS directly,
// then ignore the call.
//
// Returns true if the scaling could be applied
// Returns false if the call was ignored, or the scaling could not be applied.
// [main-thread]
bool (*set_scale)(const clap_plugin_t *plugin, double scale);

// Get the current size of the plugin UI.
// clap_plugin_gui->create() must have been called prior to asking the size.
// [main-thread]
bool (*get_size)(const clap_plugin_t *plugin, uint32_t *width, uint32_t *height);

// Returns true if the window is resizeable (mouse drag).
// Only for embedded windows.
// [main-thread]
bool (*can_resize)(const clap_plugin_t *plugin);

// Returns true if the plugin can provide hints on how to resize the window.
// [main-thread]
bool (*get_resize_hints)(const clap_plugin_t *plugin, clap_gui_resize_hints_t *hints);

// If the plugin gui is resizable, then the plugin will calculate the closest
// usable size which fits in the given size.
// This method does not change the size.
//
// Only for embedded windows.
// [main-thread]
bool (*adjust_size)(const clap_plugin_t *plugin, uint32_t *width, uint32_t *height);

// Sets the window size. Only for embedded windows.
// [main-thread]
bool (*set_size)(const clap_plugin_t *plugin, uint32_t width, uint32_t height);

// Embbeds the plugin window into the given window.
// [main-thread & !floating]
bool (*set_parent)(const clap_plugin_t *plugin, const clap_window_t *window);

// Set the plugin floating window to stay above the given window.
// [main-thread & floating]
bool (*set_transient)(const clap_plugin_t *plugin, const clap_window_t *window);

// Suggests a window title. Only for floating windows.
// [main-thread & floating]
void (*suggest_title)(const clap_plugin_t *plugin, const char *title);

// Show the window.
// [main-thread]
bool (*show)(const clap_plugin_t *plugin);

// Hide the window, this method does not free the resources, it just hides
// the window content. Yet it may be a good idea to stop painting timers.
// [main-thread]
bool (*hide)(const clap_plugin_t *plugin);
} clap_plugin_gui_t;

typedef struct clap_host_gui {
// The host should call get_resize_hints() again.
// [thread-safe]
void (*resize_hints_changed)(const clap_host_t *host);

/* Request the host to resize the client area to width, height.
* Return true if the new size is accepted, false otherwise.
* The host doesn't have to call set_size().
*
* Note: if not called from the main thread, then a return value simply means that the host
* acknowledged the request and will process it asynchronously. If the request then can't be
* satisfied then the host will call set_size() to revert the operation.
*
* [thread-safe] */
bool (*request_resize)(const clap_host_t *host, uint32_t width, uint32_t height);

/* Request the host to show the plugin gui.
* Return true on success, false otherwise.
* [thread-safe] */
bool (*request_show)(const clap_host_t *host);

/* Request the host to hide the plugin gui.
* Return true on success, false otherwise.
* [thread-safe] */
bool (*request_hide)(const clap_host_t *host);

// The floating window has been closed, or the connection to the gui has been lost.
//
// If was_destroyed is true, then the host must call clap_plugin_gui->destroy() to acknowledge
// the gui destruction.
// [thread-safe]
void (*closed)(const clap_host_t *host, bool was_destroyed);
} clap_host_gui_t;

#ifdef __cplusplus
}
#endif
296 changes: 296 additions & 0 deletions dpf/distrho/src/clap/ext/params.h
@@ -0,0 +1,296 @@
#pragma once

#include "../plugin.h"
#include "../string-sizes.h"

/// @page Parameters
/// @brief parameters management
///
/// Main idea:
///
/// The host sees the plugin as an atomic entity; and acts as a controller on top of its parameters.
/// The plugin is responsible for keeping its audio processor and its GUI in sync.
///
/// The host can at any time read parameters' value on the [main-thread] using
/// @ref clap_plugin_params.value().
///
/// There are two options to communicate parameter value changes, and they are not concurrent.
/// - send automation points during clap_plugin.process()
/// - send automation points during clap_plugin_params.flush(), for parameter changes
/// without processing audio
///
/// When the plugin changes a parameter value, it must inform the host.
/// It will send @ref CLAP_EVENT_PARAM_VALUE event during process() or flush().
/// If the user is adjusting the value, don't forget to mark the begining and end
/// of the gesture by sending CLAP_EVENT_PARAM_GESTURE_BEGIN and CLAP_EVENT_PARAM_GESTURE_END
/// events.
///
/// @note MIDI CCs are tricky because you may not know when the parameter adjustment ends.
/// Also if the host records incoming MIDI CC and parameter change automation at the same time,
/// there will be a conflict at playback: MIDI CC vs Automation.
/// The parameter automation will always target the same parameter because the param_id is stable.
/// The MIDI CC may have a different mapping in the future and may result in a different playback.
///
/// When a MIDI CC changes a parameter's value, set the flag CLAP_EVENT_DONT_RECORD in
/// clap_event_param.header.flags. That way the host may record the MIDI CC automation, but not the
/// parameter change and there won't be conflict at playback.
///
/// Scenarios:
///
/// I. Loading a preset
/// - load the preset in a temporary state
/// - call @ref clap_host_params.rescan() if anything changed
/// - call @ref clap_host_latency.changed() if latency changed
/// - invalidate any other info that may be cached by the host
/// - if the plugin is activated and the preset will introduce breaking changes
/// (latency, audio ports, new parameters, ...) be sure to wait for the host
/// to deactivate the plugin to apply those changes.
/// If there are no breaking changes, the plugin can apply them them right away.
/// The plugin is resonsible for updating both its audio processor and its gui.
///
/// II. Turning a knob on the DAW interface
/// - the host will send an automation event to the plugin via a process() or flush()
///
/// III. Turning a knob on the Plugin interface
/// - the plugin is responsible for sending the parameter value to its audio processor
/// - call clap_host_params->request_flush() or clap_host->request_process().
/// - when the host calls either clap_plugin->process() or clap_plugin_params->flush(),
/// send an automation event and don't forget to set begin_adjust,
/// end_adjust and should_record flags
///
/// IV. Turning a knob via automation
/// - host sends an automation point during clap_plugin->process() or clap_plugin_params->flush().
/// - the plugin is responsible for updating its GUI
///
/// V. Turning a knob via plugin's internal MIDI mapping
/// - the plugin sends a CLAP_EVENT_PARAM_SET output event, set should_record to false
/// - the plugin is responsible to update its GUI
///
/// VI. Adding or removing parameters
/// - if the plugin is activated call clap_host->restart()
/// - once the plugin isn't active:
/// - apply the new state
/// - if a parameter is gone or is created with an id that may have been used before,
/// call clap_host_params.clear(host, param_id, CLAP_PARAM_CLEAR_ALL)
/// - call clap_host_params->rescan(CLAP_PARAM_RESCAN_ALL)

static CLAP_CONSTEXPR const char CLAP_EXT_PARAMS[] = "clap.params";

#ifdef __cplusplus
extern "C" {
#endif

enum {
// Is this param stepped? (integer values only)
// if so the double value is converted to integer using a cast (equivalent to trunc).
CLAP_PARAM_IS_STEPPED = 1 << 0,

// Useful for for periodic parameters like a phase
CLAP_PARAM_IS_PERIODIC = 1 << 1,

// The parameter should not be shown to the user, because it is currently not used.
// It is not necessary to process automation for this parameter.
CLAP_PARAM_IS_HIDDEN = 1 << 2,

// The parameter can't be changed by the host.
CLAP_PARAM_IS_READONLY = 1 << 3,

// This parameter is used to merge the plugin and host bypass button.
// It implies that the parameter is stepped.
// min: 0 -> bypass off
// max: 1 -> bypass on
CLAP_PARAM_IS_BYPASS = 1 << 4,

// When set:
// - automation can be recorded
// - automation can be played back
//
// The host can send live user changes for this parameter regardless of this flag.
//
// If this parameters affect the internal processing structure of the plugin, ie: max delay, fft
// size, ... and the plugins needs to re-allocate its working buffers, then it should call
// host->request_restart(), and perform the change once the plugin is re-activated.
CLAP_PARAM_IS_AUTOMATABLE = 1 << 5,

// Does this parameter support per note automations?
CLAP_PARAM_IS_AUTOMATABLE_PER_NOTE_ID = 1 << 6,

// Does this parameter support per key automations?
CLAP_PARAM_IS_AUTOMATABLE_PER_KEY = 1 << 7,

// Does this parameter support per channel automations?
CLAP_PARAM_IS_AUTOMATABLE_PER_CHANNEL = 1 << 8,

// Does this parameter support per port automations?
CLAP_PARAM_IS_AUTOMATABLE_PER_PORT = 1 << 9,

// Does this parameter support the modulation signal?
CLAP_PARAM_IS_MODULATABLE = 1 << 10,

// Does this parameter support per note modulations?
CLAP_PARAM_IS_MODULATABLE_PER_NOTE_ID = 1 << 11,

// Does this parameter support per key modulations?
CLAP_PARAM_IS_MODULATABLE_PER_KEY = 1 << 12,

// Does this parameter support per channel modulations?
CLAP_PARAM_IS_MODULATABLE_PER_CHANNEL = 1 << 13,

// Does this parameter support per port modulations?
CLAP_PARAM_IS_MODULATABLE_PER_PORT = 1 << 14,

// Any change to this parameter will affect the plugin output and requires to be done via
// process() if the plugin is active.
//
// A simple example would be a DC Offset, changing it will change the output signal and must be
// processed.
CLAP_PARAM_REQUIRES_PROCESS = 1 << 15,
};
typedef uint32_t clap_param_info_flags;

/* This describes a parameter */
typedef struct clap_param_info {
// stable parameter identifier, it must never change.
clap_id id;

clap_param_info_flags flags;

// This value is optional and set by the plugin.
// Its purpose is to provide a fast access to the plugin parameter:
//
// Parameter *p = findParameter(param_id);
// param_info->cookie = p;
//
// /* and later on */
// Parameter *p = (Parameter *)cookie;
//
// It is invalidated on clap_host_params->rescan(CLAP_PARAM_RESCAN_ALL) and when the plugin is
// destroyed.
void *cookie;

// the display name
char name[CLAP_NAME_SIZE];

// the module path containing the param, eg:"oscillators/wt1"
// '/' will be used as a separator to show a tree like structure.
char module[CLAP_PATH_SIZE];

double min_value; // minimum plain value
double max_value; // maximum plain value
double default_value; // default plain value
} clap_param_info_t;

typedef struct clap_plugin_params {
// Returns the number of parameters.
// [main-thread]
uint32_t (*count)(const clap_plugin_t *plugin);

// Copies the parameter's info to param_info and returns true on success.
// [main-thread]
bool (*get_info)(const clap_plugin_t *plugin,
uint32_t param_index,
clap_param_info_t *param_info);

// Gets the parameter plain value.
// [main-thread]
bool (*get_value)(const clap_plugin_t *plugin, clap_id param_id, double *value);

// Formats the display text for the given parameter value.
// The host should always format the parameter value to text using this function
// before displaying it to the user.
// [main-thread]
bool (*value_to_text)(
const clap_plugin_t *plugin, clap_id param_id, double value, char *display, uint32_t size);

// Converts the display text to a parameter value.
// [main-thread]
bool (*text_to_value)(const clap_plugin_t *plugin,
clap_id param_id,
const char *display,
double *value);

// Flushes a set of parameter changes.
// This method must not be called concurrently to clap_plugin->process().
//
// [active ? audio-thread : main-thread]
void (*flush)(const clap_plugin_t *plugin,
const clap_input_events_t *in,
const clap_output_events_t *out);
} clap_plugin_params_t;

enum {
// The parameter values did change, eg. after loading a preset.
// The host will scan all the parameters value.
// The host will not record those changes as automation points.
// New values takes effect immediately.
CLAP_PARAM_RESCAN_VALUES = 1 << 0,

// The value to text conversion changed, and the text needs to be rendered again.
CLAP_PARAM_RESCAN_TEXT = 1 << 1,

// The parameter info did change, use this flag for:
// - name change
// - module change
// - is_periodic (flag)
// - is_hidden (flag)
// New info takes effect immediately.
CLAP_PARAM_RESCAN_INFO = 1 << 2,

// Invalidates everything the host knows about parameters.
// It can only be used while the plugin is deactivated.
// If the plugin is activated use clap_host->restart() and delay any change until the host calls
// clap_plugin->deactivate().
//
// You must use this flag if:
// - some parameters were added or removed.
// - some parameters had critical changes:
// - is_per_note (flag)
// - is_per_channel (flag)
// - is_readonly (flag)
// - is_bypass (flag)
// - is_stepped (flag)
// - is_modulatable (flag)
// - min_value
// - max_value
// - cookie
CLAP_PARAM_RESCAN_ALL = 1 << 3,
};
typedef uint32_t clap_param_rescan_flags;

enum {
// Clears all possible references to a parameter
CLAP_PARAM_CLEAR_ALL = 1 << 0,

// Clears all automations to a parameter
CLAP_PARAM_CLEAR_AUTOMATIONS = 1 << 1,

// Clears all modulations to a parameter
CLAP_PARAM_CLEAR_MODULATIONS = 1 << 2,
};
typedef uint32_t clap_param_clear_flags;

typedef struct clap_host_params {
// Rescan the full list of parameters according to the flags.
// [main-thread]
void (*rescan)(const clap_host_t *host, clap_param_rescan_flags flags);

// Clears references to a parameter.
// [main-thread]
void (*clear)(const clap_host_t *host, clap_id param_id, clap_param_clear_flags flags);

// Request a parameter flush.
//
// The host will then schedule a call to either:
// - clap_plugin.process()
// - clap_plugin_params->flush()
//
// This function is always safe to use and should not be called from an [audio-thread] as the
// plugin would already be within process() or flush().
//
// [thread-safe,!audio-thread]
void (*request_flush)(const clap_host_t *host);
} clap_host_params_t;

#ifdef __cplusplus
}
#endif
16 changes: 16 additions & 0 deletions dpf/distrho/src/clap/fixedpoint.h
@@ -0,0 +1,16 @@
#pragma once

#include "private/std.h"
#include "private/macros.h"

/// We use fixed point representation of beat time and seconds time
/// Usage:
/// double x = ...; // in beats
/// clap_beattime y = round(CLAP_BEATTIME_FACTOR * x);

// This will never change
static const CLAP_CONSTEXPR int64_t CLAP_BEATTIME_FACTOR = 1LL << 31;
static const CLAP_CONSTEXPR int64_t CLAP_SECTIME_FACTOR = 1LL << 31;

typedef int64_t clap_beattime;
typedef int64_t clap_sectime;
41 changes: 41 additions & 0 deletions dpf/distrho/src/clap/host.h
@@ -0,0 +1,41 @@
#pragma once

#include "version.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct clap_host {
clap_version_t clap_version; // initialized to CLAP_VERSION

void *host_data; // reserved pointer for the host

// name and version are mandatory.
const char *name; // eg: "Bitwig Studio"
const char *vendor; // eg: "Bitwig GmbH"
const char *url; // eg: "https://bitwig.com"
const char *version; // eg: "4.3"

// Query an extension.
// [thread-safe]
const void *(*get_extension)(const struct clap_host *host, const char *extension_id);

// Request the host to deactivate and then reactivate the plugin.
// The operation may be delayed by the host.
// [thread-safe]
void (*request_restart)(const struct clap_host *host);

// Request the host to activate and start processing the plugin.
// This is useful if you have external IO and need to wake up the plugin from "sleep".
// [thread-safe]
void (*request_process)(const struct clap_host *host);

// Request the host to schedule a call to plugin->on_main_thread(plugin) on the main thread.
// [thread-safe]
void (*request_callback)(const struct clap_host *host);
} clap_host_t;

#ifdef __cplusplus
}
#endif
8 changes: 8 additions & 0 deletions dpf/distrho/src/clap/id.h
@@ -0,0 +1,8 @@
#pragma once

#include "private/std.h"
#include "private/macros.h"

typedef uint32_t clap_id;

static const CLAP_CONSTEXPR clap_id CLAP_INVALID_ID = UINT32_MAX;
39 changes: 39 additions & 0 deletions dpf/distrho/src/clap/plugin-factory.h
@@ -0,0 +1,39 @@
#pragma once

#include "plugin.h"

static const CLAP_CONSTEXPR char CLAP_PLUGIN_FACTORY_ID[] = "clap.plugin-factory";

#ifdef __cplusplus
extern "C" {
#endif

// Every method must be thread-safe.
// It is very important to be able to scan the plugin as quickly as possible.
//
// If the content of the factory may change due to external events, like the user installed
typedef struct clap_plugin_factory {
// Get the number of plugins available.
// [thread-safe]
uint32_t (*get_plugin_count)(const struct clap_plugin_factory *factory);

// Retrieves a plugin descriptor by its index.
// Returns null in case of error.
// The descriptor must not be freed.
// [thread-safe]
const clap_plugin_descriptor_t *(*get_plugin_descriptor)(
const struct clap_plugin_factory *factory, uint32_t index);

// Create a clap_plugin by its plugin_id.
// The returned pointer must be freed by calling plugin->destroy(plugin);
// The plugin is not allowed to use the host callbacks in the create method.
// Returns null in case of error.
// [thread-safe]
const clap_plugin_t *(*create_plugin)(const struct clap_plugin_factory *factory,
const clap_host_t *host,
const char *plugin_id);
} clap_plugin_factory_t;

#ifdef __cplusplus
}
#endif
76 changes: 76 additions & 0 deletions dpf/distrho/src/clap/plugin-features.h
@@ -0,0 +1,76 @@
#pragma once

#include "private/macros.h"

// This file provides a set of standard plugin features meant to be used
// within clap_plugin_descriptor.features.
//
// For practical reasons we'll avoid spaces and use `-` instead to facilitate
// scripts that generate the feature array.
//
// Non-standard features should be formated as follow: "$namespace:$feature"

/////////////////////
// Plugin category //
/////////////////////

// Add this feature if your plugin can process note events and then produce audio
#define CLAP_PLUGIN_FEATURE_INSTRUMENT "instrument"

// Add this feature if your plugin is an audio effect
#define CLAP_PLUGIN_FEATURE_AUDIO_EFFECT "audio-effect"

// Add this feature if your plugin is a note effect or a note generator/sequencer
#define CLAP_PLUGIN_FEATURE_NOTE_EFFECT "note-effect"

// Add this feature if your plugin is an analyzer
#define CLAP_PLUGIN_FEATURE_ANALYZER "analyzer"

/////////////////////////
// Plugin sub-category //
/////////////////////////

#define CLAP_PLUGIN_FEATURE_SYNTHESIZER "synthesizer"
#define CLAP_PLUGIN_FEATURE_SAMPLER "sampler"
#define CLAP_PLUGIN_FEATURE_DRUM "drum" // For single drum
#define CLAP_PLUGIN_FEATURE_DRUM_MACHINE "drum-machine"

#define CLAP_PLUGIN_FEATURE_FILTER "filter"
#define CLAP_PLUGIN_FEATURE_PHASER "phaser"
#define CLAP_PLUGIN_FEATURE_EQUALIZER "equalizer"
#define CLAP_PLUGIN_FEATURE_DEESSER "de-esser"
#define CLAP_PLUGIN_FEATURE_PHASE_VOCODER "phase-vocoder"
#define CLAP_PLUGIN_FEATURE_GRANULAR "granular"
#define CLAP_PLUGIN_FEATURE_FREQUENCY_SHIFTER "frequency-shifter"
#define CLAP_PLUGIN_FEATURE_PITCH_SHIFTER "pitch-shifter"

#define CLAP_PLUGIN_FEATURE_DISTORTION "distortion"
#define CLAP_PLUGIN_FEATURE_TRANSIENT_SHAPER "transient-shaper"
#define CLAP_PLUGIN_FEATURE_COMPRESSOR "compressor"
#define CLAP_PLUGIN_FEATURE_LIMITER "limiter"

#define CLAP_PLUGIN_FEATURE_FLANGER "flanger"
#define CLAP_PLUGIN_FEATURE_CHORUS "chorus"
#define CLAP_PLUGIN_FEATURE_DELAY "delay"
#define CLAP_PLUGIN_FEATURE_REVERB "reverb"

#define CLAP_PLUGIN_FEATURE_TREMOLO "tremolo"
#define CLAP_PLUGIN_FEATURE_GLITCH "glitch"

#define CLAP_PLUGIN_FEATURE_UTILITY "utility"
#define CLAP_PLUGIN_FEATURE_PITCH_CORRECTION "pitch-correction"
#define CLAP_PLUGIN_FEATURE_RESTORATION "restoration" // repair the sound

#define CLAP_PLUGIN_FEATURE_MULTI_EFFECTS "multi-effects"

#define CLAP_PLUGIN_FEATURE_MIXING "mixing"
#define CLAP_PLUGIN_FEATURE_MASTERING "mastering"

////////////////////////
// Audio Capabilities //
////////////////////////

#define CLAP_PLUGIN_FEATURE_MONO "mono"
#define CLAP_PLUGIN_FEATURE_STEREO "stereo"
#define CLAP_PLUGIN_FEATURE_SURROUND "surround"
#define CLAP_PLUGIN_FEATURE_AMBISONIC "ambisonic"
96 changes: 96 additions & 0 deletions dpf/distrho/src/clap/plugin.h
@@ -0,0 +1,96 @@
#pragma once

#include "private/macros.h"
#include "host.h"
#include "process.h"
#include "plugin-features.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct clap_plugin_descriptor {
clap_version_t clap_version; // initialized to CLAP_VERSION

// Mandatory fields must be set and must not be blank.
// Otherwise the fields can be null or blank, though it is safer to make them blank.
const char *id; // eg: "com.u-he.diva", mandatory
const char *name; // eg: "Diva", mandatory
const char *vendor; // eg: "u-he"
const char *url; // eg: "https://u-he.com/products/diva/"
const char *manual_url; // eg: "https://dl.u-he.com/manuals/plugins/diva/Diva-user-guide.pdf"
const char *support_url; // eg: "https://u-he.com/support/"
const char *version; // eg: "1.4.4"
const char *description; // eg: "The spirit of analogue"

// Arbitrary list of keywords.
// They can be matched by the host indexer and used to classify the plugin.
// The array of pointers must be null terminated.
// For some standard features see plugin-features.h
const char **features;
} clap_plugin_descriptor_t;

typedef struct clap_plugin {
const clap_plugin_descriptor_t *desc;

void *plugin_data; // reserved pointer for the plugin

// Must be called after creating the plugin.
// If init returns false, the host must destroy the plugin instance.
// [main-thread]
bool (*init)(const struct clap_plugin *plugin);

// Free the plugin and its resources.
// It is required to deactivate the plugin prior to this call.
// [main-thread & !active]
void (*destroy)(const struct clap_plugin *plugin);

// Activate and deactivate the plugin.
// In this call the plugin may allocate memory and prepare everything needed for the process
// call. The process's sample rate will be constant and process's frame count will included in
// the [min, max] range, which is bounded by [1, INT32_MAX].
// Once activated the latency and port configuration must remain constant, until deactivation.
//
// [main-thread & !active_state]
bool (*activate)(const struct clap_plugin *plugin,
double sample_rate,
uint32_t min_frames_count,
uint32_t max_frames_count);

// [main-thread & active_state]
void (*deactivate)(const struct clap_plugin *plugin);

// Call start processing before processing.
// [audio-thread & active_state & !processing_state]
bool (*start_processing)(const struct clap_plugin *plugin);

// Call stop processing before sending the plugin to sleep.
// [audio-thread & active_state & processing_state]
void (*stop_processing)(const struct clap_plugin *plugin);

// - Clears all buffers, performs a full reset of the processing state (filters, oscillators,
// enveloppes, lfo, ...) and kills all voices.
// - The parameter's value remain unchanged.
// - clap_process.steady_time may jump backward.
//
// [audio-thread & active_state]
void (*reset)(const struct clap_plugin *plugin);

// process audio, events, ...
// [audio-thread & active_state & processing_state]
clap_process_status (*process)(const struct clap_plugin *plugin, const clap_process_t *process);

// Query an extension.
// The returned pointer is owned by the plugin.
// [thread-safe]
const void *(*get_extension)(const struct clap_plugin *plugin, const char *id);

// Called by the host on the main thread in response to a previous call to:
// host->request_callback(host);
// [main-thread]
void (*on_main_thread)(const struct clap_plugin *plugin);
} clap_plugin_t;

#ifdef __cplusplus
}
#endif
36 changes: 36 additions & 0 deletions dpf/distrho/src/clap/private/macros.h
@@ -0,0 +1,36 @@
#pragma once

// Define CLAP_EXPORT
#if !defined(CLAP_EXPORT)
# if defined _WIN32 || defined __CYGWIN__
# ifdef __GNUC__
# define CLAP_EXPORT __attribute__((dllexport))
# else
# define CLAP_EXPORT __declspec(dllexport)
# endif
# else
# if __GNUC__ >= 4 || defined(__clang__)
# define CLAP_EXPORT __attribute__((visibility("default")))
# else
# define CLAP_EXPORT
# endif
# endif
#endif

#if defined(__cplusplus) && __cplusplus >= 201103L
# define CLAP_HAS_CXX11
# define CLAP_CONSTEXPR constexpr
#else
# define CLAP_CONSTEXPR
#endif

#if defined(__cplusplus) && __cplusplus >= 201703L
# define CLAP_HAS_CXX17
# define CLAP_NODISCARD [[nodiscard]]
#else
# define CLAP_NODISCARD
#endif

#if defined(__cplusplus) && __cplusplus >= 202002L
# define CLAP_HAS_CXX20
#endif
16 changes: 16 additions & 0 deletions dpf/distrho/src/clap/private/std.h
@@ -0,0 +1,16 @@
#pragma once

#include "macros.h"

#ifdef CLAP_HAS_CXX11
# include <cstdint>
#else
# include <stdint.h>
#endif

#ifdef __cplusplus
# include <cstddef>
#else
# include <stddef.h>
# include <stdbool.h>
#endif
65 changes: 65 additions & 0 deletions dpf/distrho/src/clap/process.h
@@ -0,0 +1,65 @@
#pragma once

#include "events.h"
#include "audio-buffer.h"

#ifdef __cplusplus
extern "C" {
#endif

enum {
// Processing failed. The output buffer must be discarded.
CLAP_PROCESS_ERROR = 0,

// Processing succeeded, keep processing.
CLAP_PROCESS_CONTINUE = 1,

// Processing succeeded, keep processing if the output is not quiet.
CLAP_PROCESS_CONTINUE_IF_NOT_QUIET = 2,

// Rely upon the plugin's tail to determine if the plugin should continue to process.
// see clap_plugin_tail
CLAP_PROCESS_TAIL = 3,

// Processing succeeded, but no more processing is required,
// until the next event or variation in audio input.
CLAP_PROCESS_SLEEP = 4,
};
typedef int32_t clap_process_status;

typedef struct clap_process {
// A steady sample time counter.
// This field can be used to calculate the sleep duration between two process calls.
// This value may be specific to this plugin instance and have no relation to what
// other plugin instances may receive.
//
// Set to -1 if not available, otherwise the value must be greater or equal to 0,
// and must be increased by at least `frames_count` for the next call to process.
int64_t steady_time;

// Number of frames to process
uint32_t frames_count;

// time info at sample 0
// If null, then this is a free running host, no transport events will be provided
const clap_event_transport_t *transport;

// Audio buffers, they must have the same count as specified
// by clap_plugin_audio_ports->get_count().
// The index maps to clap_plugin_audio_ports->get_info().
const clap_audio_buffer_t *audio_inputs;
clap_audio_buffer_t *audio_outputs;
uint32_t audio_inputs_count;
uint32_t audio_outputs_count;

// Input and output events.
//
// Events must be sorted by time.
// The input event list can't be modified.
const clap_input_events_t *in_events;
const clap_output_events_t *out_events;
} clap_process_t;

#ifdef __cplusplus
}
#endif
21 changes: 21 additions & 0 deletions dpf/distrho/src/clap/string-sizes.h
@@ -0,0 +1,21 @@
#pragma once

#ifdef __cplusplus
extern "C" {
#endif

enum {
// String capacity for names that can be displayed to the user.
CLAP_NAME_SIZE = 256,

// String capacity for describing a path, like a parameter in a module hierarchy or path within a
// set of nested track groups.
//
// This is not suited for describing a file path on the disk, as NTFS allows up to 32K long
// paths.
CLAP_PATH_SIZE = 1024,
};

#ifdef __cplusplus
}
#endif
34 changes: 34 additions & 0 deletions dpf/distrho/src/clap/version.h
@@ -0,0 +1,34 @@
#pragma once

#include "private/macros.h"
#include "private/std.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct clap_version {
// This is the major ABI and API design
// Version 0.X.Y correspond to the development stage, API and ABI are not stable
// Version 1.X.Y correspont to the release stage, API and ABI are stable
uint32_t major;
uint32_t minor;
uint32_t revision;
} clap_version_t;

#ifdef __cplusplus
}
#endif

#define CLAP_VERSION_MAJOR ((uint32_t)1)
#define CLAP_VERSION_MINOR ((uint32_t)1)
#define CLAP_VERSION_REVISION ((uint32_t)1)
#define CLAP_VERSION_INIT {CLAP_VERSION_MAJOR, CLAP_VERSION_MINOR, CLAP_VERSION_REVISION}

static const CLAP_CONSTEXPR clap_version_t CLAP_VERSION = CLAP_VERSION_INIT;

CLAP_NODISCARD static inline CLAP_CONSTEXPR bool
clap_version_is_compatible(const clap_version_t v) {
// versions 0.x.y were used during development stage and aren't compatible
return v.major >= 1;
}
17 changes: 17 additions & 0 deletions dpf/distrho/src/travesty/audio_processor.h
Expand Up @@ -30,6 +30,23 @@ typedef uint64_t v3_speaker_arrangement;
enum {
V3_SPEAKER_L = 1 << 0,
V3_SPEAKER_R = 1 << 1,
V3_SPEAKER_C = 1 << 2,
V3_SPEAKER_LFE = 1 << 3,
V3_SPEAKER_LS = 1 << 4,
V3_SPEAKER_RS = 1 << 5,
V3_SPEAKER_LC = 1 << 6,
V3_SPEAKER_RC = 1 << 7,
V3_SPEAKER_S = 1 << 8,
V3_SPEAKER_SL = 1 << 9,
V3_SPEAKER_SR = 1 << 10,
V3_SPEAKER_TC = 1 << 11,
V3_SPEAKER_TFL = 1 << 12,
V3_SPEAKER_TFC = 1 << 13,
V3_SPEAKER_TFR = 1 << 14,
V3_SPEAKER_TRL = 1 << 15,
V3_SPEAKER_TRC = 1 << 16,
V3_SPEAKER_TRR = 1 << 17,
V3_SPEAKER_LFE2 = 1 << 18,
V3_SPEAKER_M = 1 << 19
};

Expand Down
5 changes: 4 additions & 1 deletion dpf/utils/package-osx-bundles.sh
Expand Up @@ -44,7 +44,10 @@ cd ..

DPF_UTILS_DIR=$(dirname ${0})

sed -e "s|@name@|${NAME}|" ${DPF_UTILS_DIR}/plugin.pkg/welcome.txt.in > build/welcome.txt
# can be overridden by environment variables
WELCOME_TXT=${WELCOME_TXT:=${DPF_UTILS_DIR}/plugin.pkg/welcome.txt.in}

sed -e "s|@name@|${NAME}|" "${WELCOME_TXT}" > build/welcome.txt
sed -e "s|@builddir@|${PWD}/build|" \
-e "s|@lv2bundleref@|dpf-${SNAME}-lv2bundles.pkg|" \
-e "s|@vst2bundleref@|dpf-${SNAME}-vst2bundles.pkg|" \
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
20 changes: 14 additions & 6 deletions dpf/utils/res2c.py
Expand Up @@ -40,13 +40,13 @@ def res2c(namespace, filenames):

for filename in filenames:
shortFilename = filename.rsplit(os.sep, 1)[-1].split(".", 1)[0]
shortFilename = shortFilename.replace("-", "_")
shortFilename = shortFilename.replace("-", "_").replace("@","_")

resData = open(filename, 'rb').read()

print("Generating data for \"%s\"" % (filename))

fdH.write(" extern const char* %sData;\n" % shortFilename)
fdH.write(" extern const unsigned char* %sData;\n" % shortFilename)
fdH.write(" const unsigned int %sDataSize = %i;\n" % (shortFilename, len(resData)))

if tempIndex != len(filenames):
Expand All @@ -70,7 +70,7 @@ def res2c(namespace, filenames):
curColumn += 1

fdC.write("};\n")
fdC.write("const char* %s::%sData = (const char*)temp_%s_%i;\n" % (namespace, shortFilename, shortFilename, tempIndex))
fdC.write("const unsigned char* %s::%sData = (const unsigned char*)temp_%s_%i;\n" % (namespace, shortFilename, shortFilename, tempIndex))

if tempIndex != len(filenames):
fdC.write("\n")
Expand All @@ -89,25 +89,33 @@ def res2c(namespace, filenames):
# -----------------------------------------------------

if __name__ == '__main__':
if len(sys.argv) != 3:
print("Usage: %s <namespace> <resource-folder>" % sys.argv[0])
if len(sys.argv) not in (3, 4):
print("Usage: %s <namespace> <resource-folder> [output-folder=$CWD]" % sys.argv[0])
quit()

namespace = sys.argv[1].replace("-","_")
resFolder = sys.argv[2]
outFolder = sys.argv[3] if len(sys.argv) == 4 else None

if not os.path.exists(resFolder):
print("Folder '%s' does not exist" % resFolder)
quit()

if outFolder is not None and not os.path.exists(outFolder):
print("Output folder '%s' does not exist" % outFolder)
quit()

# find resource files
resFiles = []

for root, dirs, files in os.walk(resFolder):
for name in files:
resFiles.append(os.path.join(root, name))
resFiles.append(os.path.abspath(os.path.join(root, name)))

resFiles.sort()

if outFolder is not None:
os.chdir(outFolder)

# create code now
res2c(namespace, resFiles)
2 changes: 2 additions & 0 deletions dpf/utils/symbols/clap.def
@@ -0,0 +1,2 @@
EXPORTS
clap_entry
1 change: 1 addition & 0 deletions dpf/utils/symbols/clap.exp
@@ -0,0 +1 @@
_clap_entry
4 changes: 4 additions & 0 deletions dpf/utils/symbols/clap.version
@@ -0,0 +1,4 @@
{
global: clap_entry;
local: *;
};
25 changes: 23 additions & 2 deletions dpf/utils/valgrind-dpf.supp
Expand Up @@ -21,8 +21,7 @@
{
libdl is full of leaks
Memcheck:Leak
fun:calloc
fun:allocate_dtv
...
fun:_dl_allocate_tls
...
}
Expand All @@ -32,6 +31,12 @@
...
fun:call_init.part.0
}
{
libdl is really something else
Memcheck:Addr8
...
fun:dl_open_worker
}
{
ignore XInitThreads
Memcheck:Leak
Expand All @@ -46,3 +51,19 @@
fun:XrmGetStringDatabase
...
}
{
ignore XPutImage
Memcheck:Param
writev(vector[...])
...
fun:XPutImage
...
}
{
ignore mesa stuff
Memcheck:Value8
...
obj:/usr/lib/x86_64-linux-gnu/dri/swrast_dri.so
fun:start_thread
fun:clone
}