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.

1121 lines
42KB

  1. // SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "CarlaPluginInternal.hpp"
  4. #include "CarlaEngine.hpp"
  5. #ifdef CARLA_OS_MAC
  6. # include "CarlaBackendUtils.hpp"
  7. # include "CarlaPluginUI.hpp"
  8. # include "CarlaMacUtils.hpp"
  9. # include <AudioToolbox/AudioUnit.h>
  10. # include <Foundation/Foundation.h>
  11. #endif
  12. CARLA_BACKEND_START_NAMESPACE
  13. // --------------------------------------------------------------------------------------------------------------------
  14. #ifdef CARLA_OS_MAC
  15. typedef AudioComponentPlugInInterface* (*FactoryFn)(const AudioComponentDescription*);
  16. typedef OSStatus (*InitializeFn)(void*);
  17. typedef OSStatus (*UninitializeFn)(void*);
  18. typedef OSStatus (*GetPropertyInfoFn)(void*, AudioUnitPropertyID, AudioUnitScope, AudioUnitElement, UInt32*, Boolean*);
  19. typedef OSStatus (*GetPropertyFn)(void*, AudioUnitPropertyID, AudioUnitScope, AudioUnitElement, void*, UInt32*);
  20. typedef OSStatus (*SetPropertyFn)(void*, AudioUnitPropertyID, AudioUnitScope, AudioUnitElement, const void*, UInt32);
  21. typedef OSStatus (*GetParameterFn)(void*, AudioUnitParameterID, AudioUnitScope, AudioUnitElement, AudioUnitParameterValue*);
  22. typedef OSStatus (*SetParameterFn)(void*, AudioUnitParameterID, AudioUnitScope, AudioUnitElement, AudioUnitParameterValue, UInt32);
  23. typedef OSStatus (*ScheduleParametersFn)(void*, const AudioUnitParameterEvent*, UInt32);
  24. typedef OSStatus (*ResetFn)(void*, AudioUnitScope, AudioUnitElement);
  25. typedef OSStatus (*RenderFn)(void*, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32, UInt32, AudioBufferList*);
  26. typedef OSStatus (*MIDIEventFn)(void*, UInt32, UInt32, UInt32, UInt32);
  27. static constexpr FourCharCode getFourCharCodeFromString(const char str[4])
  28. {
  29. return (str[0] << 24) + (str[1] << 16) + (str[2] << 8) + str[3];
  30. }
  31. class CarlaPluginAU : public CarlaPlugin,
  32. private CarlaPluginUI::Callback
  33. {
  34. public:
  35. CarlaPluginAU(CarlaEngine* const engine, const uint id)
  36. : CarlaPlugin(engine, id),
  37. fInterface(nullptr),
  38. fAudioBufferData(nullptr)
  39. {
  40. carla_stdout("CarlaPluginAU::CarlaPluginAU(%p, %i)", engine, id);
  41. }
  42. ~CarlaPluginAU() override
  43. {
  44. carla_stdout("CarlaPluginAU::~CarlaPluginAU()");
  45. // close UI
  46. showCustomUI(false);
  47. pData->singleMutex.lock();
  48. pData->masterMutex.lock();
  49. if (pData->client != nullptr && pData->client->isActive())
  50. pData->client->deactivate(true);
  51. if (pData->active)
  52. {
  53. deactivate();
  54. pData->active = false;
  55. }
  56. if (fInterface != nullptr)
  57. {
  58. fInterface->Close(fInterface);
  59. fInterface = nullptr;
  60. }
  61. if (fAudioBufferData != nullptr)
  62. {
  63. std::free(fAudioBufferData);
  64. fAudioBufferData = nullptr;
  65. }
  66. // if (fLastChunk != nullptr)
  67. // {
  68. // std::free(fLastChunk);
  69. // fLastChunk = nullptr;
  70. // }
  71. clearBuffers();
  72. }
  73. // -------------------------------------------------------------------
  74. // Information (base)
  75. PluginType getType() const noexcept override
  76. {
  77. return PLUGIN_AU;
  78. }
  79. PluginCategory getCategory() const noexcept override
  80. {
  81. // TODO
  82. return PLUGIN_CATEGORY_NONE;
  83. }
  84. uint32_t getLatencyInFrames() const noexcept override
  85. {
  86. // TODO
  87. return 0;
  88. }
  89. // -------------------------------------------------------------------
  90. // Information (count)
  91. // -------------------------------------------------------------------
  92. // Information (current data)
  93. // -------------------------------------------------------------------
  94. // Information (per-plugin data)
  95. uint getOptionsAvailable() const noexcept override
  96. {
  97. // TODO
  98. return 0x0;
  99. }
  100. float getParameterValue(const uint32_t parameterId) const noexcept override
  101. {
  102. CARLA_SAFE_ASSERT_RETURN(fInterface != nullptr, 0.f);
  103. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0.f);
  104. const AudioUnitParameterID paramId = pData->param.data[parameterId].rindex;
  105. AudioUnitParameterValue value = 0.f;
  106. if (fFunctions.getParameter(fInterface, paramId, kAudioUnitScope_Global, 0, &value) == noErr)
  107. return value;
  108. return 0.f;
  109. }
  110. bool getLabel(char* const strBuf) const noexcept override
  111. {
  112. std::strncpy(strBuf, fLabel.buffer(), STR_MAX);
  113. return true;
  114. }
  115. bool getMaker(char* const strBuf) const noexcept override
  116. {
  117. std::strncpy(strBuf, fMaker.buffer(), STR_MAX);
  118. return true;
  119. }
  120. bool getRealName(char* const strBuf) const noexcept override
  121. {
  122. std::strncpy(strBuf, fName.buffer(), STR_MAX);
  123. return true;
  124. }
  125. bool getParameterName(const uint32_t parameterId, char* const strBuf) const noexcept override
  126. {
  127. CARLA_SAFE_ASSERT_RETURN(fInterface != nullptr, false);
  128. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
  129. const AudioUnitParameterID paramId = pData->param.data[parameterId].rindex;
  130. AudioUnitParameterInfo info = {};
  131. UInt32 outDataSize = sizeof(AudioUnitParameterInfo);
  132. if (fFunctions.getProperty(fInterface, kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, paramId, &info, &outDataSize) == noErr)
  133. {
  134. if (info.flags & kAudioUnitParameterFlag_HasCFNameString)
  135. {
  136. *strBuf = '\0';
  137. if (! CFStringGetCString(info.cfNameString, strBuf, std::min<int>(STR_MAX, CFStringGetLength(info.cfNameString) + 1), kCFStringEncodingUTF8))
  138. {
  139. carla_stdout("CFStringGetCString fail '%s'", info.name);
  140. std::strncpy(strBuf, info.name, STR_MAX);
  141. }
  142. else
  143. {
  144. carla_stdout("CFStringGetCString ok '%s' '%s'", info.name, strBuf);
  145. std::strncpy(strBuf, info.name, STR_MAX);
  146. }
  147. if (info.flags & kAudioUnitParameterFlag_CFNameRelease)
  148. CFRelease(info.cfNameString);
  149. return true;
  150. }
  151. carla_stdout("CFStringGetCString not used '%s'", info.name);
  152. std::strncpy(strBuf, info.name, STR_MAX);
  153. return true;
  154. }
  155. carla_safe_assert("fFunctions.getProperty(...)", __FILE__, __LINE__);
  156. return CarlaPlugin::getParameterName(parameterId, strBuf);
  157. }
  158. // -------------------------------------------------------------------
  159. // Set data (plugin-specific stuff)
  160. void setParameterValue(const uint32_t parameterId, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept override
  161. {
  162. CARLA_SAFE_ASSERT_RETURN(fInterface != nullptr,);
  163. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
  164. const AudioUnitParameterID paramId = pData->param.data[parameterId].rindex;
  165. const float fixedValue = pData->param.getFixedValue(parameterId, value);
  166. fFunctions.setParameter(fInterface, paramId, kAudioUnitScope_Global, 0, value, 0);
  167. CarlaPlugin::setParameterValue(parameterId, fixedValue, sendGui, sendOsc, sendCallback);
  168. }
  169. void setParameterValueRT(const uint32_t parameterId, const float value, const uint32_t frameOffset, const bool sendCallbackLater) noexcept override
  170. {
  171. CARLA_SAFE_ASSERT_RETURN(fInterface != nullptr,);
  172. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
  173. const AudioUnitParameterID paramId = pData->param.data[parameterId].rindex;
  174. const float fixedValue = pData->param.getFixedValue(parameterId, value);
  175. // TODO use scheduled events
  176. fFunctions.setParameter(fInterface, paramId, kAudioUnitScope_Global, 0, value, frameOffset);
  177. CarlaPlugin::setParameterValueRT(parameterId, fixedValue, frameOffset, sendCallbackLater);
  178. }
  179. // ----------------------------------------------------------------------------------------------------------------
  180. // Plugin state
  181. void reload() override
  182. {
  183. CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr,);
  184. CARLA_SAFE_ASSERT_RETURN(fInterface != nullptr,);
  185. carla_debug("CarlaPluginAU::reload() - start");
  186. const EngineProcessMode processMode = pData->engine->getProccessMode();
  187. // Safely disable plugin for reload
  188. const ScopedDisabler sd(this);
  189. if (pData->active)
  190. deactivate();
  191. clearBuffers();
  192. uint32_t audioIns, audioOuts, parametersIns, parametersOuts;
  193. audioIns = audioOuts = parametersIns = parametersOuts = 0;
  194. bool needsCtrlIn, needsCtrlOut, hasMidiIn, hasMidiOut;
  195. needsCtrlIn = needsCtrlOut = hasMidiIn = hasMidiOut = false;
  196. CarlaString portName;
  197. const uint portNameSize = pData->engine->getMaxPortNameSize();
  198. UInt32 outDataSize;
  199. Boolean outWritable = false;
  200. // audio ports
  201. outDataSize = 0;
  202. if (fFunctions.getPropertyInfo(fInterface,
  203. kAudioUnitProperty_SupportedNumChannels,
  204. kAudioUnitScope_Global,
  205. 0, &outDataSize, &outWritable) == noErr
  206. && outDataSize != 0
  207. && outDataSize % sizeof(AUChannelInfo) == 0)
  208. {
  209. const uint32_t numChannels = outDataSize / sizeof(AUChannelInfo);
  210. AUChannelInfo* const channelInfo = new AUChannelInfo[numChannels];
  211. carla_stdout("kAudioUnitProperty_SupportedNumChannels returns %u configs", numChannels);
  212. if (fFunctions.getProperty(fInterface,
  213. kAudioUnitProperty_SupportedNumChannels,
  214. kAudioUnitScope_Global,
  215. 0, channelInfo, &outDataSize) == noErr
  216. && outDataSize == numChannels * sizeof(AUChannelInfo))
  217. {
  218. AUChannelInfo* highestInfo = &channelInfo[0];
  219. carla_stdout("kAudioUnitProperty_SupportedNumChannels returns {%d,%d}... config",
  220. channelInfo[0].inChannels,
  221. channelInfo[0].outChannels);
  222. for (uint32_t i=0; i<numChannels; ++i)
  223. {
  224. if (channelInfo[i].inChannels < 0)
  225. channelInfo[i].inChannels = 2;
  226. if (channelInfo[i].outChannels < 0)
  227. channelInfo[i].outChannels = 2;
  228. if (channelInfo[i].inChannels > highestInfo->inChannels
  229. && channelInfo[i].outChannels > highestInfo->outChannels)
  230. {
  231. highestInfo = &channelInfo[i];
  232. }
  233. }
  234. audioIns = std::min<int16_t>(64, highestInfo->inChannels);
  235. audioOuts = std::min<int16_t>(64, highestInfo->outChannels);
  236. }
  237. else
  238. {
  239. carla_stdout("kAudioUnitProperty_SupportedNumChannels failed");
  240. }
  241. delete[] channelInfo;
  242. }
  243. else
  244. {
  245. outDataSize = 0;
  246. if (fFunctions.getPropertyInfo(fInterface,
  247. kAudioUnitProperty_ElementCount,
  248. kAudioUnitScope_Input,
  249. 0, &outDataSize, &outWritable) == noErr
  250. && outDataSize == sizeof(UInt32))
  251. {
  252. UInt32 count = 0;
  253. if (fFunctions.getProperty(fInterface,
  254. kAudioUnitProperty_ElementCount,
  255. kAudioUnitScope_Input,
  256. 0, &count, &outDataSize) == noErr
  257. && outDataSize == sizeof(UInt32) && count != 0)
  258. {
  259. AudioStreamBasicDescription desc;
  260. std::memset(&desc, 0, sizeof(desc));
  261. outDataSize = sizeof(AudioStreamBasicDescription);
  262. if (fFunctions.getProperty(fInterface,
  263. kAudioUnitProperty_StreamFormat,
  264. kAudioUnitScope_Input,
  265. 0, &desc, &outDataSize) == noErr)
  266. audioIns = std::min<uint32_t>(64, desc.mChannelsPerFrame);
  267. }
  268. }
  269. outDataSize = 0;
  270. if (fFunctions.getPropertyInfo(fInterface,
  271. kAudioUnitProperty_ElementCount,
  272. kAudioUnitScope_Output,
  273. 0, &outDataSize, &outWritable) == noErr
  274. && outDataSize == sizeof(UInt32))
  275. {
  276. UInt32 count = 0;
  277. if (fFunctions.getProperty(fInterface,
  278. kAudioUnitProperty_ElementCount,
  279. kAudioUnitScope_Output,
  280. 0, &count, &outDataSize) == noErr
  281. && outDataSize == sizeof(UInt32) && count != 0)
  282. {
  283. AudioStreamBasicDescription desc;
  284. std::memset(&desc, 0, sizeof(desc));
  285. outDataSize = sizeof(AudioStreamBasicDescription);
  286. if (fFunctions.getProperty(fInterface,
  287. kAudioUnitProperty_StreamFormat,
  288. kAudioUnitScope_Output,
  289. 0, &desc, &outDataSize) == noErr)
  290. audioOuts = std::min<uint32_t>(64, desc.mChannelsPerFrame);
  291. }
  292. }
  293. }
  294. if (audioIns > 0)
  295. {
  296. pData->audioIn.createNew(audioIns);
  297. }
  298. if (audioOuts > 0)
  299. {
  300. pData->audioOut.createNew(audioOuts);
  301. needsCtrlIn = true;
  302. }
  303. std::free(fAudioBufferData);
  304. if (const uint32_t numBuffers = std::max(audioIns, audioOuts))
  305. {
  306. fAudioBufferData = static_cast<AudioBufferList*>(std::malloc(sizeof(uint32_t) + sizeof(AudioBuffer) * numBuffers));
  307. fAudioBufferData->mNumberBuffers = numBuffers;
  308. for (uint32_t i = 0; i < numBuffers; ++i)
  309. fAudioBufferData->mBuffers[i].mNumberChannels = 1;
  310. }
  311. else
  312. {
  313. fAudioBufferData = static_cast<AudioBufferList*>(std::malloc(sizeof(uint32_t)));
  314. fAudioBufferData->mNumberBuffers = 0;
  315. }
  316. // Audio Ins
  317. for (uint32_t i=0; i < audioIns; ++i)
  318. {
  319. portName.clear();
  320. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  321. {
  322. portName = pData->name;
  323. portName += ":";
  324. }
  325. if (audioIns > 1)
  326. {
  327. portName += "input_";
  328. portName += CarlaString(i + 1);
  329. }
  330. else
  331. portName += "input";
  332. portName.truncate(portNameSize);
  333. pData->audioIn.ports[i].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, true, i);
  334. pData->audioIn.ports[i].rindex = i;
  335. }
  336. // Audio Outs
  337. for (uint32_t i=0; i < audioOuts; ++i)
  338. {
  339. portName.clear();
  340. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  341. {
  342. portName = pData->name;
  343. portName += ":";
  344. }
  345. if (audioOuts > 1)
  346. {
  347. portName += "output_";
  348. portName += CarlaString(i + 1);
  349. }
  350. else
  351. portName += "output";
  352. portName.truncate(portNameSize);
  353. pData->audioOut.ports[i].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, false, i);
  354. pData->audioOut.ports[i].rindex = i;
  355. }
  356. // parameters
  357. outDataSize = 0;
  358. if (fFunctions.getPropertyInfo(fInterface,
  359. kAudioUnitProperty_ParameterList,
  360. kAudioUnitScope_Global,
  361. 0, &outDataSize, &outWritable) == noErr
  362. && outDataSize != 0
  363. && outDataSize % sizeof(AudioUnitParameterID) == 0)
  364. {
  365. const uint32_t numParams = outDataSize / sizeof(AudioUnitParameterID);
  366. AudioUnitParameterID* const paramIds = new AudioUnitParameterID[numParams];
  367. if (fFunctions.getProperty(fInterface, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0, paramIds, &outDataSize) == noErr && outDataSize == numParams * sizeof(AudioUnitParameterID))
  368. {
  369. pData->param.createNew(numParams, false);
  370. AudioUnitParameterInfo info;
  371. float min, max, def, step, stepSmall, stepLarge;
  372. for (uint32_t i=0; i<numParams; ++i)
  373. {
  374. carla_zeroStruct(info);
  375. outDataSize = 0;
  376. if (fFunctions.getPropertyInfo(fInterface, kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, paramIds[i], &outDataSize, &outWritable) != noErr)
  377. break;
  378. if (outDataSize != sizeof(AudioUnitParameterInfo))
  379. break;
  380. if (fFunctions.getProperty(fInterface, kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, paramIds[i], &info, &outDataSize) != noErr)
  381. break;
  382. if (info.flags & kAudioUnitParameterFlag_CFNameRelease)
  383. CFRelease(info.cfNameString);
  384. pData->param.data[i].index = static_cast<int32_t>(i);
  385. pData->param.data[i].rindex = static_cast<int32_t>(paramIds[i]);
  386. if (info.flags & kAudioUnitParameterFlag_IsWritable)
  387. {
  388. pData->param.data[i].type = PARAMETER_INPUT;
  389. needsCtrlIn = true;
  390. }
  391. else if (info.flags & (kAudioUnitParameterFlag_IsReadable|kAudioUnitParameterFlag_MeterReadOnly))
  392. {
  393. pData->param.data[i].type = PARAMETER_OUTPUT;
  394. needsCtrlOut = true;
  395. }
  396. else
  397. {
  398. pData->param.data[i].type = PARAMETER_UNKNOWN;
  399. continue;
  400. }
  401. min = info.minValue;
  402. max = info.maxValue;
  403. def = info.defaultValue;
  404. if (min > max)
  405. max = min;
  406. if (carla_isEqual(min, max))
  407. {
  408. carla_stderr2("WARNING - Broken plugin parameter '%s': max == min", info.name);
  409. max = min + 0.1f;
  410. }
  411. if (def < min)
  412. def = min;
  413. else if (def > max)
  414. def = max;
  415. pData->param.data[i].hints |= PARAMETER_IS_ENABLED;
  416. if ((info.flags & kAudioUnitParameterFlag_NonRealTime) == 0)
  417. {
  418. pData->param.data[i].hints |= PARAMETER_IS_AUTOMATABLE;
  419. pData->param.data[i].hints |= PARAMETER_CAN_BE_CV_CONTROLLED;
  420. }
  421. if (info.unit == kAudioUnitParameterUnit_Boolean)
  422. {
  423. step = max - min;
  424. stepSmall = step;
  425. stepLarge = step;
  426. pData->param.data[i].hints |= PARAMETER_IS_BOOLEAN;
  427. }
  428. else if (info.unit == kAudioUnitParameterUnit_Indexed)
  429. {
  430. step = 1.0f;
  431. stepSmall = 1.0f;
  432. stepLarge = 10.0f;
  433. pData->param.data[i].hints |= PARAMETER_IS_INTEGER;
  434. }
  435. else
  436. {
  437. float range = max - min;
  438. step = range/100.0f;
  439. stepSmall = range/1000.0f;
  440. stepLarge = range/10.0f;
  441. }
  442. pData->param.ranges[i].min = min;
  443. pData->param.ranges[i].max = max;
  444. pData->param.ranges[i].def = def;
  445. pData->param.ranges[i].step = step;
  446. pData->param.ranges[i].stepSmall = stepSmall;
  447. pData->param.ranges[i].stepLarge = stepLarge;
  448. }
  449. }
  450. delete[] paramIds;
  451. }
  452. if (needsCtrlIn || hasMidiIn)
  453. {
  454. portName.clear();
  455. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  456. {
  457. portName = pData->name;
  458. portName += ":";
  459. }
  460. portName += "events-in";
  461. portName.truncate(portNameSize);
  462. pData->event.portIn = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, true, 0);
  463. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  464. pData->event.cvSourcePorts = pData->client->createCVSourcePorts();
  465. #endif
  466. }
  467. if (needsCtrlOut || hasMidiOut)
  468. {
  469. portName.clear();
  470. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  471. {
  472. portName = pData->name;
  473. portName += ":";
  474. }
  475. portName += "events-out";
  476. portName.truncate(portNameSize);
  477. pData->event.portOut = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, false, 0);
  478. }
  479. // plugin hints
  480. pData->hints = 0x0;
  481. if (audioOuts > 0 && (audioIns == audioOuts || audioIns == 1))
  482. pData->hints |= PLUGIN_CAN_DRYWET;
  483. if (audioOuts > 0)
  484. pData->hints |= PLUGIN_CAN_VOLUME;
  485. if (audioOuts >= 2 && audioOuts % 2 == 0)
  486. pData->hints |= PLUGIN_CAN_BALANCE;
  487. // extra plugin hints
  488. pData->extraHints = 0x0;
  489. bufferSizeChanged(pData->engine->getBufferSize());
  490. reloadPrograms(true);
  491. if (pData->active)
  492. activate();
  493. carla_debug("CarlaPluginAU::reload() - end");
  494. }
  495. // -------------------------------------------------------------------
  496. // Plugin processing
  497. void activate() noexcept override
  498. {
  499. CARLA_SAFE_ASSERT_RETURN(fInterface != nullptr,);
  500. AudioStreamBasicDescription streamFormat = {
  501. .mFormatID = kAudioFormatLinearPCM,
  502. .mBitsPerChannel = 32,
  503. .mBytesPerFrame = sizeof(float),
  504. .mBytesPerPacket = sizeof(float),
  505. .mFramesPerPacket = 1,
  506. .mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved,
  507. .mChannelsPerFrame = 0,
  508. .mSampleRate = pData->engine->getSampleRate(),
  509. };
  510. if (pData->audioIn.count != 0)
  511. {
  512. streamFormat.mChannelsPerFrame = pData->audioIn.count;
  513. CARLA_SAFE_ASSERT_RETURN(fFunctions.setProperty(fInterface,
  514. kAudioUnitProperty_StreamFormat,
  515. kAudioUnitScope_Input,
  516. 0, &streamFormat, sizeof(streamFormat)) == noErr,);
  517. }
  518. if (pData->audioOut.count != 0)
  519. {
  520. streamFormat.mChannelsPerFrame = pData->audioOut.count;
  521. CARLA_SAFE_ASSERT_RETURN(fFunctions.setProperty(fInterface,
  522. kAudioUnitProperty_StreamFormat,
  523. kAudioUnitScope_Output,
  524. 0, &streamFormat, sizeof(streamFormat)) == noErr,);
  525. }
  526. fFunctions.initialize(fInterface);
  527. }
  528. void deactivate() noexcept override
  529. {
  530. CARLA_SAFE_ASSERT_RETURN(fInterface != nullptr,);
  531. fFunctions.uninitialize(fInterface);
  532. }
  533. void process(const float* const* const audioIn,
  534. float** const audioOut,
  535. const float* const* const,
  536. float** const,
  537. const uint32_t frames) override
  538. {
  539. // ------------------------------------------------------------------------------------------------------------
  540. // Check if active
  541. if (! pData->active)
  542. {
  543. // disable any output sound
  544. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  545. carla_zeroFloats(audioOut[i], frames);
  546. return;
  547. }
  548. // ------------------------------------------------------------------------------------------------------------
  549. // Check buffers
  550. CARLA_SAFE_ASSERT_RETURN(frames > 0,);
  551. if (pData->audioIn.count > 0)
  552. {
  553. CARLA_SAFE_ASSERT_RETURN(audioIn != nullptr,);
  554. }
  555. if (pData->audioOut.count > 0)
  556. {
  557. CARLA_SAFE_ASSERT_RETURN(audioOut != nullptr,);
  558. }
  559. // ------------------------------------------------------------------------------------------------------------
  560. // Try lock, silence otherwise
  561. if (pData->engine->isOffline())
  562. {
  563. pData->singleMutex.lock();
  564. }
  565. else if (! pData->singleMutex.tryLock())
  566. {
  567. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  568. carla_zeroFloats(audioOut[i], frames);
  569. return;
  570. }
  571. // ------------------------------------------------------------------------------------------------------------
  572. // Check if needs reset
  573. if (pData->needsReset)
  574. {
  575. // TODO
  576. }
  577. // ------------------------------------------------------------------------------------------------------------
  578. // Event Input (main port)
  579. if (pData->event.portIn != nullptr)
  580. {
  581. // TODO
  582. }
  583. // ------------------------------------------------------------------------------------------------------------
  584. // Plugin processing
  585. const EngineTimeInfo timeInfo(pData->engine->getTimeInfo());
  586. AudioUnitRenderActionFlags actionFlags = kAudioUnitRenderAction_DoNotCheckRenderArgs;
  587. AudioTimeStamp timeStamp = {};
  588. timeStamp.mFlags = kAudioTimeStampSampleTimeValid;
  589. timeStamp.mSampleTime = timeInfo.frame;
  590. const UInt32 inBusNumber = 0;
  591. {
  592. uint32_t i = 0;
  593. for (; i < pData->audioOut.count; ++i)
  594. {
  595. fAudioBufferData->mBuffers[i].mData = audioOut[i];
  596. fAudioBufferData->mBuffers[i].mDataByteSize = sizeof(float) * frames;
  597. if (audioOut[i] != audioIn[i])
  598. std::memcpy(audioOut[i], audioIn[i], sizeof(float) * frames);
  599. }
  600. for (; i < pData->audioIn.count; ++i)
  601. {
  602. fAudioBufferData->mBuffers[i].mData = audioOut[i];
  603. fAudioBufferData->mBuffers[i].mDataByteSize = sizeof(float) * frames;
  604. }
  605. }
  606. fFunctions.render(fInterface, &actionFlags, &timeStamp, inBusNumber, frames, fAudioBufferData);
  607. // ------------------------------------------------------------------------------------------------------------
  608. pData->singleMutex.unlock();
  609. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  610. // ------------------------------------------------------------------------------------------------------------
  611. // Control Output
  612. // TODO
  613. #endif
  614. // ------------------------------------------------------------------------------------------------------------
  615. // Events/MIDI Output
  616. // TODO
  617. }
  618. // ----------------------------------------------------------------------------------------------------------------
  619. protected:
  620. void handlePluginUIClosed() override
  621. {
  622. carla_stdout("CarlaPluginAU::handlePluginUIClosed()");
  623. // TODO
  624. }
  625. void handlePluginUIResized(const uint width, const uint height) override
  626. {
  627. // TODO
  628. }
  629. // -------------------------------------------------------------------
  630. public:
  631. bool init(const CarlaPluginPtr plugin,
  632. const char* const filename,
  633. const char* const label,
  634. const char* const name,
  635. const uint options)
  636. {
  637. CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr, false);
  638. // ---------------------------------------------------------------
  639. // first checks
  640. if (pData->client != nullptr)
  641. {
  642. pData->engine->setLastError("Plugin client is already registered");
  643. return false;
  644. }
  645. if (filename == nullptr || filename[0] == '\0')
  646. {
  647. pData->engine->setLastError("null filename");
  648. return false;
  649. }
  650. // ---------------------------------------------------------------
  651. // load bundle information
  652. if (! fBundleLoader.load(filename))
  653. {
  654. pData->engine->setLastError("Failed to load AU bundle executable");
  655. return false;
  656. }
  657. const CFTypeRef componentsRef = CFBundleGetValueForInfoDictionaryKey(fBundleLoader.getRef(), CFSTR("AudioComponents"));
  658. if (componentsRef == nullptr || CFGetTypeID(componentsRef) != CFArrayGetTypeID())
  659. {
  660. pData->engine->setLastError("Not an AU component");
  661. return false;
  662. }
  663. // ---------------------------------------------------------------
  664. // find binary matching requested label
  665. CFStringRef componentName;
  666. AudioComponentDescription desc = {};
  667. FactoryFn factoryFn;
  668. const CFArrayRef components = static_cast<CFArrayRef>(componentsRef);
  669. for (uint32_t c = 0, count = CFArrayGetCount(components); c < count; ++c)
  670. {
  671. // reset
  672. desc.componentType = 0;
  673. const CFTypeRef componentRef = CFArrayGetValueAtIndex(components, c);
  674. CARLA_SAFE_ASSERT_CONTINUE(componentRef != nullptr);
  675. CARLA_SAFE_ASSERT_CONTINUE(CFGetTypeID(componentRef) == CFDictionaryGetTypeID());
  676. const CFDictionaryRef component = static_cast<CFDictionaryRef>(componentRef);
  677. componentName = nullptr;
  678. CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("name"), (const void **)&componentName));
  679. CFStringRef componentFactoryFunction = nullptr;
  680. CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("factoryFunction"), (const void **)&componentFactoryFunction));
  681. CFStringRef componentType = nullptr;
  682. CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("type"), (const void **)&componentType));
  683. CARLA_SAFE_ASSERT_CONTINUE(CFStringGetLength(componentType) == 4);
  684. CFStringRef componentSubType = nullptr;
  685. CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("subtype"), (const void **)&componentSubType));
  686. CARLA_SAFE_ASSERT_CONTINUE(CFStringGetLength(componentSubType) == 4);
  687. CFStringRef componentManufacturer = nullptr;
  688. CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("manufacturer"), (const void **)&componentManufacturer));
  689. CARLA_SAFE_ASSERT_CONTINUE(CFStringGetLength(componentManufacturer) == 4);
  690. factoryFn = fBundleLoader.getSymbol<FactoryFn>(componentFactoryFunction);
  691. CARLA_SAFE_ASSERT_CONTINUE(factoryFn != nullptr);
  692. char clabel[15] = {};
  693. CFStringGetCString(componentType, clabel, 5, kCFStringEncodingASCII);
  694. CFStringGetCString(componentSubType, clabel + 5, 5, kCFStringEncodingASCII);
  695. CFStringGetCString(componentManufacturer, clabel + 10, 5, kCFStringEncodingASCII);
  696. desc.componentType = getFourCharCodeFromString(clabel);
  697. desc.componentSubType = getFourCharCodeFromString(clabel + 5);
  698. desc.componentManufacturer = getFourCharCodeFromString(clabel + 10);
  699. CARLA_SAFE_ASSERT_CONTINUE(desc.componentType != 0);
  700. CARLA_SAFE_ASSERT_CONTINUE(desc.componentSubType != 0);
  701. CARLA_SAFE_ASSERT_CONTINUE(desc.componentManufacturer != 0);
  702. clabel[4] = clabel[9] = ',';
  703. if (label == nullptr || label[0] == '\0' || std::strcmp(label, clabel) == 0)
  704. break;
  705. }
  706. if (desc.componentType == 0)
  707. {
  708. pData->engine->setLastError("Failed to find request plugin in Component bundle");
  709. return false;
  710. }
  711. // ---------------------------------------------------------------
  712. // load binary
  713. fInterface = factoryFn(&desc);
  714. if (fInterface == nullptr)
  715. {
  716. pData->engine->setLastError("Component failed to create new interface");
  717. return false;
  718. }
  719. if (! fFunctions.init(fInterface))
  720. {
  721. pData->engine->setLastError("Component does not provide all necessary functions");
  722. fInterface = nullptr;
  723. return false;
  724. }
  725. if (fInterface->Open(fInterface, (AudioUnit)(void*)0x1) != noErr)
  726. {
  727. pData->engine->setLastError("Component failed to open");
  728. fInterface->Close(fInterface);
  729. fInterface = nullptr;
  730. return false;
  731. }
  732. // ---------------------------------------------------------------
  733. // get info
  734. const CFIndex componentNameLen = CFStringGetLength(componentName);
  735. char* const nameBuffer = new char[componentNameLen + 1];
  736. if (CFStringGetCString(componentName, nameBuffer, componentNameLen + 1, kCFStringEncodingUTF8))
  737. {
  738. if (char* const sep = std::strstr(nameBuffer, ": "))
  739. {
  740. sep[0] = sep[1] = '\0';
  741. fName = sep + 2;
  742. fMaker = nameBuffer;
  743. }
  744. else
  745. {
  746. fName = nameBuffer;
  747. fMaker = nameBuffer + componentNameLen;
  748. }
  749. }
  750. fLabel = label;
  751. pData->name = pData->engine->getUniquePluginName(name != nullptr && name[0] != '\0' ? name : fName.buffer());
  752. pData->filename = carla_strdup(filename);
  753. delete[] nameBuffer;
  754. // ---------------------------------------------------------------
  755. // register client
  756. pData->client = pData->engine->addClient(plugin);
  757. if (pData->client == nullptr || ! pData->client->isOk())
  758. {
  759. pData->engine->setLastError("Failed to register plugin client");
  760. return false;
  761. }
  762. // ------------------------------------------------------------------------------------------------------------
  763. // init component
  764. {
  765. const UInt32 bufferSize = pData->engine->getBufferSize();
  766. if (fFunctions.setProperty(fInterface,
  767. kAudioUnitProperty_MaximumFramesPerSlice,
  768. kAudioUnitScope_Global,
  769. 0, &bufferSize, sizeof(bufferSize)) != noErr)
  770. {
  771. pData->engine->setLastError("Failed to set Component maximum frames per slice");
  772. return false;
  773. }
  774. }
  775. {
  776. const Float64 sampleRate = pData->engine->getSampleRate();
  777. // input scope
  778. UInt32 outDataSize = 0;
  779. Boolean outWritable = false;
  780. if (fFunctions.getPropertyInfo(fInterface,
  781. kAudioUnitProperty_ElementCount,
  782. kAudioUnitScope_Input,
  783. 0, &outDataSize, &outWritable) == noErr
  784. && outDataSize == sizeof(UInt32))
  785. {
  786. UInt32 outData = 0;
  787. if (fFunctions.getProperty(fInterface,
  788. kAudioUnitProperty_ElementCount,
  789. kAudioUnitScope_Input,
  790. 0, &outData, &outDataSize) == noErr
  791. && outData != 0)
  792. {
  793. if (fFunctions.setProperty(fInterface,
  794. kAudioUnitProperty_SampleRate,
  795. kAudioUnitScope_Input,
  796. 0, &sampleRate, sizeof(sampleRate)) != noErr)
  797. {
  798. pData->engine->setLastError("Failed to set Component input sample rate");
  799. return false;
  800. }
  801. }
  802. }
  803. // output scope
  804. outDataSize = 0;
  805. outWritable = false;
  806. if (fFunctions.getPropertyInfo(fInterface,
  807. kAudioUnitProperty_ElementCount,
  808. kAudioUnitScope_Output,
  809. 0, &outDataSize, &outWritable) == noErr
  810. && outDataSize == sizeof(UInt32))
  811. {
  812. UInt32 outData = 0;
  813. if (fFunctions.getProperty(fInterface,
  814. kAudioUnitProperty_ElementCount,
  815. kAudioUnitScope_Output,
  816. 0, &outData, &outDataSize) == noErr
  817. && outData != 0)
  818. {
  819. if (fFunctions.setProperty(fInterface,
  820. kAudioUnitProperty_SampleRate,
  821. kAudioUnitScope_Output,
  822. 0, &sampleRate, sizeof(sampleRate)) != noErr)
  823. {
  824. pData->engine->setLastError("Failed to set Component output sample rate");
  825. return false;
  826. }
  827. }
  828. }
  829. }
  830. // ------------------------------------------------------------------------------------------------------------
  831. // set default options
  832. pData->options = PLUGIN_OPTION_FIXED_BUFFERS;
  833. return true;
  834. }
  835. private:
  836. BundleLoader fBundleLoader;
  837. AudioComponentPlugInInterface* fInterface;
  838. AudioBufferList* fAudioBufferData;
  839. CarlaString fName;
  840. CarlaString fLabel;
  841. CarlaString fMaker;
  842. struct Functions {
  843. InitializeFn initialize;
  844. UninitializeFn uninitialize;
  845. GetPropertyInfoFn getPropertyInfo;
  846. GetPropertyFn getProperty;
  847. SetPropertyFn setProperty;
  848. GetParameterFn getParameter;
  849. SetParameterFn setParameter;
  850. ScheduleParametersFn scheduleParameters;
  851. ResetFn reset;
  852. RenderFn render;
  853. MIDIEventFn midiEvent;
  854. Functions()
  855. : initialize(nullptr),
  856. uninitialize(nullptr),
  857. getPropertyInfo(nullptr),
  858. getProperty(nullptr),
  859. setProperty(nullptr),
  860. getParameter(nullptr),
  861. setParameter(nullptr),
  862. scheduleParameters(nullptr),
  863. reset(nullptr),
  864. render(nullptr),
  865. midiEvent(nullptr) {}
  866. bool init(AudioComponentPlugInInterface* const interface)
  867. {
  868. initialize = (InitializeFn)interface->Lookup(kAudioUnitInitializeSelect);
  869. uninitialize = (UninitializeFn)interface->Lookup(kAudioUnitUninitializeSelect);
  870. getPropertyInfo = (GetPropertyInfoFn)interface->Lookup(kAudioUnitGetPropertyInfoSelect);
  871. getProperty = (GetPropertyFn)interface->Lookup(kAudioUnitGetPropertySelect);
  872. setProperty = (SetPropertyFn)interface->Lookup(kAudioUnitSetPropertySelect);
  873. getParameter = (GetParameterFn)interface->Lookup(kAudioUnitGetParameterSelect);
  874. setParameter = (SetParameterFn)interface->Lookup(kAudioUnitSetParameterSelect);
  875. scheduleParameters = (ScheduleParametersFn)interface->Lookup(kAudioUnitScheduleParametersSelect);
  876. reset = (ResetFn)interface->Lookup(kAudioUnitResetSelect);
  877. render = (RenderFn)interface->Lookup(kAudioUnitRenderSelect);
  878. midiEvent = (MIDIEventFn)interface->Lookup(kMusicDeviceMIDIEventSelect);
  879. return initialize != nullptr
  880. && uninitialize != nullptr
  881. && getPropertyInfo != nullptr
  882. && getProperty != nullptr
  883. && setProperty != nullptr
  884. && getParameter != nullptr
  885. && setParameter != nullptr
  886. && scheduleParameters != nullptr
  887. && render != nullptr;
  888. }
  889. } fFunctions;
  890. };
  891. #endif
  892. // --------------------------------------------------------------------------------------------------------------------
  893. CarlaPluginPtr CarlaPlugin::newAU(const Initializer& init)
  894. {
  895. carla_stdout("CarlaPlugin::newAU({%p, \"%s\", \"%s\", \"%s\", " P_INT64 "})",
  896. init.engine, init.filename, init.label, init.name, init.uniqueId);
  897. #ifdef CARLA_OS_MAC
  898. std::shared_ptr<CarlaPluginAU> plugin(new CarlaPluginAU(init.engine, init.id));
  899. if (! plugin->init(plugin, init.filename, init.label, init.name, init.options))
  900. return nullptr;
  901. return plugin;
  902. #else
  903. init.engine->setLastError("AU support not available");
  904. return nullptr;
  905. #endif
  906. }
  907. // --------------------------------------------------------------------------------------------------------------------
  908. CARLA_BACKEND_END_NAMESPACE