/* * Carla Plugin * Copyright (C) 2011-2013 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 GPL.txt file */ #ifndef __CARLA_PLUGIN_INTERNAL_HPP__ #define __CARLA_PLUGIN_INTERNAL_HPP__ #include "CarlaBackendUtils.hpp" #include "CarlaPluginThread.hpp" #include "CarlaPlugin.hpp" #include "CarlaEngine.hpp" #include "CarlaOscUtils.hpp" #include "CarlaStateUtils.hpp" #include "CarlaMutex.hpp" #include "CarlaMIDI.h" #include "RtList.hpp" #include #define CARLA_DECLARE_NON_COPY_STRUCT(structName) \ structName(structName&) = delete; \ structName(const structName&) = delete; #define CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(structName) \ CARLA_DECLARE_NON_COPY_STRUCT(structName) \ CARLA_LEAK_DETECTOR(structName) #define CARLA_PROCESS_CONTINUE_CHECK if (! fEnabled) { kData->engine->callback(CALLBACK_DEBUG, fId, 0, 0, 0.0, nullptr); return; } CARLA_BACKEND_START_NAMESPACE // ----------------------------------------------------------------------- const unsigned short MAX_RT_EVENTS = 128; const unsigned short MAX_MIDI_EVENTS = 512; const unsigned int PLUGIN_HINT_HAS_MIDI_IN = 0x1; const unsigned int PLUGIN_HINT_HAS_MIDI_OUT = 0x2; const unsigned int PLUGIN_HINT_CAN_RUN_RACK = 0x4; // ----------------------------------------------------------------------- struct PluginAudioPort { uint32_t rindex; CarlaEngineAudioPort* port; PluginAudioPort() : rindex(0), port(nullptr) {} ~PluginAudioPort() { CARLA_ASSERT(port == nullptr); } CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginAudioPort) }; struct PluginAudioData { uint32_t count; PluginAudioPort* ports; PluginAudioData() : count(0), ports(nullptr) {} ~PluginAudioData() { CARLA_ASSERT_INT(count == 0, count); CARLA_ASSERT(ports == nullptr); } void createNew(const uint32_t newCount) { CARLA_ASSERT_INT(count == 0, count); CARLA_ASSERT(ports == nullptr); CARLA_ASSERT_INT(newCount > 0, newCount); if (ports != nullptr || newCount == 0) return; ports = new PluginAudioPort[newCount]; count = newCount; } void clear() { if (ports != nullptr) { for (uint32_t i=0; i < count; i++) { if (ports[i].port != nullptr) { delete ports[i].port; ports[i].port = nullptr; } } delete[] ports; ports = nullptr; } count = 0; } void initBuffers(CarlaEngine* const engine) { for (uint32_t i=0; i < count; i++) { if (ports[i].port != nullptr) ports[i].port->initBuffer(engine); } } CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginAudioData) }; // ----------------------------------------------------------------------- struct PluginEventData { CarlaEngineEventPort* portIn; CarlaEngineEventPort* portOut; PluginEventData() : portIn(nullptr), portOut(nullptr) {} ~PluginEventData() { CARLA_ASSERT(portIn == nullptr); CARLA_ASSERT(portOut == nullptr); } void clear() { if (portIn != nullptr) { delete portIn; portIn = nullptr; } if (portOut != nullptr) { delete portOut; portOut = nullptr; } } void initBuffers(CarlaEngine* const engine) { if (portIn != nullptr) portIn->initBuffer(engine); if (portOut != nullptr) portOut->initBuffer(engine); } CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginEventData) }; // ----------------------------------------------------------------------- struct PluginParameterData { uint32_t count; ParameterData* data; ParameterRanges* ranges; PluginParameterData() : count(0), data(nullptr), ranges(nullptr) {} ~PluginParameterData() { CARLA_ASSERT_INT(count == 0, count); CARLA_ASSERT(data == nullptr); CARLA_ASSERT(ranges == nullptr); } void createNew(const uint32_t newCount) { CARLA_ASSERT_INT(count == 0, count); CARLA_ASSERT(data == nullptr); CARLA_ASSERT(ranges == nullptr); CARLA_ASSERT_INT(newCount > 0, newCount); if (data != nullptr || ranges != nullptr || newCount == 0) return; data = new ParameterData[newCount]; ranges = new ParameterRanges[newCount]; count = newCount; } void clear() { if (data != nullptr) { delete[] data; data = nullptr; } if (ranges != nullptr) { delete[] ranges; ranges = nullptr; } count = 0; } float fixValue(const uint32_t parameterId, const float& value) { CARLA_ASSERT(parameterId < count); return ranges[parameterId].fixValue(value); } CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginParameterData) }; // ----------------------------------------------------------------------- typedef const char* ProgramName; struct PluginProgramData { uint32_t count; int32_t current; ProgramName* names; PluginProgramData() : count(0), current(-1), names(nullptr) {} ~PluginProgramData() { CARLA_ASSERT_INT(count == 0, count); CARLA_ASSERT_INT(current == -1, current); CARLA_ASSERT(names == nullptr); } void createNew(const uint32_t newCount) { CARLA_ASSERT_INT(count == 0, count); CARLA_ASSERT_INT(current == -1, current); CARLA_ASSERT(names == nullptr); CARLA_ASSERT_INT(newCount > 0, newCount); if (names != nullptr || newCount == 0) return; names = new ProgramName[newCount]; count = newCount; for (uint32_t i=0; i < newCount; i++) names[i] = nullptr; } void clear() { if (names != nullptr) { for (uint32_t i=0; i < count; i++) { if (names[i] != nullptr) delete[] names[i]; } delete[] names; names = nullptr; } count = 0; current = -1; } CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginProgramData) }; // ----------------------------------------------------------------------- struct PluginMidiProgramData { uint32_t count; int32_t current; MidiProgramData* data; PluginMidiProgramData() : count(0), current(-1), data(nullptr) {} ~PluginMidiProgramData() { CARLA_ASSERT_INT(count == 0, count); CARLA_ASSERT_INT(current == -1, current); CARLA_ASSERT(data == nullptr); } void createNew(const uint32_t newCount) { CARLA_ASSERT_INT(count == 0, count); CARLA_ASSERT_INT(current == -1, current); CARLA_ASSERT(data == nullptr); CARLA_ASSERT_INT(newCount > 0, newCount); if (data != nullptr || newCount == 0) return; data = new MidiProgramData[newCount]; count = newCount; } void clear() { if (data != nullptr) { delete[] data; data = nullptr; } count = 0; current = -1; } const MidiProgramData& getCurrent() const { CARLA_ASSERT(current >= 0 && current < static_cast(count)); return data[current]; } CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginMidiProgramData) }; // ----------------------------------------------------------------------- struct PluginPostRtEvent { PluginPostRtEventType type; int32_t value1; int32_t value2; float value3; PluginPostRtEvent() : type(kPluginPostRtEventNull), value1(-1), value2(-1), value3(0.0f) {} #if 1//def DEBUG CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginPostRtEvent) #else CARLA_DECLARE_NON_COPY_STRUCT(PluginPostRtEvent) #endif }; // ----------------------------------------------------------------------- struct ExternalMidiNote { int8_t channel; // invalid = -1 uint8_t note; uint8_t velo; ExternalMidiNote() : channel(-1), note(0), velo(0) {} #if 1//def DEBUG CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(ExternalMidiNote) #else CARLA_DECLARE_NON_COPY_STRUCT(ExternalMidiNote) #endif }; // ----------------------------------------------------------------------- enum CarlaPluginGuiType { PLUGIN_GUI_NULL, PLUGIN_GUI_PARENT, PLUGIN_GUI_QT }; class CarlaPluginGUI : public QMainWindow { public: class Callback { public: virtual ~Callback() {} virtual void guiClosedCallback() = 0; }; CarlaPluginGUI(QWidget* const parent, Callback* const callback); ~CarlaPluginGUI(); void idle(); void resizeLater(int width, int height); // Parent UIs void* getContainerWinId(); void closeContainer(); // Qt4 UIs, TODO protected: void closeEvent(QCloseEvent* const event); private: Callback* const kCallback; QWidget* fContainer; int fNextWidth; int fNextHeight; CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginGUI) }; // ----------------------------------------------------------------------- // Engine Helpers, defined in CarlaEngine.cpp extern ::QMainWindow* getEngineHostWindow(CarlaEngine* const engine); // ----------------------------------------------------------------------- struct CarlaPluginProtectedData { CarlaEngine* const engine; CarlaEngineClient* client; CarlaPluginGUI* gui; bool active; bool activeBefore; bool needsReset; void* lib; // misc int8_t ctrlChannel; unsigned int extraHints; // latency uint32_t latency; float** latencyBuffers; // data PluginAudioData audioIn; PluginAudioData audioOut; PluginEventData event; PluginParameterData param; PluginProgramData prog; PluginMidiProgramData midiprog; NonRtList custom; CarlaMutex masterMutex; // global master lock CarlaMutex singleMutex; // small lock used only in processSingle() struct ExternalNotes { CarlaMutex mutex; RtList::Pool dataPool; RtList data; ExternalNotes() : dataPool(32, 152), data(&dataPool) {} ~ExternalNotes() { mutex.lock(); data.clear(); mutex.unlock(); } void append(const ExternalMidiNote& note) { mutex.lock(); data.append_sleepy(note); mutex.unlock(); } ExternalNotes(ExternalNotes&) = delete; ExternalNotes(const ExternalNotes&) = delete; } extNotes; struct PostRtEvents { CarlaMutex mutex; RtList::Pool dataPool; RtList data; RtList dataPendingRT; PostRtEvents() : dataPool(MAX_RT_EVENTS, MAX_RT_EVENTS), data(&dataPool), dataPendingRT(&dataPool) {} ~PostRtEvents() { clear(); } void appendRT(const PluginPostRtEvent& event) { dataPendingRT.append(event); } void trySplice() { if (mutex.tryLock()) { dataPendingRT.spliceAppend(data, true); mutex.unlock(); } } void clear() { mutex.lock(); data.clear(); dataPendingRT.clear(); mutex.unlock(); } PostRtEvents(PostRtEvents&) = delete; PostRtEvents(const PostRtEvents&) = delete; } postRtEvents; struct PostProc { float dryWet; float volume; float balanceLeft; float balanceRight; float panning; PostProc() : dryWet(1.0f), volume(1.0f), balanceLeft(-1.0f), balanceRight(1.0f), panning(0.0f) {} PostProc(PostProc&) = delete; PostProc(const PostProc&) = delete; } postProc; struct OSC { CarlaOscData data; CarlaPluginThread thread; OSC(CarlaEngine* const engine, CarlaPlugin* const plugin) : thread(engine, plugin) {} OSC() = delete; OSC(OSC&) = delete; OSC(const OSC&) = delete; } osc; CarlaPluginProtectedData(CarlaEngine* const engine_, CarlaPlugin* const plugin) : engine(engine_), client(nullptr), gui(nullptr), active(false), activeBefore(false), needsReset(false), lib(nullptr), ctrlChannel(0), extraHints(0x0), latency(0), latencyBuffers(nullptr), osc(engine, plugin) {} CarlaPluginProtectedData() = delete; CarlaPluginProtectedData(CarlaPluginProtectedData&) = delete; CarlaPluginProtectedData(const CarlaPluginProtectedData&) = delete; void createUiIfNeeded(CarlaPluginGUI::Callback* const callback) { if (gui != nullptr) return; gui = new CarlaPluginGUI(getEngineHostWindow(engine), callback); } void destroyUiIfNeeded() { if (gui == nullptr) return; gui->close(); delete gui; gui = nullptr; } void resizeUiLater(int width, int height) { if (gui == nullptr) return; gui->resizeLater(width, height); } static CarlaEngine* getEngine(CarlaPlugin* const plugin) { return plugin->kData->engine; } static CarlaEngineAudioPort* getAudioInPort(CarlaPlugin* const plugin, const uint32_t index) { return plugin->kData->audioIn.ports[index].port; } static CarlaEngineAudioPort* getAudioOutPort(CarlaPlugin* const plugin, const uint32_t index) { return plugin->kData->audioOut.ports[index].port; } static bool canRunInRack(CarlaPlugin* const plugin) { return (plugin->kData->extraHints & PLUGIN_HINT_CAN_RUN_RACK); } CARLA_LEAK_DETECTOR(CarlaPluginProtectedData) }; // ----------------------------------------------------------------------- CARLA_BACKEND_END_NAMESPACE #endif // __CARLA_PLUGIN_INTERNAL_HPP__