clap

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

commit 81bb370b4be5384f47fe308cb68155af9adf7005
parent 74c01b879b7f14b83d8c097bc524734d86ca01d6
Author: Alexandre BIQUE <bique.alexandre@gmail.com>
Date:   Mon,  7 Jun 2021 23:10:39 +0200

Create a glue library to make the Plugin class re-usable

Diffstat:
MCMakeLists.txt | 1+
Mexamples/CMakeLists.txt | 21++++++++++++---------
Aexamples/glue/CMakeLists.txt | 5+++++
Aexamples/glue/clap-plugin.cc | 754+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aexamples/glue/clap-plugin.hh | 441+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mexamples/plugins/CMakeLists.txt | 8+++-----
Mexamples/plugins/plugin-helper.hh | 4+++-
Dexamples/plugins/plugin.cc | 754-------------------------------------------------------------------------------
Dexamples/plugins/plugin.hh | 443-------------------------------------------------------------------------------
9 files changed, 1219 insertions(+), 1212 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 3.20) project(CLAP C CXX) +set(ENABLE_CLAP_GLUE TRUE CACHE BOOL "Enables the helper glue code") set(ENABLE_CLAP_HOST FALSE CACHE BOOL "Enables the example host") set(ENABLE_CLAP_PLUGINS FALSE CACHE BOOL "Enables the example plugins") set(ENABLE_CLAP_GUI FALSE CACHE BOOL "Enables the plugin GUI framework") diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt @@ -1,12 +1,16 @@ -if (ENABLE_CLAP_HOST) - add_subdirectory(host) +if(ENABLE_CLAP_GLUE) + add_subdirectory(glue) endif() -if (ENABLE_CLAP_GUI OR ENABLE_CLAP_PLUGINS) - add_subdirectory(gui) - add_subdirectory(gui-proxy) +if(ENABLE_CLAP_HOST) + add_subdirectory(host) endif() -if (ENABLE_CLAP_PLUGINS) - add_subdirectory(plugins) -endif() -\ No newline at end of file +if(ENABLE_CLAP_GUI OR ENABLE_CLAP_PLUGINS) + add_subdirectory(gui) + add_subdirectory(gui-proxy) +endif() + +if(ENABLE_CLAP_PLUGINS) + add_subdirectory(plugins) +endif() diff --git a/examples/glue/CMakeLists.txt b/examples/glue/CMakeLists.txt @@ -0,0 +1,5 @@ +add_library(clap-plugin-glue EXCLUDE_FROM_ALL STATIC clap-plugin.cc + clap-plugin.hh) +set_target_properties(clap-plugin-glue PROPERTIES CXX_STANDARD 17 + POSITION_INDEPENDENT_CODE ON) +target_include_directories(clap-plugin-glue INTERFACE .) diff --git a/examples/glue/clap-plugin.cc b/examples/glue/clap-plugin.cc @@ -0,0 +1,753 @@ +#include <cassert> +#include <cstring> +#include <filesystem> +#include <iostream> +#include <sstream> +#include <stdexcept> +#include <utility> + +#include "clap-plugin.hh" + +namespace clap { + + Plugin::Plugin(const clap_plugin_descriptor *desc, const clap_host *host) : host_(host) { + plugin_.plugin_data = this; + plugin_.desc = desc; + plugin_.init = Plugin::clapInit; + plugin_.destroy = Plugin::clapDestroy; + plugin_.extension = nullptr; + plugin_.process = nullptr; + plugin_.activate = nullptr; + plugin_.deactivate = nullptr; + plugin_.start_processing = nullptr; + plugin_.stop_processing = nullptr; + } + + ///////////////////// + // CLAP Interfaces // + ///////////////////// + + //-------------// + // clap_plugin // + //-------------// + bool Plugin::clapInit(const clap_plugin *plugin) noexcept { + auto &self = from(plugin); + + self.plugin_.extension = Plugin::clapExtension; + self.plugin_.process = Plugin::clapProcess; + self.plugin_.activate = Plugin::clapActivate; + self.plugin_.deactivate = Plugin::clapDeactivate; + self.plugin_.start_processing = Plugin::clapStartProcessing; + self.plugin_.stop_processing = Plugin::clapStopProcessing; + + self.initInterfaces(); + self.ensureMainThread("clap_plugin.init"); + return self.init(); + } + + void Plugin::clapDestroy(const clap_plugin *plugin) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin.destroy"); + delete &from(plugin); + } + + bool Plugin::clapActivate(const clap_plugin *plugin, int sample_rate) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin.activate"); + + if (self.isActive_) { + self.hostMisbehaving("Plugin was activated twice"); + + if (sample_rate != self.sampleRate_) { + std::ostringstream msg; + msg << "The plugin was activated twice and with different sample rates: " + << self.sampleRate_ << " and " << sample_rate + << ". The host must deactivate the plugin first." << std::endl + << "Simulating deactivation."; + self.hostMisbehaving(msg.str()); + clapDeactivate(plugin); + } + } + + if (sample_rate <= 0) { + std::ostringstream msg; + msg << "The plugin was activated with an invalid sample rates: " << sample_rate; + self.hostMisbehaving(msg.str()); + return false; + } + + assert(!self.isActive_); + assert(self.sampleRate_ == 0); + + if (!self.activate(sample_rate)) { + assert(!self.isActive_); + assert(self.sampleRate_ == 0); + return false; + } + + self.isActive_ = true; + self.sampleRate_ = sample_rate; + return true; + } + + void Plugin::clapDeactivate(const clap_plugin *plugin) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin.deactivate"); + + if (!self.isActive_) { + self.hostMisbehaving("The plugin was deactivated twice."); + return; + } + + self.deactivate(); + } + + bool Plugin::clapStartProcessing(const clap_plugin *plugin) noexcept { + auto &self = from(plugin); + self.ensureAudioThread("clap_plugin.start_processing"); + + if (!self.isActive_) { + self.hostMisbehaving("Host called clap_plugin.start_processing() on a deactivated plugin"); + return false; + } + + if (self.isProcessing_) { + self.hostMisbehaving("Host called clap_plugin.start_processing() twice"); + return true; + } + + self.isProcessing_ = self.startProcessing(); + return self.isProcessing_; + } + + void Plugin::clapStopProcessing(const clap_plugin *plugin) noexcept { + auto &self = from(plugin); + self.ensureAudioThread("clap_plugin.stop_processing"); + + if (!self.isActive_) { + self.hostMisbehaving("Host called clap_plugin.stop_processing() on a deactivated plugin"); + return; + } + + if (!self.isProcessing_) { + self.hostMisbehaving("Host called clap_plugin.stop_processing() twice"); + return; + } + + self.stopProcessing(); + self.isProcessing_ = false; + } + + clap_process_status Plugin::clapProcess(const clap_plugin *plugin, + const clap_process *process) noexcept { + auto &self = from(plugin); + self.ensureAudioThread("clap_plugin.process"); + + if (!self.isActive_) { + self.hostMisbehaving("Host called clap_plugin.process() on a deactivated plugin"); + return CLAP_PROCESS_ERROR; + } + + if (!self.isProcessing_) { + self.hostMisbehaving( + "Host called clap_plugin.process() without calling clap_plugin.start_processing()"); + return CLAP_PROCESS_ERROR; + } + + return self.process(process); + } + + const void *Plugin::clapExtension(const clap_plugin *plugin, const char *id) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin.extension"); + + if (!strcmp(id, CLAP_EXT_STATE) && self.implementsState()) + return &pluginState_; + if (!strcmp(id, CLAP_EXT_PRESET_LOAD) && self.implementsPresetLoad()) + return &pluginPresetLoad_; + if (!strcmp(id, CLAP_EXT_RENDER) && self.implementsRender()) + return &pluginRender_; + if (!strcmp(id, CLAP_EXT_TRACK_INFO) && self.implementsTrackInfo()) + return &pluginTrackInfo_; + if (!strcmp(id, CLAP_EXT_LATENCY) && self.implementsLatency()) + return &pluginLatency_; + if (!strcmp(id, CLAP_EXT_AUDIO_PORTS) && self.implementsAudioPorts()) + return &pluginAudioPorts_; + if (!strcmp(id, CLAP_EXT_PARAMS) && self.implementsParams()) + return &pluginParams_; + if (!strcmp(id, CLAP_EXT_NOTE_NAME) && self.implementsNoteName()) + return &pluginNoteName_; + if (!strcmp(id, CLAP_EXT_THREAD_POOL) && self.implementsThreadPool()) + return &pluginThreadPool_; + if (!strcmp(id, CLAP_EXT_EVENT_LOOP) && self.implementsEventLoop()) + return &pluginEventLoop_; + if (!strcmp(id, CLAP_EXT_GUI) && self.implementsGui()) + return &pluginGui_; + if (!strcmp(id, CLAP_EXT_GUI_X11) && self.implementsGuiX11()) + return &pluginGuiX11_; + if (!strcmp(id, CLAP_EXT_GUI_WIN32) && self.implementsGuiWin32()) + return &pluginGuiWin32_; + if (!strcmp(id, CLAP_EXT_GUI_COCOA) && self.implementsGuiCocoa()) + return &pluginGuiCocoa_; + if (!strcmp(id, CLAP_EXT_GUI_FREE_STANDING) && self.implementsGuiFreeStanding()) + return &pluginGuiFreeStanding_; + + return from(plugin).extension(id); + } + + template <typename T> + void Plugin::initInterface(const T *&ptr, const char *id) noexcept { + assert(!ptr); + assert(id); + + if (host_->extension) + ptr = static_cast<const T *>(host_->extension(host_, id)); + } + + void Plugin::initInterfaces() noexcept { + initInterface(hostLog_, CLAP_EXT_LOG); + initInterface(hostThreadCheck_, CLAP_EXT_THREAD_CHECK); + initInterface(hostThreadPool_, CLAP_EXT_THREAD_POOL); + initInterface(hostAudioPorts_, CLAP_EXT_AUDIO_PORTS); + initInterface(hostEventLoop_, CLAP_EXT_EVENT_LOOP); + initInterface(hostEventFilter_, CLAP_EXT_EVENT_FILTER); + initInterface(hostFileReference_, CLAP_EXT_FILE_REFERENCE); + initInterface(hostLatency_, CLAP_EXT_LATENCY); + initInterface(hostGui_, CLAP_EXT_GUI); + initInterface(hostParams_, CLAP_EXT_PARAMS); + initInterface(hostTrackInfo_, CLAP_EXT_TRACK_INFO); + initInterface(hostState_, CLAP_EXT_STATE); + initInterface(hostNoteName_, CLAP_EXT_NOTE_NAME); + } + + //-------------------// + // clap_plugin_state // + //-------------------// + uint32_t Plugin::clapLatencyGet(const clap_plugin *plugin) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_latency.get"); + + return self.latencyGet(); + } + + //--------------------// + // clap_plugin_render // + //--------------------// + void Plugin::clapRenderSetMode(const clap_plugin *plugin, + clap_plugin_render_mode mode) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_render.set_mode"); + + switch (mode) { + case CLAP_RENDER_REALTIME: + case CLAP_RENDER_OFFLINE: + self.renderSetMode(mode); + break; + + default: { + std::ostringstream msg; + msg << "host called clap_plugin_render.set_mode with an unknown mode : " << mode; + self.hostMisbehaving(msg.str()); + break; + } + } + } + + //-------------------------// + // clap_plugin_thread_pool // + //-------------------------// + void Plugin::clapThreadPoolExec(const clap_plugin *plugin, uint32_t task_index) noexcept { + auto &self = from(plugin); + + self.threadPoolExec(task_index); + } + + //-------------------// + // clap_plugin_state // + //-------------------// + bool Plugin::clapStateSave(const clap_plugin *plugin, clap_ostream *stream) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_state.save"); + + return self.stateSave(stream); + } + + bool Plugin::clapStateLoad(const clap_plugin *plugin, clap_istream *stream) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_state.load"); + + return self.stateLoad(stream); + } + + bool Plugin::clapStateIsDirty(const clap_plugin *plugin) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_state.is_dirty"); + + return self.stateIsDirty(); + } + + //-------------------------// + // clap_plugin_preset_load // + //-------------------------// + bool Plugin::clapPresetLoadFromFile(const clap_plugin *plugin, const char *path) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_preset_load.from_file"); + + if (!path) { + self.hostMisbehaving("host called clap_plugin_preset_load.from_file with a null path"); + return false; + } + + // TODO check if the file is readable + + return self.presetLoadFromFile(path); + } + + //------------------------// + // clap_plugin_track_info // + //------------------------// + + void Plugin::clapTrackInfoChanged(const clap_plugin *plugin) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_track_info.changed"); + + if (!self.canUseTrackInfo()) { + self.hostMisbehaving("host called clap_plugin_track_info.changed() but does not provide a " + "complete clap_host_track_info interface"); + return; + } + + self.trackInfoChanged(); + } + + //-------------------------// + // clap_plugin_audio_ports // + //-------------------------// + + uint32_t Plugin::clapAudioPortsCount(const clap_plugin *plugin, bool is_input) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_audio_ports.count"); + + return self.audioPortsCount(is_input); + } + + bool Plugin::clapAudioPortsInfo(const clap_plugin *plugin, + uint32_t index, + bool is_input, + clap_audio_port_info *info) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_audio_ports.info"); + auto count = clapAudioPortsCount(plugin, is_input); + if (index >= count) { + std::ostringstream msg; + msg << "Host called clap_plugin_audio_ports.info() with an index out of bounds: " << index + << " >= " << count; + self.hostMisbehaving(msg.str()); + return false; + } + + return self.audioPortsInfo(index, is_input, info); + } + + uint32_t Plugin::clapAudioPortsConfigCount(const clap_plugin *plugin) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_audio_ports.config_count"); + return self.audioPortsConfigCount(); + } + + bool Plugin::clapAudioPortsGetConfig(const clap_plugin *plugin, + uint32_t index, + clap_audio_ports_config *config) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_audio_ports.get_config"); + + auto count = clapAudioPortsConfigCount(plugin); + if (index >= count) { + std::ostringstream msg; + msg << "called clap_plugin_audio_ports.get_config with an index out of bounds: " << index + << " >= " << count; + self.hostMisbehaving(msg.str()); + return false; + } + return self.audioPortsGetConfig(index, config); + } + + bool Plugin::clapAudioPortsSetConfig(const clap_plugin *plugin, clap_id config_id) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_audio_ports.get_config"); + + if (self.isActive()) + self.hostMisbehaving( + "it is illegal to call clap_audio_ports.set_config if the plugin is active"); + + return self.audioPortsSetConfig(config_id); + } + + uint32_t Plugin::clapParamsCount(const clap_plugin *plugin) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_params.count"); + + return self.paramsCount(); + } + + //--------------------// + // clap_plugin_params // + //--------------------// + bool Plugin::clapParamsIinfo(const clap_plugin *plugin, + int32_t param_index, + clap_param_info *param_info) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_params.info"); + + auto count = clapParamsCount(plugin); + if (param_index >= count) { + std::ostringstream msg; + msg << "called clap_plugin_params.info with an index out of bounds: " << param_index + << " >= " << count; + self.hostMisbehaving(msg.str()); + return false; + } + + return self.paramsInfo(param_index, param_info); + } + + bool Plugin::clapParamsEnumValue(const clap_plugin *plugin, + clap_id param_id, + int32_t value_index, + clap_param_value *value) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_params.enum_value"); + + if (!self.isValidParamId(param_id)) { + std::ostringstream msg; + msg << "clap_plugin_params.enum_value called with invalid param_id: " << param_id; + self.hostMisbehaving(msg.str()); + return false; + } + + // TODO: check the value index? + + return self.paramsEnumValue(param_id, value_index, value); + } + + bool Plugin::clapParamsValue(const clap_plugin *plugin, + clap_id param_id, + clap_param_value *value) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_params.value"); + + if (!self.isValidParamId(param_id)) { + std::ostringstream msg; + msg << "clap_plugin_params.value called with invalid param_id: " << param_id; + self.hostMisbehaving(msg.str()); + return false; + } + + // TODO extra checks + + return self.paramsValue(param_id, value); + } + + bool Plugin::clapParamsSetValue(const clap_plugin *plugin, + clap_id param_id, + clap_param_value value, + clap_param_value modulation) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_params.set_value"); + + if (self.isActive_) { + self.hostMisbehaving( + "it is forbidden to call clap_plugin_params.set_value() if the plugin is activated"); + return false; + } + + if (!self.isValidParamId(param_id)) { + std::ostringstream msg; + msg << "clap_plugin_params.set_value called with invalid param_id: " << param_id; + self.hostMisbehaving(msg.str()); + return false; + } + + // TODO: extra checks + + return self.paramsSetValue(param_id, value, modulation); + } + + bool Plugin::clapParamsValueToText(const clap_plugin *plugin, + clap_id param_id, + clap_param_value value, + char *display, + uint32_t size) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_params.value_to_text"); + + if (!self.isValidParamId(param_id)) { + std::ostringstream msg; + msg << "clap_plugin_params.value_to_text called with invalid param_id: " << param_id; + self.hostMisbehaving(msg.str()); + return false; + } + + // TODO: extra checks + return self.paramsValueToText(param_id, value, display, size); + } + + bool Plugin::clapParamsTextToValue(const clap_plugin *plugin, + clap_id param_id, + const char *display, + clap_param_value *value) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_params.text_to_value"); + + if (!self.isValidParamId(param_id)) { + std::ostringstream msg; + msg << "clap_plugin_params.text_to_value called with invalid param_id: " << param_id; + self.hostMisbehaving(msg.str()); + return false; + } + + // TODO: extra checks + return self.paramsTextToValue(param_id, display, value); + } + + bool Plugin::isValidParamId(clap_id param_id) const noexcept { + checkMainThread(); + + auto count = paramsCount(); + clap_param_info info; + for (uint32_t i = 0; i < count; ++i) { + if (!paramsInfo(i, &info)) + // TODO: fatal error? + continue; + + if (info.id == param_id) + return true; + } + return false; + } + + //-----------------------// + // clap_plugin_note_name // + //-----------------------// + + uint32_t Plugin::clapNoteNameCount(const clap_plugin *plugin) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_note_name.count"); + return self.noteNameCount(); + } + + bool Plugin::clapNoteNameGet(const clap_plugin *plugin, + uint32_t index, + clap_note_name *note_name) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_note_name.get"); + + // TODO check index + auto count = clapNoteNameCount(plugin); + if (index >= count) { + std::ostringstream msg; + msg << "host called clap_plugin_note_name.get with an index out of bounds: " << index + << " >= " << count; + self.hostMisbehaving(msg.str()); + return false; + } + + return self.noteNameGet(index, note_name); + } + + //------------------------// + // clap_plugin_event_loop // + //------------------------// + void Plugin::clapEventLoopOnTimer(const clap_plugin *plugin, clap_id timer_id) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_event_loop.on_timer"); + + if (timer_id == CLAP_INVALID_ID) { + self.hostMisbehaving( + "Host called clap_plugin_event_loop.on_timer with an invalid timer_id"); + return; + } + + self.eventLoopOnTimer(timer_id); + } + + void Plugin::clapEventLoopOnFd(const clap_plugin *plugin, clap_fd fd, uint32_t flags) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_event_loop.on_fd"); + + self.eventLoopOnFd(fd, flags); + } + + //-----------------// + // clap_plugin_gui // + //-----------------// + void Plugin::clapGuiSize(const clap_plugin *plugin, int32_t *width, int32_t *height) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_gui.size"); + + self.guiSize(width, height); + } + + void Plugin::clapGuiSetScale(const clap_plugin *plugin, double scale) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_gui.set_scale"); + + self.guiSetScale(scale); + } + + void Plugin::clapGuiShow(const clap_plugin *plugin) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_gui.show"); + + self.guiShow(); + } + + void Plugin::clapGuiHide(const clap_plugin *plugin) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_gui.hide"); + + self.guiHide(); + } + + void Plugin::clapGuiClose(const clap_plugin *plugin) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_gui.close"); + + self.guiClose(); + } + + //---------------------// + // clap_plugin_gui_x11 // + //---------------------// + bool Plugin::clapGuiX11Attach(const clap_plugin *plugin, + const char *display_name, + unsigned long window) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_gui_x11.attach"); + + return self.guiX11Attach(display_name, window); + } + + //-----------------------// + // clap_plugin_gui_win32 // + //-----------------------// + bool Plugin::clapGuiWin32Attach(const clap_plugin *plugin, clap_hwnd window) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_gui_win32.attach"); + + return self.guiWin32Attach(window); + } + + //-----------------------// + // clap_plugin_gui_cocoa // + //-----------------------// + bool Plugin::clapGuiCocoaAttach(const clap_plugin *plugin, void *nsView) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_gui_cocoa.attach"); + + return self.guiCocoaAttach(nsView); + } + + //-------------------------------// + // clap_plugin_gui_free_standing // + //-------------------------------// + bool Plugin::clapGuiFreeStandingOpen(const clap_plugin *plugin) noexcept { + auto &self = from(plugin); + self.ensureMainThread("clap_plugin_gui_win32.attach"); + + return self.guiFreeStandingOpen(); + } + + ///////////// + // Logging // + ///////////// + void Plugin::log(clap_log_severity severity, const char *msg) const noexcept { + if (canUseHostLog()) + hostLog_->log(host_, severity, msg); + else + std::clog << msg << std::endl; + } + + void Plugin::hostMisbehaving(const char *msg) const noexcept { + log(CLAP_LOG_HOST_MISBEHAVING, msg); + } + + ///////////////////////////////// + // Interface consistency check // + ///////////////////////////////// + + bool Plugin::canUseHostLog() const noexcept { return hostLog_ && hostLog_->log; } + + bool Plugin::canUseThreadCheck() const noexcept { + return hostThreadCheck_ && hostThreadCheck_->is_audio_thread && + hostThreadCheck_->is_main_thread; + } + + ///////////////////// + // Thread Checking // + ///////////////////// + + void Plugin::checkMainThread() const noexcept { + if (!hostThreadCheck_ || !hostThreadCheck_->is_main_thread || + hostThreadCheck_->is_main_thread(host_)) + return; + + std::terminate(); + } + + void Plugin::ensureMainThread(const char *method) const noexcept { + if (!hostThreadCheck_ || !hostThreadCheck_->is_main_thread || + hostThreadCheck_->is_main_thread(host_)) + return; + + std::ostringstream msg; + msg << "Host called the method " << method + << "() on wrong thread! It must be called on main thread!"; + hostMisbehaving(msg.str()); + std::terminate(); + } + + void Plugin::ensureAudioThread(const char *method) const noexcept { + if (!hostThreadCheck_ || !hostThreadCheck_->is_audio_thread || + hostThreadCheck_->is_audio_thread(host_)) + return; + + std::ostringstream msg; + msg << "Host called the method " << method + << "() on wrong thread! It must be called on audio thread!"; + hostMisbehaving(msg.str()); + std::terminate(); + } + + /////////////// + // Utilities // + /////////////// + Plugin &Plugin::from(const clap_plugin *plugin) noexcept { + if (!plugin) { + std::cerr << "called with a null clap_plugin pointer!" << std::endl; + std::terminate(); + } + + if (!plugin->plugin_data) { + std::cerr << "called with a null clap_plugin->plugin_data pointer! The host must never " + "change this pointer!" + << std::endl; + std::terminate(); + } + + return *static_cast<Plugin *>(plugin->plugin_data); + } + + uint32_t Plugin::compareAudioPortsInfo(const clap_audio_port_info &a, + const clap_audio_port_info &b) noexcept { + if (a.sample_size != b.sample_size || a.in_place != b.in_place || a.is_cv != b.is_cv || + a.is_main != b.is_main || a.channel_count != b.channel_count || + a.channel_map != b.channel_map || a.id != b.id) + return CLAP_AUDIO_PORTS_RESCAN_ALL; + + if (strncmp(a.name, b.name, sizeof(a.name))) + return CLAP_AUDIO_PORTS_RESCAN_NAMES; + + return 0; + } +} // namespace clap +\ No newline at end of file diff --git a/examples/glue/clap-plugin.hh b/examples/glue/clap-plugin.hh @@ -0,0 +1,440 @@ +#pragma once + +#include <cassert> +#include <string> +#include <string_view> +#include <vector> + +#include <clap/all.h> + +namespace clap { + /// @brief C++ glue and checks + /// + /// @note for an higher level implementation, see @ref PluginHelper + class Plugin { + public: + const clap_plugin *clapPlugin() noexcept { return &plugin_; } + + protected: + Plugin(const clap_plugin_descriptor *desc, const clap_host *host); + virtual ~Plugin() = default; + + // not copyable, not moveable + Plugin(const Plugin &) = delete; + Plugin(Plugin &&) = delete; + Plugin &operator=(const Plugin &) = delete; + Plugin &operator=(Plugin &&) = delete; + + ///////////////////////// + // Methods to override // + ///////////////////////// + + //-------------// + // clap_plugin // + //-------------// + virtual bool init() noexcept { return true; } + virtual bool activate(int sampleRate) noexcept { return true; } + virtual void deactivate() noexcept {} + virtual bool startProcessing() noexcept { return true; } + virtual void stopProcessing() noexcept {} + virtual clap_process_status process(const clap_process *process) noexcept { + return CLAP_PROCESS_SLEEP; + } + virtual const void *extension(const char *id) noexcept { return nullptr; } + + //---------------------// + // clap_plugin_latenxy // + //---------------------// + virtual bool implementsLatency() const noexcept { return false; } + virtual uint32_t latencyGet() const noexcept { return 0; } + + //--------------------// + // clap_plugin_render // + //--------------------// + virtual bool implementsRender() const noexcept { return false; } + virtual void renderSetMode(clap_plugin_render_mode mode) noexcept {} + + //-------------------------// + // clap_plugin_thread_pool // + //-------------------------// + virtual bool implementsThreadPool() const noexcept { return false; } + virtual void threadPoolExec(uint32_t task_index) noexcept; + + //-------------------// + // clap_plugin_state // + //-------------------// + virtual bool implementsState() const noexcept { return false; } + virtual bool stateSave(clap_ostream *stream) noexcept { return false; } + virtual bool stateLoad(clap_istream *stream) noexcept { return false; } + virtual bool stateIsDirty() const noexcept { return false; } + void stateMarkDirty() const noexcept { + if (canUseState()) + hostState_->mark_dirty(host_); + } + + //-------------------------// + // clap_plugin_preset_load // + //-------------------------// + virtual bool implementsPresetLoad() const noexcept { return false; } + virtual bool presetLoadFromFile(const char *path) noexcept { return false; } + + //------------------------// + // clap_plugin_track_info // + //------------------------// + virtual bool implementsTrackInfo() const noexcept { return false; } + virtual void trackInfoChanged() noexcept {} + + //-------------------------// + // clap_plugin_audio_ports // + //-------------------------// + virtual bool implementsAudioPorts() const noexcept { return false; } + virtual uint32_t audioPortsCount(bool is_input) const noexcept { return 0; } + virtual bool + audioPortsInfo(uint32_t index, bool is_input, clap_audio_port_info *info) const noexcept { + return false; + } + virtual uint32_t audioPortsConfigCount() const noexcept { return 0; } + virtual bool audioPortsGetConfig(uint32_t index, + clap_audio_ports_config *config) const noexcept { + return false; + } + virtual bool audioPortsSetConfig(clap_id config_id) noexcept { return false; } + + //--------------------// + // clap_plugin_params // + //--------------------// + virtual bool implementsParams() const noexcept { return false; } + virtual uint32_t paramsCount() const noexcept { return 0; } + virtual bool paramsInfo(int32_t paramIndex, clap_param_info *info) const noexcept { + return false; + } + virtual bool + paramsEnumValue(clap_id paramId, int32_t valueIndex, clap_param_value *value) noexcept { + return false; + } + virtual bool paramsValue(clap_id paramId, clap_param_value *value) noexcept { return false; } + virtual bool paramsSetValue(clap_id paramId, + clap_param_value value, + clap_param_value modulation) noexcept { + return false; + } + virtual bool paramsValueToText(clap_id paramId, + clap_param_value value, + char *display, + uint32_t size) noexcept { + return false; + } + virtual bool + paramsTextToValue(clap_id param_id, const char *display, clap_param_value *value) noexcept { + return false; + } + + //-----------------------// + // clap_plugin_note_name // + //-----------------------// + virtual bool implementsNoteName() const noexcept { return false; } + virtual int noteNameCount() noexcept { return 0; } + virtual bool noteNameGet(int index, clap_note_name *note_name) noexcept { return false; } + + //------------------------// + // clap_plugin_event_loop // + //------------------------// + virtual bool implementsEventLoop() const noexcept { return false; } + virtual void eventLoopOnTimer(clap_id timer_id) noexcept {} + virtual void eventLoopOnFd(clap_fd fd, uint32_t flags) noexcept {} + + //-----------------// + // clap_plugin_gui // + //-----------------// + virtual bool implementsGui() const noexcept { return false; } + virtual void guiSize(int32_t *width, int32_t *height) noexcept {} + virtual void guiSetScale(double scale) noexcept {} + virtual void guiShow() noexcept {} + virtual void guiHide() noexcept {} + virtual void guiClose() noexcept {} + + //---------------------// + // clap_plugin_gui_x11 // + //---------------------// + virtual bool implementsGuiX11() const noexcept { return false; } + virtual bool guiX11Attach(const char *display_name, unsigned long window) noexcept; + + //-----------------------// + // clap_plugin_gui_win32 // + //-----------------------// + virtual bool implementsGuiWin32() const noexcept { return false; } + virtual bool guiWin32Attach(clap_hwnd window) noexcept; + + //-----------------------// + // clap_plugin_gui_cocoa // + //-----------------------// + virtual bool implementsGuiCocoa() const noexcept { return false; } + virtual bool guiCocoaAttach(void *nsView) noexcept; + + //-------------------------------// + // clap_plugin_gui_free_standing // + //-------------------------------// + virtual bool implementsGuiFreeStanding() const noexcept { return false; } + virtual bool guiFreeStandingOpen() noexcept; + + ////////////////// + // Invalidation // + ////////////////// + void invalidateAudioPortsDefinition(); + + ///////////// + // Logging // + ///////////// + void log(clap_log_severity severity, const char *msg) const noexcept; + void hostMisbehaving(const char *msg) const noexcept; + void hostMisbehaving(const std::string &msg) const noexcept { hostMisbehaving(msg.c_str()); } + + ///////////////////////////////// + // Interface consistency check // + ///////////////////////////////// + bool canUseHostLog() const noexcept; + bool canUseThreadCheck() const noexcept; + bool canUseTrackInfo() const noexcept; + bool canUseState() const noexcept; + bool canChangeAudioPorts() const noexcept; + + ///////////////////// + // Thread Checking // + ///////////////////// + void checkMainThread() const noexcept; + void ensureMainThread(const char *method) const noexcept; + void ensureAudioThread(const char *method) const noexcept; + + /////////////// + // Utilities // + /////////////// + static Plugin &from(const clap_plugin *plugin) noexcept; + + template <typename T> + void initInterface(const T *&ptr, const char *id) noexcept; + void initInterfaces() noexcept; + + static uint32_t compareAudioPortsInfo(const clap_audio_port_info &a, + const clap_audio_port_info &b) noexcept; + + virtual bool isValidParamId(clap_id param_id) const noexcept; + + ////////////////////// + // Processing State // + ////////////////////// + bool isActive() const noexcept { return isActive_; } + bool isProcessing() const noexcept { return isProcessing_; } + int sampleRate() const noexcept { + assert(isActive_ && "sample rate is only known if the plugin is active"); + assert(sampleRate_ > 0); + return sampleRate_; + } + + protected: + const clap_host *const host_ = nullptr; + const clap_host_log *hostLog_ = nullptr; + const clap_host_thread_check *hostThreadCheck_ = nullptr; + const clap_host_thread_pool *hostThreadPool_ = nullptr; + const clap_host_audio_ports *hostAudioPorts_ = nullptr; + const clap_host_event_filter *hostEventFilter_ = nullptr; + const clap_host_file_reference *hostFileReference_ = nullptr; + const clap_host_latency *hostLatency_ = nullptr; + const clap_host_gui *hostGui_ = nullptr; + const clap_host_event_loop *hostEventLoop_ = nullptr; + const clap_host_params *hostParams_ = nullptr; + const clap_host_track_info *hostTrackInfo_ = nullptr; + const clap_host_state *hostState_ = nullptr; + const clap_host_note_name *hostNoteName_ = nullptr; + + private: + ///////////////////// + // CLAP Interfaces // + ///////////////////// + + clap_plugin plugin_; + // clap_plugin + static bool clapInit(const clap_plugin *plugin) noexcept; + static void clapDestroy(const clap_plugin *plugin) noexcept; + static bool clapActivate(const clap_plugin *plugin, int sample_rate) noexcept; + static void clapDeactivate(const clap_plugin *plugin) noexcept; + static bool clapStartProcessing(const clap_plugin *plugin) noexcept; + static void clapStopProcessing(const clap_plugin *plugin) noexcept; + static clap_process_status clapProcess(const clap_plugin *plugin, + const clap_process *process) noexcept; + static const void *clapExtension(const clap_plugin *plugin, const char *id) noexcept; + + // latency + static uint32_t clapLatencyGet(const clap_plugin *plugin) noexcept; + + // clap_plugin_render + static void clapRenderSetMode(const clap_plugin *plugin, + clap_plugin_render_mode mode) noexcept; + + // clap_plugin_thread_pool + static void clapThreadPoolExec(const clap_plugin *plugin, uint32_t task_index) noexcept; + + // clap_plugin_state + static bool clapStateSave(const clap_plugin *plugin, clap_ostream *stream) noexcept; + static bool clapStateLoad(const clap_plugin *plugin, clap_istream *stream) noexcept; + static bool clapStateIsDirty(const clap_plugin *plugin) noexcept; + + // clap_plugin_preset + static bool clapPresetLoadFromFile(const clap_plugin *plugin, const char *path) noexcept; + + // clap_plugin_track_info + static void clapTrackInfoChanged(const clap_plugin *plugin) noexcept; + + // clap_plugin_audio_ports + static uint32_t clapAudioPortsCount(const clap_plugin *plugin, bool is_input) noexcept; + static bool clapAudioPortsInfo(const clap_plugin *plugin, + uint32_t index, + bool is_input, + clap_audio_port_info *info) noexcept; + static uint32_t clapAudioPortsConfigCount(const clap_plugin *plugin) noexcept; + static bool clapAudioPortsGetConfig(const clap_plugin *plugin, + uint32_t index, + clap_audio_ports_config *config) noexcept; + static bool clapAudioPortsSetConfig(const clap_plugin *plugin, clap_id config_id) noexcept; + + // clap_plugin_params + static uint32_t clapParamsCount(const clap_plugin *plugin) noexcept; + static bool clapParamsIinfo(const clap_plugin *plugin, + int32_t param_index, + clap_param_info *param_info) noexcept; + static bool clapParamsEnumValue(const clap_plugin *plugin, + clap_id param_id, + int32_t value_index, + clap_param_value *value) noexcept; + static bool clapParamsValue(const clap_plugin *plugin, + clap_id param_id, + clap_param_value *value) noexcept; + static bool clapParamsSetValue(const clap_plugin *plugin, + clap_id param_id, + clap_param_value value, + clap_param_value modulation) noexcept; + static bool clapParamsValueToText(const clap_plugin *plugin, + clap_id param_id, + clap_param_value value, + char *display, + uint32_t size) noexcept; + static bool clapParamsTextToValue(const clap_plugin *plugin, + clap_id param_id, + const char *display, + clap_param_value *value) noexcept; + + // clap_plugin_note_name + static uint32_t clapNoteNameCount(const clap_plugin *plugin) noexcept; + static bool clapNoteNameGet(const clap_plugin *plugin, + uint32_t index, + clap_note_name *note_name) noexcept; + + // clap_plugin_event_loop + static void clapEventLoopOnTimer(const clap_plugin *plugin, clap_id timer_id) noexcept; + static void clapEventLoopOnFd(const clap_plugin *plugin, clap_fd fd, uint32_t flags) noexcept; + + // clap_plugin_gui + static void clapGuiSize(const clap_plugin *plugin, int32_t *width, int32_t *height) noexcept; + static void clapGuiSetScale(const clap_plugin *plugin, double scale) noexcept; + static void clapGuiShow(const clap_plugin *plugin) noexcept; + static void clapGuiHide(const clap_plugin *plugin) noexcept; + static void clapGuiClose(const clap_plugin *plugin) noexcept; + + // clap_plugin_gui_x11 + static bool clapGuiX11Attach(const clap_plugin *plugin, + const char *display_name, + unsigned long window) noexcept; + + // clap_plugin_gui_win32 + static bool clapGuiWin32Attach(const clap_plugin *plugin, clap_hwnd window) noexcept; + + // clap_plugin_gui_cocoa + static bool clapGuiCocoaAttach(const clap_plugin *plugin, void *nsView) noexcept; + + // clap_plugin_gui_free_standing + static bool clapGuiFreeStandingOpen(const clap_plugin *plugin) noexcept; + + // interfaces + static const constexpr clap_plugin_render pluginRender_ = { + clapRenderSetMode, + }; + + static const constexpr clap_plugin_thread_pool pluginThreadPool_ = { + clapThreadPoolExec, + }; + + static const constexpr clap_plugin_state pluginState_ = { + clapStateSave, + clapStateLoad, + clapStateIsDirty, + }; + + static const constexpr clap_plugin_preset_load pluginPresetLoad_ = { + clapPresetLoadFromFile, + }; + + static const constexpr clap_plugin_track_info pluginTrackInfo_ = { + clapTrackInfoChanged, + }; + + static const constexpr clap_plugin_audio_ports pluginAudioPorts_ = { + clapAudioPortsCount, + clapAudioPortsInfo, + clapAudioPortsConfigCount, + clapAudioPortsGetConfig, + clapAudioPortsSetConfig, + }; + + static const constexpr clap_plugin_params pluginParams_ = { + clapParamsCount, + clapParamsIinfo, + clapParamsEnumValue, + clapParamsValue, + clapParamsSetValue, + clapParamsValueToText, + clapParamsTextToValue, + }; + + static const constexpr clap_plugin_latency pluginLatency_ = { + clapLatencyGet, + }; + + static const constexpr clap_plugin_note_name pluginNoteName_ = { + clapNoteNameCount, + clapNoteNameGet, + }; + + static const constexpr clap_plugin_event_loop pluginEventLoop_ = { + clapEventLoopOnTimer, + clapEventLoopOnFd, + }; + + static const constexpr clap_plugin_gui pluginGui_ = { + clapGuiSize, + clapGuiSetScale, + clapGuiShow, + clapGuiHide, + clapGuiClose, + }; + + static const constexpr clap_plugin_gui_x11 pluginGuiX11_ = { + clapGuiX11Attach, + }; + + static const constexpr clap_plugin_gui_win32 pluginGuiWin32_ = { + clapGuiWin32Attach, + }; + + static const constexpr clap_plugin_gui_cocoa pluginGuiCocoa_ = { + clapGuiCocoaAttach, + }; + + static const constexpr clap_plugin_gui_free_standing pluginGuiFreeStanding_ = { + clapGuiFreeStandingOpen, + }; + + // state + bool isActive_ = false; + bool isProcessing_ = false; + int sampleRate_ = 0; + }; +} // namespace clap +\ No newline at end of file diff --git a/examples/plugins/CMakeLists.txt b/examples/plugins/CMakeLists.txt @@ -1,13 +1,11 @@ add_library( - clap-plugin SHARED + clap-plugins SHARED clap-entry.cc parameters.cc parameters.hh - plugin.cc - plugin.hh plugin-helper.cc plugin-helper.hh gain/gain.hh gain/gain.cc) - -set_target_properties(clap-plugin PROPERTIES CXX_STANDARD 20) +target_link_libraries(clap-plugins clap-plugin-glue) +set_target_properties(clap-plugins PROPERTIES CXX_STANDARD 20) diff --git a/examples/plugins/plugin-helper.hh b/examples/plugins/plugin-helper.hh @@ -1,6 +1,8 @@ #pragma once -#include "plugin.hh" +#include <clap-plugin.hh> + +#include "parameters.hh" namespace clap { class PluginHelper : public Plugin { diff --git a/examples/plugins/plugin.cc b/examples/plugins/plugin.cc @@ -1,753 +0,0 @@ -#include <cassert> -#include <cstring> -#include <filesystem> -#include <iostream> -#include <sstream> -#include <stdexcept> -#include <utility> - -#include "plugin.hh" - -namespace clap { - - Plugin::Plugin(const clap_plugin_descriptor *desc, const clap_host *host) : host_(host) { - plugin_.plugin_data = this; - plugin_.desc = desc; - plugin_.init = Plugin::clapInit; - plugin_.destroy = Plugin::clapDestroy; - plugin_.extension = nullptr; - plugin_.process = nullptr; - plugin_.activate = nullptr; - plugin_.deactivate = nullptr; - plugin_.start_processing = nullptr; - plugin_.stop_processing = nullptr; - } - - ///////////////////// - // CLAP Interfaces // - ///////////////////// - - //-------------// - // clap_plugin // - //-------------// - bool Plugin::clapInit(const clap_plugin *plugin) noexcept { - auto &self = from(plugin); - - self.plugin_.extension = Plugin::clapExtension; - self.plugin_.process = Plugin::clapProcess; - self.plugin_.activate = Plugin::clapActivate; - self.plugin_.deactivate = Plugin::clapDeactivate; - self.plugin_.start_processing = Plugin::clapStartProcessing; - self.plugin_.stop_processing = Plugin::clapStopProcessing; - - self.initInterfaces(); - self.ensureMainThread("clap_plugin.init"); - return self.init(); - } - - void Plugin::clapDestroy(const clap_plugin *plugin) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin.destroy"); - delete &from(plugin); - } - - bool Plugin::clapActivate(const clap_plugin *plugin, int sample_rate) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin.activate"); - - if (self.isActive_) { - self.hostMisbehaving("Plugin was activated twice"); - - if (sample_rate != self.sampleRate_) { - std::ostringstream msg; - msg << "The plugin was activated twice and with different sample rates: " - << self.sampleRate_ << " and " << sample_rate - << ". The host must deactivate the plugin first." << std::endl - << "Simulating deactivation."; - self.hostMisbehaving(msg.str()); - clapDeactivate(plugin); - } - } - - if (sample_rate <= 0) { - std::ostringstream msg; - msg << "The plugin was activated with an invalid sample rates: " << sample_rate; - self.hostMisbehaving(msg.str()); - return false; - } - - assert(!self.isActive_); - assert(self.sampleRate_ == 0); - - if (!self.activate(sample_rate)) { - assert(!self.isActive_); - assert(self.sampleRate_ == 0); - return false; - } - - self.isActive_ = true; - self.sampleRate_ = sample_rate; - return true; - } - - void Plugin::clapDeactivate(const clap_plugin *plugin) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin.deactivate"); - - if (!self.isActive_) { - self.hostMisbehaving("The plugin was deactivated twice."); - return; - } - - self.deactivate(); - } - - bool Plugin::clapStartProcessing(const clap_plugin *plugin) noexcept { - auto &self = from(plugin); - self.ensureAudioThread("clap_plugin.start_processing"); - - if (!self.isActive_) { - self.hostMisbehaving("Host called clap_plugin.start_processing() on a deactivated plugin"); - return false; - } - - if (self.isProcessing_) { - self.hostMisbehaving("Host called clap_plugin.start_processing() twice"); - return true; - } - - self.isProcessing_ = self.startProcessing(); - return self.isProcessing_; - } - - void Plugin::clapStopProcessing(const clap_plugin *plugin) noexcept { - auto &self = from(plugin); - self.ensureAudioThread("clap_plugin.stop_processing"); - - if (!self.isActive_) { - self.hostMisbehaving("Host called clap_plugin.stop_processing() on a deactivated plugin"); - return; - } - - if (!self.isProcessing_) { - self.hostMisbehaving("Host called clap_plugin.stop_processing() twice"); - return; - } - - self.stopProcessing(); - self.isProcessing_ = false; - } - - clap_process_status Plugin::clapProcess(const clap_plugin *plugin, - const clap_process *process) noexcept { - auto &self = from(plugin); - self.ensureAudioThread("clap_plugin.process"); - - if (!self.isActive_) { - self.hostMisbehaving("Host called clap_plugin.process() on a deactivated plugin"); - return CLAP_PROCESS_ERROR; - } - - if (!self.isProcessing_) { - self.hostMisbehaving( - "Host called clap_plugin.process() without calling clap_plugin.start_processing()"); - return CLAP_PROCESS_ERROR; - } - - return self.process(process); - } - - const void *Plugin::clapExtension(const clap_plugin *plugin, const char *id) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin.extension"); - - if (!strcmp(id, CLAP_EXT_STATE) && self.implementsState()) - return &pluginState_; - if (!strcmp(id, CLAP_EXT_PRESET_LOAD) && self.implementsPresetLoad()) - return &pluginPresetLoad_; - if (!strcmp(id, CLAP_EXT_RENDER) && self.implementsRender()) - return &pluginRender_; - if (!strcmp(id, CLAP_EXT_TRACK_INFO) && self.implementsTrackInfo()) - return &pluginTrackInfo_; - if (!strcmp(id, CLAP_EXT_LATENCY) && self.implementsLatency()) - return &pluginLatency_; - if (!strcmp(id, CLAP_EXT_AUDIO_PORTS) && self.implementsAudioPorts()) - return &pluginAudioPorts_; - if (!strcmp(id, CLAP_EXT_PARAMS) && self.implementsParams()) - return &pluginParams_; - if (!strcmp(id, CLAP_EXT_NOTE_NAME) && self.implementsNoteName()) - return &pluginNoteName_; - if (!strcmp(id, CLAP_EXT_THREAD_POOL) && self.implementsThreadPool()) - return &pluginThreadPool_; - if (!strcmp(id, CLAP_EXT_EVENT_LOOP) && self.implementsEventLoop()) - return &pluginEventLoop_; - if (!strcmp(id, CLAP_EXT_GUI) && self.implementsGui()) - return &pluginGui_; - if (!strcmp(id, CLAP_EXT_GUI_X11) && self.implementsGuiX11()) - return &pluginGuiX11_; - if (!strcmp(id, CLAP_EXT_GUI_WIN32) && self.implementsGuiWin32()) - return &pluginGuiWin32_; - if (!strcmp(id, CLAP_EXT_GUI_COCOA) && self.implementsGuiCocoa()) - return &pluginGuiCocoa_; - if (!strcmp(id, CLAP_EXT_GUI_FREE_STANDING) && self.implementsGuiFreeStanding()) - return &pluginGuiFreeStanding_; - - return from(plugin).extension(id); - } - - template <typename T> - void Plugin::initInterface(const T *&ptr, const char *id) noexcept { - assert(!ptr); - assert(id); - - if (host_->extension) - ptr = static_cast<const T *>(host_->extension(host_, id)); - } - - void Plugin::initInterfaces() noexcept { - initInterface(hostLog_, CLAP_EXT_LOG); - initInterface(hostThreadCheck_, CLAP_EXT_THREAD_CHECK); - initInterface(hostThreadPool_, CLAP_EXT_THREAD_POOL); - initInterface(hostAudioPorts_, CLAP_EXT_AUDIO_PORTS); - initInterface(hostEventLoop_, CLAP_EXT_EVENT_LOOP); - initInterface(hostEventFilter_, CLAP_EXT_EVENT_FILTER); - initInterface(hostFileReference_, CLAP_EXT_FILE_REFERENCE); - initInterface(hostLatency_, CLAP_EXT_LATENCY); - initInterface(hostGui_, CLAP_EXT_GUI); - initInterface(hostParams_, CLAP_EXT_PARAMS); - initInterface(hostTrackInfo_, CLAP_EXT_TRACK_INFO); - initInterface(hostState_, CLAP_EXT_STATE); - initInterface(hostNoteName_, CLAP_EXT_NOTE_NAME); - } - - //-------------------// - // clap_plugin_state // - //-------------------// - uint32_t Plugin::clapLatencyGet(const clap_plugin *plugin) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_latency.get"); - - return self.latencyGet(); - } - - //--------------------// - // clap_plugin_render // - //--------------------// - void Plugin::clapRenderSetMode(const clap_plugin *plugin, - clap_plugin_render_mode mode) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_render.set_mode"); - - switch (mode) { - case CLAP_RENDER_REALTIME: - case CLAP_RENDER_OFFLINE: - self.renderSetMode(mode); - break; - - default: { - std::ostringstream msg; - msg << "host called clap_plugin_render.set_mode with an unknown mode : " << mode; - self.hostMisbehaving(msg.str()); - break; - } - } - } - - //-------------------------// - // clap_plugin_thread_pool // - //-------------------------// - void Plugin::clapThreadPoolExec(const clap_plugin *plugin, uint32_t task_index) noexcept { - auto &self = from(plugin); - - self.threadPoolExec(task_index); - } - - //-------------------// - // clap_plugin_state // - //-------------------// - bool Plugin::clapStateSave(const clap_plugin *plugin, clap_ostream *stream) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_state.save"); - - return self.stateSave(stream); - } - - bool Plugin::clapStateLoad(const clap_plugin *plugin, clap_istream *stream) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_state.load"); - - return self.stateLoad(stream); - } - - bool Plugin::clapStateIsDirty(const clap_plugin *plugin) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_state.is_dirty"); - - return self.stateIsDirty(); - } - - //-------------------------// - // clap_plugin_preset_load // - //-------------------------// - bool Plugin::clapPresetLoadFromFile(const clap_plugin *plugin, const char *path) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_preset_load.from_file"); - - if (!path) { - self.hostMisbehaving("host called clap_plugin_preset_load.from_file with a null path"); - return false; - } - - // TODO check if the file is readable - - return self.presetLoadFromFile(path); - } - - //------------------------// - // clap_plugin_track_info // - //------------------------// - - void Plugin::clapTrackInfoChanged(const clap_plugin *plugin) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_track_info.changed"); - - if (!self.canUseTrackInfo()) { - self.hostMisbehaving("host called clap_plugin_track_info.changed() but does not provide a " - "complete clap_host_track_info interface"); - return; - } - - self.trackInfoChanged(); - } - - //-------------------------// - // clap_plugin_audio_ports // - //-------------------------// - - uint32_t Plugin::clapAudioPortsCount(const clap_plugin *plugin, bool is_input) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_audio_ports.count"); - - return self.audioPortsCount(is_input); - } - - bool Plugin::clapAudioPortsInfo(const clap_plugin *plugin, - uint32_t index, - bool is_input, - clap_audio_port_info *info) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_audio_ports.info"); - auto count = clapAudioPortsCount(plugin, is_input); - if (index >= count) { - std::ostringstream msg; - msg << "Host called clap_plugin_audio_ports.info() with an index out of bounds: " << index - << " >= " << count; - self.hostMisbehaving(msg.str()); - return false; - } - - return self.audioPortsInfo(index, is_input, info); - } - - uint32_t Plugin::clapAudioPortsConfigCount(const clap_plugin *plugin) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_audio_ports.config_count"); - return self.audioPortsConfigCount(); - } - - bool Plugin::clapAudioPortsGetConfig(const clap_plugin *plugin, - uint32_t index, - clap_audio_ports_config *config) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_audio_ports.get_config"); - - auto count = clapAudioPortsConfigCount(plugin); - if (index >= count) { - std::ostringstream msg; - msg << "called clap_plugin_audio_ports.get_config with an index out of bounds: " << index - << " >= " << count; - self.hostMisbehaving(msg.str()); - return false; - } - return self.audioPortsGetConfig(index, config); - } - - bool Plugin::clapAudioPortsSetConfig(const clap_plugin *plugin, clap_id config_id) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_audio_ports.get_config"); - - if (self.isActive()) - self.hostMisbehaving( - "it is illegal to call clap_audio_ports.set_config if the plugin is active"); - - return self.audioPortsSetConfig(config_id); - } - - uint32_t Plugin::clapParamsCount(const clap_plugin *plugin) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_params.count"); - - return self.paramsCount(); - } - - //--------------------// - // clap_plugin_params // - //--------------------// - bool Plugin::clapParamsIinfo(const clap_plugin *plugin, - int32_t param_index, - clap_param_info *param_info) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_params.info"); - - auto count = clapParamsCount(plugin); - if (param_index >= count) { - std::ostringstream msg; - msg << "called clap_plugin_params.info with an index out of bounds: " << param_index - << " >= " << count; - self.hostMisbehaving(msg.str()); - return false; - } - - return self.paramsInfo(param_index, param_info); - } - - bool Plugin::clapParamsEnumValue(const clap_plugin *plugin, - clap_id param_id, - int32_t value_index, - clap_param_value *value) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_params.enum_value"); - - if (!self.isValidParamId(param_id)) { - std::ostringstream msg; - msg << "clap_plugin_params.enum_value called with invalid param_id: " << param_id; - self.hostMisbehaving(msg.str()); - return false; - } - - // TODO: check the value index? - - return self.paramsEnumValue(param_id, value_index, value); - } - - bool Plugin::clapParamsValue(const clap_plugin *plugin, - clap_id param_id, - clap_param_value *value) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_params.value"); - - if (!self.isValidParamId(param_id)) { - std::ostringstream msg; - msg << "clap_plugin_params.value called with invalid param_id: " << param_id; - self.hostMisbehaving(msg.str()); - return false; - } - - // TODO extra checks - - return self.paramsValue(param_id, value); - } - - bool Plugin::clapParamsSetValue(const clap_plugin *plugin, - clap_id param_id, - clap_param_value value, - clap_param_value modulation) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_params.set_value"); - - if (self.isActive_) { - self.hostMisbehaving( - "it is forbidden to call clap_plugin_params.set_value() if the plugin is activated"); - return false; - } - - if (!self.isValidParamId(param_id)) { - std::ostringstream msg; - msg << "clap_plugin_params.set_value called with invalid param_id: " << param_id; - self.hostMisbehaving(msg.str()); - return false; - } - - // TODO: extra checks - - return self.paramsSetValue(param_id, value, modulation); - } - - bool Plugin::clapParamsValueToText(const clap_plugin *plugin, - clap_id param_id, - clap_param_value value, - char *display, - uint32_t size) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_params.value_to_text"); - - if (!self.isValidParamId(param_id)) { - std::ostringstream msg; - msg << "clap_plugin_params.value_to_text called with invalid param_id: " << param_id; - self.hostMisbehaving(msg.str()); - return false; - } - - // TODO: extra checks - return self.paramsValueToText(param_id, value, display, size); - } - - bool Plugin::clapParamsTextToValue(const clap_plugin *plugin, - clap_id param_id, - const char *display, - clap_param_value *value) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_params.text_to_value"); - - if (!self.isValidParamId(param_id)) { - std::ostringstream msg; - msg << "clap_plugin_params.text_to_value called with invalid param_id: " << param_id; - self.hostMisbehaving(msg.str()); - return false; - } - - // TODO: extra checks - return self.paramsTextToValue(param_id, display, value); - } - - bool Plugin::isValidParamId(clap_id param_id) const noexcept { - checkMainThread(); - - auto count = paramsCount(); - clap_param_info info; - for (uint32_t i = 0; i < count; ++i) { - if (!paramsInfo(i, &info)) - // TODO: fatal error? - continue; - - if (info.id == param_id) - return true; - } - return false; - } - - //-----------------------// - // clap_plugin_note_name // - //-----------------------// - - uint32_t Plugin::clapNoteNameCount(const clap_plugin *plugin) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_note_name.count"); - return self.noteNameCount(); - } - - bool Plugin::clapNoteNameGet(const clap_plugin *plugin, - uint32_t index, - clap_note_name *note_name) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_note_name.get"); - - // TODO check index - auto count = clapNoteNameCount(plugin); - if (index >= count) { - std::ostringstream msg; - msg << "host called clap_plugin_note_name.get with an index out of bounds: " << index - << " >= " << count; - self.hostMisbehaving(msg.str()); - return false; - } - - return self.noteNameGet(index, note_name); - } - - //------------------------// - // clap_plugin_event_loop // - //------------------------// - void Plugin::clapEventLoopOnTimer(const clap_plugin *plugin, clap_id timer_id) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_event_loop.on_timer"); - - if (timer_id == CLAP_INVALID_ID) { - self.hostMisbehaving( - "Host called clap_plugin_event_loop.on_timer with an invalid timer_id"); - return; - } - - self.eventLoopOnTimer(timer_id); - } - - void Plugin::clapEventLoopOnFd(const clap_plugin *plugin, clap_fd fd, uint32_t flags) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_event_loop.on_fd"); - - self.eventLoopOnFd(fd, flags); - } - - //-----------------// - // clap_plugin_gui // - //-----------------// - void Plugin::clapGuiSize(const clap_plugin *plugin, int32_t *width, int32_t *height) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_gui.size"); - - self.guiSize(width, height); - } - - void Plugin::clapGuiSetScale(const clap_plugin *plugin, double scale) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_gui.set_scale"); - - self.guiSetScale(scale); - } - - void Plugin::clapGuiShow(const clap_plugin *plugin) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_gui.show"); - - self.guiShow(); - } - - void Plugin::clapGuiHide(const clap_plugin *plugin) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_gui.hide"); - - self.guiHide(); - } - - void Plugin::clapGuiClose(const clap_plugin *plugin) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_gui.close"); - - self.guiClose(); - } - - //---------------------// - // clap_plugin_gui_x11 // - //---------------------// - bool Plugin::clapGuiX11Attach(const clap_plugin *plugin, - const char *display_name, - unsigned long window) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_gui_x11.attach"); - - return self.guiX11Attach(display_name, window); - } - - //-----------------------// - // clap_plugin_gui_win32 // - //-----------------------// - bool Plugin::clapGuiWin32Attach(const clap_plugin *plugin, clap_hwnd window) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_gui_win32.attach"); - - return self.guiWin32Attach(window); - } - - //-----------------------// - // clap_plugin_gui_cocoa // - //-----------------------// - bool Plugin::clapGuiCocoaAttach(const clap_plugin *plugin, void *nsView) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_gui_cocoa.attach"); - - return self.guiCocoaAttach(nsView); - } - - //-------------------------------// - // clap_plugin_gui_free_standing // - //-------------------------------// - bool Plugin::clapGuiFreeStandingOpen(const clap_plugin *plugin) noexcept { - auto &self = from(plugin); - self.ensureMainThread("clap_plugin_gui_win32.attach"); - - return self.guiFreeStandingOpen(); - } - - ///////////// - // Logging // - ///////////// - void Plugin::log(clap_log_severity severity, const char *msg) const noexcept { - if (canUseHostLog()) - hostLog_->log(host_, severity, msg); - else - std::clog << msg << std::endl; - } - - void Plugin::hostMisbehaving(const char *msg) const noexcept { - log(CLAP_LOG_HOST_MISBEHAVING, msg); - } - - ///////////////////////////////// - // Interface consistency check // - ///////////////////////////////// - - bool Plugin::canUseHostLog() const noexcept { return hostLog_ && hostLog_->log; } - - bool Plugin::canUseThreadCheck() const noexcept { - return hostThreadCheck_ && hostThreadCheck_->is_audio_thread && - hostThreadCheck_->is_main_thread; - } - - ///////////////////// - // Thread Checking // - ///////////////////// - - void Plugin::checkMainThread() const noexcept { - if (!hostThreadCheck_ || !hostThreadCheck_->is_main_thread || - hostThreadCheck_->is_main_thread(host_)) - return; - - std::terminate(); - } - - void Plugin::ensureMainThread(const char *method) const noexcept { - if (!hostThreadCheck_ || !hostThreadCheck_->is_main_thread || - hostThreadCheck_->is_main_thread(host_)) - return; - - std::ostringstream msg; - msg << "Host called the method " << method - << "() on wrong thread! It must be called on main thread!"; - hostMisbehaving(msg.str()); - std::terminate(); - } - - void Plugin::ensureAudioThread(const char *method) const noexcept { - if (!hostThreadCheck_ || !hostThreadCheck_->is_audio_thread || - hostThreadCheck_->is_audio_thread(host_)) - return; - - std::ostringstream msg; - msg << "Host called the method " << method - << "() on wrong thread! It must be called on audio thread!"; - hostMisbehaving(msg.str()); - std::terminate(); - } - - /////////////// - // Utilities // - /////////////// - Plugin &Plugin::from(const clap_plugin *plugin) noexcept { - if (!plugin) { - std::cerr << "called with a null clap_plugin pointer!" << std::endl; - std::terminate(); - } - - if (!plugin->plugin_data) { - std::cerr << "called with a null clap_plugin->plugin_data pointer! The host must never " - "change this pointer!" - << std::endl; - std::terminate(); - } - - return *static_cast<Plugin *>(plugin->plugin_data); - } - - uint32_t Plugin::compareAudioPortsInfo(const clap_audio_port_info &a, - const clap_audio_port_info &b) noexcept { - if (a.sample_size != b.sample_size || a.in_place != b.in_place || a.is_cv != b.is_cv || - a.is_main != b.is_main || a.channel_count != b.channel_count || - a.channel_map != b.channel_map || a.id != b.id) - return CLAP_AUDIO_PORTS_RESCAN_ALL; - - if (strncmp(a.name, b.name, sizeof(a.name))) - return CLAP_AUDIO_PORTS_RESCAN_NAMES; - - return 0; - } -} // namespace clap -\ No newline at end of file diff --git a/examples/plugins/plugin.hh b/examples/plugins/plugin.hh @@ -1,442 +0,0 @@ -#pragma once - -#include <cassert> -#include <string> -#include <string_view> -#include <vector> - -#include <clap/all.h> - -#include "parameters.hh" - -namespace clap { - /// @brief C++ glue and checks - /// - /// @note for an higher level implementation, see @ref PluginHelper - class Plugin { - public: - const clap_plugin *clapPlugin() noexcept { return &plugin_; } - - protected: - Plugin(const clap_plugin_descriptor *desc, const clap_host *host); - virtual ~Plugin() = default; - - // not copyable, not moveable - Plugin(const Plugin &) = delete; - Plugin(Plugin &&) = delete; - Plugin &operator=(const Plugin &) = delete; - Plugin &operator=(Plugin &&) = delete; - - ///////////////////////// - // Methods to override // - ///////////////////////// - - //-------------// - // clap_plugin // - //-------------// - virtual bool init() noexcept { return true; } - virtual bool activate(int sampleRate) noexcept { return true; } - virtual void deactivate() noexcept {} - virtual bool startProcessing() noexcept { return true; } - virtual void stopProcessing() noexcept {} - virtual clap_process_status process(const clap_process *process) noexcept { - return CLAP_PROCESS_SLEEP; - } - virtual const void *extension(const char *id) noexcept { return nullptr; } - - //---------------------// - // clap_plugin_latenxy // - //---------------------// - virtual bool implementsLatency() const noexcept { return false; } - virtual uint32_t latencyGet() const noexcept { return 0; } - - //--------------------// - // clap_plugin_render // - //--------------------// - virtual bool implementsRender() const noexcept { return false; } - virtual void renderSetMode(clap_plugin_render_mode mode) noexcept {} - - //-------------------------// - // clap_plugin_thread_pool // - //-------------------------// - virtual bool implementsThreadPool() const noexcept { return false; } - virtual void threadPoolExec(uint32_t task_index) noexcept; - - //-------------------// - // clap_plugin_state // - //-------------------// - virtual bool implementsState() const noexcept { return false; } - virtual bool stateSave(clap_ostream *stream) noexcept { return false; } - virtual bool stateLoad(clap_istream *stream) noexcept { return false; } - virtual bool stateIsDirty() const noexcept { return false; } - void stateMarkDirty() const noexcept { - if (canUseState()) - hostState_->mark_dirty(host_); - } - - //-------------------------// - // clap_plugin_preset_load // - //-------------------------// - virtual bool implementsPresetLoad() const noexcept { return false; } - virtual bool presetLoadFromFile(const char *path) noexcept { return false; } - - //------------------------// - // clap_plugin_track_info // - //------------------------// - virtual bool implementsTrackInfo() const noexcept { return false; } - virtual void trackInfoChanged() noexcept {} - - //-------------------------// - // clap_plugin_audio_ports // - //-------------------------// - virtual bool implementsAudioPorts() const noexcept { return false; } - virtual uint32_t audioPortsCount(bool is_input) const noexcept { return 0; } - virtual bool - audioPortsInfo(uint32_t index, bool is_input, clap_audio_port_info *info) const noexcept { - return false; - } - virtual uint32_t audioPortsConfigCount() const noexcept { return 0; } - virtual bool audioPortsGetConfig(uint32_t index, - clap_audio_ports_config *config) const noexcept { - return false; - } - virtual bool audioPortsSetConfig(clap_id config_id) noexcept { return false; } - - //--------------------// - // clap_plugin_params // - //--------------------// - virtual bool implementsParams() const noexcept { return false; } - virtual uint32_t paramsCount() const noexcept { return 0; } - virtual bool paramsInfo(int32_t paramIndex, clap_param_info *info) const noexcept { - return false; - } - virtual bool - paramsEnumValue(clap_id paramId, int32_t valueIndex, clap_param_value *value) noexcept { - return false; - } - virtual bool paramsValue(clap_id paramId, clap_param_value *value) noexcept { return false; } - virtual bool paramsSetValue(clap_id paramId, - clap_param_value value, - clap_param_value modulation) noexcept { - return false; - } - virtual bool paramsValueToText(clap_id paramId, - clap_param_value value, - char *display, - uint32_t size) noexcept { - return false; - } - virtual bool - paramsTextToValue(clap_id param_id, const char *display, clap_param_value *value) noexcept { - return false; - } - - //-----------------------// - // clap_plugin_note_name // - //-----------------------// - virtual bool implementsNoteName() const noexcept { return false; } - virtual int noteNameCount() noexcept { return 0; } - virtual bool noteNameGet(int index, clap_note_name *note_name) noexcept { return false; } - - //------------------------// - // clap_plugin_event_loop // - //------------------------// - virtual bool implementsEventLoop() const noexcept { return false; } - virtual void eventLoopOnTimer(clap_id timer_id) noexcept {} - virtual void eventLoopOnFd(clap_fd fd, uint32_t flags) noexcept {} - - //-----------------// - // clap_plugin_gui // - //-----------------// - virtual bool implementsGui() const noexcept { return false; } - virtual void guiSize(int32_t *width, int32_t *height) noexcept {} - virtual void guiSetScale(double scale) noexcept {} - virtual void guiShow() noexcept {} - virtual void guiHide() noexcept {} - virtual void guiClose() noexcept {} - - //---------------------// - // clap_plugin_gui_x11 // - //---------------------// - virtual bool implementsGuiX11() const noexcept { return false; } - virtual bool guiX11Attach(const char *display_name, unsigned long window) noexcept; - - //-----------------------// - // clap_plugin_gui_win32 // - //-----------------------// - virtual bool implementsGuiWin32() const noexcept { return false; } - virtual bool guiWin32Attach(clap_hwnd window) noexcept; - - //-----------------------// - // clap_plugin_gui_cocoa // - //-----------------------// - virtual bool implementsGuiCocoa() const noexcept { return false; } - virtual bool guiCocoaAttach(void *nsView) noexcept; - - //-------------------------------// - // clap_plugin_gui_free_standing // - //-------------------------------// - virtual bool implementsGuiFreeStanding() const noexcept { return false; } - virtual bool guiFreeStandingOpen() noexcept; - - ////////////////// - // Invalidation // - ////////////////// - void invalidateAudioPortsDefinition(); - - ///////////// - // Logging // - ///////////// - void log(clap_log_severity severity, const char *msg) const noexcept; - void hostMisbehaving(const char *msg) const noexcept; - void hostMisbehaving(const std::string &msg) const noexcept { hostMisbehaving(msg.c_str()); } - - ///////////////////////////////// - // Interface consistency check // - ///////////////////////////////// - bool canUseHostLog() const noexcept; - bool canUseThreadCheck() const noexcept; - bool canUseTrackInfo() const noexcept; - bool canUseState() const noexcept; - bool canChangeAudioPorts() const noexcept; - - ///////////////////// - // Thread Checking // - ///////////////////// - void checkMainThread() const noexcept; - void ensureMainThread(const char *method) const noexcept; - void ensureAudioThread(const char *method) const noexcept; - - /////////////// - // Utilities // - /////////////// - static Plugin &from(const clap_plugin *plugin) noexcept; - - template <typename T> - void initInterface(const T *&ptr, const char *id) noexcept; - void initInterfaces() noexcept; - - static uint32_t compareAudioPortsInfo(const clap_audio_port_info &a, - const clap_audio_port_info &b) noexcept; - - virtual bool isValidParamId(clap_id param_id) const noexcept; - - ////////////////////// - // Processing State // - ////////////////////// - bool isActive() const noexcept { return isActive_; } - bool isProcessing() const noexcept { return isProcessing_; } - int sampleRate() const noexcept { - assert(isActive_ && "sample rate is only known if the plugin is active"); - assert(sampleRate_ > 0); - return sampleRate_; - } - - protected: - const clap_host *const host_ = nullptr; - const clap_host_log *hostLog_ = nullptr; - const clap_host_thread_check *hostThreadCheck_ = nullptr; - const clap_host_thread_pool *hostThreadPool_ = nullptr; - const clap_host_audio_ports *hostAudioPorts_ = nullptr; - const clap_host_event_filter *hostEventFilter_ = nullptr; - const clap_host_file_reference *hostFileReference_ = nullptr; - const clap_host_latency *hostLatency_ = nullptr; - const clap_host_gui *hostGui_ = nullptr; - const clap_host_event_loop *hostEventLoop_ = nullptr; - const clap_host_params *hostParams_ = nullptr; - const clap_host_track_info *hostTrackInfo_ = nullptr; - const clap_host_state *hostState_ = nullptr; - const clap_host_note_name *hostNoteName_ = nullptr; - - private: - ///////////////////// - // CLAP Interfaces // - ///////////////////// - - clap_plugin plugin_; - // clap_plugin - static bool clapInit(const clap_plugin *plugin) noexcept; - static void clapDestroy(const clap_plugin *plugin) noexcept; - static bool clapActivate(const clap_plugin *plugin, int sample_rate) noexcept; - static void clapDeactivate(const clap_plugin *plugin) noexcept; - static bool clapStartProcessing(const clap_plugin *plugin) noexcept; - static void clapStopProcessing(const clap_plugin *plugin) noexcept; - static clap_process_status clapProcess(const clap_plugin *plugin, - const clap_process *process) noexcept; - static const void *clapExtension(const clap_plugin *plugin, const char *id) noexcept; - - // latency - static uint32_t clapLatencyGet(const clap_plugin *plugin) noexcept; - - // clap_plugin_render - static void clapRenderSetMode(const clap_plugin *plugin, - clap_plugin_render_mode mode) noexcept; - - // clap_plugin_thread_pool - static void clapThreadPoolExec(const clap_plugin *plugin, uint32_t task_index) noexcept; - - // clap_plugin_state - static bool clapStateSave(const clap_plugin *plugin, clap_ostream *stream) noexcept; - static bool clapStateLoad(const clap_plugin *plugin, clap_istream *stream) noexcept; - static bool clapStateIsDirty(const clap_plugin *plugin) noexcept; - - // clap_plugin_preset - static bool clapPresetLoadFromFile(const clap_plugin *plugin, const char *path) noexcept; - - // clap_plugin_track_info - static void clapTrackInfoChanged(const clap_plugin *plugin) noexcept; - - // clap_plugin_audio_ports - static uint32_t clapAudioPortsCount(const clap_plugin *plugin, bool is_input) noexcept; - static bool clapAudioPortsInfo(const clap_plugin *plugin, - uint32_t index, - bool is_input, - clap_audio_port_info *info) noexcept; - static uint32_t clapAudioPortsConfigCount(const clap_plugin *plugin) noexcept; - static bool clapAudioPortsGetConfig(const clap_plugin *plugin, - uint32_t index, - clap_audio_ports_config *config) noexcept; - static bool clapAudioPortsSetConfig(const clap_plugin *plugin, clap_id config_id) noexcept; - - // clap_plugin_params - static uint32_t clapParamsCount(const clap_plugin *plugin) noexcept; - static bool clapParamsIinfo(const clap_plugin *plugin, - int32_t param_index, - clap_param_info *param_info) noexcept; - static bool clapParamsEnumValue(const clap_plugin *plugin, - clap_id param_id, - int32_t value_index, - clap_param_value *value) noexcept; - static bool clapParamsValue(const clap_plugin *plugin, - clap_id param_id, - clap_param_value *value) noexcept; - static bool clapParamsSetValue(const clap_plugin *plugin, - clap_id param_id, - clap_param_value value, - clap_param_value modulation) noexcept; - static bool clapParamsValueToText(const clap_plugin *plugin, - clap_id param_id, - clap_param_value value, - char *display, - uint32_t size) noexcept; - static bool clapParamsTextToValue(const clap_plugin *plugin, - clap_id param_id, - const char *display, - clap_param_value *value) noexcept; - - // clap_plugin_note_name - static uint32_t clapNoteNameCount(const clap_plugin *plugin) noexcept; - static bool clapNoteNameGet(const clap_plugin *plugin, - uint32_t index, - clap_note_name *note_name) noexcept; - - // clap_plugin_event_loop - static void clapEventLoopOnTimer(const clap_plugin *plugin, clap_id timer_id) noexcept; - static void clapEventLoopOnFd(const clap_plugin *plugin, clap_fd fd, uint32_t flags) noexcept; - - // clap_plugin_gui - static void clapGuiSize(const clap_plugin *plugin, int32_t *width, int32_t *height) noexcept; - static void clapGuiSetScale(const clap_plugin *plugin, double scale) noexcept; - static void clapGuiShow(const clap_plugin *plugin) noexcept; - static void clapGuiHide(const clap_plugin *plugin) noexcept; - static void clapGuiClose(const clap_plugin *plugin) noexcept; - - // clap_plugin_gui_x11 - static bool clapGuiX11Attach(const clap_plugin *plugin, - const char *display_name, - unsigned long window) noexcept; - - // clap_plugin_gui_win32 - static bool clapGuiWin32Attach(const clap_plugin *plugin, clap_hwnd window) noexcept; - - // clap_plugin_gui_cocoa - static bool clapGuiCocoaAttach(const clap_plugin *plugin, void *nsView) noexcept; - - // clap_plugin_gui_free_standing - static bool clapGuiFreeStandingOpen(const clap_plugin *plugin) noexcept; - - // interfaces - static const constexpr clap_plugin_render pluginRender_ = { - clapRenderSetMode, - }; - - static const constexpr clap_plugin_thread_pool pluginThreadPool_ = { - clapThreadPoolExec, - }; - - static const constexpr clap_plugin_state pluginState_ = { - clapStateSave, - clapStateLoad, - clapStateIsDirty, - }; - - static const constexpr clap_plugin_preset_load pluginPresetLoad_ = { - clapPresetLoadFromFile, - }; - - static const constexpr clap_plugin_track_info pluginTrackInfo_ = { - clapTrackInfoChanged, - }; - - static const constexpr clap_plugin_audio_ports pluginAudioPorts_ = { - clapAudioPortsCount, - clapAudioPortsInfo, - clapAudioPortsConfigCount, - clapAudioPortsGetConfig, - clapAudioPortsSetConfig, - }; - - static const constexpr clap_plugin_params pluginParams_ = { - clapParamsCount, - clapParamsIinfo, - clapParamsEnumValue, - clapParamsValue, - clapParamsSetValue, - clapParamsValueToText, - clapParamsTextToValue, - }; - - static const constexpr clap_plugin_latency pluginLatency_ = { - clapLatencyGet, - }; - - static const constexpr clap_plugin_note_name pluginNoteName_ = { - clapNoteNameCount, - clapNoteNameGet, - }; - - static const constexpr clap_plugin_event_loop pluginEventLoop_ = { - clapEventLoopOnTimer, - clapEventLoopOnFd, - }; - - static const constexpr clap_plugin_gui pluginGui_ = { - clapGuiSize, - clapGuiSetScale, - clapGuiShow, - clapGuiHide, - clapGuiClose, - }; - - static const constexpr clap_plugin_gui_x11 pluginGuiX11_ = { - clapGuiX11Attach, - }; - - static const constexpr clap_plugin_gui_win32 pluginGuiWin32_ = { - clapGuiWin32Attach, - }; - - static const constexpr clap_plugin_gui_cocoa pluginGuiCocoa_ = { - clapGuiCocoaAttach, - }; - - static const constexpr clap_plugin_gui_free_standing pluginGuiFreeStanding_ = { - clapGuiFreeStandingOpen, - }; - - // state - bool isActive_ = false; - bool isProcessing_ = false; - int sampleRate_ = 0; - }; -} // namespace clap -\ No newline at end of file