clap

CLAP Audio Plugin API
Log | Files | Refs | README | LICENSE

commit ab615b89ca68bf0e4c83f5688d47ca1624340282
parent ebae08466008f83453975290aec0be25d67283bd
Author: Alexandre BIQUE <bique.alexandre@gmail.com>
Date:   Tue,  3 May 2022 21:57:48 +0200

More work on the plugin template

Diffstat:
MCMakeLists.txt | 22+++++++++++++++++++++-
Asrc/linux-my_plug.version | 6++++++
Asrc/macos-symbols.txt | 1+
Msrc/plugin-template.c | 134++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Asrc/plugins.plist.in | 34++++++++++++++++++++++++++++++++++
5 files changed, 195 insertions(+), 2 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -18,7 +18,7 @@ add_executable(clap-compile-cpp EXCLUDE_FROM_ALL src/main.cc) target_link_libraries(clap-compile-cpp clap-core) set_target_properties(clap-compile-cpp PROPERTIES CXX_STANDARD 14) -add_library(clap-plugin-template EXCLUDE_FROM_ALL src/plugin-template.c) +add_library(clap-plugin-template MODULE EXCLUDE_FROM_ALL src/plugin-template.c) target_link_libraries(clap-plugin-template clap-core) set_target_properties(clap-plugin-template PROPERTIES C_STANDARD 11) @@ -32,6 +32,26 @@ if (${CMAKE_C_COMPILER_ID} STREQUAL "Clang") target_compile_options(clap-compile-cpp PRIVATE -Werror=pragma-pack) endif() +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + target_link_libraries(clap-plugin-template PRIVATE -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/linux-my_plug.version) + target_link_libraries(clap-plugin-template PRIVATE -Wl,-z,defs) + set_target_properties(clap-plugin-template PROPERTIES SUFFIX ".clap" PREFIX "") +elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + target_link_options(clap-plugin-template PRIVATE -exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/src/macos-symbols.txt) + + set_target_properties(clap-plugin-template PROPERTIES + BUNDLE True + BUNDLE_EXTENSION clap + MACOSX_BUNDLE_GUI_IDENTIFIER com.my_company.my_plug + MACOSX_BUNDLE_BUNDLE_NAME my_plug + MACOSX_BUNDLE_BUNDLE_VERSION "1" + MACOSX_BUNDLE_SHORT_VERSION_STRING "1" + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/src/plugins.plist.in + ) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + set_target_properties(clap-plugin-template PROPERTIES SUFFIX ".clap" PREFIX "") +endif() + add_test(NAME test-clap-compile-c COMMAND clap-compile-c) add_test(NAME test-clap-compile-cpp COMMAND clap-compile-cpp) diff --git a/src/linux-my_plug.version b/src/linux-my_plug.version @@ -0,0 +1,6 @@ +MY_PLUG_ABI_1.0 { + global: + clap_entry; + local: + *; +}; diff --git a/src/macos-symbols.txt b/src/macos-symbols.txt @@ -0,0 +1 @@ +_clap_entry diff --git a/src/plugin-template.c b/src/plugin-template.c @@ -19,6 +19,7 @@ static const clap_plugin_descriptor_t s_my_plug_desc = { typedef struct { clap_plugin_t plugin; const clap_host_t *host; + uint32_t latency; } my_plug_t; ///////////////////////////// @@ -47,11 +48,39 @@ static const clap_plugin_audio_ports_t s_my_plug_audio_ports = { .get = my_plug_audio_ports_get, }; +//////////////////////////// +// clap_plugin_note_ports // +//////////////////////////// + +static uint32_t my_plug_note_ports_count(const clap_plugin_t *plugin, bool is_input) { return 1; } + +static bool my_plug_note_ports_get(const clap_plugin_t *plugin, + uint32_t index, + bool is_input, + clap_note_port_info_t *info) { + if (index != 1) + return false; + info->id = 0; + snprintf(info->name, sizeof(info->name), "%s", "My Port Name"); + info->supported_dialects = + CLAP_NOTE_DIALECT_CLAP | CLAP_NOTE_DIALECT_MIDI_MPE | CLAP_NOTE_DIALECT_MIDI2; + info->preferred_dialect = CLAP_NOTE_DIALECT_CLAP; + return true; +} + +static const clap_plugin_note_ports_t s_my_plug_note_ports = { + .count = my_plug_note_ports_count, + .get = my_plug_note_ports_get, +}; + ////////////////// // clap_latency // ////////////////// -uint32_t my_plug_latency_get(const clap_plugin_t *plugin) { return 0; } +uint32_t my_plug_latency_get(const clap_plugin_t *plugin) { + my_plug_t *plug = plugin->plugin_data; + return plug->latency; +} static const clap_plugin_latency_t s_my_plug_latency = { .get = my_plug_latency_get, @@ -80,8 +109,109 @@ static void my_plug_stop_processing(const struct clap_plugin *plugin) {} static void my_plug_reset(const struct clap_plugin *plugin) {} +static void my_plug_process_event(my_plug_t *plug, const clap_event_header_t *hdr) { + if (hdr->space_id == CLAP_CORE_EVENT_SPACE_ID) { + switch (hdr->type) { + case CLAP_EVENT_NOTE_ON: { + const clap_event_note_t *ev = (const clap_event_note_t *)hdr; + // TODO: handle note on + break; + } + + case CLAP_EVENT_NOTE_OFF: { + const clap_event_note_t *ev = (const clap_event_note_t *)hdr; + // TODO: handle note on + break; + } + + case CLAP_EVENT_NOTE_CHOKE: { + const clap_event_note_t *ev = (const clap_event_note_t *)hdr; + // TODO: handle note choke + break; + } + + case CLAP_EVENT_NOTE_EXPRESSION: { + const clap_event_note_expression_t *ev = (const clap_event_note_expression_t *)hdr; + // TODO: handle note expression + break; + } + + case CLAP_EVENT_PARAM_VALUE: { + const clap_event_param_value_t *ev = (const clap_event_param_value_t *)hdr; + // TODO: handle parameter change + break; + } + + case CLAP_EVENT_PARAM_MOD: { + const clap_event_param_mod_t *ev = (const clap_event_param_mod_t *)hdr; + // TODO: handle parameter modulation + break; + } + + case CLAP_EVENT_TRANSPORT: { + const clap_event_transport_t *ev = (const clap_event_transport_t *)hdr; + // TODO: handle transport event + break; + } + + case CLAP_EVENT_MIDI: { + const clap_event_midi_t *ev = (const clap_event_midi_t *)hdr; + // TODO: handle MIDI event + break; + } + + case CLAP_EVENT_MIDI_SYSEX: { + const clap_event_midi_sysex_t *ev = (const clap_event_midi_sysex_t *)hdr; + // TODO: handle MIDI Sysex event + break; + } + + case CLAP_EVENT_MIDI2: { + const clap_event_midi2_t *ev = (const clap_event_midi2_t *)hdr; + // TODO: handle MIDI2 event + break; + } + } + } +} + static clap_process_status my_plug_process(const struct clap_plugin *plugin, const clap_process_t *process) { + my_plug_t *plug = plugin->plugin_data; + const uint32_t nframes = process->frames_count; + const uint32_t nev = process->in_events->size(process->in_events); + uint32_t ev_index = 0; + uint32_t next_ev_frame = (nev == 0 ? nframes : 0); + + for (uint32_t i = 0; i < nframes;) { + while (ev_index < nev && next_ev_frame == i) { + const clap_event_header_t *hdr = process->in_events->get(process->in_events, ev_index); + if (hdr->time != i) { + next_ev_frame = hdr->time; + break; + } + + my_plug_process_event(plug, hdr); + ++ev_index; + if (ev_index == nev) { + next_ev_frame = nframes; + } + } + + const uint32_t until_frame = next_ev_frame < nframes ? next_ev_frame : nframes; + for (; i < until_frame; ++i) { + const float in_l = process->audio_inputs[0].data32[0][i]; + const float in_r = process->audio_inputs[0].data32[1][i]; + + /* TODO: process samples, here we simply swap left and right channels */ + const float out_l = in_r; + const float out_r = in_l; + + process->audio_outputs[0].data32[0][i] = out_l; + process->audio_outputs[0].data32[1][i] = out_r; + } + } + return CLAP_PROCESS_CONTINUE; } @@ -90,6 +220,8 @@ static const void *my_plug_get_extension(const struct clap_plugin *plugin, const return &s_my_plug_latency; if (!strcmp(id, CLAP_EXT_AUDIO_PORTS)) return &s_my_plug_audio_ports; + if (!strcmp(id, CLAP_EXT_NOTE_PORTS)) + return &s_my_plug_note_ports; return NULL; } diff --git a/src/plugins.plist.in b/src/plugins.plist.in @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleExecutable</key> + <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string> + <key>CFBundleGetInfoString</key> + <string>${MACOSX_BUNDLE_INFO_STRING}</string> + <key>CFBundleIconFile</key> + <string>${MACOSX_BUNDLE_ICON_FILE}</string> + <key>CFBundleIdentifier</key> + <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleLongVersionString</key> + <string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string> + <key>CFBundleName</key> + <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string> + <key>CFBundlePackageType</key> + <string>BNDL</string> + <key>CFBundleShortVersionString</key> + <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string> + <key>CSResourcesFileMapped</key> + <true/> + <key>NSHumanReadableCopyright</key> + <string>${MACOSX_BUNDLE_COPYRIGHT}</string> +</dict> +</plist>