/* * Carla Bridge utils * Copyright (C) 2013-2022 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_BRIDGE_UTILS_HPP_INCLUDED #define CARLA_BRIDGE_UTILS_HPP_INCLUDED #include "CarlaBridgeDefines.hpp" #include "CarlaMutex.hpp" #include "CarlaRingBuffer.hpp" #include "CarlaString.hpp" // ------------------------------------------------------------------------------------------------------------------- static inline const char* PluginBridgeRtClientOpcode2str(const PluginBridgeRtClientOpcode opcode) noexcept { switch (opcode) { case kPluginBridgeRtClientNull: return "kPluginBridgeRtClientNull"; case kPluginBridgeRtClientSetAudioPool: return "kPluginBridgeRtClientSetAudioPool"; case kPluginBridgeRtClientSetBufferSize: return "kPluginBridgeRtClientSetBufferSize"; case kPluginBridgeRtClientSetSampleRate: return "kPluginBridgeRtClientSetSampleRate"; case kPluginBridgeRtClientSetOnline: return "kPluginBridgeRtClientSetOnline"; case kPluginBridgeRtClientControlEventParameter: return "kPluginBridgeRtClientControlEventParameter"; case kPluginBridgeRtClientControlEventMidiBank: return "kPluginBridgeRtClientControlEventMidiBank"; case kPluginBridgeRtClientControlEventMidiProgram: return "kPluginBridgeRtClientControlEventMidiProgram"; case kPluginBridgeRtClientControlEventAllSoundOff: return "kPluginBridgeRtClientControlEventAllSoundOff"; case kPluginBridgeRtClientControlEventAllNotesOff: return "kPluginBridgeRtClientControlEventAllNotesOff"; case kPluginBridgeRtClientMidiEvent: return "kPluginBridgeRtClientMidiEvent"; case kPluginBridgeRtClientProcess: return "kPluginBridgeRtClientProcess"; case kPluginBridgeRtClientQuit: return "kPluginBridgeRtClientQuit"; } carla_stderr("CarlaBackend::PluginBridgeRtClientOpcode2str(%i) - invalid opcode", opcode); return ""; } static inline const char* PluginBridgeNonRtClientOpcode2str(const PluginBridgeNonRtClientOpcode opcode) noexcept { switch (opcode) { case kPluginBridgeNonRtClientNull: return "kPluginBridgeNonRtClientNull"; case kPluginBridgeNonRtClientVersion: return "kPluginBridgeNonRtClientVersion"; case kPluginBridgeNonRtClientPing: return "kPluginBridgeNonRtClientPing"; case kPluginBridgeNonRtClientPingOnOff: return "kPluginBridgeNonRtClientPingOnOff"; case kPluginBridgeNonRtClientActivate: return "kPluginBridgeNonRtClientActivate"; case kPluginBridgeNonRtClientDeactivate: return "kPluginBridgeNonRtClientDeactivate"; case kPluginBridgeNonRtClientInitialSetup: return "kPluginBridgeNonRtClientInitialSetup"; case kPluginBridgeNonRtClientSetParameterValue: return "kPluginBridgeNonRtClientSetParameterValue"; case kPluginBridgeNonRtClientSetParameterMidiChannel: return "kPluginBridgeNonRtClientSetParameterMidiChannel"; case kPluginBridgeNonRtClientSetParameterMappedControlIndex: return "kPluginBridgeNonRtClientSetParameterMappedControlIndex"; case kPluginBridgeNonRtClientSetProgram: return "kPluginBridgeNonRtClientSetProgram"; case kPluginBridgeNonRtClientSetMidiProgram: return "kPluginBridgeNonRtClientSetMidiProgram"; case kPluginBridgeNonRtClientSetCustomData: return "kPluginBridgeNonRtClientSetCustomData"; case kPluginBridgeNonRtClientSetChunkDataFile: return "kPluginBridgeNonRtClientSetChunkDataFile"; case kPluginBridgeNonRtClientSetCtrlChannel: return "kPluginBridgeNonRtClientSetCtrlChannel"; case kPluginBridgeNonRtClientSetOption: return "kPluginBridgeNonRtClientSetOption"; case kPluginBridgeNonRtClientGetParameterText: return "kPluginBridgeNonRtClientGetParameterText"; case kPluginBridgeNonRtClientPrepareForSave: return "kPluginBridgeNonRtClientPrepareForSave"; case kPluginBridgeNonRtClientRestoreLV2State: return "kPluginBridgeNonRtClientRestoreLV2State"; case kPluginBridgeNonRtClientShowUI: return "kPluginBridgeNonRtClientShowUI"; case kPluginBridgeNonRtClientHideUI: return "kPluginBridgeNonRtClientHideUI"; case kPluginBridgeNonRtClientUiParameterChange: return "kPluginBridgeNonRtClientUiParameterChange"; case kPluginBridgeNonRtClientUiProgramChange: return "kPluginBridgeNonRtClientUiProgramChange"; case kPluginBridgeNonRtClientUiMidiProgramChange: return "kPluginBridgeNonRtClientUiMidiProgramChange"; case kPluginBridgeNonRtClientUiNoteOn: return "kPluginBridgeNonRtClientUiNoteOn"; case kPluginBridgeNonRtClientUiNoteOff: return "kPluginBridgeNonRtClientUiNoteOff"; case kPluginBridgeNonRtClientQuit: return "kPluginBridgeNonRtClientQuit"; case kPluginBridgeNonRtClientSetParameterMappedRange: return "kPluginBridgeNonRtClientSetParameterMappedRange"; case kPluginBridgeNonRtClientSetOptions: return "kPluginBridgeNonRtClientSetOptions"; case kPluginBridgeNonRtClientSetWindowTitle: return "kPluginBridgeNonRtClientSetWindowTitle"; case kPluginBridgeNonRtClientEmbedUI: return "kPluginBridgeNonRtClientEmbedUI"; case kPluginBridgeNonRtClientReload: return "kPluginBridgeNonRtClientReload"; } carla_stderr("CarlaBackend::PluginBridgeNonRtClientOpcode2str(%i) - invalid opcode", opcode); return ""; } static inline const char* PluginBridgeNonRtServerOpcode2str(const PluginBridgeNonRtServerOpcode opcode) noexcept { switch (opcode) { case kPluginBridgeNonRtServerNull: return "kPluginBridgeNonRtServerNull"; case kPluginBridgeNonRtServerPong: return "kPluginBridgeNonRtServerPong"; case kPluginBridgeNonRtServerPluginInfo1: return "kPluginBridgeNonRtServerPluginInfo1"; case kPluginBridgeNonRtServerPluginInfo2: return "kPluginBridgeNonRtServerPluginInfo2"; case kPluginBridgeNonRtServerAudioCount: return "kPluginBridgeNonRtServerAudioCount"; case kPluginBridgeNonRtServerMidiCount: return "kPluginBridgeNonRtServerMidiCount"; case kPluginBridgeNonRtServerCvCount: return "kPluginBridgeNonRtServerCvCount"; case kPluginBridgeNonRtServerParameterCount: return "kPluginBridgeNonRtServerParameterCount"; case kPluginBridgeNonRtServerProgramCount: return "kPluginBridgeNonRtServerProgramCount"; case kPluginBridgeNonRtServerMidiProgramCount: return "kPluginBridgeNonRtServerMidiProgramCount"; case kPluginBridgeNonRtServerPortName: return "kPluginBridgeNonRtServerPortName"; case kPluginBridgeNonRtServerParameterData1: return "kPluginBridgeNonRtServerParameterData1"; case kPluginBridgeNonRtServerParameterData2: return "kPluginBridgeNonRtServerParameterData2"; case kPluginBridgeNonRtServerParameterRanges: return "kPluginBridgeNonRtServerParameterRanges"; case kPluginBridgeNonRtServerParameterValue: return "kPluginBridgeNonRtServerParameterValue"; case kPluginBridgeNonRtServerParameterValue2: return "kPluginBridgeNonRtServerParameterValue2"; case kPluginBridgeNonRtServerParameterTouch: return "kPluginBridgeNonRtServerParameterTouch"; case kPluginBridgeNonRtServerDefaultValue: return "kPluginBridgeNonRtServerDefaultValue"; case kPluginBridgeNonRtServerCurrentProgram: return "kPluginBridgeNonRtServerCurrentProgram"; case kPluginBridgeNonRtServerCurrentMidiProgram: return "kPluginBridgeNonRtServerCurrentMidiProgram"; case kPluginBridgeNonRtServerProgramName: return "kPluginBridgeNonRtServerProgramName"; case kPluginBridgeNonRtServerMidiProgramData: return "kPluginBridgeNonRtServerMidiProgramData"; case kPluginBridgeNonRtServerSetCustomData: return "kPluginBridgeNonRtServerSetCustomData"; case kPluginBridgeNonRtServerSetChunkDataFile: return "kPluginBridgeNonRtServerSetChunkDataFile"; case kPluginBridgeNonRtServerSetLatency: return "kPluginBridgeNonRtServerSetLatency"; case kPluginBridgeNonRtServerSetParameterText: return "kPluginBridgeNonRtServerSetParameterText"; case kPluginBridgeNonRtServerReady: return "kPluginBridgeNonRtServerReady"; case kPluginBridgeNonRtServerSaved: return "kPluginBridgeNonRtServerSaved"; case kPluginBridgeNonRtServerUiClosed: return "kPluginBridgeNonRtServerUiClosed"; case kPluginBridgeNonRtServerError: return "kPluginBridgeNonRtServerError"; case kPluginBridgeNonRtServerVersion: return "kPluginBridgeNonRtServerVersion"; case kPluginBridgeNonRtServerRespEmbedUI: return "kPluginBridgeNonRtServerRespEmbedUI"; case kPluginBridgeNonRtServerResizeEmbedUI: return "kPluginBridgeNonRtServerResizeEmbedUI"; } carla_stderr("CarlaBackend::PluginBridgeNonRtServerOpcode2str%i) - invalid opcode", opcode); return ""; } // ------------------------------------------------------------------------------------------------------------------- static const std::size_t kBridgeRtClientDataMidiOutSize = 511*4; static const std::size_t kBridgeBaseMidiOutHeaderSize = 6U /* time, port and size */; // Server => Client RT struct BridgeRtClientData { BridgeSemaphore sem; BridgeTimeInfo timeInfo; SmallStackBuffer ringBuffer; uint8_t midiOut[kBridgeRtClientDataMidiOutSize]; uint32_t procFlags; }; // Server => Client Non-RT struct BridgeNonRtClientData { BigStackBuffer ringBuffer; }; // Client => Server Non-RT struct BridgeNonRtServerData { HugeStackBuffer ringBuffer; }; // ------------------------------------------------------------------------------------------------------------------- struct CARLA_API BridgeAudioPool { float* data; std::size_t dataSize; CarlaString filename; char shm[64]; bool isServer; BridgeAudioPool() noexcept; ~BridgeAudioPool() noexcept; bool initializeServer() noexcept; bool attachClient(const char* const fname) noexcept; void clear() noexcept; void resize(const uint32_t bufferSize, const uint32_t audioPortCount, const uint32_t cvPortCount) noexcept; const char* getFilenameSuffix() const noexcept; CARLA_DECLARE_NON_COPYABLE(BridgeAudioPool) }; // ------------------------------------------------------------------------------------------------------------------- struct CARLA_API BridgeRtClientControl : public CarlaRingBufferControl { BridgeRtClientData* data; CarlaString filename; bool needsSemDestroy; // client only char shm[64]; bool isServer; BridgeRtClientControl() noexcept; ~BridgeRtClientControl() noexcept override; bool initializeServer() noexcept; bool attachClient(const char* const basename) noexcept; void clear() noexcept; bool mapData() noexcept; void unmapData() noexcept; // non-bridge, server bool waitForClient(const uint msecs) noexcept; bool writeOpcode(const PluginBridgeRtClientOpcode opcode) noexcept; // bridge, client PluginBridgeRtClientOpcode readOpcode() noexcept; // helper class that automatically posts semaphore on destructor struct WaitHelper { BridgeRtClientData* const data; const bool ok; WaitHelper(BridgeRtClientControl& c) noexcept; ~WaitHelper() noexcept; CARLA_DECLARE_NON_COPYABLE(WaitHelper) }; CARLA_DECLARE_NON_COPYABLE(BridgeRtClientControl) }; // ------------------------------------------------------------------------------------------------------------------- struct CARLA_API BridgeNonRtClientControl : public CarlaRingBufferControl { BridgeNonRtClientData* data; CarlaString filename; CarlaMutex mutex; char shm[64]; bool isServer; BridgeNonRtClientControl() noexcept; ~BridgeNonRtClientControl() noexcept override; bool initializeServer() noexcept; bool attachClient(const char* const basename) noexcept; void clear() noexcept; bool mapData() noexcept; void unmapData() noexcept; // non-bridge, server void waitIfDataIsReachingLimit() noexcept; bool writeOpcode(const PluginBridgeNonRtClientOpcode opcode) noexcept; // bridge, client PluginBridgeNonRtClientOpcode readOpcode() noexcept; CARLA_DECLARE_NON_COPYABLE(BridgeNonRtClientControl) }; // ------------------------------------------------------------------------------------------------------------------- struct CARLA_API BridgeNonRtServerControl : public CarlaRingBufferControl { BridgeNonRtServerData* data; CarlaString filename; CarlaMutex mutex; char shm[64]; bool isServer; BridgeNonRtServerControl() noexcept; ~BridgeNonRtServerControl() noexcept override; bool initializeServer() noexcept; bool attachClient(const char* const basename) noexcept; void clear() noexcept; bool mapData() noexcept; void unmapData() noexcept; // non-bridge, server PluginBridgeNonRtServerOpcode readOpcode() noexcept; // bridge, client void waitIfDataIsReachingLimit() noexcept; bool writeOpcode(const PluginBridgeNonRtServerOpcode opcode) noexcept; CARLA_DECLARE_NON_COPYABLE(BridgeNonRtServerControl) }; // ------------------------------------------------------------------------------------------------------------------- #endif // CARLA_BRIDGE_UTILS_HPP_INCLUDED