From 5b98c24cacce0fc4d0593fd8cd52d8a1f9880766 Mon Sep 17 00:00:00 2001 From: falkTX Date: Tue, 19 Feb 2013 19:25:19 +0000 Subject: [PATCH] More rename and fixes; Initial RtAudio MIDI code --- source/backend/CarlaEngine.hpp | 15 +- .../{carla_engine.pro => CarlaEngine.pro} | 0 .../engine/{jack.cpp => CarlaEngineJack.cpp} | 98 ++-- .../{plugin.cpp => CarlaEnginePlugin.cpp} | 0 source/backend/engine/CarlaEngineRtAudio.cpp | 547 ++++++++++++++++++ source/backend/engine/Makefile | 6 +- .../{plugin => distrho}/DistrhoPluginInfo.h | 0 source/backend/engine/rtaudio.cpp | 421 -------------- source/backend/plugin/CarlaPluginInternal.hpp | 1 + source/tests/ANSI.cpp | 3 +- source/tests/Makefile | 4 +- source/utils/CarlaUtils.hpp | 6 +- 12 files changed, 598 insertions(+), 503 deletions(-) rename source/backend/engine/{carla_engine.pro => CarlaEngine.pro} (100%) rename source/backend/engine/{jack.cpp => CarlaEngineJack.cpp} (94%) rename source/backend/engine/{plugin.cpp => CarlaEnginePlugin.cpp} (100%) create mode 100644 source/backend/engine/CarlaEngineRtAudio.cpp rename source/backend/engine/{plugin => distrho}/DistrhoPluginInfo.h (100%) delete mode 100644 source/backend/engine/rtaudio.cpp diff --git a/source/backend/CarlaEngine.hpp b/source/backend/CarlaEngine.hpp index 22e6200d3..b89f6966a 100644 --- a/source/backend/CarlaEngine.hpp +++ b/source/backend/CarlaEngine.hpp @@ -836,6 +836,9 @@ public: */ float getOutputPeak(const unsigned int pluginId, const unsigned short id) const; + // FIXME - remove once IPC audio is implemented + void setPeaks(const unsigned int pluginId, float const inPeaks[MAX_PEAKS], float const outPeaks[MAX_PEAKS]); + // ------------------------------------------------------------------- // Callback @@ -958,14 +961,6 @@ protected: */ void proccessPendingEvents(); - /*! - * TODO. - */ -public: - // FIXME - remove once IPC audio is implemented - void setPeaks(const unsigned int pluginId, float const inPeaks[MAX_PEAKS], float const outPeaks[MAX_PEAKS]); - -private: #ifndef BUILD_BRIDGE // Rack mode data EngineEvent* getRackEventBuffer(const bool isInput); @@ -999,8 +994,8 @@ private: }; static CarlaEngine* newRtAudio(const RtAudioApi api); - static unsigned int getRtAudioApiCount(); - static const char* getRtAudioApiName(unsigned int index); + static size_t getRtAudioApiCount(); + static const char* getRtAudioApiName(const unsigned int index); #endif public: diff --git a/source/backend/engine/carla_engine.pro b/source/backend/engine/CarlaEngine.pro similarity index 100% rename from source/backend/engine/carla_engine.pro rename to source/backend/engine/CarlaEngine.pro diff --git a/source/backend/engine/jack.cpp b/source/backend/engine/CarlaEngineJack.cpp similarity index 94% rename from source/backend/engine/jack.cpp rename to source/backend/engine/CarlaEngineJack.cpp index 595d55632..fcb4d3fa4 100644 --- a/source/backend/engine/jack.cpp +++ b/source/backend/engine/CarlaEngineJack.cpp @@ -32,7 +32,7 @@ CARLA_BACKEND_START_NAMESPACE #endif // ------------------------------------------------------------------- -// Helpers, defined in carla_plugin.cpp +// Helpers, defined in CarlaPlugin.cpp extern CarlaEngine* CarlaPluginGetEngine(CarlaPlugin* const plugin); extern CarlaEngineAudioPort* CarlaPluginGetAudioInPort(CarlaPlugin* const plugin, uint32_t index); @@ -242,7 +242,7 @@ public: fRetEvent.midi.data[0] = midiStatus; fRetEvent.midi.data[1] = jackEvent.buffer[1]; fRetEvent.midi.data[2] = jackEvent.buffer[2]; - fRetEvent.midi.size = jackEvent.size; + fRetEvent.midi.size = static_cast(jackEvent.size); } return fRetEvent; @@ -257,7 +257,8 @@ public: CARLA_ASSERT(fJackBuffer != nullptr); CARLA_ASSERT(type != kEngineControlEventTypeNull); CARLA_ASSERT(channel < MAX_MIDI_CHANNELS); - CARLA_ASSERT(value >= 0.0 && value <= 1.0); + CARLA_ASSERT(param < MAX_MIDI_VALUE); + CARLA_SAFE_ASSERT(value >= 0.0 && value <= 1.0); if (kIsInput) return; @@ -267,11 +268,15 @@ public: return; if (channel >= MAX_MIDI_CHANNELS) return; + if (param >= MAX_MIDI_VALUE) + return; if (type == kEngineControlEventTypeParameter) { CARLA_ASSERT(! MIDI_IS_CONTROL_BANK_SELECT(param)); } + const double fixedValue = carla_fixValue(0.0, 1.0, value); + uint8_t data[3] = { 0 }; uint8_t size = 0; @@ -281,19 +286,19 @@ public: break; case kEngineControlEventTypeParameter: data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; - data[1] = param; - data[2] = value * 127; + data[1] = static_cast(param); + data[2] = uint8_t(fixedValue * 127.0); size = 3; break; case kEngineControlEventTypeMidiBank: data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; data[1] = MIDI_CONTROL_BANK_SELECT; - data[2] = param; + data[2] = static_cast(param); size = 3; break; case kEngineControlEventTypeMidiProgram: data[0] = MIDI_STATUS_PROGRAM_CHANGE + channel; - data[1] = param; + data[1] = static_cast(param); size = 2; break; case kEngineControlEventTypeAllSoundOff: @@ -467,7 +472,7 @@ public: return new CarlaEngineJackEventPort(isInput, kProcessMode, kClient, port); } - qCritical("CarlaEngineJackClient::addPort(%s, \"%s\", %s) - invalid type", EnginePortType2Str(portType), name, bool2str(isInput)); + carla_stderr("CarlaEngineJackClient::addPort(%s, \"%s\", %s) - invalid type", EnginePortType2Str(portType), name, bool2str(isInput)); return nullptr; } @@ -481,21 +486,6 @@ private: // ------------------------------------------------------------------------------------------------------------------- // Jack Engine -#if 0 -struct EnginePluginData { - CarlaEngine* const engine; - CarlaPlugin* const plugin; - - EnginePluginData(CarlaEngine* const engine_, CarlaPlugin* const plugin_) - : engine(engine_), - plugin(plugin_) {} - - EnginePluginData() = delete; - EnginePluginData(EnginePlugin&) = delete; - EnginePluginData(const EnginePlugin&) = delete; -}; -#endif - class CarlaEngineJack : public CarlaEngine { public: @@ -530,9 +520,7 @@ public: unsigned int maxClientNameSize() { -#ifndef BUILD_BRIDGE if (fOptions.processMode == PROCESS_MODE_SINGLE_CLIENT || fOptions.processMode == PROCESS_MODE_MULTIPLE_CLIENTS) -#endif return static_cast(jackbridge_client_name_size()); return CarlaEngine::maxClientNameSize(); @@ -540,9 +528,7 @@ public: unsigned int maxPortNameSize() { -#ifndef BUILD_BRIDGE if (fOptions.processMode == PROCESS_MODE_SINGLE_CLIENT || fOptions.processMode == PROCESS_MODE_MULTIPLE_CLIENTS) -#endif return static_cast(jackbridge_port_name_size()); return CarlaEngine::maxPortNameSize(); @@ -563,7 +549,7 @@ public: #ifndef BUILD_BRIDGE fClient = jackbridge_client_open(clientName, JackNullOption, nullptr); - if (fClient) + if (fClient != nullptr) { fBufferSize = jackbridge_get_buffer_size(fClient); fSampleRate = jackbridge_get_sample_rate(fClient); @@ -587,14 +573,14 @@ public: if (jackbridge_activate(fClient) == 0) { - const char* const clientName = jackbridge_get_client_name(fClient); + const char* const jackClientName = jackbridge_get_client_name(fClient); - CarlaEngine::init(clientName); - return true; + return CarlaEngine::init(jackClientName); } else { setLastError("Failed to activate the JACK client"); + jackbridge_client_close(fClient); fClient = nullptr; } } @@ -603,23 +589,19 @@ public: return false; #else - // open temp client to get initial buffer-size and sample-rate values if (fBufferSize == 0 || fSampleRate == 0.0) { - fClient = jackbridge_client_open(clientName, JackNullOption, nullptr); - - if (fClient) + // open temp client to get initial buffer-size and sample-rate values + if (jack_client_t* tmpClient = jackbridge_client_open(clientName, JackNullOption, nullptr)) { - fBufferSize = jackbridge_get_buffer_size(fClient); - fSampleRate = jackbridge_get_sample_rate(fClient); + fBufferSize = jackbridge_get_buffer_size(tmpClient); + fSampleRate = jackbridge_get_sample_rate(tmpClient); - jackbridge_client_close(fClient); - fClient = nullptr; + jackbridge_client_close(tmpClient); } } - CarlaEngine::init(clientName); - return true; + return CarlaEngine::init(clientName); #endif } @@ -709,11 +691,7 @@ public: } #endif -#ifdef BUILD_BRIDGE - return new CarlaEngineJackClient(kEngineTypeJack, PROCESS_MODE_MULTIPLE_CLIENTS, client); -#else return new CarlaEngineJackClient(kEngineTypeJack, fOptions.processMode, client); -#endif } // ------------------------------------- @@ -746,11 +724,9 @@ protected: void handleJackProcessCallback(const uint32_t nframes) { - proccessPendingEvents(); - #ifndef BUILD_BRIDGE if (kData->curPluginCount == 0) - return; + return proccessPendingEvents(); #endif fTransportPos.unique_1 = fTransportPos.unique_2 + 1; // invalidate @@ -974,17 +950,15 @@ protected: } #endif } -#endif +#endif // ! BUILD_BRIDGE proccessPendingEvents(); } void handleJackLatencyCallback(const jack_latency_callback_mode_t mode) { -#ifndef BUILD_BRIDGE if (fOptions.processMode != PROCESS_MODE_SINGLE_CLIENT) return; -#endif for (unsigned int i=0; i < kData->curPluginCount; i++) { @@ -1136,45 +1110,43 @@ private: // ------------------------------------- + #define handlePtr ((CarlaEngineJack*)arg) + static int carla_jack_srate_callback(jack_nframes_t newSampleRate, void* arg) { - if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg) - _this_->handleJackSampleRateCallback(newSampleRate); + handlePtr->handleJackSampleRateCallback(newSampleRate); return 0; } static int carla_jack_bufsize_callback(jack_nframes_t newBufferSize, void* arg) { - if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg) - _this_->handleJackBufferSizeCallback(newBufferSize); + handlePtr->handleJackBufferSizeCallback(newBufferSize); return 0; } static void carla_jack_freewheel_callback(int starting, void* arg) { - if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg) - _this_->handleJackFreewheelCallback(bool(starting)); + handlePtr->handleJackFreewheelCallback(bool(starting)); } static int carla_jack_process_callback(jack_nframes_t nframes, void* arg) { - if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg) - _this_->handleJackProcessCallback(nframes); + handlePtr->handleJackProcessCallback(nframes); return 0; } static void carla_jack_latency_callback(jack_latency_callback_mode_t mode, void* arg) { - if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg) - _this_->handleJackLatencyCallback(mode); + handlePtr->handleJackLatencyCallback(mode); } static void carla_jack_shutdown_callback(void* arg) { - if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg) - _this_->handleJackShutdownCallback(); + handlePtr->handleJackShutdownCallback(); } + #undef handlePtr + // ------------------------------------- #ifndef BUILD_BRIDGE diff --git a/source/backend/engine/plugin.cpp b/source/backend/engine/CarlaEnginePlugin.cpp similarity index 100% rename from source/backend/engine/plugin.cpp rename to source/backend/engine/CarlaEnginePlugin.cpp diff --git a/source/backend/engine/CarlaEngineRtAudio.cpp b/source/backend/engine/CarlaEngineRtAudio.cpp new file mode 100644 index 000000000..979b5e539 --- /dev/null +++ b/source/backend/engine/CarlaEngineRtAudio.cpp @@ -0,0 +1,547 @@ +/* + * Carla RtAudio Engine + * Copyright (C) 2012-2013 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the GPL.txt file + */ + +#ifdef WANT_RTAUDIO + +#include "CarlaEngineInternal.hpp" +#include "CarlaBackendUtils.hpp" +#include "CarlaMIDI.h" +#include "RtList.hpp" + +#include "RtAudio.h" +#include "RtMidi.h" + +CARLA_BACKEND_START_NAMESPACE + +#if 0 +} // Fix editor indentation +#endif + +// ------------------------------------------------------------------------------------------------------------------- + +RtMidi::Api getMatchedAudioMidiAPi(const RtAudio::Api rtApi) +{ + switch (rtApi) + { + case RtAudio::UNSPECIFIED: + return RtMidi::UNSPECIFIED; + + case RtAudio::LINUX_ALSA: + case RtAudio::LINUX_OSS: + case RtAudio::LINUX_PULSE: + return RtMidi::LINUX_ALSA; + + case RtAudio::UNIX_JACK: + return RtMidi::UNIX_JACK; + + case RtAudio::MACOSX_CORE: + return RtMidi::MACOSX_CORE; + + case RtAudio::WINDOWS_ASIO: + case RtAudio::WINDOWS_DS: + return RtMidi::WINDOWS_MM; + + case RtAudio::RTAUDIO_DUMMY: + return RtMidi::RTMIDI_DUMMY; + } + + return RtMidi::UNSPECIFIED; +} + +// ------------------------------------------------------------------------------------------------------------------- +// RtAudio Engine + +class CarlaEngineRtAudio : public CarlaEngine +{ +public: + CarlaEngineRtAudio(const RtAudio::Api api) + : CarlaEngine(), + fAudio(api), + fAudioIsInterleaved(false), + fAudioIsReady(false), + fAudioInBuf1(nullptr), + fAudioInBuf2(nullptr), + fAudioOutBuf1(nullptr), + fAudioOutBuf2(nullptr), + fMidiIn(getMatchedAudioMidiAPi(api)), + fMidiOut(getMatchedAudioMidiAPi(api)) + { + carla_debug("CarlaEngineRtAudio::CarlaEngineRtAudio(%i)", api); + + // just to make sure + fOptions.forceStereo = true; + fOptions.processMode = PROCESS_MODE_CONTINUOUS_RACK; + } + + ~CarlaEngineRtAudio() + { + carla_debug("CarlaEngineRtAudio::~CarlaEngineRtAudio()"); + CARLA_ASSERT(fAudioInBuf1 == nullptr); + CARLA_ASSERT(fAudioInBuf2 == nullptr); + CARLA_ASSERT(fAudioOutBuf1 == nullptr); + CARLA_ASSERT(fAudioOutBuf2 == nullptr); + } + + // ------------------------------------- + + bool init(const char* const clientName) + { + carla_debug("CarlaEngineRtAudio::init(\"%s\")", clientName); + CARLA_ASSERT(! fAudioIsReady); + CARLA_ASSERT(fAudioInBuf1 == nullptr); + CARLA_ASSERT(fAudioInBuf2 == nullptr); + CARLA_ASSERT(fAudioOutBuf1 == nullptr); + CARLA_ASSERT(fAudioOutBuf2 == nullptr); + + if (fAudio.getDeviceCount() == 0) + { + setLastError("No audio devices available for this driver"); + return false; + } + + fBufferSize = fOptions.preferredBufferSize; + + // Audio + { + RtAudio::StreamParameters iParams, oParams; + iParams.deviceId = fAudio.getDefaultInputDevice(); + oParams.deviceId = fAudio.getDefaultOutputDevice(); + iParams.nChannels = 2; + oParams.nChannels = 2; + + RtAudio::StreamOptions rtOptions; + rtOptions.flags = RTAUDIO_MINIMIZE_LATENCY | RTAUDIO_HOG_DEVICE | RTAUDIO_SCHEDULE_REALTIME; + rtOptions.numberOfBuffers = 2; + rtOptions.streamName = clientName; + rtOptions.priority = 85; + + if (fAudio.getCurrentApi() != RtAudio::LINUX_PULSE) + { + rtOptions.flags |= RTAUDIO_NONINTERLEAVED; + fAudioIsInterleaved = false; + + if (fAudio.getCurrentApi() == RtAudio::LINUX_ALSA) + rtOptions.flags |= RTAUDIO_ALSA_USE_DEFAULT; + } + else + fAudioIsInterleaved = true; + + try { + fAudio.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, fOptions.preferredSampleRate, &fBufferSize, carla_rtaudio_process_callback, this, &rtOptions); + } + catch (RtError& e) + { + setLastError(e.what()); + return false; + } + + try { + fAudio.startStream(); + } + catch (RtError& e) + { + setLastError(e.what()); + return false; + } + + fAudioInBuf1 = new float[fBufferSize]; + fAudioInBuf2 = new float[fBufferSize]; + fAudioOutBuf1 = new float[fBufferSize]; + fAudioOutBuf2 = new float[fBufferSize]; + + fSampleRate = fAudio.getStreamSampleRate(); + } + + // MIDI + { + fMidiIn.setCallback(carla_rtmidi_callback, this); + fMidiIn.openVirtualPort("events-in"); + fMidiOut.openVirtualPort("events-out"); + } + + fAudioIsReady = true; + + return CarlaEngine::init(clientName); + } + + bool close() + { + carla_debug("CarlaEngineRtAudio::close()"); + CARLA_ASSERT(fAudioIsReady); + CARLA_ASSERT(fAudioInBuf1 != nullptr); + CARLA_ASSERT(fAudioInBuf2 != nullptr); + CARLA_ASSERT(fAudioOutBuf1 != nullptr); + CARLA_ASSERT(fAudioOutBuf2 != nullptr); + + CarlaEngine::close(); + + fAudioIsReady = false; + + if (fAudio.isStreamRunning()) + fAudio.stopStream(); + + if (fAudio.isStreamOpen()) + fAudio.closeStream(); + + fMidiIn.cancelCallback(); + fMidiIn.closePort(); + fMidiOut.closePort(); + + if (fAudioInBuf1 != nullptr) + { + delete[] fAudioInBuf1; + fAudioInBuf1 = nullptr; + } + + if (fAudioInBuf2 != nullptr) + { + delete[] fAudioInBuf2; + fAudioInBuf2 = nullptr; + } + + if (fAudioOutBuf1 != nullptr) + { + delete[] fAudioOutBuf1; + fAudioOutBuf1 = nullptr; + } + + if (fAudioOutBuf2 != nullptr) + { + delete[] fAudioOutBuf2; + fAudioOutBuf2 = nullptr; + } + + fMidiInEvents.clear(); + fMidiOutEvents.clear(); + + return true; + } + + bool isRunning() const + { + return fAudio.isStreamRunning(); + } + + bool isOffline() const + { + return false; + } + + EngineType type() const + { + return kEngineTypeRtAudio; + } + + // ------------------------------------- + +protected: + void handleAudioProcessCallback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status) + { + // get buffers from RtAudio + float* insPtr = (float*)inputBuffer; + float* outsPtr = (float*)outputBuffer; + + // assert buffers + CARLA_ASSERT(insPtr != nullptr); + CARLA_ASSERT(outsPtr != nullptr); + + if (currentPluginCount() == 0 || ! fAudioIsReady) + { + carla_zeroFloat(outsPtr, sizeof(float)*nframes*2); + return; + } + + // initialize audio input + if (fAudioIsInterleaved) + { + for (unsigned int i=0; i < nframes*2; i++) + { + if (i % 2) + fAudioInBuf1[i/2] = insPtr[i]; + else + fAudioInBuf2[i/2] = insPtr[i]; + } + } + else + { + std::memcpy(fAudioInBuf1, insPtr, sizeof(float)*nframes); + std::memcpy(fAudioInBuf2, insPtr+nframes, sizeof(float)*nframes); + + //for (unsigned int i=0; i < nframes; i++) + // fAudioInBuf1[i] = insPtr[i]; + //for (unsigned int i=0, j=nframes; i < nframes; i++, j++) + // fAudioInBuf2[i] = insPtr[j]; + } + + // initialize audio output + carla_zeroFloat(fAudioOutBuf1, fBufferSize); + carla_zeroFloat(fAudioOutBuf2, fBufferSize); + + // initialize events input + //memset(rackEventsIn, 0, sizeof(EngineEvent)*MAX_EVENTS); + { + // TODO + } + + // create audio buffers + float* inBuf[2] = { fAudioInBuf1, fAudioInBuf2 }; + float* outBuf[2] = { fAudioOutBuf1, fAudioOutBuf2 }; + + processRack(inBuf, outBuf, nframes); + + // output audio + if (fAudioIsInterleaved) + { + for (unsigned int i=0; i < nframes*2; i++) + { + if (i % 2) + outsPtr[i] = fAudioOutBuf1[i/2]; + else + outsPtr[i] = fAudioOutBuf2[i/2]; + } + } + else + { + std::memcpy(outsPtr, fAudioOutBuf1, sizeof(float)*nframes); + std::memcpy(outsPtr+nframes, fAudioOutBuf2, sizeof(float)*nframes); + + //for (unsigned int i=0; i < nframes; i++) + // outsPtr[i] = fAudioOutBuf1[i]; + //for (unsigned int i=0, j=nframes; i < nframes; i++, j++) + // outsPtr[j] = fAudioOutBuf2[i]; + } + + // output events + { + // TODO + //fMidiOut.sendMessage(); + } + + (void)streamTime; + (void)status; + } + + void handleMidiCallback(const double timeStamp, std::vector* const message) + { + const size_t messageSize = message->size(); + + if (messageSize == 0 || messageSize > 3) + return; + + RtMidiEvent midiEvent; + midiEvent.time = timeStamp; + + if (messageSize == 1) + { + midiEvent.data[0] = message->at(0); + midiEvent.data[1] = 0; + midiEvent.data[2] = 0; + } + else if (messageSize == 2) + { + midiEvent.data[0] = message->at(0); + midiEvent.data[1] = message->at(1); + midiEvent.data[2] = 0; + } + else + { + midiEvent.data[0] = message->at(0); + midiEvent.data[1] = message->at(1); + midiEvent.data[2] = message->at(2); + } + + fMidiInEvents.append(midiEvent); + } + + // ------------------------------------- + +private: + RtAudio fAudio; + bool fAudioIsInterleaved; + bool fAudioIsReady; + float* fAudioInBuf1; + float* fAudioInBuf2; + float* fAudioOutBuf1; + float* fAudioOutBuf2; + + RtMidiIn fMidiIn; + RtMidiOut fMidiOut; + + struct RtMidiEvent { + double time; + unsigned char data[3]; + }; + + struct RtMidiEvents { + CarlaMutex mutex; + RtList::Pool dataPool; + RtList data; + RtList dataPending; + + RtMidiEvents() + : dataPool(512, 512), + data(&dataPool), + dataPending(&dataPool) {} + + ~RtMidiEvents() + { + clear(); + } + + void append(const RtMidiEvent& event) + { + mutex.lock(); + dataPending.append(event); + mutex.unlock(); + } + + void clear() + { + mutex.lock(); + data.clear(); + dataPending.clear(); + mutex.unlock(); + } + + void trySplice() + { + if (mutex.tryLock()) + { + dataPending.splice(data, true); + mutex.unlock(); + } + } + }; + + RtMidiEvents fMidiInEvents; + RtMidiEvents fMidiOutEvents; + + #define handlePtr ((CarlaEngineRtAudio*)userData) + + static int carla_rtaudio_process_callback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status, void* userData) + { + handlePtr->handleAudioProcessCallback(outputBuffer, inputBuffer, nframes, streamTime, status); + return 0; + } + + static void carla_rtmidi_callback(double timeStamp, std::vector* message, void* userData) + { + handlePtr->handleMidiCallback(timeStamp, message); + } + + #undef handlePtr + + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineRtAudio) +}; + +// ----------------------------------------- + +static std::vector sRtAudioApis; + +static void initRtApis() +{ + static bool initiated = false; + + if (! initiated) + { + initiated = true; + + RtAudio::getCompiledApi(sRtAudioApis); + } +} + +CarlaEngine* CarlaEngine::newRtAudio(RtAudioApi 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); +} + +size_t CarlaEngine::getRtAudioApiCount() +{ + initRtApis(); + + return sRtAudioApis.size(); +} + +const char* CarlaEngine::getRtAudioApiName(const unsigned int index) +{ + initRtApis(); + + if (index < sRtAudioApis.size()) + { + const RtAudio::Api& api(sRtAudioApis[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 + +#endif // CARLA_ENGINE_RTAUDIO diff --git a/source/backend/engine/Makefile b/source/backend/engine/Makefile index 6237c41d5..18eccb2f5 100644 --- a/source/backend/engine/Makefile +++ b/source/backend/engine/Makefile @@ -44,10 +44,10 @@ endif OBJS = \ CarlaEngine.cpp.o \ + CarlaEngineJack.cpp.o \ + CarlaEngineRtAudio.cpp.o \ CarlaEngineOsc.cpp.o \ - CarlaEngineThread.cpp.o \ - jack.cpp.o \ - rtaudio.cpp.o + CarlaEngineThread.cpp.o ifeq ($(CARLA_RTAUDIO_SUPPORT),true) OBJS += \ diff --git a/source/backend/engine/plugin/DistrhoPluginInfo.h b/source/backend/engine/distrho/DistrhoPluginInfo.h similarity index 100% rename from source/backend/engine/plugin/DistrhoPluginInfo.h rename to source/backend/engine/distrho/DistrhoPluginInfo.h diff --git a/source/backend/engine/rtaudio.cpp b/source/backend/engine/rtaudio.cpp deleted file mode 100644 index 1bf76ba11..000000000 --- a/source/backend/engine/rtaudio.cpp +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Carla RtAudio Engine - * Copyright (C) 2012-2013 Filipe Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * For a full copy of the GNU General Public License see the GPL.txt file - */ - -#ifdef WANT_RTAUDIO - -#include "CarlaEngineInternal.hpp" -#include "CarlaBackendUtils.hpp" -#include "CarlaMIDI.h" - -#include "RtAudio.h" -#include "RtMidi.h" - -CARLA_BACKEND_START_NAMESPACE - -#if 0 -} // Fix editor indentation -#endif - -// ------------------------------------------------------------------------------------------------------------------- -// RtAudio Engine - -class CarlaEngineRtAudio : public CarlaEngine -{ -public: - CarlaEngineRtAudio(RtAudio::Api api) - : CarlaEngine(), - audio(api) - { - qDebug("CarlaEngineRtAudio::CarlaEngineRtAudio(%i)", api); - - evIn = nullptr; - evOut = nullptr; - - m_audioInterleaved = false; - m_inBuf1 = nullptr; - m_inBuf2 = nullptr; - m_outBuf1 = nullptr; - m_outBuf2 = nullptr; - - // just to make sure - fOptions.forceStereo = true; - fOptions.processMode = PROCESS_MODE_CONTINUOUS_RACK; - } - - ~CarlaEngineRtAudio() - { - qDebug("CarlaEngineRtAudio::~CarlaEngineRtAudio()"); - } - - // ------------------------------------- - - bool init(const char* const clientName) - { - qDebug("CarlaEngineRtAudio::init(\"%s\")", clientName); - - if (audio.getDeviceCount() < 1) - { - setLastError("No audio devices available for this driver"); - return false; - } - - fBufferSize = fOptions.preferredBufferSize; - fSampleRate = fOptions.preferredSampleRate; - - RtAudio::StreamParameters iParams, oParams; - iParams.deviceId = audio.getDefaultInputDevice(); - oParams.deviceId = audio.getDefaultOutputDevice(); - iParams.nChannels = 2; - oParams.nChannels = 2; - - RtAudio::StreamOptions rtOptions; - rtOptions.flags = RTAUDIO_MINIMIZE_LATENCY | RTAUDIO_HOG_DEVICE | RTAUDIO_SCHEDULE_REALTIME; - rtOptions.numberOfBuffers = 2; - rtOptions.streamName = clientName; - rtOptions.priority = 85; - - if (audio.getCurrentApi() != RtAudio::LINUX_PULSE) - { - rtOptions.flags |= RTAUDIO_NONINTERLEAVED; - m_audioInterleaved = false; - - if (audio.getCurrentApi() == RtAudio::LINUX_ALSA) - rtOptions.flags |= RTAUDIO_ALSA_USE_DEFAULT; - } - else - m_audioInterleaved = true; - - try { - audio.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, fSampleRate, &fBufferSize, carla_rtaudio_process_callback, this, &rtOptions); - } - catch (RtError& e) - { - setLastError(e.what()); - return false; - } - - try { - audio.startStream(); - } - catch (RtError& e) - { - setLastError(e.what()); - return false; - } - - fSampleRate = audio.getStreamSampleRate(); - - m_inBuf1 = new float[fBufferSize]; - m_inBuf2 = new float[fBufferSize]; - m_outBuf1 = new float[fBufferSize]; - m_outBuf2 = new float[fBufferSize]; - - //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"); - - fName = clientName; - fName.toBasic(); - - CarlaEngine::init(fName); - return true; - } - - bool close() - { - qDebug("CarlaEngineRtAudio::close()"); - CarlaEngine::close(); - - if (audio.isStreamRunning()) - audio.stopStream(); - - if (audio.isStreamOpen()) - audio.closeStream(); - -#if 0 - if (midiIn) - { - midiIn->cancelCallback(); - midiIn->closePort(); - delete midiIn; - midiIn = nullptr; - } - - if (midiOut) - { - midiOut->closePort(); - delete midiOut; - midiOut = nullptr; - } -#endif - - if (m_inBuf1) - { - delete[] m_inBuf1; - m_inBuf1 = nullptr; - } - - if (m_inBuf2) - { - delete[] m_inBuf2; - m_inBuf2 = nullptr; - } - - if (m_outBuf1) - { - delete[] m_outBuf1; - m_outBuf1 = nullptr; - } - - if (m_outBuf2) - { - delete[] m_outBuf2; - m_outBuf2 = nullptr; - } - - return true; - } - - bool isRunning() const - { - return audio.isStreamRunning(); - } - - bool isOffline() const - { - return false; - } - - EngineType type() const - { - return kEngineTypeRtAudio; - } - - // ------------------------------------- - -protected: - void 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); - - // initialize audio input - if (m_audioInterleaved) - { - for (unsigned int i=0; i < nframes*2; i++) - { - if (i % 2) - m_inBuf2[i/2] = insPtr[i]; - else - m_inBuf1[i/2] = insPtr[i]; - } - } - else - { - for (unsigned int i=0; i < nframes; i++) - m_inBuf1[i] = insPtr[i]; - - for (unsigned int i=0, j=nframes; i < nframes; i++, j++) - m_inBuf2[i] = insPtr[j]; - } - - // create audio buffers - float* inBuf[2] = { m_inBuf1, m_inBuf2 }; - float* outBuf[2] = { m_outBuf1, m_outBuf2 }; - - // initialize events input - //memset(rackEventsIn, 0, sizeof(EngineEvent)*MAX_EVENTS); - { - // TODO - } - - processRack(inBuf, outBuf, nframes); - - // output audio - if (m_audioInterleaved) - { - for (unsigned int i=0; i < nframes*2; i++) - { - if (i % 2) - outsPtr[i] = m_outBuf2[i/2]; - else - outsPtr[i] = m_outBuf1[i/2]; - } - } - else - { - for (unsigned int i=0; i < nframes; i++) - outsPtr[i] = m_outBuf1[i]; - - for (unsigned int i=0, j=nframes; i < nframes; i++, j++) - outsPtr[j] = m_outBuf2[i]; - } - - // output control - { - // TODO - } - - // output midi - { - // TODO - } - - Q_UNUSED(streamTime); - Q_UNUSED(status); - } - - // ------------------------------------- - -private: - RtAudio audio; - ScopedPointer evIn; - ScopedPointer evOut; - - bool m_audioInterleaved; - float* m_inBuf1; - float* m_inBuf2; - float* m_outBuf1; - float* m_outBuf2; - - static int carla_rtaudio_process_callback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status, void* userData) - { - CarlaEngineRtAudio* const _this_ = (CarlaEngineRtAudio*)userData; - _this_->handleProcessCallback(outputBuffer, inputBuffer, nframes, streamTime, status); - return 0; - } - - CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineRtAudio) -}; - -// ----------------------------------------- - -static std::vector rtApis; - -static void initRtApis() -{ - static bool initiated = false; - - if (! initiated) - { - initiated = true; - - RtAudio::getCompiledApi(rtApis); - } -} - -CarlaEngine* CarlaEngine::newRtAudio(RtAudioApi 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() -{ - initRtApis(); - - return rtApis.size(); -} - -const char* CarlaEngine::getRtAudioApiName(unsigned int index) -{ - initRtApis(); - - if (index < rtApis.size()) - { - const RtAudio::Api& api(rtApis[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 - -#ifdef QTCREATOR_TEST -int main() -{ - return 0; -} - -#endif - -#endif // CARLA_ENGINE_RTAUDIO diff --git a/source/backend/plugin/CarlaPluginInternal.hpp b/source/backend/plugin/CarlaPluginInternal.hpp index a75c3917b..44e5dd7a6 100644 --- a/source/backend/plugin/CarlaPluginInternal.hpp +++ b/source/backend/plugin/CarlaPluginInternal.hpp @@ -443,6 +443,7 @@ struct CarlaPluginProtectedData { void appendRT(const PluginPostRtEvent& event) { + // FIXME!! need lock? dataPendingRT.append(event); } diff --git a/source/tests/ANSI.cpp b/source/tests/ANSI.cpp index c09c73ade..3e4258a98 100644 --- a/source/tests/ANSI.cpp +++ b/source/tests/ANSI.cpp @@ -16,7 +16,8 @@ */ // still need qt classes check -#include "engine/CarlaEngineThread.cpp" +//#include "CarlaPlugin.hpp" +#include "engine/RtAudio.cpp" #if 0 #include "CarlaDefines.hpp" diff --git a/source/tests/Makefile b/source/tests/Makefile index afbed7d6d..eafccbbb4 100644 --- a/source/tests/Makefile +++ b/source/tests/Makefile @@ -8,9 +8,9 @@ include ../Makefile.mk # -------------------------------------------------------------- -BUILD_CXX_FLAGS += -I../backend -I../includes -I../utils -Wall -Wextra +BUILD_CXX_FLAGS += -I../backend -I../includes -I../libs -I../utils -Wall -Wextra BUILD_CXX_FLAGS += -DWANT_JACK -DWANT_RTAUDIO -BUILD_CXX_FLAGS += -isystem /usr/include/qt4 +BUILD_CXX_FLAGS += -isystem /usr/include/qt4 -isystem ../backend/engine/rtaudio-4.0.11 # BUILD_CXX_FLAGS += -D_FORTIFY_SOURCE=2 -fstack-protector # BUILD_CXX_FLAGS += -I/opt/mingw32/include diff --git a/source/utils/CarlaUtils.hpp b/source/utils/CarlaUtils.hpp index 72bd3e418..d2ece9de0 100644 --- a/source/utils/CarlaUtils.hpp +++ b/source/utils/CarlaUtils.hpp @@ -237,7 +237,7 @@ const T& carla_fixValue(const T& min, const T& max, const T& value) template static inline -void carla_fill(T* data, const unsigned int size, const T v) +void carla_fill(T* data, const size_t size, const T v) { CARLA_ASSERT(data != nullptr); CARLA_ASSERT(size > 0); @@ -250,13 +250,13 @@ void carla_fill(T* data, const unsigned int size, const T v) } static inline -void carla_zeroDouble(double* data, const unsigned size) +void carla_zeroDouble(double* data, const size_t size) { carla_fill(data, size, 0.0); } static inline -void carla_zeroFloat(float* data, const unsigned size) +void carla_zeroFloat(float* data, const size_t size) { carla_fill(data, size, 0.0f); }