#pragma once #include #include #include #include #include #include #include #include #include "checking-level.hh" #include "host-proxy.hh" #include "misbehaviour-handler.hh" namespace clap { namespace helpers { /// @brief C++ glue and checks /// /// @note for an higher level implementation, see @ref PluginHelper template 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(double sampleRate, uint32_t minFrameCount, uint32_t maxFrameCount) 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 void reset() noexcept {} virtual void onMainThread() noexcept {} virtual const void *extension(const char *id) noexcept { return nullptr; } //---------------------// // clap_plugin_latency // //---------------------// virtual bool implementsLatency() const noexcept { return false; } virtual uint32_t latencyGet() const noexcept { return 0; } //------------------// // clap_plugin_tail // //------------------// virtual bool implementsTail() const noexcept { return false; } virtual uint32_t tailGet(const clap_plugin_t *plugin) const noexcept { return 0; } //--------------------// // clap_plugin_render // //--------------------// virtual bool implementsRender() const noexcept { return false; } virtual bool renderHasHardRealtimeRequirement() noexcept { return false; } virtual bool renderSetMode(clap_plugin_render_mode mode) noexcept { return false; } //-------------------------// // clap_plugin_thread_pool // //-------------------------// virtual bool implementsThreadPool() const noexcept { return false; } virtual void threadPoolExec(uint32_t taskIndex) noexcept {} //-------------------// // clap_plugin_state // //-------------------// virtual bool implementsState() const noexcept { return false; } virtual bool stateSave(const clap_ostream *stream) noexcept { return false; } virtual bool stateLoad(const clap_istream *stream) noexcept { return false; } //-------------------------// // 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 isInput) const noexcept { return 0; } virtual bool audioPortsInfo(uint32_t index, bool isInput, 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 configId) noexcept { return false; } //--------------------// // clap_plugin_params // //--------------------// virtual bool implementsParams() const noexcept { return false; } virtual uint32_t paramsCount() const noexcept { return 0; } virtual bool paramsInfo(uint32_t paramIndex, clap_param_info *info) const noexcept { return false; } virtual bool paramsValue(clap_id paramId, double *value) noexcept { return false; } virtual bool paramsValueToText(clap_id paramId, double value, char *display, uint32_t size) noexcept { return false; } virtual bool paramsTextToValue(clap_id paramId, const char *display, double *value) noexcept { return false; } virtual void paramsFlush(const clap_input_events *in, const clap_output_events *out) noexcept {} virtual bool isValidParamId(clap_id paramId) const noexcept; //----------------------------// // clap_plugin_quick_controls // //----------------------------// virtual bool implementQuickControls() const noexcept { return false; } virtual uint32_t quickControlsPageCount() noexcept { return 0; } virtual bool quickControlsPageGet(uint32_t pageIndex, clap_quick_controls_page *page) noexcept { return false; } virtual void quickControlsSelectPage(clap_id pageId) noexcept {} virtual clap_id quickControlsSelectedPage() noexcept { return CLAP_INVALID_ID; } //------------------------// // clap_plugin_note_ports // //------------------------// virtual bool implementsNotePorts() const noexcept { return false; } virtual uint32_t notePortsCount(bool isInput) const noexcept { return 0; } virtual bool notePortsInfo(uint32_t index, bool isInput, clap_note_port_info *info) const 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 *noteName) noexcept { return false; } //---------------------------// // clap_plugin_timer_support // //---------------------------// virtual bool implementsTimerSupport() const noexcept { return false; } virtual void onTimer(clap_id timerId) noexcept {} //------------------------------// // clap_plugin_posix_fd_support // //------------------------------// virtual bool implementsPosixFdSupport() const noexcept { return false; } virtual void onPosixFd(int fd, int flags) noexcept {} //-----------------// // clap_plugin_gui // //-----------------// virtual bool implementsGui() const noexcept { return false; } virtual bool guiIsApiSupported(const char *api, bool isFloating) noexcept { return false; } virtual bool guiGetPreferredApi(const char **api, bool *is_floating) noexcept { return false; } virtual bool guiCreate(const char *api, bool isFloating) noexcept { return false; } virtual void guiDestroy() noexcept {} virtual bool guiSetScale(double scale) noexcept { return false; } virtual bool guiShow() noexcept { return false; } virtual bool guiHide() noexcept { return false; } virtual bool guiGetSize(uint32_t *width, uint32_t *height) noexcept { return false; } virtual bool guiCanResize() const noexcept { return false; } virtual bool guiGetResizeHints(clap_gui_resize_hints_t *hints) noexcept { return false; } virtual bool guiAdjustSize(uint32_t *width, uint32_t *height) noexcept { return guiGetSize(width, height); } virtual bool guiSetSize(uint32_t width, uint32_t height) noexcept { return false; } virtual void guiSuggestTitle(const char *title) noexcept {} virtual bool guiSetParent(const clap_window *window) noexcept { return false; } virtual bool guiSetTransient(const clap_window *window) noexcept { return false; } //------------------------// // clap_plugin_voice_info // //------------------------// virtual bool implementsVoiceInfo() const noexcept { return false; } virtual bool voiceInfoGet(clap_voice_info *info) noexcept { return false; } ///////////// // 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()); } // Receives a copy of all the logging messages sent to the host. // This is useful to have the messages in both the host's logs and the plugin's logs. virtual void logTee(clap_log_severity severity, const char *msg) const noexcept {} ///////////////////// // Thread Checking // ///////////////////// void checkMainThread() const noexcept; void checkAudioThread() const noexcept; void checkParamThread() const noexcept; void ensureMainThread(const char *method) const noexcept; void ensureAudioThread(const char *method) const noexcept; void ensureParamThread(const char *method) const noexcept; /////////////// // Utilities // /////////////// static Plugin &from(const clap_plugin *plugin, bool requireInitialized = true) noexcept; // runs the callback immediately if on the main thread, otherwise queue it. // be aware that the callback may be ran during the plugin destruction phase, // so check isBeingDestroyed() and ajust your code. void runOnMainThread(std::function callback); // This actually runs callbacks on the main thread, you should not need to call it void runCallbacksOnMainThread(); template 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; ////////////////////// // 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; } bool isBeingDestroyed() const noexcept { return _isBeingDestroyed; } protected: HostProxy _host; 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, double sample_rate, uint32_t minFrameCount, uint32_t maxFrameCount) 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 void clapReset(const clap_plugin *plugin) noexcept; static clap_process_status clapProcess(const clap_plugin *plugin, const clap_process *process) noexcept; static void clapOnMainThread(const clap_plugin *plugin) 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_tail static uint32_t clapTailGet(const clap_plugin_t *plugin) noexcept; // clap_plugin_render static bool clapRenderHasHardRealtimeRequirement(const clap_plugin_t *plugin) noexcept; static bool 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, const clap_ostream *stream) noexcept; static bool clapStateLoad(const clap_plugin *plugin, const clap_istream *stream) 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 clapParamsInfo(const clap_plugin *plugin, uint32_t param_index, clap_param_info *param_info) noexcept; static bool clapParamsValue(const clap_plugin *plugin, clap_id param_id, double *value) noexcept; static bool clapParamsValueToText(const clap_plugin *plugin, clap_id param_id, double value, char *display, uint32_t size) noexcept; static bool clapParamsTextToValue(const clap_plugin *plugin, clap_id param_id, const char *display, double *value) noexcept; static void clapParamsFlush(const clap_plugin *plugin, const clap_input_events *in, const clap_output_events *out) noexcept; // clap_plugin_quick_controls static uint32_t clapQuickControlsPageCount(const clap_plugin *plugin) noexcept; static bool clapQuickControlsPageGet(const clap_plugin *plugin, uint32_t page_index, clap_quick_controls_page *page) noexcept; // clap_plugin_note_port static uint32_t clapNotePortsCount(const clap_plugin *plugin, bool is_input) noexcept; static bool clapNotePortsInfo(const clap_plugin *plugin, uint32_t index, bool is_input, clap_note_port_info *info) 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_timer_support static void clapOnTimer(const clap_plugin *plugin, clap_id timer_id) noexcept; // clap_plugin_fd_support static void clapOnPosixFd(const clap_plugin *plugin, int fd, clap_posix_fd_flags_t flags) noexcept; // clap_plugin_gui static bool clapGuiIsApiSupported(const clap_plugin *plugin, const char *api, bool isFloating) noexcept; static bool clapGuiGetPreferredApi(const clap_plugin_t *plugin, const char **api, bool *is_floating) noexcept; static bool clapGuiCreate(const clap_plugin *plugin, const char *api, bool isFloating) noexcept; static void clapGuiDestroy(const clap_plugin *plugin) noexcept; static bool clapGuiSetScale(const clap_plugin *plugin, double scale) noexcept; static bool clapGuiGetSize(const clap_plugin *plugin, uint32_t *width, uint32_t *height) noexcept; static bool clapGuiSetSize(const clap_plugin *plugin, uint32_t width, uint32_t height) noexcept; static bool clapGuiCanResize(const clap_plugin *plugin) noexcept; static bool clapGuiGetResizeHints(const clap_plugin_t *plugin, clap_gui_resize_hints_t *hints) noexcept; static bool clapGuiAdjustSize(const clap_plugin *plugin, uint32_t *width, uint32_t *height) noexcept; static bool clapGuiShow(const clap_plugin *plugin) noexcept; static bool clapGuiHide(const clap_plugin *plugin) noexcept; static bool clapGuiSetParent(const clap_plugin *plugin, const clap_window *window) noexcept; static bool clapGuiSetTransient(const clap_plugin *plugin, const clap_window *window) noexcept; static void clapGuiSuggestTitle(const clap_plugin *plugin, const char *title) noexcept; static bool clapVoiceInfoGet(const clap_plugin *plugin, clap_voice_info *info) noexcept; // interfaces static const clap_plugin_render _pluginRender; static const clap_plugin_thread_pool _pluginThreadPool; static const clap_plugin_state _pluginState; static const clap_plugin_preset_load _pluginPresetLoad; static const clap_plugin_track_info _pluginTrackInfo; static const clap_plugin_audio_ports _pluginAudioPorts; static const clap_plugin_audio_ports_config _pluginAudioPortsConfig; static const clap_plugin_params _pluginParams; static const clap_plugin_quick_controls _pluginQuickControls; static const clap_plugin_latency _pluginLatency; static const clap_plugin_note_ports _pluginNotePorts; static const clap_plugin_note_name _pluginNoteName; static const clap_plugin_timer_support _pluginTimerSupport; static const clap_plugin_posix_fd_support _pluginPosixFdSupport; static const clap_plugin_gui _pluginGui; static const clap_plugin_voice_info _pluginVoiceInfo; static const clap_plugin_tail _pluginTail; // state bool _wasInitialized = false; bool _isActive = false; bool _isProcessing = false; bool _isBeingDestroyed = false; double _sampleRate = 0; std::string _guiApi; bool _isGuiCreated = false; bool _isGuiFloating = false; bool _isGuiEmbedded = false; std::mutex _mainThredCallbacksLock; std::queue> _mainThredCallbacks; }; }} // namespace clap::helpers