|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449 |
- /*
- * Carla RtAudio Engine
- * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
- *
- * 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
-
- // -------------------------------------------------------------------------------------------------------------------
-
- static const char** gRetNames = nullptr;
- static std::vector<RtAudio::Api> gRtAudioApis;
-
- static void initRtApis()
- {
- static bool initiated = false;
-
- if (! initiated)
- {
- initiated = true;
-
- RtAudio::getCompiledApi(gRtAudioApis);
- }
- }
-
- 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:
- #if defined(CARLA_OS_WIN)
- return RtMidi::WINDOWS_MM;
- #elif defined(CARLA_OS_MAC)
- return RtMidi::MACOSX_CORE;
- #elif defined(CARLA_OS_LINUX)
- return RtMidi::LINUX_ALSA;
- #else
- return RtMidi::UNIX_JACK;
- #endif
-
- 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),
- fAudioBufIn(nullptr),
- fAudioBufOut(nullptr),
- fAudioBufRackIn{nullptr},
- fAudioBufRackOut{nullptr},
- fAudioCountIn(0),
- fAudioCountOut(0),
- fAudioIsInterleaved(false),
- fAudioIsReady(false),
- fDummyMidiIn(getMatchedAudioMidiAPi(api), "Carla-Probe-In"),
- fDummyMidiOut(getMatchedAudioMidiAPi(api), "Carla-Probe-Out"),
- fLastConnectionId(0)
- {
- carla_debug("CarlaEngineRtAudio::CarlaEngineRtAudio(%i)", api);
-
- // just to make sure
- fOptions.forceStereo = true;
- fOptions.processMode = PROCESS_MODE_CONTINUOUS_RACK;
- }
-
- ~CarlaEngineRtAudio() override
- {
- CARLA_ASSERT(fAudioBufIn == nullptr);
- CARLA_ASSERT(fAudioBufOut == nullptr);
- CARLA_ASSERT(fAudioCountIn == 0);
- CARLA_ASSERT(fAudioCountOut == 0);
- CARLA_ASSERT(! fAudioIsReady);
- carla_debug("CarlaEngineRtAudio::~CarlaEngineRtAudio()");
-
- fUsedMidiIns.clear();
- fUsedMidiOuts.clear();
- fUsedConnections.clear();
-
- if (gRetNames != nullptr)
- {
- delete[] gRetNames;
- gRetNames = nullptr;
- }
- }
-
- // -------------------------------------
-
- bool init(const char* const clientName) override
- {
- CARLA_ASSERT(fAudioBufIn == nullptr);
- CARLA_ASSERT(fAudioBufOut == nullptr);
- CARLA_ASSERT(fAudioCountIn == 0);
- CARLA_ASSERT(fAudioCountOut == 0);
- CARLA_ASSERT(! fAudioIsReady);
- CARLA_ASSERT(clientName != nullptr);
- carla_debug("CarlaEngineRtAudio::init(\"%s\")", clientName);
-
- RtAudio::StreamParameters iParams, oParams;
- bool deviceSet = false;
-
- const unsigned int devCount(fAudio.getDeviceCount());
-
- if (devCount == 0)
- {
- setLastError("No audio devices available for this driver");
- return false;
- }
-
- if (fOptions.rtaudioDevice.isNotEmpty())
- {
- for (unsigned int i=0; i < devCount; ++i)
- {
- RtAudio::DeviceInfo devInfo(fAudio.getDeviceInfo(i));
-
- if (devInfo.probed && devInfo.outputChannels > 0 && devInfo.name == (const char*)fOptions.rtaudioDevice)
- {
- deviceSet = true;
- fConnectName = devInfo.name.c_str();
- iParams.deviceId = i;
- oParams.deviceId = i;
- iParams.nChannels = devInfo.inputChannels;
- oParams.nChannels = devInfo.outputChannels;
- break;
- }
- }
- }
-
- if (! deviceSet)
- {
- 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.streamName = clientName;
- rtOptions.priority = 85;
-
- if (fAudio.getCurrentApi() != RtAudio::LINUX_PULSE)
- {
- rtOptions.flags |= RTAUDIO_NONINTERLEAVED;
- fAudioIsInterleaved = false;
-
- if (fAudio.getCurrentApi() == RtAudio::LINUX_ALSA && ! deviceSet)
- rtOptions.flags |= RTAUDIO_ALSA_USE_DEFAULT;
- }
- else
- fAudioIsInterleaved = true;
-
- fBufferSize = fOptions.rtaudioBufferSize;
-
- try {
- fAudio.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, fOptions.rtaudioSampleRate, &fBufferSize, carla_rtaudio_process_callback, this, &rtOptions);
- }
- catch (RtError& e)
- {
- setLastError(e.what());
- return false;
- }
-
- try {
- fAudio.startStream();
- }
- catch (RtError& e)
- {
- setLastError(e.what());
- fAudio.closeStream();
- return false;
- }
-
- fAudioCountIn = iParams.nChannels;
- fAudioCountOut = oParams.nChannels;
- fSampleRate = fAudio.getStreamSampleRate();
-
- CARLA_ASSERT(fAudioCountOut > 0);
-
- if (fAudioCountIn > 0)
- {
- fAudioBufIn = new float*[fAudioCountIn];
-
- for (uint i=0; i < fAudioCountIn; ++i)
- fAudioBufIn[i] = new float[fBufferSize];
- }
-
- if (fAudioCountOut > 0)
- {
- fAudioBufOut = new float*[fAudioCountOut];
-
- for (uint i=0; i < fAudioCountOut; ++i)
- fAudioBufOut[i] = new float[fBufferSize];
- }
-
- fAudioBufRackIn[0] = new float[fBufferSize];
- fAudioBufRackIn[1] = new float[fBufferSize];
- fAudioBufRackOut[0] = new float[fBufferSize];
- fAudioBufRackOut[1] = new float[fBufferSize];
-
- fAudioIsReady = true;
-
- CarlaEngine::init(clientName);
- patchbayRefresh();
-
- return true;
- }
-
- bool close() override
- {
- carla_debug("CarlaEngineRtAudio::close()");
- CARLA_ASSERT(fAudioBufOut != nullptr);
- CARLA_ASSERT(fAudioCountOut > 0);
- CARLA_ASSERT(fAudioIsReady);
-
- fAudioIsReady = false;
-
- bool hasError = !CarlaEngine::close();
-
- if (fAudio.isStreamRunning())
- {
- try {
- fAudio.stopStream();
- }
- catch (RtError& e)
- {
- if (! hasError)
- {
- setLastError(e.what());
- hasError = true;
- }
- }
- }
-
- if (fAudio.isStreamOpen())
- {
- try {
- fAudio.closeStream();
- }
- catch (RtError& e)
- {
- if (! hasError)
- {
- setLastError(e.what());
- hasError = true;
- }
- }
- }
-
- if (fAudioBufIn != nullptr)
- {
- CARLA_ASSERT(fAudioCountIn > 0);
-
- for (uint i=0; i < fAudioCountIn; ++i)
- delete[] fAudioBufIn[i];
-
- delete[] fAudioBufIn;
- fAudioBufIn = nullptr;
- }
-
- if (fAudioBufOut != nullptr)
- {
- CARLA_ASSERT(fAudioCountOut > 0);
-
- for (uint i=0; i < fAudioCountOut; ++i)
- delete[] fAudioBufOut[i];
-
- delete[] fAudioBufOut;
- fAudioBufOut = nullptr;
- }
-
- delete[] fAudioBufRackIn[0];
- delete[] fAudioBufRackIn[1];
- delete[] fAudioBufRackOut[0];
- delete[] fAudioBufRackOut[1];
-
- fAudioCountIn = 0;
- fAudioCountOut = 0;
-
- fConnectedAudioIns[0].clear();
- fConnectedAudioIns[1].clear();
- fConnectedAudioOuts[0].clear();
- fConnectedAudioOuts[1].clear();
-
- fConnectName.clear();
-
- for (auto it = fMidiIns.begin(); it.valid(); it.next())
- {
- MidiPort& port(*it);
- RtMidiIn* const midiInPort((RtMidiIn*)port.rtmidi);
-
- midiInPort->cancelCallback();
- delete midiInPort;
- }
-
- for (auto it = fMidiOuts.begin(); it.valid(); it.next())
- {
- MidiPort& port(*it);
- RtMidiOut* const midiOutPort((RtMidiOut*)port.rtmidi);
-
- delete midiOutPort;
- }
-
- fMidiIns.clear();
- fMidiOuts.clear();
-
- fMidiInEvents.clear();
- fMidiOutEvents.clear();
-
- return true;
- }
-
- bool isRunning() const override
- {
- return fAudio.isStreamRunning();
- }
-
- bool isOffline() const override
- {
- return false;
- }
-
- EngineType type() const override
- {
- return kEngineTypeRtAudio;
- }
-
- // -------------------------------------------------------------------
- // Patchbay
-
- bool patchbayConnect(int portA, int portB) override
- {
- CARLA_ASSERT(fAudioIsReady);
- CARLA_ASSERT(portA > PATCHBAY_PORT_MAX);
- CARLA_ASSERT(portB > PATCHBAY_PORT_MAX);
-
- if (! fAudioIsReady)
- {
- setLastError("Engine not ready");
- return false;
- }
- if (portA < PATCHBAY_PORT_MAX)
- {
- setLastError("Invalid output port");
- return false;
- }
- if (portB < PATCHBAY_PORT_MAX)
- {
- setLastError("Invalid input port");
- return false;
- }
-
- // only allow connections between Carla and other ports
- if (portA < 0 && portB < 0)
- {
- setLastError("Invalid connection");
- return false;
- }
- if (portA >= 0 && portB >= 0)
- {
- setLastError("Invalid connection");
- return false;
- }
-
- const int carlaPort = (portA < 0) ? portA : portB;
- const int targetPort = (carlaPort == portA) ? portB : portA;
- bool makeConnection = false;
-
- switch (carlaPort)
- {
- case PATCHBAY_PORT_AUDIO_IN1:
- CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_AUDIO_IN*1000);
- CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_AUDIO_IN*1000+999);
- fConnectAudioLock.lock();
- fConnectedAudioIns[0].append(targetPort - PATCHBAY_GROUP_AUDIO_IN*1000);
- fConnectAudioLock.unlock();
- makeConnection = true;
- break;
-
- case PATCHBAY_PORT_AUDIO_IN2:
- CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_AUDIO_IN*1000);
- CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_AUDIO_IN*1000+999);
- fConnectAudioLock.lock();
- fConnectedAudioIns[1].append(targetPort - PATCHBAY_GROUP_AUDIO_IN*1000);
- fConnectAudioLock.unlock();
- makeConnection = true;
- break;
-
- case PATCHBAY_PORT_AUDIO_OUT1:
- CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_AUDIO_OUT*1000);
- CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_AUDIO_OUT*1000+999);
- fConnectAudioLock.lock();
- fConnectedAudioOuts[0].append(targetPort - PATCHBAY_GROUP_AUDIO_OUT*1000);
- fConnectAudioLock.unlock();
- makeConnection = true;
- break;
-
- case PATCHBAY_PORT_AUDIO_OUT2:
- CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_AUDIO_OUT*1000);
- CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_AUDIO_OUT*1000+999);
- fConnectAudioLock.lock();
- fConnectedAudioOuts[1].append(targetPort - PATCHBAY_GROUP_AUDIO_OUT*1000);
- fConnectAudioLock.unlock();
- makeConnection = true;
- break;
-
- case PATCHBAY_PORT_MIDI_IN:
- CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_MIDI_IN*1000);
- CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_MIDI_IN*1000 + 999);
- makeConnection = connectMidiInPort(targetPort - PATCHBAY_GROUP_MIDI_IN*1000);
- break;
-
- case PATCHBAY_PORT_MIDI_OUT:
- CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_MIDI_OUT*1000);
- CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_MIDI_OUT*1000 + 999);
- makeConnection = connectMidiOutPort(targetPort - PATCHBAY_GROUP_MIDI_OUT*1000);
- break;
- }
-
- if (! makeConnection)
- {
- setLastError("Invalid connection");
- return false;
- }
-
- ConnectionToId connectionToId;
- connectionToId.id = fLastConnectionId;
- connectionToId.portOut = portA;
- connectionToId.portIn = portB;
-
- callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, portA, portB, nullptr);
-
- fUsedConnections.append(connectionToId);
- fLastConnectionId++;
-
- return true;
- }
-
- bool patchbayDisconnect(int connectionId) override
- {
- CARLA_ASSERT(fAudioIsReady);
- CARLA_ASSERT(fUsedConnections.count() > 0);
-
- if (! fAudioIsReady)
- {
- setLastError("Engine not ready");
- return false;
- }
- if (fUsedConnections.count() == 0)
- {
- setLastError("No connections available");
- return false;
- }
-
- for (auto it=fUsedConnections.begin(); it.valid(); it.next())
- {
- const ConnectionToId& connection(*it);
-
- if (connection.id == connectionId)
- {
- const int targetPort((connection.portOut >= 0) ? connection.portOut : connection.portIn);
- const int carlaPort((targetPort == connection.portOut) ? connection.portIn : connection.portOut);
-
- if (targetPort >= PATCHBAY_GROUP_MIDI_OUT*1000)
- {
- int portId = targetPort-PATCHBAY_GROUP_MIDI_IN*1000;
-
- for (auto it=fMidiOuts.begin(); it.valid(); it.next())
- {
- MidiPort& midiPort(*it);
-
- if (midiPort.portId == portId)
- {
- RtMidiOut* const midiOutPort((RtMidiOut*)midiPort.rtmidi);
-
- delete midiOutPort;
-
- fMidiOuts.remove(it);
- break;
- }
- }
- }
- else if (targetPort >= PATCHBAY_GROUP_MIDI_IN*1000)
- {
- int portId = targetPort-PATCHBAY_GROUP_MIDI_IN*1000;
-
- for (auto it=fMidiIns.begin(); it.valid(); it.next())
- {
- MidiPort& midiPort(*it);
-
- if (midiPort.portId == portId)
- {
- RtMidiIn* const midiInPort((RtMidiIn*)midiPort.rtmidi);
-
- midiInPort->cancelCallback();
- delete midiInPort;
-
- fMidiIns.remove(it);
- break;
- }
- }
- }
- else if (targetPort >= PATCHBAY_GROUP_AUDIO_OUT*1000)
- {
- CARLA_ASSERT(carlaPort == PATCHBAY_PORT_AUDIO_OUT1 || carlaPort == PATCHBAY_PORT_AUDIO_OUT2);
-
- fConnectAudioLock.lock();
-
- if (carlaPort == PATCHBAY_PORT_AUDIO_OUT1)
- fConnectedAudioOuts[0].removeAll(targetPort-PATCHBAY_GROUP_AUDIO_OUT*1000);
- else
- fConnectedAudioOuts[1].removeAll(targetPort-PATCHBAY_GROUP_AUDIO_OUT*1000);
-
- fConnectAudioLock.unlock();
- }
- else if (targetPort >= PATCHBAY_GROUP_AUDIO_IN*1000)
- {
- CARLA_ASSERT(carlaPort == PATCHBAY_PORT_AUDIO_IN1 || carlaPort == PATCHBAY_PORT_AUDIO_IN2);
-
- fConnectAudioLock.lock();
-
- if (carlaPort == PATCHBAY_PORT_AUDIO_IN1)
- fConnectedAudioIns[0].removeAll(targetPort-PATCHBAY_GROUP_AUDIO_IN*1000);
- else
- fConnectedAudioIns[1].removeAll(targetPort-PATCHBAY_GROUP_AUDIO_IN*1000);
-
- fConnectAudioLock.unlock();
- }
- else
- {
- CARLA_ASSERT(false);
- }
-
- callback(CALLBACK_PATCHBAY_CONNECTION_REMOVED, 0, connection.id, 0, 0.0f, nullptr);
-
- fUsedConnections.remove(it);
- break;
- }
- }
-
- return true;
- }
-
- void patchbayRefresh() override
- {
- CARLA_ASSERT(fAudioIsReady);
-
- if (! fAudioIsReady)
- return;
-
- char strBuf[STR_MAX+1];
-
- fLastConnectionId = 0;
- fUsedMidiIns.clear();
- fUsedMidiOuts.clear();
- fUsedConnections.clear();
-
- // Main
- {
- callback(CALLBACK_PATCHBAY_CLIENT_ADDED, 0, PATCHBAY_GROUP_CARLA, 0, 0.0f, getName());
-
- callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_AUDIO_IN1, PATCHBAY_PORT_IS_AUDIO|PATCHBAY_PORT_IS_INPUT, "audio-in1");
- callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_AUDIO_IN2, PATCHBAY_PORT_IS_AUDIO|PATCHBAY_PORT_IS_INPUT, "audio-in2");
- callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_AUDIO_OUT1, PATCHBAY_PORT_IS_AUDIO|PATCHBAY_PORT_IS_OUTPUT, "audio-out1");
- callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_AUDIO_OUT2, PATCHBAY_PORT_IS_AUDIO|PATCHBAY_PORT_IS_OUTPUT, "audio-out2");
- callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_MIDI_IN, PATCHBAY_PORT_IS_MIDI|PATCHBAY_PORT_IS_INPUT, "midi-in");
- callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_MIDI_OUT, PATCHBAY_PORT_IS_MIDI|PATCHBAY_PORT_IS_OUTPUT, "midi-out");
- }
-
- // Audio In
- {
- if (fConnectName.isNotEmpty())
- std::snprintf(strBuf, STR_MAX, "Capture (%s)", (const char*)fConnectName);
- else
- std::strncpy(strBuf, "Capture", STR_MAX);
-
- callback(CALLBACK_PATCHBAY_CLIENT_ADDED, 0, PATCHBAY_GROUP_AUDIO_IN, 0, 0.0f, strBuf);
-
- for (unsigned int i=0; i < fAudioCountIn; ++i)
- {
- std::snprintf(strBuf, STR_MAX, "capture_%i", i+1);
- callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_AUDIO_IN, PATCHBAY_GROUP_AUDIO_IN*1000 + i, PATCHBAY_PORT_IS_AUDIO|PATCHBAY_PORT_IS_OUTPUT, strBuf);
- }
- }
-
- // Audio Out
- {
- if (fConnectName.isNotEmpty())
- std::snprintf(strBuf, STR_MAX, "Playback (%s)", (const char*)fConnectName);
- else
- std::strncpy(strBuf, "Playback", STR_MAX);
-
- callback(CALLBACK_PATCHBAY_CLIENT_ADDED, 0, PATCHBAY_GROUP_AUDIO_OUT, 0, 0.0f, strBuf);
-
- for (unsigned int i=0; i < fAudioCountOut; ++i)
- {
- std::snprintf(strBuf, STR_MAX, "playback_%i", i+1);
- callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_AUDIO_OUT, PATCHBAY_GROUP_AUDIO_OUT*1000 + i, PATCHBAY_PORT_IS_AUDIO|PATCHBAY_PORT_IS_INPUT, strBuf);
- }
- }
-
- // MIDI In
- {
- callback(CALLBACK_PATCHBAY_CLIENT_ADDED, 0, PATCHBAY_GROUP_MIDI_IN, 0, 0.0f, "Readable MIDI ports");
-
- for (unsigned int i=0, count=fDummyMidiIn.getPortCount(); i < count; ++i)
- {
- PortNameToId portNameToId;
- portNameToId.portId = PATCHBAY_GROUP_MIDI_IN*1000 + i;
- std::strncpy(portNameToId.name, fDummyMidiIn.getPortName(i).c_str(), STR_MAX);
- fUsedMidiIns.append(portNameToId);
-
- callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_MIDI_IN, portNameToId.portId, PATCHBAY_PORT_IS_MIDI|PATCHBAY_PORT_IS_OUTPUT, portNameToId.name);
- }
- }
-
- // MIDI Out
- {
- callback(CALLBACK_PATCHBAY_CLIENT_ADDED, 0, PATCHBAY_GROUP_MIDI_OUT, 0, 0.0f, "Writable MIDI ports");
-
- for (unsigned int i=0, count=fDummyMidiOut.getPortCount(); i < count; ++i)
- {
- PortNameToId portNameToId;
- portNameToId.portId = PATCHBAY_GROUP_MIDI_OUT*1000 + i;
- std::strncpy(portNameToId.name, fDummyMidiOut.getPortName(i).c_str(), STR_MAX);
- fUsedMidiOuts.append(portNameToId);
-
- callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_MIDI_OUT, portNameToId.portId, PATCHBAY_PORT_IS_MIDI|PATCHBAY_PORT_IS_INPUT, portNameToId.name);
- }
- }
-
- // Connections
- fConnectAudioLock.lock();
-
- for (auto it = fConnectedAudioIns[0].begin(); it.valid(); it.next())
- {
- const uint& port(*it);
- CARLA_ASSERT(port < fAudioCountIn);
-
- ConnectionToId connectionToId;
- connectionToId.id = fLastConnectionId;
- connectionToId.portOut = PATCHBAY_GROUP_AUDIO_IN*1000 + port;
- connectionToId.portIn = PATCHBAY_PORT_AUDIO_IN1;
-
- callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
-
- fUsedConnections.append(connectionToId);
- fLastConnectionId++;
- }
-
- for (auto it = fConnectedAudioIns[1].begin(); it.valid(); it.next())
- {
- const uint& port(*it);
- CARLA_ASSERT(port < fAudioCountIn);
-
- ConnectionToId connectionToId;
- connectionToId.id = fLastConnectionId;
- connectionToId.portOut = PATCHBAY_GROUP_AUDIO_IN*1000 + port;
- connectionToId.portIn = PATCHBAY_PORT_AUDIO_IN2;
-
- callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
-
- fUsedConnections.append(connectionToId);
- fLastConnectionId++;
- }
-
- for (auto it = fConnectedAudioOuts[0].begin(); it.valid(); it.next())
- {
- const uint& port(*it);
- CARLA_ASSERT(port < fAudioCountOut);
-
- ConnectionToId connectionToId;
- connectionToId.id = fLastConnectionId;
- connectionToId.portOut = PATCHBAY_PORT_AUDIO_OUT1;
- connectionToId.portIn = PATCHBAY_GROUP_AUDIO_OUT*1000 + port;
-
- callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
-
- fUsedConnections.append(connectionToId);
- fLastConnectionId++;
- }
-
- for (auto it = fConnectedAudioOuts[1].begin(); it.valid(); it.next())
- {
- const uint& port(*it);
- CARLA_ASSERT(port < fAudioCountOut);
-
- ConnectionToId connectionToId;
- connectionToId.id = fLastConnectionId;
- connectionToId.portOut = PATCHBAY_PORT_AUDIO_OUT2;
- connectionToId.portIn = PATCHBAY_GROUP_AUDIO_OUT*1000 + port;
-
- callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
-
- fUsedConnections.append(connectionToId);
- fLastConnectionId++;
- }
-
- fConnectAudioLock.unlock();
-
- for (auto it=fMidiIns.begin(); it.valid(); it.next())
- {
- const MidiPort& midiPort(*it);
-
- ConnectionToId connectionToId;
- connectionToId.id = fLastConnectionId;
- connectionToId.portOut = midiPort.portId;
- connectionToId.portIn = PATCHBAY_PORT_MIDI_IN;
-
- callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
-
- fUsedConnections.append(connectionToId);
- fLastConnectionId++;
- }
-
- for (auto it=fMidiOuts.begin(); it.valid(); it.next())
- {
- const MidiPort& midiPort(*it);
-
- ConnectionToId connectionToId;
- connectionToId.id = fLastConnectionId;
- connectionToId.portOut = PATCHBAY_PORT_MIDI_OUT;
- connectionToId.portIn = midiPort.portId;
-
- callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
-
- fUsedConnections.append(connectionToId);
- fLastConnectionId++;
- }
- }
-
- // -------------------------------------------------------------------
-
- 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(nframes == fBufferSize);
- CARLA_ASSERT(outsPtr != nullptr);
-
- if (kData->curPluginCount == 0 || ! (fAudioIsReady && fConnectAudioLock.tryLock()))
- {
- carla_zeroFloat(outsPtr, nframes*fAudioCountOut);
- return proccessPendingEvents();
- }
-
- // initialize audio input
- if (fAudioIsInterleaved)
- {
- for (unsigned int i=0, j=0; i < nframes*fAudioCountIn; ++i)
- {
- fAudioBufIn[i/fAudioCountIn][j] = insPtr[i];
-
- if ((i+1) % fAudioCountIn == 0)
- j += 1;
- }
- }
- else
- {
- for (unsigned int i=0; i < fAudioCountIn; ++i)
- carla_copyFloat(fAudioBufIn[i], insPtr+(nframes*i), nframes);
- }
-
- // initialize audio output
- for (unsigned int i=0; i < fAudioCountOut; ++i)
- carla_zeroFloat(fAudioBufOut[i], nframes);
-
- carla_zeroFloat(fAudioBufRackOut[0], nframes);
- carla_zeroFloat(fAudioBufRackOut[1], nframes);
-
- // initialize input events
- carla_zeroMem(kData->rack.in, sizeof(EngineEvent)*RACK_EVENT_COUNT);
-
- if (fMidiInEvents.mutex.tryLock())
- {
- uint32_t engineEventIndex = 0;
- fMidiInEvents.splice();
-
- while (! fMidiInEvents.data.isEmpty())
- {
- const RtMidiEvent& midiEvent(fMidiInEvents.data.getFirst(true));
-
- EngineEvent& engineEvent(kData->rack.in[engineEventIndex++]);
- engineEvent.clear();
-
- const uint8_t midiStatus = MIDI_GET_STATUS_FROM_DATA(midiEvent.data);
- const uint8_t midiChannel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent.data);
-
- engineEvent.channel = midiChannel;
-
- if (midiEvent.time < fTimeInfo.frame)
- engineEvent.time = 0;
- else if (midiEvent.time >= fTimeInfo.frame + nframes)
- {
- engineEvent.time = fTimeInfo.frame + nframes-1;
- carla_stderr("MIDI Event in the future!, %i vs %i", engineEvent.time, fTimeInfo.frame);
- }
- else
- engineEvent.time = midiEvent.time - fTimeInfo.frame;
-
- carla_stdout("Got midi, time %f vs %i", midiEvent.time, engineEvent.time);
-
- if (MIDI_IS_STATUS_CONTROL_CHANGE(midiStatus))
- {
- const uint8_t midiControl = midiEvent.data[1];
- engineEvent.type = kEngineEventTypeControl;
-
- if (MIDI_IS_CONTROL_BANK_SELECT(midiControl))
- {
- const uint8_t midiBank = midiEvent.data[2];
-
- engineEvent.ctrl.type = kEngineControlEventTypeMidiBank;
- engineEvent.ctrl.param = midiBank;
- engineEvent.ctrl.value = 0.0f;
- }
- else if (midiControl == MIDI_CONTROL_ALL_SOUND_OFF)
- {
- engineEvent.ctrl.type = kEngineControlEventTypeAllSoundOff;
- engineEvent.ctrl.param = 0;
- engineEvent.ctrl.value = 0.0f;
- }
- else if (midiControl == MIDI_CONTROL_ALL_NOTES_OFF)
- {
- engineEvent.ctrl.type = kEngineControlEventTypeAllNotesOff;
- engineEvent.ctrl.param = 0;
- engineEvent.ctrl.value = 0.0f;
- }
- else
- {
- const uint8_t midiValue = midiEvent.data[2];
-
- engineEvent.ctrl.type = kEngineControlEventTypeParameter;
- engineEvent.ctrl.param = midiControl;
- engineEvent.ctrl.value = float(midiValue)/127.0f;
- }
- }
- else if (MIDI_IS_STATUS_PROGRAM_CHANGE(midiStatus))
- {
- const uint8_t midiProgram = midiEvent.data[1];
- engineEvent.type = kEngineEventTypeControl;
-
- engineEvent.ctrl.type = kEngineControlEventTypeMidiProgram;
- engineEvent.ctrl.param = midiProgram;
- engineEvent.ctrl.value = 0.0f;
- }
- else
- {
- engineEvent.type = kEngineEventTypeMidi;
-
- engineEvent.midi.data[0] = midiStatus;
- engineEvent.midi.data[1] = midiEvent.data[1];
- engineEvent.midi.data[2] = midiEvent.data[2];
- engineEvent.midi.data[3] = midiEvent.data[3];
- engineEvent.midi.size = midiEvent.size;
- }
-
- if (engineEventIndex >= RACK_EVENT_COUNT)
- break;
- }
-
- fMidiInEvents.mutex.unlock();
- }
-
- // connect input buffers
- if (fConnectedAudioIns[0].count() == 0)
- {
- carla_zeroFloat(fAudioBufRackIn[0], nframes);
- }
- else
- {
- bool first = true;
-
- for (auto it = fConnectedAudioIns[0].begin(); it.valid(); it.next())
- {
- const uint& port(*it);
- CARLA_ASSERT(port < fAudioCountIn);
-
- if (first)
- {
- carla_copyFloat(fAudioBufRackIn[0], fAudioBufIn[port], nframes);
- first = false;
- }
- else
- carla_addFloat(fAudioBufRackIn[0], fAudioBufIn[port], nframes);
- }
-
- if (first)
- carla_zeroFloat(fAudioBufRackIn[0], nframes);
- }
-
- if (fConnectedAudioIns[1].count() == 0)
- {
- carla_zeroFloat(fAudioBufRackIn[1], nframes);
- }
- else
- {
- bool first = true;
-
- for (auto it = fConnectedAudioIns[1].begin(); it.valid(); it.next())
- {
- const uint& port(*it);
- CARLA_ASSERT(port < fAudioCountIn);
-
- if (first)
- {
- carla_copyFloat(fAudioBufRackIn[1], fAudioBufIn[port], nframes);
- first = false;
- }
- else
- carla_addFloat(fAudioBufRackIn[1], fAudioBufIn[port], nframes);
- }
-
- if (first)
- carla_zeroFloat(fAudioBufRackIn[1], nframes);
- }
-
- // process
- processRack(fAudioBufRackIn, fAudioBufRackOut, nframes);
-
- // connect output buffers
- if (fConnectedAudioOuts[0].count() != 0)
- {
- for (auto it = fConnectedAudioOuts[0].begin(); it.valid(); it.next())
- {
- const uint& port(*it);
- CARLA_ASSERT(port < fAudioCountOut);
-
- carla_addFloat(fAudioBufOut[port], fAudioBufRackOut[0], nframes);
- }
- }
-
- fConnectAudioLock.unlock();
-
- // output audio
- if (fAudioIsInterleaved)
- {
- for (unsigned int i=0, j=0; i < nframes*fAudioCountOut; ++i)
- {
- outsPtr[i] = fAudioBufOut[i/fAudioCountOut][j];
-
- if ((i+1) % fAudioCountOut == 0)
- j += 1;
- }
- }
- else
- {
- for (unsigned int i=0; i < fAudioCountOut; ++i)
- carla_copyFloat(outsPtr+(nframes*i), fAudioBufOut[i], nframes);
- }
-
- // output events
- {
- // TODO
- //fMidiOut.sendMessage();
- }
-
- proccessPendingEvents();
-
- return;
-
- // unused
- (void)streamTime;
- (void)status;
- }
-
- void handleMidiCallback(double timeStamp, std::vector<unsigned char>* const message)
- {
- if (! fAudioIsReady)
- return;
-
- const size_t messageSize = message->size();
- static uint32_t lastTime = 0;
-
- if (messageSize == 0 || messageSize > 4)
- return;
-
- timeStamp /= 2;
-
- if (timeStamp > 0.95)
- timeStamp = 0.95;
- else if (timeStamp < 0.0)
- timeStamp = 0.0;
-
- RtMidiEvent midiEvent;
- midiEvent.time = fTimeInfo.frame + (timeStamp*(double)fBufferSize);
- carla_stdout("Put midi, frame:%09i/%09i, stamp:%f", fTimeInfo.frame, midiEvent.time, timeStamp);
-
- if (midiEvent.time < lastTime)
- midiEvent.time = lastTime;
- else
- lastTime = midiEvent.time;
-
- if (messageSize == 1)
- {
- midiEvent.data[0] = message->at(0);
- midiEvent.data[1] = 0;
- midiEvent.data[2] = 0;
- midiEvent.data[3] = 0;
- midiEvent.size = 1;
- }
- else if (messageSize == 2)
- {
- midiEvent.data[0] = message->at(0);
- midiEvent.data[1] = message->at(1);
- midiEvent.data[2] = 0;
- midiEvent.data[3] = 0;
- midiEvent.size = 2;
- }
- else if (messageSize == 3)
- {
- midiEvent.data[0] = message->at(0);
- midiEvent.data[1] = message->at(1);
- midiEvent.data[2] = message->at(2);
- midiEvent.data[3] = 0;
- midiEvent.size = 3;
- }
- else
- {
- midiEvent.data[0] = message->at(0);
- midiEvent.data[1] = message->at(1);
- midiEvent.data[2] = message->at(2);
- midiEvent.data[3] = message->at(3);
- midiEvent.size = 4;
- }
-
- fMidiInEvents.append(midiEvent);
- }
-
- bool connectMidiInPort(const int portId)
- {
- const char* portName = nullptr;
-
- for (auto it = fUsedMidiIns.begin(); it.valid(); it.next())
- {
- const PortNameToId& portNameId(*it);
-
- if (portNameId.portId == portId)
- {
- portName = portNameId.name;
- break;
- }
- }
-
- if (portName == nullptr)
- return false;
-
- int rtMidiPortIndex = -1;
-
- RtMidiIn* const rtMidiIn(new RtMidiIn(getMatchedAudioMidiAPi(fAudio.getCurrentApi()), getName(), 512));
- rtMidiIn->ignoreTypes();
- rtMidiIn->setCallback(carla_rtmidi_callback, this);
-
- for (unsigned int i=0, count=rtMidiIn->getPortCount(); i < count; ++i)
- {
- if (rtMidiIn->getPortName(i) == portName)
- {
- rtMidiPortIndex = i;
- break;
- }
- }
-
- if (rtMidiPortIndex == -1)
- {
- delete rtMidiIn;
- return false;
- }
-
- rtMidiIn->openPort(rtMidiPortIndex, "in");
-
- MidiPort midiPort;
- midiPort.portId = portId;
- midiPort.rtmidi = rtMidiIn;
-
- fMidiIns.append(midiPort);
-
- return true;
- }
-
- bool connectMidiOutPort(const int portId)
- {
- const char* portName = nullptr;
-
- for (auto it = fUsedMidiOuts.begin(); it.valid(); it.next())
- {
- const PortNameToId& portNameId(*it);
-
- if (portNameId.portId == portId)
- {
- portName = portNameId.name;
- break;
- }
- }
-
- if (portName == nullptr)
- return false;
-
- int rtMidiPortIndex = -1;
-
- RtMidiOut* const rtMidiOut(new RtMidiOut(getMatchedAudioMidiAPi(fAudio.getCurrentApi()), getName()));
-
- for (unsigned int i=0, count=rtMidiOut->getPortCount(); i < count; ++i)
- {
- if (rtMidiOut->getPortName(i) == portName)
- {
- rtMidiPortIndex = i;
- break;
- }
- }
-
- if (rtMidiPortIndex == -1)
- {
- delete rtMidiOut;
- return false;
- }
-
- rtMidiOut->openPort(rtMidiPortIndex, "in");
-
- MidiPort midiPort;
- midiPort.portId = portId;
- midiPort.rtmidi = rtMidiOut;
-
- fMidiOuts.append(midiPort);
-
- return true;
- }
-
- // -------------------------------------
-
- private:
- RtAudio fAudio;
- float** fAudioBufIn;
- float** fAudioBufOut;
- float* fAudioBufRackIn[2];
- float* fAudioBufRackOut[2];
-
- uint fAudioCountIn;
- uint fAudioCountOut;
- bool fAudioIsInterleaved;
- bool fAudioIsReady;
-
- NonRtList<uint> fConnectedAudioIns[2];
- NonRtList<uint> fConnectedAudioOuts[2];
- CarlaMutex fConnectAudioLock;
- CarlaString fConnectName;
-
- RtMidiIn fDummyMidiIn;
- RtMidiOut fDummyMidiOut;
-
- enum PatchbayGroupIds {
- PATCHBAY_GROUP_CARLA = -1,
- PATCHBAY_GROUP_AUDIO_IN = 0,
- PATCHBAY_GROUP_AUDIO_OUT = 1,
- PATCHBAY_GROUP_MIDI_IN = 2,
- PATCHBAY_GROUP_MIDI_OUT = 3,
- PATCHBAY_GROUP_MAX = 4
- };
-
- enum PatchbayPortIds {
- PATCHBAY_PORT_AUDIO_IN1 = -1,
- PATCHBAY_PORT_AUDIO_IN2 = -2,
- PATCHBAY_PORT_AUDIO_OUT1 = -3,
- PATCHBAY_PORT_AUDIO_OUT2 = -4,
- PATCHBAY_PORT_MIDI_IN = -5,
- PATCHBAY_PORT_MIDI_OUT = -6,
- PATCHBAY_PORT_MAX = -7
- };
-
- struct ConnectionToId {
- int id;
- int portOut;
- int portIn;
- };
-
- struct PortNameToId {
- int portId;
- char name[STR_MAX+1];
- };
-
- int fLastConnectionId;
- NonRtList<PortNameToId> fUsedMidiIns;
- NonRtList<PortNameToId> fUsedMidiOuts;
- NonRtList<ConnectionToId> fUsedConnections;
-
- struct MidiPort {
- RtMidi* rtmidi;
- int portId;
- };
-
- NonRtList<MidiPort> fMidiIns;
- NonRtList<MidiPort> fMidiOuts;
-
- struct RtMidiEvent {
- uint32_t time;
- unsigned char data[4];
- unsigned char size;
- };
-
- struct RtMidiEvents {
- CarlaMutex mutex;
- RtList<RtMidiEvent>::Pool dataPool;
- RtList<RtMidiEvent> data;
- RtList<RtMidiEvent> 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 splice()
- {
- dataPending.spliceAppend(data, true);
- }
- };
-
- 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<unsigned char>* message, void* userData)
- {
- handlePtr->handleMidiCallback(timeStamp, message);
- }
-
- #undef handlePtr
-
- CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineRtAudio)
- };
-
- // -----------------------------------------
-
- 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 gRtAudioApis.size();
- }
-
- const char* CarlaEngine::getRtAudioApiName(const unsigned int index)
- {
- initRtApis();
-
- if (index < gRtAudioApis.size())
- {
- const RtAudio::Api& api(gRtAudioApis[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:
- #if defined(CARLA_OS_WIN)
- return "JACK with WinMM";
- #elif defined(CARLA_OS_MAC)
- return "JACK with CoreMidi";
- #elif defined(CARLA_OS_LINUX)
- return "JACK with ALSA-MIDI";
- #else
- return "JACK (RtAudio)";
- #endif
- 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;
- }
-
- const char** CarlaEngine::getRtAudioApiDeviceNames(const unsigned int index)
- {
- initRtApis();
-
- if (index < gRtAudioApis.size())
- {
- const RtAudio::Api& api(gRtAudioApis[index]);
-
- RtAudio rtAudio(api);
-
- if (gRetNames != nullptr)
- {
- int i=0;
- while (gRetNames[i] != nullptr)
- delete[] gRetNames[i++];
- delete[] gRetNames;
- gRetNames = nullptr;
- }
-
- const unsigned int devCount(rtAudio.getDeviceCount());
-
- if (devCount > 0)
- {
- NonRtList<const char*> devNames;
-
- for (unsigned int i=0; i < devCount; ++i)
- {
- RtAudio::DeviceInfo devInfo(rtAudio.getDeviceInfo(i));
-
- if (devInfo.probed && devInfo.outputChannels > 0 /*&& (devInfo.nativeFormats & RTAUDIO_FLOAT32) != 0*/)
- devNames.append(carla_strdup(devInfo.name.c_str()));
- }
-
- const unsigned int realDevCount(devNames.count());
-
- gRetNames = new const char*[realDevCount+1];
-
- for (unsigned int i=0; i < realDevCount; ++i)
- gRetNames[i] = devNames.getAt(i);
-
- gRetNames[realDevCount] = nullptr;
- devNames.clear();
-
- return gRetNames;
- }
- }
-
- return nullptr;
- }
-
- // -----------------------------------------
-
- CARLA_BACKEND_END_NAMESPACE
-
- #endif // CARLA_ENGINE_RTAUDIO
|