Browse Source

Start implementing CLAP

pull/321/merge
falkTX 3 years ago
parent
commit
04d86c7196
21 changed files with 1474 additions and 3 deletions
  1. +3
    -1
      Makefile.plugins.mk
  2. +1
    -1
      distrho/DistrhoPluginMain.cpp
  3. +515
    -0
      distrho/src/DistrhoPluginCLAP.cpp
  4. +37
    -0
      distrho/src/clap/audio-buffer.h
  5. +68
    -0
      distrho/src/clap/entry.h
  6. +283
    -0
      distrho/src/clap/events.h
  7. +116
    -0
      distrho/src/clap/ext/audio-ports.h
  8. +16
    -0
      distrho/src/clap/fixedpoint.h
  9. +41
    -0
      distrho/src/clap/host.h
  10. +8
    -0
      distrho/src/clap/id.h
  11. +39
    -0
      distrho/src/clap/plugin-factory.h
  12. +76
    -0
      distrho/src/clap/plugin-features.h
  13. +96
    -0
      distrho/src/clap/plugin.h
  14. +36
    -0
      distrho/src/clap/private/macros.h
  15. +16
    -0
      distrho/src/clap/private/std.h
  16. +65
    -0
      distrho/src/clap/process.h
  17. +21
    -0
      distrho/src/clap/string-sizes.h
  18. +34
    -0
      distrho/src/clap/version.h
  19. +1
    -0
      utils/symbols/clap.def
  20. +1
    -0
      utils/symbols/clap.exp
  21. +1
    -1
      utils/symbols/clap.version

+ 3
- 1
Makefile.plugins.mk View File

@@ -309,7 +309,7 @@ SYMBOLS_LV2UI = -sEXPORTED_FUNCTIONS="['lv2ui_descriptor']"
SYMBOLS_LV2 = -sEXPORTED_FUNCTIONS="['lv2_descriptor','lv2_generate_ttl','lv2ui_descriptor']"
SYMBOLS_VST2 = -sEXPORTED_FUNCTIONS="['VSTPluginMain']"
SYMBOLS_VST3 = -sEXPORTED_FUNCTIONS="['GetPluginFactory','ModuleEntry','ModuleExit']"
SYMBOLS_CLAP = -sEXPORTED_FUNCTIONS="['']"
SYMBOLS_CLAP = -sEXPORTED_FUNCTIONS="['clap_entry']"
SYMBOLS_SHARED = -sEXPORTED_FUNCTIONS="['createSharedPlugin']"
else ifeq ($(WINDOWS),true)
SYMBOLS_LADSPA = $(DPF_PATH)/utils/symbols/ladspa.def
@@ -605,6 +605,7 @@ endif
-include $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.d
-include $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.d
-include $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.d
-include $(BUILD_DIR)/DistrhoPluginMain_CLAP.cpp.d
-include $(BUILD_DIR)/DistrhoPluginMain_SHARED.cpp.d
-include $(BUILD_DIR)/DistrhoPluginMain_STATIC.cpp.d

@@ -613,6 +614,7 @@ endif
-include $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_CLAP.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_SHARED.cpp.d
-include $(BUILD_DIR)/DistrhoUIMain_STATIC.cpp.d



+ 1
- 1
distrho/DistrhoPluginMain.cpp View File

@@ -19,7 +19,7 @@
#if defined(DISTRHO_PLUGIN_TARGET_CARLA)
# include "src/DistrhoPluginCarla.cpp"
#elif defined(DISTRHO_PLUGIN_TARGET_CLAP)
# include "src/DistrhoPluginStub.cpp"
# include "src/DistrhoPluginCLAP.cpp"
#elif defined(DISTRHO_PLUGIN_TARGET_JACK)
# include "src/DistrhoPluginJACK.cpp"
#elif (defined(DISTRHO_PLUGIN_TARGET_LADSPA) || defined(DISTRHO_PLUGIN_TARGET_DSSI))


+ 515
- 0
distrho/src/DistrhoPluginCLAP.cpp View File

@@ -0,0 +1,515 @@
/*
* 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 "DistrhoPluginInfo.h"
#include "DistrhoPluginInternal.hpp"
#include "extra/ScopedPointer.hpp"

#include "clap/entry.h"
#include "clap/plugin-factory.h"
#include "clap/ext/audio-ports.h"
#include "src/DistrhoDefines.h"
#include "src/clap/version.h"

START_NAMESPACE_DISTRHO

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

#if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
static constexpr const writeMidiFunc writeMidiCallback = nullptr;
#endif
#if ! DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
static constexpr const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr;
#endif
#if ! DISTRHO_PLUGIN_WANT_STATE
static const updateStateValueFunc updateStateValueCallback = nullptr;
#endif

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

/**
* CLAP plugin class.
*/
class PluginCLAP
{
public:
PluginCLAP(const clap_host_t* const host)
: fPlugin(this,
writeMidiCallback,
requestParameterValueChangeCallback,
updateStateValueCallback),
fHost(host),
fOutputEvents(nullptr)
{
}

bool init()
{
if (!clap_version_is_compatible(fHost->clap_version))
return false;

// TODO check host features
return true;
}

void activate(const double sampleRate, const uint32_t maxFramesCount)
{
fPlugin.setSampleRate(sampleRate, true);
fPlugin.setBufferSize(maxFramesCount, true);
fPlugin.activate();
}

void deactivate()
{
fPlugin.deactivate();
}

bool process(const clap_process_t* const process)
{
#if DISTRHO_PLUGIN_WANT_TIMEPOS
if (const clap_event_transport_t* const transport = process->transport)
{
fTimePosition.playing = transport->flags & CLAP_TRANSPORT_IS_PLAYING;

fTimePosition.frame = process->steady_time >= 0 ? process->steady_time : 0;

if (transport->flags & CLAP_TRANSPORT_HAS_TEMPO)
fTimePosition.bbt.beatsPerMinute = transport->tempo;
else
fTimePosition.bbt.beatsPerMinute = 120.0;

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

// TODO verify if this works or makes any sense
if ((transport->flags & (CLAP_TRANSPORT_HAS_BEATS_TIMELINE|CLAP_TRANSPORT_HAS_TIME_SIGNATURE)) == (CLAP_TRANSPORT_HAS_BEATS_TIMELINE|CLAP_TRANSPORT_HAS_TIME_SIGNATURE))
{
const double ppqPos = std::abs(transport->song_pos_beats);
const int ppqPerBar = transport->tsig_num * 4 / transport->tsig_denom;
const double barBeats = (std::fmod(ppqPos, ppqPerBar) / ppqPerBar) * transport->tsig_num;
const double rest = std::fmod(barBeats, 1.0);

fTimePosition.bbt.valid = true;
fTimePosition.bbt.bar = static_cast<int32_t>(ppqPos) / ppqPerBar + 1;
fTimePosition.bbt.beat = static_cast<int32_t>(barBeats - rest + 0.5) + 1;
fTimePosition.bbt.tick = rest * fTimePosition.bbt.ticksPerBeat;
fTimePosition.bbt.beatsPerBar = transport->tsig_num;
fTimePosition.bbt.beatType = transport->tsig_denom;

if (transport->song_pos_beats < 0.0)
{
--fTimePosition.bbt.bar;
fTimePosition.bbt.beat = transport->tsig_num - fTimePosition.bbt.beat + 1;
fTimePosition.bbt.tick = fTimePosition.bbt.ticksPerBeat - fTimePosition.bbt.tick - 1;
}
}
else
{
fTimePosition.bbt.valid = false;
fTimePosition.bbt.bar = 1;
fTimePosition.bbt.beat = 1;
fTimePosition.bbt.tick = 0.0;
fTimePosition.bbt.beatsPerBar = 4.0f;
fTimePosition.bbt.beatType = 4.0f;
}

fTimePosition.bbt.barStartTick = fTimePosition.bbt.ticksPerBeat*
fTimePosition.bbt.beatsPerBar*
(fTimePosition.bbt.bar-1);
}
else
{
fTimePosition.playing = false;
fTimePosition.frame = 0;
fTimePosition.bbt.valid = false;
fTimePosition.bbt.beatsPerMinute = 120.0;
fTimePosition.bbt.bar = 1;
fTimePosition.bbt.beat = 1;
fTimePosition.bbt.tick = 0.0;
fTimePosition.bbt.beatsPerBar = 4.f;
fTimePosition.bbt.beatType = 4.f;
fTimePosition.bbt.barStartTick = 0;
}

fPlugin.setTimePosition(fTimePosition);
#endif

if (const clap_input_events_t* const inputEvents = process->in_events)
{
if (const uint32_t len = inputEvents->size(inputEvents))
{
for (uint32_t i=0; i<len; ++i)
{
const clap_event_header_t* const event = inputEvents->get(inputEvents, i);

// event->time
switch (event->type)
{
case CLAP_EVENT_NOTE_ON:
case CLAP_EVENT_NOTE_OFF:
case CLAP_EVENT_NOTE_CHOKE:
case CLAP_EVENT_NOTE_END:
case CLAP_EVENT_NOTE_EXPRESSION:
case CLAP_EVENT_PARAM_VALUE:
case CLAP_EVENT_PARAM_MOD:
case CLAP_EVENT_PARAM_GESTURE_BEGIN:
case CLAP_EVENT_PARAM_GESTURE_END:
case CLAP_EVENT_TRANSPORT:
case CLAP_EVENT_MIDI:
case CLAP_EVENT_MIDI_SYSEX:
case CLAP_EVENT_MIDI2:
break;
}
}
}
}

if (const uint32_t frames = process->frames_count)
{
DISTRHO_SAFE_ASSERT_UINT2_RETURN(process->audio_inputs_count == DISTRHO_PLUGIN_NUM_INPUTS,
process->audio_inputs_count, DISTRHO_PLUGIN_NUM_INPUTS, false);
DISTRHO_SAFE_ASSERT_UINT2_RETURN(process->audio_outputs_count == DISTRHO_PLUGIN_NUM_OUTPUTS,
process->audio_outputs_count, DISTRHO_PLUGIN_NUM_OUTPUTS, false);

// TODO multi-port bus stuff
const float** inputs = process->audio_inputs != nullptr
? const_cast<const float**>(process->audio_inputs->data32)
: nullptr;
/**/ float** outputs = process->audio_outputs != nullptr
? process->audio_inputs->data32
: nullptr;

fOutputEvents = process->out_events;

#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
fPlugin.run(inputs, outputs, frames, fMidiEvents, midiEventCount);
#else
fPlugin.run(inputs, outputs, frames);
#endif

fOutputEvents = nullptr;
}

return true;
}

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

private:
// Plugin
PluginExporter fPlugin;

// CLAP stuff
const clap_host_t* const fHost;
const clap_output_events_t* fOutputEvents;
#if DISTRHO_PLUGIN_WANT_TIMEPOS
TimePosition fTimePosition;
#endif

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

#if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
bool writeMidi(const MidiEvent&)
{
return true;
}

static bool writeMidiCallback(void* const ptr, const MidiEvent& midiEvent)
{
return ((PluginStub*)ptr)->writeMidi(midiEvent);
}
#endif

#if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
bool requestParameterValueChange(uint32_t, float)
{
return true;
}

static bool requestParameterValueChangeCallback(void* const ptr, const uint32_t index, const float value)
{
return ((PluginStub*)ptr)->requestParameterValueChange(index, value);
}
#endif

#if DISTRHO_PLUGIN_WANT_STATE
bool updateState(const char*, const char*)
{
return true;
}

static bool updateStateValueCallback(void* const ptr, const char* const key, const char* const value)
{
return ((PluginStub*)ptr)->updateState(key, value);
}
#endif
};

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

static ScopedPointer<PluginExporter> sPlugin;

// --------------------------------------------------------------------------------------------------------------------
// plugin audio ports

static uint32_t clap_plugin_audio_ports_count(const clap_plugin_t*, const bool is_input)
{
return is_input ? DISTRHO_PLUGIN_NUM_INPUTS : DISTRHO_PLUGIN_NUM_OUTPUTS;
}

static bool clap_plugin_audio_ports_get(const clap_plugin_t*,
const uint32_t index,
const bool is_input,
clap_audio_port_info_t* const info)
{
const uint32_t maxPortCount = is_input ? DISTRHO_PLUGIN_NUM_INPUTS : DISTRHO_PLUGIN_NUM_OUTPUTS;
DISTRHO_SAFE_ASSERT_UINT2_RETURN(index < maxPortCount, index, maxPortCount, false);

AudioPortWithBusId& audioPort(sPlugin->getAudioPort(is_input, index));

info->id = index;
std::strncpy(info->name, audioPort.name, CLAP_NAME_SIZE-1);

// TODO bus stuff
info->flags = CLAP_AUDIO_PORT_IS_MAIN;
info->channel_count = maxPortCount;

// TODO CV
// info->port_type = audioPort.hints & kAudioPortIsCV ? CLAP_PORT_CV : nullptr;
info->port_type = nullptr;

info->in_place_pair = index < (is_input ? DISTRHO_PLUGIN_NUM_OUTPUTS : DISTRHO_PLUGIN_NUM_INPUTS)
? index
: CLAP_INVALID_ID;
return true;
}

static const clap_plugin_audio_ports_t clap_plugin_audio_ports = {
clap_plugin_audio_ports_count,
clap_plugin_audio_ports_get
};

// --------------------------------------------------------------------------------------------------------------------
// plugin

static bool clap_plugin_init(const clap_plugin_t* const plugin)
{
PluginCLAP* const instance = static_cast<PluginCLAP*>(plugin->plugin_data);
return instance->init();
}

static void clap_plugin_destroy(const clap_plugin_t* const plugin)
{
delete static_cast<PluginCLAP*>(plugin->plugin_data);
std::free(const_cast<clap_plugin_t*>(plugin));
}

static bool clap_plugin_activate(const clap_plugin_t* const plugin,
const double sample_rate,
uint32_t,
const uint32_t max_frames_count)
{
d_nextBufferSize = max_frames_count;
d_nextSampleRate = sample_rate;

PluginCLAP* const instance = static_cast<PluginCLAP*>(plugin->plugin_data);
instance->activate(sample_rate, max_frames_count);
return true;
}

static void clap_plugin_deactivate(const clap_plugin_t* const plugin)
{
PluginCLAP* const instance = static_cast<PluginCLAP*>(plugin->plugin_data);
instance->deactivate();
}

static bool clap_plugin_start_processing(const clap_plugin_t*)
{
// nothing to do
return true;
}

static void clap_plugin_stop_processing(const clap_plugin_t*)
{
// nothing to do
}

static void clap_plugin_reset(const clap_plugin_t*)
{
// nothing to do
}

static clap_process_status clap_plugin_process(const clap_plugin_t* const plugin, const clap_process_t* const process)
{
PluginCLAP* const instance = static_cast<PluginCLAP*>(plugin->plugin_data);
return instance->process(process) ? CLAP_PROCESS_CONTINUE : CLAP_PROCESS_ERROR;
}

static const void* clap_plugin_get_extension(const clap_plugin_t*, const char* const id)
{
if (std::strcmp(id, CLAP_EXT_AUDIO_PORTS) == 0)
return &clap_plugin_audio_ports;
return nullptr;
}

static void clap_plugin_on_main_thread(const clap_plugin_t*)
{
// nothing to do
}

// --------------------------------------------------------------------------------------------------------------------
// plugin factory

static uint32_t clap_get_plugin_count(const clap_plugin_factory_t*)
{
return 1;
}

static const clap_plugin_descriptor_t* clap_get_plugin_descriptor(const clap_plugin_factory_t*, const uint32_t index)
{
DISTRHO_SAFE_ASSERT_UINT_RETURN(index == 0, index, nullptr);

static const char* features[] = {
#ifdef DISTRHO_PLUGIN_CLAP_FEATURES
DISTRHO_PLUGIN_CLAP_FEATURES,
#elif DISTRHO_PLUGIN_IS_SYNTH
"instrument",
#endif
nullptr
};

static const clap_plugin_descriptor_t descriptor = {
CLAP_VERSION,
sPlugin->getLabel(),
sPlugin->getName(),
sPlugin->getMaker(),
// TODO url
"",
// TODO manual url
"",
// TODO support url
"",
// TODO version string
"",
sPlugin->getDescription(),
features
};

return &descriptor;
}

static const clap_plugin_t* clap_create_plugin(const clap_plugin_factory_t* const factory,
const clap_host_t* const host,
const char*)
{
clap_plugin_t* const pluginptr = static_cast<clap_plugin_t*>(std::malloc(sizeof(clap_plugin_t)));
DISTRHO_SAFE_ASSERT_RETURN(pluginptr != nullptr, nullptr);

// default early values
if (d_nextBufferSize == 0)
d_nextBufferSize = 1024;
if (d_nextSampleRate <= 0.0)
d_nextSampleRate = 44100.0;

d_nextCanRequestParameterValueChanges = true;

const clap_plugin_t plugin = {
clap_get_plugin_descriptor(factory, 0),
new PluginCLAP(host),
clap_plugin_init,
clap_plugin_destroy,
clap_plugin_activate,
clap_plugin_deactivate,
clap_plugin_start_processing,
clap_plugin_stop_processing,
clap_plugin_reset,
clap_plugin_process,
clap_plugin_get_extension,
clap_plugin_on_main_thread
};

std::memcpy(pluginptr, &plugin, sizeof(clap_plugin_t));
return pluginptr;
}

static const clap_plugin_factory_t clap_plugin_factory = {
clap_get_plugin_count,
clap_get_plugin_descriptor,
clap_create_plugin
};

// --------------------------------------------------------------------------------------------------------------------
// plugin entry

static bool clap_plugin_entry_init(const char* const plugin_path)
{
static String bundlePath;
bundlePath = plugin_path;
d_nextBundlePath = bundlePath.buffer();

// init dummy plugin
if (sPlugin == nullptr)
{
// set valid but dummy values
d_nextBufferSize = 512;
d_nextSampleRate = 44100.0;
d_nextPluginIsDummy = true;
d_nextCanRequestParameterValueChanges = true;

// Create dummy plugin to get data from
sPlugin = new PluginExporter(nullptr, nullptr, nullptr, nullptr);

// unset
d_nextBufferSize = 0;
d_nextSampleRate = 0.0;
d_nextPluginIsDummy = false;
d_nextCanRequestParameterValueChanges = false;
}

return true;
}

static void clap_plugin_entry_deinit(void)
{
sPlugin = nullptr;
}

static const void* clap_plugin_entry_get_factory(const char* const factory_id)
{
if (std::strcmp(factory_id, CLAP_PLUGIN_FACTORY_ID) == 0)
return &clap_plugin_factory;
return nullptr;
}

static const clap_plugin_entry_t clap_plugin_entry = {
CLAP_VERSION,
clap_plugin_entry_init,
clap_plugin_entry_deinit,
clap_plugin_entry_get_factory
};

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

END_NAMESPACE_DISTRHO

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

DISTRHO_PLUGIN_EXPORT
const clap_plugin_entry_t clap_entry = DISTRHO_NAMESPACE::clap_plugin_entry;

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

+ 37
- 0
distrho/src/clap/audio-buffer.h View File

@@ -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
- 0
distrho/src/clap/entry.h View File

@@ -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
- 0
distrho/src/clap/events.h View File

@@ -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
- 0
distrho/src/clap/ext/audio-ports.h View File

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

+ 16
- 0
distrho/src/clap/fixedpoint.h View File

@@ -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
- 0
distrho/src/clap/host.h View File

@@ -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
- 0
distrho/src/clap/id.h View File

@@ -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
- 0
distrho/src/clap/plugin-factory.h View File

@@ -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
- 0
distrho/src/clap/plugin-features.h View File

@@ -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
- 0
distrho/src/clap/plugin.h View File

@@ -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
- 0
distrho/src/clap/private/macros.h View File

@@ -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
- 0
distrho/src/clap/private/std.h View File

@@ -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
- 0
distrho/src/clap/process.h View File

@@ -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
- 0
distrho/src/clap/string-sizes.h View File

@@ -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
- 0
distrho/src/clap/version.h View File

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

+ 1
- 0
utils/symbols/clap.def View File

@@ -1 +1,2 @@
EXPORTS
clap_entry

+ 1
- 0
utils/symbols/clap.exp View File

@@ -0,0 +1 @@
_clap_entry

+ 1
- 1
utils/symbols/clap.version View File

@@ -1,4 +1,4 @@
{
global: __name;
global: clap_entry;
local: *;
};

Loading…
Cancel
Save