| @@ -83,63 +83,14 @@ unsigned int get_engine_driver_count() | |||
| { | |||
| qDebug("CarlaBackendStandalone::get_engine_driver_count()"); | |||
| unsigned int count = 0; | |||
| #ifdef CARLA_ENGINE_JACK | |||
| count += 1; | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| std::vector<RtAudio::Api> apis; | |||
| RtAudio::getCompiledApi(apis); | |||
| count += apis.size(); | |||
| #endif | |||
| return count; | |||
| return CarlaBackend::CarlaEngine::getDriverCount(); | |||
| } | |||
| const char* get_engine_driver_name(unsigned int index) | |||
| { | |||
| qDebug("CarlaBackendStandalone::get_engine_driver_name(%i)", index); | |||
| #ifdef CARLA_ENGINE_JACK | |||
| if (index == 0) | |||
| return "JACK"; | |||
| else | |||
| index -= 1; | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| std::vector<RtAudio::Api> 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"; | |||
| } | |||
| } | |||
| #endif | |||
| qWarning("CarlaBackendStandalone::get_engine_driver_name(%i) - invalid index", index); | |||
| return nullptr; | |||
| return CarlaBackend::CarlaEngine::getDriverName(index); | |||
| } | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| @@ -183,49 +134,9 @@ bool engine_init(const char* driver_name, const char* client_name) | |||
| qDebug("CarlaBackendStandalone::engine_init(\"%s\", \"%s\")", driver_name, client_name); | |||
| CARLA_ASSERT(! carlaEngine); | |||
| #ifdef CARLA_ENGINE_JACK | |||
| if (strcmp(driver_name, "JACK") == 0) | |||
| carlaEngine = new CarlaBackend::CarlaEngineJack; | |||
| #else | |||
| if (false) | |||
| pass(); | |||
| #endif | |||
| carlaEngine = CarlaBackend::CarlaEngine::newDriverByName(driver_name); | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| #ifdef __LINUX_ALSA__ | |||
| else if (strcmp(driver_name, "ALSA") == 0) | |||
| carlaEngine = new CarlaBackend::CarlaEngineRtAudio(RtAudio::LINUX_ALSA); | |||
| #endif | |||
| #ifdef __LINUX_PULSE__ | |||
| else if (strcmp(driver_name, "PulseAudio") == 0) | |||
| carlaEngine = new CarlaBackend::CarlaEngineRtAudio(RtAudio::LINUX_PULSE); | |||
| #endif | |||
| #ifdef __LINUX_OSS__ | |||
| else if (strcmp(driver_name, "OSS") == 0) | |||
| carlaEngine = new CarlaBackend::CarlaEngineRtAudio(RtAudio::LINUX_OSS); | |||
| #endif | |||
| #ifdef __UNIX_JACK__ | |||
| else if (strcmp(driver_name, "JACK (RtAudio)") == 0) | |||
| carlaEngine = new CarlaBackend::CarlaEngineRtAudio(RtAudio::UNIX_JACK); | |||
| #endif | |||
| #ifdef __MACOSX_CORE__ | |||
| else if (strcmp(driver_name, "CoreAudio") == 0) | |||
| carlaEngine = new CarlaBackend::CarlaEngineRtAudio(RtAudio::MACOSX_CORE); | |||
| #endif | |||
| #ifdef __WINDOWS_ASIO__ | |||
| else if (strcmp(driver_name, "ASIO") == 0) | |||
| carlaEngine = new CarlaBackend::CarlaEngineRtAudio(RtAudio::WINDOWS_ASIO); | |||
| #endif | |||
| #ifdef __WINDOWS_DS__ | |||
| else if (strcmp(driver_name, "DirectSound") == 0) | |||
| carlaEngine = new CarlaBackend::CarlaEngineRtAudio(RtAudio::WINDOWS_DS); | |||
| #endif | |||
| #ifdef __RTAUDIO_DUMMY__ | |||
| else if (strcmp(driver_name, "Dummy") == 0) | |||
| carlaEngine = new CarlaBackend::CarlaEngineRtAudio(RtAudio::RTAUDIO_DUMMY); | |||
| #endif | |||
| #endif | |||
| else | |||
| if (! carlaEngine) | |||
| { | |||
| CarlaBackend::setLastError("The seleted audio driver is not available!"); | |||
| return false; | |||
| @@ -245,7 +156,14 @@ bool engine_init(const char* driver_name, const char* client_name) | |||
| carlaEngineStarted = carlaEngine->init(client_name); | |||
| if (carlaEngineStarted) | |||
| { | |||
| CarlaBackend::setLastError("no error"); | |||
| } | |||
| else if (carlaEngine) | |||
| { | |||
| delete carlaEngine; | |||
| carlaEngine = nullptr; | |||
| } | |||
| return carlaEngineStarted; | |||
| } | |||
| @@ -427,7 +427,7 @@ public: | |||
| info.copyright = strdup(copyright); | |||
| if (! m_name) | |||
| m_name = x_engine->getUniqueName(name); | |||
| m_name = x_engine->getUniquePluginName(name); | |||
| break; | |||
| } | |||
| @@ -936,7 +936,7 @@ public: | |||
| m_filename = strdup(filename); | |||
| if (name) | |||
| m_name = x_engine->getUniqueName(name); | |||
| m_name = x_engine->getUniquePluginName(name); | |||
| // register plugin now so we can receive OSC (and wait for it) | |||
| x_engine->__bridgePluginRegister(m_id, this); | |||
| @@ -102,6 +102,127 @@ 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; | |||
| #ifdef CARLA_ENGINE_JACK | |||
| count += 1; | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| std::vector<RtAudio::Api> apis; | |||
| RtAudio::getCompiledApi(apis); | |||
| count += apis.size(); | |||
| #endif | |||
| return count; | |||
| } | |||
| const char* CarlaEngine::getDriverName(unsigned int index) | |||
| { | |||
| #ifdef CARLA_ENGINE_JACK | |||
| if (index == 0) | |||
| return "JACK"; | |||
| else | |||
| index -= 1; | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| std::vector<RtAudio::Api> 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"; | |||
| } | |||
| } | |||
| #endif | |||
| qWarning("CarlaEngine::getDriverName(%i) - invalid index", index); | |||
| return nullptr; | |||
| } | |||
| CarlaEngine* CarlaEngine::newDriverByName(const char* driverName) | |||
| { | |||
| #ifdef CARLA_ENGINE_JACK | |||
| if (strcmp(driverName, "JACK") == 0) | |||
| return newJack(); | |||
| #else | |||
| if (false) | |||
| pass(); | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| #ifdef __LINUX_ALSA__ | |||
| else if (strcmp(driverName, "ALSA") == 0) | |||
| return newRtAudio(RtAudio::LINUX_ALSA); | |||
| #endif | |||
| #ifdef __LINUX_PULSE__ | |||
| else if (strcmp(driverName, "PulseAudio") == 0) | |||
| return newRtAudio(RtAudio::LINUX_PULSE); | |||
| #endif | |||
| #ifdef __LINUX_OSS__ | |||
| else if (strcmp(driverName, "OSS") == 0) | |||
| 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__ | |||
| else if (strcmp(driverName, "CoreAudio") == 0) | |||
| return newRtAudio(RtAudio::MACOSX_CORE); | |||
| #endif | |||
| #ifdef __WINDOWS_ASIO__ | |||
| else if (strcmp(driverName, "ASIO") == 0) | |||
| 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 | |||
| #endif | |||
| return nullptr; | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Virtual, per-engine type calls | |||
| bool CarlaEngine::init(const char* const clientName) | |||
| { | |||
| qDebug("CarlaEngine::init(\"%s\")", clientName); | |||
| @@ -169,9 +290,10 @@ CarlaPlugin* CarlaEngine::getPluginUnchecked(const unsigned short id) const | |||
| return m_carlaPlugins[id]; | |||
| } | |||
| const char* CarlaEngine::getUniqueName(const char* const name) | |||
| const char* CarlaEngine::getUniquePluginName(const char* const name) | |||
| { | |||
| qDebug("CarlaEngine::getUniqueName(\"%s\")", name); | |||
| qDebug("CarlaEngine::getUniquePluginName(\"%s\")", name); | |||
| CARLA_ASSERT(name); | |||
| QString qname(name); | |||
| @@ -695,10 +817,6 @@ CarlaEngineClient::~CarlaEngineClient() | |||
| #ifdef CARLA_ENGINE_JACK | |||
| if (handle.jackClient) | |||
| jackbridge_client_close(handle.jackClient); | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| if (handle.rtAudioPtr) | |||
| delete handle.rtAudioPtr; | |||
| #endif | |||
| } | |||
| } | |||
| @@ -717,10 +835,6 @@ void CarlaEngineClient::activate() | |||
| #ifdef CARLA_ENGINE_JACK | |||
| if (handle.jackClient) | |||
| jackbridge_activate(handle.jackClient); | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| if (handle.rtAudioPtr) | |||
| handle.rtAudioPtr->startStream(); | |||
| #endif | |||
| } | |||
| } | |||
| @@ -742,10 +856,6 @@ void CarlaEngineClient::deactivate() | |||
| #ifdef CARLA_ENGINE_JACK | |||
| if (handle.jackClient) | |||
| jackbridge_deactivate(handle.jackClient); | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| if (handle.rtAudioPtr) | |||
| handle.rtAudioPtr->stopStream(); | |||
| #endif | |||
| } | |||
| } | |||
| @@ -771,10 +881,6 @@ bool CarlaEngineClient::isOk() const | |||
| #ifdef CARLA_ENGINE_JACK | |||
| if (handle.type == CarlaEngineTypeJack) | |||
| return bool(handle.jackClient); | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| if (handle.type == CarlaEngineTypeRtAudio) | |||
| return bool(handle.rtAudioPtr); | |||
| #endif | |||
| } | |||
| @@ -809,13 +915,6 @@ const CarlaEngineBasePort* CarlaEngineClient::addPort(const CarlaEnginePortType | |||
| } | |||
| } | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| if (handle.type == CarlaEngineTypeRtAudio) | |||
| { | |||
| // TODO | |||
| } | |||
| #endif | |||
| } | |||
| switch (portType) | |||
| @@ -857,10 +956,6 @@ CarlaEngineBasePort::~CarlaEngineBasePort() | |||
| if (handle.jackClient && handle.jackPort) | |||
| jackbridge_port_unregister(handle.jackClient, handle.jackPort); | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| // TODO | |||
| #endif | |||
| } | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| @@ -918,10 +1013,6 @@ void CarlaEngineControlPort::initBuffer(CarlaEngine* const engine) | |||
| jackbridge_midi_clear_buffer(buffer); | |||
| } | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| // TODO | |||
| #endif | |||
| } | |||
| uint32_t CarlaEngineControlPort::getEventCount() | |||
| @@ -954,10 +1045,6 @@ uint32_t CarlaEngineControlPort::getEventCount() | |||
| return jackbridge_midi_get_event_count(buffer); | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| // TODO | |||
| #endif | |||
| return 0; | |||
| } | |||
| @@ -1037,10 +1124,6 @@ const CarlaEngineControlEvent* CarlaEngineControlPort::getEvent(uint32_t index) | |||
| } | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| // TODO | |||
| #endif | |||
| return nullptr; | |||
| } | |||
| @@ -1116,10 +1199,6 @@ void CarlaEngineControlPort::writeEvent(CarlaEngineControlEventType type, uint32 | |||
| } | |||
| } | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| // TODO | |||
| #endif | |||
| } | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| @@ -1152,10 +1231,6 @@ void CarlaEngineMidiPort::initBuffer(CarlaEngine* const engine) | |||
| jackbridge_midi_clear_buffer(buffer); | |||
| } | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| // TODO | |||
| #endif | |||
| } | |||
| uint32_t CarlaEngineMidiPort::getEventCount() | |||
| @@ -1188,10 +1263,6 @@ uint32_t CarlaEngineMidiPort::getEventCount() | |||
| return jackbridge_midi_get_event_count(buffer); | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| // TODO | |||
| #endif | |||
| return 0; | |||
| } | |||
| @@ -1232,10 +1303,6 @@ const CarlaEngineMidiEvent* CarlaEngineMidiPort::getEvent(uint32_t index) | |||
| } | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| // TODO | |||
| #endif | |||
| return nullptr; | |||
| } | |||
| @@ -1275,10 +1342,6 @@ void CarlaEngineMidiPort::writeEvent(uint32_t time, const uint8_t* data, uint8_t | |||
| if (handle.jackPort) | |||
| jackbridge_midi_event_write(buffer, time, data, size); | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| // TODO | |||
| #endif | |||
| } | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| @@ -142,18 +142,12 @@ struct CarlaEngineClientNativeHandle { | |||
| #ifdef CARLA_ENGINE_JACK | |||
| jack_client_t* jackClient; | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| RtAudio* rtAudioPtr; | |||
| #endif | |||
| CarlaEngineClientNativeHandle() | |||
| { | |||
| type = CarlaEngineTypeNull; | |||
| #ifdef CARLA_ENGINE_JACK | |||
| jackClient = nullptr; | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| rtAudioPtr = nullptr; | |||
| #endif | |||
| } | |||
| }; | |||
| @@ -199,6 +193,11 @@ public: | |||
| static int maxClientNameSize(); | |||
| static int maxPortNameSize(); | |||
| static unsigned short maxPluginNumber(); | |||
| static const char* getFixedClientName(const char* const clientName); | |||
| static unsigned int getDriverCount(); | |||
| static const char* getDriverName(unsigned int index); | |||
| static CarlaEngine* newDriverByName(const char* driverName); | |||
| // ------------------------------------------------------------------- | |||
| // Virtual, per-engine type calls | |||
| @@ -216,7 +215,7 @@ public: | |||
| short getNewPluginId() const; | |||
| CarlaPlugin* getPlugin(const unsigned short id) const; | |||
| CarlaPlugin* getPluginUnchecked(const unsigned short id) const; | |||
| const char* getUniqueName(const char* const name); | |||
| const char* getUniquePluginName(const char* const name); | |||
| short addPlugin(const BinaryType btype, const PluginType ptype, const char* const filename, const char* const name, const char* const label, void* const extra = nullptr); | |||
| short addPlugin(const PluginType ptype, const char* const filename, const char* const name, const char* const label, void* const extra = nullptr); | |||
| @@ -404,6 +403,13 @@ private: | |||
| double m_outsPeak[MAX_PLUGINS * MAX_PEAKS]; | |||
| static unsigned short m_maxPluginNumber; | |||
| #ifdef CARLA_ENGINE_JACK | |||
| static CarlaEngine* newJack(); | |||
| #endif | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| static CarlaEngine* newRtAudio(RtAudio::Api api); | |||
| #endif | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| @@ -429,6 +435,7 @@ private: | |||
| // ----------------------------------------------------------------------- | |||
| // base | |||
| class CarlaEngineBasePort | |||
| { | |||
| public: | |||
| @@ -443,6 +450,7 @@ protected: | |||
| const CarlaEnginePortNativeHandle handle; | |||
| }; | |||
| // audio | |||
| class CarlaEngineAudioPort : public CarlaEngineBasePort | |||
| { | |||
| public: | |||
| @@ -455,6 +463,7 @@ public: | |||
| #endif | |||
| }; | |||
| // control | |||
| class CarlaEngineControlPort : public CarlaEngineBasePort | |||
| { | |||
| public: | |||
| @@ -468,6 +477,7 @@ public: | |||
| void writeEvent(CarlaEngineControlEventType type, uint32_t time, uint8_t channel, uint8_t controller, double value); | |||
| }; | |||
| // midi | |||
| class CarlaEngineMidiPort : public CarlaEngineBasePort | |||
| { | |||
| public: | |||
| @@ -483,84 +493,6 @@ public: | |||
| // ----------------------------------------------------------------------- | |||
| #ifdef CARLA_ENGINE_JACK | |||
| class CarlaEngineJack : public CarlaEngine | |||
| { | |||
| public: | |||
| CarlaEngineJack(); | |||
| ~CarlaEngineJack(); | |||
| // ------------------------------------- | |||
| bool init(const char* const clientName); | |||
| bool close(); | |||
| bool isOffline(); | |||
| bool isRunning(); | |||
| CarlaEngineClient* addClient(CarlaPlugin* const plugin); | |||
| // ------------------------------------- | |||
| void handleSampleRateCallback(double newSampleRate); | |||
| void handleBufferSizeCallback(uint32_t newBufferSize); | |||
| void handleFreewheelCallback(bool isFreewheel); | |||
| void handleProcessCallback(uint32_t nframes); | |||
| void handleShutdownCallback(); | |||
| // ------------------------------------- | |||
| private: | |||
| jack_client_t* client; | |||
| jack_transport_state_t state; | |||
| jack_position_t pos; | |||
| bool freewheel; | |||
| // ------------------------------------- | |||
| #ifndef BUILD_BRIDGE | |||
| static const unsigned short rackPortAudioIn1 = 0; | |||
| static const unsigned short rackPortAudioIn2 = 1; | |||
| static const unsigned short rackPortAudioOut1 = 2; | |||
| static const unsigned short rackPortAudioOut2 = 3; | |||
| static const unsigned short rackPortControlIn = 4; | |||
| static const unsigned short rackPortControlOut = 5; | |||
| static const unsigned short rackPortMidiIn = 6; | |||
| static const unsigned short rackPortMidiOut = 7; | |||
| static const unsigned short rackPortCount = 8; | |||
| jack_port_t* rackJackPorts[rackPortCount]; | |||
| #endif | |||
| }; | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| #ifdef CARLA_ENGINE_RTAUDIO | |||
| class CarlaEngineRtAudio : public CarlaEngine | |||
| { | |||
| public: | |||
| CarlaEngineRtAudio(RtAudio::Api api); | |||
| ~CarlaEngineRtAudio(); | |||
| // ------------------------------------- | |||
| bool init(const char* const clientName); | |||
| bool close(); | |||
| bool isOffline(); | |||
| bool isRunning(); | |||
| CarlaEngineClient* addClient(CarlaPlugin* const plugin); | |||
| // ------------------------------------- | |||
| void handleProcessCallback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status); | |||
| private: | |||
| RtAudio adac; | |||
| }; | |||
| #endif | |||
| /**@}*/ | |||
| CARLA_BACKEND_END_NAMESPACE | |||
| @@ -20,492 +20,546 @@ | |||
| #include "carla_engine.h" | |||
| #include "carla_plugin.h" | |||
| #include <iostream> | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| // static JACK<->Engine calls | |||
| static int carla_jack_srate_callback(jack_nframes_t newSampleRate, void* arg) | |||
| { | |||
| CarlaEngineJack* const engine = (CarlaEngineJack*)arg; | |||
| engine->handleSampleRateCallback(newSampleRate); | |||
| return 0; | |||
| } | |||
| static int carla_jack_bufsize_callback(jack_nframes_t newBufferSize, void* arg) | |||
| { | |||
| CarlaEngineJack* const engine = (CarlaEngineJack*)arg; | |||
| engine->handleBufferSizeCallback(newBufferSize); | |||
| return 0; | |||
| } | |||
| static void carla_jack_freewheel_callback(int starting, void* arg) | |||
| { | |||
| CarlaEngineJack* const engine = (CarlaEngineJack*)arg; | |||
| engine->handleFreewheelCallback(bool(starting)); | |||
| } | |||
| static int carla_jack_process_callback(jack_nframes_t nframes, void* arg) | |||
| { | |||
| CarlaEngineJack* const engine = (CarlaEngineJack*)arg; | |||
| engine->handleProcessCallback(nframes); | |||
| return 0; | |||
| } | |||
| // ----------------------------------------- | |||
| static int carla_jack_process_callback_plugin(jack_nframes_t nframes, void* arg) | |||
| class CarlaEngineJack : public CarlaEngine | |||
| { | |||
| CarlaPlugin* const plugin = (CarlaPlugin*)arg; | |||
| if (plugin && plugin->enabled()) | |||
| { | |||
| plugin->engineProcessLock(); | |||
| plugin->initBuffers(); | |||
| plugin->process_jack(nframes); | |||
| plugin->engineProcessUnlock(); | |||
| } | |||
| return 0; | |||
| } | |||
| static void carla_jack_shutdown_callback(void* arg) | |||
| { | |||
| CarlaEngineJack* const engine = (CarlaEngineJack*)arg; | |||
| engine->handleShutdownCallback(); | |||
| } | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| // Carla Engine (JACK) | |||
| CarlaEngineJack::CarlaEngineJack() | |||
| : CarlaEngine() | |||
| public: | |||
| CarlaEngineJack() | |||
| : CarlaEngine() | |||
| #ifndef BUILD_BRIDGE | |||
| # ifdef Q_COMPILER_INITIALIZER_LISTS | |||
| , rackJackPorts{nullptr} | |||
| , rackJackPorts{nullptr} | |||
| # endif | |||
| #endif | |||
| { | |||
| qDebug("CarlaEngineJack::CarlaEngineJack()"); | |||
| { | |||
| qDebug("CarlaEngineJack::CarlaEngineJack()"); | |||
| type = CarlaEngineTypeJack; | |||
| type = CarlaEngineTypeJack; | |||
| client = nullptr; | |||
| state = JackTransportStopped; | |||
| freewheel = false; | |||
| client = nullptr; | |||
| state = JackTransportStopped; | |||
| freewheel = false; | |||
| memset(&pos, 0, sizeof(jack_position_t)); | |||
| memset(&pos, 0, sizeof(jack_position_t)); | |||
| #ifndef BUILD_BRIDGE | |||
| # ifndef Q_COMPILER_INITIALIZER_LISTS | |||
| for (unsigned short i=0; i < rackPortCount; i++) | |||
| rackJackPorts[i] = nullptr; | |||
| for (unsigned short i=0; i < rackPortCount; i++) | |||
| rackJackPorts[i] = nullptr; | |||
| # endif | |||
| #endif | |||
| } | |||
| } | |||
| CarlaEngineJack::~CarlaEngineJack() | |||
| { | |||
| qDebug("CarlaEngineJack::~CarlaEngineJack()"); | |||
| } | |||
| ~CarlaEngineJack() | |||
| { | |||
| qDebug("CarlaEngineJack::~CarlaEngineJack()"); | |||
| } | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| // ------------------------------------- | |||
| bool CarlaEngineJack::init(const char* const clientName) | |||
| { | |||
| qDebug("CarlaEngineJack::init(\"%s\")", clientName); | |||
| bool init(const char* const clientName) | |||
| { | |||
| qDebug("CarlaEngineJack::init(\"%s\")", clientName); | |||
| client = jackbridge_client_open(clientName, JackNullOption, nullptr); | |||
| state = JackTransportStopped; | |||
| freewheel = false; | |||
| client = jackbridge_client_open(clientName, JackNullOption, nullptr); | |||
| state = JackTransportStopped; | |||
| freewheel = false; | |||
| if (client) | |||
| { | |||
| sampleRate = jackbridge_get_sample_rate(client); | |||
| bufferSize = jackbridge_get_buffer_size(client); | |||
| if (client) | |||
| { | |||
| sampleRate = jackbridge_get_sample_rate(client); | |||
| bufferSize = jackbridge_get_buffer_size(client); | |||
| 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_on_shutdown(client, carla_jack_shutdown_callback, this); | |||
| 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_on_shutdown(client, carla_jack_shutdown_callback, this); | |||
| #ifndef BUILD_BRIDGE | |||
| if (carlaOptions.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); | |||
| } | |||
| if (carlaOptions.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); | |||
| } | |||
| #endif | |||
| if (jackbridge_activate(client) == 0) | |||
| { | |||
| // set client name, fixed for OSC usage | |||
| // FIXME - put this in shared? | |||
| char* fixedName = strdup(jackbridge_get_client_name(client)); | |||
| for (size_t i=0; i < strlen(fixedName); i++) | |||
| if (jackbridge_activate(client) == 0) | |||
| { | |||
| name = getFixedClientName(jackbridge_get_client_name(client)); | |||
| CarlaEngine::init(name); | |||
| return true; | |||
| } | |||
| else | |||
| { | |||
| if (! (std::isalpha(fixedName[i]) || std::isdigit(fixedName[i]))) | |||
| fixedName[i] = '_'; | |||
| setLastError("Failed to activate the JACK client"); | |||
| client = nullptr; | |||
| } | |||
| } | |||
| else | |||
| setLastError("Failed to create new JACK client"); | |||
| name = strdup(fixedName); | |||
| free((void*)fixedName); | |||
| return false; | |||
| } | |||
| CarlaEngine::init(name); | |||
| bool close() | |||
| { | |||
| qDebug("CarlaEngineJack::close()"); | |||
| CarlaEngine::close(); | |||
| return true; | |||
| if (name) | |||
| { | |||
| free((void*)name); | |||
| name = nullptr; | |||
| } | |||
| else | |||
| if (jackbridge_deactivate(client) == 0) | |||
| { | |||
| setLastError("Failed to activate the JACK client"); | |||
| client = nullptr; | |||
| #ifndef BUILD_BRIDGE | |||
| if (carlaOptions.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]); | |||
| } | |||
| #endif | |||
| if (jackbridge_client_close(client) == 0) | |||
| { | |||
| client = nullptr; | |||
| return true; | |||
| } | |||
| else | |||
| setLastError("Failed to close the JACK client"); | |||
| } | |||
| } | |||
| else | |||
| setLastError("Failed to create new JACK client"); | |||
| else | |||
| setLastError("Failed to deactivate the JACK client"); | |||
| return false; | |||
| } | |||
| client = nullptr; | |||
| return false; | |||
| } | |||
| bool CarlaEngineJack::close() | |||
| { | |||
| qDebug("CarlaEngineJack::close()"); | |||
| CarlaEngine::close(); | |||
| bool isOffline() | |||
| { | |||
| return freewheel; | |||
| } | |||
| if (name) | |||
| bool isRunning() | |||
| { | |||
| free((void*)name); | |||
| name = nullptr; | |||
| return bool(client); | |||
| } | |||
| if (jackbridge_deactivate(client) == 0) | |||
| CarlaEngineClient* addClient(CarlaPlugin* const plugin) | |||
| { | |||
| CarlaEngineClientNativeHandle handle; | |||
| handle.type = CarlaEngineTypeJack; | |||
| #ifndef BUILD_BRIDGE | |||
| if (carlaOptions.processMode == PROCESS_MODE_CONTINUOUS_RACK) | |||
| if (carlaOptions.processMode == PROCESS_MODE_SINGLE_CLIENT) | |||
| { | |||
| 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]); | |||
| handle.jackClient = client; | |||
| } | |||
| else if (carlaOptions.processMode == PROCESS_MODE_MULTIPLE_CLIENTS) | |||
| #endif | |||
| if (jackbridge_client_close(client) == 0) | |||
| { | |||
| client = nullptr; | |||
| return true; | |||
| handle.jackClient = jackbridge_client_open(plugin->name(), JackNullOption, nullptr); | |||
| jackbridge_set_process_callback(handle.jackClient, carla_jack_process_callback_plugin, plugin); | |||
| } | |||
| else | |||
| setLastError("Failed to close the JACK client"); | |||
| } | |||
| else | |||
| setLastError("Failed to deactivate the JACK client"); | |||
| client = nullptr; | |||
| return false; | |||
| } | |||
| bool CarlaEngineJack::isOffline() | |||
| { | |||
| return freewheel; | |||
| } | |||
| bool CarlaEngineJack::isRunning() | |||
| { | |||
| return bool(client); | |||
| } | |||
| return new CarlaEngineClient(handle); | |||
| } | |||
| CarlaEngineClient* CarlaEngineJack::addClient(CarlaPlugin* const plugin) | |||
| { | |||
| CarlaEngineClientNativeHandle handle; | |||
| handle.type = type; | |||
| // ------------------------------------- | |||
| #ifndef BUILD_BRIDGE | |||
| if (carlaOptions.processMode == PROCESS_MODE_SINGLE_CLIENT) | |||
| { | |||
| handle.jackClient = client; | |||
| } | |||
| else if (carlaOptions.processMode == PROCESS_MODE_MULTIPLE_CLIENTS) | |||
| #endif | |||
| protected: | |||
| void handleSampleRateCallback(double newSampleRate) | |||
| { | |||
| handle.jackClient = jackbridge_client_open(plugin->name(), JackNullOption, nullptr); | |||
| jackbridge_set_process_callback(handle.jackClient, carla_jack_process_callback_plugin, plugin); | |||
| sampleRate = newSampleRate; | |||
| } | |||
| //else if (carla_options.process_mode == PROCESS_MODE_CONTINUOUS_RACK) | |||
| //{ | |||
| //} | |||
| return new CarlaEngineClient(handle); | |||
| } | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| void CarlaEngineJack::handleSampleRateCallback(double newSampleRate) | |||
| { | |||
| sampleRate = newSampleRate; | |||
| } | |||
| void CarlaEngineJack::handleBufferSizeCallback(uint32_t newBufferSize) | |||
| { | |||
| void handleBufferSizeCallback(uint32_t newBufferSize) | |||
| { | |||
| #ifndef BUILD_BRIDGE | |||
| if (carlaOptions.processHighPrecision) | |||
| return; | |||
| if (carlaOptions.processHighPrecision) | |||
| return; | |||
| #endif | |||
| bufferSizeChanged(newBufferSize); | |||
| } | |||
| bufferSizeChanged(newBufferSize); | |||
| } | |||
| void CarlaEngineJack::handleFreewheelCallback(bool isFreewheel) | |||
| { | |||
| freewheel = isFreewheel; | |||
| } | |||
| void handleFreewheelCallback(bool isFreewheel) | |||
| { | |||
| freewheel = isFreewheel; | |||
| } | |||
| void CarlaEngineJack::handleProcessCallback(uint32_t nframes) | |||
| { | |||
| void handleProcessCallback(uint32_t nframes) | |||
| { | |||
| #ifndef BUILD_BRIDGE | |||
| if (maxPluginNumber() == 0) | |||
| return; | |||
| if (maxPluginNumber() == 0) | |||
| return; | |||
| #endif | |||
| state = jackbridge_transport_query(client, &pos); | |||
| state = jackbridge_transport_query(client, &pos); | |||
| timeInfo.playing = (state != JackTransportStopped); | |||
| timeInfo.playing = (state != JackTransportStopped); | |||
| if (pos.unique_1 == pos.unique_2) | |||
| { | |||
| timeInfo.frame = pos.frame; | |||
| timeInfo.time = pos.usecs; | |||
| if (pos.valid & JackPositionBBT) | |||
| if (pos.unique_1 == pos.unique_2) | |||
| { | |||
| timeInfo.valid = CarlaEngineTimeBBT; | |||
| timeInfo.bbt.bar = pos.bar; | |||
| timeInfo.bbt.beat = pos.beat; | |||
| timeInfo.bbt.tick = pos.tick; | |||
| timeInfo.bbt.bar_start_tick = pos.bar_start_tick; | |||
| timeInfo.bbt.beats_per_bar = pos.beats_per_bar; | |||
| timeInfo.bbt.beat_type = pos.beat_type; | |||
| timeInfo.bbt.ticks_per_beat = pos.ticks_per_beat; | |||
| timeInfo.bbt.beats_per_minute = pos.beats_per_minute; | |||
| timeInfo.frame = pos.frame; | |||
| timeInfo.time = pos.usecs; | |||
| if (pos.valid & JackPositionBBT) | |||
| { | |||
| timeInfo.valid = CarlaEngineTimeBBT; | |||
| timeInfo.bbt.bar = pos.bar; | |||
| timeInfo.bbt.beat = pos.beat; | |||
| timeInfo.bbt.tick = pos.tick; | |||
| timeInfo.bbt.bar_start_tick = pos.bar_start_tick; | |||
| timeInfo.bbt.beats_per_bar = pos.beats_per_bar; | |||
| timeInfo.bbt.beat_type = pos.beat_type; | |||
| timeInfo.bbt.ticks_per_beat = pos.ticks_per_beat; | |||
| timeInfo.bbt.beats_per_minute = pos.beats_per_minute; | |||
| } | |||
| else | |||
| timeInfo.valid = 0; | |||
| } | |||
| else | |||
| { | |||
| timeInfo.frame = 0; | |||
| timeInfo.valid = 0; | |||
| } | |||
| else | |||
| { | |||
| timeInfo.frame = 0; | |||
| timeInfo.valid = 0; | |||
| } | |||
| } | |||
| #ifndef BUILD_BRIDGE | |||
| if (carlaOptions.processMode == PROCESS_MODE_SINGLE_CLIENT) | |||
| { | |||
| for (unsigned short i=0, max=maxPluginNumber(); i < max; i++) | |||
| if (carlaOptions.processMode == PROCESS_MODE_SINGLE_CLIENT) | |||
| { | |||
| CarlaPlugin* const plugin = getPluginUnchecked(i); | |||
| if (plugin && plugin->enabled()) | |||
| for (unsigned short i=0, max=maxPluginNumber(); i < max; i++) | |||
| { | |||
| plugin->engineProcessLock(); | |||
| plugin->initBuffers(); | |||
| plugin->process_jack(nframes); | |||
| plugin->engineProcessUnlock(); | |||
| CarlaPlugin* const plugin = getPluginUnchecked(i); | |||
| if (plugin && plugin->enabled()) | |||
| { | |||
| plugin->engineProcessLock(); | |||
| plugin->initBuffers(); | |||
| processPlugin(plugin, nframes); | |||
| plugin->engineProcessUnlock(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| else if (carlaOptions.processMode == PROCESS_MODE_CONTINUOUS_RACK) | |||
| { | |||
| // get buffers from jack | |||
| float* audioIn1 = (float*)jackbridge_port_get_buffer(rackJackPorts[rackPortAudioIn1], nframes); | |||
| float* audioIn2 = (float*)jackbridge_port_get_buffer(rackJackPorts[rackPortAudioIn2], nframes); | |||
| float* audioOut1 = (float*)jackbridge_port_get_buffer(rackJackPorts[rackPortAudioOut1], nframes); | |||
| float* audioOut2 = (float*)jackbridge_port_get_buffer(rackJackPorts[rackPortAudioOut2], nframes); | |||
| void* controlIn = jackbridge_port_get_buffer(rackJackPorts[rackPortControlIn], nframes); | |||
| void* controlOut = jackbridge_port_get_buffer(rackJackPorts[rackPortControlOut], nframes); | |||
| void* midiIn = jackbridge_port_get_buffer(rackJackPorts[rackPortMidiIn], nframes); | |||
| void* midiOut = jackbridge_port_get_buffer(rackJackPorts[rackPortMidiOut], nframes); | |||
| // assert buffers | |||
| CARLA_ASSERT(audioIn1); | |||
| CARLA_ASSERT(audioIn2); | |||
| CARLA_ASSERT(audioOut1); | |||
| CARLA_ASSERT(audioOut2); | |||
| CARLA_ASSERT(controlIn); | |||
| CARLA_ASSERT(controlOut); | |||
| CARLA_ASSERT(midiIn); | |||
| CARLA_ASSERT(midiOut); | |||
| // create audio buffers | |||
| float* inBuf[2] = { audioIn1, audioIn2 }; | |||
| float* outBuf[2] = { audioOut1, audioOut2 }; | |||
| // initialize control input | |||
| memset(rackControlEventsIn, 0, sizeof(CarlaEngineControlEvent)*MAX_ENGINE_CONTROL_EVENTS); | |||
| else if (carlaOptions.processMode == PROCESS_MODE_CONTINUOUS_RACK) | |||
| { | |||
| jackbridge_midi_event_t jackEvent; | |||
| const uint32_t jackEventCount = jackbridge_midi_get_event_count(controlIn); | |||
| uint32_t carlaEventIndex = 0; | |||
| for (uint32_t jackEventIndex=0; jackEventIndex < jackEventCount; jackEventIndex++) | |||
| // get buffers from jack | |||
| float* audioIn1 = (float*)jackbridge_port_get_buffer(rackJackPorts[rackPortAudioIn1], nframes); | |||
| float* audioIn2 = (float*)jackbridge_port_get_buffer(rackJackPorts[rackPortAudioIn2], nframes); | |||
| float* audioOut1 = (float*)jackbridge_port_get_buffer(rackJackPorts[rackPortAudioOut1], nframes); | |||
| float* audioOut2 = (float*)jackbridge_port_get_buffer(rackJackPorts[rackPortAudioOut2], nframes); | |||
| void* controlIn = jackbridge_port_get_buffer(rackJackPorts[rackPortControlIn], nframes); | |||
| void* controlOut = jackbridge_port_get_buffer(rackJackPorts[rackPortControlOut], nframes); | |||
| void* midiIn = jackbridge_port_get_buffer(rackJackPorts[rackPortMidiIn], nframes); | |||
| void* midiOut = jackbridge_port_get_buffer(rackJackPorts[rackPortMidiOut], nframes); | |||
| // assert buffers | |||
| CARLA_ASSERT(audioIn1); | |||
| CARLA_ASSERT(audioIn2); | |||
| CARLA_ASSERT(audioOut1); | |||
| CARLA_ASSERT(audioOut2); | |||
| CARLA_ASSERT(controlIn); | |||
| CARLA_ASSERT(controlOut); | |||
| CARLA_ASSERT(midiIn); | |||
| CARLA_ASSERT(midiOut); | |||
| // create audio buffers | |||
| float* inBuf[2] = { audioIn1, audioIn2 }; | |||
| float* outBuf[2] = { audioOut1, audioOut2 }; | |||
| // initialize control input | |||
| memset(rackControlEventsIn, 0, sizeof(CarlaEngineControlEvent)*MAX_ENGINE_CONTROL_EVENTS); | |||
| { | |||
| if (jackbridge_midi_event_get(&jackEvent, controlIn, jackEventIndex) != 0) | |||
| continue; | |||
| jackbridge_midi_event_t jackEvent; | |||
| const uint32_t jackEventCount = jackbridge_midi_get_event_count(controlIn); | |||
| CarlaEngineControlEvent* const carlaEvent = &rackControlEventsIn[carlaEventIndex++]; | |||
| uint32_t carlaEventIndex = 0; | |||
| uint8_t midiStatus = jackEvent.buffer[0]; | |||
| uint8_t midiChannel = midiStatus & 0x0F; | |||
| for (uint32_t jackEventIndex=0; jackEventIndex < jackEventCount; jackEventIndex++) | |||
| { | |||
| if (jackbridge_midi_event_get(&jackEvent, controlIn, jackEventIndex) != 0) | |||
| continue; | |||
| carlaEvent->time = jackEvent.time; | |||
| carlaEvent->channel = midiChannel; | |||
| CarlaEngineControlEvent* const carlaEvent = &rackControlEventsIn[carlaEventIndex++]; | |||
| if (MIDI_IS_STATUS_CONTROL_CHANGE(midiStatus)) | |||
| { | |||
| uint8_t midiControl = jackEvent.buffer[1]; | |||
| uint8_t midiStatus = jackEvent.buffer[0]; | |||
| uint8_t midiChannel = midiStatus & 0x0F; | |||
| 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->time = jackEvent.time; | |||
| carlaEvent->channel = midiChannel; | |||
| if (MIDI_IS_STATUS_CONTROL_CHANGE(midiStatus)) | |||
| { | |||
| carlaEvent->type = CarlaEngineEventAllSoundOff; | |||
| 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; | |||
| } | |||
| } | |||
| else if (midiControl == MIDI_CONTROL_ALL_NOTES_OFF) | |||
| else if (MIDI_IS_STATUS_PROGRAM_CHANGE(midiStatus)) | |||
| { | |||
| carlaEvent->type = CarlaEngineEventAllNotesOff; | |||
| uint8_t midiProgram = jackEvent.buffer[1]; | |||
| carlaEvent->type = CarlaEngineEventMidiProgramChange; | |||
| carlaEvent->value = midiProgram; | |||
| } | |||
| else | |||
| } | |||
| } | |||
| // initialize midi input | |||
| memset(rackMidiEventsIn, 0, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS); | |||
| { | |||
| uint32_t i = 0, j = 0; | |||
| jackbridge_midi_event_t jackEvent; | |||
| while (jackbridge_midi_event_get(&jackEvent, midiIn, j++) == 0) | |||
| { | |||
| if (i == MAX_ENGINE_MIDI_EVENTS) | |||
| break; | |||
| if (jackEvent.size < 4) | |||
| { | |||
| uint8_t midiValue = jackEvent.buffer[2]; | |||
| carlaEvent->type = CarlaEngineEventControlChange; | |||
| carlaEvent->controller = midiControl; | |||
| carlaEvent->value = double(midiValue)/127; | |||
| rackMidiEventsIn[i].time = jackEvent.time; | |||
| rackMidiEventsIn[i].size = jackEvent.size; | |||
| memcpy(rackMidiEventsIn[i].data, jackEvent.buffer, jackEvent.size); | |||
| i += 1; | |||
| } | |||
| } | |||
| else if (MIDI_IS_STATUS_PROGRAM_CHANGE(midiStatus)) | |||
| } | |||
| // process rack | |||
| processRack(inBuf, outBuf, nframes); | |||
| // output control | |||
| { | |||
| jackbridge_midi_clear_buffer(controlOut); | |||
| for (unsigned short i=0; i < MAX_ENGINE_CONTROL_EVENTS; i++) | |||
| { | |||
| uint8_t midiProgram = jackEvent.buffer[1]; | |||
| carlaEvent->type = CarlaEngineEventMidiProgramChange; | |||
| carlaEvent->value = midiProgram; | |||
| CarlaEngineControlEvent* const event = &rackControlEventsOut[i]; | |||
| if (event->type == CarlaEngineEventControlChange && MIDI_IS_CONTROL_BANK_SELECT(event->controller)) | |||
| event->type = CarlaEngineEventMidiBankChange; | |||
| uint8_t data[4] = { 0 }; | |||
| switch (event->type) | |||
| { | |||
| case CarlaEngineEventNull: | |||
| break; | |||
| case CarlaEngineEventControlChange: | |||
| 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: | |||
| 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: | |||
| data[0] = MIDI_STATUS_PROGRAM_CHANGE + event->channel; | |||
| data[1] = event->value; | |||
| jackbridge_midi_event_write(controlOut, event->time, data, 2); | |||
| break; | |||
| case CarlaEngineEventAllSoundOff: | |||
| 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: | |||
| data[0] = MIDI_STATUS_CONTROL_CHANGE + event->channel; | |||
| data[1] = MIDI_CONTROL_ALL_NOTES_OFF; | |||
| jackbridge_midi_event_write(controlOut, event->time, data, 2); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // initialize midi input | |||
| memset(rackMidiEventsIn, 0, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS); | |||
| { | |||
| uint32_t i = 0, j = 0; | |||
| jackbridge_midi_event_t jackEvent; | |||
| while (jackbridge_midi_event_get(&jackEvent, midiIn, j++) == 0) | |||
| // output midi | |||
| { | |||
| if (i == MAX_ENGINE_MIDI_EVENTS) | |||
| break; | |||
| jackbridge_midi_clear_buffer(midiOut); | |||
| if (jackEvent.size < 4) | |||
| for (unsigned short i=0; i < MAX_ENGINE_MIDI_EVENTS; i++) | |||
| { | |||
| rackMidiEventsIn[i].time = jackEvent.time; | |||
| rackMidiEventsIn[i].size = jackEvent.size; | |||
| memcpy(rackMidiEventsIn[i].data, jackEvent.buffer, jackEvent.size); | |||
| i += 1; | |||
| if (rackMidiEventsOut[i].size == 0) | |||
| break; | |||
| jackbridge_midi_event_write(midiOut, rackMidiEventsOut[i].time, rackMidiEventsOut[i].data, rackMidiEventsOut[i].size); | |||
| } | |||
| } | |||
| } | |||
| #else | |||
| Q_UNUSED(nframes); | |||
| #endif | |||
| } | |||
| // process rack | |||
| processRack(inBuf, outBuf, nframes); | |||
| // output control | |||
| void handleShutdownCallback() | |||
| { | |||
| for (unsigned short i=0, max=maxPluginNumber(); i < max; i++) | |||
| { | |||
| jackbridge_midi_clear_buffer(controlOut); | |||
| CarlaPlugin* const plugin = getPluginUnchecked(i); | |||
| plugin->x_client = nullptr; | |||
| } | |||
| for (unsigned short i=0; i < MAX_ENGINE_CONTROL_EVENTS; i++) | |||
| { | |||
| CarlaEngineControlEvent* const event = &rackControlEventsOut[i]; | |||
| client = nullptr; | |||
| callback(CALLBACK_QUIT, 0, 0, 0, 0.0); | |||
| } | |||
| if (event->type == CarlaEngineEventControlChange && MIDI_IS_CONTROL_BANK_SELECT(event->controller)) | |||
| event->type = CarlaEngineEventMidiBankChange; | |||
| // ------------------------------------- | |||
| uint8_t data[4] = { 0 }; | |||
| private: | |||
| jack_client_t* client; | |||
| jack_transport_state_t state; | |||
| jack_position_t pos; | |||
| bool freewheel; | |||
| switch (event->type) | |||
| { | |||
| case CarlaEngineEventNull: | |||
| break; | |||
| case CarlaEngineEventControlChange: | |||
| 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: | |||
| 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: | |||
| data[0] = MIDI_STATUS_PROGRAM_CHANGE + event->channel; | |||
| data[1] = event->value; | |||
| jackbridge_midi_event_write(controlOut, event->time, data, 2); | |||
| break; | |||
| case CarlaEngineEventAllSoundOff: | |||
| 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: | |||
| data[0] = MIDI_STATUS_CONTROL_CHANGE + event->channel; | |||
| data[1] = MIDI_CONTROL_ALL_NOTES_OFF; | |||
| jackbridge_midi_event_write(controlOut, event->time, data, 2); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| // ------------------------------------- | |||
| #ifndef BUILD_BRIDGE | |||
| enum RackPorts { | |||
| rackPortAudioIn1 = 0, | |||
| rackPortAudioIn2 = 1, | |||
| rackPortAudioOut1 = 2, | |||
| rackPortAudioOut2 = 3, | |||
| rackPortControlIn = 4, | |||
| rackPortControlOut = 5, | |||
| rackPortMidiIn = 6, | |||
| rackPortMidiOut = 7, | |||
| rackPortCount = 8 | |||
| }; | |||
| jack_port_t* rackJackPorts[rackPortCount]; | |||
| #endif | |||
| static void processPlugin(CarlaPlugin* const p, const uint32_t nframes) | |||
| { | |||
| float* inBuffer[p->aIn.count]; | |||
| float* outBuffer[p->aOut.count]; | |||
| // output midi | |||
| for (uint32_t i=0; i < p->aIn.count; i++) | |||
| inBuffer[i] = p->aIn.ports[i]->getJackAudioBuffer(nframes); | |||
| for (uint32_t i=0; i < p->aOut.count; i++) | |||
| outBuffer[i] = p->aOut.ports[i]->getJackAudioBuffer(nframes); | |||
| #ifndef BUILD_BRIDGE | |||
| if (carlaOptions.processHighPrecision) | |||
| { | |||
| jackbridge_midi_clear_buffer(midiOut); | |||
| float* inBuffer2[p->aIn.count]; | |||
| float* outBuffer2[p->aOut.count]; | |||
| for (unsigned short i=0; i < MAX_ENGINE_MIDI_EVENTS; i++) | |||
| for (uint32_t i=0, j; i < nframes; i += 8) | |||
| { | |||
| if (rackMidiEventsOut[i].size == 0) | |||
| break; | |||
| for (j=0; j < p->aIn.count; j++) | |||
| inBuffer2[j] = inBuffer[j] + i; | |||
| jackbridge_midi_event_write(midiOut, rackMidiEventsOut[i].time, rackMidiEventsOut[i].data, rackMidiEventsOut[i].size); | |||
| for (j=0; j < p->aOut.count; j++) | |||
| outBuffer2[j] = outBuffer[j] + i; | |||
| p->process(inBuffer2, outBuffer2, 8, i); | |||
| } | |||
| } | |||
| } | |||
| #else | |||
| Q_UNUSED(nframes); | |||
| else | |||
| #endif | |||
| } | |||
| p->process(inBuffer, outBuffer, nframes); | |||
| } | |||
| void CarlaEngineJack::handleShutdownCallback() | |||
| static int carla_jack_srate_callback(jack_nframes_t newSampleRate, void* arg) | |||
| { | |||
| CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg; | |||
| _this_->handleSampleRateCallback(newSampleRate); | |||
| return 0; | |||
| } | |||
| static int carla_jack_bufsize_callback(jack_nframes_t newBufferSize, void* arg) | |||
| { | |||
| CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg; | |||
| _this_->handleBufferSizeCallback(newBufferSize); | |||
| return 0; | |||
| } | |||
| static void carla_jack_freewheel_callback(int starting, void* arg) | |||
| { | |||
| CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg; | |||
| _this_->handleFreewheelCallback(bool(starting)); | |||
| } | |||
| static int carla_jack_process_callback(jack_nframes_t nframes, void* arg) | |||
| { | |||
| CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg; | |||
| _this_->handleProcessCallback(nframes); | |||
| return 0; | |||
| } | |||
| static int carla_jack_process_callback_plugin(jack_nframes_t nframes, void* arg) | |||
| { | |||
| CarlaPlugin* const plugin = (CarlaPlugin*)arg; | |||
| if (plugin && plugin->enabled()) | |||
| { | |||
| plugin->engineProcessLock(); | |||
| plugin->initBuffers(); | |||
| processPlugin(plugin, nframes); | |||
| plugin->engineProcessUnlock(); | |||
| } | |||
| return 0; | |||
| } | |||
| static void carla_jack_shutdown_callback(void* arg) | |||
| { | |||
| CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg; | |||
| _this_->handleShutdownCallback(); | |||
| } | |||
| }; | |||
| // ----------------------------------------- | |||
| CarlaEngine* CarlaEngine::newJack() | |||
| { | |||
| //for (unsigned short i=0, max=maxPluginNumber(); i < max; i++) | |||
| //{ | |||
| //CarlaPlugin* const plugin = getPluginUnchecked(i); | |||
| //plugin->x_client | |||
| //} | |||
| client = nullptr; | |||
| callback(CALLBACK_QUIT, 0, 0, 0, 0.0); | |||
| return new CarlaEngineJack(); | |||
| } | |||
| // ----------------------------------------- | |||
| CARLA_BACKEND_END_NAMESPACE | |||
| #endif // CARLA_ENGINE_JACK | |||
| @@ -22,223 +22,239 @@ | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| // static RtAudio<->Engine calls | |||
| // ----------------------------------------- | |||
| static int carla_rtaudio_process_callback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status, void* userData) | |||
| class CarlaEngineRtAudio : public CarlaEngine | |||
| { | |||
| CarlaEngineRtAudio* const engine = (CarlaEngineRtAudio*)userData; | |||
| engine->handleProcessCallback(outputBuffer, inputBuffer, nframes, streamTime, status); | |||
| return 0; | |||
| } | |||
| public: | |||
| CarlaEngineRtAudio(RtAudio::Api api) | |||
| : CarlaEngine(), | |||
| audio(api) | |||
| { | |||
| qDebug("CarlaEngineRtAudio::CarlaEngineRtAudio()"); | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| // Carla Engine (RtAudio) | |||
| type = CarlaEngineTypeRtAudio; | |||
| CarlaEngineRtAudio::CarlaEngineRtAudio(RtAudio::Api api) | |||
| : CarlaEngine(), | |||
| adac(api) | |||
| { | |||
| qDebug("CarlaEngineRtAudio::CarlaEngineRtAudio()"); | |||
| midiIn = nullptr; | |||
| midiOut = nullptr; | |||
| type = CarlaEngineTypeRtAudio; | |||
| } | |||
| CarlaEngineRtAudio::~CarlaEngineRtAudio() | |||
| { | |||
| qDebug("CarlaEngineRtAudio::~CarlaEngineRtAudio()"); | |||
| } | |||
| bool CarlaEngineRtAudio::init(const char* const clientName) | |||
| { | |||
| qDebug("CarlaEngineRtAudio::init(\"%s\")", clientName); | |||
| if (adac.getDeviceCount() < 1) | |||
| { | |||
| setLastError("No audio devices available"); | |||
| return false; | |||
| // just to make sure | |||
| carlaOptions.forceStereo = true; | |||
| carlaOptions.processMode = PROCESS_MODE_CONTINUOUS_RACK; | |||
| } | |||
| sampleRate = 48000; | |||
| unsigned int rtBufferFrames = 512; | |||
| RtAudio::StreamParameters iParams, oParams; | |||
| //iParams.deviceId = 3; | |||
| //oParams.deviceId = 2; | |||
| iParams.nChannels = 2; | |||
| oParams.nChannels = 2; | |||
| RtAudio::StreamOptions options; | |||
| options.flags = /*RTAUDIO_NONINTERLEAVED |*/ RTAUDIO_MINIMIZE_LATENCY /*| RTAUDIO_HOG_DEVICE*/ | RTAUDIO_SCHEDULE_REALTIME | RTAUDIO_ALSA_USE_DEFAULT; | |||
| options.streamName = clientName; | |||
| options.priority = 85; | |||
| try { | |||
| adac.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, sampleRate, &rtBufferFrames, carla_rtaudio_process_callback, this, &options); | |||
| } | |||
| catch (RtError& e) | |||
| ~CarlaEngineRtAudio() | |||
| { | |||
| setLastError(e.what()); | |||
| return false; | |||
| qDebug("CarlaEngineRtAudio::~CarlaEngineRtAudio()"); | |||
| } | |||
| bufferSize = rtBufferFrames; | |||
| // ------------------------------------- | |||
| // set client name, fixed for OSC usage | |||
| // FIXME - put this in shared? | |||
| char* fixedName = strdup(clientName); | |||
| for (size_t i=0; i < strlen(fixedName); i++) | |||
| bool init(const char* const clientName) | |||
| { | |||
| if (! (std::isalpha(fixedName[i]) || std::isdigit(fixedName[i]))) | |||
| fixedName[i] = '_'; | |||
| qDebug("CarlaEngineRtAudio::init(\"%s\")", clientName); | |||
| if (audio.getDeviceCount() < 1) | |||
| { | |||
| setLastError("No audio devices available for this driver"); | |||
| return false; | |||
| } | |||
| bufferSize = carlaOptions.preferredBufferSize; | |||
| sampleRate = carlaOptions.preferredSampleRate; | |||
| RtAudio::StreamParameters iParams, oParams; | |||
| //iParams.deviceId = 3; | |||
| //oParams.deviceId = 2; | |||
| iParams.nChannels = 2; | |||
| oParams.nChannels = 2; | |||
| RtAudio::StreamOptions options; | |||
| options.flags = /*RTAUDIO_NONINTERLEAVED |*/ RTAUDIO_MINIMIZE_LATENCY /*| RTAUDIO_HOG_DEVICE*/ | RTAUDIO_SCHEDULE_REALTIME | RTAUDIO_ALSA_USE_DEFAULT; | |||
| options.streamName = clientName; | |||
| options.priority = 85; | |||
| try { | |||
| audio.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, sampleRate, &bufferSize, carla_rtaudio_process_callback, this, &options); | |||
| } | |||
| catch (RtError& e) | |||
| { | |||
| setLastError(e.what()); | |||
| return false; | |||
| } | |||
| try { | |||
| audio.startStream(); | |||
| } | |||
| catch (RtError& e) | |||
| { | |||
| setLastError(e.what()); | |||
| return false; | |||
| } | |||
| midiIn = new MidiInAlsa(clientName, 512); | |||
| midiIn->openVirtualPort("control-in"); | |||
| midiIn->openVirtualPort("midi-in"); | |||
| midiOut = new MidiOutAlsa(clientName); | |||
| midiOut->openVirtualPort("control-out"); | |||
| midiOut->openVirtualPort("midi-out"); | |||
| name = getFixedClientName(clientName); | |||
| CarlaEngine::init(name); | |||
| return true; | |||
| } | |||
| name = strdup(fixedName); | |||
| free((void*)fixedName); | |||
| qDebug("RtAudio bufferSize = %i", bufferSize); | |||
| try { | |||
| adac.startStream(); | |||
| } | |||
| catch (RtError& e) | |||
| bool close() | |||
| { | |||
| setLastError(e.what()); | |||
| return false; | |||
| qDebug("CarlaEngineRtAudio::close()"); | |||
| CarlaEngine::close(); | |||
| if (name) | |||
| { | |||
| free((void*)name); | |||
| name = nullptr; | |||
| } | |||
| if (audio.isStreamRunning()) | |||
| audio.stopStream(); | |||
| if (audio.isStreamOpen()) | |||
| audio.closeStream(); | |||
| if (midiIn) | |||
| { | |||
| midiIn->cancelCallback(); | |||
| midiIn->closePort(); | |||
| delete midiIn; | |||
| midiIn = nullptr; | |||
| } | |||
| if (midiOut) | |||
| { | |||
| midiOut->closePort(); | |||
| delete midiOut; | |||
| midiOut = nullptr; | |||
| } | |||
| return true; | |||
| } | |||
| CarlaEngine::init(name); | |||
| return true; | |||
| } | |||
| bool CarlaEngineRtAudio::close() | |||
| { | |||
| qDebug("CarlaEngineRtAudio::close()"); | |||
| CarlaEngine::close(); | |||
| if (name) | |||
| bool isOffline() | |||
| { | |||
| free((void*)name); | |||
| name = nullptr; | |||
| return false; | |||
| } | |||
| if (adac.isStreamRunning()) | |||
| adac.stopStream(); | |||
| if (adac.isStreamOpen()) | |||
| adac.closeStream(); | |||
| return true; | |||
| } | |||
| bool CarlaEngineRtAudio::isOffline() | |||
| { | |||
| return false; | |||
| } | |||
| bool CarlaEngineRtAudio::isRunning() | |||
| { | |||
| return adac.isStreamRunning(); | |||
| } | |||
| CarlaEngineClient* CarlaEngineRtAudio::addClient(CarlaPlugin* const plugin) | |||
| { | |||
| CarlaEngineClientNativeHandle handle; | |||
| handle.type = type; | |||
| // unsigned int rtBufferFrames = getBufferSize(); | |||
| // RtAudio::StreamParameters iParams, oParams; | |||
| // iParams.nChannels = plugin->audioInCount(); | |||
| // oParams.nChannels = plugin->audioOutCount(); | |||
| // RtAudio::StreamOptions options; | |||
| // options.flags = /*RTAUDIO_NONINTERLEAVED |*/ RTAUDIO_MINIMIZE_LATENCY /*| RTAUDIO_HOG_DEVICE*/ | RTAUDIO_SCHEDULE_REALTIME | RTAUDIO_ALSA_USE_DEFAULT; | |||
| // options.streamName = plugin->name(); | |||
| // options.priority = 85; | |||
| // try { | |||
| // adac.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, getSampleRate(), &rtBufferFrames, carla_rtaudio_process_callback, this, &options); | |||
| // } | |||
| // catch (RtError& e) | |||
| // { | |||
| // setLastError(e.what()); | |||
| // return false; | |||
| // } | |||
| return new CarlaEngineClient(handle); | |||
| Q_UNUSED(plugin); | |||
| } | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| void CarlaEngineRtAudio::handleProcessCallback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status) | |||
| { | |||
| if (maxPluginNumber() == 0) | |||
| return; | |||
| // get buffers from RtAudio | |||
| float* insPtr = (float*)inputBuffer; | |||
| float* outsPtr = (float*)outputBuffer; | |||
| // assert buffers | |||
| CARLA_ASSERT(insPtr); | |||
| CARLA_ASSERT(outsPtr); | |||
| // create temporary audio buffers | |||
| float inBuf1[nframes]; | |||
| float inBuf2[nframes]; | |||
| float outBuf1[nframes]; | |||
| float outBuf2[nframes]; | |||
| // initialize audio input | |||
| for (unsigned int i=0; i < nframes*2; i++) | |||
| bool isRunning() | |||
| { | |||
| if (i % 2) | |||
| inBuf2[i/2] = insPtr[i]; | |||
| else | |||
| inBuf1[i/2] = insPtr[i]; | |||
| return audio.isStreamRunning(); | |||
| } | |||
| // create (real) audio buffers | |||
| float* inBuf[2] = { inBuf1, inBuf2 }; | |||
| float* outBuf[2] = { outBuf1, outBuf2 }; | |||
| // initialize control input | |||
| memset(rackControlEventsIn, 0, sizeof(CarlaEngineControlEvent)*MAX_ENGINE_CONTROL_EVENTS); | |||
| CarlaEngineClient* addClient(CarlaPlugin* const plugin) | |||
| { | |||
| // TODO | |||
| } | |||
| CarlaEngineClientNativeHandle handle; | |||
| handle.type = CarlaEngineTypeRtAudio; | |||
| // initialize midi input | |||
| memset(rackMidiEventsIn, 0, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS); | |||
| { | |||
| // TODO | |||
| return new CarlaEngineClient(handle); | |||
| Q_UNUSED(plugin); | |||
| } | |||
| processRack(inBuf, outBuf, nframes); | |||
| // ------------------------------------- | |||
| // output audio | |||
| for (unsigned int i=0; i < nframes*2; i++) | |||
| protected: | |||
| void handleProcessCallback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status) | |||
| { | |||
| if (i % 2) | |||
| outsPtr[i] = outBuf2[i/2]; | |||
| else | |||
| outsPtr[i] = outBuf1[i/2]; | |||
| if (maxPluginNumber() == 0) | |||
| return; | |||
| // get buffers from RtAudio | |||
| float* insPtr = (float*)inputBuffer; | |||
| float* outsPtr = (float*)outputBuffer; | |||
| // assert buffers | |||
| CARLA_ASSERT(insPtr); | |||
| CARLA_ASSERT(outsPtr); | |||
| // create temporary audio buffers | |||
| float inBuf1[nframes]; | |||
| float inBuf2[nframes]; | |||
| float outBuf1[nframes]; | |||
| float outBuf2[nframes]; | |||
| // initialize audio input | |||
| for (unsigned int i=0; i < nframes*2; i++) | |||
| { | |||
| if (i % 2) | |||
| inBuf2[i/2] = insPtr[i]; | |||
| else | |||
| inBuf1[i/2] = insPtr[i]; | |||
| } | |||
| // create (real) audio buffers | |||
| float* inBuf[2] = { inBuf1, inBuf2 }; | |||
| float* outBuf[2] = { outBuf1, outBuf2 }; | |||
| // initialize control input | |||
| memset(rackControlEventsIn, 0, sizeof(CarlaEngineControlEvent)*MAX_ENGINE_CONTROL_EVENTS); | |||
| { | |||
| // TODO | |||
| } | |||
| // initialize midi input | |||
| memset(rackMidiEventsIn, 0, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS); | |||
| { | |||
| // TODO | |||
| } | |||
| processRack(inBuf, outBuf, nframes); | |||
| // output audio | |||
| for (unsigned int i=0; i < nframes*2; i++) | |||
| { | |||
| if (i % 2) | |||
| outsPtr[i] = outBuf2[i/2]; | |||
| else | |||
| outsPtr[i] = outBuf1[i/2]; | |||
| } | |||
| // output control | |||
| { | |||
| // TODO | |||
| } | |||
| // output midi | |||
| { | |||
| // TODO | |||
| } | |||
| Q_UNUSED(streamTime); | |||
| Q_UNUSED(status); | |||
| } | |||
| // output control | |||
| { | |||
| // TODO | |||
| } | |||
| // ------------------------------------- | |||
| private: | |||
| RtAudio audio; | |||
| MidiInApi* midiIn; | |||
| MidiOutApi* midiOut; | |||
| // output midi | |||
| static int carla_rtaudio_process_callback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status, void* userData) | |||
| { | |||
| // TODO | |||
| CarlaEngineRtAudio* const _this_ = (CarlaEngineRtAudio*)userData; | |||
| _this_->handleProcessCallback(outputBuffer, inputBuffer, nframes, streamTime, status); | |||
| return 0; | |||
| } | |||
| }; | |||
| Q_UNUSED(streamTime); | |||
| Q_UNUSED(status); | |||
| // ----------------------------------------- | |||
| CarlaEngine* CarlaEngine::newRtAudio(RtAudio::Api api) | |||
| { | |||
| return new CarlaEngineRtAudio(api); | |||
| } | |||
| // ----------------------------------------- | |||
| CARLA_BACKEND_END_NAMESPACE | |||
| #endif // CARLA_ENGINE_RTAUDIO | |||
| @@ -18,6 +18,14 @@ | |||
| #include "carla_plugin.h" | |||
| #include "plugins/carla_native.h" | |||
| // Internal C plugins | |||
| extern "C" { | |||
| extern void carla_register_native_plugin_bypass(); | |||
| } | |||
| // Internal C++ plugins | |||
| extern void carla_register_native_plugin_midiSplit(); | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| struct NativePluginMidiData { | |||
| @@ -36,6 +44,7 @@ class NativePluginScopedInitiliazer | |||
| public: | |||
| NativePluginScopedInitiliazer() | |||
| { | |||
| firstInit = true; | |||
| } | |||
| ~NativePluginScopedInitiliazer() | |||
| @@ -51,6 +60,16 @@ public: | |||
| descriptors.clear(); | |||
| } | |||
| void maybeFirstInit() | |||
| { | |||
| if (firstInit) | |||
| { | |||
| firstInit = false; | |||
| carla_register_native_plugin_bypass(); | |||
| carla_register_native_plugin_midiSplit(); | |||
| } | |||
| } | |||
| void initializeIfNeeded(const PluginDescriptor* const desc) | |||
| { | |||
| if (descriptors.empty() || std::find(descriptors.begin(), descriptors.end(), desc) == descriptors.end()) | |||
| @@ -63,6 +82,7 @@ public: | |||
| } | |||
| private: | |||
| bool firstInit; | |||
| std::vector<const PluginDescriptor*> descriptors; | |||
| }; | |||
| @@ -1541,6 +1561,7 @@ public: | |||
| static size_t getPluginCount() | |||
| { | |||
| scopedInitliazer.maybeFirstInit(); | |||
| return pluginDescriptors.size(); | |||
| } | |||
| @@ -1601,9 +1622,9 @@ public: | |||
| // get info | |||
| if (name) | |||
| m_name = x_engine->getUniqueName(name); | |||
| m_name = x_engine->getUniquePluginName(name); | |||
| else | |||
| m_name = x_engine->getUniqueName(descriptor->name); | |||
| m_name = x_engine->getUniquePluginName(descriptor->name); | |||
| // --------------------------------------------------------------- | |||
| // register client | |||
| @@ -1358,44 +1358,6 @@ public: | |||
| Q_UNUSED(framesOffset); | |||
| } | |||
| #ifdef CARLA_ENGINE_JACK | |||
| /*! | |||
| * Plugin process callback, JACK helper version. | |||
| */ | |||
| void process_jack(const uint32_t nframes) | |||
| { | |||
| float* inBuffer[aIn.count]; | |||
| float* outBuffer[aOut.count]; | |||
| for (uint32_t i=0; i < aIn.count; i++) | |||
| inBuffer[i] = aIn.ports[i]->getJackAudioBuffer(nframes); | |||
| for (uint32_t i=0; i < aOut.count; i++) | |||
| outBuffer[i] = aOut.ports[i]->getJackAudioBuffer(nframes); | |||
| #ifndef BUILD_BRIDGE | |||
| if (carlaOptions.processHighPrecision) | |||
| { | |||
| float* inBuffer2[aIn.count]; | |||
| float* outBuffer2[aOut.count]; | |||
| for (uint32_t i=0, j; i < nframes; i += 8) | |||
| { | |||
| for (j=0; j < aIn.count; j++) | |||
| inBuffer2[j] = inBuffer[j] + i; | |||
| for (j=0; j < aOut.count; j++) | |||
| outBuffer2[j] = outBuffer[j] + i; | |||
| process(inBuffer2, outBuffer2, 8, i); | |||
| } | |||
| } | |||
| else | |||
| #endif | |||
| process(inBuffer, outBuffer, nframes); | |||
| } | |||
| #endif | |||
| /*! | |||
| * Tell the plugin the current buffer size has changed. | |||
| */ | |||
| @@ -2266,6 +2228,8 @@ protected: | |||
| { | |||
| return (value < 0.0) ? -value : value; | |||
| } | |||
| friend class CarlaEngineJack; | |||
| }; | |||
| /**@}*/ | |||
| @@ -1483,9 +1483,9 @@ public: | |||
| m_filename = strdup(filename); | |||
| if (name) | |||
| m_name = x_engine->getUniqueName(name); | |||
| m_name = x_engine->getUniquePluginName(name); | |||
| else | |||
| m_name = x_engine->getUniqueName(ldescriptor->Name); | |||
| m_name = x_engine->getUniquePluginName(ldescriptor->Name); | |||
| // --------------------------------------------------------------- | |||
| // register client | |||
| @@ -1251,9 +1251,9 @@ public: | |||
| m_label = strdup(label); | |||
| if (name) | |||
| m_name = x_engine->getUniqueName(name); | |||
| m_name = x_engine->getUniquePluginName(name); | |||
| else | |||
| m_name = x_engine->getUniqueName(label); | |||
| m_name = x_engine->getUniquePluginName(label); | |||
| // --------------------------------------------------------------- | |||
| // register client | |||
| @@ -1102,11 +1102,11 @@ public: | |||
| rdf_descriptor = ladspa_rdf_dup(rdf_descriptor_); | |||
| if (name) | |||
| m_name = x_engine->getUniqueName(name); | |||
| m_name = x_engine->getUniquePluginName(name); | |||
| else if (rdf_descriptor && rdf_descriptor->Title) | |||
| m_name = x_engine->getUniqueName(rdf_descriptor->Title); | |||
| m_name = x_engine->getUniquePluginName(rdf_descriptor->Title); | |||
| else | |||
| m_name = x_engine->getUniqueName(descriptor->Name); | |||
| m_name = x_engine->getUniquePluginName(descriptor->Name); | |||
| // --------------------------------------------------------------- | |||
| // register client | |||
| @@ -721,9 +721,9 @@ public: | |||
| m_filename = strdup(filename); | |||
| if (name) | |||
| m_name = x_engine->getUniqueName(name); | |||
| m_name = x_engine->getUniquePluginName(name); | |||
| else | |||
| m_name = x_engine->getUniqueName(label && label[0] ? label : info.InstrumentName.c_str()); | |||
| m_name = x_engine->getUniquePluginName(label && label[0] ? label : info.InstrumentName.c_str()); | |||
| sampler_channel = sampler->AddSamplerChannel(); | |||
| sampler_channel->SetEngineType(stype); | |||
| @@ -4031,9 +4031,9 @@ public: | |||
| m_filename = strdup(bundle); | |||
| if (name) | |||
| m_name = x_engine->getUniqueName(name); | |||
| m_name = x_engine->getUniquePluginName(name); | |||
| else | |||
| m_name = x_engine->getUniqueName(rdf_descriptor->Name); | |||
| m_name = x_engine->getUniquePluginName(rdf_descriptor->Name); | |||
| // --------------------------------------------------------------- | |||
| // register client | |||
| @@ -170,8 +170,7 @@ typedef struct _PluginDescriptor { | |||
| void carla_register_native_plugin(const PluginDescriptor* desc); | |||
| #define CARLA_REGISTER_NATIVE_PLUGIN(label, desc) \ | |||
| void carla_register_native_plugin_##label () __attribute__((constructor)); \ | |||
| #define CARLA_REGISTER_NATIVE_PLUGIN(label, desc) \ | |||
| void carla_register_native_plugin_##label () { carla_register_native_plugin(&desc); } | |||
| #ifdef __cplusplus | |||
| @@ -436,8 +436,7 @@ private: | |||
| // ----------------------------------------------------------------------- | |||
| #define CARLA_REGISTER_NATIVE_PLUGIN_MM(label, descMM) \ | |||
| void carla_register_native_plugin_##label () __attribute__((constructor)); \ | |||
| #define CARLA_REGISTER_NATIVE_PLUGIN_MM(label, descMM) \ | |||
| void carla_register_native_plugin_##label () { carla_register_native_plugin(descMM.descriptorInit()); } | |||
| #endif // CARLA_NATIVE_MM_H | |||
| @@ -2163,7 +2163,7 @@ public: | |||
| if (name) | |||
| { | |||
| m_name = x_engine->getUniqueName(name); | |||
| m_name = x_engine->getUniquePluginName(name); | |||
| } | |||
| else | |||
| { | |||
| @@ -2171,9 +2171,9 @@ public: | |||
| effect->dispatcher(effect, effGetEffectName, 0, 0, strBuf, 0.0f); | |||
| if (strBuf[0] != 0) | |||
| m_name = x_engine->getUniqueName(strBuf); | |||
| m_name = x_engine->getUniquePluginName(strBuf); | |||
| else | |||
| m_name = x_engine->getUniqueName(label); | |||
| m_name = x_engine->getUniquePluginName(label); | |||
| } | |||
| // --------------------------------------------------------------- | |||