| @@ -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 | |||
| @@ -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)) | |||
| @@ -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; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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; | |||
| @@ -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 | |||
| @@ -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; | |||
| @@ -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 | |||
| @@ -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" | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 +1,2 @@ | |||
| EXPORTS | |||
| clap_entry | |||
| @@ -0,0 +1 @@ | |||
| _clap_entry | |||
| @@ -1,4 +1,4 @@ | |||
| { | |||
| global: __name; | |||
| global: clap_entry; | |||
| local: *; | |||
| }; | |||