From 7ff10ddc4aab6d35ca93d6ad8a3b5f9f34d7d7f7 Mon Sep 17 00:00:00 2001 From: falkTX Date: Fri, 9 Nov 2012 12:13:24 +0000 Subject: [PATCH] Rework Carla Engine --- c++/carla-backend/carla_backend.hpp | 5 +- c++/carla-backend/carla_backend_utils.hpp | 30 +- c++/carla-engine/carla_engine.cpp | 1502 ++++++++------------- c++/carla-engine/carla_engine.doxygen | 2 +- c++/carla-engine/carla_engine.hpp | 655 ++++++--- c++/carla-engine/carla_engine.pro | 6 +- c++/carla-engine/carla_engine_osc.cpp | 41 +- c++/carla-engine/carla_engine_osc.hpp | 10 +- c++/carla-engine/carla_engine_thread.cpp | 24 +- c++/carla-engine/carla_engine_thread.hpp | 6 +- c++/carla-engine/jack.cpp | 581 ++++++-- c++/carla-engine/plugin.cpp | 66 +- c++/carla-engine/rtaudio.cpp | 146 +- c++/carla-plugin/carla_plugin.hpp | 9 +- c++/carla-utils/carla_utils.hpp | 100 +- src/shared_carla.py | 3 +- 16 files changed, 1805 insertions(+), 1381 deletions(-) diff --git a/c++/carla-backend/carla_backend.hpp b/c++/carla-backend/carla_backend.hpp index f489544..2036a65 100644 --- a/c++/carla-backend/carla_backend.hpp +++ b/c++/carla-backend/carla_backend.hpp @@ -516,10 +516,11 @@ enum CallbackType { * * \see OPTION_PROCESS_MODE */ -enum ProcessModeType { +enum ProcessMode { PROCESS_MODE_SINGLE_CLIENT = 0, //!< Single client mode (dynamic input/outputs as needed by plugins) PROCESS_MODE_MULTIPLE_CLIENTS = 1, //!< Multiple client mode (1 master client + 1 client per plugin) - PROCESS_MODE_CONTINUOUS_RACK = 2 //!< Single client, "rack" mode. Processes plugins in order of id, with forced stereo. + PROCESS_MODE_CONTINUOUS_RACK = 2, //!< Single client, "rack" mode. Processes plugins in order of id, with forced stereo. + PROCESS_MODE_PATCHBAY = 3 //!< Single client, "patchbay" mode. }; /*! diff --git a/c++/carla-backend/carla_backend_utils.hpp b/c++/carla-backend/carla_backend_utils.hpp index 3143a73..979d8a2 100644 --- a/c++/carla-backend/carla_backend_utils.hpp +++ b/c++/carla-backend/carla_backend_utils.hpp @@ -323,9 +323,9 @@ const char* CallbackType2Str(const CallbackType& type) } static inline -const char* ProcessModeType2Str(const ProcessModeType& type) +const char* ProcessMode2Str(const ProcessMode& mode) { - switch (type) + switch (mode) { case PROCESS_MODE_SINGLE_CLIENT: return "PROCESS_MODE_SINGLE_CLIENT"; @@ -333,9 +333,11 @@ const char* ProcessModeType2Str(const ProcessModeType& type) return "PROCESS_MODE_MULTIPLE_CLIENTS"; case PROCESS_MODE_CONTINUOUS_RACK: return "PROCESS_MODE_CONTINUOUS_RACK"; + case PROCESS_MODE_PATCHBAY: + return "PROCESS_MODE_PATCHBAY"; } - qWarning("CarlaBackend::ProcessModeType2Str(%i) - invalid type", type); + qWarning("CarlaBackend::ProcessModeType2Str(%i) - invalid type", mode); return nullptr; } @@ -414,16 +416,6 @@ const char* getPluginTypeString(const PluginType& type) // ------------------------------------------------------------------------------------------------------------------- -static inline -void* getPointerFromAddress(const uintptr_t& addr) -{ - qDebug("CarlaBackend::getPointerFromAddress(" P_UINTPTR ")", addr); - CARLA_ASSERT(addr != 0); - - uintptr_t** const ptr = (uintptr_t**)&addr; - return *ptr; -} - static inline uintptr_t getAddressFromPointer(void* const ptr) { @@ -434,6 +426,16 @@ uintptr_t getAddressFromPointer(void* const ptr) return *addr; } +static inline +void* getPointerFromAddress(const uintptr_t& addr) +{ + qDebug("CarlaBackend::getPointerFromAddress(" P_UINTPTR ")", addr); + CARLA_ASSERT(addr != 0); + + uintptr_t** const ptr = (uintptr_t**)&addr; + return *ptr; +} + static inline PluginCategory getPluginCategoryFromName(const char* const name) { @@ -443,7 +445,7 @@ PluginCategory getPluginCategoryFromName(const char* const name) if (! name) return PLUGIN_CATEGORY_NONE; - carla_string sname(name); + CarlaString sname(name); if (sname.isEmpty()) return PLUGIN_CATEGORY_NONE; diff --git a/c++/carla-engine/carla_engine.cpp b/c++/carla-engine/carla_engine.cpp index b38fec3..daf4e72 100644 --- a/c++/carla-engine/carla_engine.cpp +++ b/c++/carla-engine/carla_engine.cpp @@ -18,90 +18,368 @@ #include "carla_engine.hpp" #include "carla_plugin.hpp" -#ifdef CARLA_ENGINE_JACK -# include "carla_jackbridge.h" -#endif +CARLA_BACKEND_START_NAMESPACE -#ifdef CARLA_ENGINE_RTAUDIO -# include "RtAudio.h" -# include "RtMidi.h" +// ------------------------------------------------------------------------------------------------------------------- +// Engine port (Base) + +CarlaEngineBasePort::CarlaEngineBasePort(const bool isInput_, const ProcessMode processMode_) + : isInput(isInput_), + processMode(processMode_) +{ + qDebug("CarlaEngineBasePort::CarlaEngineBasePort(%s, %s)", bool2str(isInput), ProcessMode2Str(processMode)); + + buffer = nullptr; +} + +CarlaEngineBasePort::~CarlaEngineBasePort() +{ + qDebug("CarlaEngineBasePort::~CarlaEngineBasePort()"); +} + +// ------------------------------------------------------------------------------------------------------------------- +// Engine port (Audio) + +CarlaEngineAudioPort::CarlaEngineAudioPort(const bool isInput, const ProcessMode processMode) + : CarlaEngineBasePort(isInput, processMode) +{ + qDebug("CarlaEngineAudioPort::CarlaEngineAudioPort(%s, %s)", bool2str(isInput), ProcessMode2Str(processMode)); +} + +CarlaEngineAudioPort::~CarlaEngineAudioPort() +{ + qDebug("CarlaEngineAudioPort::~CarlaEngineAudioPort()"); +} + +void CarlaEngineAudioPort::initBuffer(CarlaEngine* const) +{ +} + +// ------------------------------------------------------------------------------------------------------------------- +// Engine port (Control) + +CarlaEngineControlPort::CarlaEngineControlPort(const bool isInput, const ProcessMode processMode) + : CarlaEngineBasePort(isInput, processMode) +{ + qDebug("CarlaEngineControlPort::CarlaEngineControlPort(%s, %s)", bool2str(isInput), ProcessMode2Str(processMode)); +} + +void CarlaEngineControlPort::initBuffer(CarlaEngine* const engine) +{ + CARLA_ASSERT(engine); + +#ifndef BUILD_BRIDGE + if (processMode == PROCESS_MODE_CONTINUOUS_RACK) + buffer = isInput ? engine->rackControlEventsIn : engine->rackControlEventsOut; #endif +} -CARLA_BACKEND_START_NAMESPACE +uint32_t CarlaEngineControlPort::getEventCount() +{ + if (! isInput) + return 0; -struct CarlaEngineClientNativeHandle { - CarlaEngineType type; -#ifdef CARLA_ENGINE_JACK - jack_client_t* jackClient; + CARLA_ASSERT(buffer); + +#ifndef BUILD_BRIDGE + if (processMode == PROCESS_MODE_CONTINUOUS_RACK) + { + uint32_t count = 0; + const CarlaEngineControlEvent* const events = (CarlaEngineControlEvent*)buffer; + + for (unsigned short i=0; i < CarlaEngine::MAX_ENGINE_CONTROL_EVENTS; i++, count++) + { + if (events[i].type == CarlaEngineNullEvent) + break; + } + + return count; + } #endif - CarlaEngineClientNativeHandle() + return 0; +} + +const CarlaEngineControlEvent* CarlaEngineControlPort::getEvent(uint32_t index) +{ + if (! isInput) + return nullptr; + + CARLA_ASSERT(buffer); + +#ifndef BUILD_BRIDGE + if (processMode == PROCESS_MODE_CONTINUOUS_RACK) { - type = CarlaEngineTypeNull; -#ifdef CARLA_ENGINE_JACK - jackClient = nullptr; + CARLA_ASSERT(index < CarlaEngine::MAX_ENGINE_CONTROL_EVENTS); + + const CarlaEngineControlEvent* const events = (CarlaEngineControlEvent*)buffer; + + if (index < CarlaEngine::MAX_ENGINE_CONTROL_EVENTS) + return &events[index]; + } #endif + + return nullptr; +} + +void CarlaEngineControlPort::writeEvent(CarlaEngineControlEventType type, uint32_t time, uint8_t channel, uint16_t controller, double value) +{ + if (isInput) + return; + + CARLA_ASSERT(buffer); + CARLA_ASSERT(type != CarlaEngineNullEvent); + +#ifndef BUILD_BRIDGE + if (processMode == PROCESS_MODE_CONTINUOUS_RACK) + { + CarlaEngineControlEvent* const events = (CarlaEngineControlEvent*)buffer; + + for (unsigned short i=0; i < CarlaEngine::MAX_ENGINE_CONTROL_EVENTS; i++) + { + if (events[i].type != CarlaEngineNullEvent) + continue; + + events[i].type = type; + events[i].time = time; + events[i].value = value; + events[i].channel = channel; + events[i].controller = controller; + break; + } } -}; +#endif +} -struct CarlaEnginePortNativeHandle { -#ifdef CARLA_ENGINE_JACK - jack_client_t* jackClient; - jack_port_t* jackPort; +// ------------------------------------------------------------------------------------------------------------------- +// Engine port (MIDI) + +CarlaEngineMidiPort::CarlaEngineMidiPort(const bool isInput, const ProcessMode processMode) + : CarlaEngineBasePort(isInput, processMode) +{ + qDebug("CarlaEngineMidiPort::CarlaEngineMidiPort(%s, %s)", bool2str(isInput), ProcessMode2Str(processMode)); +} + +void CarlaEngineMidiPort::initBuffer(CarlaEngine* const engine) +{ + CARLA_ASSERT(engine); + +#ifndef BUILD_BRIDGE + if (processMode == PROCESS_MODE_CONTINUOUS_RACK) + buffer = isInput ? engine->rackMidiEventsIn : engine->rackMidiEventsOut; #endif +} - CarlaEnginePortNativeHandle() +uint32_t CarlaEngineMidiPort::getEventCount() +{ + if (! isInput) + return 0; + + CARLA_ASSERT(buffer); + +#ifndef BUILD_BRIDGE + if (processMode == PROCESS_MODE_CONTINUOUS_RACK) { -#ifdef CARLA_ENGINE_JACK - jackClient = nullptr; - jackPort = nullptr; + uint32_t count = 0; + const CarlaEngineMidiEvent* const events = (CarlaEngineMidiEvent*)buffer; + + for (unsigned short i=0; i < CarlaEngine::MAX_ENGINE_MIDI_EVENTS; i++, count++) + { + if (events[i].size == 0) + break; + } + + return count; + } #endif + + return 0; +} + +const CarlaEngineMidiEvent* CarlaEngineMidiPort::getEvent(uint32_t index) +{ + if (! isInput) + return nullptr; + + CARLA_ASSERT(buffer); + +#ifndef BUILD_BRIDGE + if (processMode == PROCESS_MODE_CONTINUOUS_RACK) + { + CARLA_ASSERT(index < CarlaEngine::MAX_ENGINE_MIDI_EVENTS); + + const CarlaEngineMidiEvent* const events = (CarlaEngineMidiEvent*)buffer; + + if (index < CarlaEngine::MAX_ENGINE_MIDI_EVENTS) + return &events[index]; } -}; +#endif + + return nullptr; +} -double abs_d(const double& value) +void CarlaEngineMidiPort::writeEvent(uint32_t time, const uint8_t* data, uint8_t size) { - return (value < 0.0) ? -value : value; + if (isInput) + return; + + CARLA_ASSERT(buffer); + CARLA_ASSERT(data); + CARLA_ASSERT(size > 0); + +#ifndef BUILD_BRIDGE + if (processMode == PROCESS_MODE_CONTINUOUS_RACK) + { + if (size > 4) + return; + + CarlaEngineMidiEvent* const events = (CarlaEngineMidiEvent*)buffer; + + for (unsigned short i=0; i < CarlaEngine::MAX_ENGINE_MIDI_EVENTS; i++) + { + if (events[i].size != 0) + continue; + + events[i].time = time; + events[i].size = size; + memcpy(events[i].data, data, size); + break; + } + } +#endif } -static const char* carlaLastError = nullptr; +//#ifdef CARLA_ENGINE_JACK +//float* CarlaEngineAudioPort::getJackAudioBuffer(uint32_t nframes) +//{ +//# ifndef BUILD_BRIDGE +// if (CarlaEngine::processMode == PROCESS_MODE_CONTINUOUS_RACK) +// return nullptr; +//# endif +// CARLA_ASSERT(handle.jackPort); +// return (float*)jackbridge_port_get_buffer(handle.jackPort, nframes); +//} +//#endif // ------------------------------------------------------------------------------------------------------------------- +// Carla Engine Client -const char* getLastError() +CarlaEngineClient::CarlaEngineClient(const CarlaEngineType engineType_, const ProcessMode processMode_) + : engineType(engineType_), + processMode(processMode_) { - qDebug("CarlaBackend::getLastError()"); + qDebug("CarlaEngineClient::CarlaEngineClient(%s, %s)", "" /* TODO */, ProcessMode2Str(processMode)); + CARLA_ASSERT(engineType != CarlaEngineTypeNull); - return carlaLastError; + m_active = false; + m_latency = 0; } -void setLastError(const char* const error) +CarlaEngineClient::~CarlaEngineClient() { - qDebug("CarlaBackend::setLastError(\"%s\")", error); + qDebug("CarlaEngineClient::~CarlaEngineClient()"); + CARLA_ASSERT(! m_active); +} - if (carlaLastError) - free((void*)carlaLastError); +void CarlaEngineClient::activate() +{ + qDebug("CarlaEngineClient::activate()"); + CARLA_ASSERT(! m_active); - carlaLastError = error ? strdup(error) : nullptr; + m_active = true; } -#ifndef BUILD_BRIDGE -//uint32_t getPluginHintsFromNative(const uint32_t nativeHints) +void CarlaEngineClient::deactivate() +{ + qDebug("CarlaEngineClient::deactivate()"); + CARLA_ASSERT(m_active); + + m_active = false; +} + +bool CarlaEngineClient::isActive() const +{ + qDebug("CarlaEngineClient::isActive()"); + + return m_active; +} + +bool CarlaEngineClient::isOk() const +{ + qDebug("CarlaEngineClient::isOk()"); + + return true; +} + +uint32_t CarlaEngineClient::getLatency() const +{ + return m_latency; +} + +void CarlaEngineClient::setLatency(const uint32_t samples) +{ + m_latency = samples; +} + +//const CarlaEngineBasePort* CarlaEngineClient::addPort(const CarlaEnginePortType portType, const char* const name, const bool isInput) //{ -// uint32_t realHints = 0; -// if (nativeHints & ::PLUGIN_IS_SYNTH) -// realHints |= PLUGIN_IS_SYNTH; -// if (nativeHints & ::PLUGIN_HAS_GUI) -// realHints |= PLUGIN_HAS_GUI; -// if (nativeHints & ::PLUGIN_USES_SINGLE_THREAD) -// realHints |= PLUGIN_USES_SINGLE_THREAD; -// return realHints; +// qDebug("CarlaEngineClient::addPort(%i, \"%s\", %s)", portType, name, bool2str(isInput)); + +// CarlaEngineBasePort::Handle portHandle; + +//#ifndef BUILD_BRIDGE +// if (CarlaEngine::processMode != PROCESS_MODE_CONTINUOUS_RACK) +//#endif +// { +//#ifdef CARLA_ENGINE_JACK +// if (engineType == CarlaEngineTypeJack) +// { +// switch (portType) +// { +// case CarlaEnginePortTypeAudio: +// portHandle = jackbridge_port_register((jack_client_t*)handle, name, JACK_DEFAULT_AUDIO_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0); +// break; +// case CarlaEnginePortTypeControl: +// case CarlaEnginePortTypeMIDI: +// portHandle = jackbridge_port_register((jack_client_t*)handle, name, JACK_DEFAULT_MIDI_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0); +// break; +// } +// } +//#endif +// } + +// switch (portType) +// { +// case CarlaEnginePortTypeAudio: +// return new CarlaEngineAudioPort(portHandle, isInput); +// case CarlaEnginePortTypeControl: +// return new CarlaEngineControlPort(portHandle, isInput); +// case CarlaEnginePortTypeMIDI: +// return new CarlaEngineMidiPort(portHandle, isInput); +// } + +// qCritical("CarlaEngineClient::addPort(%i, \"%s\", %s) - invalid type", portType, name, bool2str(isInput)); +// return nullptr; //} -#endif // BUILD_BRIDGE -// ----------------------------------------------------------------------- +//void CarlaEngineClient::removePort(CarlaEngineBasePort* const port) +//{ +//#ifndef BUILD_BRIDGE +// if (CarlaEngine::processMode == PROCESS_MODE_CONTINUOUS_RACK) +// return; +//#endif + +//#ifdef CARLA_ENGINE_JACK +// if (engineType == CarlaEngineTypeJack) +// { +// if (handle && port->handle) +// jackbridge_port_unregister((jack_client_t*)handle, (jack_port_t*)port->handle); +// } +//#endif +//} -unsigned short CarlaEngine::m_maxPluginNumber = 0; +// ------------------------------------------------------------------------------------------------------------------- +// Carla Engine Client CarlaEngine::CarlaEngine() : m_thread(this), @@ -122,10 +400,9 @@ CarlaEngine::CarlaEngine() { qDebug("CarlaEngine::CarlaEngine()"); - type = CarlaEngineTypeNull; - name = nullptr; bufferSize = 0; sampleRate = 0.0; + m_maxPluginNumber = 0; #ifndef Q_COMPILER_INITIALIZER_LISTS @@ -146,52 +423,11 @@ CarlaEngine::CarlaEngine() CarlaEngine::~CarlaEngine() { qDebug("CarlaEngine::~CarlaEngine()"); - - if (name) - free((void*)name); } // ----------------------------------------------------------------------- // Static values -int CarlaEngine::maxClientNameSize() -{ -#ifdef CARLA_ENGINE_JACK -# ifndef BUILD_BRIDGE - if (processMode != PROCESS_MODE_CONTINUOUS_RACK) -# endif - return jackbridge_client_name_size(); -#endif - return STR_MAX/2; -} - -int CarlaEngine::maxPortNameSize() -{ -#ifdef CARLA_ENGINE_JACK -# ifndef BUILD_BRIDGE - if (processMode != PROCESS_MODE_CONTINUOUS_RACK) -# endif - return jackbridge_port_name_size(); -#endif - return STR_MAX; -} - -unsigned short CarlaEngine::maxPluginNumber() -{ - return m_maxPluginNumber; -} - -const char* CarlaEngine::getFixedClientName(const char* const clientName) -{ - char* fixedName = strdup(clientName); - for (size_t i=0; i < strlen(fixedName); i++) - { - if (! (std::isalpha(fixedName[i]) || std::isdigit(fixedName[i]))) - fixedName[i] = '_'; - } - return fixedName; -} - unsigned int CarlaEngine::getDriverCount() { unsigned int count = 0; @@ -199,9 +435,7 @@ unsigned int CarlaEngine::getDriverCount() count += 1; #endif #ifdef CARLA_ENGINE_RTAUDIO - std::vector apis; - RtAudio::getCompiledApi(apis); - count += apis.size(); + count += getRtAudioApiCount(); #endif return count; } @@ -216,42 +450,15 @@ const char* CarlaEngine::getDriverName(unsigned int index) #endif #ifdef CARLA_ENGINE_RTAUDIO - std::vector apis; - RtAudio::getCompiledApi(apis); - - if (index < apis.size()) - { - RtAudio::Api api = apis[index]; - - switch (api) - { - case RtAudio::UNSPECIFIED: - return "Unspecified"; - case RtAudio::LINUX_ALSA: - return "ALSA"; - case RtAudio::LINUX_PULSE: - return "PulseAudio"; - case RtAudio::LINUX_OSS: - return "OSS"; - case RtAudio::UNIX_JACK: - return "JACK (RtAudio)"; - case RtAudio::MACOSX_CORE: - return "CoreAudio"; - case RtAudio::WINDOWS_ASIO: - return "ASIO"; - case RtAudio::WINDOWS_DS: - return "DirectSound"; - case RtAudio::RTAUDIO_DUMMY: - return "Dummy"; - } - } + if (index < getRtAudioApiCount()) + return getRtAudioApiName(index); #endif qWarning("CarlaEngine::getDriverName(%i) - invalid index", index); return nullptr; } -CarlaEngine* CarlaEngine::newDriverByName(const char* driverName) +CarlaEngine* CarlaEngine::newDriverByName(const char* const driverName) { #ifdef CARLA_ENGINE_JACK if (strcmp(driverName, "JACK") == 0) @@ -262,201 +469,68 @@ CarlaEngine* CarlaEngine::newDriverByName(const char* driverName) #endif #ifdef CARLA_ENGINE_RTAUDIO -#ifdef __LINUX_ALSA__ +# ifdef __LINUX_ALSA__ else if (strcmp(driverName, "ALSA") == 0) - return newRtAudio(RtAudio::LINUX_ALSA); -#endif -#ifdef __LINUX_PULSE__ + return newRtAudio(RTAUDIO_LINUX_ALSA); +# endif +# ifdef __LINUX_PULSE__ else if (strcmp(driverName, "PulseAudio") == 0) - return newRtAudio(RtAudio::LINUX_PULSE); -#endif -#ifdef __LINUX_OSS__ + return newRtAudio(RTAUDIO_LINUX_PULSE); +# endif +# ifdef __LINUX_OSS__ else if (strcmp(driverName, "OSS") == 0) - return newRtAudio(RtAudio::LINUX_OSS); -#endif -#ifdef __UNIX_JACK__ + return newRtAudio(RTAUDIO_LINUX_OSS); +# endif +# ifdef __UNIX_JACK__ else if (strcmp(driverName, "JACK (RtAudio)") == 0) - return newRtAudio(RtAudio::UNIX_JACK); -#endif -#ifdef __MACOSX_CORE__ + return newRtAudio(RTAUDIO_UNIX_JACK); +# endif +# ifdef __MACOSX_CORE__ else if (strcmp(driverName, "CoreAudio") == 0) - return newRtAudio(RtAudio::MACOSX_CORE); -#endif -#ifdef __WINDOWS_ASIO__ + return newRtAudio(RTAUDIO_MACOSX_CORE); +# endif +# ifdef __WINDOWS_ASIO__ else if (strcmp(driverName, "ASIO") == 0) - return newRtAudio(RtAudio::WINDOWS_ASIO); -#endif -#ifdef __WINDOWS_DS__ + return newRtAudio(RTAUDIO_WINDOWS_ASIO); +# endif +# ifdef __WINDOWS_DS__ else if (strcmp(driverName, "DirectSound") == 0) - return newRtAudio(RtAudio::WINDOWS_DS); -#endif -#ifdef __RTAUDIO_DUMMY__ - else if (strcmp(driverName, "Dummy") == 0) - return newRtAudio(RtAudio::RTAUDIO_DUMMY); -#endif + return newRtAudio(RTAUDIO_WINDOWS_DS); +# endif #endif return nullptr; } // ----------------------------------------------------------------------- -// Global options - -#ifndef BUILD_BRIDGE -ProcessModeType CarlaEngine::processMode = PROCESS_MODE_MULTIPLE_CLIENTS; +// Maximum values -void CarlaEngine::setOption(const OptionsType option, const int value, const char* const valueStr) +int CarlaEngine::maxClientNameSize() { - qDebug("CarlaEngine::setOption(%s, %i, \"%s\")", OptionsType2Str(option), value, valueStr); - - switch (option) - { - case OPTION_PROCESS_NAME: - carla_setprocname(valueStr); - break; - case OPTION_PROCESS_MODE: - if (value < PROCESS_MODE_SINGLE_CLIENT || value > PROCESS_MODE_CONTINUOUS_RACK) - return qCritical("CarlaEngine::setOption(%s, %i, \"%s\") - invalid value", OptionsType2Str(option), value, valueStr); - processMode = (ProcessModeType)value; - break; - case OPTION_PROCESS_HIGH_PRECISION: - options.processHighPrecision = value; - break; - case OPTION_MAX_PARAMETERS: - options.maxParameters = (value > 0) ? value : MAX_PARAMETERS; - break; - case OPTION_PREFERRED_BUFFER_SIZE: - options.preferredBufferSize = value; - break; - case OPTION_PREFERRED_SAMPLE_RATE: - options.preferredSampleRate = value; - break; - case OPTION_FORCE_STEREO: - options.forceStereo = value; - break; - case OPTION_USE_DSSI_VST_CHUNKS: - options.useDssiVstChunks = value; - break; - case OPTION_PREFER_PLUGIN_BRIDGES: - options.preferPluginBridges = value; - break; - case OPTION_PREFER_UI_BRIDGES: - options.preferUiBridges = value; - break; - case OPTION_OSC_UI_TIMEOUT: - options.oscUiTimeout = value/100; - break; - case OPTION_PATH_LADSPA: - carla_setenv("LADSPA_PATH", valueStr); - break; - case OPTION_PATH_DSSI: - carla_setenv("DSSI_PATH", valueStr); - break; - case OPTION_PATH_LV2: - carla_setenv("LV2_PATH", valueStr); - break; - case OPTION_PATH_VST: - carla_setenv("VST_PATH", valueStr); - break; - case OPTION_PATH_GIG: - carla_setenv("GIG_PATH", valueStr); - break; - case OPTION_PATH_SF2: - carla_setenv("SF2_PATH", valueStr); - break; - case OPTION_PATH_SFZ: - carla_setenv("SFZ_PATH", valueStr); - break; - case OPTION_PATH_BRIDGE_POSIX32: - options.bridge_posix32 = strdup(valueStr); - break; - case OPTION_PATH_BRIDGE_POSIX64: - options.bridge_posix64 = strdup(valueStr); - break; - case OPTION_PATH_BRIDGE_WIN32: - options.bridge_win32 = strdup(valueStr); - break; - case OPTION_PATH_BRIDGE_WIN64: - options.bridge_win64 = strdup(valueStr); - break; - case OPTION_PATH_BRIDGE_LV2_GTK2: - options.bridge_lv2gtk2 = strdup(valueStr); - break; - case OPTION_PATH_BRIDGE_LV2_GTK3: - options.bridge_lv2gtk3 = strdup(valueStr); - break; - case OPTION_PATH_BRIDGE_LV2_QT4: - options.bridge_lv2qt4 = strdup(valueStr); - break; - case OPTION_PATH_BRIDGE_LV2_X11: - options.bridge_lv2x11 = strdup(valueStr); - break; - case OPTION_PATH_BRIDGE_VST_HWND: - options.bridge_vsthwnd = strdup(valueStr); - break; - case OPTION_PATH_BRIDGE_VST_X11: - options.bridge_vstx11 = strdup(valueStr); - break; - } +//#ifdef CARLA_ENGINE_JACK +//# ifndef BUILD_BRIDGE +// if (type() == CarlaEngineTypeJack && processMode != PROCESS_MODE_CONTINUOUS_RACK) +//# endif +// return jackbridge_client_name_size(); +//#endif + return STR_MAX/2; } -void CarlaEngine::resetOptions() +int CarlaEngine::maxPortNameSize() { - qDebug("CarlaEngine::resetOptions()"); - - if (options.bridge_posix32) - free((void*)options.bridge_posix32); - - if (options.bridge_posix64) - free((void*)options.bridge_posix64); - - if (options.bridge_win32) - free((void*)options.bridge_win32); - - if (options.bridge_win64) - free((void*)options.bridge_win64); - - if (options.bridge_lv2gtk2) - free((void*)options.bridge_lv2gtk2); - - if (options.bridge_lv2gtk3) - free((void*)options.bridge_lv2gtk3); - - if (options.bridge_lv2qt4) - free((void*)options.bridge_lv2qt4); - - if (options.bridge_lv2x11) - free((void*)options.bridge_lv2x11); - - if (options.bridge_vsthwnd) - free((void*)options.bridge_vsthwnd); - - if (options.bridge_vstx11) - free((void*)options.bridge_vstx11); - - processMode = PROCESS_MODE_MULTIPLE_CLIENTS; - options.processHighPrecision = false; - options.maxParameters = MAX_PARAMETERS; - options.preferredBufferSize = 512; - options.preferredSampleRate = 44100; - options.forceStereo = false; - options.useDssiVstChunks = false; - options.preferPluginBridges = false; - options.preferUiBridges = true; - options.oscUiTimeout = 4000/100; +//#ifdef CARLA_ENGINE_JACK +//# ifndef BUILD_BRIDGE +// if (type() == CarlaEngineTypeJack && processMode != PROCESS_MODE_CONTINUOUS_RACK) +//# endif +// return jackbridge_port_name_size(); +//#endif + return STR_MAX; +} - options.bridge_posix32 = nullptr; - options.bridge_posix64 = nullptr; - options.bridge_win32 = nullptr; - options.bridge_win64 = nullptr; - options.bridge_lv2gtk2 = nullptr; - options.bridge_lv2gtk3 = nullptr; - options.bridge_lv2qt4 = nullptr; - options.bridge_lv2x11 = nullptr; - options.bridge_vsthwnd = nullptr; - options.bridge_vstx11 = nullptr; +unsigned short CarlaEngine::maxPluginNumber() +{ + return m_maxPluginNumber; } -#endif // ----------------------------------------------------------------------- // Virtual, per-engine type calls @@ -469,10 +543,12 @@ bool CarlaEngine::init(const char* const clientName) m_osc.init(clientName); m_oscData = m_osc.getControlData(); - if (strcmp(clientName, "Carla")) + if (strcmp(clientName, "Carla") != 0) carla_setprocname(clientName); #endif + m_thread.startNow(); + return true; } @@ -490,11 +566,13 @@ bool CarlaEngine::close() m_maxPluginNumber = 0; + name.clear(); + return true; } // ----------------------------------------------------------------------- -// plugin management +// Plugin management short CarlaEngine::getNewPluginId() const { @@ -534,62 +612,66 @@ const char* CarlaEngine::getUniquePluginName(const char* const name) qDebug("CarlaEngine::getUniquePluginName(\"%s\")", name); CARLA_ASSERT(name); - QString qname(name); + CarlaString sname(name); - if (qname.isEmpty()) - qname = "(No name)"; + if (sname.isEmpty()) + sname = "(No name)"; - qname.truncate(maxClientNameSize()-5-1); // 5 = strlen(" (10)") - qname.replace(":", "."); // ":" is used in JACK1 to split client/port names + sname.truncate(maxClientNameSize()-5-1); // 5 = strlen(" (10)") + sname.replace(':', '.'); // ':' is used in JACK1 to split client/port names for (unsigned short i=0; i < m_maxPluginNumber; i++) { // Check if unique name already exists - if (m_uniqueNames[i] && qname == m_uniqueNames[i]) + if (m_uniqueNames[i] && sname == m_uniqueNames[i]) { // Check if string has already been modified - uint len = qname.size(); + size_t len = sname.length(); // 1 digit, ex: " (2)" - if (qname.at(len-4) == QChar(' ') && qname.at(len-3) == QChar('(') && qname.at(len-2).isDigit() && qname.at(len-1) == QChar(')')) + if (sname[len-4] == ' ' && sname[len-3] == '(' && sname.isDigit(len-2) && sname[len-1] == ')') { - int number = qname.at(len-2).toAscii()-'0'; + int number = sname[len-2]-'0'; if (number == 9) + { // next number is 10, 2 digits - qname.replace(" (9)", " (10)"); + sname.truncate(len-4); + sname += " (10)"; + //sname.replace(" (9)", " (10)"); + } else - qname[len-2] = QChar('0'+number+1); + sname[len-2] = '0'+number+1; continue; } // 2 digits, ex: " (11)" - if (qname.at(len-5) == QChar(' ') && qname.at(len-4) == QChar('(') && qname.at(len-3).isDigit() && qname.at(len-2).isDigit() && qname.at(len-1) == QChar(')')) + if (sname[len-5] == ' ' && sname[len-4] == '(' && sname.isDigit(len-3) && sname.isDigit(len-2) && sname[len-1] == ')') { - QChar n2 = qname.at(len-2); - QChar n3 = qname.at(len-3); + char n2 = sname[len-2]; + char n3 = sname[len-3]; - if (n2 == QChar('9')) + if (n2 == '9') { - n2 = QChar('0'); - n3 = QChar(n3.toAscii()+1); + n2 = '0'; + n3 = n3+1; } else - n2 = QChar(n2.toAscii()+1); + n2 = n2+1; - qname[len-2] = n2; - qname[len-3] = n3; + sname[len-2] = n2; + sname[len-3] = n3; continue; } // Modify string if not - qname += " (2)"; + sname += " (2)"; } } - return strdup(qname.toUtf8().constData()); + return strdup(sname); } short CarlaEngine::addPlugin(const PluginType ptype, const char* const filename, const char* const name, const char* const label, void* const extra) @@ -610,7 +692,7 @@ short CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, con #ifdef BUILD_BRIDGE m_maxPluginNumber = MAX_PLUGINS; #else - m_maxPluginNumber = (processMode == PROCESS_MODE_CONTINUOUS_RACK) ? 16 : MAX_PLUGINS; + m_maxPluginNumber = (options.processMode == PROCESS_MODE_CONTINUOUS_RACK) ? 16 : MAX_PLUGINS; #endif } @@ -624,17 +706,17 @@ short CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, con CarlaPlugin* plugin = nullptr; #ifndef BUILD_BRIDGE - if (btype != BINARY_NATIVE || (options.preferPluginBridges && /*getBinaryBidgePath(btype) &&*/ type == CarlaEngineTypeJack)) + if (btype != BINARY_NATIVE || (options.preferPluginBridges && /*getBinaryBidgePath(btype) &&*/ type() == CarlaEngineTypeJack)) { # ifdef CARLA_ENGINE_JACK - if (processMode != CarlaBackend::PROCESS_MODE_MULTIPLE_CLIENTS) + if (options.processMode != CarlaBackend::PROCESS_MODE_MULTIPLE_CLIENTS) { setLastError("Can only use bridged plugins in JACK Multi-Client mode"); return -1; } # endif - if (type != CarlaEngineTypeJack) + if (type() != CarlaEngineTypeJack) { setLastError("Can only use bridged plugins with JACK backend"); return -1; @@ -722,7 +804,7 @@ bool CarlaEngine::removePlugin(const unsigned short id) #ifndef BUILD_BRIDGE osc_send_control_remove_plugin(id); - if (processMode == PROCESS_MODE_CONTINUOUS_RACK) + if (options.processMode == PROCESS_MODE_CONTINUOUS_RACK) { // TODO - handle OSC server comm @@ -878,14 +960,14 @@ void CarlaEngine::processRack(float* inBuf[2], float* outBuf[2], uint32_t frames for (uint32_t k=0; k < frames; k++) { - if (abs_d(inBuf[0][k]) > inPeak1) - inPeak1 = abs_d(inBuf[0][k]); - if (abs_d(inBuf[1][k]) > inPeak2) - inPeak2 = abs_d(inBuf[1][k]); - if (abs_d(outBuf[0][k]) > outPeak1) - outPeak1 = abs_d(outBuf[0][k]); - if (abs_d(outBuf[1][k]) > outPeak2) - outPeak2 = abs_d(outBuf[1][k]); + if (std::abs(inBuf[0][k]) > inPeak1) + inPeak1 = std::abs(inBuf[0][k]); + if (std::abs(inBuf[1][k]) > inPeak2) + inPeak2 = std::abs(inBuf[1][k]); + if (std::abs(outBuf[0][k]) > outPeak1) + outPeak1 = std::abs(outBuf[0][k]); + if (std::abs(outBuf[1][k]) > outPeak2) + outPeak2 = std::abs(outBuf[1][k]); } m_insPeak[i*MAX_PEAKS + 0] = inPeak1; @@ -911,11 +993,6 @@ void CarlaEngine::processRack(float* inBuf[2], float* outBuf[2], uint32_t frames // ----------------------------------------------------------------------- // Information (base) -CarlaEngineType CarlaEngine::getType() const -{ - return type; -} - const char* CarlaEngine::getName() const { CARLA_ASSERT(name); @@ -937,7 +1014,7 @@ uint32_t CarlaEngine::getBufferSize() const return bufferSize; } -const CarlaTimeInfo* CarlaEngine::getTimeInfo() const +const CarlaEngineTimeInfo* CarlaEngine::getTimeInfo() const { return &timeInfo; } @@ -998,7 +1075,7 @@ void CarlaEngine::setCallback(const CallbackFunc func, void* const ptr) } // ----------------------------------------------------------------------- -// Mutex locks +// Error handling const char* CarlaEngine::getLastError() const { @@ -1009,6 +1086,134 @@ void CarlaEngine::setLastError(const char* const error) { m_lastError = error; } +// ----------------------------------------------------------------------- +// Global options + +#ifndef BUILD_BRIDGE + +#define CARLA_ENGINE_SET_OPTION_RUNNING_CHECK \ + if (isRunning()) \ + return qCritical("CarlaEngine::setOption(%s, %i, \"%s\") - Cannot set this option while engine is running!", OptionsType2Str(option), value, valueStr); + +void CarlaEngine::setOption(const OptionsType option, const int value, const char* const valueStr) +{ + qDebug("CarlaEngine::setOption(%s, %i, \"%s\")", OptionsType2Str(option), value, valueStr); + + switch (option) + { + case OPTION_PROCESS_NAME: + carla_setprocname(valueStr); + break; + + case OPTION_PROCESS_MODE: + CARLA_ENGINE_SET_OPTION_RUNNING_CHECK + + if (value < PROCESS_MODE_SINGLE_CLIENT || value > PROCESS_MODE_PATCHBAY) + return qCritical("CarlaEngine::setOption(%s, %i, \"%s\") - invalid value", OptionsType2Str(option), value, valueStr); + + options.processMode = static_cast(value); + break; + + case OPTION_PROCESS_HIGH_PRECISION: + CARLA_ENGINE_SET_OPTION_RUNNING_CHECK + options.processHighPrecision = value; + break; + + case OPTION_MAX_PARAMETERS: + CARLA_ENGINE_SET_OPTION_RUNNING_CHECK + options.maxParameters = (value > 0) ? value : MAX_PARAMETERS; + break; + + case OPTION_PREFERRED_BUFFER_SIZE: + CARLA_ENGINE_SET_OPTION_RUNNING_CHECK + options.preferredBufferSize = value; + break; + + case OPTION_PREFERRED_SAMPLE_RATE: + CARLA_ENGINE_SET_OPTION_RUNNING_CHECK + options.preferredSampleRate = value; + break; + + case OPTION_FORCE_STEREO: + CARLA_ENGINE_SET_OPTION_RUNNING_CHECK + options.forceStereo = value; + break; + + case OPTION_USE_DSSI_VST_CHUNKS: + CARLA_ENGINE_SET_OPTION_RUNNING_CHECK + options.useDssiVstChunks = value; + break; + + case OPTION_PREFER_PLUGIN_BRIDGES: + CARLA_ENGINE_SET_OPTION_RUNNING_CHECK + options.preferPluginBridges = value; + break; + + case OPTION_PREFER_UI_BRIDGES: + CARLA_ENGINE_SET_OPTION_RUNNING_CHECK + options.preferUiBridges = value; + break; + + case OPTION_OSC_UI_TIMEOUT: + CARLA_ENGINE_SET_OPTION_RUNNING_CHECK + options.oscUiTimeout = value/100; + break; + + case OPTION_PATH_LADSPA: + carla_setenv("LADSPA_PATH", valueStr); + break; + case OPTION_PATH_DSSI: + carla_setenv("DSSI_PATH", valueStr); + break; + case OPTION_PATH_LV2: + carla_setenv("LV2_PATH", valueStr); + break; + case OPTION_PATH_VST: + carla_setenv("VST_PATH", valueStr); + break; + case OPTION_PATH_GIG: + carla_setenv("GIG_PATH", valueStr); + break; + case OPTION_PATH_SF2: + carla_setenv("SF2_PATH", valueStr); + break; + case OPTION_PATH_SFZ: + carla_setenv("SFZ_PATH", valueStr); + break; + + case OPTION_PATH_BRIDGE_POSIX32: + options.bridge_posix32 = valueStr; + break; + case OPTION_PATH_BRIDGE_POSIX64: + options.bridge_posix64 = valueStr; + break; + case OPTION_PATH_BRIDGE_WIN32: + options.bridge_win32 = valueStr; + break; + case OPTION_PATH_BRIDGE_WIN64: + options.bridge_win64 = valueStr; + break; + case OPTION_PATH_BRIDGE_LV2_GTK2: + options.bridge_lv2gtk2 = valueStr; + break; + case OPTION_PATH_BRIDGE_LV2_GTK3: + options.bridge_lv2gtk3 = valueStr; + break; + case OPTION_PATH_BRIDGE_LV2_QT4: + options.bridge_lv2qt4 = valueStr; + break; + case OPTION_PATH_BRIDGE_LV2_X11: + options.bridge_lv2x11 = valueStr; + break; + case OPTION_PATH_BRIDGE_VST_HWND: + options.bridge_vsthwnd = valueStr; + break; + case OPTION_PATH_BRIDGE_VST_X11: + options.bridge_vstx11 = valueStr; + break; + } +} +#endif // ----------------------------------------------------------------------- // Mutex locks @@ -1083,595 +1288,6 @@ void CarlaEngine::bufferSizeChanged(const uint32_t newBufferSize) } } -void CarlaEngine::startCheckThread() -{ - if (! m_thread.isRunning()) - m_thread.startNow(); -} - -// ------------------------------------------------------------------------------------------------------------------- -// Carla Engine Client - -CarlaEngineClient::CarlaEngineClient(const CarlaEngineClientNativeHandle* handle_) - : handle(handle_) -{ - qDebug("CarlaEngineClient::CarlaEngineClient(%p)", handle); - CARLA_ASSERT(handle); - CARLA_ASSERT(handle->type != CarlaEngineTypeNull); - - m_active = false; - m_latency = 0; -} - -CarlaEngineClient::~CarlaEngineClient() -{ - qDebug("CarlaEngineClient::~CarlaEngineClient()"); - CARLA_ASSERT(handle); - CARLA_ASSERT(! m_active); - -#ifndef BUILD_BRIDGE - if (CarlaEngine::processMode == PROCESS_MODE_MULTIPLE_CLIENTS) -#endif - { -#ifdef CARLA_ENGINE_JACK - if (handle->jackClient) - jackbridge_client_close(handle->jackClient); -#endif - } - - delete handle; -} - -void CarlaEngineClient::activate() -{ - qDebug("CarlaEngineClient::activate()"); - CARLA_ASSERT(! m_active); - -#ifndef BUILD_BRIDGE - if (CarlaEngine::processMode == PROCESS_MODE_MULTIPLE_CLIENTS) -#endif - { - if (! m_active) - { -#ifdef CARLA_ENGINE_JACK - if (handle->jackClient) - jackbridge_activate(handle->jackClient); -#endif - } - } - - m_active = true; -} - -void CarlaEngineClient::deactivate() -{ - qDebug("CarlaEngineClient::deactivate()"); - CARLA_ASSERT(m_active); - -#ifndef BUILD_BRIDGE - if (CarlaEngine::processMode == PROCESS_MODE_MULTIPLE_CLIENTS) -#endif - { - if (m_active) - { -#ifdef CARLA_ENGINE_JACK - if (handle->jackClient) - jackbridge_deactivate(handle->jackClient); -#endif - } - } - - m_active = false; -} - -bool CarlaEngineClient::isActive() const -{ - qDebug("CarlaEngineClient::isActive()"); - - return m_active; -} - -bool CarlaEngineClient::isOk() const -{ - qDebug("CarlaEngineClient::isOk()"); - -#ifndef BUILD_BRIDGE - if (CarlaEngine::processMode != PROCESS_MODE_CONTINUOUS_RACK) -#endif - { -#ifdef CARLA_ENGINE_JACK - if (handle->type == CarlaEngineTypeJack) - return bool(handle->jackClient); -#endif - } - - return true; -} - -uint32_t CarlaEngineClient::getLatency() const -{ - return m_latency; -} - -void CarlaEngineClient::setLatency(const uint32_t samples) -{ - m_latency = samples; - -#ifndef BUILD_BRIDGE - if (CarlaEngine::processMode != PROCESS_MODE_CONTINUOUS_RACK) -#endif - { -#ifdef CARLA_ENGINE_JACK - if (handle->type == CarlaEngineTypeJack) - jackbridge_recompute_total_latencies(handle->jackClient); -#endif - } -} - -const CarlaEngineBasePort* CarlaEngineClient::addPort(const CarlaEnginePortType portType, const char* const name, const bool isInput) -{ - qDebug("CarlaEngineClient::addPort(%i, \"%s\", %s)", portType, name, bool2str(isInput)); - - CarlaEnginePortNativeHandle* portHandle = new CarlaEnginePortNativeHandle; -#ifdef CARLA_ENGINE_JACK - portHandle->jackClient = handle->jackClient; -#endif - -#ifndef BUILD_BRIDGE - if (CarlaEngine::processMode != PROCESS_MODE_CONTINUOUS_RACK) -#endif - { -#ifdef CARLA_ENGINE_JACK - if (handle->type == CarlaEngineTypeJack) - { - switch (portType) - { - case CarlaEnginePortTypeAudio: - portHandle->jackPort = jackbridge_port_register(handle->jackClient, name, JACK_DEFAULT_AUDIO_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0); - break; - case CarlaEnginePortTypeControl: - case CarlaEnginePortTypeMIDI: - portHandle->jackPort = jackbridge_port_register(handle->jackClient, name, JACK_DEFAULT_MIDI_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0); - break; - } - } -#endif - } - - switch (portType) - { - case CarlaEnginePortTypeAudio: - return new CarlaEngineAudioPort(portHandle, isInput); - case CarlaEnginePortTypeControl: - return new CarlaEngineControlPort(portHandle, isInput); - case CarlaEnginePortTypeMIDI: - return new CarlaEngineMidiPort(portHandle, isInput); - } - - qCritical("CarlaEngineClient::addPort(%i, \"%s\", %s) - invalid type", portType, name, bool2str(isInput)); - return nullptr; -} - -// ------------------------------------------------------------------------------------------------------------------- -// Carla Engine Port (Base class) - -CarlaEngineBasePort::CarlaEngineBasePort(const CarlaEnginePortNativeHandle* handle_, const bool isInput_) - : isInput(isInput_), - handle(handle_) -{ - qDebug("CarlaEngineBasePort::CarlaEngineBasePort(%p, %s)", handle, bool2str(isInput_)); - CARLA_ASSERT(handle); - - buffer = nullptr; -} - -CarlaEngineBasePort::~CarlaEngineBasePort() -{ - qDebug("CarlaEngineBasePort::~CarlaEngineBasePort()"); - CARLA_ASSERT(handle); - -#ifndef BUILD_BRIDGE - if (CarlaEngine::processMode == PROCESS_MODE_CONTINUOUS_RACK) - return; -#endif - -#ifdef CARLA_ENGINE_JACK - if (handle->jackClient && handle->jackPort) - jackbridge_port_unregister(handle->jackClient, handle->jackPort); -#endif - - delete handle; -} - -// ------------------------------------------------------------------------------------------------------------------- -// Carla Engine Port (Audio) - -CarlaEngineAudioPort::CarlaEngineAudioPort(const CarlaEnginePortNativeHandle* handle, const bool isInput) - : CarlaEngineBasePort(handle, isInput) -{ - qDebug("CarlaEngineAudioPort::CarlaEngineAudioPort(%p, %s)", handle, bool2str(isInput)); - CARLA_ASSERT(handle); -} - -void CarlaEngineAudioPort::initBuffer(CarlaEngine* const /*engine*/) -{ -} - -#ifdef CARLA_ENGINE_JACK -float* CarlaEngineAudioPort::getJackAudioBuffer(uint32_t nframes) -{ -# ifndef BUILD_BRIDGE - if (CarlaEngine::processMode == PROCESS_MODE_CONTINUOUS_RACK) - return nullptr; -# endif - CARLA_ASSERT(handle->jackPort); - return (float*)jackbridge_port_get_buffer(handle->jackPort, nframes); -} -#endif - -// ------------------------------------------------------------------------------------------------------------------- -// Carla Engine Port (Control) - -CarlaEngineControlPort::CarlaEngineControlPort(const CarlaEnginePortNativeHandle* handle, const bool isInput) - : CarlaEngineBasePort(handle, isInput) -{ - qDebug("CarlaEngineControlPort::CarlaEngineControlPort(%p, %s)", handle, bool2str(isInput)); - CARLA_ASSERT(handle); -} - -void CarlaEngineControlPort::initBuffer(CarlaEngine* const engine) -{ - CARLA_ASSERT(engine); - -#ifndef BUILD_BRIDGE - if (CarlaEngine::processMode == PROCESS_MODE_CONTINUOUS_RACK) - { - buffer = isInput ? engine->rackControlEventsIn : engine->rackControlEventsOut; - return; - } -#endif - -#ifdef CARLA_ENGINE_JACK - if (handle->jackPort) - { - buffer = jackbridge_port_get_buffer(handle->jackPort, engine->getBufferSize()); - - if (! isInput) - jackbridge_midi_clear_buffer(buffer); - } -#endif -} - -uint32_t CarlaEngineControlPort::getEventCount() -{ - if (! isInput) - return 0; - - CARLA_ASSERT(buffer); - -#ifndef BUILD_BRIDGE - if (CarlaEngine::processMode == PROCESS_MODE_CONTINUOUS_RACK) - { - uint32_t count = 0; - const CarlaEngineControlEvent* const events = (CarlaEngineControlEvent*)buffer; - - for (unsigned short i=0; i < CarlaEngine::MAX_ENGINE_CONTROL_EVENTS; i++) - { - if (events[i].type != CarlaEngineEventNull) - count++; - else - break; - } - - return count; - } -#endif - -#ifdef CARLA_ENGINE_JACK - if (handle->jackPort) - return jackbridge_midi_get_event_count(buffer); -#endif - - return 0; -} - -const CarlaEngineControlEvent* CarlaEngineControlPort::getEvent(uint32_t index) -{ - if (! isInput) - return nullptr; - - CARLA_ASSERT(buffer); - -#ifndef BUILD_BRIDGE - CARLA_ASSERT(index < CarlaEngine::MAX_ENGINE_CONTROL_EVENTS); - - if (CarlaEngine::processMode == PROCESS_MODE_CONTINUOUS_RACK) - { - const CarlaEngineControlEvent* const events = (CarlaEngineControlEvent*)buffer; - - if (index < CarlaEngine::MAX_ENGINE_CONTROL_EVENTS) - return &events[index]; - return nullptr; - } -#endif - -#ifdef CARLA_ENGINE_JACK - if (handle->jackPort) - { - static jack_midi_event_t jackEvent; - static CarlaEngineControlEvent carlaEvent; - - if (jackbridge_midi_event_get(&jackEvent, buffer, index) != 0) - return nullptr; - - memset(&carlaEvent, 0, sizeof(CarlaEngineControlEvent)); - - uint8_t midiStatus = jackEvent.buffer[0]; - uint8_t midiChannel = midiStatus & 0x0F; - - carlaEvent.time = jackEvent.time; - carlaEvent.channel = midiChannel; - - if (MIDI_IS_STATUS_CONTROL_CHANGE(midiStatus)) - { - uint8_t midiControl = jackEvent.buffer[1]; - - if (MIDI_IS_CONTROL_BANK_SELECT(midiControl)) - { - uint8_t midiBank = jackEvent.buffer[2]; - carlaEvent.type = CarlaEngineEventMidiBankChange; - carlaEvent.value = midiBank; - } - else if (midiControl == MIDI_CONTROL_ALL_SOUND_OFF) - { - carlaEvent.type = CarlaEngineEventAllSoundOff; - } - else if (midiControl == MIDI_CONTROL_ALL_NOTES_OFF) - { - carlaEvent.type = CarlaEngineEventAllNotesOff; - } - else - { - uint8_t midiValue = jackEvent.buffer[2]; - carlaEvent.type = CarlaEngineEventControlChange; - carlaEvent.controller = midiControl; - carlaEvent.value = double(midiValue)/127; - } - - return &carlaEvent; - } - else if (MIDI_IS_STATUS_PROGRAM_CHANGE(midiStatus)) - { - uint8_t midiProgram = jackEvent.buffer[1]; - carlaEvent.type = CarlaEngineEventMidiProgramChange; - carlaEvent.value = midiProgram; - - return &carlaEvent; - } - } -#endif - - return nullptr; -} - -void CarlaEngineControlPort::writeEvent(CarlaEngineControlEventType type, uint32_t time, uint8_t channel, uint8_t controller, double value) -{ - if (isInput) - return; - - CARLA_ASSERT(buffer); - CARLA_ASSERT(type != CarlaEngineEventNull); - -#ifndef BUILD_BRIDGE - if (CarlaEngine::processMode == PROCESS_MODE_CONTINUOUS_RACK) - { - CarlaEngineControlEvent* const events = (CarlaEngineControlEvent*)buffer; - - for (unsigned short i=0; i < CarlaEngine::MAX_ENGINE_CONTROL_EVENTS; i++) - { - if (events[i].type == CarlaEngineEventNull) - { - events[i].type = type; - events[i].time = time; - events[i].value = value; - events[i].channel = channel; - events[i].controller = controller; - break; - } - } - - return; - } -#endif - -#ifdef CARLA_ENGINE_JACK - if (handle->jackPort) - { - if (type == CarlaEngineEventControlChange && MIDI_IS_CONTROL_BANK_SELECT(controller)) - type = CarlaEngineEventMidiBankChange; - - uint8_t data[4] = { 0 }; - - switch (type) - { - case CarlaEngineEventNull: - break; - case CarlaEngineEventControlChange: - data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; - data[1] = controller; - data[2] = value * 127; - jackbridge_midi_event_write(buffer, time, data, 3); - break; - case CarlaEngineEventMidiBankChange: - data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; - data[1] = MIDI_CONTROL_BANK_SELECT; - data[2] = value; - jackbridge_midi_event_write(buffer, time, data, 3); - break; - case CarlaEngineEventMidiProgramChange: - data[0] = MIDI_STATUS_PROGRAM_CHANGE + channel; - data[1] = value; - jackbridge_midi_event_write(buffer, time, data, 2); - break; - case CarlaEngineEventAllSoundOff: - data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; - data[1] = MIDI_CONTROL_ALL_SOUND_OFF; - jackbridge_midi_event_write(buffer, time, data, 2); - break; - case CarlaEngineEventAllNotesOff: - data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; - data[1] = MIDI_CONTROL_ALL_NOTES_OFF; - jackbridge_midi_event_write(buffer, time, data, 2); - break; - } - } -#endif -} - -// ------------------------------------------------------------------------------------------------------------------- -// Carla Engine Port (MIDI) - -CarlaEngineMidiPort::CarlaEngineMidiPort(const CarlaEnginePortNativeHandle* handle, const bool isInput) - : CarlaEngineBasePort(handle, isInput) -{ - qDebug("CarlaEngineMidiPort::CarlaEngineMidiPort(%p, %s)", handle, bool2str(isInput)); - CARLA_ASSERT(handle); -} - -void CarlaEngineMidiPort::initBuffer(CarlaEngine* const engine) -{ - CARLA_ASSERT(engine); - -#ifndef BUILD_BRIDGE - if (CarlaEngine::processMode == PROCESS_MODE_CONTINUOUS_RACK) - { - buffer = isInput ? engine->rackMidiEventsIn : engine->rackMidiEventsOut; - return; - } -#endif - -#ifdef CARLA_ENGINE_JACK - if (handle->jackPort) - { - buffer = jackbridge_port_get_buffer(handle->jackPort, engine->getBufferSize()); - - if (! isInput) - jackbridge_midi_clear_buffer(buffer); - } -#endif -} - -uint32_t CarlaEngineMidiPort::getEventCount() -{ - if (! isInput) - return 0; - - CARLA_ASSERT(buffer); - -#ifndef BUILD_BRIDGE - if (CarlaEngine::processMode == PROCESS_MODE_CONTINUOUS_RACK) - { - uint32_t count = 0; - const CarlaEngineMidiEvent* const events = (CarlaEngineMidiEvent*)buffer; - - for (unsigned short i=0; i < CarlaEngine::MAX_ENGINE_MIDI_EVENTS; i++) - { - if (events[i].size > 0) - count++; - else - break; - } - - return count; - } -#endif - -#ifdef CARLA_ENGINE_JACK - if (handle->jackPort) - return jackbridge_midi_get_event_count(buffer); -#endif - - return 0; -} - -const CarlaEngineMidiEvent* CarlaEngineMidiPort::getEvent(uint32_t index) -{ - if (! isInput) - return nullptr; - - CARLA_ASSERT(buffer); - -#ifndef BUILD_BRIDGE - CARLA_ASSERT(index < CarlaEngine::MAX_ENGINE_MIDI_EVENTS); - - if (CarlaEngine::processMode == PROCESS_MODE_CONTINUOUS_RACK) - { - const CarlaEngineMidiEvent* const events = (CarlaEngineMidiEvent*)buffer; - - if (index < CarlaEngine::MAX_ENGINE_MIDI_EVENTS) - return &events[index]; - - return nullptr; - } -#endif - -#ifdef CARLA_ENGINE_JACK - if (handle->jackPort) - { - static jack_midi_event_t jackEvent; - static CarlaEngineMidiEvent carlaEvent; - - if (jackbridge_midi_event_get(&jackEvent, buffer, index) == 0 && jackEvent.size <= 4) - { - carlaEvent.time = jackEvent.time; - carlaEvent.size = jackEvent.size; - memcpy(carlaEvent.data, jackEvent.buffer, jackEvent.size); - return &carlaEvent; - } - } -#endif - - return nullptr; -} - -void CarlaEngineMidiPort::writeEvent(uint32_t time, const uint8_t* data, uint8_t size) -{ - if (isInput) - return; - - CARLA_ASSERT(buffer); - CARLA_ASSERT(data); - CARLA_ASSERT(size > 0); - -#ifndef BUILD_BRIDGE - if (CarlaEngine::processMode == PROCESS_MODE_CONTINUOUS_RACK) - { - if (size > 4) - return; - - CarlaEngineMidiEvent* const events = (CarlaEngineMidiEvent*)buffer; - - for (unsigned short i=0; i < CarlaEngine::MAX_ENGINE_MIDI_EVENTS; i++) - { - if (events[i].size == 0) - { - events[i].time = time; - events[i].size = size; - memcpy(events[i].data, data, size); - break; - } - } - - return; - } -#endif - -#ifdef CARLA_ENGINE_JACK - if (handle->jackPort) - jackbridge_midi_event_write(buffer, time, data, size); -#endif -} - // ------------------------------------------------------------------------------------------------------------------- // Carla Engine OSC stuff @@ -1989,9 +1605,9 @@ void CarlaEngine::osc_send_control_note_off(const int32_t pluginId, const int32_ } } -void CarlaEngine::osc_send_control_set_input_peak_value(const int32_t pluginId, const int32_t portId, const double value) +void CarlaEngine::osc_send_control_set_input_peak_value(const int32_t pluginId, const int32_t portId) { - //qDebug("CarlaEngine::osc_send_control_set_input_peak_value(%i, %i, %g)", pluginId, portId, value); + //qDebug("CarlaEngine::osc_send_control_set_input_peak_value(%i, %i)", pluginId, portId); CARLA_ASSERT(m_oscData); CARLA_ASSERT(pluginId >= 0 && pluginId < m_maxPluginNumber); CARLA_ASSERT(portId == 1 || portId == 2); @@ -2001,13 +1617,13 @@ void CarlaEngine::osc_send_control_set_input_peak_value(const int32_t pluginId, char target_path[strlen(m_oscData->path)+22]; strcpy(target_path, m_oscData->path); strcat(target_path, "/set_input_peak_value"); - lo_send(m_oscData->target, target_path, "iid", pluginId, portId, value); + lo_send(m_oscData->target, target_path, "iid", pluginId, portId, m_insPeak[pluginId*MAX_PEAKS + portId-1]); } } -void CarlaEngine::osc_send_control_set_output_peak_value(const int32_t pluginId, const int32_t portId, const double value) +void CarlaEngine::osc_send_control_set_output_peak_value(const int32_t pluginId, const int32_t portId) { - //qDebug("CarlaEngine::osc_send_control_set_output_peak_value(%i, %i, %g)", pluginId, portId, value); + //qDebug("CarlaEngine::osc_send_control_set_output_peak_value(%i, %i)", pluginId, portId); CARLA_ASSERT(m_oscData); CARLA_ASSERT(pluginId >= 0 && pluginId < m_maxPluginNumber); CARLA_ASSERT(portId == 1 || portId == 2); @@ -2017,7 +1633,7 @@ void CarlaEngine::osc_send_control_set_output_peak_value(const int32_t pluginId, char target_path[strlen(m_oscData->path)+23]; strcpy(target_path, m_oscData->path); strcat(target_path, "/set_output_peak_value"); - lo_send(m_oscData->target, target_path, "iid", pluginId, portId, value); + lo_send(m_oscData->target, target_path, "iid", pluginId, portId, m_outsPeak[pluginId*MAX_PEAKS + portId-1]); } } @@ -2300,7 +1916,7 @@ void CarlaEngine::osc_send_bridge_set_chunk_data(const char* const chunkFile) } } -void CarlaEngine::osc_send_bridge_set_inpeak(const int32_t portId, const double value) +void CarlaEngine::osc_send_bridge_set_inpeak(const int32_t portId) { CARLA_ASSERT(m_oscData); CARLA_ASSERT(portId == 1 || portId == 2); @@ -2310,11 +1926,11 @@ void CarlaEngine::osc_send_bridge_set_inpeak(const int32_t portId, const double char target_path[strlen(m_oscData->path)+28]; strcpy(target_path, m_oscData->path); strcat(target_path, "/bridge_set_inpeak"); - lo_send(m_oscData->target, target_path, "id", portId, value); + lo_send(m_oscData->target, target_path, "id", portId, m_insPeak[portId-1]); } } -void CarlaEngine::osc_send_bridge_set_outpeak(const int32_t portId, const double value) +void CarlaEngine::osc_send_bridge_set_outpeak(const int32_t portId) { CARLA_ASSERT(m_oscData); CARLA_ASSERT(portId == 1 || portId == 2); @@ -2324,7 +1940,7 @@ void CarlaEngine::osc_send_bridge_set_outpeak(const int32_t portId, const double char target_path[strlen(m_oscData->path)+29]; strcpy(target_path, m_oscData->path); strcat(target_path, "/bridge_set_outpeak"); - lo_send(m_oscData->target, target_path, "id", portId, value); + lo_send(m_oscData->target, target_path, "id", portId, m_insPeak[portId-1]); } } #endif diff --git a/c++/carla-engine/carla_engine.doxygen b/c++/carla-engine/carla_engine.doxygen index 3d0215b..6df3c55 100644 --- a/c++/carla-engine/carla_engine.doxygen +++ b/c++/carla-engine/carla_engine.doxygen @@ -241,7 +241,7 @@ EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = -PREDEFINED = DOXYGEN +PREDEFINED = DOXYGEN CARLA_ENGINE_JACK CARLA_ENGINE_RTAUDIO EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- diff --git a/c++/carla-engine/carla_engine.hpp b/c++/carla-engine/carla_engine.hpp index 0c79f48..8f5bad4 100644 --- a/c++/carla-engine/carla_engine.hpp +++ b/c++/carla-engine/carla_engine.hpp @@ -21,15 +21,6 @@ #include "carla_engine_osc.hpp" #include "carla_engine_thread.hpp" -//#ifdef CARLA_ENGINE_JACK -//typedef struct _jack_client jack_client_t; -//typedef struct _jack_port jack_port_t; -//#endif - -#ifdef CARLA_ENGINE_RTAUDIO -typedef int RtAudioApi; -#endif - CARLA_BACKEND_START_NAMESPACE /*! @@ -48,28 +39,99 @@ CARLA_BACKEND_START_NAMESPACE const uint32_t CarlaEngineTimeBBT = 0x1; /**@}*/ +/*! + * The type of an engine. + */ enum CarlaEngineType { - CarlaEngineTypeNull, - CarlaEngineTypeJack, - CarlaEngineTypeRtAudio, - CarlaEngineTypePlugin + /*! + * Null engine type. + */ + CarlaEngineTypeNull = 0, + + /*! + * Jack engine type.\n + * Provides single, multi-client, and rack processing modes. + */ + CarlaEngineTypeJack = 1, + + /*! + * RtAudio engine type, used to provide ALSA, PulseAudio, DirectSound, ASIO and CoreAudio/Midi support.\n + * Provides rack mode processing only. + */ + CarlaEngineTypeRtAudio = 2, + + /*! + * Plugin engine type, used to export the engine as a plugin (DSSI, LV2 and VST) via the DISTRHO Plugin Toolkit.\n + * Works in rack mode only. + */ + CarlaEngineTypePlugin = 3 }; +/*! + * The type of an engine port. + */ enum CarlaEnginePortType { - CarlaEnginePortTypeAudio, - CarlaEnginePortTypeControl, - CarlaEnginePortTypeMIDI + /*! + * Null engine port type. + */ + CarlaEnginePortTypeNull = 0, + + /*! + * Audio port. + */ + CarlaEnginePortTypeAudio = 1, + + /*! + * Control port.\n + * These are MIDI ports on some engine types, by handling MIDI-CC as control. + */ + CarlaEnginePortTypeControl = 2, + + /*! + * MIDI port. + */ + CarlaEnginePortTypeMIDI = 3 }; +/*! + * The type of a control event. + */ enum CarlaEngineControlEventType { - CarlaEngineEventNull = 0, - CarlaEngineEventControlChange, - CarlaEngineEventMidiBankChange, - CarlaEngineEventMidiProgramChange, - CarlaEngineEventAllSoundOff, - CarlaEngineEventAllNotesOff + /*! + * Null event type. + */ + CarlaEngineNullEvent = 0, + + /*! + * Parameter change event.\n + * \note Value uses a range of 0.0<->1.0. + */ + CarlaEngineParameterChangeEvent = 1, + + /*! + * MIDI Bank change event. + */ + CarlaEngineMidiBankChangeEvent = 2, + + /*! + * MIDI Program change event. + */ + CarlaEngineMidiProgramChangeEvent = 3, + + /*! + * All sound off event. + */ + CarlaEngineAllSoundOffEvent = 4, + + /*! + * All notes off event. + */ + CarlaEngineAllNotesOffEvent = 5 }; +/*! + * Engine control event. + */ struct CarlaEngineControlEvent { CarlaEngineControlEventType type; uint32_t time; @@ -78,29 +140,35 @@ struct CarlaEngineControlEvent { double value; CarlaEngineControlEvent() - : type(CarlaEngineEventNull), + : type(CarlaEngineNullEvent), time(0), channel(0), controller(0), value(0.0) {} }; +/*! + * Engine MIDI event. + */ struct CarlaEngineMidiEvent { uint32_t time; uint8_t size; - uint8_t data[4]; + uint8_t data[3]; CarlaEngineMidiEvent() : time(0), - #ifdef Q_COMPILER_INITIALIZER_LISTS +#ifdef Q_COMPILER_INITIALIZER_LISTS size(0), data{0} {} - #else - size(0) { data[0] = data[1] = data[2] = data[3] = 0; } - #endif +#else + size(0) { data[0] = data[1] = data[2] = 0; } +#endif }; -struct CarlaTimeInfoBBT { +/*! + * Engine BBT Time information. + */ +struct CarlaEngineTimeInfoBBT { int32_t bar; int32_t beat; int32_t tick; @@ -110,7 +178,7 @@ struct CarlaTimeInfoBBT { double ticks_per_beat; double beats_per_minute; - CarlaTimeInfoBBT() + CarlaEngineTimeInfoBBT() : bar(0), beat(0), tick(0), @@ -121,26 +189,29 @@ struct CarlaTimeInfoBBT { beats_per_minute(0.0) {} }; -struct CarlaTimeInfo { +/*! + * Engine Time information. + */ +struct CarlaEngineTimeInfo { bool playing; uint32_t frame; uint32_t time; uint32_t valid; - CarlaTimeInfoBBT bbt; + CarlaEngineTimeInfoBBT bbt; - CarlaTimeInfo() + CarlaEngineTimeInfo() : playing(false), frame(0), time(0), valid(0) {} }; -struct CarlaEngineClientNativeHandle; -struct CarlaEnginePortNativeHandle; - #ifndef BUILD_BRIDGE -// Global options +/*! + * Engine options. + */ struct CarlaEngineOptions { + ProcessMode processMode; bool processHighPrecision; uint maxParameters; @@ -154,19 +225,20 @@ struct CarlaEngineOptions { bool preferUiBridges; uint oscUiTimeout; - const char* bridge_posix32; - const char* bridge_posix64; - const char* bridge_win32; - const char* bridge_win64; - const char* bridge_lv2gtk2; - const char* bridge_lv2gtk3; - const char* bridge_lv2qt4; - const char* bridge_lv2x11; - const char* bridge_vsthwnd; - const char* bridge_vstx11; + CarlaString bridge_posix32; + CarlaString bridge_posix64; + CarlaString bridge_win32; + CarlaString bridge_win64; + CarlaString bridge_lv2gtk2; + CarlaString bridge_lv2gtk3; + CarlaString bridge_lv2qt4; + CarlaString bridge_lv2x11; + CarlaString bridge_vsthwnd; + CarlaString bridge_vstx11; CarlaEngineOptions() - : processHighPrecision(false), + : processMode(PROCESS_MODE_CONTINUOUS_RACK), + processHighPrecision(false), maxParameters(MAX_PARAMETERS), preferredBufferSize(512), preferredSampleRate(44100), @@ -174,71 +246,344 @@ struct CarlaEngineOptions { useDssiVstChunks(false), preferPluginBridges(false), preferUiBridges(true), - oscUiTimeout(4000/100), - bridge_posix32(nullptr), - bridge_posix64(nullptr), - bridge_win32(nullptr), - bridge_win64(nullptr), - bridge_lv2gtk2(nullptr), - bridge_lv2gtk3(nullptr), - bridge_lv2qt4(nullptr), - bridge_lv2x11(nullptr), - bridge_vsthwnd(nullptr), - bridge_vstx11(nullptr) {} + oscUiTimeout(4000/100) {} + +// void reset() +// { +// processMode = PROCESS_MODE_CONTINUOUS_RACK; +// processHighPrecision = false; +// maxParameters = MAX_PARAMETERS; +// preferredBufferSize = 512; +// preferredSampleRate = 44100; +// forceStereo = false; +// useDssiVstChunks = false; +// preferPluginBridges = false; +// preferUiBridges = true; +// oscUiTimeout = 4000/100; + +// bridge_posix32.clear(); +// bridge_posix64.clear(); +// bridge_win32.clear(); +// bridge_win64.clear(); +// bridge_lv2gtk2.clear(); +// bridge_lv2gtk3.clear(); +// bridge_lv2qt4.clear(); +// bridge_lv2x11.clear(); +// bridge_vsthwnd.clear(); +// bridge_vstx11.clear(); +// } }; #endif // ----------------------------------------------------------------------- -class CarlaEngineClient; -class CarlaEngineBasePort; +/*! + * Engine port (Base).\n + * This is the base class for all Carla engine ports. + */ +class CarlaEngineBasePort +{ +public: + /*! + * The contructor.\n + * Param \a isInput defines wherever this is an input port or not (output otherwise).\n + * Input/output state is constant for the lifetime of the port. + */ + CarlaEngineBasePort(const bool isInput, const ProcessMode processMode); + + /*! + * The decontructor. + */ + virtual ~CarlaEngineBasePort(); + + /*! + * Get the type of the port, as provided by the respective subclasses. + */ + virtual CarlaEnginePortType type() = 0; + + /*! + * Initialize the port's internal buffer for \a engine. + */ + virtual void initBuffer(CarlaEngine* const engine) = 0; + +protected: + const bool isInput; + const ProcessMode processMode; + void* buffer; +}; + +// ----------------------------------------------------------------------- /*! - * \class CarlaEngine - * - * \brief Carla Backend base engine class - * - * This is the base class for all available engine types available in Carla Backend. + * Engine port (Audio). + */ +class CarlaEngineAudioPort : public CarlaEngineBasePort +{ +public: + /*! + * The contructor.\n + * Param \a isInput defines wherever this is an input port or not (output otherwise).\n + * Input/output state is constant for the lifetime of the port. + */ + CarlaEngineAudioPort(const bool isInput, const ProcessMode processMode); + + /*! + * The decontructor. + */ + virtual ~CarlaEngineAudioPort(); + + /*! + * Get the type of the port, in this case CarlaEnginePortTypeAudio. + */ + CarlaEnginePortType type() + { + return CarlaEnginePortTypeAudio; + } + + /*! + * Initialize the port's internal buffer for \a engine. + */ + virtual void initBuffer(CarlaEngine* const engine); +}; + +// ----------------------------------------------------------------------- + +/*! + * Engine port (Control). + */ +class CarlaEngineControlPort : public CarlaEngineBasePort +{ +public: + /*! + * The contructor.\n + * Param \a isInput defines wherever this is an input port or not (output otherwise).\n + * Input/output state is constant for the lifetime of the port. + */ + CarlaEngineControlPort(const bool isInput, const ProcessMode processMode); + + /*! + * The decontructor. + */ + virtual ~CarlaEngineControlPort(); + + /*! + * Get the type of the port, in this case CarlaEnginePortTypeControl. + */ + CarlaEnginePortType type() + { + return CarlaEnginePortTypeControl; + } + + /*! + * Initialize the port's internal buffer for \a engine. + */ + virtual void initBuffer(CarlaEngine* const engine); + + /*! + * Get the number of control events present in the buffer. + * \note You must only call this for input ports. + */ + virtual uint32_t getEventCount(); + + /*! + * Get the control event at \a index. + ** \note You must only call this for input ports. + */ + virtual const CarlaEngineControlEvent* getEvent(uint32_t index); + + /*! + * Write a control event to the buffer.\n + * Arguments are the same as in the CarlaEngineControlEvent struct. + ** \note You must only call this for output ports. + */ + virtual void writeEvent(CarlaEngineControlEventType type, uint32_t time, uint8_t channel, uint16_t controller, double value); +}; + +// ----------------------------------------------------------------------- + +/*! + * Engine port (MIDI). + */ +class CarlaEngineMidiPort : public CarlaEngineBasePort +{ +public: + /*! + * The contructor.\n + * Param \a isInput defines wherever this is an input port or not (output otherwise).\n + * Input/output state is constant for the lifetime of the port. + */ + CarlaEngineMidiPort(const bool isInput, const ProcessMode processMode); + + /*! + * The decontructor. + */ + virtual ~CarlaEngineMidiPort(); + + /*! + * Get the type of the port, in this case CarlaEnginePortTypeMIDI. + */ + CarlaEnginePortType type() + { + return CarlaEnginePortTypeMIDI; + } + + /*! + * Initialize the port's internal buffer for \a engine. + */ + virtual void initBuffer(CarlaEngine* const engine); + + /*! + * Get the number of MIDI events present in the buffer. + * \note You must only call this for input ports. + */ + virtual uint32_t getEventCount(); + + /*! + * Get the MIDI event at \a index. + ** \note You must only call this for input ports. + */ + virtual const CarlaEngineMidiEvent* getEvent(uint32_t index); + + /*! + * Write a MIDI event to the buffer.\n + * Arguments are the same as in the CarlaEngineMidiEvent struct. + ** \note You must only call this for output ports. + */ + virtual void writeEvent(uint32_t time, const uint8_t* data, uint8_t size); +}; + +// ----------------------------------------------------------------------- + +/*! + * Engine client.\n + * Each plugin requires one client from the engine (created via CarlaEngine::addPort()).\n + * \note This is a virtual class, each engine type provides its own funtionality. + */ +class CarlaEngineClient +{ +public: + /*! + * The contructor.\n + * All constructor parameters are constant and will never change in the lifetime of the client.\n + * Client starts in deactivated state. + */ + CarlaEngineClient(const CarlaEngineType engineType, const ProcessMode processMode); + + /*! + * The decontructor. + */ + virtual ~CarlaEngineClient(); + + /*! + * Activate this client.\n + * \note Client must be deactivated before calling this function. + */ + virtual void activate(); + + /*! + * Deactivate this client.\n + * \note Client must be activated before calling this function. + */ + virtual void deactivate(); + + /*! + * Check if the client is activated. + */ + virtual bool isActive() const; + + /*! + * Check if the client is ok.\n + * Plugins will refuse to instantiate if this returns false. + * \note This is always true in rack and patchbay processing modes. + */ + virtual bool isOk() const; + + /*! + * Get the current latency, in samples. + */ + virtual uint32_t getLatency() const; + + /*! + * Change the client's latency. + */ + virtual void setLatency(const uint32_t samples); + + /*! + * Add a new port of type \a portType. + * \note This function does nothing in rack processing mode since its ports are static (2 audio, 1 midi and 1 control for both input and output). + */ + virtual const CarlaEngineBasePort* addPort(const CarlaEnginePortType portType, const char* const name, const bool isInput) = 0; + +protected: + const CarlaEngineType engineType; + const ProcessMode processMode; + +private: + bool m_active; + uint32_t m_latency; +}; + +// ----------------------------------------------------------------------- + +/*! + * Carla Engine. + * \note This is a virtual class for all available engine types available in Carla. */ class CarlaEngine { public: + /*! + * The contructor.\n + * \note This only initializes engine data, it doesn't initialize the engine itself. + */ CarlaEngine(); + + /*! + * The decontructor. + * The engine must have been closed before this happens. + */ virtual ~CarlaEngine(); // ------------------------------------------------------------------- // Static values + /*! + * Maximum number of peaks per plugin.\n + * \note There are both input and output peaks. + */ static const unsigned short MAX_PEAKS = 2; - static int maxClientNameSize(); - static int maxPortNameSize(); - static unsigned short maxPluginNumber(); - static const char* getFixedClientName(const char* const clientName); - + /*! + * Get the number of available engine drivers. + */ static unsigned int getDriverCount(); - static const char* getDriverName(unsigned int index); - static CarlaEngine* newDriverByName(const char* driverName); -#ifndef BUILD_BRIDGE - // ------------------------------------------------------------------- - // Global options + /*! + * Get the name of the engine driver at \a index. + */ + static const char* getDriverName(unsigned int index); - CarlaEngineOptions options; - static ProcessModeType processMode; + /*! + * Create a new engine, using driver \a driverName. + */ + static CarlaEngine* newDriverByName(const char* const driverName); - void setOption(const OptionsType option, const int value, const char* const valueStr); - void resetOptions(); -#endif + // ------------------------------------------------------------------- + // Maximum values + + virtual int maxClientNameSize(); + virtual int maxPortNameSize(); + unsigned short maxPluginNumber(); // ------------------------------------------------------------------- // Virtual, per-engine type calls virtual bool init(const char* const clientName); virtual bool close(); - virtual bool isOffline() = 0; - virtual bool isRunning() = 0; + virtual bool isOffline() const = 0; + virtual bool isRunning() const = 0; + virtual CarlaEngineType type() const = 0; virtual CarlaEngineClient* addClient(CarlaPlugin* const plugin) = 0; // ------------------------------------------------------------------- @@ -267,11 +612,10 @@ public: // ------------------------------------------------------------------- // Information (base) - CarlaEngineType getType() const; const char* getName() const; double getSampleRate() const; uint32_t getBufferSize() const; - const CarlaTimeInfo* getTimeInfo() const; + const CarlaEngineTimeInfo* getTimeInfo() const; // ------------------------------------------------------------------- // Information (audio peaks) @@ -293,6 +637,18 @@ public: const char* getLastError() const; void setLastError(const char* const error); +#ifndef BUILD_BRIDGE + // ------------------------------------------------------------------- + // Options + + void setOption(const OptionsType option, const int value, const char* const valueStr); + + ProcessMode processMode() const + { + return options.processMode; + } +#endif + // ------------------------------------------------------------------- // Mutex locks @@ -333,8 +689,8 @@ public: void osc_send_bridge_set_midi_program(const int32_t index); void osc_send_bridge_set_custom_data(const char* const stype, const char* const key, const char* const value); void osc_send_bridge_set_chunk_data(const char* const chunkFile); - void osc_send_bridge_set_inpeak(const int32_t portId, const double value); - void osc_send_bridge_set_outpeak(const int32_t portId, const double value); + void osc_send_bridge_set_inpeak(const int32_t portId); + void osc_send_bridge_set_outpeak(const int32_t portId); #else void osc_send_control_add_plugin_start(const int32_t pluginId, const char* const pluginName); void osc_send_control_add_plugin_end(const int32_t pluginId); @@ -355,8 +711,8 @@ public: void osc_send_control_set_midi_program_data(const int32_t pluginId, const int32_t index, const int32_t bank, const int32_t program, const char* const name); void osc_send_control_note_on(const int32_t pluginId, const int32_t channel, const int32_t note, const int32_t velo); void osc_send_control_note_off(const int32_t pluginId, const int32_t channel, const int32_t note); - void osc_send_control_set_input_peak_value(const int32_t pluginId, const int32_t portId, const double value); - void osc_send_control_set_output_peak_value(const int32_t pluginId, const int32_t portId, const double value); + void osc_send_control_set_input_peak_value(const int32_t pluginId, const int32_t portId); + void osc_send_control_set_output_peak_value(const int32_t pluginId, const int32_t portId); void osc_send_control_exit(); #endif @@ -392,35 +748,35 @@ public: * \param lock Wherever to lock the engine or not, true by default */ ScopedLocker(CarlaEngine* const engine, bool lock = true) - : m_engine(engine), + : mutex(&engine->m_procLock), m_lock(lock) { if (m_lock) - m_engine->processLock(); + mutex->lock(); } ~ScopedLocker() { if (m_lock) - m_engine->processUnlock(); + mutex->unlock(); } private: - CarlaEngine* const m_engine; + QMutex* const mutex; const bool m_lock; }; // ------------------------------------- protected: - CarlaEngineType type; - const char* name; + CarlaEngineOptions options; + + CarlaString name; uint32_t bufferSize; double sampleRate; - CarlaTimeInfo timeInfo; + CarlaEngineTimeInfo timeInfo; void bufferSizeChanged(const uint32_t newBufferSize); - void startCheckThread(); private: CarlaEngineThread m_thread; @@ -433,7 +789,7 @@ private: CallbackFunc m_callback; void* m_callbackPtr; - carla_string m_lastError; + CarlaString m_lastError; QMutex m_procLock; QMutex m_midiLock; @@ -444,104 +800,29 @@ private: double m_insPeak[MAX_PLUGINS * MAX_PEAKS]; double m_outsPeak[MAX_PLUGINS * MAX_PEAKS]; - static unsigned short m_maxPluginNumber; + unsigned short m_maxPluginNumber; #ifdef CARLA_ENGINE_JACK static CarlaEngine* newJack(); #endif #ifdef CARLA_ENGINE_RTAUDIO - static CarlaEngine* newRtAudio(RtAudioApi api); -#endif -}; - -// ----------------------------------------------------------------------- - -class CarlaEngineClient -{ -public: - CarlaEngineClient(const CarlaEngineClientNativeHandle* handle); - ~CarlaEngineClient(); - - void activate(); - void deactivate(); - - bool isActive() const; - bool isOk() const; - - uint32_t getLatency() const; - void setLatency(const uint32_t samples); - - const CarlaEngineBasePort* addPort(const CarlaEnginePortType portType, const char* const name, const bool isInput); - -private: - bool m_active; - uint32_t m_latency; - const CarlaEngineClientNativeHandle* handle; -}; - -// ----------------------------------------------------------------------- - -// base -class CarlaEngineBasePort -{ -public: - CarlaEngineBasePort(const CarlaEnginePortNativeHandle* handle, const bool isInput); - virtual ~CarlaEngineBasePort(); - - virtual void initBuffer(CarlaEngine* const engine) = 0; - - const CarlaEnginePortNativeHandle* getHandle() const - { - return handle; - } - -protected: - void* buffer; - const bool isInput; - const CarlaEnginePortNativeHandle* handle; -}; - -// audio -class CarlaEngineAudioPort : public CarlaEngineBasePort -{ -public: - CarlaEngineAudioPort(const CarlaEnginePortNativeHandle* handle, const bool isInput); - - void initBuffer(CarlaEngine* const engine); + enum RtAudioApi { + RTAUDIO_DUMMY = 0, + RTAUDIO_LINUX_ALSA = 1, + RTAUDIO_LINUX_PULSE = 2, + RTAUDIO_LINUX_OSS = 3, + RTAUDIO_UNIX_JACK = 4, + RTAUDIO_MACOSX_CORE = 5, + RTAUDIO_WINDOWS_ASIO = 6, + RTAUDIO_WINDOWS_DS = 7 + }; -#ifdef CARLA_ENGINE_JACK - float* getJackAudioBuffer(uint32_t nframes); + static CarlaEngine* newRtAudio(RtAudioApi api); + static unsigned int getRtAudioApiCount(); + static const char* getRtAudioApiName(unsigned int index); #endif }; -// control -class CarlaEngineControlPort : public CarlaEngineBasePort -{ -public: - CarlaEngineControlPort(const CarlaEnginePortNativeHandle* handle, const bool isInput); - - void initBuffer(CarlaEngine* const engine); - - uint32_t getEventCount(); - const CarlaEngineControlEvent* getEvent(uint32_t index); - - void writeEvent(CarlaEngineControlEventType type, uint32_t time, uint8_t channel, uint8_t controller, double value); -}; - -// midi -class CarlaEngineMidiPort : public CarlaEngineBasePort -{ -public: - CarlaEngineMidiPort(const CarlaEnginePortNativeHandle* handle, const bool isInput); - - void initBuffer(CarlaEngine* const engine); - - uint32_t getEventCount(); - const CarlaEngineMidiEvent* getEvent(uint32_t index); - - void writeEvent(uint32_t time, const uint8_t* data, uint8_t size); -}; - // ----------------------------------------------------------------------- /**@}*/ diff --git a/c++/carla-engine/carla_engine.pro b/c++/carla-engine/carla_engine.pro index 2921114..d97fa7f 100644 --- a/c++/carla-engine/carla_engine.pro +++ b/c++/carla-engine/carla_engine.pro @@ -26,7 +26,8 @@ SOURCES = \ carla_engine_osc.cpp \ carla_engine_thread.cpp \ jack.cpp \ - rtaudio.cpp + rtaudio.cpp \ + plugin.cpp HEADERS = \ carla_engine.hpp \ @@ -48,4 +49,7 @@ INCLUDEPATH += rtmidi-2.0.1 SOURCES += rtaudio-4.0.11/RtAudio.cpp SOURCES += rtmidi-2.0.1/RtMidi.cpp +# Plugin +INCLUDEPATH += distrho-plugin-toolkit + QMAKE_CXXFLAGS *= -std=c++0x diff --git a/c++/carla-engine/carla_engine_osc.cpp b/c++/carla-engine/carla_engine_osc.cpp index a94111f..f9a4531 100644 --- a/c++/carla-engine/carla_engine_osc.cpp +++ b/c++/carla-engine/carla_engine_osc.cpp @@ -1,5 +1,5 @@ /* - * Carla Engine + * Carla Engine OSC * Copyright (C) 2011-2012 Filipe Coelho * * This program is free software; you can redistribute it and/or modify @@ -40,8 +40,6 @@ CarlaEngineOsc::CarlaEngineOsc(CarlaEngine* const engine_) m_serverTCP = nullptr; m_serverUDP = nullptr; - m_serverPathTCP = nullptr; - m_serverPathUDP = nullptr; m_controlData.path = nullptr; m_controlData.source = nullptr; m_controlData.target = nullptr; @@ -60,28 +58,30 @@ void CarlaEngineOsc::init(const char* const name) qDebug("CarlaEngineOsc::init(\"%s\")", name); CARLA_ASSERT(! m_serverTCP); CARLA_ASSERT(! m_serverUDP); - CARLA_ASSERT(! m_serverPathTCP); - CARLA_ASSERT(! m_serverPathUDP); - CARLA_ASSERT(name); + CARLA_ASSERT(m_serverPathTCP.isEmpty()); + CARLA_ASSERT(m_serverPathUDP.isEmpty()); CARLA_ASSERT(m_nameSize == 0); + CARLA_ASSERT(name); m_name = strdup(name ? name : ""); m_nameSize = strlen(m_name); - // create new OSC thread + // create new OSC severs m_serverTCP = lo_server_new_with_proto(nullptr, LO_TCP, osc_error_handlerTCP); m_serverUDP = lo_server_new_with_proto(nullptr, LO_UDP, osc_error_handlerUDP); - // get our full OSC server path + // get our full OSC servers path char* const serverPathTCP = lo_server_get_url(m_serverTCP); - m_serverPathTCP = strdup(QString("%1%2").arg(serverPathTCP).arg(m_name).toUtf8().constData()); + m_serverPathTCP = serverPathTCP; + m_serverPathTCP += m_name; free(serverPathTCP); char* const serverPathUDP = lo_server_get_url(m_serverUDP); - m_serverPathUDP = strdup(QString("%1%2").arg(serverPathUDP).arg(m_name).toUtf8().constData()); + m_serverPathUDP = serverPathUDP; + m_serverPathUDP += m_name; free(serverPathUDP); - // register message handler and start OSC thread + // register message handler lo_server_add_method(m_serverTCP, nullptr, nullptr, osc_message_handler, this); lo_server_add_method(m_serverUDP, nullptr, nullptr, osc_message_handler, this); } @@ -110,8 +110,8 @@ void CarlaEngineOsc::close() qDebug("CarlaEngineOsc::close()"); CARLA_ASSERT(m_serverTCP); CARLA_ASSERT(m_serverUDP); - CARLA_ASSERT(m_serverPathTCP); - CARLA_ASSERT(m_serverPathUDP); + CARLA_ASSERT(m_serverPathTCP.isNotEmpty()); + CARLA_ASSERT(m_serverPathUDP.isNotEmpty()); CARLA_ASSERT(m_name); m_controlData.free(); @@ -121,13 +121,10 @@ void CarlaEngineOsc::close() lo_server_thread_free(m_serverTCP); lo_server_thread_free(m_serverUDP); - free((void*)m_serverPathTCP); - free((void*)m_serverPathUDP); - m_serverTCP = nullptr; m_serverUDP = nullptr; - m_serverPathTCP = nullptr; - m_serverPathUDP = nullptr; + m_serverPathTCP.clear(); + m_serverPathUDP.clear(); free(m_name); m_name = nullptr; @@ -143,7 +140,8 @@ int CarlaEngineOsc::handleMessage(const char* const path, const int argc, const qDebug("CarlaEngineOsc::handleMessage(%s, %i, %p, %s, %p)", path, argc, argv, types, msg); #endif CARLA_ASSERT(m_serverTCP || m_serverUDP); - CARLA_ASSERT(m_serverPathTCP || m_serverPathUDP); + CARLA_ASSERT(m_serverPathTCP.isNotEmpty() || m_serverPathUDP.isNotEmpty()); + CARLA_ASSERT(m_name); CARLA_ASSERT(path); if (! path) @@ -176,7 +174,7 @@ int CarlaEngineOsc::handleMessage(const char* const path, const int argc, const if (std::isdigit(path[m_nameSize+3])) pluginId += (path[m_nameSize+3]-'0')*10; - if (pluginId < 0 || pluginId > CarlaEngine::maxPluginNumber()) + if (pluginId < 0 || pluginId > engine->maxPluginNumber()) { qCritical("CarlaEngineOsc::handleMessage() - failed to get plugin, wrong id '%i'", pluginId); return 1; @@ -334,8 +332,7 @@ int CarlaEngineOsc::handleMsgRegister(const int argc, const lo_arg* const* const free((void*)host); free((void*)port); - // FIXME - max plugins - for (unsigned short i=0; i < CarlaEngine::maxPluginNumber(); i++) + for (unsigned short i=0; i < engine->maxPluginNumber(); i++) { CarlaPlugin* const plugin = engine->getPluginUnchecked(i); diff --git a/c++/carla-engine/carla_engine_osc.hpp b/c++/carla-engine/carla_engine_osc.hpp index 5f02897..858db6b 100644 --- a/c++/carla-engine/carla_engine_osc.hpp +++ b/c++/carla-engine/carla_engine_osc.hpp @@ -1,6 +1,6 @@ /* - * Carla Engine - * Copyright (C) 2011-2012 Filipe Coelho + * Carla Engine OSC + * Copyright (C) 2012 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 @@ -22,7 +22,7 @@ #include "carla_osc_utils.hpp" #define CARLA_ENGINE_OSC_HANDLE_ARGS1 CarlaPlugin* const plugin -#define CARLA_ENGINE_OSC_HANDLE_ARGS2 CARLA_ENGINE_OSC_HANDLE_ARGS1, const int argc, const lo_arg* const* const argv, const char* const types +#define CARLA_ENGINE_OSC_HANDLE_ARGS2 CarlaPlugin* const plugin, const int argc, const lo_arg* const* const argv, const char* const types #define CARLA_ENGINE_OSC_CHECK_OSC_TYPES(/* argc, types, */ argcToCompare, typesToCompare) \ /* check argument count */ \ @@ -91,8 +91,8 @@ private: lo_server m_serverTCP; lo_server m_serverUDP; - const char* m_serverPathTCP; - const char* m_serverPathUDP; + CarlaString m_serverPathTCP; + CarlaString m_serverPathUDP; CarlaOscData m_controlData; // for carla-control char* m_name; diff --git a/c++/carla-engine/carla_engine_thread.cpp b/c++/carla-engine/carla_engine_thread.cpp index 8c8b8a2..2f76637 100644 --- a/c++/carla-engine/carla_engine_thread.cpp +++ b/c++/carla-engine/carla_engine_thread.cpp @@ -1,5 +1,5 @@ /* - * Carla Engine + * Carla Engine Thread * Copyright (C) 2012 Filipe Coelho * * This program is free software; you can redistribute it and/or modify @@ -80,7 +80,7 @@ void CarlaEngineThread::run() const ScopedLocker m(this); oscControlRegisted = engine->isOscControlRegisted(); - for (unsigned short i=0, max = CarlaEngine::maxPluginNumber(); i < max; i++) + for (unsigned short i=0; i < engine->maxPluginNumber(); i++) { CarlaPlugin* const plugin = engine->getPluginUnchecked(i); @@ -124,7 +124,7 @@ void CarlaEngineThread::run() } // ------------------------------------------------------- - // Update OSC control client + // Update OSC control client (peaks) if (oscControlRegisted) { @@ -132,21 +132,21 @@ void CarlaEngineThread::run() if (plugin->audioInCount() > 0) { #ifdef BUILD_BRIDGE - engine->osc_send_bridge_set_inpeak(1, engine->getInputPeak(id, 0)); - engine->osc_send_bridge_set_inpeak(2, engine->getInputPeak(id, 1)); + engine->osc_send_bridge_set_inpeak(1); + engine->osc_send_bridge_set_inpeak(2); #else - engine->osc_send_control_set_input_peak_value(id, 1, engine->getInputPeak(id, 0)); - engine->osc_send_control_set_input_peak_value(id, 2, engine->getInputPeak(id, 1)); + engine->osc_send_control_set_input_peak_value(id, 1); + engine->osc_send_control_set_input_peak_value(id, 2); #endif } if (plugin->audioOutCount() > 0) { #ifdef BUILD_BRIDGE - engine->osc_send_bridge_set_outpeak(1, engine->getOutputPeak(id, 0)); - engine->osc_send_bridge_set_outpeak(2, engine->getOutputPeak(id, 1)); + engine->osc_send_bridge_set_outpeak(1); + engine->osc_send_bridge_set_outpeak(2); #else - engine->osc_send_control_set_output_peak_value(id, 1, engine->getOutputPeak(id, 0)); - engine->osc_send_control_set_output_peak_value(id, 2, engine->getOutputPeak(id, 1)); + engine->osc_send_control_set_output_peak_value(id, 1); + engine->osc_send_control_set_output_peak_value(id, 2); #endif } } @@ -154,7 +154,7 @@ void CarlaEngineThread::run() } if (! engine->idleOsc()) - QThread::msleep(50); + msleep(50); } } diff --git a/c++/carla-engine/carla_engine_thread.hpp b/c++/carla-engine/carla_engine_thread.hpp index 47de07b..8d1af14 100644 --- a/c++/carla-engine/carla_engine_thread.hpp +++ b/c++/carla-engine/carla_engine_thread.hpp @@ -1,5 +1,5 @@ /* - * Carla Engine + * Carla Engine Thread * Copyright (C) 2012 Filipe Coelho * * This program is free software; you can redistribute it and/or modify @@ -36,9 +36,13 @@ public: void startNow(); void stopNow(); + // ---------------------------------------------- + protected: void run(); + // ---------------------------------------------- + private: CarlaEngine* const engine; diff --git a/c++/carla-engine/jack.cpp b/c++/carla-engine/jack.cpp index 1c80dd4..c872080 100644 --- a/c++/carla-engine/jack.cpp +++ b/c++/carla-engine/jack.cpp @@ -24,37 +24,385 @@ CARLA_BACKEND_START_NAMESPACE -struct CarlaEngineClientNativeHandle { - CarlaEngineType type; -#ifdef CARLA_ENGINE_JACK - jack_client_t* jackClient; -#endif +// ------------------------------------------------------------------------------------------------------------------- +// Engine port (JackAudio) - CarlaEngineClientNativeHandle() +class CarlaEngineJackAudioPort : public CarlaEngineAudioPort +{ +public: + CarlaEngineJackAudioPort(const bool isInput, const ProcessMode processMode, jack_client_t* const client_, jack_port_t* const port_) + : CarlaEngineAudioPort(isInput, processMode), + client(client_), + port(port_) { - type = CarlaEngineTypeNull; -#ifdef CARLA_ENGINE_JACK - jackClient = nullptr; -#endif + if (processMode == PROCESS_MODE_CONTINUOUS_RACK || processMode == PROCESS_MODE_PATCHBAY) + CARLA_ASSERT(! port); + } + + ~CarlaEngineJackAudioPort() + { + if (client && port) + jackbridge_port_unregister(client, port); + } + + void initBuffer(CarlaEngine* const engine) + { + if (! port) + return CarlaEngineAudioPort::initBuffer(engine); + + buffer = jackbridge_port_get_buffer(port, engine->getBufferSize()); } + +private: + jack_client_t* const client; + jack_port_t* const port; + + friend class CarlaEngineJack; }; -struct CarlaEnginePortNativeHandle { -#ifdef CARLA_ENGINE_JACK - jack_client_t* jackClient; - jack_port_t* jackPort; -#endif +// ------------------------------------------------------------------------------------------------------------------- +// Engine port (JackControl) - CarlaEnginePortNativeHandle() +class CarlaEngineJackControlPort : public CarlaEngineControlPort +{ +public: + CarlaEngineJackControlPort(const bool isInput, const ProcessMode processMode, jack_client_t* const client_, jack_port_t* const port_) + : CarlaEngineControlPort(isInput, processMode), + client(client_), + port(port_) { -#ifdef CARLA_ENGINE_JACK - jackClient = nullptr; - jackPort = nullptr; -#endif + if (processMode == PROCESS_MODE_CONTINUOUS_RACK || processMode == PROCESS_MODE_PATCHBAY) + CARLA_ASSERT(! port); } + + ~CarlaEngineJackControlPort() + { + if (client && port) + jackbridge_port_unregister(client, port); + } + + void initBuffer(CarlaEngine* const engine) + { + if (! port) + return CarlaEngineControlPort::initBuffer(engine); + + buffer = jackbridge_port_get_buffer(port, engine->getBufferSize()); + + if (! isInput) + jackbridge_midi_clear_buffer(buffer); + } + + uint32_t getEventCount() + { + if (! port) + return CarlaEngineControlPort::getEventCount(); + + if (! isInput) + return 0; + + return jackbridge_midi_get_event_count(buffer); + } + + const CarlaEngineControlEvent* getEvent(uint32_t index) + { + if (! port) + return CarlaEngineControlPort::getEvent(index); + + if (! isInput) + return nullptr; + + static jack_midi_event_t jackEvent; + static CarlaEngineControlEvent carlaEvent; + + if (jackbridge_midi_event_get(&jackEvent, buffer, index) != 0) + return nullptr; + + memset(&carlaEvent, 0, sizeof(CarlaEngineControlEvent)); + + uint8_t midiStatus = jackEvent.buffer[0]; + uint8_t midiChannel = midiStatus & 0x0F; + + carlaEvent.time = jackEvent.time; + carlaEvent.channel = midiChannel; + + if (MIDI_IS_STATUS_CONTROL_CHANGE(midiStatus)) + { + uint8_t midiControl = jackEvent.buffer[1]; + + if (MIDI_IS_CONTROL_BANK_SELECT(midiControl)) + { + uint8_t midiBank = jackEvent.buffer[2]; + carlaEvent.type = CarlaEngineMidiBankChangeEvent; + carlaEvent.value = midiBank; + } + else if (midiControl == MIDI_CONTROL_ALL_SOUND_OFF) + { + carlaEvent.type = CarlaEngineAllSoundOffEvent; + } + else if (midiControl == MIDI_CONTROL_ALL_NOTES_OFF) + { + carlaEvent.type = CarlaEngineAllNotesOffEvent; + } + else + { + uint8_t midiValue = jackEvent.buffer[2]; + carlaEvent.type = CarlaEngineParameterChangeEvent; + carlaEvent.controller = midiControl; + carlaEvent.value = double(midiValue)/127; + } + + return &carlaEvent; + } + if (MIDI_IS_STATUS_PROGRAM_CHANGE(midiStatus)) + { + uint8_t midiProgram = jackEvent.buffer[1]; + carlaEvent.type = CarlaEngineMidiProgramChangeEvent; + carlaEvent.value = midiProgram; + + return &carlaEvent; + } + + return nullptr; + } + + void writeEvent(CarlaEngineControlEventType type, uint32_t time, uint8_t channel, uint16_t controller, double value) + { + if (! port) + return CarlaEngineControlPort::writeEvent(type, time, channel, controller, value); + + if (isInput) + return; + + if (type == CarlaEngineParameterChangeEvent && MIDI_IS_CONTROL_BANK_SELECT(controller)) + type = CarlaEngineMidiBankChangeEvent; + + uint8_t data[3] = { 0 }; + + switch (type) + { + case CarlaEngineNullEvent: + break; + case CarlaEngineParameterChangeEvent: + data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; + data[1] = controller; + data[2] = value * 127; + jackbridge_midi_event_write(buffer, time, data, 3); + break; + case CarlaEngineMidiBankChangeEvent: + data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; + data[1] = MIDI_CONTROL_BANK_SELECT; + data[2] = value; + jackbridge_midi_event_write(buffer, time, data, 3); + break; + case CarlaEngineMidiProgramChangeEvent: + data[0] = MIDI_STATUS_PROGRAM_CHANGE + channel; + data[1] = value; + jackbridge_midi_event_write(buffer, time, data, 2); + break; + case CarlaEngineAllSoundOffEvent: + data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; + data[1] = MIDI_CONTROL_ALL_SOUND_OFF; + jackbridge_midi_event_write(buffer, time, data, 2); + break; + case CarlaEngineAllNotesOffEvent: + data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; + data[1] = MIDI_CONTROL_ALL_NOTES_OFF; + jackbridge_midi_event_write(buffer, time, data, 2); + break; + } + } + +private: + jack_client_t* const client; + jack_port_t* const port; }; -// ----------------------------------------- +// ------------------------------------------------------------------------------------------------------------------- +// Engine port (JackMIDI) + +class CarlaEngineJackMidiPort : public CarlaEngineMidiPort +{ +public: + CarlaEngineJackMidiPort(const bool isInput, const ProcessMode processMode, jack_client_t* const client_, jack_port_t* const port_) + : CarlaEngineMidiPort(isInput, processMode), + client(client_), + port(port_) + { + if (processMode == PROCESS_MODE_CONTINUOUS_RACK || processMode == PROCESS_MODE_PATCHBAY) + CARLA_ASSERT(! port); + } + + ~CarlaEngineJackMidiPort() + { + if (client && port) + jackbridge_port_unregister(client, port); + } + + void initBuffer(CarlaEngine* const engine) + { + if (! port) + return CarlaEngineMidiPort::initBuffer(engine); + + buffer = jackbridge_port_get_buffer(port, engine->getBufferSize()); + + if (! isInput) + jackbridge_midi_clear_buffer(buffer); + } + + uint32_t getEventCount() + { + if (! port) + return CarlaEngineMidiPort::getEventCount(); + + if (! isInput) + return 0; + + return jackbridge_midi_get_event_count(buffer); + } + + const CarlaEngineMidiEvent* getEvent(uint32_t index) + { + if (! port) + return CarlaEngineMidiPort::getEvent(index); + + if (! isInput) + return nullptr; + + static jack_midi_event_t jackEvent; + static CarlaEngineMidiEvent carlaEvent; + + if (jackbridge_midi_event_get(&jackEvent, buffer, index) == 0 && jackEvent.size <= 4) + { + carlaEvent.time = jackEvent.time; + carlaEvent.size = jackEvent.size; + memcpy(carlaEvent.data, jackEvent.buffer, jackEvent.size); + return &carlaEvent; + } + + return nullptr; + } + + void writeEvent(uint32_t time, const uint8_t* data, uint8_t size) + { + if (! port) + return CarlaEngineMidiPort::writeEvent(time, data, size); + + if (isInput) + return; + + jackbridge_midi_event_write(buffer, time, data, size); + } + +private: + jack_client_t* const client; + jack_port_t* const port; +}; + +// ------------------------------------------------------------------------------------------------------------------- +// Jack Engine client + +class CarlaEngineJackClient : public CarlaEngineClient +{ +public: + CarlaEngineJackClient(jack_client_t* const client_, const CarlaEngineType engineType, const ProcessMode processMode) + : CarlaEngineClient(engineType, processMode), + client(client_) + { + } + + ~CarlaEngineJackClient() + { + if (processMode == PROCESS_MODE_MULTIPLE_CLIENTS) + { + if (client) + jackbridge_client_close(client); + } + } + + void activate() + { + if (processMode == PROCESS_MODE_MULTIPLE_CLIENTS) + { + if (client && ! isActive()) + jackbridge_activate(client); + } + + CarlaEngineClient::activate(); + } + + void deactivate() + { + CarlaEngineClient::deactivate(); + + if (processMode == PROCESS_MODE_MULTIPLE_CLIENTS) + { + if (client && isActive()) + jackbridge_deactivate(client); + } + } + + bool isOk() const + { + if (processMode != PROCESS_MODE_CONTINUOUS_RACK) + return bool(client); + + return CarlaEngineClient::isOk(); + } + + void setLatency(const uint32_t samples) + { + CarlaEngineClient::setLatency(samples); + + if (processMode != PROCESS_MODE_CONTINUOUS_RACK) + jackbridge_recompute_total_latencies(client); + } + + const CarlaEngineBasePort* addPort(const CarlaEnginePortType portType, const char* const name, const bool isInput) + { + qDebug("CarlaEngineClient::addPort(%i, \"%s\", %s)", portType, name, bool2str(isInput)); + + jack_port_t* port = nullptr; + + // Create Jack port if needed + if (processMode != PROCESS_MODE_CONTINUOUS_RACK) + { + switch (portType) + { + case CarlaEnginePortTypeNull: + break; + case CarlaEnginePortTypeAudio: + port = jackbridge_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0); + break; + case CarlaEnginePortTypeControl: + case CarlaEnginePortTypeMIDI: + port = jackbridge_port_register(client, name, JACK_DEFAULT_MIDI_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0); + break; + } + } + + // Create Engine port + switch (portType) + { + case CarlaEnginePortTypeNull: + break; + case CarlaEnginePortTypeAudio: + return new CarlaEngineJackAudioPort(isInput, processMode, client, port); + case CarlaEnginePortTypeControl: + return new CarlaEngineJackControlPort(isInput, processMode, client, port); + case CarlaEnginePortTypeMIDI: + return new CarlaEngineJackMidiPort(isInput, processMode, client, port); + } + + qCritical("CarlaEngineClient::addPort(%i, \"%s\", %s) - invalid type", portType, name, bool2str(isInput)); + return nullptr; + } + +private: + jack_client_t* const client; +}; + +// ------------------------------------------------------------------------------------------------------------------- +// Jack Engine class CarlaEngineJack : public CarlaEngine { @@ -62,26 +410,24 @@ public: CarlaEngineJack() : CarlaEngine() #ifndef BUILD_BRIDGE -# ifdef Q_COMPILER_INITIALIZER_LISTS +# ifdef Q_COMPILER_INITIALIZER_LISTS , rackJackPorts{nullptr} -# endif +# endif #endif { qDebug("CarlaEngineJack::CarlaEngineJack()"); - type = CarlaEngineTypeJack; - - client = nullptr; - state = JackTransportStopped; - freewheel = false; + globalClient = nullptr; + state = JackTransportStopped; + freewheel = false; memset(&pos, 0, sizeof(jack_position_t)); #ifndef BUILD_BRIDGE -# ifndef Q_COMPILER_INITIALIZER_LISTS +# ifndef Q_COMPILER_INITIALIZER_LISTS for (unsigned short i=0; i < rackPortCount; i++) rackJackPorts[i] = nullptr; -# endif +# endif #endif } @@ -100,42 +446,43 @@ public: state = JackTransportStopped; #ifndef BUILD_BRIDGE - client = jackbridge_client_open(clientName, JackNullOption, nullptr); + globalClient = jackbridge_client_open(clientName, JackNullOption, nullptr); - if (client) + if (globalClient) { - sampleRate = jackbridge_get_sample_rate(client); - bufferSize = jackbridge_get_buffer_size(client); + sampleRate = jackbridge_get_sample_rate(globalClient); + bufferSize = jackbridge_get_buffer_size(globalClient); - jackbridge_set_sample_rate_callback(client, carla_jack_srate_callback, this); - jackbridge_set_buffer_size_callback(client, carla_jack_bufsize_callback, this); - jackbridge_set_freewheel_callback(client, carla_jack_freewheel_callback, this); - jackbridge_set_process_callback(client, carla_jack_process_callback, this); - jackbridge_set_latency_callback(client, carla_jack_latency_callback, this); - jackbridge_on_shutdown(client, carla_jack_shutdown_callback, this); + jackbridge_set_sample_rate_callback(globalClient, carla_jack_srate_callback, this); + jackbridge_set_buffer_size_callback(globalClient, carla_jack_bufsize_callback, this); + jackbridge_set_freewheel_callback(globalClient, carla_jack_freewheel_callback, this); + jackbridge_set_process_callback(globalClient, carla_jack_process_callback, this); + jackbridge_set_latency_callback(globalClient, carla_jack_latency_callback, this); + jackbridge_on_shutdown(globalClient, carla_jack_shutdown_callback, this); - if (processMode == PROCESS_MODE_CONTINUOUS_RACK) + if (options.processMode == PROCESS_MODE_CONTINUOUS_RACK) { - rackJackPorts[rackPortAudioIn1] = jackbridge_port_register(client, "in1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); - rackJackPorts[rackPortAudioIn2] = jackbridge_port_register(client, "in2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); - rackJackPorts[rackPortAudioOut1] = jackbridge_port_register(client, "out1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); - rackJackPorts[rackPortAudioOut2] = jackbridge_port_register(client, "out2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); - rackJackPorts[rackPortControlIn] = jackbridge_port_register(client, "control-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); - rackJackPorts[rackPortControlOut] = jackbridge_port_register(client, "control-out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); - rackJackPorts[rackPortMidiIn] = jackbridge_port_register(client, "midi-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); - rackJackPorts[rackPortMidiOut] = jackbridge_port_register(client, "midi-out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); + rackJackPorts[rackPortAudioIn1] = jackbridge_port_register(globalClient, "in1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); + rackJackPorts[rackPortAudioIn2] = jackbridge_port_register(globalClient, "in2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); + rackJackPorts[rackPortAudioOut1] = jackbridge_port_register(globalClient, "out1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + rackJackPorts[rackPortAudioOut2] = jackbridge_port_register(globalClient, "out2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + rackJackPorts[rackPortControlIn] = jackbridge_port_register(globalClient, "control-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); + rackJackPorts[rackPortControlOut] = jackbridge_port_register(globalClient, "control-out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); + rackJackPorts[rackPortMidiIn] = jackbridge_port_register(globalClient, "midi-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); + rackJackPorts[rackPortMidiOut] = jackbridge_port_register(globalClient, "midi-out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); } - if (jackbridge_activate(client) == 0) + if (jackbridge_activate(globalClient) == 0) { - name = getFixedClientName(jackbridge_get_client_name(client)); + name = jackbridge_get_client_name(globalClient); + name.toBasic(); CarlaEngine::init(name); return true; } else { setLastError("Failed to activate the JACK client"); - client = nullptr; + globalClient = nullptr; } } else @@ -143,7 +490,9 @@ public: return false; #else - name = getFixedClientName(clientName); + name = clientName; + name.toBasic(); + CarlaEngine::init(name); return true; #endif @@ -154,33 +503,27 @@ public: qDebug("CarlaEngineJack::close()"); CarlaEngine::close(); - if (name) - { - free((void*)name); - name = nullptr; - } - #ifdef BUILD_BRIDGE - client = nullptr; + globalClient = nullptr; return true; #else - if (jackbridge_deactivate(client) == 0) + if (jackbridge_deactivate(globalClient) == 0) { - if (processMode == PROCESS_MODE_CONTINUOUS_RACK) + if (options.processMode == PROCESS_MODE_CONTINUOUS_RACK) { - jackbridge_port_unregister(client, rackJackPorts[rackPortAudioIn1]); - jackbridge_port_unregister(client, rackJackPorts[rackPortAudioIn2]); - jackbridge_port_unregister(client, rackJackPorts[rackPortAudioOut1]); - jackbridge_port_unregister(client, rackJackPorts[rackPortAudioOut2]); - jackbridge_port_unregister(client, rackJackPorts[rackPortControlIn]); - jackbridge_port_unregister(client, rackJackPorts[rackPortControlOut]); - jackbridge_port_unregister(client, rackJackPorts[rackPortMidiIn]); - jackbridge_port_unregister(client, rackJackPorts[rackPortMidiOut]); + jackbridge_port_unregister(globalClient, rackJackPorts[rackPortAudioIn1]); + jackbridge_port_unregister(globalClient, rackJackPorts[rackPortAudioIn2]); + jackbridge_port_unregister(globalClient, rackJackPorts[rackPortAudioOut1]); + jackbridge_port_unregister(globalClient, rackJackPorts[rackPortAudioOut2]); + jackbridge_port_unregister(globalClient, rackJackPorts[rackPortControlIn]); + jackbridge_port_unregister(globalClient, rackJackPorts[rackPortControlOut]); + jackbridge_port_unregister(globalClient, rackJackPorts[rackPortMidiIn]); + jackbridge_port_unregister(globalClient, rackJackPorts[rackPortMidiOut]); } - if (jackbridge_client_close(client) == 0) + if (jackbridge_client_close(globalClient) == 0) { - client = nullptr; + globalClient = nullptr; return true; } else @@ -189,28 +532,32 @@ public: else setLastError("Failed to deactivate the JACK client"); - client = nullptr; + globalClient = nullptr; #endif return false; } - bool isOffline() + bool isOffline() const { return freewheel; } - bool isRunning() + bool isRunning() const + { + return bool(globalClient); + } + + CarlaEngineType type() const { - return bool(client); + return CarlaEngineTypeJack; } CarlaEngineClient* addClient(CarlaPlugin* const plugin) { - CarlaEngineClientNativeHandle* handle = new CarlaEngineClientNativeHandle; - handle->type = CarlaEngineTypeJack; + jack_client_t* client = nullptr; #ifdef BUILD_BRIDGE - client = handle.jackClient = jackbridge_client_open(plugin->name(), JackNullOption, nullptr); + client = globalClient = jackbridge_client_open(plugin->name(), JackNullOption, nullptr); sampleRate = jackbridge_get_sample_rate(client); bufferSize = jackbridge_get_buffer_size(client); @@ -222,19 +569,19 @@ public: jackbridge_set_latency_callback(handle.jackClient, carla_jack_latency_callback, this); jackbridge_on_shutdown(client, carla_jack_shutdown_callback, this); #else - if (processMode == PROCESS_MODE_SINGLE_CLIENT) + if (options.processMode == PROCESS_MODE_SINGLE_CLIENT) { - handle->jackClient = client; + client = globalClient; } - else if (processMode == PROCESS_MODE_MULTIPLE_CLIENTS) + else if (options.processMode == PROCESS_MODE_MULTIPLE_CLIENTS) { - handle->jackClient = jackbridge_client_open(plugin->name(), JackNullOption, nullptr); - jackbridge_set_process_callback(handle->jackClient, carla_jack_process_callback_plugin, plugin); - jackbridge_set_latency_callback(handle->jackClient, carla_jack_latency_callback_plugin, plugin); + client = jackbridge_client_open(plugin->name(), JackNullOption, nullptr); + jackbridge_set_process_callback(client, carla_jack_process_callback_plugin, plugin); + jackbridge_set_latency_callback(client, carla_jack_latency_callback_plugin, plugin); } #endif - return new CarlaEngineClient(handle); + return new CarlaEngineJackClient(client, CarlaEngineTypeJack, options.processMode); } // ------------------------------------- @@ -266,7 +613,7 @@ protected: if (maxPluginNumber() == 0) return; #endif - state = jackbridge_transport_query(client, &pos); + state = jackbridge_transport_query(globalClient, &pos); timeInfo.playing = (state != JackTransportStopped); @@ -297,7 +644,7 @@ protected: } #ifndef BUILD_BRIDGE - if (processMode == PROCESS_MODE_SINGLE_CLIENT) + if (options.processMode == PROCESS_MODE_SINGLE_CLIENT) { for (unsigned short i=0, max=maxPluginNumber(); i < max; i++) { @@ -319,7 +666,7 @@ protected: plugin->engineProcessUnlock(); } } - else if (processMode == PROCESS_MODE_CONTINUOUS_RACK) + else if (options.processMode == PROCESS_MODE_CONTINUOUS_RACK) { // get buffers from jack float* audioIn1 = (float*)jackbridge_port_get_buffer(rackJackPorts[rackPortAudioIn1], nframes); @@ -373,21 +720,21 @@ protected: if (MIDI_IS_CONTROL_BANK_SELECT(midiControl)) { uint8_t midiBank = jackEvent.buffer[2]; - carlaEvent->type = CarlaEngineEventMidiBankChange; + carlaEvent->type = CarlaEngineMidiBankChangeEvent; carlaEvent->value = midiBank; } else if (midiControl == MIDI_CONTROL_ALL_SOUND_OFF) { - carlaEvent->type = CarlaEngineEventAllSoundOff; + carlaEvent->type = CarlaEngineAllSoundOffEvent; } else if (midiControl == MIDI_CONTROL_ALL_NOTES_OFF) { - carlaEvent->type = CarlaEngineEventAllNotesOff; + carlaEvent->type = CarlaEngineAllNotesOffEvent; } else { uint8_t midiValue = jackEvent.buffer[2]; - carlaEvent->type = CarlaEngineEventControlChange; + carlaEvent->type = CarlaEngineParameterChangeEvent; carlaEvent->controller = midiControl; carlaEvent->value = double(midiValue)/127; } @@ -395,7 +742,7 @@ protected: else if (MIDI_IS_STATUS_PROGRAM_CHANGE(midiStatus)) { uint8_t midiProgram = jackEvent.buffer[1]; - carlaEvent->type = CarlaEngineEventMidiProgramChange; + carlaEvent->type = CarlaEngineMidiProgramChangeEvent; carlaEvent->value = midiProgram; } } @@ -433,38 +780,38 @@ protected: { CarlaEngineControlEvent* const event = &rackControlEventsOut[i]; - if (event->type == CarlaEngineEventControlChange && MIDI_IS_CONTROL_BANK_SELECT(event->controller)) - event->type = CarlaEngineEventMidiBankChange; + if (event->type == CarlaEngineParameterChangeEvent && MIDI_IS_CONTROL_BANK_SELECT(event->controller)) + event->type = CarlaEngineMidiBankChangeEvent; uint8_t data[4] = { 0 }; switch (event->type) { - case CarlaEngineEventNull: + case CarlaEngineNullEvent: break; - case CarlaEngineEventControlChange: + case CarlaEngineParameterChangeEvent: data[0] = MIDI_STATUS_CONTROL_CHANGE + event->channel; data[1] = event->controller; data[2] = event->value * 127; jackbridge_midi_event_write(controlOut, event->time, data, 3); break; - case CarlaEngineEventMidiBankChange: + case CarlaEngineMidiBankChangeEvent: data[0] = MIDI_STATUS_CONTROL_CHANGE + event->channel; data[1] = MIDI_CONTROL_BANK_SELECT; data[2] = event->value; jackbridge_midi_event_write(controlOut, event->time, data, 3); break; - case CarlaEngineEventMidiProgramChange: + case CarlaEngineMidiProgramChangeEvent: data[0] = MIDI_STATUS_PROGRAM_CHANGE + event->channel; data[1] = event->value; jackbridge_midi_event_write(controlOut, event->time, data, 2); break; - case CarlaEngineEventAllSoundOff: + case CarlaEngineAllSoundOffEvent: data[0] = MIDI_STATUS_CONTROL_CHANGE + event->channel; data[1] = MIDI_CONTROL_ALL_SOUND_OFF; jackbridge_midi_event_write(controlOut, event->time, data, 2); break; - case CarlaEngineEventAllNotesOff: + case CarlaEngineAllNotesOffEvent: data[0] = MIDI_STATUS_CONTROL_CHANGE + event->channel; data[1] = MIDI_CONTROL_ALL_NOTES_OFF; jackbridge_midi_event_write(controlOut, event->time, data, 2); @@ -509,7 +856,7 @@ protected: void handleLatencyCallback(jack_latency_callback_mode_t mode) { #ifndef BUILD_BRIDGE - if (processMode != PROCESS_MODE_SINGLE_CLIENT) + if (options.processMode != PROCESS_MODE_SINGLE_CLIENT) return; #endif @@ -532,14 +879,14 @@ protected: plugin->x_client = nullptr; } - client = nullptr; + globalClient = nullptr; callback(CALLBACK_QUIT, 0, 0, 0, 0.0); } // ------------------------------------- private: - jack_client_t* client; + jack_client_t* globalClient; jack_transport_state_t state; jack_position_t pos; bool freewheel; @@ -567,11 +914,13 @@ private: float* inBuffer[p->aIn.count]; float* outBuffer[p->aOut.count]; +#if 0 for (uint32_t i=0; i < p->aIn.count; i++) - inBuffer[i] = p->aIn.ports[i]->getJackAudioBuffer(nframes); + inBuffer[i] = (float*)jackbridge_port_get_buffer(p->aIn.ports[i]->handle.jackPort, nframes); for (uint32_t i=0; i < p->aOut.count; i++) - outBuffer[i] = p->aOut.ports[i]->getJackAudioBuffer(nframes); + outBuffer[i] = (float*)jackbridge_port_get_buffer(p->aOut.ports[i]->handle.jackPort, nframes); +#endif #ifndef BUILD_BRIDGE if (/*options.processHighPrecision*/ 0) @@ -597,11 +946,15 @@ private: static void processPluginNOT(CarlaPlugin* const p, const uint32_t nframes) { - for (uint32_t i=0; i < p->aIn.count; i++) - carla_zeroF(p->aIn.ports[i]->getJackAudioBuffer(nframes), nframes); + CarlaEngineJackAudioPort* port; + float* buffer; for (uint32_t i=0; i < p->aOut.count; i++) - carla_zeroF(p->aOut.ports[i]->getJackAudioBuffer(nframes), nframes); + { + port = (CarlaEngineJackAudioPort*)p->aOut.ports[i]; + buffer = (float*)jackbridge_port_get_buffer(port->port, nframes); + carla_zeroF(buffer, nframes); + } } static void latencyPlugin(CarlaPlugin* const p, jack_latency_callback_mode_t mode) @@ -617,8 +970,8 @@ private: for (uint32_t i=0; i < p->aIn.count; i++) { uint aOutI = (i >= p->aOut.count) ? p->aOut.count : i; - jack_port_t* const portIn = p->aIn.ports[i]->getHandle()->jackPort; - jack_port_t* const portOut = p->aOut.ports[aOutI]->getHandle()->jackPort; + jack_port_t* const portIn = ((CarlaEngineJackAudioPort*)p->aIn.ports[i])->port; + jack_port_t* const portOut = ((CarlaEngineJackAudioPort*)p->aOut.ports[aOutI])->port; jackbridge_port_get_latency_range(portIn, mode, &range); range.min += pluginLatency; @@ -631,8 +984,8 @@ private: for (uint32_t i=0; i < p->aOut.count; i++) { uint aInI = (i >= p->aIn.count) ? p->aIn.count : i; - jack_port_t* const portIn = p->aIn.ports[aInI]->getHandle()->jackPort; - jack_port_t* const portOut = p->aOut.ports[i]->getHandle()->jackPort; + jack_port_t* const portIn = ((CarlaEngineJackAudioPort*)p->aIn.ports[aInI])->port; + jack_port_t* const portOut = ((CarlaEngineJackAudioPort*)p->aOut.ports[i])->port; jackbridge_port_get_latency_range(portOut, mode, &range); range.min += pluginLatency; diff --git a/c++/carla-engine/plugin.cpp b/c++/carla-engine/plugin.cpp index 6e4ca43..9b2633d 100644 --- a/c++/carla-engine/plugin.cpp +++ b/c++/carla-engine/plugin.cpp @@ -39,6 +39,42 @@ static const unsigned int paramPan = 8; static const unsigned int paramCount = sizeof(paramMap); static const unsigned int programCount = 128; +// ------------------------------------------------------------------------------------------------------------------- +// Plugin Engine client + +class CarlaEnginePluginClient : public CarlaEngineClient +{ +public: + CarlaEnginePluginClient(const CarlaEngineType engineType, const ProcessMode processMode) + : CarlaEngineClient(engineType, processMode) + { + } + + ~CarlaEnginePluginClient() + { + } + + const CarlaEngineBasePort* addPort(const CarlaEnginePortType portType, const char* const name, const bool isInput) + { + qDebug("CarlaEnginePluginClient::addPort(%i, \"%s\", %s)", portType, name, bool2str(isInput)); + + switch (portType) + { + case CarlaEnginePortTypeNull: + break; + case CarlaEnginePortTypeAudio: + return new CarlaEngineAudioPort(isInput, processMode); + case CarlaEnginePortTypeControl: + return new CarlaEngineControlPort(isInput, processMode); + case CarlaEnginePortTypeMIDI: + return new CarlaEngineMidiPort(isInput, processMode); + } + + qCritical("CarlaEnginePluginClient::addPort(%i, \"%s\", %s) - invalid type", portType, name, bool2str(isInput)); + return nullptr; + } +}; + // ----------------------------------------- class CarlaEnginePlugin : public CarlaEngine, @@ -64,7 +100,7 @@ public: memcpy(prevParamBuffers, paramBuffers, sizeof(float)*paramCount); // set-up engine - processMode = PROCESS_MODE_CONTINUOUS_RACK; + options.processMode = PROCESS_MODE_CONTINUOUS_RACK; options.forceStereo = true; options.preferPluginBridges = false; options.preferUiBridges = false; @@ -96,9 +132,10 @@ public: bufferSize = d_bufferSize(); sampleRate = d_sampleRate(); - name = strdup(clientName); - CarlaEngine::init(name); + name = clientName; + name.toBasic(); + CarlaEngine::init(name); return true; } @@ -107,32 +144,27 @@ public: qDebug("CarlaEnginePlugin::close()"); CarlaEngine::close(); - if (name) - { - free((void*)name); - name = nullptr; - } - return true; } - bool isOffline() + bool isOffline() const { return false; } - bool isRunning() + bool isRunning() const { return true; } - CarlaEngineClient* addClient(CarlaPlugin* const plugin) + CarlaEngineType type() const { - CarlaEngineClientNativeHandle handle; - handle.type = CarlaEngineTypeRtAudio; + return CarlaEngineTypeRtAudio; + } - return new CarlaEngineClient(handle); - Q_UNUSED(plugin); + CarlaEngineClient* addClient(CarlaPlugin* const) + { + return new CarlaEnginePluginClient(CarlaEngineTypeRtAudio, options.processMode); } protected: @@ -441,7 +473,7 @@ protected: CarlaEngineControlEvent* const carlaEvent = &rackControlEventsIn[carlaEventIndex++]; - carlaEvent->type = CarlaEngineEventControlChange; + carlaEvent->type = CarlaEngineParameterChangeEvent; carlaEvent->controller = paramMap[i]; carlaEvent->value = paramBuffers[i]/127; } diff --git a/c++/carla-engine/rtaudio.cpp b/c++/carla-engine/rtaudio.cpp index 5900d89..cb46449 100644 --- a/c++/carla-engine/rtaudio.cpp +++ b/c++/carla-engine/rtaudio.cpp @@ -25,22 +25,44 @@ CARLA_BACKEND_START_NAMESPACE -struct CarlaEngineClientNativeHandle { - CarlaEngineType type; -#ifdef CARLA_ENGINE_JACK - void* jackClient; -#endif +// ------------------------------------------------------------------------------------------------------------------- +// RtAudio Engine client - CarlaEngineClientNativeHandle() +class CarlaEngineRtAudioClient : public CarlaEngineClient +{ +public: + CarlaEngineRtAudioClient(const CarlaEngineType engineType, const ProcessMode processMode) + : CarlaEngineClient(engineType, processMode) + { + } + + ~CarlaEngineRtAudioClient() { - type = CarlaEngineTypeNull; -#ifdef CARLA_ENGINE_JACK - jackClient = nullptr; -#endif + } + + const CarlaEngineBasePort* addPort(const CarlaEnginePortType portType, const char* const name, const bool isInput) + { + qDebug("CarlaEngineRtAudioClient::addPort(%i, \"%s\", %s)", portType, name, bool2str(isInput)); + + switch (portType) + { + case CarlaEnginePortTypeNull: + break; + case CarlaEnginePortTypeAudio: + return new CarlaEngineAudioPort(isInput, processMode); + case CarlaEnginePortTypeControl: + return new CarlaEngineControlPort(isInput, processMode); + case CarlaEnginePortTypeMIDI: + return new CarlaEngineMidiPort(isInput, processMode); + } + + qCritical("CarlaEngineRtAudioClient::addPort(%i, \"%s\", %s) - invalid type", portType, name, bool2str(isInput)); + return nullptr; } }; -// ----------------------------------------- +// ------------------------------------------------------------------------------------------------------------------- +// RtAudio Engine class CarlaEngineRtAudio : public CarlaEngine { @@ -51,14 +73,12 @@ public: { qDebug("CarlaEngineRtAudio::CarlaEngineRtAudio()"); - type = CarlaEngineTypeRtAudio; - midiIn = nullptr; midiOut = nullptr; // just to make sure options.forceStereo = true; - processMode = PROCESS_MODE_CONTINUOUS_RACK; + options.processMode = PROCESS_MODE_CONTINUOUS_RACK; } ~CarlaEngineRtAudio() @@ -118,7 +138,9 @@ public: midiOut->openVirtualPort("control-out"); midiOut->openVirtualPort("midi-out"); - name = getFixedClientName(clientName); + name = clientName; + name.toBasic(); + CarlaEngine::init(name); return true; } @@ -128,12 +150,6 @@ public: qDebug("CarlaEngineRtAudio::close()"); CarlaEngine::close(); - if (name) - { - free((void*)name); - name = nullptr; - } - if (audio.isStreamRunning()) audio.stopStream(); @@ -158,22 +174,24 @@ public: return true; } - bool isOffline() + bool isOffline() const { return false; } - bool isRunning() + bool isRunning() const { return audio.isStreamRunning(); } - CarlaEngineClient* addClient(CarlaPlugin* const) + CarlaEngineType type() const { - CarlaEngineClientNativeHandle* handle = new CarlaEngineClientNativeHandle; - handle->type = CarlaEngineTypeRtAudio; + return CarlaEngineTypeRtAudio; + } - return new CarlaEngineClient(handle); + CarlaEngineClient* addClient(CarlaPlugin* const) + { + return new CarlaEngineRtAudioClient(CarlaEngineTypeRtAudio, options.processMode); } // ------------------------------------- @@ -267,10 +285,80 @@ private: CarlaEngine* CarlaEngine::newRtAudio(RtAudioApi api) { - return new CarlaEngineRtAudio(static_cast(api)); + RtAudio::Api rtApi = RtAudio::UNSPECIFIED; + + switch (api) + { + case RTAUDIO_DUMMY: + rtApi = RtAudio::RTAUDIO_DUMMY; + break; + case RTAUDIO_LINUX_ALSA: + rtApi = RtAudio::LINUX_ALSA; + break; + case RTAUDIO_LINUX_PULSE: + rtApi = RtAudio::LINUX_PULSE; + break; + case RTAUDIO_LINUX_OSS: + rtApi = RtAudio::LINUX_OSS; + break; + case RTAUDIO_UNIX_JACK: + rtApi = RtAudio::UNIX_JACK; + break; + case RTAUDIO_MACOSX_CORE: + rtApi = RtAudio::MACOSX_CORE; + break; + case RTAUDIO_WINDOWS_ASIO: + rtApi = RtAudio::WINDOWS_ASIO; + break; + case RTAUDIO_WINDOWS_DS: + rtApi = RtAudio::WINDOWS_DS; + break; + } + + return new CarlaEngineRtAudio(rtApi); +} + +unsigned int CarlaEngine::getRtAudioApiCount() +{ + std::vector apis; + RtAudio::getCompiledApi(apis); + return apis.size(); } -// ----------------------------------------- +const char* CarlaEngine::getRtAudioApiName(unsigned int index) +{ + std::vector apis; + RtAudio::getCompiledApi(apis); + + if (index < apis.size()) + { + const RtAudio::Api& api(apis[index]); + + switch (api) + { + case RtAudio::UNSPECIFIED: + return "Unspecified"; + case RtAudio::LINUX_ALSA: + return "ALSA"; + case RtAudio::LINUX_PULSE: + return "PulseAudio"; + case RtAudio::LINUX_OSS: + return "OSS"; + case RtAudio::UNIX_JACK: + return "JACK (RtAudio)"; + case RtAudio::MACOSX_CORE: + return "CoreAudio"; + case RtAudio::WINDOWS_ASIO: + return "ASIO"; + case RtAudio::WINDOWS_DS: + return "DirectSound"; + case RtAudio::RTAUDIO_DUMMY: + return "Dummy"; + } + } + + return nullptr; +} CARLA_BACKEND_END_NAMESPACE diff --git a/c++/carla-plugin/carla_plugin.hpp b/c++/carla-plugin/carla_plugin.hpp index 4231349..69b3d74 100644 --- a/c++/carla-plugin/carla_plugin.hpp +++ b/c++/carla-plugin/carla_plugin.hpp @@ -740,7 +740,7 @@ public: /*! * Process all the post-poned events. - * This function will only be called from the main thread if PLUGIN_USES_SINGLE_THREAD is set. + * This function must be called from the main thread (ie, idleGui()) if PLUGIN_USES_SINGLE_THREAD is set. */ void postEventsRun(); @@ -847,7 +847,7 @@ public: #endif static size_t getNativePluginCount(); - static const PluginDescriptor* getNativePlugin(size_t index); + static const PluginDescriptor* getNativePluginDescriptor(const size_t index); // ------------------------------------------------------------------- @@ -976,11 +976,6 @@ protected: return value; } - static double abs(const double& value) - { - return (value < 0.0) ? -value : value; - } - friend class CarlaEngineJack; }; diff --git a/c++/carla-utils/carla_utils.hpp b/c++/carla-utils/carla_utils.hpp index b6eeb4c..661f42e 100644 --- a/c++/carla-utils/carla_utils.hpp +++ b/c++/carla-utils/carla_utils.hpp @@ -121,30 +121,30 @@ static inline void pass() {} // ------------------------------------------------- -// carla_string class +// CarlaString class -class carla_string +class CarlaString { public: // --------------------------------------------- // constructors (no explicit conversions allowed) - explicit carla_string() + explicit CarlaString() { buffer = ::strdup(""); } - explicit carla_string(char* const strBuf) + explicit CarlaString(char* const strBuf) { buffer = ::strdup(strBuf ? strBuf : ""); } - explicit carla_string(const char* const strBuf) + explicit CarlaString(const char* const strBuf) { buffer = ::strdup(strBuf ? strBuf : ""); } - explicit carla_string(const int value) + explicit CarlaString(const int value) { const size_t strBufSize = ::abs(value/10) + 3; char strBuf[strBufSize]; @@ -153,7 +153,7 @@ public: buffer = ::strdup(strBuf); } - explicit carla_string(const unsigned int value, const bool hexadecimal = false) + explicit CarlaString(const unsigned int value, const bool hexadecimal = false) { const size_t strBufSize = value/10 + 2 + (hexadecimal ? 2 : 0); char strBuf[strBufSize]; @@ -162,7 +162,7 @@ public: buffer = ::strdup(strBuf); } - explicit carla_string(const long int value) + explicit CarlaString(const long int value) { const size_t strBufSize = ::labs(value/10) + 3; char strBuf[strBufSize]; @@ -171,7 +171,7 @@ public: buffer = ::strdup(strBuf); } - explicit carla_string(const unsigned long int value, const bool hexadecimal = false) + explicit CarlaString(const unsigned long int value, const bool hexadecimal = false) { const size_t strBufSize = value/10 + 2 + (hexadecimal ? 2 : 0); char strBuf[strBufSize]; @@ -180,7 +180,7 @@ public: buffer = ::strdup(strBuf); } - explicit carla_string(const float value) + explicit CarlaString(const float value) { char strBuf[0xff]; ::snprintf(strBuf, 0xff, "%f", value); @@ -188,7 +188,7 @@ public: buffer = ::strdup(strBuf); } - explicit carla_string(const double value) + explicit CarlaString(const double value) { char strBuf[0xff]; ::snprintf(strBuf, 0xff, "%g", value); @@ -199,7 +199,7 @@ public: // --------------------------------------------- // non-explicit constructor - carla_string(const carla_string& str) + CarlaString(const CarlaString& str) { buffer = ::strdup(str.buffer); } @@ -207,7 +207,7 @@ public: // --------------------------------------------- // deconstructor - ~carla_string() + ~CarlaString() { ::free(buffer); } @@ -225,6 +225,11 @@ public: return (*buffer == 0); } + bool isNotEmpty() const + { + return !isEmpty(); + } + bool contains(const char* const strBuf) const { if (! strBuf) @@ -249,11 +254,51 @@ public: return false; } - bool contains(const carla_string& str) const + bool contains(const CarlaString& str) const { return contains(str.buffer); } + bool isDigit(size_t pos) const + { + if (pos >= length()) + return false; + + return (buffer[pos] >= '0' && buffer[pos] <= '9'); + } + + void clear() + { + for (size_t i=0, len = ::strlen(buffer); i < len; i++) + buffer[i] = 0; + } + + void replace(char before, char after) + { + for (size_t i=0, len = ::strlen(buffer); i < len; i++) + { + if (buffer[i] == before) + buffer[i] = after; + } + } + + void truncate(unsigned int n) + { + for (size_t i=n, len = ::strlen(buffer); i < len; i++) + buffer[i] = 0; + } + + void toBasic() + { + for (size_t i=0, len = ::strlen(buffer); i < len; i++) + { + if ((buffer[i] >= '0' && buffer[i] <= '9') || (buffer[i] >= 'A' && buffer[i] <= 'Z') || (buffer[i] >= 'a' && buffer[i] <= '<')) + continue; + + buffer[i] = '_'; + } + } + void toLower() { for (size_t i=0, len = ::strlen(buffer); i < len; i++) @@ -280,12 +325,17 @@ public: return buffer; } + char& operator[](int pos) + { + return buffer[pos]; + } + bool operator==(const char* const strBuf) const { return (strBuf && ::strcmp(buffer, strBuf) == 0); } - bool operator==(const carla_string& str) const + bool operator==(const CarlaString& str) const { return operator==(str.buffer); } @@ -295,12 +345,12 @@ public: return !operator==(strBuf); } - bool operator!=(const carla_string& str) const + bool operator!=(const CarlaString& str) const { return !operator==(str.buffer); } - carla_string& operator=(const char* const strBuf) + CarlaString& operator=(const char* const strBuf) { ::free(buffer); @@ -309,12 +359,12 @@ public: return *this; } - carla_string& operator=(const carla_string& str) + CarlaString& operator=(const CarlaString& str) { return operator=(str.buffer); } - carla_string& operator+=(const char* const strBuf) + CarlaString& operator+=(const char* const strBuf) { const size_t newBufSize = ::strlen(buffer) + (strBuf ? ::strlen(strBuf) : 0) + 1; char newBuf[newBufSize]; @@ -328,12 +378,12 @@ public: return *this; } - carla_string& operator+=(const carla_string& str) + CarlaString& operator+=(const CarlaString& str) { return operator+=(str.buffer); } - carla_string operator+(const char* const strBuf) + CarlaString operator+(const char* const strBuf) { const size_t newBufSize = ::strlen(buffer) + (strBuf ? ::strlen(strBuf) : 0) + 1; char newBuf[newBufSize]; @@ -341,10 +391,10 @@ public: ::strcpy(newBuf, buffer); ::strcat(newBuf, strBuf); - return carla_string(newBuf); + return CarlaString(newBuf); } - carla_string operator+(const carla_string& str) + CarlaString operator+(const CarlaString& str) { return operator+(str.buffer); } @@ -356,7 +406,7 @@ private: }; static inline -carla_string operator+(const char* const strBufBefore, const carla_string& strAfter) +CarlaString operator+(const char* const strBufBefore, const CarlaString& strAfter) { const char* const strBufAfter = (const char*)strAfter; const size_t newBufSize = (strBufBefore ? ::strlen(strBufBefore) : 0) + ::strlen(strBufAfter) + 1; @@ -365,7 +415,7 @@ carla_string operator+(const char* const strBufBefore, const carla_string& strAf ::strcpy(newBuf, strBufBefore); ::strcat(newBuf, strBufAfter); - return carla_string(newBuf); + return CarlaString(newBuf); } // ------------------------------------------------- diff --git a/src/shared_carla.py b/src/shared_carla.py index d305d4f..9ccb19e 100644 --- a/src/shared_carla.py +++ b/src/shared_carla.py @@ -201,11 +201,12 @@ CALLBACK_QUIT = 20 PROCESS_MODE_SINGLE_CLIENT = 0 PROCESS_MODE_MULTIPLE_CLIENTS = 1 PROCESS_MODE_CONTINUOUS_RACK = 2 +PROCESS_MODE_PATCHBAY = 3 # ------------------------------------------------------------------------------------------------ # Carla GUI stuff -Carla.processMode = PROCESS_MODE_MULTIPLE_CLIENTS +Carla.processMode = PROCESS_MODE_CONTINUOUS_RACK Carla.maxParameters = MAX_PARAMETERS # set native binary type