DISTRHO Plugin Framework
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.

3242 lines
129KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. // TODO
  17. // - g_nextBundlePath vs d_nextBundlePath cleanup
  18. // - scale points to kAudioUnitParameterFlag_ValuesHaveStrings
  19. // - report latency changes
  20. #include "DistrhoPluginInternal.hpp"
  21. #include "../DistrhoPluginUtils.hpp"
  22. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  23. # include "../extra/RingBuffer.hpp"
  24. #endif
  25. #include <AudioUnit/AudioUnit.h>
  26. #include <AudioToolbox/AudioUnitUtilities.h>
  27. #include <map>
  28. #include <vector>
  29. #ifndef DISTRHO_PLUGIN_BRAND_ID
  30. # error DISTRHO_PLUGIN_BRAND_ID undefined!
  31. #endif
  32. #ifndef DISTRHO_PLUGIN_UNIQUE_ID
  33. # error DISTRHO_PLUGIN_UNIQUE_ID undefined!
  34. #endif
  35. START_NAMESPACE_DISTRHO
  36. // --------------------------------------------------------------------------------------------------------------------
  37. #ifndef __MAC_12_3
  38. enum {
  39. kAudioUnitProperty_MIDIOutputBufferSizeHint = 66,
  40. };
  41. #endif
  42. // --------------------------------------------------------------------------------------------------------------------
  43. static const char* AudioUnitPropertyID2Str(const AudioUnitPropertyID prop) noexcept
  44. {
  45. switch (prop)
  46. {
  47. #define PROP(s) case s: return #s;
  48. PROP(kAudioUnitProperty_ClassInfo)
  49. PROP(kAudioUnitProperty_MakeConnection)
  50. PROP(kAudioUnitProperty_SampleRate)
  51. PROP(kAudioUnitProperty_ParameterList)
  52. PROP(kAudioUnitProperty_ParameterInfo)
  53. #if !TARGET_OS_IPHONE
  54. PROP(kAudioUnitProperty_FastDispatch)
  55. #endif
  56. PROP(kAudioUnitProperty_CPULoad)
  57. PROP(kAudioUnitProperty_StreamFormat)
  58. PROP(kAudioUnitProperty_ElementCount)
  59. PROP(kAudioUnitProperty_Latency)
  60. PROP(kAudioUnitProperty_SupportedNumChannels)
  61. PROP(kAudioUnitProperty_MaximumFramesPerSlice)
  62. PROP(kAudioUnitProperty_ParameterValueStrings)
  63. PROP(kAudioUnitProperty_AudioChannelLayout)
  64. PROP(kAudioUnitProperty_TailTime)
  65. PROP(kAudioUnitProperty_BypassEffect)
  66. PROP(kAudioUnitProperty_LastRenderError)
  67. PROP(kAudioUnitProperty_SetRenderCallback)
  68. PROP(kAudioUnitProperty_FactoryPresets)
  69. PROP(kAudioUnitProperty_RenderQuality)
  70. PROP(kAudioUnitProperty_HostCallbacks)
  71. PROP(kAudioUnitProperty_InPlaceProcessing)
  72. PROP(kAudioUnitProperty_ElementName)
  73. PROP(kAudioUnitProperty_SupportedChannelLayoutTags)
  74. PROP(kAudioUnitProperty_PresentPreset)
  75. PROP(kAudioUnitProperty_DependentParameters)
  76. PROP(kAudioUnitProperty_InputSamplesInOutput)
  77. PROP(kAudioUnitProperty_ShouldAllocateBuffer)
  78. PROP(kAudioUnitProperty_FrequencyResponse)
  79. PROP(kAudioUnitProperty_ParameterHistoryInfo)
  80. PROP(kAudioUnitProperty_NickName)
  81. PROP(kAudioUnitProperty_OfflineRender)
  82. PROP(kAudioUnitProperty_ParameterIDName)
  83. PROP(kAudioUnitProperty_ParameterStringFromValue)
  84. PROP(kAudioUnitProperty_ParameterClumpName)
  85. PROP(kAudioUnitProperty_ParameterValueFromString)
  86. PROP(kAudioUnitProperty_PresentationLatency)
  87. PROP(kAudioUnitProperty_ClassInfoFromDocument)
  88. PROP(kAudioUnitProperty_RequestViewController)
  89. PROP(kAudioUnitProperty_ParametersForOverview)
  90. PROP(kAudioUnitProperty_SupportsMPE)
  91. PROP(kAudioUnitProperty_RenderContextObserver)
  92. PROP(kAudioUnitProperty_LastRenderSampleTime)
  93. PROP(kAudioUnitProperty_LoadedOutOfProcess)
  94. #if !TARGET_OS_IPHONE
  95. PROP(kAudioUnitProperty_SetExternalBuffer)
  96. PROP(kAudioUnitProperty_GetUIComponentList)
  97. PROP(kAudioUnitProperty_CocoaUI)
  98. PROP(kAudioUnitProperty_IconLocation)
  99. PROP(kAudioUnitProperty_AUHostIdentifier)
  100. #endif
  101. PROP(kAudioUnitProperty_MIDIOutputCallbackInfo)
  102. PROP(kAudioUnitProperty_MIDIOutputCallback)
  103. PROP(kAudioUnitProperty_MIDIOutputEventListCallback)
  104. PROP(kAudioUnitProperty_AudioUnitMIDIProtocol)
  105. PROP(kAudioUnitProperty_HostMIDIProtocol)
  106. PROP(kAudioUnitProperty_MIDIOutputBufferSizeHint)
  107. PROP(kMusicDeviceProperty_DualSchedulingMode)
  108. #undef PROP
  109. // DPF specific properties
  110. #define PROPX(s) (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | (s[3] << 0)
  111. #define PROP(s) case PROPX(#s): return #s;
  112. PROP(DPFi)
  113. PROP(DPFe)
  114. PROP(DPFp)
  115. PROP(DPFn)
  116. PROP(DPFo)
  117. PROP(DPFl)
  118. PROP(DPFs)
  119. PROP(DPFa)
  120. #undef PROP
  121. #undef PROPX
  122. }
  123. return "[unknown]";
  124. }
  125. static const char* AudioUnitScope2Str(const AudioUnitScope scope) noexcept
  126. {
  127. switch (scope)
  128. {
  129. #define SCOPE(s) case s: return #s;
  130. SCOPE(kAudioUnitScope_Global)
  131. SCOPE(kAudioUnitScope_Input)
  132. SCOPE(kAudioUnitScope_Output)
  133. SCOPE(kAudioUnitScope_Group)
  134. SCOPE(kAudioUnitScope_Part)
  135. SCOPE(kAudioUnitScope_Note)
  136. SCOPE(kAudioUnitScope_Layer)
  137. SCOPE(kAudioUnitScope_LayerItem)
  138. #undef SCOPE
  139. }
  140. return "[unknown]";
  141. }
  142. static const char* AudioUnitSelector2Str(const SInt16 selector) noexcept
  143. {
  144. switch (selector)
  145. {
  146. #define SEL(s) case s: return #s;
  147. SEL(kAudioUnitInitializeSelect)
  148. SEL(kAudioUnitUninitializeSelect)
  149. SEL(kAudioUnitGetPropertyInfoSelect)
  150. SEL(kAudioUnitGetPropertySelect)
  151. SEL(kAudioUnitSetPropertySelect)
  152. SEL(kAudioUnitAddPropertyListenerSelect)
  153. SEL(kAudioUnitRemovePropertyListenerSelect)
  154. SEL(kAudioUnitRemovePropertyListenerWithUserDataSelect)
  155. SEL(kAudioUnitAddRenderNotifySelect)
  156. SEL(kAudioUnitRemoveRenderNotifySelect)
  157. SEL(kAudioUnitGetParameterSelect)
  158. SEL(kAudioUnitSetParameterSelect)
  159. SEL(kAudioUnitScheduleParametersSelect)
  160. SEL(kAudioUnitRenderSelect)
  161. SEL(kAudioUnitResetSelect)
  162. SEL(kAudioUnitComplexRenderSelect)
  163. SEL(kAudioUnitProcessSelect)
  164. SEL(kAudioUnitProcessMultipleSelect)
  165. SEL(kMusicDeviceMIDIEventSelect)
  166. SEL(kMusicDeviceSysExSelect)
  167. SEL(kMusicDevicePrepareInstrumentSelect)
  168. SEL(kMusicDeviceReleaseInstrumentSelect)
  169. SEL(kMusicDeviceStartNoteSelect)
  170. SEL(kMusicDeviceStopNoteSelect)
  171. SEL(kMusicDeviceMIDIEventListSelect)
  172. SEL(kAudioOutputUnitStartSelect)
  173. SEL(kAudioOutputUnitStopSelect)
  174. #undef SEL
  175. }
  176. return "[unknown]";
  177. }
  178. #if 0
  179. static OSStatus FastDispatchGetParameter(void*, AudioUnitParameterID, AudioUnitScope, AudioUnitElement, Float32*);
  180. static OSStatus FastDispatchSetParameter(void*, AudioUnitParameterID, AudioUnitScope, AudioUnitElement, Float32, UInt32);
  181. static OSStatus FastDispatchRender(void*, AudioUnitRenderActionFlags*, const AudioTimeStamp*, UInt32, UInt32, AudioBufferList*);
  182. #endif
  183. // --------------------------------------------------------------------------------------------------------------------
  184. static constexpr const uint32_t kType = d_cconst(STRINGIFY(DISTRHO_PLUGIN_AU_TYPE));
  185. static constexpr const uint32_t kSubType = d_cconst(STRINGIFY(DISTRHO_PLUGIN_UNIQUE_ID));
  186. static constexpr const uint32_t kManufacturer = d_cconst(STRINGIFY(DISTRHO_PLUGIN_BRAND_ID));
  187. static constexpr const uint32_t kWantedAudioFormat = kAudioFormatFlagsNativeFloatPacked
  188. | kAudioFormatFlagIsNonInterleaved;
  189. // --------------------------------------------------------------------------------------------------------------------
  190. // clang `std::max` is not constexpr compatible, we need to define our own
  191. template<typename T>
  192. static inline constexpr T d_max(const T a, const T b) { return a > b ? a : b; }
  193. // --------------------------------------------------------------------------------------------------------------------
  194. static constexpr const AUChannelInfo kChannelInfo[] = {
  195. { DISTRHO_PLUGIN_NUM_INPUTS, DISTRHO_PLUGIN_NUM_OUTPUTS },
  196. #ifdef DISTRHO_PLUGIN_EXTRA_IO
  197. DISTRHO_PLUGIN_EXTRA_IO
  198. #endif
  199. };
  200. #ifdef DISTRHO_PLUGIN_EXTRA_IO
  201. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS == 0
  202. #error DISTRHO_PLUGIN_EXTRA_IO defined but no IO available
  203. #endif
  204. static inline
  205. bool isInputNumChannelsValid(const uint16_t numChannels)
  206. {
  207. for (uint16_t i = 0; i < ARRAY_SIZE(kChannelInfo); ++i)
  208. {
  209. if (kChannelInfo[i].inChannels == numChannels)
  210. return true;
  211. }
  212. return false;
  213. }
  214. static inline
  215. bool isOutputNumChannelsValid(const uint16_t numChannels)
  216. {
  217. for (uint16_t i = 0; i < ARRAY_SIZE(kChannelInfo); ++i)
  218. {
  219. if (kChannelInfo[i].outChannels == numChannels)
  220. return true;
  221. }
  222. return false;
  223. }
  224. static inline
  225. bool isNumChannelsComboValid(const uint16_t numInputs, const uint16_t numOutputs)
  226. {
  227. for (uint16_t i = 0; i < ARRAY_SIZE(kChannelInfo); ++i)
  228. {
  229. if (kChannelInfo[i].inChannels == numInputs && kChannelInfo[i].outChannels == numOutputs)
  230. return true;
  231. }
  232. return false;
  233. }
  234. #endif
  235. // --------------------------------------------------------------------------------------------------------------------
  236. struct PropertyListener {
  237. AudioUnitPropertyID prop;
  238. AudioUnitPropertyListenerProc proc;
  239. void* userData;
  240. };
  241. struct RenderListener {
  242. AURenderCallback proc;
  243. void* userData;
  244. };
  245. typedef std::vector<PropertyListener> PropertyListeners;
  246. typedef std::vector<RenderListener> RenderListeners;
  247. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  248. // useful definitions
  249. static constexpr const uint32_t kMIDIPacketNonDataSize = sizeof(MIDIPacket) - sizeof(MIDIPacket::data);
  250. static constexpr const uint32_t kMIDIPacketListNonDataSize = sizeof(MIDIPacketList) - sizeof(MIDIPacketList::packet);
  251. // size of data used for midi events
  252. static constexpr const uint32_t kMIDIPacketListMaxDataSize = kMIDIPacketNonDataSize * kMaxMidiEvents
  253. + sizeof(Byte) * MidiEvent::kDataSize * kMaxMidiEvents;
  254. // size of midi list + data
  255. static constexpr const uint32_t kMIDIPacketListSize = kMIDIPacketListNonDataSize + kMIDIPacketListMaxDataSize;
  256. #endif
  257. // --------------------------------------------------------------------------------------------------------------------
  258. #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  259. static constexpr const writeMidiFunc writeMidiCallback = nullptr;
  260. #endif
  261. #if ! DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
  262. static constexpr const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr;
  263. #endif
  264. #if ! DISTRHO_PLUGIN_WANT_STATE
  265. static constexpr const updateStateValueFunc updateStateValueCallback = nullptr;
  266. #endif
  267. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  268. static constexpr const double kDefaultTicksPerBeat = 1920.0;
  269. #endif
  270. typedef std::map<const String, String> StringMap;
  271. // --------------------------------------------------------------------------------------------------------------------
  272. class PluginAU
  273. {
  274. public:
  275. PluginAU(const AudioUnit component)
  276. : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback, updateStateValueCallback),
  277. fComponent(component),
  278. fLastRenderError(noErr),
  279. fPropertyListeners(),
  280. fRenderListeners(),
  281. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  282. fInputConnectionBus(0),
  283. fInputConnectionUnit(nullptr),
  284. fSampleRateForInput(d_nextSampleRate),
  285. #ifdef DISTRHO_PLUGIN_EXTRA_IO
  286. fNumInputs(DISTRHO_PLUGIN_NUM_INPUTS),
  287. #endif
  288. #endif
  289. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  290. fSampleRateForOutput(d_nextSampleRate),
  291. #ifdef DISTRHO_PLUGIN_EXTRA_IO
  292. fNumOutputs(DISTRHO_PLUGIN_NUM_OUTPUTS),
  293. #endif
  294. #endif
  295. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  296. fAudioBufferList(nullptr),
  297. #endif
  298. fUsingRenderListeners(false),
  299. fParameterCount(fPlugin.getParameterCount()),
  300. fLastParameterValues(nullptr),
  301. fBypassParameterIndex(UINT32_MAX)
  302. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  303. , fMidiEventCount(0)
  304. #endif
  305. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  306. , fMidiOutputDataOffset(0)
  307. #endif
  308. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  309. , fCurrentProgram(-1)
  310. , fLastFactoryProgram(0)
  311. , fProgramCount(fPlugin.getProgramCount())
  312. , fFactoryPresetsData(nullptr)
  313. #endif
  314. #if DISTRHO_PLUGIN_WANT_STATE
  315. , fStateCount(fPlugin.getStateCount())
  316. #endif
  317. {
  318. if (fParameterCount != 0)
  319. {
  320. fLastParameterValues = new float[fParameterCount];
  321. std::memset(fLastParameterValues, 0, sizeof(float) * fParameterCount);
  322. for (uint32_t i=0; i<fParameterCount; ++i)
  323. {
  324. fLastParameterValues[i] = fPlugin.getParameterValue(i);
  325. if (fPlugin.getParameterDesignation(i) == kParameterDesignationBypass)
  326. fBypassParameterIndex = i;
  327. }
  328. }
  329. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  330. std::memset(&fInputRenderCallback, 0, sizeof(fInputRenderCallback));
  331. fInputRenderCallback.inputProc = nullptr;
  332. fInputRenderCallback.inputProcRefCon = nullptr;
  333. #endif
  334. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  335. std::memset(&fMidiEvents, 0, sizeof(fMidiEvents));
  336. #endif
  337. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  338. if ((fMidiOutputPackets = static_cast<MIDIPacketList*>(std::malloc(kMIDIPacketListSize))) != nullptr)
  339. std::memset(fMidiOutputPackets, 0, kMIDIPacketListSize);
  340. std::memset(&fMidiOutput, 0, sizeof(fMidiOutput));
  341. #endif
  342. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  343. if (fProgramCount != 0)
  344. {
  345. fFactoryPresetsData = new AUPreset[fProgramCount];
  346. std::memset(fFactoryPresetsData, 0, sizeof(AUPreset) * fProgramCount);
  347. for (uint32_t i=0; i<fProgramCount; ++i)
  348. {
  349. fFactoryPresetsData[i].presetNumber = i;
  350. if (const CFStringRef nameRef = CFStringCreateWithCString(nullptr,
  351. fPlugin.getProgramName(i),
  352. kCFStringEncodingUTF8))
  353. fFactoryPresetsData[i].presetName = nameRef;
  354. else
  355. fFactoryPresetsData[i].presetName = CFSTR("");
  356. }
  357. }
  358. else
  359. {
  360. fFactoryPresetsData = new AUPreset;
  361. std::memset(fFactoryPresetsData, 0, sizeof(AUPreset));
  362. fFactoryPresetsData->presetNumber = 0;
  363. fFactoryPresetsData->presetName = CFSTR("Default");
  364. }
  365. #endif
  366. fUserPresetData.presetNumber = -1;
  367. fUserPresetData.presetName = CFSTR("");
  368. #if DISTRHO_PLUGIN_WANT_STATE
  369. for (uint32_t i=0; i<fStateCount; ++i)
  370. {
  371. const String& dkey(fPlugin.getStateKey(i));
  372. fStateMap[dkey] = fPlugin.getStateDefaultValue(i);
  373. }
  374. #endif
  375. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  376. std::memset(&fHostCallbackInfo, 0, sizeof(fHostCallbackInfo));
  377. fTimePosition.bbt.ticksPerBeat = kDefaultTicksPerBeat;
  378. #endif
  379. }
  380. ~PluginAU()
  381. {
  382. delete[] fLastParameterValues;
  383. CFRelease(fUserPresetData.presetName);
  384. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  385. reallocAudioBufferList(false);
  386. #endif
  387. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  388. std::free(fMidiOutputPackets);
  389. #endif
  390. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  391. for (uint32_t i=0; i<fProgramCount; ++i)
  392. CFRelease(fFactoryPresetsData[i].presetName);
  393. delete[] fFactoryPresetsData;
  394. #endif
  395. }
  396. OSStatus auInitialize()
  397. {
  398. #if defined(DISTRHO_PLUGIN_EXTRA_IO) && DISTRHO_PLUGIN_NUM_INPUTS != 0 && DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  399. if (! isNumChannelsComboValid(fNumInputs, fNumOutputs))
  400. return kAudioUnitErr_FormatNotSupported;
  401. #endif
  402. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  403. if (! reallocAudioBufferList(true))
  404. return kAudio_ParamError;
  405. #endif
  406. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  407. fMidiEventCount = 0;
  408. #endif
  409. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  410. fMidiOutputDataOffset = 0;
  411. fMidiOutputPackets->numPackets = 0;
  412. #endif
  413. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  414. fTimePosition.clear();
  415. fTimePosition.bbt.ticksPerBeat = kDefaultTicksPerBeat;
  416. #endif
  417. fPlugin.activate();
  418. return noErr;
  419. }
  420. OSStatus auUninitialize()
  421. {
  422. fPlugin.deactivateIfNeeded();
  423. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  424. reallocAudioBufferList(false);
  425. #endif
  426. return noErr;
  427. }
  428. OSStatus auGetPropertyInfo(const AudioUnitPropertyID inProp,
  429. const AudioUnitScope inScope,
  430. const AudioUnitElement inElement,
  431. UInt32& outDataSize,
  432. Boolean& outWritable)
  433. {
  434. switch (inProp)
  435. {
  436. case kAudioUnitProperty_ClassInfo:
  437. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  438. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  439. outDataSize = sizeof(CFPropertyListRef);
  440. outWritable = true;
  441. return noErr;
  442. case kAudioUnitProperty_MakeConnection:
  443. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Input, inScope, kAudioUnitErr_InvalidScope);
  444. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  445. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  446. outDataSize = sizeof(AudioUnitConnection);
  447. outWritable = true;
  448. return noErr;
  449. #else
  450. return kAudioUnitErr_InvalidProperty;
  451. #endif
  452. case kAudioUnitProperty_SampleRate:
  453. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  454. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  455. if (inScope == kAudioUnitScope_Input)
  456. {
  457. outDataSize = sizeof(Float64);
  458. outWritable = true;
  459. return noErr;
  460. }
  461. #endif
  462. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  463. if (inScope == kAudioUnitScope_Output)
  464. {
  465. outDataSize = sizeof(Float64);
  466. outWritable = true;
  467. return noErr;
  468. }
  469. #endif
  470. return kAudioUnitErr_InvalidScope;
  471. case kAudioUnitProperty_ParameterList:
  472. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  473. outDataSize = inScope == kAudioUnitScope_Global ? sizeof(AudioUnitParameterID) * fParameterCount : 0;
  474. outWritable = false;
  475. return noErr;
  476. case kAudioUnitProperty_ParameterInfo:
  477. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  478. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement < fParameterCount, inElement, kAudioUnitErr_InvalidElement);
  479. outDataSize = sizeof(AudioUnitParameterInfo);
  480. outWritable = false;
  481. return noErr;
  482. #if 0
  483. case kAudioUnitProperty_FastDispatch:
  484. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  485. outDataSize = sizeof(void*);
  486. outWritable = false;
  487. return noErr;
  488. #endif
  489. case kAudioUnitProperty_StreamFormat:
  490. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  491. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  492. if (inScope == kAudioUnitScope_Input)
  493. {
  494. outDataSize = sizeof(AudioStreamBasicDescription);
  495. outWritable = true;
  496. return noErr;
  497. }
  498. #endif
  499. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  500. if (inScope == kAudioUnitScope_Output)
  501. {
  502. outDataSize = sizeof(AudioStreamBasicDescription);
  503. outWritable = true;
  504. return noErr;
  505. }
  506. #endif
  507. return kAudioUnitErr_InvalidScope;
  508. case kAudioUnitProperty_ElementCount:
  509. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  510. outDataSize = sizeof(UInt32);
  511. outWritable = false;
  512. return noErr;
  513. case kAudioUnitProperty_Latency:
  514. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  515. #if DISTRHO_PLUGIN_WANT_LATENCY
  516. if (inScope == kAudioUnitScope_Global)
  517. {
  518. outDataSize = sizeof(Float64);
  519. outWritable = false;
  520. return noErr;
  521. }
  522. #endif
  523. return kAudioUnitErr_InvalidProperty;
  524. case kAudioUnitProperty_SupportedNumChannels:
  525. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  526. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  527. outDataSize = sizeof(kChannelInfo);
  528. outWritable = false;
  529. return noErr;
  530. case kAudioUnitProperty_MaximumFramesPerSlice:
  531. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  532. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  533. outDataSize = sizeof(UInt32);
  534. outWritable = true;
  535. return noErr;
  536. case kAudioUnitProperty_BypassEffect:
  537. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  538. if (inScope == kAudioUnitScope_Global && fBypassParameterIndex != UINT32_MAX)
  539. {
  540. outDataSize = sizeof(UInt32);
  541. outWritable = true;
  542. return noErr;
  543. }
  544. return kAudioUnitErr_InvalidProperty;
  545. case kAudioUnitProperty_LastRenderError:
  546. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  547. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  548. outDataSize = sizeof(OSStatus);
  549. outWritable = false;
  550. return noErr;
  551. case kAudioUnitProperty_SetRenderCallback:
  552. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Input, inScope, kAudioUnitErr_InvalidScope);
  553. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  554. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  555. outDataSize = sizeof(AURenderCallbackStruct);
  556. outWritable = true;
  557. return noErr;
  558. #else
  559. return kAudioUnitErr_InvalidProperty;
  560. #endif
  561. case kAudioUnitProperty_FactoryPresets:
  562. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  563. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  564. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  565. outDataSize = sizeof(CFArrayRef);
  566. outWritable = false;
  567. return noErr;
  568. #else
  569. return kAudioUnitErr_InvalidProperty;
  570. #endif
  571. case kAudioUnitProperty_HostCallbacks:
  572. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  573. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  574. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  575. outDataSize = sizeof(HostCallbackInfo);
  576. outWritable = false;
  577. return noErr;
  578. #else
  579. return kAudioUnitErr_InvalidProperty;
  580. #endif
  581. case kAudioUnitProperty_InPlaceProcessing:
  582. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  583. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  584. #if DISTRHO_PLUGIN_NUM_INPUTS != 0 && DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  585. outDataSize = sizeof(UInt32);
  586. outWritable = false;
  587. return noErr;
  588. #else
  589. return kAudioUnitErr_InvalidProperty;
  590. #endif
  591. case kAudioUnitProperty_PresentPreset:
  592. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  593. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  594. outDataSize = sizeof(AUPreset);
  595. outWritable = true;
  596. return noErr;
  597. case kAudioUnitProperty_CocoaUI:
  598. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  599. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  600. #if DISTRHO_PLUGIN_HAS_UI
  601. outDataSize = sizeof(AudioUnitCocoaViewInfo);
  602. outWritable = false;
  603. return noErr;
  604. #else
  605. return kAudioUnitErr_InvalidProperty;
  606. #endif
  607. case kAudioUnitProperty_MIDIOutputCallbackInfo:
  608. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  609. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  610. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  611. outDataSize = sizeof(CFArrayRef);
  612. outWritable = false;
  613. return noErr;
  614. #else
  615. return kAudioUnitErr_InvalidProperty;
  616. #endif
  617. case kAudioUnitProperty_MIDIOutputCallback:
  618. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  619. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  620. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  621. outDataSize = sizeof(AUMIDIOutputCallbackStruct);
  622. outWritable = true;
  623. return noErr;
  624. #else
  625. return kAudioUnitErr_InvalidProperty;
  626. #endif
  627. case kAudioUnitProperty_AudioUnitMIDIProtocol:
  628. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  629. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  630. // FIXME implement the event list stuff
  631. #if 0 && (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT)
  632. outDataSize = sizeof(SInt32);
  633. outWritable = false;
  634. return noErr;
  635. #else
  636. return kAudioUnitErr_InvalidProperty;
  637. #endif
  638. case 'DPFi':
  639. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  640. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  641. outDataSize = sizeof(uint16_t);
  642. outWritable = false;
  643. return noErr;
  644. case 'DPFe':
  645. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  646. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement < fParameterCount, inElement, kAudioUnitErr_InvalidElement);
  647. outDataSize = sizeof(uint8_t);
  648. outWritable = true;
  649. return noErr;
  650. case 'DPFp':
  651. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  652. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement < fParameterCount, inElement, kAudioUnitErr_InvalidElement);
  653. outDataSize = sizeof(float);
  654. outWritable = true;
  655. return noErr;
  656. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  657. case 'DPFn':
  658. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  659. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  660. outDataSize = sizeof(uint8_t) * 3;
  661. outWritable = true;
  662. return noErr;
  663. #endif
  664. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  665. case 'DPFo':
  666. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  667. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  668. outDataSize = sizeof(uint32_t);
  669. outWritable = false;
  670. return noErr;
  671. #endif
  672. #if DISTRHO_PLUGIN_WANT_STATE
  673. case 'DPFl':
  674. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  675. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  676. outDataSize = sizeof(CFArrayRef);
  677. outWritable = false;
  678. return noErr;
  679. case 'DPFs':
  680. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  681. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement < fStateCount, inElement, kAudioUnitErr_InvalidElement);
  682. outDataSize = sizeof(CFStringRef);
  683. outWritable = true;
  684. return noErr;
  685. #endif
  686. #if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  687. case 'DPFa':
  688. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  689. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  690. outDataSize = sizeof(void*);
  691. outWritable = false;
  692. return noErr;
  693. #endif
  694. // unwanted properties
  695. case kAudioUnitProperty_CPULoad:
  696. case kAudioUnitProperty_RenderContextObserver:
  697. case kAudioUnitProperty_AudioChannelLayout:
  698. case kAudioUnitProperty_TailTime:
  699. case kAudioUnitProperty_SupportedChannelLayoutTags:
  700. case kMusicDeviceProperty_DualSchedulingMode:
  701. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  702. return kAudioUnitErr_InvalidProperty;
  703. }
  704. d_stdout("TODO GetPropertyInfo(%d:%x:%s, %d:%s, %d, ...)",
  705. inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement);
  706. return kAudioUnitErr_InvalidProperty;
  707. }
  708. OSStatus auGetProperty(const AudioUnitPropertyID inProp,
  709. const AudioUnitScope inScope,
  710. const AudioUnitElement inElement,
  711. void* const outData)
  712. {
  713. switch (inProp)
  714. {
  715. case kAudioUnitProperty_ClassInfo:
  716. *static_cast<CFPropertyListRef*>(outData) = retrieveClassInfo();
  717. return noErr;
  718. case kAudioUnitProperty_SampleRate:
  719. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  720. if (inScope == kAudioUnitScope_Input)
  721. {
  722. *static_cast<Float64*>(outData) = fSampleRateForInput;
  723. }
  724. else
  725. #endif
  726. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  727. if (inScope == kAudioUnitScope_Output)
  728. {
  729. *static_cast<Float64*>(outData) = fSampleRateForOutput;
  730. }
  731. else
  732. #endif
  733. {
  734. return kAudioUnitErr_InvalidScope;
  735. }
  736. return noErr;
  737. case kAudioUnitProperty_ParameterList:
  738. {
  739. AudioUnitParameterID* const paramList = static_cast<AudioUnitParameterID*>(outData);
  740. for (uint32_t i=0; i<fParameterCount; ++i)
  741. paramList[i] = i;
  742. }
  743. return noErr;
  744. case kAudioUnitProperty_ParameterInfo:
  745. {
  746. AudioUnitParameterInfo* const info = static_cast<AudioUnitParameterInfo*>(outData);
  747. std::memset(info, 0, sizeof(*info));
  748. const ParameterRanges& ranges(fPlugin.getParameterRanges(inElement));
  749. info->flags = kAudioUnitParameterFlag_IsHighResolution
  750. | kAudioUnitParameterFlag_IsReadable
  751. | kAudioUnitParameterFlag_HasCFNameString;
  752. if (fPlugin.getParameterDesignation(inElement) == kParameterDesignationBypass)
  753. {
  754. info->flags |= kAudioUnitParameterFlag_IsWritable;
  755. info->unit = kAudioUnitParameterUnit_Boolean;
  756. d_strncpy(info->name, "Bypass", sizeof(info->name));
  757. info->cfNameString = CFSTR("Bypass");
  758. }
  759. else
  760. {
  761. const uint32_t hints = fPlugin.getParameterHints(inElement);
  762. info->flags |= kAudioUnitParameterFlag_CFNameRelease;
  763. if (hints & kParameterIsOutput)
  764. {
  765. info->flags |= kAudioUnitParameterFlag_MeterReadOnly;
  766. }
  767. else
  768. {
  769. info->flags |= kAudioUnitParameterFlag_IsWritable;
  770. if ((hints & kParameterIsAutomatable) == 0x0)
  771. info->flags |= kAudioUnitParameterFlag_NonRealTime;
  772. }
  773. if (hints & kParameterIsBoolean)
  774. info->unit = kAudioUnitParameterUnit_Boolean;
  775. else if (hints & kParameterIsInteger)
  776. info->unit = kAudioUnitParameterUnit_Indexed;
  777. else
  778. info->unit = kAudioUnitParameterUnit_Generic;
  779. // | kAudioUnitParameterFlag_ValuesHaveStrings;
  780. const String& name(fPlugin.getParameterName(inElement));
  781. d_strncpy(info->name, name, sizeof(info->name));
  782. info->cfNameString = CFStringCreateWithCString(nullptr, name, kCFStringEncodingUTF8);
  783. }
  784. info->minValue = ranges.min;
  785. info->maxValue = ranges.max;
  786. info->defaultValue = ranges.def;
  787. }
  788. return noErr;
  789. #if 0
  790. case kAudioUnitProperty_FastDispatch:
  791. switch (inElement)
  792. {
  793. case kAudioUnitGetParameterSelect:
  794. *static_cast<AudioUnitGetParameterProc*>(outData) = FastDispatchGetParameter;
  795. return noErr;
  796. case kAudioUnitSetParameterSelect:
  797. *static_cast<AudioUnitSetParameterProc*>(outData) = FastDispatchSetParameter;
  798. return noErr;
  799. case kAudioUnitRenderSelect:
  800. *static_cast<AudioUnitRenderProc*>(outData) = FastDispatchRender;
  801. return noErr;
  802. }
  803. d_stdout("WIP FastDispatch(%d:%x:%s)", inElement, inElement, AudioUnitPropertyID2Str(inElement));
  804. return kAudioUnitErr_InvalidElement;
  805. #endif
  806. case kAudioUnitProperty_StreamFormat:
  807. {
  808. AudioStreamBasicDescription* const desc = static_cast<AudioStreamBasicDescription*>(outData);
  809. std::memset(desc, 0, sizeof(*desc));
  810. if (inElement != 0)
  811. return kAudioUnitErr_InvalidElement;
  812. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  813. if (inScope == kAudioUnitScope_Input)
  814. {
  815. #ifdef DISTRHO_PLUGIN_EXTRA_IO
  816. desc->mChannelsPerFrame = fNumInputs;
  817. #else
  818. desc->mChannelsPerFrame = DISTRHO_PLUGIN_NUM_INPUTS;
  819. #endif
  820. }
  821. else
  822. #endif
  823. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  824. if (inScope == kAudioUnitScope_Output)
  825. {
  826. #ifdef DISTRHO_PLUGIN_EXTRA_IO
  827. desc->mChannelsPerFrame = fNumOutputs;
  828. #else
  829. desc->mChannelsPerFrame = DISTRHO_PLUGIN_NUM_OUTPUTS;
  830. #endif
  831. }
  832. else
  833. #endif
  834. {
  835. return kAudioUnitErr_InvalidScope;
  836. }
  837. desc->mFormatID = kAudioFormatLinearPCM;
  838. desc->mFormatFlags = kWantedAudioFormat;
  839. desc->mSampleRate = fPlugin.getSampleRate();
  840. desc->mBitsPerChannel = 32;
  841. desc->mBytesPerFrame = sizeof(float);
  842. desc->mBytesPerPacket = sizeof(float);
  843. desc->mFramesPerPacket = 1;
  844. }
  845. return noErr;
  846. case kAudioUnitProperty_ElementCount:
  847. switch (inScope)
  848. {
  849. case kAudioUnitScope_Global:
  850. *static_cast<UInt32*>(outData) = 1;
  851. break;
  852. case kAudioUnitScope_Input:
  853. *static_cast<UInt32*>(outData) = DISTRHO_PLUGIN_NUM_INPUTS != 0 ? 1 : 0;
  854. break;
  855. case kAudioUnitScope_Output:
  856. *static_cast<UInt32*>(outData) = DISTRHO_PLUGIN_NUM_OUTPUTS != 0 ? 1 : 0;
  857. break;
  858. default:
  859. *static_cast<UInt32*>(outData) = 0;
  860. break;
  861. }
  862. return noErr;
  863. #if DISTRHO_PLUGIN_WANT_LATENCY
  864. case kAudioUnitProperty_Latency:
  865. *static_cast<Float64*>(outData) = static_cast<double>(fPlugin.getLatency()) / fPlugin.getSampleRate();
  866. return noErr;
  867. #endif
  868. case kAudioUnitProperty_SupportedNumChannels:
  869. std::memcpy(outData, kChannelInfo, sizeof(kChannelInfo));
  870. return noErr;
  871. case kAudioUnitProperty_MaximumFramesPerSlice:
  872. *static_cast<UInt32*>(outData) = fPlugin.getBufferSize();
  873. return noErr;
  874. case kAudioUnitProperty_LastRenderError:
  875. *static_cast<OSStatus*>(outData) = fLastRenderError;
  876. fLastRenderError = noErr;
  877. return noErr;
  878. case kAudioUnitProperty_BypassEffect:
  879. *static_cast<OSStatus*>(outData) = fPlugin.getParameterValue(fBypassParameterIndex) > 0.5f ? 1 : 0;
  880. return noErr;
  881. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  882. case kAudioUnitProperty_SetRenderCallback:
  883. std::memcpy(outData, &fInputRenderCallback, sizeof(AURenderCallbackStruct));
  884. return noErr;
  885. #endif
  886. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  887. case kAudioUnitProperty_FactoryPresets:
  888. if (const CFMutableArrayRef presetsRef = CFArrayCreateMutable(nullptr, fProgramCount, nullptr))
  889. {
  890. for (uint32_t i=0; i<fProgramCount; ++i)
  891. CFArrayAppendValue(presetsRef, &fFactoryPresetsData[i]);
  892. *static_cast<CFArrayRef*>(outData) = presetsRef;
  893. return noErr;
  894. }
  895. return kAudio_ParamError;
  896. #endif
  897. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  898. case kAudioUnitProperty_HostCallbacks:
  899. std::memcpy(outData, &fHostCallbackInfo, sizeof(HostCallbackInfo));
  900. return noErr;
  901. #endif
  902. #if DISTRHO_PLUGIN_NUM_INPUTS != 0 && DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  903. case kAudioUnitProperty_InPlaceProcessing:
  904. *static_cast<UInt32*>(outData) = 1;
  905. return noErr;
  906. #endif
  907. case kAudioUnitProperty_PresentPreset:
  908. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  909. if (fCurrentProgram >= 0)
  910. {
  911. std::memcpy(outData, &fFactoryPresetsData[fCurrentProgram], sizeof(AUPreset));
  912. }
  913. else
  914. #endif
  915. {
  916. std::memcpy(outData, &fUserPresetData, sizeof(AUPreset));
  917. }
  918. return noErr;
  919. #if DISTRHO_PLUGIN_HAS_UI
  920. case kAudioUnitProperty_CocoaUI:
  921. {
  922. AudioUnitCocoaViewInfo* const info = static_cast<AudioUnitCocoaViewInfo*>(outData);
  923. std::memset(info, 0, sizeof(*info));
  924. NSString* const bundlePathString = [[NSString alloc]
  925. initWithBytes:d_nextBundlePath
  926. length:strlen(d_nextBundlePath)
  927. encoding:NSUTF8StringEncoding];
  928. info->mCocoaAUViewBundleLocation = static_cast<CFURLRef>([[NSURL fileURLWithPath: bundlePathString] retain]);
  929. #define MACRO_STR3(a, b, c) a "_" b "_" c
  930. #define MACRO_STR2(a, b, c) MACRO_STR3(#a, #b, #c)
  931. #define MACRO_STR(a, b, c) MACRO_STR2(a, b, c)
  932. info->mCocoaAUViewClass[0] = CFSTR("CocoaAUView_" MACRO_STR(DISTRHO_PLUGIN_AU_TYPE,
  933. DISTRHO_PLUGIN_UNIQUE_ID,
  934. DISTRHO_PLUGIN_BRAND_ID));
  935. #undef MACRO_STR
  936. #undef MACRO_STR2
  937. #undef MACRO_STR3
  938. [bundlePathString release];
  939. }
  940. return noErr;
  941. #endif
  942. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  943. case kAudioUnitProperty_MIDIOutputCallbackInfo:
  944. {
  945. CFStringRef refs[1] = { CFSTR("MIDI Output") };
  946. *static_cast<CFArrayRef*>(outData) = CFArrayCreate(nullptr,
  947. reinterpret_cast<const void**>(refs),
  948. 1,
  949. &kCFTypeArrayCallBacks);
  950. }
  951. return noErr;
  952. #endif
  953. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  954. /* FIXME implement the event list stuff
  955. case kAudioUnitProperty_AudioUnitMIDIProtocol:
  956. *static_cast<SInt32*>(outData) = kMIDIProtocol_1_0;
  957. return noErr;
  958. */
  959. #endif
  960. case 'DPFp':
  961. *static_cast<float*>(outData) = fPlugin.getParameterValue(inElement);
  962. return noErr;
  963. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  964. case 'DPFo':
  965. *static_cast<uint32_t*>(outData) = fLastFactoryProgram;
  966. return noErr;
  967. #endif
  968. #if DISTRHO_PLUGIN_WANT_STATE
  969. case 'DPFl':
  970. if (const CFMutableArrayRef keysRef = CFArrayCreateMutable(nullptr,
  971. fStateCount,
  972. &kCFTypeArrayCallBacks))
  973. {
  974. for (uint32_t i=0; i<fStateCount; ++i)
  975. {
  976. const CFStringRef keyRef = CFStringCreateWithCString(nullptr,
  977. fPlugin.getStateKey(i),
  978. kCFStringEncodingASCII);
  979. CFArrayAppendValue(keysRef, keyRef);
  980. CFRelease(keyRef);
  981. }
  982. *static_cast<CFArrayRef*>(outData) = keysRef;
  983. return noErr;
  984. }
  985. return kAudio_ParamError;
  986. case 'DPFs':
  987. {
  988. const String& key(fPlugin.getStateKey(inElement));
  989. #if DISTRHO_PLUGIN_WANT_FULL_STATE
  990. fStateMap[key] = fPlugin.getStateValue(key);
  991. #endif
  992. *static_cast<CFStringRef*>(outData) = CFStringCreateWithCString(nullptr,
  993. fStateMap[key],
  994. kCFStringEncodingUTF8);
  995. }
  996. return noErr;
  997. #endif
  998. #if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  999. case 'DPFa':
  1000. *static_cast<void**>(outData) = fPlugin.getInstancePointer();
  1001. return noErr;
  1002. #endif
  1003. }
  1004. d_stdout("TODO GetProperty(%d:%x:%s, %d:%s, %d, ...)",
  1005. inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement);
  1006. return kAudioUnitErr_InvalidProperty;
  1007. }
  1008. OSStatus auSetProperty(const AudioUnitPropertyID inProp,
  1009. const AudioUnitScope inScope,
  1010. const AudioUnitElement inElement,
  1011. const void* const inData,
  1012. const UInt32 inDataSize)
  1013. {
  1014. switch (inProp)
  1015. {
  1016. case kAudioUnitProperty_ClassInfo:
  1017. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  1018. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  1019. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(CFPropertyListRef), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  1020. {
  1021. const CFPropertyListRef propList = *static_cast<const CFPropertyListRef*>(inData);
  1022. DISTRHO_SAFE_ASSERT_RETURN(CFGetTypeID(propList) == CFDictionaryGetTypeID(), kAudioUnitErr_InvalidPropertyValue);
  1023. restoreClassInfo(static_cast<CFDictionaryRef>(propList));
  1024. }
  1025. return noErr;
  1026. case kAudioUnitProperty_MakeConnection:
  1027. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Input, inScope, kAudioUnitErr_InvalidScope);
  1028. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  1029. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(AudioUnitConnection), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  1030. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  1031. {
  1032. const AudioUnitConnection conn = *static_cast<const AudioUnitConnection*>(inData);
  1033. if (conn.sourceAudioUnit == nullptr)
  1034. {
  1035. fInputConnectionBus = 0;
  1036. fInputConnectionUnit = nullptr;
  1037. return noErr;
  1038. }
  1039. AudioStreamBasicDescription desc;
  1040. std::memset(&desc, 0, sizeof(desc));
  1041. UInt32 dataSize = sizeof(AudioStreamBasicDescription);
  1042. if (AudioUnitGetProperty(conn.sourceAudioUnit,
  1043. kAudioUnitProperty_StreamFormat,
  1044. kAudioUnitScope_Output,
  1045. conn.sourceOutputNumber, &desc, &dataSize) != noErr)
  1046. return kAudioUnitErr_InvalidPropertyValue;
  1047. DISTRHO_SAFE_ASSERT_INT_RETURN(desc.mFormatID == kAudioFormatLinearPCM,
  1048. desc.mFormatID, kAudioUnitErr_FormatNotSupported);
  1049. DISTRHO_SAFE_ASSERT_INT_RETURN(desc.mBitsPerChannel == 32,
  1050. desc.mBitsPerChannel, kAudioUnitErr_FormatNotSupported);
  1051. DISTRHO_SAFE_ASSERT_INT_RETURN(desc.mBytesPerFrame == sizeof(float),
  1052. desc.mBytesPerFrame, kAudioUnitErr_FormatNotSupported);
  1053. DISTRHO_SAFE_ASSERT_INT_RETURN(desc.mBytesPerPacket == sizeof(float),
  1054. desc.mBytesPerPacket, kAudioUnitErr_FormatNotSupported);
  1055. DISTRHO_SAFE_ASSERT_INT_RETURN(desc.mFramesPerPacket == 1,
  1056. desc.mFramesPerPacket, kAudioUnitErr_FormatNotSupported);
  1057. DISTRHO_SAFE_ASSERT_INT_RETURN(desc.mFormatFlags == kWantedAudioFormat,
  1058. desc.mFormatFlags, kAudioUnitErr_FormatNotSupported);
  1059. #ifdef DISTRHO_PLUGIN_EXTRA_IO
  1060. DISTRHO_SAFE_ASSERT_UINT_RETURN(desc.mChannelsPerFrame == fNumInputs,
  1061. desc.mChannelsPerFrame, kAudioUnitErr_FormatNotSupported);
  1062. #else
  1063. DISTRHO_SAFE_ASSERT_UINT_RETURN(desc.mChannelsPerFrame == DISTRHO_PLUGIN_NUM_INPUTS,
  1064. desc.mChannelsPerFrame, kAudioUnitErr_FormatNotSupported);
  1065. #endif
  1066. fInputConnectionBus = conn.sourceOutputNumber;
  1067. fInputConnectionUnit = conn.sourceAudioUnit;
  1068. }
  1069. return noErr;
  1070. #else
  1071. return kAudioUnitErr_PropertyNotInUse;
  1072. #endif
  1073. case kAudioUnitProperty_SampleRate:
  1074. #if DISTRHO_PLUGIN_NUM_INPUTS != 0 && DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1075. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Output, inScope, kAudioUnitErr_InvalidScope);
  1076. #elif DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1077. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Output, inScope, kAudioUnitErr_InvalidScope);
  1078. #else
  1079. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Input, inScope, kAudioUnitErr_InvalidScope);
  1080. #endif
  1081. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  1082. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(Float64), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  1083. {
  1084. #if DISTRHO_PLUGIN_NUM_INPUTS != 0 || DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1085. const Float64 sampleRate = *static_cast<const Float64*>(inData);
  1086. #endif
  1087. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  1088. if (inScope == kAudioUnitScope_Input)
  1089. {
  1090. if (d_isNotEqual(fSampleRateForInput, sampleRate))
  1091. {
  1092. fSampleRateForInput = sampleRate;
  1093. d_nextSampleRate = sampleRate;
  1094. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1095. if (d_isEqual(fSampleRateForOutput, sampleRate))
  1096. #endif
  1097. {
  1098. fPlugin.setSampleRate(sampleRate, true);
  1099. }
  1100. notifyPropertyListeners(inProp, inScope, inElement);
  1101. }
  1102. return noErr;
  1103. }
  1104. #endif
  1105. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1106. if (inScope == kAudioUnitScope_Output)
  1107. {
  1108. if (d_isNotEqual(fSampleRateForOutput, sampleRate))
  1109. {
  1110. fSampleRateForOutput = sampleRate;
  1111. d_nextSampleRate = sampleRate;
  1112. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  1113. if (d_isEqual(fSampleRateForInput, sampleRate))
  1114. #endif
  1115. {
  1116. fPlugin.setSampleRate(sampleRate, true);
  1117. }
  1118. notifyPropertyListeners(inProp, inScope, inElement);
  1119. }
  1120. return noErr;
  1121. }
  1122. #endif
  1123. }
  1124. return kAudioUnitErr_PropertyNotInUse;
  1125. case kAudioUnitProperty_StreamFormat:
  1126. #if DISTRHO_PLUGIN_NUM_INPUTS != 0 && DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1127. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Output, inScope, kAudioUnitErr_InvalidScope);
  1128. #elif DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1129. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Output, inScope, kAudioUnitErr_InvalidScope);
  1130. #else
  1131. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Input, inScope, kAudioUnitErr_InvalidScope);
  1132. #endif
  1133. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  1134. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(AudioStreamBasicDescription), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  1135. {
  1136. const AudioStreamBasicDescription* const desc = static_cast<const AudioStreamBasicDescription*>(inData);
  1137. if (desc->mFormatID != kAudioFormatLinearPCM)
  1138. return kAudioUnitErr_FormatNotSupported;
  1139. if (desc->mBitsPerChannel != 32)
  1140. return kAudioUnitErr_FormatNotSupported;
  1141. if (desc->mBytesPerFrame != sizeof(float))
  1142. return kAudioUnitErr_FormatNotSupported;
  1143. if (desc->mBytesPerPacket != sizeof(float))
  1144. return kAudioUnitErr_FormatNotSupported;
  1145. if (desc->mFramesPerPacket != 1)
  1146. return kAudioUnitErr_FormatNotSupported;
  1147. if (desc->mFormatFlags != kWantedAudioFormat)
  1148. return kAudioUnitErr_FormatNotSupported;
  1149. #ifndef DISTRHO_PLUGIN_EXTRA_IO
  1150. if (desc->mChannelsPerFrame != (inScope == kAudioUnitScope_Input ? DISTRHO_PLUGIN_NUM_INPUTS
  1151. : DISTRHO_PLUGIN_NUM_OUTPUTS))
  1152. return kAudioUnitErr_FormatNotSupported;
  1153. #endif
  1154. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  1155. if (inScope == kAudioUnitScope_Input)
  1156. {
  1157. bool changed = false;
  1158. #ifdef DISTRHO_PLUGIN_EXTRA_IO
  1159. if (! isInputNumChannelsValid(desc->mChannelsPerFrame))
  1160. return kAudioUnitErr_FormatNotSupported;
  1161. if (fNumInputs != desc->mChannelsPerFrame)
  1162. {
  1163. changed = true;
  1164. fNumInputs = desc->mChannelsPerFrame;
  1165. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1166. if (isNumChannelsComboValid(fNumInputs, fNumOutputs))
  1167. #endif
  1168. {
  1169. fPlugin.setAudioPortIO(fNumInputs, fNumOutputs);
  1170. }
  1171. }
  1172. #endif
  1173. if (d_isNotEqual(fSampleRateForInput, desc->mSampleRate))
  1174. {
  1175. changed = true;
  1176. fSampleRateForInput = desc->mSampleRate;
  1177. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1178. if (d_isEqual(fSampleRateForOutput, desc->mSampleRate))
  1179. #endif
  1180. {
  1181. fPlugin.setSampleRate(desc->mSampleRate, true);
  1182. }
  1183. notifyPropertyListeners(kAudioUnitProperty_SampleRate, inScope, inElement);
  1184. }
  1185. if (changed)
  1186. notifyPropertyListeners(inProp, inScope, inElement);
  1187. return noErr;
  1188. }
  1189. #endif
  1190. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1191. if (inScope == kAudioUnitScope_Output)
  1192. {
  1193. bool changed = false;
  1194. #ifdef DISTRHO_PLUGIN_EXTRA_IO
  1195. if (! isOutputNumChannelsValid(desc->mChannelsPerFrame))
  1196. return kAudioUnitErr_FormatNotSupported;
  1197. if (fNumOutputs != desc->mChannelsPerFrame)
  1198. {
  1199. changed = true;
  1200. fNumOutputs = desc->mChannelsPerFrame;
  1201. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  1202. if (isNumChannelsComboValid(fNumInputs, fNumOutputs))
  1203. #endif
  1204. {
  1205. fPlugin.setAudioPortIO(fNumInputs, fNumOutputs);
  1206. }
  1207. }
  1208. #endif
  1209. if (d_isNotEqual(fSampleRateForOutput, desc->mSampleRate))
  1210. {
  1211. changed = true;
  1212. fSampleRateForOutput = desc->mSampleRate;
  1213. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  1214. if (d_isEqual(fSampleRateForInput, desc->mSampleRate))
  1215. #endif
  1216. {
  1217. fPlugin.setSampleRate(desc->mSampleRate, true);
  1218. }
  1219. notifyPropertyListeners(kAudioUnitProperty_SampleRate, inScope, inElement);
  1220. }
  1221. if (changed)
  1222. notifyPropertyListeners(inProp, inScope, inElement);
  1223. return noErr;
  1224. }
  1225. #endif
  1226. }
  1227. return kAudioUnitErr_PropertyNotInUse;
  1228. case kAudioUnitProperty_MaximumFramesPerSlice:
  1229. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  1230. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  1231. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(UInt32), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  1232. {
  1233. const UInt32 bufferSize = *static_cast<const UInt32*>(inData);
  1234. if (fPlugin.setBufferSize(bufferSize, true))
  1235. notifyPropertyListeners(inProp, inScope, inElement);
  1236. }
  1237. return noErr;
  1238. case kAudioUnitProperty_BypassEffect:
  1239. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  1240. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  1241. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(UInt32), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  1242. DISTRHO_SAFE_ASSERT_RETURN(fBypassParameterIndex != UINT32_MAX, kAudioUnitErr_PropertyNotInUse);
  1243. {
  1244. const bool bypass = *static_cast<const UInt32*>(inData) != 0;
  1245. if ((fLastParameterValues[fBypassParameterIndex] > 0.5f) != bypass)
  1246. {
  1247. const float value = bypass ? 1.f : 0.f;
  1248. fLastParameterValues[fBypassParameterIndex] = value;
  1249. fPlugin.setParameterValue(fBypassParameterIndex, value);
  1250. notifyPropertyListeners(inProp, inScope, inElement);
  1251. }
  1252. }
  1253. return noErr;
  1254. case kAudioUnitProperty_SetRenderCallback:
  1255. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Input, inScope, kAudioUnitErr_InvalidScope);
  1256. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  1257. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(AURenderCallbackStruct), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  1258. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  1259. std::memcpy(&fInputRenderCallback, inData, sizeof(AURenderCallbackStruct));
  1260. return noErr;
  1261. #else
  1262. return kAudioUnitErr_PropertyNotInUse;
  1263. #endif
  1264. case kAudioUnitProperty_HostCallbacks:
  1265. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  1266. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  1267. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  1268. {
  1269. const UInt32 usableDataSize = std::min(inDataSize, static_cast<UInt32>(sizeof(HostCallbackInfo)));
  1270. const bool changed = std::memcmp(&fHostCallbackInfo, inData, usableDataSize) != 0;
  1271. std::memcpy(&fHostCallbackInfo, inData, usableDataSize);
  1272. if (sizeof(HostCallbackInfo) > usableDataSize)
  1273. std::memset(&fHostCallbackInfo + usableDataSize, 0, sizeof(HostCallbackInfo) - usableDataSize);
  1274. if (changed)
  1275. notifyPropertyListeners(inProp, inScope, inElement);
  1276. }
  1277. return noErr;
  1278. #else
  1279. return kAudioUnitErr_PropertyNotInUse;
  1280. #endif
  1281. case kAudioUnitProperty_InPlaceProcessing:
  1282. // nothing to do
  1283. return noErr;
  1284. case kAudioUnitProperty_PresentPreset:
  1285. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  1286. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  1287. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(AUPreset), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  1288. {
  1289. const int32_t presetNumber = static_cast<const AUPreset*>(inData)->presetNumber;
  1290. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  1291. if (presetNumber >= 0)
  1292. {
  1293. if (fCurrentProgram != presetNumber)
  1294. {
  1295. fCurrentProgram = presetNumber;
  1296. fLastFactoryProgram = presetNumber;
  1297. fPlugin.loadProgram(fLastFactoryProgram);
  1298. notifyPropertyListeners('DPFo', kAudioUnitScope_Global, 0);
  1299. }
  1300. }
  1301. else
  1302. {
  1303. fCurrentProgram = presetNumber;
  1304. CFRelease(fUserPresetData.presetName);
  1305. std::memcpy(&fUserPresetData, inData, sizeof(AUPreset));
  1306. }
  1307. #else
  1308. DISTRHO_SAFE_ASSERT_INT_RETURN(presetNumber < 0, presetNumber, kAudioUnitErr_InvalidPropertyValue);
  1309. CFRelease(fUserPresetData.presetName);
  1310. std::memcpy(&fUserPresetData, inData, sizeof(AUPreset));
  1311. #endif
  1312. }
  1313. return noErr;
  1314. case kAudioUnitProperty_MIDIOutputCallback:
  1315. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  1316. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  1317. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(AUMIDIOutputCallbackStruct), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  1318. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  1319. std::memcpy(&fMidiOutput, inData, sizeof(AUMIDIOutputCallbackStruct));
  1320. return noErr;
  1321. #else
  1322. return kAudioUnitErr_PropertyNotInUse;
  1323. #endif
  1324. case 'DPFi':
  1325. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  1326. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  1327. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(uint16_t), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  1328. {
  1329. const uint16_t magic = *static_cast<const uint16_t*>(inData);
  1330. if (magic != 1337)
  1331. return noErr;
  1332. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  1333. notifyPropertyListeners('DPFo', kAudioUnitScope_Global, 0);
  1334. #endif
  1335. #if DISTRHO_PLUGIN_WANT_STATE
  1336. for (uint32_t i=0; i<fStateCount; ++i)
  1337. notifyPropertyListeners('DPFs', kAudioUnitScope_Global, i);
  1338. #endif
  1339. for (uint32_t i=0; i<fParameterCount; ++i)
  1340. notifyPropertyListeners('DPFp', kAudioUnitScope_Global, i);
  1341. }
  1342. return noErr;
  1343. case 'DPFe':
  1344. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  1345. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement < fParameterCount, inElement, kAudioUnitErr_InvalidElement);
  1346. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(uint8_t), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  1347. {
  1348. const uint8_t flag = *static_cast<const uint8_t*>(inData);
  1349. if (flag != 1 && flag != 2)
  1350. return noErr;
  1351. AudioUnitEvent event;
  1352. std::memset(&event, 0, sizeof(event));
  1353. event.mEventType = flag == 1 ? kAudioUnitEvent_BeginParameterChangeGesture
  1354. : kAudioUnitEvent_EndParameterChangeGesture;
  1355. event.mArgument.mParameter.mAudioUnit = fComponent;
  1356. event.mArgument.mParameter.mParameterID = inElement;
  1357. event.mArgument.mParameter.mScope = kAudioUnitScope_Global;
  1358. AUEventListenerNotify(NULL, NULL, &event);
  1359. }
  1360. return noErr;
  1361. case 'DPFp':
  1362. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  1363. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement < fParameterCount, inElement, kAudioUnitErr_InvalidElement);
  1364. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(float), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  1365. {
  1366. const float value = *static_cast<const float*>(inData);
  1367. DISTRHO_SAFE_ASSERT_RETURN(std::isfinite(value), kAudioUnitErr_InvalidParameterValue);
  1368. if (d_isEqual(fLastParameterValues[inElement], value))
  1369. return noErr;
  1370. fLastParameterValues[inElement] = value;
  1371. fPlugin.setParameterValue(inElement, value);
  1372. AudioUnitEvent event;
  1373. std::memset(&event, 0, sizeof(event));
  1374. event.mEventType = kAudioUnitEvent_ParameterValueChange;
  1375. event.mArgument.mParameter.mAudioUnit = fComponent;
  1376. event.mArgument.mParameter.mParameterID = inElement;
  1377. event.mArgument.mParameter.mScope = kAudioUnitScope_Global;
  1378. AUEventListenerNotify(NULL, NULL, &event);
  1379. if (fBypassParameterIndex == inElement)
  1380. notifyPropertyListeners(kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0);
  1381. }
  1382. return noErr;
  1383. case 'DPFn':
  1384. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  1385. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  1386. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(uint8_t) * 3, inDataSize, kAudioUnitErr_InvalidPropertyValue);
  1387. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1388. {
  1389. const uint8_t* const midiData = static_cast<const uint8_t*>(inData);
  1390. if (midiData[0] == 0)
  1391. return noErr;
  1392. fNotesRingBuffer.writeCustomData(midiData, 3);
  1393. fNotesRingBuffer.commitWrite();
  1394. }
  1395. return noErr;
  1396. #else
  1397. return kAudioUnitErr_PropertyNotInUse;
  1398. #endif
  1399. case 'DPFs':
  1400. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  1401. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(CFStringRef), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  1402. #if DISTRHO_PLUGIN_WANT_STATE
  1403. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement < fStateCount, inElement, kAudioUnitErr_InvalidElement);
  1404. {
  1405. const CFStringRef valueRef = *static_cast<const CFStringRef*>(inData);
  1406. DISTRHO_SAFE_ASSERT_RETURN(valueRef != nullptr && CFGetTypeID(valueRef) == CFStringGetTypeID(),
  1407. kAudioUnitErr_InvalidPropertyValue);
  1408. const CFIndex valueLen = CFStringGetLength(valueRef);
  1409. char* const value = static_cast<char*>(std::malloc(valueLen + 1));
  1410. DISTRHO_SAFE_ASSERT_RETURN(value != nullptr, kAudio_ParamError);
  1411. DISTRHO_SAFE_ASSERT_RETURN(CFStringGetCString(valueRef, value, valueLen + 1, kCFStringEncodingUTF8),
  1412. kAudioUnitErr_InvalidPropertyValue);
  1413. const String& key(fPlugin.getStateKey(inElement));
  1414. // save this key as needed
  1415. if (fPlugin.wantStateKey(key))
  1416. fStateMap[key] = value;
  1417. fPlugin.setState(key, value);
  1418. std::free(value);
  1419. }
  1420. return noErr;
  1421. #else
  1422. return kAudioUnitErr_PropertyNotInUse;
  1423. #endif
  1424. // unwanted properties
  1425. case kMusicDeviceProperty_DualSchedulingMode:
  1426. return kAudioUnitErr_PropertyNotInUse;
  1427. }
  1428. d_stdout("TODO SetProperty(%d:%x:%s, %d:%s, %d, %p, %u)",
  1429. inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement, inData, inDataSize);
  1430. return kAudioUnitErr_InvalidProperty;
  1431. }
  1432. OSStatus auAddPropertyListener(const AudioUnitPropertyID prop,
  1433. const AudioUnitPropertyListenerProc proc,
  1434. void* const userData)
  1435. {
  1436. const PropertyListener pl = {
  1437. prop, proc, userData
  1438. };
  1439. fPropertyListeners.push_back(pl);
  1440. return noErr;
  1441. }
  1442. OSStatus auRemovePropertyListener(const AudioUnitPropertyID prop, const AudioUnitPropertyListenerProc proc)
  1443. {
  1444. for (PropertyListeners::iterator it = fPropertyListeners.begin(); it != fPropertyListeners.end(); ++it)
  1445. {
  1446. const PropertyListener& pl(*it);
  1447. if (pl.prop == prop && pl.proc == proc)
  1448. {
  1449. fPropertyListeners.erase(it);
  1450. return auRemovePropertyListener(prop, proc);
  1451. }
  1452. }
  1453. return noErr;
  1454. }
  1455. OSStatus auRemovePropertyListenerWithUserData(const AudioUnitPropertyID prop,
  1456. const AudioUnitPropertyListenerProc proc,
  1457. void* const userData)
  1458. {
  1459. for (PropertyListeners::iterator it = fPropertyListeners.begin(); it != fPropertyListeners.end(); ++it)
  1460. {
  1461. const PropertyListener& pl(*it);
  1462. if (pl.prop == prop && pl.proc == proc && pl.userData == userData)
  1463. {
  1464. fPropertyListeners.erase(it);
  1465. return auRemovePropertyListenerWithUserData(prop, proc, userData);
  1466. }
  1467. }
  1468. return noErr;
  1469. }
  1470. OSStatus auAddRenderNotify(const AURenderCallback proc, void* const userData)
  1471. {
  1472. fUsingRenderListeners = true;
  1473. const RenderListener rl = {
  1474. proc, userData
  1475. };
  1476. fRenderListeners.push_back(rl);
  1477. return noErr;
  1478. }
  1479. OSStatus auRemoveRenderNotify(const AURenderCallback proc, void* const userData)
  1480. {
  1481. for (RenderListeners::iterator it = fRenderListeners.begin(); it != fRenderListeners.end(); ++it)
  1482. {
  1483. const RenderListener& rl(*it);
  1484. if (rl.proc == proc && rl.userData == userData)
  1485. {
  1486. fRenderListeners.erase(it);
  1487. return auRemoveRenderNotify(proc, userData);
  1488. }
  1489. }
  1490. if (fRenderListeners.empty())
  1491. fUsingRenderListeners = false;
  1492. return noErr;
  1493. }
  1494. OSStatus auGetParameter(const AudioUnitParameterID param,
  1495. const AudioUnitScope scope,
  1496. const AudioUnitElement elem,
  1497. AudioUnitParameterValue* const value)
  1498. {
  1499. DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global, scope, kAudioUnitErr_InvalidScope);
  1500. DISTRHO_SAFE_ASSERT_UINT_RETURN(param < fParameterCount, param, kAudioUnitErr_InvalidElement);
  1501. DISTRHO_SAFE_ASSERT_UINT_RETURN(elem == 0, elem, kAudioUnitErr_InvalidElement);
  1502. DISTRHO_SAFE_ASSERT_RETURN(value != nullptr, kAudio_ParamError);
  1503. *value = fPlugin.getParameterValue(param);
  1504. return noErr;
  1505. }
  1506. OSStatus auSetParameter(const AudioUnitParameterID param,
  1507. const AudioUnitScope scope,
  1508. const AudioUnitElement elem,
  1509. const AudioUnitParameterValue value,
  1510. UInt32 /* bufferOffset */)
  1511. {
  1512. DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global, scope, kAudioUnitErr_InvalidScope);
  1513. DISTRHO_SAFE_ASSERT_UINT_RETURN(param < fParameterCount, param, kAudioUnitErr_InvalidElement);
  1514. DISTRHO_SAFE_ASSERT_UINT_RETURN(elem == 0, elem, kAudioUnitErr_InvalidElement);
  1515. DISTRHO_SAFE_ASSERT_RETURN(std::isfinite(value), kAudioUnitErr_InvalidParameterValue);
  1516. if (d_isNotEqual(fLastParameterValues[param], value))
  1517. {
  1518. fLastParameterValues[param] = value;
  1519. fPlugin.setParameterValue(param, value);
  1520. // TODO flag param only, notify listeners later on bg thread (sem_post etc)
  1521. notifyPropertyListeners('DPFp', kAudioUnitScope_Global, param);
  1522. if (fBypassParameterIndex == elem)
  1523. notifyPropertyListeners(kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0);
  1524. }
  1525. return noErr;
  1526. }
  1527. OSStatus auScheduleParameters(const AudioUnitParameterEvent* const events, const UInt32 numEvents)
  1528. {
  1529. for (UInt32 i=0; i<numEvents; ++i)
  1530. {
  1531. const AudioUnitParameterEvent& event(events[i]);
  1532. if (event.eventType == kParameterEvent_Immediate)
  1533. {
  1534. auSetParameter(event.parameter,
  1535. event.scope,
  1536. event.element,
  1537. event.eventValues.immediate.value,
  1538. event.eventValues.immediate.bufferOffset);
  1539. }
  1540. else
  1541. {
  1542. // TODO?
  1543. d_stdout("WIP ScheduleParameters(%p, %u)", events, numEvents);
  1544. }
  1545. }
  1546. return noErr;
  1547. }
  1548. OSStatus auReset(const AudioUnitScope scope, const AudioUnitElement elem)
  1549. {
  1550. DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global || scope == kAudioUnitScope_Input || scope == kAudioUnitScope_Output, scope, kAudioUnitErr_InvalidScope);
  1551. DISTRHO_SAFE_ASSERT_UINT_RETURN(elem == 0, elem, kAudioUnitErr_InvalidElement);
  1552. if (fPlugin.isActive())
  1553. {
  1554. fPlugin.deactivate();
  1555. fPlugin.activate();
  1556. }
  1557. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1558. fMidiEventCount = 0;
  1559. #endif
  1560. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  1561. fMidiOutputDataOffset = 0;
  1562. fMidiOutputPackets->numPackets = 0;
  1563. #endif
  1564. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  1565. fTimePosition.clear();
  1566. fTimePosition.bbt.ticksPerBeat = kDefaultTicksPerBeat;
  1567. #endif
  1568. return noErr;
  1569. }
  1570. OSStatus auRender(const AudioUnitRenderActionFlags actionFlags,
  1571. const AudioTimeStamp* const inTimeStamp,
  1572. const UInt32 inBusNumber,
  1573. const UInt32 inFramesToProcess,
  1574. AudioBufferList* const ioData)
  1575. {
  1576. if ((actionFlags & kAudioUnitRenderAction_DoNotCheckRenderArgs) == 0x0)
  1577. {
  1578. DISTRHO_SAFE_ASSERT_RETURN(fPlugin.isActive(), kAudio_ParamError);
  1579. DISTRHO_SAFE_ASSERT_UINT_RETURN(inBusNumber == 0, inBusNumber, kAudioUnitErr_InvalidElement);
  1580. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1581. DISTRHO_SAFE_ASSERT_UINT_RETURN(ioData->mNumberBuffers == fAudioBufferList->mNumberBuffers,
  1582. ioData->mNumberBuffers, kAudio_ParamError);
  1583. #else
  1584. DISTRHO_SAFE_ASSERT_UINT_RETURN(ioData->mNumberBuffers == 0, ioData->mNumberBuffers, kAudio_ParamError);
  1585. #endif
  1586. if (inFramesToProcess > fPlugin.getBufferSize())
  1587. {
  1588. setLastRenderError(kAudioUnitErr_TooManyFramesToProcess);
  1589. return kAudioUnitErr_TooManyFramesToProcess;
  1590. }
  1591. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1592. for (uint16_t i = 0; i < ioData->mNumberBuffers; ++i)
  1593. {
  1594. if (ioData->mBuffers[i].mDataByteSize != sizeof(float) * inFramesToProcess)
  1595. {
  1596. setLastRenderError(kAudio_ParamError);
  1597. return kAudio_ParamError;
  1598. }
  1599. }
  1600. #endif
  1601. }
  1602. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  1603. #ifdef DISTRHO_PLUGIN_EXTRA_IO
  1604. const uint32_t numInputs = fNumInputs;
  1605. #else
  1606. constexpr const uint32_t numInputs = DISTRHO_PLUGIN_NUM_INPUTS;
  1607. #endif
  1608. const float* inputs[numInputs];
  1609. #else
  1610. constexpr const float** inputs = nullptr;
  1611. #endif
  1612. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1613. #ifdef DISTRHO_PLUGIN_EXTRA_IO
  1614. const uint32_t numOutputs = fNumOutputs;
  1615. #else
  1616. constexpr const uint32_t numOutputs = DISTRHO_PLUGIN_NUM_OUTPUTS;
  1617. #endif
  1618. float* outputs[numOutputs];
  1619. #else
  1620. constexpr float** outputs = nullptr;
  1621. #endif
  1622. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  1623. if (fInputConnectionUnit != nullptr)
  1624. {
  1625. AudioUnitRenderActionFlags ioActionFlags = 0;
  1626. const OSStatus err = AudioUnitRender(fInputConnectionUnit,
  1627. &ioActionFlags,
  1628. inTimeStamp,
  1629. fInputConnectionBus,
  1630. inFramesToProcess,
  1631. fAudioBufferList);
  1632. if (err != noErr)
  1633. {
  1634. setLastRenderError(err);
  1635. return err;
  1636. }
  1637. for (uint16_t i = 0; i < numInputs; ++i)
  1638. inputs[i] = static_cast<const float*>(fAudioBufferList->mBuffers[i].mData);
  1639. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1640. for (uint16_t i = 0; i < numOutputs; ++i)
  1641. {
  1642. if (ioData->mBuffers[i].mData == nullptr)
  1643. ioData->mBuffers[i].mData = fAudioBufferList->mBuffers[i].mData;
  1644. outputs[i] = static_cast<float*>(ioData->mBuffers[i].mData);
  1645. }
  1646. #endif
  1647. }
  1648. else if (fInputRenderCallback.inputProc != nullptr)
  1649. {
  1650. bool adjustDataByteSize, usingHostBuffer = true;
  1651. UInt32 prevDataByteSize;
  1652. for (uint16_t i = 0; i < ioData->mNumberBuffers; ++i)
  1653. {
  1654. if (ioData->mBuffers[i].mData == nullptr)
  1655. {
  1656. usingHostBuffer = false;
  1657. ioData->mBuffers[i].mData = fAudioBufferList->mBuffers[i].mData;
  1658. }
  1659. }
  1660. if (! usingHostBuffer)
  1661. {
  1662. prevDataByteSize = fAudioBufferList->mBuffers[0].mDataByteSize;
  1663. adjustDataByteSize = prevDataByteSize != sizeof(float) * inFramesToProcess;
  1664. if (adjustDataByteSize)
  1665. {
  1666. for (uint16_t i = 0; i < ioData->mNumberBuffers; ++i)
  1667. fAudioBufferList->mBuffers[i].mDataByteSize = sizeof(float) * inFramesToProcess;
  1668. }
  1669. }
  1670. else
  1671. {
  1672. adjustDataByteSize = false;
  1673. }
  1674. AudioUnitRenderActionFlags rActionFlags = 0;
  1675. AudioBufferList* const rData = usingHostBuffer ? ioData : fAudioBufferList;
  1676. const OSStatus err = fInputRenderCallback.inputProc(fInputRenderCallback.inputProcRefCon,
  1677. &rActionFlags,
  1678. inTimeStamp,
  1679. inBusNumber,
  1680. inFramesToProcess,
  1681. rData);
  1682. if (err != noErr)
  1683. {
  1684. if (adjustDataByteSize)
  1685. {
  1686. for (uint16_t i = 0; i < ioData->mNumberBuffers; ++i)
  1687. fAudioBufferList->mBuffers[i].mDataByteSize = prevDataByteSize;
  1688. }
  1689. setLastRenderError(err);
  1690. return err;
  1691. }
  1692. if (usingHostBuffer)
  1693. {
  1694. for (uint16_t i = 0; i < numInputs; ++i)
  1695. inputs[i] = static_cast<const float*>(ioData->mBuffers[i].mData);
  1696. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1697. for (uint16_t i = 0; i < numOutputs; ++i)
  1698. outputs[i] = static_cast<float*>(ioData->mBuffers[i].mData);
  1699. #endif
  1700. }
  1701. else
  1702. {
  1703. for (uint16_t i = 0; i < numInputs; ++i)
  1704. inputs[i] = static_cast<const float*>(fAudioBufferList->mBuffers[i].mData);
  1705. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1706. for (uint16_t i = 0; i < numOutputs; ++i)
  1707. outputs[i] = static_cast<float*>(ioData->mBuffers[i].mData);
  1708. #endif
  1709. }
  1710. }
  1711. else
  1712. #endif // DISTRHO_PLUGIN_NUM_INPUTS != 0
  1713. {
  1714. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  1715. for (uint16_t i = 0; i < numInputs; ++i)
  1716. {
  1717. if (ioData->mBuffers[i].mData == nullptr)
  1718. {
  1719. ioData->mBuffers[i].mData = fAudioBufferList->mBuffers[i].mData;
  1720. std::memset(ioData->mBuffers[i].mData, 0, sizeof(float) * inFramesToProcess);
  1721. }
  1722. inputs[i] = static_cast<const float*>(ioData->mBuffers[i].mData);
  1723. }
  1724. #endif
  1725. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1726. for (uint16_t i = 0; i < numOutputs; ++i)
  1727. {
  1728. if (ioData->mBuffers[i].mData == nullptr)
  1729. ioData->mBuffers[i].mData = fAudioBufferList->mBuffers[i].mData;
  1730. outputs[i] = static_cast<float*>(ioData->mBuffers[i].mData);
  1731. }
  1732. #endif
  1733. }
  1734. if (fUsingRenderListeners)
  1735. {
  1736. AudioUnitRenderActionFlags ioActionFlags = actionFlags | kAudioUnitRenderAction_PreRender;
  1737. notifyRenderListeners(&ioActionFlags, inTimeStamp, inBusNumber, inFramesToProcess, ioData);
  1738. }
  1739. run(inputs, outputs, inFramesToProcess, inTimeStamp);
  1740. if (fUsingRenderListeners)
  1741. {
  1742. AudioUnitRenderActionFlags ioActionFlags = actionFlags | kAudioUnitRenderAction_PostRender;
  1743. notifyRenderListeners(&ioActionFlags, inTimeStamp, inBusNumber, inFramesToProcess, ioData);
  1744. }
  1745. return noErr;
  1746. }
  1747. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1748. OSStatus auMIDIEvent(const UInt32 inStatus,
  1749. const UInt32 inData1,
  1750. const UInt32 inData2,
  1751. const UInt32 inOffsetSampleFrame)
  1752. {
  1753. if (fMidiEventCount >= kMaxMidiEvents)
  1754. return noErr;
  1755. MidiEvent& midiEvent(fMidiEvents[fMidiEventCount++]);
  1756. midiEvent.frame = inOffsetSampleFrame;
  1757. midiEvent.data[0] = inStatus;
  1758. midiEvent.data[1] = inData1;
  1759. midiEvent.data[2] = inData2;
  1760. switch (inStatus & 0xF0)
  1761. {
  1762. case 0x80:
  1763. case 0x90:
  1764. case 0xA0:
  1765. case 0xB0:
  1766. case 0xE0:
  1767. midiEvent.size = 3;
  1768. break;
  1769. case 0xC0:
  1770. case 0xD0:
  1771. midiEvent.size = 2;
  1772. break;
  1773. case 0xF0:
  1774. switch (inStatus & 0x0F)
  1775. {
  1776. case 0x0:
  1777. case 0x4:
  1778. case 0x5:
  1779. case 0x7:
  1780. case 0x9:
  1781. case 0xD:
  1782. // unsupported
  1783. return kAudioUnitErr_InvalidPropertyValue;
  1784. case 0x1:
  1785. case 0x2:
  1786. case 0x3:
  1787. case 0xE:
  1788. midiEvent.size = 3;
  1789. break;
  1790. case 0x6:
  1791. case 0x8:
  1792. case 0xA:
  1793. case 0xB:
  1794. case 0xC:
  1795. case 0xF:
  1796. midiEvent.size = 1;
  1797. break;
  1798. }
  1799. break;
  1800. default:
  1801. // invalid
  1802. d_debug("auMIDIEvent received invalid event %u %u %u %u @ %u",
  1803. inStatus, inData1, inData2, inOffsetSampleFrame, fMidiEventCount);
  1804. return kAudioUnitErr_InvalidPropertyValue;
  1805. }
  1806. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS == 0
  1807. // handle case of plugin having no working audio, simulate audio-side processing
  1808. run(nullptr, nullptr, std::max(1u, inOffsetSampleFrame), nullptr);
  1809. #endif
  1810. return noErr;
  1811. }
  1812. OSStatus auSysEx(const UInt8* const inData, const UInt32 inLength)
  1813. {
  1814. if (fMidiEventCount >= kMaxMidiEvents)
  1815. return noErr;
  1816. MidiEvent& midiEvent(fMidiEvents[fMidiEventCount++]);
  1817. midiEvent.frame = fMidiEventCount != 1 ? fMidiEvents[fMidiEventCount - 1].frame : 0;
  1818. midiEvent.size = inLength;
  1819. // FIXME who owns inData ??
  1820. if (inLength > MidiEvent::kDataSize)
  1821. {
  1822. std::memset(midiEvent.data, 0, MidiEvent::kDataSize);
  1823. midiEvent.dataExt = inData;
  1824. }
  1825. else
  1826. {
  1827. std::memcpy(midiEvent.data, inData, inLength);
  1828. }
  1829. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS == 0
  1830. // handle case of plugin having no working audio, simulate audio-side processing
  1831. run(nullptr, nullptr, 1, nullptr);
  1832. #endif
  1833. return noErr;
  1834. }
  1835. #endif
  1836. // ----------------------------------------------------------------------------------------------------------------
  1837. private:
  1838. PluginExporter fPlugin;
  1839. // AU component
  1840. const AudioUnit fComponent;
  1841. // AUv2 related fields
  1842. OSStatus fLastRenderError;
  1843. PropertyListeners fPropertyListeners;
  1844. RenderListeners fRenderListeners;
  1845. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  1846. UInt32 fInputConnectionBus;
  1847. AudioUnit fInputConnectionUnit;
  1848. AURenderCallbackStruct fInputRenderCallback;
  1849. Float64 fSampleRateForInput;
  1850. #ifdef DISTRHO_PLUGIN_EXTRA_IO
  1851. uint32_t fNumInputs;
  1852. #endif
  1853. #endif
  1854. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1855. Float64 fSampleRateForOutput;
  1856. #ifdef DISTRHO_PLUGIN_EXTRA_IO
  1857. uint32_t fNumOutputs;
  1858. #endif
  1859. #endif
  1860. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1861. AudioBufferList* fAudioBufferList;
  1862. #endif
  1863. bool fUsingRenderListeners;
  1864. // Caching
  1865. const uint32_t fParameterCount;
  1866. float* fLastParameterValues;
  1867. uint32_t fBypassParameterIndex;
  1868. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1869. uint32_t fMidiEventCount;
  1870. MidiEvent fMidiEvents[kMaxMidiEvents];
  1871. SmallStackRingBuffer fNotesRingBuffer;
  1872. #endif
  1873. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  1874. uint32_t fMidiOutputDataOffset;
  1875. MIDIPacketList* fMidiOutputPackets;
  1876. AUMIDIOutputCallbackStruct fMidiOutput;
  1877. #endif
  1878. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  1879. int32_t fCurrentProgram;
  1880. uint32_t fLastFactoryProgram;
  1881. uint32_t fProgramCount;
  1882. AUPreset* fFactoryPresetsData;
  1883. #endif
  1884. AUPreset fUserPresetData;
  1885. #if DISTRHO_PLUGIN_WANT_STATE
  1886. const uint32_t fStateCount;
  1887. StringMap fStateMap;
  1888. #endif
  1889. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  1890. HostCallbackInfo fHostCallbackInfo;
  1891. TimePosition fTimePosition;
  1892. #endif
  1893. // ----------------------------------------------------------------------------------------------------------------
  1894. void notifyPropertyListeners(const AudioUnitPropertyID prop, const AudioUnitScope scope, const AudioUnitElement elem)
  1895. {
  1896. for (PropertyListeners::iterator it = fPropertyListeners.begin(); it != fPropertyListeners.end(); ++it)
  1897. {
  1898. const PropertyListener& pl(*it);
  1899. if (pl.prop == prop)
  1900. pl.proc(pl.userData, fComponent, prop, scope, elem);
  1901. }
  1902. }
  1903. void notifyRenderListeners(AudioUnitRenderActionFlags* const ioActionFlags,
  1904. const AudioTimeStamp* const inTimeStamp,
  1905. const UInt32 inBusNumber,
  1906. const UInt32 inNumberFrames,
  1907. AudioBufferList* const ioData)
  1908. {
  1909. for (RenderListeners::iterator it = fRenderListeners.begin(); it != fRenderListeners.end(); ++it)
  1910. {
  1911. const RenderListener& rl(*it);
  1912. rl.proc(rl.userData, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
  1913. }
  1914. }
  1915. // ----------------------------------------------------------------------------------------------------------------
  1916. void run(const float** inputs, float** outputs, const uint32_t frames, const AudioTimeStamp* const inTimeStamp)
  1917. {
  1918. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1919. if (fMidiEventCount != kMaxMidiEvents && fNotesRingBuffer.isDataAvailableForReading())
  1920. {
  1921. uint8_t midiData[3];
  1922. const uint32_t frame = fMidiEventCount != 0 ? fMidiEvents[fMidiEventCount - 1].frame : 0;
  1923. while (fNotesRingBuffer.isDataAvailableForReading())
  1924. {
  1925. if (! fNotesRingBuffer.readCustomData(midiData, 3))
  1926. break;
  1927. MidiEvent& midiEvent(fMidiEvents[fMidiEventCount++]);
  1928. midiEvent.frame = frame;
  1929. midiEvent.size = 3;
  1930. std::memcpy(midiEvent.data, midiData, 3);
  1931. if (fMidiEventCount == kMaxMidiEvents)
  1932. break;
  1933. }
  1934. }
  1935. #endif
  1936. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  1937. fMidiOutputDataOffset = 0;
  1938. fMidiOutputPackets->numPackets = 0;
  1939. #endif
  1940. #if DISTRHO_PLUGIN_WANT_TIMEPOS
  1941. if (fHostCallbackInfo.beatAndTempoProc != nullptr ||
  1942. fHostCallbackInfo.musicalTimeLocationProc != nullptr ||
  1943. fHostCallbackInfo.transportStateProc != nullptr)
  1944. {
  1945. // reused values so we can check null and return value together
  1946. Boolean b1 = false;
  1947. Float32 f1 = 4.f; // initial value for beats per bar
  1948. Float64 g1 = 0.0;
  1949. Float64 g2 = 0.0;
  1950. UInt32 u1 = 0;
  1951. if (fHostCallbackInfo.musicalTimeLocationProc != nullptr
  1952. && fHostCallbackInfo.musicalTimeLocationProc(fHostCallbackInfo.hostUserData,
  1953. nullptr, &f1, &u1, nullptr) == noErr)
  1954. {
  1955. fTimePosition.bbt.beatsPerBar = f1;
  1956. fTimePosition.bbt.beatType = u1;
  1957. }
  1958. else
  1959. {
  1960. fTimePosition.bbt.beatsPerBar = 4.f;
  1961. fTimePosition.bbt.beatType = 4.f;
  1962. }
  1963. if (fHostCallbackInfo.beatAndTempoProc != nullptr
  1964. && fHostCallbackInfo.beatAndTempoProc(fHostCallbackInfo.hostUserData, &g1, &g2) == noErr)
  1965. {
  1966. const double beat = static_cast<int32_t>(g1);
  1967. fTimePosition.bbt.valid = true;
  1968. fTimePosition.bbt.bar = static_cast<int32_t>(beat / f1) + 1;
  1969. fTimePosition.bbt.beat = static_cast<int32_t>(std::fmod(beat, f1)) + 1;
  1970. fTimePosition.bbt.tick = std::fmod(g1, 1.0) * 1920.0;
  1971. fTimePosition.bbt.beatsPerMinute = g2;
  1972. }
  1973. else
  1974. {
  1975. fTimePosition.bbt.valid = false;
  1976. fTimePosition.bbt.bar = 1;
  1977. fTimePosition.bbt.beat = 1;
  1978. fTimePosition.bbt.tick = 0.0;
  1979. fTimePosition.bbt.beatsPerMinute = 120.0;
  1980. }
  1981. if (fHostCallbackInfo.transportStateProc != nullptr
  1982. && fHostCallbackInfo.transportStateProc(fHostCallbackInfo.hostUserData,
  1983. &b1, nullptr, &g1, nullptr, nullptr, nullptr) == noErr)
  1984. {
  1985. fTimePosition.playing = b1;
  1986. fTimePosition.frame = static_cast<int64_t>(g1);
  1987. }
  1988. else
  1989. {
  1990. fTimePosition.playing = false;
  1991. fTimePosition.frame = 0;
  1992. }
  1993. fTimePosition.bbt.barStartTick = kDefaultTicksPerBeat *
  1994. fTimePosition.bbt.beatsPerBar *
  1995. (fTimePosition.bbt.bar - 1);
  1996. fPlugin.setTimePosition(fTimePosition);
  1997. }
  1998. #endif
  1999. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  2000. fPlugin.run(inputs, outputs, frames, fMidiEvents, fMidiEventCount);
  2001. fMidiEventCount = 0;
  2002. #else
  2003. fPlugin.run(inputs, outputs, frames);
  2004. #endif
  2005. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  2006. if (fMidiOutputPackets != nullptr &&
  2007. fMidiOutputPackets->numPackets != 0 &&
  2008. fMidiOutput.midiOutputCallback != nullptr)
  2009. {
  2010. fMidiOutput.midiOutputCallback(fMidiOutput.userData, inTimeStamp, 0, fMidiOutputPackets);
  2011. }
  2012. #else
  2013. // unused
  2014. (void)inTimeStamp;
  2015. #endif
  2016. float value;
  2017. AudioUnitEvent event;
  2018. std::memset(&event, 0, sizeof(event));
  2019. event.mEventType = kAudioUnitEvent_ParameterValueChange;
  2020. event.mArgument.mParameter.mAudioUnit = fComponent;
  2021. event.mArgument.mParameter.mScope = kAudioUnitScope_Global;
  2022. for (uint32_t i=0; i<fParameterCount; ++i)
  2023. {
  2024. if (fPlugin.isParameterOutputOrTrigger(i))
  2025. {
  2026. value = fPlugin.getParameterValue(i);
  2027. if (d_isEqual(fLastParameterValues[i], value))
  2028. continue;
  2029. fLastParameterValues[i] = value;
  2030. // TODO flag param only, notify listeners later on bg thread (sem_post etc)
  2031. event.mArgument.mParameter.mParameterID = i;
  2032. AUEventListenerNotify(NULL, NULL, &event);
  2033. notifyPropertyListeners('DPFp', kAudioUnitScope_Global, i);
  2034. }
  2035. }
  2036. }
  2037. void setLastRenderError(const OSStatus err)
  2038. {
  2039. if (fLastRenderError != noErr)
  2040. return;
  2041. fLastRenderError = err;
  2042. notifyPropertyListeners(kAudioUnitProperty_LastRenderError, kAudioUnitScope_Global, 0);
  2043. }
  2044. // ----------------------------------------------------------------------------------------------------------------
  2045. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  2046. bool reallocAudioBufferList(const bool alloc)
  2047. {
  2048. if (fAudioBufferList != nullptr)
  2049. {
  2050. for (uint16_t i = 0; i < fAudioBufferList->mNumberBuffers; ++i)
  2051. delete[] static_cast<float*>(fAudioBufferList->mBuffers[i].mData);
  2052. }
  2053. #ifdef DISTRHO_PLUGIN_EXTRA_IO
  2054. #if DISTRHO_PLUGIN_NUM_INPUTS != 0 && DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  2055. const uint16_t numBuffers = std::max(fNumInputs, fNumOutputs);
  2056. #elif DISTRHO_PLUGIN_NUM_INPUTS != 0
  2057. const uint16_t numBuffers = fNumInputs;
  2058. #else
  2059. const uint16_t numBuffers = fNumOutputs;
  2060. #endif
  2061. #else
  2062. constexpr const uint16_t numBuffers = d_max(DISTRHO_PLUGIN_NUM_INPUTS, DISTRHO_PLUGIN_NUM_OUTPUTS);
  2063. #endif
  2064. const uint32_t bufferSize = fPlugin.getBufferSize();
  2065. if (! alloc)
  2066. {
  2067. std::free(fAudioBufferList);
  2068. fAudioBufferList = nullptr;
  2069. return true;
  2070. }
  2071. if (AudioBufferList* const abl = static_cast<AudioBufferList*>(
  2072. std::realloc(fAudioBufferList, sizeof(uint32_t) + sizeof(AudioBuffer) * numBuffers)))
  2073. {
  2074. abl->mNumberBuffers = numBuffers;
  2075. for (uint16_t i = 0; i < numBuffers; ++i)
  2076. {
  2077. abl->mBuffers[i].mNumberChannels = 1;
  2078. abl->mBuffers[i].mData = new float[bufferSize];
  2079. abl->mBuffers[i].mDataByteSize = sizeof(float) * bufferSize;
  2080. }
  2081. fAudioBufferList = abl;
  2082. return true;
  2083. }
  2084. std::free(fAudioBufferList);
  2085. fAudioBufferList = nullptr;
  2086. return false;
  2087. }
  2088. #endif
  2089. // ----------------------------------------------------------------------------------------------------------------
  2090. CFMutableDictionaryRef retrieveClassInfo()
  2091. {
  2092. CFMutableDictionaryRef clsInfo = CFDictionaryCreateMutable(nullptr,
  2093. 0,
  2094. &kCFTypeDictionaryKeyCallBacks,
  2095. &kCFTypeDictionaryValueCallBacks);
  2096. SInt32 value;
  2097. value = 0;
  2098. if (const CFNumberRef num = CFNumberCreate(nullptr, kCFNumberSInt32Type, &value))
  2099. {
  2100. CFDictionarySetValue(clsInfo, CFSTR(kAUPresetVersionKey), num);
  2101. CFRelease(num);
  2102. }
  2103. value = kType;
  2104. if (const CFNumberRef num = CFNumberCreate(nullptr, kCFNumberSInt32Type, &value))
  2105. {
  2106. CFDictionarySetValue(clsInfo, CFSTR(kAUPresetTypeKey), num);
  2107. CFRelease(num);
  2108. }
  2109. value = kSubType;
  2110. if (const CFNumberRef num = CFNumberCreate(nullptr, kCFNumberSInt32Type, &value))
  2111. {
  2112. CFDictionarySetValue(clsInfo, CFSTR(kAUPresetSubtypeKey), num);
  2113. CFRelease(num);
  2114. }
  2115. value = kManufacturer;
  2116. if (const CFNumberRef num = CFNumberCreate(nullptr, kCFNumberSInt32Type, &value))
  2117. {
  2118. CFDictionarySetValue(clsInfo, CFSTR(kAUPresetManufacturerKey), num);
  2119. CFRelease(num);
  2120. }
  2121. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  2122. if (fCurrentProgram >= 0)
  2123. {
  2124. CFDictionarySetValue(clsInfo, CFSTR(kAUPresetNameKey), fFactoryPresetsData[fCurrentProgram].presetName);
  2125. }
  2126. else
  2127. #endif
  2128. {
  2129. CFDictionarySetValue(clsInfo, CFSTR(kAUPresetNameKey), fUserPresetData.presetName);
  2130. }
  2131. if (const CFMutableDictionaryRef data = CFDictionaryCreateMutable(nullptr,
  2132. 0,
  2133. &kCFTypeDictionaryKeyCallBacks,
  2134. &kCFTypeDictionaryValueCallBacks))
  2135. {
  2136. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  2137. const SInt32 program = fCurrentProgram;
  2138. if (const CFNumberRef programRef = CFNumberCreate(nullptr, kCFNumberSInt32Type, &program))
  2139. {
  2140. CFDictionarySetValue(data, CFSTR("program"), programRef);
  2141. CFRelease(programRef);
  2142. }
  2143. #endif
  2144. #if DISTRHO_PLUGIN_WANT_FULL_STATE
  2145. // Update current state
  2146. for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
  2147. {
  2148. const String& key(cit->first);
  2149. fStateMap[key] = fPlugin.getStateValue(key);
  2150. }
  2151. #endif
  2152. #if DISTRHO_PLUGIN_WANT_STATE
  2153. if (const CFMutableArrayRef statesRef = CFArrayCreateMutable(nullptr,
  2154. fStateCount,
  2155. &kCFTypeArrayCallBacks))
  2156. {
  2157. for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
  2158. {
  2159. const String& key(cit->first);
  2160. const String& value(cit->second);
  2161. #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS && ! DISTRHO_PLUGIN_HAS_UI
  2162. bool wantStateKey = true;
  2163. for (uint32_t i=0; i<fStateCount; ++i)
  2164. {
  2165. if (fPlugin.getStateKey(i) == key)
  2166. {
  2167. if (fPlugin.getStateHints(i) & kStateIsOnlyForUI)
  2168. wantStateKey = false;
  2169. break;
  2170. }
  2171. }
  2172. if (! wantStateKey)
  2173. continue;
  2174. #endif
  2175. CFStringRef keyRef = CFStringCreateWithCString(nullptr, key, kCFStringEncodingASCII);
  2176. CFStringRef valueRef = CFStringCreateWithCString(nullptr, value, kCFStringEncodingUTF8);
  2177. if (CFDictionaryRef dictRef = CFDictionaryCreate(nullptr,
  2178. reinterpret_cast<const void**>(&keyRef),
  2179. reinterpret_cast<const void**>(&valueRef),
  2180. 1,
  2181. &kCFTypeDictionaryKeyCallBacks,
  2182. &kCFTypeDictionaryValueCallBacks))
  2183. {
  2184. CFArrayAppendValue(statesRef, dictRef);
  2185. CFRelease(dictRef);
  2186. }
  2187. CFRelease(keyRef);
  2188. CFRelease(valueRef);
  2189. }
  2190. CFDictionarySetValue(data, CFSTR("states"), statesRef);
  2191. CFRelease(statesRef);
  2192. }
  2193. #endif
  2194. if (const CFMutableArrayRef paramsRef = CFArrayCreateMutable(nullptr,
  2195. fParameterCount,
  2196. &kCFTypeArrayCallBacks))
  2197. {
  2198. for (uint32_t i=0; i<fParameterCount; ++i)
  2199. {
  2200. if (fPlugin.isParameterOutputOrTrigger(i))
  2201. continue;
  2202. const float value = fPlugin.getParameterValue(i);
  2203. CFStringRef keyRef = CFStringCreateWithCString(nullptr,
  2204. fPlugin.getParameterSymbol(i),
  2205. kCFStringEncodingASCII);
  2206. CFNumberRef valueRef = CFNumberCreate(nullptr, kCFNumberFloat32Type, &value);
  2207. if (CFDictionaryRef dictRef = CFDictionaryCreate(nullptr,
  2208. reinterpret_cast<const void**>(&keyRef),
  2209. reinterpret_cast<const void**>(&valueRef),
  2210. 1,
  2211. &kCFTypeDictionaryKeyCallBacks,
  2212. &kCFTypeDictionaryValueCallBacks))
  2213. {
  2214. CFArrayAppendValue(paramsRef, dictRef);
  2215. CFRelease(dictRef);
  2216. }
  2217. CFRelease(keyRef);
  2218. CFRelease(valueRef);
  2219. }
  2220. CFDictionarySetValue(data, CFSTR("params"), paramsRef);
  2221. CFRelease(paramsRef);
  2222. }
  2223. CFDictionarySetValue(clsInfo, CFSTR(kAUPresetDataKey), data);
  2224. CFRelease(data);
  2225. }
  2226. return clsInfo;
  2227. }
  2228. void restoreClassInfo(const CFDictionaryRef clsInfo)
  2229. {
  2230. CFDictionaryRef data = nullptr;
  2231. DISTRHO_SAFE_ASSERT_RETURN(CFDictionaryGetValueIfPresent(clsInfo,
  2232. CFSTR(kAUPresetDataKey),
  2233. reinterpret_cast<const void**>(&data)),);
  2234. DISTRHO_SAFE_ASSERT_RETURN(CFGetTypeID(data) == CFDictionaryGetTypeID(),);
  2235. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  2236. CFNumberRef programRef = nullptr;
  2237. if (CFDictionaryGetValueIfPresent(data, CFSTR("program"), reinterpret_cast<const void**>(&programRef))
  2238. && CFGetTypeID(programRef) == CFNumberGetTypeID())
  2239. {
  2240. SInt32 program = -1;
  2241. if (CFNumberGetValue(programRef, kCFNumberSInt32Type, &program))
  2242. {
  2243. fCurrentProgram = program;
  2244. if (program >= 0)
  2245. {
  2246. fLastFactoryProgram = program;
  2247. fPlugin.loadProgram(fLastFactoryProgram);
  2248. notifyPropertyListeners('DPFo', kAudioUnitScope_Global, 0);
  2249. }
  2250. notifyPropertyListeners(kAudioUnitProperty_PresentPreset, kAudioUnitScope_Global, 0);
  2251. }
  2252. }
  2253. #endif
  2254. #if DISTRHO_PLUGIN_WANT_STATE
  2255. CFArrayRef statesRef = nullptr;
  2256. if (CFDictionaryGetValueIfPresent(data, CFSTR("states"), reinterpret_cast<const void**>(&statesRef))
  2257. && CFGetTypeID(statesRef) == CFArrayGetTypeID())
  2258. {
  2259. const CFIndex numStates = CFArrayGetCount(statesRef);
  2260. char* key = nullptr;
  2261. char* value = nullptr;
  2262. CFIndex keyLen = -1;
  2263. CFIndex valueLen = -1;
  2264. for (CFIndex i=0; i<numStates; ++i)
  2265. {
  2266. const CFDictionaryRef state = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(statesRef, i));
  2267. DISTRHO_SAFE_ASSERT_BREAK(CFGetTypeID(state) == CFDictionaryGetTypeID());
  2268. DISTRHO_SAFE_ASSERT_BREAK(CFDictionaryGetCount(state) == 1);
  2269. CFStringRef keyRef = nullptr;
  2270. CFStringRef valueRef = nullptr;
  2271. CFDictionaryGetKeysAndValues(state,
  2272. reinterpret_cast<const void**>(&keyRef),
  2273. reinterpret_cast<const void**>(&valueRef));
  2274. DISTRHO_SAFE_ASSERT_BREAK(keyRef != nullptr && CFGetTypeID(keyRef) == CFStringGetTypeID());
  2275. DISTRHO_SAFE_ASSERT_BREAK(valueRef != nullptr && CFGetTypeID(valueRef) == CFStringGetTypeID());
  2276. const CFIndex keyRefLen = CFStringGetLength(keyRef);
  2277. if (keyLen < keyRefLen)
  2278. {
  2279. keyLen = keyRefLen;
  2280. key = static_cast<char*>(std::realloc(key, keyLen + 1));
  2281. }
  2282. DISTRHO_SAFE_ASSERT_BREAK(CFStringGetCString(keyRef, key, keyLen + 1, kCFStringEncodingASCII));
  2283. if (! fPlugin.wantStateKey(key))
  2284. continue;
  2285. const CFIndex valueRefLen = CFStringGetLength(valueRef);
  2286. if (valueLen < valueRefLen)
  2287. {
  2288. valueLen = valueRefLen;
  2289. value = static_cast<char*>(std::realloc(value, valueLen + 1));
  2290. }
  2291. DISTRHO_SAFE_ASSERT_BREAK(CFStringGetCString(valueRef, value, valueLen + 1, kCFStringEncodingUTF8));
  2292. const String dkey(key);
  2293. fStateMap[dkey] = value;
  2294. fPlugin.setState(key, value);
  2295. for (uint32_t j=0; j<fStateCount; ++j)
  2296. {
  2297. if (fPlugin.getStateKey(j) == key)
  2298. {
  2299. if ((fPlugin.getStateHints(i) & kStateIsOnlyForDSP) == 0x0)
  2300. notifyPropertyListeners('DPFs', kAudioUnitScope_Global, j);
  2301. break;
  2302. }
  2303. }
  2304. }
  2305. std::free(key);
  2306. std::free(value);
  2307. }
  2308. #endif
  2309. CFArrayRef paramsRef = nullptr;
  2310. if (CFDictionaryGetValueIfPresent(data, CFSTR("params"), reinterpret_cast<const void**>(&paramsRef))
  2311. && CFGetTypeID(paramsRef) == CFArrayGetTypeID())
  2312. {
  2313. const CFIndex numParams = CFArrayGetCount(paramsRef);
  2314. char* symbol = nullptr;
  2315. CFIndex symbolLen = -1;
  2316. for (CFIndex i=0; i<numParams; ++i)
  2317. {
  2318. const CFDictionaryRef param = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(paramsRef, i));
  2319. DISTRHO_SAFE_ASSERT_BREAK(CFGetTypeID(param) == CFDictionaryGetTypeID());
  2320. DISTRHO_SAFE_ASSERT_BREAK(CFDictionaryGetCount(param) == 1);
  2321. CFStringRef keyRef = nullptr;
  2322. CFNumberRef valueRef = nullptr;
  2323. CFDictionaryGetKeysAndValues(param,
  2324. reinterpret_cast<const void**>(&keyRef),
  2325. reinterpret_cast<const void**>(&valueRef));
  2326. DISTRHO_SAFE_ASSERT_BREAK(keyRef != nullptr && CFGetTypeID(keyRef) == CFStringGetTypeID());
  2327. DISTRHO_SAFE_ASSERT_BREAK(valueRef != nullptr && CFGetTypeID(valueRef) == CFNumberGetTypeID());
  2328. float value = 0.f;
  2329. DISTRHO_SAFE_ASSERT_BREAK(CFNumberGetValue(valueRef, kCFNumberFloat32Type, &value));
  2330. const CFIndex keyRefLen = CFStringGetLength(keyRef);
  2331. if (symbolLen < keyRefLen)
  2332. {
  2333. symbolLen = keyRefLen;
  2334. symbol = static_cast<char*>(std::realloc(symbol, symbolLen + 1));
  2335. }
  2336. DISTRHO_SAFE_ASSERT_BREAK(CFStringGetCString(keyRef, symbol, symbolLen + 1, kCFStringEncodingASCII));
  2337. for (uint32_t j=0; j<fParameterCount; ++j)
  2338. {
  2339. if (fPlugin.isParameterOutputOrTrigger(j))
  2340. continue;
  2341. if (fPlugin.getParameterSymbol(j) != symbol)
  2342. continue;
  2343. fLastParameterValues[j] = value;
  2344. fPlugin.setParameterValue(j, value);
  2345. notifyPropertyListeners('DPFp', kAudioUnitScope_Global, j);
  2346. if (fBypassParameterIndex == j)
  2347. notifyPropertyListeners(kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0);
  2348. break;
  2349. }
  2350. }
  2351. std::free(symbol);
  2352. }
  2353. }
  2354. // ----------------------------------------------------------------------------------------------------------------
  2355. // DPF callbacks
  2356. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  2357. bool writeMidi(const MidiEvent& midiEvent)
  2358. {
  2359. DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN("MIDI output unsupported", fMidiOutput.midiOutputCallback != nullptr, false);
  2360. DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN("Out of memory", fMidiOutputPackets != nullptr, false);
  2361. if (fMidiOutputDataOffset + kMIDIPacketNonDataSize + midiEvent.size >= kMIDIPacketListMaxDataSize)
  2362. return false;
  2363. const uint8_t* const midiData = midiEvent.size > MidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data;
  2364. MIDIPacket* const packet = reinterpret_cast<MIDIPacket*>(
  2365. reinterpret_cast<uint8_t*>(fMidiOutputPackets->packet) + fMidiOutputDataOffset);
  2366. packet->timeStamp = midiEvent.frame;
  2367. packet->length = midiEvent.size;
  2368. std::memcpy(packet->data, midiData, midiEvent.size);
  2369. ++fMidiOutputPackets->numPackets;
  2370. fMidiOutputDataOffset += kMIDIPacketNonDataSize + midiEvent.size;
  2371. return true;
  2372. }
  2373. static bool writeMidiCallback(void* const ptr, const MidiEvent& midiEvent)
  2374. {
  2375. return static_cast<PluginAU*>(ptr)->writeMidi(midiEvent);
  2376. }
  2377. #endif
  2378. #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
  2379. bool requestParameterValueChange(const uint32_t index, const float value)
  2380. {
  2381. AudioUnitEvent event;
  2382. std::memset(&event, 0, sizeof(event));
  2383. event.mEventType = kAudioUnitEvent_ParameterValueChange;
  2384. event.mArgument.mParameter.mAudioUnit = fComponent;
  2385. event.mArgument.mParameter.mParameterID = index;
  2386. event.mArgument.mParameter.mScope = kAudioUnitScope_Global;
  2387. fLastParameterValues[index] = value;
  2388. AUEventListenerNotify(NULL, NULL, &event);
  2389. notifyPropertyListeners('DPFp', kAudioUnitScope_Global, index);
  2390. return true;
  2391. }
  2392. static bool requestParameterValueChangeCallback(void* const ptr, const uint32_t index, const float value)
  2393. {
  2394. return static_cast<PluginAU*>(ptr)->requestParameterValueChange(index, value);
  2395. }
  2396. #endif
  2397. #if DISTRHO_PLUGIN_WANT_STATE
  2398. bool updateState(const char* const key, const char* const newValue)
  2399. {
  2400. fPlugin.setState(key, newValue);
  2401. for (uint32_t i=0; i<fStateCount; ++i)
  2402. {
  2403. if (fPlugin.getStateKey(i) == key)
  2404. {
  2405. const String dkey(key);
  2406. fStateMap[dkey] = newValue;
  2407. if ((fPlugin.getStateHints(i) & kStateIsOnlyForDSP) == 0x0)
  2408. notifyPropertyListeners('DPFs', kAudioUnitScope_Global, i);
  2409. return true;
  2410. }
  2411. }
  2412. d_stderr("Failed to find plugin state with key \"%s\"", key);
  2413. return false;
  2414. }
  2415. static bool updateStateValueCallback(void* const ptr, const char* const key, const char* const newValue)
  2416. {
  2417. return static_cast<PluginAU*>(ptr)->updateState(key, newValue);
  2418. }
  2419. #endif
  2420. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginAU)
  2421. };
  2422. // --------------------------------------------------------------------------------------------------------------------
  2423. struct AudioComponentPlugInInstance {
  2424. AudioComponentPlugInInterface acpi;
  2425. PluginAU* plugin;
  2426. AudioComponentPlugInInstance() noexcept
  2427. : acpi(),
  2428. plugin(nullptr)
  2429. {
  2430. std::memset(&acpi, 0, sizeof(acpi));
  2431. acpi.Open = Open;
  2432. acpi.Close = Close;
  2433. acpi.Lookup = Lookup;
  2434. acpi.reserved = nullptr;
  2435. }
  2436. ~AudioComponentPlugInInstance()
  2437. {
  2438. delete plugin;
  2439. }
  2440. static OSStatus Open(void* const self, const AudioUnit component)
  2441. {
  2442. d_debug("AudioComponentPlugInInstance::Open(%p)", self);
  2443. static_cast<AudioComponentPlugInInstance*>(self)->plugin = new PluginAU(component);
  2444. return noErr;
  2445. }
  2446. static OSStatus Close(void* const self)
  2447. {
  2448. d_debug("AudioComponentPlugInInstance::Close(%p)", self);
  2449. delete static_cast<AudioComponentPlugInInstance*>(self);
  2450. return noErr;
  2451. }
  2452. static AudioComponentMethod Lookup(const SInt16 selector)
  2453. {
  2454. d_debug("AudioComponentPlugInInstance::Lookup(%3d:%s)", selector, AudioUnitSelector2Str(selector));
  2455. switch (selector)
  2456. {
  2457. case kAudioUnitInitializeSelect:
  2458. return reinterpret_cast<AudioComponentMethod>(Initialize);
  2459. case kAudioUnitUninitializeSelect:
  2460. return reinterpret_cast<AudioComponentMethod>(Uninitialize);
  2461. case kAudioUnitGetPropertyInfoSelect:
  2462. return reinterpret_cast<AudioComponentMethod>(GetPropertyInfo);
  2463. case kAudioUnitGetPropertySelect:
  2464. return reinterpret_cast<AudioComponentMethod>(GetProperty);
  2465. case kAudioUnitSetPropertySelect:
  2466. return reinterpret_cast<AudioComponentMethod>(SetProperty);
  2467. case kAudioUnitAddPropertyListenerSelect:
  2468. return reinterpret_cast<AudioComponentMethod>(AddPropertyListener);
  2469. case kAudioUnitRemovePropertyListenerSelect:
  2470. return reinterpret_cast<AudioComponentMethod>(RemovePropertyListener);
  2471. case kAudioUnitRemovePropertyListenerWithUserDataSelect:
  2472. return reinterpret_cast<AudioComponentMethod>(RemovePropertyListenerWithUserData);
  2473. case kAudioUnitAddRenderNotifySelect:
  2474. return reinterpret_cast<AudioComponentMethod>(AddRenderNotify);
  2475. case kAudioUnitRemoveRenderNotifySelect:
  2476. return reinterpret_cast<AudioComponentMethod>(RemoveRenderNotify);
  2477. case kAudioUnitGetParameterSelect:
  2478. return reinterpret_cast<AudioComponentMethod>(GetParameter);
  2479. case kAudioUnitSetParameterSelect:
  2480. return reinterpret_cast<AudioComponentMethod>(SetParameter);
  2481. case kAudioUnitScheduleParametersSelect:
  2482. return reinterpret_cast<AudioComponentMethod>(ScheduleParameters);
  2483. case kAudioUnitRenderSelect:
  2484. return reinterpret_cast<AudioComponentMethod>(Render);
  2485. /*
  2486. case kAudioUnitComplexRenderSelect:
  2487. return reinterpret_cast<AudioComponentMethod>(ComplexRender);
  2488. */
  2489. case kAudioUnitResetSelect:
  2490. return reinterpret_cast<AudioComponentMethod>(Reset);
  2491. /*
  2492. case kAudioUnitProcessSelect:
  2493. return reinterpret_cast<AudioComponentMethod>(Process);
  2494. case kAudioUnitProcessMultipleSelect:
  2495. return reinterpret_cast<AudioComponentMethod>(ProcessMultiple);
  2496. */
  2497. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  2498. case kMusicDeviceMIDIEventSelect:
  2499. return reinterpret_cast<AudioComponentMethod>(MIDIEvent);
  2500. case kMusicDeviceSysExSelect:
  2501. return reinterpret_cast<AudioComponentMethod>(SysEx);
  2502. #else
  2503. case kMusicDeviceMIDIEventSelect:
  2504. case kMusicDeviceSysExSelect:
  2505. return nullptr;
  2506. #endif
  2507. }
  2508. d_stdout("TODO Lookup(%3d:%s)", selector, AudioUnitSelector2Str(selector));
  2509. return nullptr;
  2510. }
  2511. static OSStatus Initialize(AudioComponentPlugInInstance* const self)
  2512. {
  2513. d_debug("AudioComponentPlugInInstance::Initialize(%p)", self);
  2514. return self->plugin->auInitialize();
  2515. }
  2516. static OSStatus Uninitialize(AudioComponentPlugInInstance* const self)
  2517. {
  2518. d_debug("AudioComponentPlugInInstance::Uninitialize(%p)", self);
  2519. return self->plugin->auUninitialize();
  2520. }
  2521. static OSStatus GetPropertyInfo(AudioComponentPlugInInstance* const self,
  2522. const AudioUnitPropertyID inProp,
  2523. const AudioUnitScope inScope,
  2524. const AudioUnitElement inElement,
  2525. UInt32* const outDataSize,
  2526. Boolean* const outWritable)
  2527. {
  2528. d_debug("AudioComponentPlugInInstance::GetPropertyInfo(%p, %d:%x:%s, %d:%s, %d, ...)",
  2529. self, inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement);
  2530. UInt32 dataSize = 0;
  2531. Boolean writable = false;
  2532. const OSStatus res = self->plugin->auGetPropertyInfo(inProp, inScope, inElement, dataSize, writable);
  2533. if (outDataSize != nullptr)
  2534. *outDataSize = dataSize;
  2535. if (outWritable != nullptr)
  2536. *outWritable = writable;
  2537. return res;
  2538. }
  2539. static OSStatus GetProperty(AudioComponentPlugInInstance* const self,
  2540. const AudioUnitPropertyID inProp,
  2541. const AudioUnitScope inScope,
  2542. const AudioUnitElement inElement,
  2543. void* const outData,
  2544. UInt32* const ioDataSize)
  2545. {
  2546. #ifdef DEBUG
  2547. switch (inProp) {
  2548. case kAudioUnitProperty_PresentPreset:
  2549. break;
  2550. default:
  2551. d_debug("AudioComponentPlugInInstance::GetProperty(%p, %d:%x:%s, %d:%s, %d, ...)",
  2552. self, inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement);
  2553. break;
  2554. }
  2555. #endif
  2556. DISTRHO_SAFE_ASSERT_RETURN(ioDataSize != nullptr, kAudio_ParamError);
  2557. Boolean writable;
  2558. UInt32 outDataSize = 0;
  2559. OSStatus res;
  2560. if (outData == nullptr)
  2561. {
  2562. res = self->plugin->auGetPropertyInfo(inProp, inScope, inElement, outDataSize, writable);
  2563. *ioDataSize = outDataSize;
  2564. return res;
  2565. }
  2566. const UInt32 inDataSize = *ioDataSize;
  2567. if (inDataSize == 0)
  2568. return kAudio_ParamError;
  2569. res = self->plugin->auGetPropertyInfo(inProp, inScope, inElement, outDataSize, writable);
  2570. if (res != noErr)
  2571. return res;
  2572. void* outBuffer;
  2573. uint8_t* tmpBuffer;
  2574. if (inDataSize < outDataSize)
  2575. {
  2576. tmpBuffer = new uint8_t[outDataSize];
  2577. outBuffer = tmpBuffer;
  2578. }
  2579. else
  2580. {
  2581. tmpBuffer = nullptr;
  2582. outBuffer = outData;
  2583. }
  2584. res = self->plugin->auGetProperty(inProp, inScope, inElement, outBuffer);
  2585. if (res != noErr)
  2586. {
  2587. *ioDataSize = 0;
  2588. return res;
  2589. }
  2590. if (tmpBuffer != nullptr)
  2591. {
  2592. memcpy(outData, tmpBuffer, inDataSize);
  2593. delete[] tmpBuffer;
  2594. }
  2595. else
  2596. {
  2597. *ioDataSize = outDataSize;
  2598. }
  2599. return noErr;
  2600. }
  2601. static OSStatus SetProperty(AudioComponentPlugInInstance* const self,
  2602. const AudioUnitPropertyID inProp,
  2603. const AudioUnitScope inScope,
  2604. const AudioUnitElement inElement,
  2605. const void* const inData,
  2606. const UInt32 inDataSize)
  2607. {
  2608. d_debug("AudioComponentPlugInInstance::SetProperty(%p, %d:%x:%s, %d:%s, %d, %p, %u)",
  2609. self, inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement, inData, inDataSize);
  2610. return self->plugin->auSetProperty(inProp, inScope, inElement, inData, inDataSize);
  2611. }
  2612. static OSStatus AddPropertyListener(AudioComponentPlugInInstance* const self,
  2613. const AudioUnitPropertyID prop,
  2614. const AudioUnitPropertyListenerProc proc,
  2615. void* const userData)
  2616. {
  2617. d_debug("AudioComponentPlugInInstance::AddPropertyListener(%p, %d:%x:%s, %p, %p)",
  2618. self, prop, prop, AudioUnitPropertyID2Str(prop), proc, userData);
  2619. return self->plugin->auAddPropertyListener(prop, proc, userData);
  2620. }
  2621. static OSStatus RemovePropertyListener(AudioComponentPlugInInstance* const self,
  2622. const AudioUnitPropertyID prop,
  2623. const AudioUnitPropertyListenerProc proc)
  2624. {
  2625. d_debug("AudioComponentPlugInInstance::RemovePropertyListener(%p, %d:%x:%s, %p)",
  2626. self, prop, prop, AudioUnitPropertyID2Str(prop), proc);
  2627. return self->plugin->auRemovePropertyListener(prop, proc);
  2628. }
  2629. static OSStatus RemovePropertyListenerWithUserData(AudioComponentPlugInInstance* const self,
  2630. const AudioUnitPropertyID prop,
  2631. const AudioUnitPropertyListenerProc proc,
  2632. void* const userData)
  2633. {
  2634. d_debug("AudioComponentPlugInInstance::RemovePropertyListenerWithUserData(%p, %d:%x:%s, %p, %p)",
  2635. self, prop, prop, AudioUnitPropertyID2Str(prop), proc, userData);
  2636. return self->plugin->auRemovePropertyListenerWithUserData(prop, proc, userData);
  2637. }
  2638. static OSStatus AddRenderNotify(AudioComponentPlugInInstance* const self,
  2639. const AURenderCallback proc,
  2640. void* const userData)
  2641. {
  2642. d_debug("AudioComponentPlugInInstance::AddRenderNotify(%p, %p, %p)", self, proc, userData);
  2643. return self->plugin->auAddRenderNotify(proc, userData);
  2644. }
  2645. static OSStatus RemoveRenderNotify(AudioComponentPlugInInstance* const self,
  2646. const AURenderCallback proc,
  2647. void* const userData)
  2648. {
  2649. d_debug("AudioComponentPlugInInstance::RemoveRenderNotify(%p, %p, %p)", self, proc, userData);
  2650. return self->plugin->auRemoveRenderNotify(proc, userData);
  2651. }
  2652. static OSStatus GetParameter(AudioComponentPlugInInstance* const self,
  2653. const AudioUnitParameterID param,
  2654. const AudioUnitScope scope,
  2655. const AudioUnitElement elem,
  2656. AudioUnitParameterValue* const value)
  2657. {
  2658. d_debug("AudioComponentPlugInInstance::GetParameter(%p, %d, %d:%s, %d, %p)",
  2659. self, param, scope, AudioUnitScope2Str(scope), elem, value);
  2660. return self->plugin->auGetParameter(param, scope, elem, value);
  2661. }
  2662. static OSStatus SetParameter(AudioComponentPlugInInstance* const self,
  2663. const AudioUnitParameterID param,
  2664. const AudioUnitScope scope,
  2665. const AudioUnitElement elem,
  2666. const AudioUnitParameterValue value,
  2667. const UInt32 bufferOffset)
  2668. {
  2669. d_debug("AudioComponentPlugInInstance::SetParameter(%p, %d %d:%s, %d, %f, %u)",
  2670. self, param, scope, AudioUnitScope2Str(scope), elem, value, bufferOffset);
  2671. return self->plugin->auSetParameter(param, scope, elem, value, bufferOffset);
  2672. }
  2673. static OSStatus ScheduleParameters(AudioComponentPlugInInstance* const self,
  2674. const AudioUnitParameterEvent* const events,
  2675. const UInt32 numEvents)
  2676. {
  2677. d_debug("AudioComponentPlugInInstance::ScheduleParameters(%p, %p, %u)", self, events, numEvents);
  2678. return self->plugin->auScheduleParameters(events, numEvents);
  2679. }
  2680. static OSStatus Reset(AudioComponentPlugInInstance* const self,
  2681. const AudioUnitScope scope,
  2682. const AudioUnitElement elem)
  2683. {
  2684. d_debug("AudioComponentPlugInInstance::Reset(%p, %d:%s, %d)", self, scope, AudioUnitScope2Str(scope), elem);
  2685. return self->plugin->auReset(scope, elem);
  2686. }
  2687. static OSStatus Render(AudioComponentPlugInInstance* const self,
  2688. AudioUnitRenderActionFlags* ioActionFlags,
  2689. const AudioTimeStamp* const inTimeStamp,
  2690. const UInt32 inOutputBusNumber,
  2691. const UInt32 inNumberFrames,
  2692. AudioBufferList* const ioData)
  2693. {
  2694. const AudioUnitRenderActionFlags actionFlags = ioActionFlags != nullptr ? *ioActionFlags : 0;
  2695. if ((actionFlags & kAudioUnitRenderAction_DoNotCheckRenderArgs) == 0x0)
  2696. {
  2697. DISTRHO_SAFE_ASSERT_RETURN(inTimeStamp != nullptr, kAudio_ParamError);
  2698. DISTRHO_SAFE_ASSERT_RETURN(ioData != nullptr, kAudio_ParamError);
  2699. }
  2700. return self->plugin->auRender(actionFlags, inTimeStamp, inOutputBusNumber, inNumberFrames, ioData);
  2701. }
  2702. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  2703. static OSStatus MIDIEvent(AudioComponentPlugInInstance* const self,
  2704. const UInt32 inStatus,
  2705. const UInt32 inData1,
  2706. const UInt32 inData2,
  2707. const UInt32 inOffsetSampleFrame)
  2708. {
  2709. return self->plugin->auMIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame);
  2710. }
  2711. static OSStatus SysEx(AudioComponentPlugInInstance* const self, const UInt8* const inData, const UInt32 inLength)
  2712. {
  2713. return self->plugin->auSysEx(inData, inLength);
  2714. }
  2715. #endif
  2716. DISTRHO_DECLARE_NON_COPYABLE(AudioComponentPlugInInstance)
  2717. };
  2718. #if 0
  2719. static OSStatus FastDispatchGetParameter(void* const self,
  2720. const AudioUnitParameterID param,
  2721. const AudioUnitScope scope,
  2722. const AudioUnitElement elem,
  2723. Float32* const value)
  2724. {
  2725. d_debug("FastDispatchGetParameter(%p, %d, %d:%s, %d, %p)",
  2726. self, param, scope, AudioUnitScope2Str(scope), elem, value);
  2727. return static_cast<AudioComponentPlugInInstance*>(self)->plugin->auGetParameter(param, scope, elem, value);
  2728. }
  2729. static OSStatus FastDispatchSetParameter(void* const self,
  2730. const AudioUnitParameterID param,
  2731. const AudioUnitScope scope,
  2732. const AudioUnitElement elem,
  2733. const Float32 value,
  2734. const UInt32 bufferOffset)
  2735. {
  2736. d_debug("FastDispatchSetParameter(%p, %d %d:%s, %d, %f, %u)",
  2737. self, param, scope, AudioUnitScope2Str(scope), elem, value, bufferOffset);
  2738. return static_cast<AudioComponentPlugInInstance*>(self)->plugin->auSetParameter(param, scope, elem, value, bufferOffset);
  2739. }
  2740. static OSStatus FastDispatchRender(void* const self,
  2741. AudioUnitRenderActionFlags* const ioActionFlags,
  2742. const AudioTimeStamp* const inTimeStamp,
  2743. const UInt32 inBusNumber,
  2744. const UInt32 inNumberFrames,
  2745. AudioBufferList* const ioData)
  2746. {
  2747. DISTRHO_SAFE_ASSERT_RETURN(inTimeStamp != nullptr, kAudio_ParamError);
  2748. DISTRHO_SAFE_ASSERT_RETURN(ioData != nullptr, kAudio_ParamError);
  2749. return static_cast<AudioComponentPlugInInstance*>(self)->plugin->auRender(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, *ioData);
  2750. }
  2751. #endif
  2752. // --------------------------------------------------------------------------------------------------------------------
  2753. END_NAMESPACE_DISTRHO
  2754. DISTRHO_PLUGIN_EXPORT
  2755. void* PluginAUFactory(const AudioComponentDescription* const desc)
  2756. {
  2757. USE_NAMESPACE_DISTRHO
  2758. DISTRHO_SAFE_ASSERT_UINT2_RETURN(desc->componentType == kType, desc->componentType, kType, nullptr);
  2759. DISTRHO_SAFE_ASSERT_UINT2_RETURN(desc->componentSubType == kSubType, desc->componentSubType, kSubType, nullptr);
  2760. DISTRHO_SAFE_ASSERT_UINT2_RETURN(desc->componentManufacturer == kManufacturer, desc->componentManufacturer, kManufacturer, nullptr);
  2761. if (d_nextBufferSize == 0)
  2762. d_nextBufferSize = 1156;
  2763. if (d_isZero(d_nextSampleRate))
  2764. d_nextSampleRate = 44100.0;
  2765. if (d_nextBundlePath == nullptr)
  2766. {
  2767. static String bundlePath;
  2768. String tmpPath(getBinaryFilename());
  2769. tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP));
  2770. tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP));
  2771. if (tmpPath.endsWith(DISTRHO_OS_SEP_STR "Contents"))
  2772. {
  2773. tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP));
  2774. bundlePath = tmpPath;
  2775. }
  2776. else
  2777. {
  2778. bundlePath = "error";
  2779. }
  2780. d_nextBundlePath = bundlePath.buffer();
  2781. }
  2782. d_nextCanRequestParameterValueChanges = true;
  2783. return new AudioComponentPlugInInstance();
  2784. }
  2785. // --------------------------------------------------------------------------------------------------------------------