Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CarlaEngineRtAudio.cpp 45KB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467
  1. /*
  2. * Carla RtAudio Engine
  3. * Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the GPL.txt file
  16. */
  17. #ifdef WANT_RTAUDIO
  18. #include "CarlaEngineInternal.hpp"
  19. #include "CarlaBackendUtils.hpp"
  20. #include "CarlaMIDI.h"
  21. #include "RtList.hpp"
  22. #include "RtAudio.h"
  23. #include "RtMidi.h"
  24. CARLA_BACKEND_START_NAMESPACE
  25. #if 0
  26. } // Fix editor indentation
  27. #endif
  28. // -------------------------------------------------------------------------------------------------------------------
  29. static const char** gRetNames = nullptr;
  30. static std::vector<RtAudio::Api> gRtAudioApis;
  31. static void initRtApis()
  32. {
  33. if (gRtAudioApis.size() == 0)
  34. RtAudio::getCompiledApi(gRtAudioApis);
  35. }
  36. RtMidi::Api getMatchedAudioMidiAPi(const RtAudio::Api rtApi)
  37. {
  38. switch (rtApi)
  39. {
  40. case RtAudio::UNSPECIFIED:
  41. return RtMidi::UNSPECIFIED;
  42. case RtAudio::LINUX_ALSA:
  43. case RtAudio::LINUX_OSS:
  44. case RtAudio::LINUX_PULSE:
  45. return RtMidi::LINUX_ALSA;
  46. case RtAudio::UNIX_JACK:
  47. #if defined(CARLA_OS_WIN)
  48. return RtMidi::WINDOWS_MM;
  49. #elif defined(CARLA_OS_MAC)
  50. return RtMidi::MACOSX_CORE;
  51. #elif defined(CARLA_OS_LINUX)
  52. return RtMidi::LINUX_ALSA;
  53. #else
  54. return RtMidi::UNIX_JACK;
  55. #endif
  56. case RtAudio::MACOSX_CORE:
  57. return RtMidi::MACOSX_CORE;
  58. case RtAudio::WINDOWS_ASIO:
  59. case RtAudio::WINDOWS_DS:
  60. return RtMidi::WINDOWS_MM;
  61. case RtAudio::RTAUDIO_DUMMY:
  62. return RtMidi::RTMIDI_DUMMY;
  63. }
  64. return RtMidi::UNSPECIFIED;
  65. }
  66. // -------------------------------------------------------------------------------------------------------------------
  67. // RtAudio Engine
  68. class CarlaEngineRtAudio : public CarlaEngine
  69. {
  70. public:
  71. CarlaEngineRtAudio(const RtAudio::Api api)
  72. : CarlaEngine(),
  73. fAudio(api),
  74. fAudioBufIn(nullptr),
  75. fAudioBufOut(nullptr),
  76. #ifdef CARLA_PROPER_CPP11_SUPPORT
  77. fAudioBufRackIn{nullptr},
  78. fAudioBufRackOut{nullptr},
  79. #endif
  80. fAudioCountIn(0),
  81. fAudioCountOut(0),
  82. fAudioIsInterleaved(false),
  83. fAudioIsReady(false),
  84. fDummyMidiIn(getMatchedAudioMidiAPi(api), "Carla"),
  85. fDummyMidiOut(getMatchedAudioMidiAPi(api), "Carla"),
  86. fLastConnectionId(0)
  87. {
  88. carla_debug("CarlaEngineRtAudio::CarlaEngineRtAudio(%i)", api);
  89. #ifndef CARLA_PROPER_CPP11_SUPPORT
  90. fAudioBufRackIn[0] = fAudioBufRackIn[1] = nullptr;
  91. fAudioBufRackOut[0] = fAudioBufRackOut[1] = nullptr;
  92. #endif
  93. // just to make sure
  94. fOptions.forceStereo = true;
  95. fOptions.processMode = PROCESS_MODE_CONTINUOUS_RACK;
  96. fOptions.transportMode = TRANSPORT_MODE_INTERNAL;
  97. }
  98. ~CarlaEngineRtAudio() override
  99. {
  100. CARLA_ASSERT(fAudioBufIn == nullptr);
  101. CARLA_ASSERT(fAudioBufOut == nullptr);
  102. CARLA_ASSERT(fAudioCountIn == 0);
  103. CARLA_ASSERT(fAudioCountOut == 0);
  104. CARLA_ASSERT(! fAudioIsReady);
  105. carla_debug("CarlaEngineRtAudio::~CarlaEngineRtAudio()");
  106. fUsedMidiIns.clear();
  107. fUsedMidiOuts.clear();
  108. fUsedConnections.clear();
  109. if (gRetNames != nullptr)
  110. {
  111. delete[] gRetNames;
  112. gRetNames = nullptr;
  113. }
  114. }
  115. // -------------------------------------
  116. bool init(const char* const clientName) override
  117. {
  118. CARLA_ASSERT(fAudioBufIn == nullptr);
  119. CARLA_ASSERT(fAudioBufOut == nullptr);
  120. CARLA_ASSERT(fAudioCountIn == 0);
  121. CARLA_ASSERT(fAudioCountOut == 0);
  122. CARLA_ASSERT(! fAudioIsReady);
  123. CARLA_ASSERT(clientName != nullptr);
  124. carla_debug("CarlaEngineRtAudio::init(\"%s\")", clientName);
  125. RtAudio::StreamParameters iParams, oParams;
  126. bool deviceSet = false;
  127. const unsigned int devCount(fAudio.getDeviceCount());
  128. if (devCount == 0)
  129. {
  130. setLastError("No audio devices available for this driver");
  131. return false;
  132. }
  133. if (fOptions.rtaudioDevice.isNotEmpty())
  134. {
  135. for (unsigned int i=0; i < devCount; ++i)
  136. {
  137. RtAudio::DeviceInfo devInfo(fAudio.getDeviceInfo(i));
  138. if (devInfo.probed && devInfo.outputChannels > 0 && devInfo.name == (const char*)fOptions.rtaudioDevice)
  139. {
  140. deviceSet = true;
  141. fConnectName = devInfo.name.c_str();
  142. iParams.deviceId = i;
  143. oParams.deviceId = i;
  144. iParams.nChannels = devInfo.inputChannels;
  145. oParams.nChannels = devInfo.outputChannels;
  146. break;
  147. }
  148. }
  149. }
  150. if (! deviceSet)
  151. {
  152. iParams.deviceId = fAudio.getDefaultInputDevice();
  153. oParams.deviceId = fAudio.getDefaultOutputDevice();
  154. iParams.nChannels = 2;
  155. oParams.nChannels = 2;
  156. }
  157. RtAudio::StreamOptions rtOptions;
  158. rtOptions.flags = RTAUDIO_MINIMIZE_LATENCY | RTAUDIO_HOG_DEVICE | RTAUDIO_SCHEDULE_REALTIME;
  159. rtOptions.streamName = clientName;
  160. rtOptions.priority = 85;
  161. if (fAudio.getCurrentApi() != RtAudio::LINUX_PULSE)
  162. {
  163. rtOptions.flags |= RTAUDIO_NONINTERLEAVED;
  164. fAudioIsInterleaved = false;
  165. if (fAudio.getCurrentApi() == RtAudio::LINUX_ALSA && ! deviceSet)
  166. rtOptions.flags |= RTAUDIO_ALSA_USE_DEFAULT;
  167. }
  168. else
  169. fAudioIsInterleaved = true;
  170. fBufferSize = fOptions.rtaudioBufferSize;
  171. try {
  172. fAudio.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, fOptions.rtaudioSampleRate, &fBufferSize, carla_rtaudio_process_callback, this, &rtOptions);
  173. }
  174. catch (RtError& e)
  175. {
  176. setLastError(e.what());
  177. return false;
  178. }
  179. try {
  180. fAudio.startStream();
  181. }
  182. catch (RtError& e)
  183. {
  184. setLastError(e.what());
  185. fAudio.closeStream();
  186. return false;
  187. }
  188. fAudioCountIn = iParams.nChannels;
  189. fAudioCountOut = oParams.nChannels;
  190. fSampleRate = fAudio.getStreamSampleRate();
  191. CARLA_ASSERT(fAudioCountOut > 0);
  192. if (fAudioCountIn > 0)
  193. {
  194. fAudioBufIn = new float*[fAudioCountIn];
  195. for (uint i=0; i < fAudioCountIn; ++i)
  196. fAudioBufIn[i] = new float[fBufferSize];
  197. }
  198. if (fAudioCountOut > 0)
  199. {
  200. fAudioBufOut = new float*[fAudioCountOut];
  201. for (uint i=0; i < fAudioCountOut; ++i)
  202. fAudioBufOut[i] = new float[fBufferSize];
  203. }
  204. fAudioBufRackIn[0] = new float[fBufferSize];
  205. fAudioBufRackIn[1] = new float[fBufferSize];
  206. fAudioBufRackOut[0] = new float[fBufferSize];
  207. fAudioBufRackOut[1] = new float[fBufferSize];
  208. fAudioIsReady = true;
  209. CarlaEngine::init(clientName);
  210. patchbayRefresh();
  211. return true;
  212. }
  213. bool close() override
  214. {
  215. carla_debug("CarlaEngineRtAudio::close()");
  216. CARLA_ASSERT(fAudioBufOut != nullptr);
  217. CARLA_ASSERT(fAudioCountOut > 0);
  218. CARLA_ASSERT(fAudioIsReady);
  219. fAudioIsReady = false;
  220. bool hasError = !CarlaEngine::close();
  221. if (fAudio.isStreamRunning())
  222. {
  223. try {
  224. fAudio.stopStream();
  225. }
  226. catch (RtError& e)
  227. {
  228. if (! hasError)
  229. {
  230. setLastError(e.what());
  231. hasError = true;
  232. }
  233. }
  234. }
  235. if (fAudio.isStreamOpen())
  236. {
  237. try {
  238. fAudio.closeStream();
  239. }
  240. catch (RtError& e)
  241. {
  242. if (! hasError)
  243. {
  244. setLastError(e.what());
  245. hasError = true;
  246. }
  247. }
  248. }
  249. if (fAudioBufIn != nullptr)
  250. {
  251. CARLA_ASSERT(fAudioCountIn > 0);
  252. for (uint i=0; i < fAudioCountIn; ++i)
  253. delete[] fAudioBufIn[i];
  254. delete[] fAudioBufIn;
  255. fAudioBufIn = nullptr;
  256. }
  257. if (fAudioBufOut != nullptr)
  258. {
  259. CARLA_ASSERT(fAudioCountOut > 0);
  260. for (uint i=0; i < fAudioCountOut; ++i)
  261. delete[] fAudioBufOut[i];
  262. delete[] fAudioBufOut;
  263. fAudioBufOut = nullptr;
  264. }
  265. delete[] fAudioBufRackIn[0];
  266. delete[] fAudioBufRackIn[1];
  267. delete[] fAudioBufRackOut[0];
  268. delete[] fAudioBufRackOut[1];
  269. fAudioCountIn = 0;
  270. fAudioCountOut = 0;
  271. fConnectedAudioIns[0].clear();
  272. fConnectedAudioIns[1].clear();
  273. fConnectedAudioOuts[0].clear();
  274. fConnectedAudioOuts[1].clear();
  275. fConnectName.clear();
  276. for (NonRtList<MidiPort>::Itenerator it = fMidiIns.begin(); it.valid(); it.next())
  277. {
  278. MidiPort& port(*it);
  279. RtMidiIn* const midiInPort((RtMidiIn*)port.rtmidi);
  280. midiInPort->cancelCallback();
  281. delete midiInPort;
  282. }
  283. for (NonRtList<MidiPort>::Itenerator it = fMidiOuts.begin(); it.valid(); it.next())
  284. {
  285. MidiPort& port(*it);
  286. RtMidiOut* const midiOutPort((RtMidiOut*)port.rtmidi);
  287. delete midiOutPort;
  288. }
  289. fMidiIns.clear();
  290. fMidiOuts.clear();
  291. fMidiInEvents.clear();
  292. //fMidiOutEvents.clear();
  293. return (! hasError);
  294. }
  295. bool isRunning() const override
  296. {
  297. return fAudio.isStreamRunning();
  298. }
  299. bool isOffline() const override
  300. {
  301. return false;
  302. }
  303. EngineType type() const override
  304. {
  305. return kEngineTypeRtAudio;
  306. }
  307. // -------------------------------------------------------------------
  308. // Patchbay
  309. bool patchbayConnect(int portA, int portB) override
  310. {
  311. CARLA_ASSERT(fAudioIsReady);
  312. CARLA_ASSERT(portA > PATCHBAY_PORT_MAX);
  313. CARLA_ASSERT(portB > PATCHBAY_PORT_MAX);
  314. carla_debug("CarlaEngineRtAudio::patchbayConnect(%i, %i)", portA, portB);
  315. if (! fAudioIsReady)
  316. {
  317. setLastError("Engine not ready");
  318. return false;
  319. }
  320. if (portA < PATCHBAY_PORT_MAX)
  321. {
  322. setLastError("Invalid output port");
  323. return false;
  324. }
  325. if (portB < PATCHBAY_PORT_MAX)
  326. {
  327. setLastError("Invalid input port");
  328. return false;
  329. }
  330. // only allow connections between Carla and other ports
  331. if (portA < 0 && portB < 0)
  332. {
  333. setLastError("Invalid connection (1)");
  334. return false;
  335. }
  336. if (portA >= 0 && portB >= 0)
  337. {
  338. setLastError("Invalid connection (2)");
  339. return false;
  340. }
  341. const int carlaPort = (portA < 0) ? portA : portB;
  342. const int targetPort = (carlaPort == portA) ? portB : portA;
  343. bool makeConnection = false;
  344. switch (carlaPort)
  345. {
  346. case PATCHBAY_PORT_AUDIO_IN1:
  347. CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_AUDIO_IN*1000);
  348. CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_AUDIO_IN*1000+999);
  349. fConnectAudioLock.lock();
  350. fConnectedAudioIns[0].append(targetPort - PATCHBAY_GROUP_AUDIO_IN*1000);
  351. fConnectAudioLock.unlock();
  352. makeConnection = true;
  353. break;
  354. case PATCHBAY_PORT_AUDIO_IN2:
  355. CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_AUDIO_IN*1000);
  356. CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_AUDIO_IN*1000+999);
  357. fConnectAudioLock.lock();
  358. fConnectedAudioIns[1].append(targetPort - PATCHBAY_GROUP_AUDIO_IN*1000);
  359. fConnectAudioLock.unlock();
  360. makeConnection = true;
  361. break;
  362. case PATCHBAY_PORT_AUDIO_OUT1:
  363. CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_AUDIO_OUT*1000);
  364. CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_AUDIO_OUT*1000+999);
  365. fConnectAudioLock.lock();
  366. fConnectedAudioOuts[0].append(targetPort - PATCHBAY_GROUP_AUDIO_OUT*1000);
  367. fConnectAudioLock.unlock();
  368. makeConnection = true;
  369. break;
  370. case PATCHBAY_PORT_AUDIO_OUT2:
  371. CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_AUDIO_OUT*1000);
  372. CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_AUDIO_OUT*1000+999);
  373. fConnectAudioLock.lock();
  374. fConnectedAudioOuts[1].append(targetPort - PATCHBAY_GROUP_AUDIO_OUT*1000);
  375. fConnectAudioLock.unlock();
  376. makeConnection = true;
  377. break;
  378. case PATCHBAY_PORT_MIDI_IN:
  379. CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_MIDI_IN*1000);
  380. CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_MIDI_IN*1000+999);
  381. makeConnection = connectMidiInPort(targetPort - PATCHBAY_GROUP_MIDI_IN*1000);
  382. break;
  383. case PATCHBAY_PORT_MIDI_OUT:
  384. CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_MIDI_OUT*1000);
  385. CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_MIDI_OUT*1000+999);
  386. makeConnection = connectMidiOutPort(targetPort - PATCHBAY_GROUP_MIDI_OUT*1000);
  387. break;
  388. }
  389. if (! makeConnection)
  390. {
  391. setLastError("Invalid connection (3)");
  392. return false;
  393. }
  394. ConnectionToId connectionToId;
  395. connectionToId.id = fLastConnectionId;
  396. connectionToId.portOut = portA;
  397. connectionToId.portIn = portB;
  398. callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, portA, portB, nullptr);
  399. fUsedConnections.append(connectionToId);
  400. fLastConnectionId++;
  401. return true;
  402. }
  403. bool patchbayDisconnect(int connectionId) override
  404. {
  405. CARLA_ASSERT(fAudioIsReady);
  406. CARLA_ASSERT(fUsedConnections.count() > 0);
  407. carla_debug("CarlaEngineRtAudio::patchbayDisconnect(%i)", connectionId);
  408. if (! fAudioIsReady)
  409. {
  410. setLastError("Engine not ready");
  411. return false;
  412. }
  413. if (fUsedConnections.count() == 0)
  414. {
  415. setLastError("No connections available");
  416. return false;
  417. }
  418. for (NonRtList<ConnectionToId>::Itenerator it=fUsedConnections.begin(); it.valid(); it.next())
  419. {
  420. const ConnectionToId& connection(*it);
  421. if (connection.id == connectionId)
  422. {
  423. const int targetPort((connection.portOut >= 0) ? connection.portOut : connection.portIn);
  424. const int carlaPort((targetPort == connection.portOut) ? connection.portIn : connection.portOut);
  425. if (targetPort >= PATCHBAY_GROUP_MIDI_OUT*1000)
  426. {
  427. const int portId(targetPort-PATCHBAY_GROUP_MIDI_OUT*1000);
  428. for (NonRtList<MidiPort>::Itenerator it=fMidiOuts.begin(); it.valid(); it.next())
  429. {
  430. MidiPort& midiPort(*it);
  431. if (midiPort.portId == portId)
  432. {
  433. RtMidiOut* const midiOutPort((RtMidiOut*)midiPort.rtmidi);
  434. delete midiOutPort;
  435. fMidiOuts.remove(it);
  436. break;
  437. }
  438. }
  439. }
  440. else if (targetPort >= PATCHBAY_GROUP_MIDI_IN*1000)
  441. {
  442. const int portId(targetPort-PATCHBAY_GROUP_MIDI_IN*1000);
  443. for (NonRtList<MidiPort>::Itenerator it=fMidiIns.begin(); it.valid(); it.next())
  444. {
  445. MidiPort& midiPort(*it);
  446. if (midiPort.portId == portId)
  447. {
  448. RtMidiIn* const midiInPort((RtMidiIn*)midiPort.rtmidi);
  449. midiInPort->cancelCallback();
  450. delete midiInPort;
  451. fMidiIns.remove(it);
  452. break;
  453. }
  454. }
  455. }
  456. else if (targetPort >= PATCHBAY_GROUP_AUDIO_OUT*1000)
  457. {
  458. CARLA_ASSERT(carlaPort == PATCHBAY_PORT_AUDIO_OUT1 || carlaPort == PATCHBAY_PORT_AUDIO_OUT2);
  459. const int portId(targetPort-PATCHBAY_GROUP_AUDIO_OUT*1000);
  460. fConnectAudioLock.lock();
  461. if (carlaPort == PATCHBAY_PORT_AUDIO_OUT1)
  462. fConnectedAudioOuts[0].removeAll(portId);
  463. else
  464. fConnectedAudioOuts[1].removeAll(portId);
  465. fConnectAudioLock.unlock();
  466. }
  467. else if (targetPort >= PATCHBAY_GROUP_AUDIO_IN*1000)
  468. {
  469. CARLA_ASSERT(carlaPort == PATCHBAY_PORT_AUDIO_IN1 || carlaPort == PATCHBAY_PORT_AUDIO_IN2);
  470. const int portId(targetPort-PATCHBAY_GROUP_AUDIO_IN*1000);
  471. fConnectAudioLock.lock();
  472. if (carlaPort == PATCHBAY_PORT_AUDIO_IN1)
  473. fConnectedAudioIns[0].removeAll(portId);
  474. else
  475. fConnectedAudioIns[1].removeAll(portId);
  476. fConnectAudioLock.unlock();
  477. }
  478. else
  479. {
  480. CARLA_ASSERT(false);
  481. }
  482. callback(CALLBACK_PATCHBAY_CONNECTION_REMOVED, 0, connection.id, 0, 0.0f, nullptr);
  483. fUsedConnections.remove(it);
  484. break;
  485. }
  486. }
  487. return true;
  488. }
  489. void patchbayRefresh() override
  490. {
  491. CARLA_ASSERT(fAudioIsReady);
  492. if (! fAudioIsReady)
  493. return;
  494. char strBuf[STR_MAX+1];
  495. fLastConnectionId = 0;
  496. fUsedMidiIns.clear();
  497. fUsedMidiOuts.clear();
  498. fUsedConnections.clear();
  499. // Main
  500. {
  501. callback(CALLBACK_PATCHBAY_CLIENT_ADDED, 0, PATCHBAY_GROUP_CARLA, 0, 0.0f, getName());
  502. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_AUDIO_IN1, PATCHBAY_PORT_IS_AUDIO|PATCHBAY_PORT_IS_INPUT, "audio-in1");
  503. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_AUDIO_IN2, PATCHBAY_PORT_IS_AUDIO|PATCHBAY_PORT_IS_INPUT, "audio-in2");
  504. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_AUDIO_OUT1, PATCHBAY_PORT_IS_AUDIO|PATCHBAY_PORT_IS_OUTPUT, "audio-out1");
  505. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_AUDIO_OUT2, PATCHBAY_PORT_IS_AUDIO|PATCHBAY_PORT_IS_OUTPUT, "audio-out2");
  506. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_MIDI_IN, PATCHBAY_PORT_IS_MIDI|PATCHBAY_PORT_IS_INPUT, "midi-in");
  507. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_MIDI_OUT, PATCHBAY_PORT_IS_MIDI|PATCHBAY_PORT_IS_OUTPUT, "midi-out");
  508. }
  509. // Audio In
  510. {
  511. if (fConnectName.isNotEmpty())
  512. std::snprintf(strBuf, STR_MAX, "Capture (%s)", (const char*)fConnectName);
  513. else
  514. std::strncpy(strBuf, "Capture", STR_MAX);
  515. callback(CALLBACK_PATCHBAY_CLIENT_ADDED, 0, PATCHBAY_GROUP_AUDIO_IN, 0, 0.0f, strBuf);
  516. for (unsigned int i=0; i < fAudioCountIn; ++i)
  517. {
  518. std::snprintf(strBuf, STR_MAX, "capture_%i", i+1);
  519. 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);
  520. }
  521. }
  522. // Audio Out
  523. {
  524. if (fConnectName.isNotEmpty())
  525. std::snprintf(strBuf, STR_MAX, "Playback (%s)", (const char*)fConnectName);
  526. else
  527. std::strncpy(strBuf, "Playback", STR_MAX);
  528. callback(CALLBACK_PATCHBAY_CLIENT_ADDED, 0, PATCHBAY_GROUP_AUDIO_OUT, 0, 0.0f, strBuf);
  529. for (unsigned int i=0; i < fAudioCountOut; ++i)
  530. {
  531. std::snprintf(strBuf, STR_MAX, "playback_%i", i+1);
  532. 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);
  533. }
  534. }
  535. // MIDI In
  536. {
  537. callback(CALLBACK_PATCHBAY_CLIENT_ADDED, 0, PATCHBAY_GROUP_MIDI_IN, 0, 0.0f, "Readable MIDI ports");
  538. for (unsigned int i=0, count=fDummyMidiIn.getPortCount(); i < count; ++i)
  539. {
  540. PortNameToId portNameToId;
  541. portNameToId.portId = PATCHBAY_GROUP_MIDI_IN*1000 + i;
  542. std::strncpy(portNameToId.name, fDummyMidiIn.getPortName(i).c_str(), STR_MAX);
  543. fUsedMidiIns.append(portNameToId);
  544. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_MIDI_IN, portNameToId.portId, PATCHBAY_PORT_IS_MIDI|PATCHBAY_PORT_IS_OUTPUT, portNameToId.name);
  545. }
  546. }
  547. #if 0 // midi-out not implemented yet
  548. // MIDI Out
  549. {
  550. callback(CALLBACK_PATCHBAY_CLIENT_ADDED, 0, PATCHBAY_GROUP_MIDI_OUT, 0, 0.0f, "Writable MIDI ports");
  551. for (unsigned int i=0, count=fDummyMidiOut.getPortCount(); i < count; ++i)
  552. {
  553. PortNameToId portNameToId;
  554. portNameToId.portId = PATCHBAY_GROUP_MIDI_OUT*1000 + i;
  555. std::strncpy(portNameToId.name, fDummyMidiOut.getPortName(i).c_str(), STR_MAX);
  556. fUsedMidiOuts.append(portNameToId);
  557. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_MIDI_OUT, portNameToId.portId, PATCHBAY_PORT_IS_MIDI|PATCHBAY_PORT_IS_INPUT, portNameToId.name);
  558. }
  559. }
  560. #endif
  561. // Connections
  562. fConnectAudioLock.lock();
  563. for (NonRtList<uint>::Itenerator it = fConnectedAudioIns[0].begin(); it.valid(); it.next())
  564. {
  565. const uint& port(*it);
  566. CARLA_ASSERT(port < fAudioCountIn);
  567. ConnectionToId connectionToId;
  568. connectionToId.id = fLastConnectionId;
  569. connectionToId.portOut = PATCHBAY_GROUP_AUDIO_IN*1000 + port;
  570. connectionToId.portIn = PATCHBAY_PORT_AUDIO_IN1;
  571. callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
  572. fUsedConnections.append(connectionToId);
  573. fLastConnectionId++;
  574. }
  575. for (NonRtList<uint>::Itenerator it = fConnectedAudioIns[1].begin(); it.valid(); it.next())
  576. {
  577. const uint& port(*it);
  578. CARLA_ASSERT(port < fAudioCountIn);
  579. ConnectionToId connectionToId;
  580. connectionToId.id = fLastConnectionId;
  581. connectionToId.portOut = PATCHBAY_GROUP_AUDIO_IN*1000 + port;
  582. connectionToId.portIn = PATCHBAY_PORT_AUDIO_IN2;
  583. callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
  584. fUsedConnections.append(connectionToId);
  585. fLastConnectionId++;
  586. }
  587. for (NonRtList<uint>::Itenerator it = fConnectedAudioOuts[0].begin(); it.valid(); it.next())
  588. {
  589. const uint& port(*it);
  590. CARLA_ASSERT(port < fAudioCountOut);
  591. ConnectionToId connectionToId;
  592. connectionToId.id = fLastConnectionId;
  593. connectionToId.portOut = PATCHBAY_PORT_AUDIO_OUT1;
  594. connectionToId.portIn = PATCHBAY_GROUP_AUDIO_OUT*1000 + port;
  595. callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
  596. fUsedConnections.append(connectionToId);
  597. fLastConnectionId++;
  598. }
  599. for (NonRtList<uint>::Itenerator it = fConnectedAudioOuts[1].begin(); it.valid(); it.next())
  600. {
  601. const uint& port(*it);
  602. CARLA_ASSERT(port < fAudioCountOut);
  603. ConnectionToId connectionToId;
  604. connectionToId.id = fLastConnectionId;
  605. connectionToId.portOut = PATCHBAY_PORT_AUDIO_OUT2;
  606. connectionToId.portIn = PATCHBAY_GROUP_AUDIO_OUT*1000 + port;
  607. callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
  608. fUsedConnections.append(connectionToId);
  609. fLastConnectionId++;
  610. }
  611. fConnectAudioLock.unlock();
  612. for (NonRtList<MidiPort>::Itenerator it=fMidiIns.begin(); it.valid(); it.next())
  613. {
  614. const MidiPort& midiPort(*it);
  615. ConnectionToId connectionToId;
  616. connectionToId.id = fLastConnectionId;
  617. connectionToId.portOut = PATCHBAY_GROUP_MIDI_IN*1000 + midiPort.portId;
  618. connectionToId.portIn = PATCHBAY_PORT_MIDI_IN;
  619. callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
  620. fUsedConnections.append(connectionToId);
  621. fLastConnectionId++;
  622. }
  623. for (NonRtList<MidiPort>::Itenerator it=fMidiOuts.begin(); it.valid(); it.next())
  624. {
  625. const MidiPort& midiPort(*it);
  626. ConnectionToId connectionToId;
  627. connectionToId.id = fLastConnectionId;
  628. connectionToId.portOut = PATCHBAY_PORT_MIDI_OUT;
  629. connectionToId.portIn = PATCHBAY_GROUP_MIDI_OUT*1000 + midiPort.portId;
  630. callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
  631. fUsedConnections.append(connectionToId);
  632. fLastConnectionId++;
  633. }
  634. }
  635. // -------------------------------------------------------------------
  636. protected:
  637. void handleAudioProcessCallback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status)
  638. {
  639. // get buffers from RtAudio
  640. float* insPtr = (float*)inputBuffer;
  641. float* outsPtr = (float*)outputBuffer;
  642. // assert buffers
  643. CARLA_ASSERT(nframes != 0);
  644. CARLA_ASSERT_INT2(nframes == fBufferSize, nframes, fBufferSize);
  645. CARLA_ASSERT(outsPtr != nullptr);
  646. if (kData->curPluginCount == 0 || fAudioCountOut == 0 || ! fAudioIsReady)
  647. {
  648. if (fAudioCountOut > 0 && fAudioIsReady)
  649. carla_zeroFloat(outsPtr, nframes*fAudioCountOut);
  650. return proccessPendingEvents();
  651. }
  652. // initialize audio input
  653. if (fAudioIsInterleaved)
  654. {
  655. for (unsigned int i=0, j=0; i < nframes*fAudioCountIn; ++i)
  656. {
  657. fAudioBufIn[i/fAudioCountIn][j] = insPtr[i];
  658. if ((i+1) % fAudioCountIn == 0)
  659. j += 1;
  660. }
  661. }
  662. else
  663. {
  664. for (unsigned int i=0; i < fAudioCountIn; ++i)
  665. carla_copyFloat(fAudioBufIn[i], insPtr+(nframes*i), nframes);
  666. }
  667. // initialize audio output
  668. for (unsigned int i=0; i < fAudioCountOut; ++i)
  669. carla_zeroFloat(fAudioBufOut[i], nframes);
  670. carla_zeroFloat(fAudioBufRackOut[0], nframes);
  671. carla_zeroFloat(fAudioBufRackOut[1], nframes);
  672. // initialize input events
  673. carla_zeroMem(kData->bufEvents.in, sizeof(EngineEvent)*INTERNAL_EVENT_COUNT);
  674. if (fMidiInEvents.mutex.tryLock())
  675. {
  676. uint32_t engineEventIndex = 0;
  677. fMidiInEvents.splice();
  678. while (! fMidiInEvents.data.isEmpty())
  679. {
  680. const RtMidiEvent& midiEvent(fMidiInEvents.data.getFirst(true));
  681. EngineEvent& engineEvent(kData->bufEvents.in[engineEventIndex++]);
  682. engineEvent.clear();
  683. const uint8_t midiStatus = MIDI_GET_STATUS_FROM_DATA(midiEvent.data);
  684. const uint8_t midiChannel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent.data);
  685. engineEvent.channel = midiChannel;
  686. if (midiEvent.time < fTimeInfo.frame)
  687. {
  688. engineEvent.time = 0;
  689. }
  690. else if (midiEvent.time >= fTimeInfo.frame + nframes)
  691. {
  692. engineEvent.time = fTimeInfo.frame + nframes-1;
  693. carla_stderr("MIDI Event in the future!, %i vs %i", engineEvent.time, fTimeInfo.frame);
  694. }
  695. else
  696. engineEvent.time = midiEvent.time - fTimeInfo.frame;
  697. if (MIDI_IS_STATUS_CONTROL_CHANGE(midiStatus))
  698. {
  699. const uint8_t midiControl = midiEvent.data[1];
  700. engineEvent.type = kEngineEventTypeControl;
  701. if (MIDI_IS_CONTROL_BANK_SELECT(midiControl))
  702. {
  703. const uint8_t midiBank = midiEvent.data[2];
  704. engineEvent.ctrl.type = kEngineControlEventTypeMidiBank;
  705. engineEvent.ctrl.param = midiBank;
  706. engineEvent.ctrl.value = 0.0f;
  707. }
  708. else if (midiControl == MIDI_CONTROL_ALL_SOUND_OFF)
  709. {
  710. engineEvent.ctrl.type = kEngineControlEventTypeAllSoundOff;
  711. engineEvent.ctrl.param = 0;
  712. engineEvent.ctrl.value = 0.0f;
  713. }
  714. else if (midiControl == MIDI_CONTROL_ALL_NOTES_OFF)
  715. {
  716. engineEvent.ctrl.type = kEngineControlEventTypeAllNotesOff;
  717. engineEvent.ctrl.param = 0;
  718. engineEvent.ctrl.value = 0.0f;
  719. }
  720. else
  721. {
  722. const uint8_t midiValue = midiEvent.data[2];
  723. engineEvent.ctrl.type = kEngineControlEventTypeParameter;
  724. engineEvent.ctrl.param = midiControl;
  725. engineEvent.ctrl.value = float(midiValue)/127.0f;
  726. }
  727. }
  728. else if (MIDI_IS_STATUS_PROGRAM_CHANGE(midiStatus))
  729. {
  730. const uint8_t midiProgram = midiEvent.data[1];
  731. engineEvent.type = kEngineEventTypeControl;
  732. engineEvent.ctrl.type = kEngineControlEventTypeMidiProgram;
  733. engineEvent.ctrl.param = midiProgram;
  734. engineEvent.ctrl.value = 0.0f;
  735. }
  736. else
  737. {
  738. engineEvent.type = kEngineEventTypeMidi;
  739. engineEvent.midi.data[0] = midiStatus;
  740. engineEvent.midi.data[1] = midiEvent.data[1];
  741. engineEvent.midi.data[2] = midiEvent.data[2];
  742. engineEvent.midi.data[3] = midiEvent.data[3];
  743. engineEvent.midi.size = midiEvent.size;
  744. }
  745. if (engineEventIndex >= INTERNAL_EVENT_COUNT)
  746. break;
  747. }
  748. fMidiInEvents.mutex.unlock();
  749. }
  750. fConnectAudioLock.lock();
  751. // connect input buffers
  752. if (fConnectedAudioIns[0].count() == 0)
  753. {
  754. carla_zeroFloat(fAudioBufRackIn[0], nframes);
  755. }
  756. else
  757. {
  758. bool first = true;
  759. for (NonRtList<uint>::Itenerator it = fConnectedAudioIns[0].begin(); it.valid(); it.next())
  760. {
  761. const uint& port(*it);
  762. CARLA_ASSERT(port < fAudioCountIn);
  763. if (first)
  764. {
  765. carla_copyFloat(fAudioBufRackIn[0], fAudioBufIn[port], nframes);
  766. first = false;
  767. }
  768. else
  769. carla_addFloat(fAudioBufRackIn[0], fAudioBufIn[port], nframes);
  770. }
  771. if (first)
  772. carla_zeroFloat(fAudioBufRackIn[0], nframes);
  773. }
  774. if (fConnectedAudioIns[1].count() == 0)
  775. {
  776. carla_zeroFloat(fAudioBufRackIn[1], nframes);
  777. }
  778. else
  779. {
  780. bool first = true;
  781. for (NonRtList<uint>::Itenerator it = fConnectedAudioIns[1].begin(); it.valid(); it.next())
  782. {
  783. const uint& port(*it);
  784. CARLA_ASSERT(port < fAudioCountIn);
  785. if (first)
  786. {
  787. carla_copyFloat(fAudioBufRackIn[1], fAudioBufIn[port], nframes);
  788. first = false;
  789. }
  790. else
  791. carla_addFloat(fAudioBufRackIn[1], fAudioBufIn[port], nframes);
  792. }
  793. if (first)
  794. carla_zeroFloat(fAudioBufRackIn[1], nframes);
  795. }
  796. // process
  797. processRack(fAudioBufRackIn, fAudioBufRackOut, nframes);
  798. // connect output buffers
  799. if (fConnectedAudioOuts[0].count() != 0)
  800. {
  801. for (NonRtList<uint>::Itenerator it = fConnectedAudioOuts[0].begin(); it.valid(); it.next())
  802. {
  803. const uint& port(*it);
  804. CARLA_ASSERT(port < fAudioCountOut);
  805. carla_addFloat(fAudioBufOut[port], fAudioBufRackOut[0], nframes);
  806. }
  807. }
  808. if (fConnectedAudioOuts[1].count() != 0)
  809. {
  810. for (NonRtList<uint>::Itenerator it = fConnectedAudioOuts[1].begin(); it.valid(); it.next())
  811. {
  812. const uint& port(*it);
  813. CARLA_ASSERT(port < fAudioCountOut);
  814. carla_addFloat(fAudioBufOut[port], fAudioBufRackOut[1], nframes);
  815. }
  816. }
  817. fConnectAudioLock.unlock();
  818. // output audio
  819. if (fAudioIsInterleaved)
  820. {
  821. for (unsigned int i=0, j=0; i < nframes*fAudioCountOut; ++i)
  822. {
  823. outsPtr[i] = fAudioBufOut[i/fAudioCountOut][j];
  824. if ((i+1) % fAudioCountOut == 0)
  825. j += 1;
  826. }
  827. }
  828. else
  829. {
  830. for (unsigned int i=0; i < fAudioCountOut; ++i)
  831. carla_copyFloat(outsPtr+(nframes*i), fAudioBufOut[i], nframes);
  832. }
  833. // output events
  834. {
  835. // TODO
  836. //fMidiOutEvents...
  837. }
  838. proccessPendingEvents();
  839. return;
  840. // unused
  841. (void)streamTime;
  842. (void)status;
  843. }
  844. void handleMidiCallback(double timeStamp, std::vector<unsigned char>* const message)
  845. {
  846. if (! fAudioIsReady)
  847. return;
  848. const size_t messageSize = message->size();
  849. static uint32_t lastTime = 0;
  850. if (messageSize == 0 || messageSize > 4)
  851. return;
  852. timeStamp /= 2;
  853. if (timeStamp > 0.95)
  854. timeStamp = 0.95;
  855. else if (timeStamp < 0.0)
  856. timeStamp = 0.0;
  857. RtMidiEvent midiEvent;
  858. midiEvent.time = fTimeInfo.frame + (timeStamp*(double)fBufferSize);
  859. if (midiEvent.time < lastTime)
  860. midiEvent.time = lastTime;
  861. else
  862. lastTime = midiEvent.time;
  863. if (messageSize == 1)
  864. {
  865. midiEvent.data[0] = message->at(0);
  866. midiEvent.data[1] = 0;
  867. midiEvent.data[2] = 0;
  868. midiEvent.data[3] = 0;
  869. midiEvent.size = 1;
  870. }
  871. else if (messageSize == 2)
  872. {
  873. midiEvent.data[0] = message->at(0);
  874. midiEvent.data[1] = message->at(1);
  875. midiEvent.data[2] = 0;
  876. midiEvent.data[3] = 0;
  877. midiEvent.size = 2;
  878. }
  879. else if (messageSize == 3)
  880. {
  881. midiEvent.data[0] = message->at(0);
  882. midiEvent.data[1] = message->at(1);
  883. midiEvent.data[2] = message->at(2);
  884. midiEvent.data[3] = 0;
  885. midiEvent.size = 3;
  886. }
  887. else
  888. {
  889. midiEvent.data[0] = message->at(0);
  890. midiEvent.data[1] = message->at(1);
  891. midiEvent.data[2] = message->at(2);
  892. midiEvent.data[3] = message->at(3);
  893. midiEvent.size = 4;
  894. }
  895. fMidiInEvents.append(midiEvent);
  896. }
  897. bool connectMidiInPort(const int portId)
  898. {
  899. CARLA_ASSERT(fUsedMidiIns.count() > 0);
  900. CARLA_ASSERT(portId >= 0);
  901. CARLA_ASSERT(static_cast<size_t>(portId) < fUsedMidiIns.count());
  902. carla_debug("CarlaEngineRtAudio::connectMidiInPort(%i)", portId);
  903. if (portId < 0 || static_cast<size_t>(portId) >= fUsedMidiIns.count())
  904. return false;
  905. const char* const portName(fUsedMidiIns.getAt(portId).name);
  906. char newPortName[STR_MAX+1];
  907. std::snprintf(newPortName, STR_MAX, "%s:in-%i", (const char*)getName(), portId+1);
  908. int rtMidiPortIndex = -1;
  909. RtMidiIn* const rtMidiIn(new RtMidiIn(getMatchedAudioMidiAPi(fAudio.getCurrentApi()), newPortName, 512));
  910. rtMidiIn->ignoreTypes();
  911. rtMidiIn->setCallback(carla_rtmidi_callback, this);
  912. for (unsigned int i=0, count=rtMidiIn->getPortCount(); i < count; ++i)
  913. {
  914. if (rtMidiIn->getPortName(i) == portName)
  915. {
  916. rtMidiPortIndex = i;
  917. break;
  918. }
  919. }
  920. if (rtMidiPortIndex == -1)
  921. {
  922. delete rtMidiIn;
  923. return false;
  924. }
  925. rtMidiIn->openPort(rtMidiPortIndex, newPortName+(std::strlen(getName())+1));
  926. MidiPort midiPort;
  927. midiPort.portId = portId;
  928. midiPort.rtmidi = rtMidiIn;
  929. fMidiIns.append(midiPort);
  930. return true;
  931. }
  932. bool connectMidiOutPort(const int portId)
  933. {
  934. CARLA_ASSERT(fUsedMidiOuts.count() > 0);
  935. CARLA_ASSERT(portId >= 0);
  936. CARLA_ASSERT(static_cast<size_t>(portId) < fUsedMidiOuts.count());
  937. carla_debug("CarlaEngineRtAudio::connectMidiOutPort(%i)", portId);
  938. if (portId < 0 || static_cast<size_t>(portId) >= fUsedMidiOuts.count())
  939. return false;
  940. const char* const portName(fUsedMidiOuts.getAt(portId).name);
  941. char newPortName[STR_MAX+1];
  942. std::snprintf(newPortName, STR_MAX, "%s:out-%i", (const char*)getName(), portId+1);
  943. int rtMidiPortIndex = -1;
  944. RtMidiOut* const rtMidiOut(new RtMidiOut(getMatchedAudioMidiAPi(fAudio.getCurrentApi()), newPortName));
  945. for (unsigned int i=0, count=rtMidiOut->getPortCount(); i < count; ++i)
  946. {
  947. if (rtMidiOut->getPortName(i) == portName)
  948. {
  949. rtMidiPortIndex = i;
  950. break;
  951. }
  952. }
  953. if (rtMidiPortIndex == -1)
  954. {
  955. delete rtMidiOut;
  956. return false;
  957. }
  958. rtMidiOut->openPort(rtMidiPortIndex, newPortName+(std::strlen(getName())+1));
  959. MidiPort midiPort;
  960. midiPort.portId = portId;
  961. midiPort.rtmidi = rtMidiOut;
  962. fMidiOuts.append(midiPort);
  963. return true;
  964. }
  965. // -------------------------------------
  966. private:
  967. RtAudio fAudio;
  968. float** fAudioBufIn;
  969. float** fAudioBufOut;
  970. float* fAudioBufRackIn[2];
  971. float* fAudioBufRackOut[2];
  972. uint fAudioCountIn;
  973. uint fAudioCountOut;
  974. bool fAudioIsInterleaved;
  975. bool fAudioIsReady;
  976. NonRtList<uint> fConnectedAudioIns[2];
  977. NonRtList<uint> fConnectedAudioOuts[2];
  978. CarlaMutex fConnectAudioLock;
  979. CarlaString fConnectName;
  980. RtMidiIn fDummyMidiIn;
  981. RtMidiOut fDummyMidiOut;
  982. enum PatchbayGroupIds {
  983. PATCHBAY_GROUP_CARLA = -1,
  984. PATCHBAY_GROUP_AUDIO_IN = 0,
  985. PATCHBAY_GROUP_AUDIO_OUT = 1,
  986. PATCHBAY_GROUP_MIDI_IN = 2,
  987. PATCHBAY_GROUP_MIDI_OUT = 3,
  988. PATCHBAY_GROUP_MAX = 4
  989. };
  990. enum PatchbayPortIds {
  991. PATCHBAY_PORT_AUDIO_IN1 = -1,
  992. PATCHBAY_PORT_AUDIO_IN2 = -2,
  993. PATCHBAY_PORT_AUDIO_OUT1 = -3,
  994. PATCHBAY_PORT_AUDIO_OUT2 = -4,
  995. PATCHBAY_PORT_MIDI_IN = -5,
  996. PATCHBAY_PORT_MIDI_OUT = -6,
  997. PATCHBAY_PORT_MAX = -7
  998. };
  999. struct ConnectionToId {
  1000. int id;
  1001. int portOut;
  1002. int portIn;
  1003. };
  1004. struct PortNameToId {
  1005. int portId;
  1006. char name[STR_MAX+1];
  1007. };
  1008. int fLastConnectionId;
  1009. NonRtList<PortNameToId> fUsedMidiIns;
  1010. NonRtList<PortNameToId> fUsedMidiOuts;
  1011. NonRtList<ConnectionToId> fUsedConnections;
  1012. struct MidiPort {
  1013. RtMidi* rtmidi;
  1014. int portId;
  1015. };
  1016. NonRtList<MidiPort> fMidiIns;
  1017. NonRtList<MidiPort> fMidiOuts;
  1018. struct RtMidiEvent {
  1019. uint32_t time;
  1020. unsigned char data[4];
  1021. unsigned char size;
  1022. };
  1023. struct RtMidiEvents {
  1024. CarlaMutex mutex;
  1025. RtList<RtMidiEvent>::Pool dataPool;
  1026. RtList<RtMidiEvent> data;
  1027. RtList<RtMidiEvent> dataPending;
  1028. RtMidiEvents()
  1029. : dataPool(512, 512),
  1030. data(dataPool),
  1031. dataPending(dataPool) {}
  1032. ~RtMidiEvents()
  1033. {
  1034. clear();
  1035. }
  1036. void append(const RtMidiEvent& event)
  1037. {
  1038. mutex.lock();
  1039. dataPending.append(event);
  1040. mutex.unlock();
  1041. }
  1042. void clear()
  1043. {
  1044. mutex.lock();
  1045. data.clear();
  1046. dataPending.clear();
  1047. mutex.unlock();
  1048. }
  1049. void splice()
  1050. {
  1051. dataPending.spliceAppend(data, true);
  1052. }
  1053. };
  1054. RtMidiEvents fMidiInEvents;
  1055. //RtMidiEvents fMidiOutEvents;
  1056. #define handlePtr ((CarlaEngineRtAudio*)userData)
  1057. static int carla_rtaudio_process_callback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status, void* userData)
  1058. {
  1059. handlePtr->handleAudioProcessCallback(outputBuffer, inputBuffer, nframes, streamTime, status);
  1060. return 0;
  1061. }
  1062. static void carla_rtmidi_callback(double timeStamp, std::vector<unsigned char>* message, void* userData)
  1063. {
  1064. handlePtr->handleMidiCallback(timeStamp, message);
  1065. }
  1066. #undef handlePtr
  1067. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineRtAudio)
  1068. };
  1069. // -----------------------------------------
  1070. CarlaEngine* CarlaEngine::newRtAudio(RtAudioApi api)
  1071. {
  1072. RtAudio::Api rtApi(RtAudio::UNSPECIFIED);
  1073. switch (api)
  1074. {
  1075. case RTAUDIO_DUMMY:
  1076. rtApi = RtAudio::RTAUDIO_DUMMY;
  1077. break;
  1078. case RTAUDIO_LINUX_ALSA:
  1079. rtApi = RtAudio::LINUX_ALSA;
  1080. break;
  1081. case RTAUDIO_LINUX_PULSE:
  1082. rtApi = RtAudio::LINUX_PULSE;
  1083. break;
  1084. case RTAUDIO_LINUX_OSS:
  1085. rtApi = RtAudio::LINUX_OSS;
  1086. break;
  1087. case RTAUDIO_UNIX_JACK:
  1088. rtApi = RtAudio::UNIX_JACK;
  1089. break;
  1090. case RTAUDIO_MACOSX_CORE:
  1091. rtApi = RtAudio::MACOSX_CORE;
  1092. break;
  1093. case RTAUDIO_WINDOWS_ASIO:
  1094. rtApi = RtAudio::WINDOWS_ASIO;
  1095. break;
  1096. case RTAUDIO_WINDOWS_DS:
  1097. rtApi = RtAudio::WINDOWS_DS;
  1098. break;
  1099. }
  1100. return new CarlaEngineRtAudio(rtApi);
  1101. }
  1102. size_t CarlaEngine::getRtAudioApiCount()
  1103. {
  1104. initRtApis();
  1105. return gRtAudioApis.size();
  1106. }
  1107. const char* CarlaEngine::getRtAudioApiName(const unsigned int index)
  1108. {
  1109. initRtApis();
  1110. if (index < gRtAudioApis.size())
  1111. {
  1112. const RtAudio::Api& api(gRtAudioApis[index]);
  1113. switch (api)
  1114. {
  1115. case RtAudio::UNSPECIFIED:
  1116. return "Unspecified";
  1117. case RtAudio::LINUX_ALSA:
  1118. return "ALSA";
  1119. case RtAudio::LINUX_PULSE:
  1120. return "PulseAudio";
  1121. case RtAudio::LINUX_OSS:
  1122. return "OSS";
  1123. case RtAudio::UNIX_JACK:
  1124. #if defined(CARLA_OS_WIN)
  1125. return "JACK with WinMM";
  1126. #elif defined(CARLA_OS_MAC)
  1127. return "JACK with CoreMidi";
  1128. #elif defined(CARLA_OS_LINUX)
  1129. return "JACK with ALSA-MIDI";
  1130. #else
  1131. return "JACK (RtAudio)";
  1132. #endif
  1133. case RtAudio::MACOSX_CORE:
  1134. return "CoreAudio";
  1135. case RtAudio::WINDOWS_ASIO:
  1136. return "ASIO";
  1137. case RtAudio::WINDOWS_DS:
  1138. return "DirectSound";
  1139. case RtAudio::RTAUDIO_DUMMY:
  1140. return "Dummy";
  1141. }
  1142. }
  1143. return nullptr;
  1144. }
  1145. const char** CarlaEngine::getRtAudioApiDeviceNames(const unsigned int index)
  1146. {
  1147. initRtApis();
  1148. if (index < gRtAudioApis.size())
  1149. {
  1150. const RtAudio::Api& api(gRtAudioApis[index]);
  1151. RtAudio rtAudio(api);
  1152. if (gRetNames != nullptr)
  1153. {
  1154. int i=0;
  1155. while (gRetNames[i] != nullptr)
  1156. delete[] gRetNames[i++];
  1157. delete[] gRetNames;
  1158. gRetNames = nullptr;
  1159. }
  1160. const unsigned int devCount(rtAudio.getDeviceCount());
  1161. if (devCount > 0)
  1162. {
  1163. NonRtList<const char*> devNames;
  1164. for (unsigned int i=0; i < devCount; ++i)
  1165. {
  1166. RtAudio::DeviceInfo devInfo(rtAudio.getDeviceInfo(i));
  1167. if (devInfo.probed && devInfo.outputChannels > 0 /*&& (devInfo.nativeFormats & RTAUDIO_FLOAT32) != 0*/)
  1168. devNames.append(carla_strdup(devInfo.name.c_str()));
  1169. }
  1170. const unsigned int realDevCount(devNames.count());
  1171. gRetNames = new const char*[realDevCount+1];
  1172. for (unsigned int i=0; i < realDevCount; ++i)
  1173. gRetNames[i] = devNames.getAt(i);
  1174. gRetNames[realDevCount] = nullptr;
  1175. devNames.clear();
  1176. return gRetNames;
  1177. }
  1178. }
  1179. return nullptr;
  1180. }
  1181. // -----------------------------------------
  1182. CARLA_BACKEND_END_NAMESPACE
  1183. #endif // CARLA_ENGINE_RTAUDIO