435 lines
19 KiB
C++
435 lines
19 KiB
C++
|
#pragma once
|
||
|
|
||
|
#include <cassert>
|
||
|
#include <functional>
|
||
|
#include <mutex>
|
||
|
#include <queue>
|
||
|
#include <string>
|
||
|
#include <string_view>
|
||
|
#include <vector>
|
||
|
|
||
|
#include <clap/clap.h>
|
||
|
|
||
|
#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 <MisbehaviourHandler h, CheckingLevel l>
|
||
|
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<void()> callback);
|
||
|
|
||
|
// This actually runs callbacks on the main thread, you should not need to call it
|
||
|
void runCallbacksOnMainThread();
|
||
|
|
||
|
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;
|
||
|
|
||
|
//////////////////////
|
||
|
// 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<h, l> _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<std::function<void()>> _mainThredCallbacks;
|
||
|
};
|
||
|
}} // namespace clap::helpers
|