/* * Carla Plugin * Copyright (C) 2011-2019 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * For a full copy of the GNU General Public License see the doc/GPL.txt file. */ #ifndef CARLA_PLUGIN_INTERNAL_HPP_INCLUDED #define CARLA_PLUGIN_INTERNAL_HPP_INCLUDED #include "CarlaPlugin.hpp" #include "CarlaJuceUtils.hpp" #include "CarlaLibUtils.hpp" #include "CarlaStateUtils.hpp" #include "CarlaMIDI.h" #include "CarlaMutex.hpp" #include "CarlaString.hpp" #include "RtLinkedList.hpp" CARLA_BACKEND_START_NAMESPACE // ----------------------------------------------------------------------- // Engine helper macro, sets lastError and returns false/NULL #define CARLA_SAFE_ASSERT_RETURN_ERR(cond, err) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); pData->engine->setLastError(err); return false; } #define CARLA_SAFE_ASSERT_RETURN_ERRN(cond, err) if (! (cond)) { carla_safe_assert(#cond, __FILE__, __LINE__); pData->engine->setLastError(err); return nullptr; } #define CARLA_SAFE_EXCEPTION_RETURN_ERR(excptMsg, errMsg) catch(...) { carla_safe_exception(excptMsg, __FILE__, __LINE__); pData->engine->setLastError(errMsg); return false; } #define CARLA_SAFE_EXCEPTION_RETURN_ERRN(excptMsg, errMsg) catch(...) { carla_safe_exception(excptMsg, __FILE__, __LINE__); pData->engine->setLastError(errMsg); return nullptr; } // ----------------------------------------------------------------------- // Maximum pre-allocated events for some plugin types const ushort kPluginMaxMidiEvents = 512; // ----------------------------------------------------------------------- // Extra parameter hints, hidden from backend const uint PARAMETER_MAPPED_RANGES_SET = 0x10000; const uint PARAMETER_IS_STRICT_BOUNDS = 0x20000; const uint PARAMETER_IS_TRIGGER = 0x40000; // ----------------------------------------------------------------------- // Extra plugin hints, hidden from backend const uint PLUGIN_EXTRA_HINT_HAS_MIDI_IN = 0x01; const uint PLUGIN_EXTRA_HINT_HAS_MIDI_OUT = 0x02; // ----------------------------------------------------------------------- // Special parameters enum SpecialParameterType { PARAMETER_SPECIAL_NULL = 0, PARAMETER_SPECIAL_FREEWHEEL = 1, PARAMETER_SPECIAL_LATENCY = 2, PARAMETER_SPECIAL_SAMPLE_RATE = 3, PARAMETER_SPECIAL_TIME = 4 }; // ----------------------------------------------------------------------- /*! * Post-RT event type. * These are events postponned from within the process function, * * During process, we cannot lock, allocate memory or do UI stuff. * Events have to be postponned to be executed later, on a separate thread. * @see PluginPostRtEvent */ enum PluginPostRtEventType { kPluginPostRtEventNull = 0, kPluginPostRtEventParameterChange, kPluginPostRtEventProgramChange, kPluginPostRtEventMidiProgramChange, kPluginPostRtEventNoteOn, kPluginPostRtEventNoteOff, kPluginPostRtEventMidiLearn }; /*! * A Post-RT event. * @see PluginPostRtEventType */ struct PluginPostRtEvent { PluginPostRtEventType type; bool sendCallback; union { struct { int32_t index; float value; } parameter; struct { uint32_t index; } program; struct { uint8_t channel; uint8_t note; uint8_t velocity; } note; struct { uint32_t parameter; uint8_t cc; uint8_t channel; } midiLearn; }; }; // ----------------------------------------------------------------------- struct ExternalMidiNote { int8_t channel; // invalid if -1 uint8_t note; // 0 to 127 uint8_t velo; // 1 to 127, 0 for note-off }; // ----------------------------------------------------------------------- struct PluginAudioPort { uint32_t rindex; CarlaEngineAudioPort* port; }; struct PluginAudioData { uint32_t count; PluginAudioPort* ports; PluginAudioData() noexcept; ~PluginAudioData() noexcept; void createNew(uint32_t newCount); void clear() noexcept; void initBuffers() const noexcept; CARLA_DECLARE_NON_COPY_STRUCT(PluginAudioData) }; // ----------------------------------------------------------------------- struct PluginCVPort { uint32_t rindex; //uint32_t param; // FIXME is this needed? CarlaEngineCVPort* port; }; struct PluginCVData { uint32_t count; PluginCVPort* ports; PluginCVData() noexcept; ~PluginCVData() noexcept; void createNew(uint32_t newCount); void clear() noexcept; void initBuffers() const noexcept; CARLA_DECLARE_NON_COPY_STRUCT(PluginCVData) }; // ----------------------------------------------------------------------- struct PluginEventData { CarlaEngineEventPort* portIn; CarlaEngineEventPort* portOut; #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH CarlaEngineCVSourcePorts* cvSourcePorts; #endif PluginEventData() noexcept; ~PluginEventData() noexcept; void clear() noexcept; void initBuffers() const noexcept; CARLA_DECLARE_NON_COPY_STRUCT(PluginEventData) }; // ----------------------------------------------------------------------- struct PluginParameterData { uint32_t count; ParameterData* data; ParameterRanges* ranges; SpecialParameterType* special; PluginParameterData() noexcept; ~PluginParameterData() noexcept; void createNew(uint32_t newCount, bool withSpecial); void clear() noexcept; float getFixedValue(uint32_t parameterId, float value) const noexcept; float getFinalUnnormalizedValue(uint32_t parameterId, float normalizedValue) const noexcept; float getFinalValueWithMidiDelta(uint32_t parameterId, float value, int8_t delta) const noexcept; CARLA_DECLARE_NON_COPY_STRUCT(PluginParameterData) }; // ----------------------------------------------------------------------- typedef const char* ProgramName; struct PluginProgramData { uint32_t count; int32_t current; ProgramName* names; PluginProgramData() noexcept; ~PluginProgramData() noexcept; void createNew(uint32_t newCount); void clear() noexcept; CARLA_DECLARE_NON_COPY_STRUCT(PluginProgramData) }; // ----------------------------------------------------------------------- struct PluginMidiProgramData { uint32_t count; int32_t current; MidiProgramData* data; PluginMidiProgramData() noexcept; ~PluginMidiProgramData() noexcept; void createNew(uint32_t newCount); void clear() noexcept; const MidiProgramData& getCurrent() const noexcept; CARLA_DECLARE_NON_COPY_STRUCT(PluginMidiProgramData) }; // ----------------------------------------------------------------------- struct CarlaPlugin::ProtectedData { CarlaEngine* const engine; CarlaEngineClient* client; uint id; uint hints; uint options; uint32_t nodeId; bool active; bool enabled; bool needsReset; bool engineBridged; bool enginePlugin; lib_t lib; lib_t uiLib; // misc int8_t ctrlChannel; uint extraHints; #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH int32_t midiLearnParameterIndex; uint transientTryCounter; bool transientFirstTry; #endif // data 1 const char* name; const char* filename; const char* iconName; // data 2 PluginAudioData audioIn; PluginAudioData audioOut; PluginCVData cvIn; PluginCVData cvOut; PluginEventData event; PluginParameterData param; PluginProgramData prog; PluginMidiProgramData midiprog; LinkedList custom; CarlaMutex masterMutex; // global master lock CarlaMutex singleMutex; // small lock used only in processSingle() CarlaStateSave stateSave; CarlaString uiTitle; struct ExternalNotes { CarlaMutex mutex; RtLinkedList::Pool dataPool; RtLinkedList data; ExternalNotes() noexcept; ~ExternalNotes() noexcept; void appendNonRT(const ExternalMidiNote& note) noexcept; void clear() noexcept; CARLA_DECLARE_NON_COPY_STRUCT(ExternalNotes) } extNotes; struct Latency { uint32_t frames; #ifndef BUILD_BRIDGE uint32_t channels; float** buffers; #endif Latency() noexcept; #ifndef BUILD_BRIDGE ~Latency() noexcept; void clearBuffers() noexcept; void recreateBuffers(uint32_t newChannels, uint32_t newFrames); #endif CARLA_DECLARE_NON_COPY_STRUCT(Latency) } latency; class PostRtEvents { public: PostRtEvents() noexcept; ~PostRtEvents() noexcept; void appendRT(const PluginPostRtEvent& event) noexcept; void trySplice() noexcept; struct Access { Access(PostRtEvents& e) : data2(e.dataPool) { const CarlaMutexLocker cml(e.dataMutex); if (e.data.isNotEmpty()) e.data.moveTo(data2, true); } ~Access() { data2.clear(); } inline RtLinkedList::Itenerator getDataIterator() const noexcept { return data2.begin2(); } inline std::size_t isEmpty() const noexcept { return data2.isEmpty(); } private: RtLinkedList data2; }; private: RtLinkedList::Pool dataPool; RtLinkedList data, dataPendingRT; CarlaMutex dataMutex; CarlaMutex dataPendingMutex; CARLA_DECLARE_NON_COPY_CLASS(PostRtEvents) } postRtEvents; struct PostUiEvents { CarlaMutex mutex; LinkedList data; PostUiEvents() noexcept; ~PostUiEvents() noexcept; void append(const PluginPostRtEvent& event) noexcept; void clear() noexcept; CARLA_DECLARE_NON_COPY_STRUCT(PostUiEvents) } postUiEvents; #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH struct PostProc { float dryWet; float volume; float balanceLeft; float balanceRight; float panning; PostProc() noexcept; CARLA_DECLARE_NON_COPY_STRUCT(PostProc) } postProc; #endif ProtectedData(CarlaEngine* engine, uint idx) noexcept; ~ProtectedData() noexcept; // ------------------------------------------------------------------- // Buffer functions void clearBuffers() noexcept; // ------------------------------------------------------------------- // Post-poned events void postponeRtEvent(const PluginPostRtEvent& rtEvent) noexcept; void postponeParameterChangeRtEvent(bool sendCallbackLater, int32_t index, float value) noexcept; void postponeProgramChangeRtEvent(bool sendCallbackLater, uint32_t index) noexcept; void postponeMidiProgramChangeRtEvent(bool sendCallbackLater, uint32_t index) noexcept; void postponeNoteOnRtEvent(bool sendCallbackLater, uint8_t channel, uint8_t note, uint8_t velocity) noexcept; void postponeNoteOffRtEvent(bool sendCallbackLater, uint8_t channel, uint8_t note) noexcept; void postponeMidiLearnRtEvent(bool sendCallbackLater, uint32_t parameter, uint8_t cc, uint8_t channel) noexcept; // ------------------------------------------------------------------- // Library functions static const char* libError(const char* filename) noexcept; bool libOpen(const char* filename) noexcept; bool libClose() noexcept; void setCanDeleteLib(bool canDelete) noexcept; bool uiLibOpen(const char* filename, bool canDelete) noexcept; bool uiLibClose() noexcept; template Func libSymbol(const char* symbol) const noexcept { return lib_symbol(lib, symbol); } template Func uiLibSymbol(const char* symbol) const noexcept { return lib_symbol(uiLib, symbol); } // ------------------------------------------------------------------- // Misc #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH void tryTransient() noexcept; #endif void updateParameterValues(CarlaPlugin* plugin, bool sendCallback, bool sendOsc, bool useDefault) noexcept; void updateDefaultParameterValues(CarlaPlugin* plugin) noexcept; // ------------------------------------------------------------------- #ifdef CARLA_PROPER_CPP11_SUPPORT ProtectedData() = delete; CARLA_DECLARE_NON_COPY_STRUCT(ProtectedData); #endif CARLA_LEAK_DETECTOR(ProtectedData); }; CARLA_BACKEND_END_NAMESPACE #endif // CARLA_PLUGIN_INTERNAL_HPP_INCLUDED