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.

2053 lines
84KB

  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. #include "DistrhoPluginInternal.hpp"
  20. #include "../DistrhoPluginUtils.hpp"
  21. #if DISTRHO_PLUGIN_HAS_UI
  22. # include "../extra/RingBuffer.hpp"
  23. #endif
  24. #include <AudioUnit/AudioUnit.h>
  25. #include <AudioToolbox/AudioUnitUtilities.h>
  26. #include <vector>
  27. #ifndef DISTRHO_PLUGIN_AU_SUBTYPE
  28. # error DISTRHO_PLUGIN_AU_SUBTYPE undefined!
  29. #endif
  30. #ifndef DISTRHO_PLUGIN_AU_MANUFACTURER
  31. # error DISTRHO_PLUGIN_AU_MANUFACTURER undefined!
  32. #endif
  33. START_NAMESPACE_DISTRHO
  34. // --------------------------------------------------------------------------------------------------------------------
  35. static const char* AudioUnitPropertyID2Str(const AudioUnitPropertyID prop) noexcept
  36. {
  37. switch (prop)
  38. {
  39. #define PROP(s) case s: return #s;
  40. PROP(kAudioUnitProperty_ClassInfo)
  41. PROP(kAudioUnitProperty_MakeConnection)
  42. PROP(kAudioUnitProperty_SampleRate)
  43. PROP(kAudioUnitProperty_ParameterList)
  44. PROP(kAudioUnitProperty_ParameterInfo)
  45. #if !TARGET_OS_IPHONE
  46. PROP(kAudioUnitProperty_FastDispatch)
  47. #endif
  48. PROP(kAudioUnitProperty_CPULoad)
  49. PROP(kAudioUnitProperty_StreamFormat)
  50. PROP(kAudioUnitProperty_ElementCount)
  51. PROP(kAudioUnitProperty_Latency)
  52. PROP(kAudioUnitProperty_SupportedNumChannels)
  53. PROP(kAudioUnitProperty_MaximumFramesPerSlice)
  54. PROP(kAudioUnitProperty_ParameterValueStrings)
  55. PROP(kAudioUnitProperty_AudioChannelLayout)
  56. PROP(kAudioUnitProperty_TailTime)
  57. PROP(kAudioUnitProperty_BypassEffect)
  58. PROP(kAudioUnitProperty_LastRenderError)
  59. PROP(kAudioUnitProperty_SetRenderCallback)
  60. PROP(kAudioUnitProperty_FactoryPresets)
  61. PROP(kAudioUnitProperty_RenderQuality)
  62. PROP(kAudioUnitProperty_HostCallbacks)
  63. PROP(kAudioUnitProperty_InPlaceProcessing)
  64. PROP(kAudioUnitProperty_ElementName)
  65. PROP(kAudioUnitProperty_SupportedChannelLayoutTags)
  66. PROP(kAudioUnitProperty_PresentPreset)
  67. PROP(kAudioUnitProperty_DependentParameters)
  68. PROP(kAudioUnitProperty_InputSamplesInOutput)
  69. PROP(kAudioUnitProperty_ShouldAllocateBuffer)
  70. PROP(kAudioUnitProperty_FrequencyResponse)
  71. PROP(kAudioUnitProperty_ParameterHistoryInfo)
  72. PROP(kAudioUnitProperty_NickName)
  73. PROP(kAudioUnitProperty_OfflineRender)
  74. PROP(kAudioUnitProperty_ParameterIDName)
  75. PROP(kAudioUnitProperty_ParameterStringFromValue)
  76. PROP(kAudioUnitProperty_ParameterClumpName)
  77. PROP(kAudioUnitProperty_ParameterValueFromString)
  78. PROP(kAudioUnitProperty_PresentationLatency)
  79. PROP(kAudioUnitProperty_ClassInfoFromDocument)
  80. PROP(kAudioUnitProperty_RequestViewController)
  81. PROP(kAudioUnitProperty_ParametersForOverview)
  82. PROP(kAudioUnitProperty_SupportsMPE)
  83. PROP(kAudioUnitProperty_RenderContextObserver)
  84. PROP(kAudioUnitProperty_LastRenderSampleTime)
  85. PROP(kAudioUnitProperty_LoadedOutOfProcess)
  86. #if !TARGET_OS_IPHONE
  87. PROP(kAudioUnitProperty_SetExternalBuffer)
  88. PROP(kAudioUnitProperty_GetUIComponentList)
  89. PROP(kAudioUnitProperty_CocoaUI)
  90. PROP(kAudioUnitProperty_IconLocation)
  91. PROP(kAudioUnitProperty_AUHostIdentifier)
  92. #endif
  93. PROP(kAudioUnitProperty_MIDIOutputCallbackInfo)
  94. PROP(kAudioUnitProperty_MIDIOutputCallback)
  95. PROP(kAudioUnitProperty_MIDIOutputEventListCallback)
  96. PROP(kAudioUnitProperty_AudioUnitMIDIProtocol)
  97. PROP(kAudioUnitProperty_HostMIDIProtocol)
  98. PROP(kAudioUnitProperty_MIDIOutputBufferSizeHint)
  99. #undef PROP
  100. }
  101. return "[unknown]";
  102. }
  103. static const char* AudioUnitScope2Str(const AudioUnitScope scope) noexcept
  104. {
  105. switch (scope)
  106. {
  107. #define SCOPE(s) case s: return #s;
  108. SCOPE(kAudioUnitScope_Global)
  109. SCOPE(kAudioUnitScope_Input)
  110. SCOPE(kAudioUnitScope_Output)
  111. SCOPE(kAudioUnitScope_Group)
  112. SCOPE(kAudioUnitScope_Part)
  113. SCOPE(kAudioUnitScope_Note)
  114. SCOPE(kAudioUnitScope_Layer)
  115. SCOPE(kAudioUnitScope_LayerItem)
  116. #undef SCOPE
  117. }
  118. return "[unknown]";
  119. }
  120. static const char* AudioUnitSelector2Str(const SInt16 selector) noexcept
  121. {
  122. switch (selector)
  123. {
  124. #define SEL(s) case s: return #s;
  125. SEL(kAudioUnitInitializeSelect)
  126. SEL(kAudioUnitUninitializeSelect)
  127. SEL(kAudioUnitGetPropertyInfoSelect)
  128. SEL(kAudioUnitGetPropertySelect)
  129. SEL(kAudioUnitSetPropertySelect)
  130. SEL(kAudioUnitAddPropertyListenerSelect)
  131. SEL(kAudioUnitRemovePropertyListenerSelect)
  132. SEL(kAudioUnitRemovePropertyListenerWithUserDataSelect)
  133. SEL(kAudioUnitAddRenderNotifySelect)
  134. SEL(kAudioUnitRemoveRenderNotifySelect)
  135. SEL(kAudioUnitGetParameterSelect)
  136. SEL(kAudioUnitSetParameterSelect)
  137. SEL(kAudioUnitScheduleParametersSelect)
  138. SEL(kAudioUnitRenderSelect)
  139. SEL(kAudioUnitResetSelect)
  140. SEL(kAudioUnitComplexRenderSelect)
  141. SEL(kAudioUnitProcessSelect)
  142. SEL(kAudioUnitProcessMultipleSelect)
  143. SEL(kMusicDeviceMIDIEventSelect)
  144. SEL(kMusicDeviceSysExSelect)
  145. SEL(kMusicDevicePrepareInstrumentSelect)
  146. SEL(kMusicDeviceReleaseInstrumentSelect)
  147. SEL(kMusicDeviceStartNoteSelect)
  148. SEL(kMusicDeviceStopNoteSelect)
  149. SEL(kMusicDeviceMIDIEventListSelect)
  150. SEL(kAudioOutputUnitStartSelect)
  151. SEL(kAudioOutputUnitStopSelect)
  152. #undef SEL
  153. }
  154. return "[unknown]";
  155. }
  156. static constexpr FourCharCode getFourCharCodeFromString(const char str[4])
  157. {
  158. return (str[0] << 24) + (str[1] << 16) + (str[2] << 8) + str[3];
  159. }
  160. // --------------------------------------------------------------------------------------------------------------------
  161. #define MACRO_STR2(s) #s
  162. #define MACRO_STR(s) MACRO_STR2(s)
  163. static constexpr const char kTypeStr[] = MACRO_STR(DISTRHO_PLUGIN_AU_TYPE);
  164. static constexpr const char kSubTypeStr[] = MACRO_STR(DISTRHO_PLUGIN_AU_SUBTYPE);
  165. static constexpr const char kManufacturerStr[] = MACRO_STR(DISTRHO_PLUGIN_AU_MANUFACTURER);
  166. #undef MACRO_STR
  167. #undef MACRO_STR2
  168. static constexpr const FourCharCode kType = getFourCharCodeFromString(kTypeStr);
  169. static constexpr const FourCharCode kSubType = getFourCharCodeFromString(kSubTypeStr);
  170. static constexpr const FourCharCode kManufacturer = getFourCharCodeFromString(kManufacturerStr);
  171. // --------------------------------------------------------------------------------------------------------------------
  172. struct PropertyListener {
  173. AudioUnitPropertyID prop;
  174. AudioUnitPropertyListenerProc proc;
  175. void* userData;
  176. };
  177. typedef std::vector<PropertyListener> PropertyListeners;
  178. // --------------------------------------------------------------------------------------------------------------------
  179. typedef struct {
  180. UInt32 numPackets;
  181. MIDIPacket packets[kMaxMidiEvents];
  182. } MIDIPacketList;
  183. // --------------------------------------------------------------------------------------------------------------------
  184. #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  185. static constexpr const writeMidiFunc writeMidiCallback = nullptr;
  186. #endif
  187. #if ! DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
  188. static constexpr const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr;
  189. #endif
  190. #if ! DISTRHO_PLUGIN_WANT_STATE
  191. static constexpr const updateStateValueFunc updateStateValueCallback = nullptr;
  192. #endif
  193. class PluginAU
  194. {
  195. public:
  196. PluginAU(const AudioUnit component)
  197. : fPlugin(this, writeMidiCallback, requestParameterValueChangeCallback, updateStateValueCallback),
  198. fComponent(component),
  199. fLastRenderError(noErr),
  200. fPropertyListeners(),
  201. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  202. fSampleRateForInput(d_nextSampleRate),
  203. #endif
  204. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  205. fSampleRateForOutput(d_nextSampleRate),
  206. #endif
  207. fParameterCount(fPlugin.getParameterCount()),
  208. fLastParameterValues(nullptr),
  209. fBypassParameterIndex(UINT32_MAX)
  210. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  211. , fMidiEventCount(0)
  212. #endif
  213. {
  214. if (fParameterCount != 0)
  215. {
  216. fLastParameterValues = new float[fParameterCount];
  217. std::memset(fLastParameterValues, 0, sizeof(float) * fParameterCount);
  218. for (uint32_t i=0; i<fParameterCount; ++i)
  219. {
  220. fLastParameterValues[i] = fPlugin.getParameterValue(i);
  221. if (fPlugin.getParameterDesignation(i) == kParameterDesignationBypass)
  222. fBypassParameterIndex = i;
  223. }
  224. }
  225. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  226. std::memset(&fMidiEvents, 0, sizeof(fMidiEvents));
  227. #endif
  228. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  229. std::memset(&fMidiOutput, 0, sizeof(fMidiOutput));
  230. std::memset(&fMidiOutputPackets, 0, sizeof(fMidiOutputPackets));
  231. #endif
  232. }
  233. ~PluginAU()
  234. {
  235. delete[] fLastParameterValues;
  236. }
  237. OSStatus auInitialize()
  238. {
  239. fPlugin.activate();
  240. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  241. fMidiEventCount = 0;
  242. #endif
  243. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  244. fMidiOutputPackets.numPackets = 0;
  245. #endif
  246. return noErr;
  247. }
  248. OSStatus auUninitialize()
  249. {
  250. fPlugin.deactivateIfNeeded();
  251. return noErr;
  252. }
  253. OSStatus auGetPropertyInfo(const AudioUnitPropertyID inProp,
  254. const AudioUnitScope inScope,
  255. const AudioUnitElement inElement,
  256. UInt32& outDataSize,
  257. Boolean& outWritable)
  258. {
  259. switch (inProp)
  260. {
  261. case kAudioUnitProperty_ClassInfo:
  262. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  263. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  264. outDataSize = sizeof(CFPropertyListRef);
  265. outWritable = true;
  266. return noErr;
  267. case kAudioUnitProperty_MakeConnection:
  268. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global || inScope == kAudioUnitScope_Input, inScope, kAudioUnitErr_InvalidScope);
  269. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  270. outDataSize = sizeof(AudioUnitConnection);
  271. outWritable = true;
  272. return noErr;
  273. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  274. case kAudioUnitProperty_SampleRate:
  275. #if DISTRHO_PLUGIN_NUM_INPUTS != 0 && DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  276. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Output, inScope, kAudioUnitErr_InvalidScope);
  277. #elif DISTRHO_PLUGIN_NUM_INPUTS != 0
  278. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Input, inScope, kAudioUnitErr_InvalidScope);
  279. #else
  280. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Output, inScope, kAudioUnitErr_InvalidScope);
  281. #endif
  282. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  283. outDataSize = sizeof(Float64);
  284. outWritable = true;
  285. return noErr;
  286. #endif
  287. case kAudioUnitProperty_ParameterList:
  288. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  289. outDataSize = inScope == kAudioUnitScope_Global ? sizeof(AudioUnitParameterID) * fParameterCount : 0;
  290. outWritable = false;
  291. return noErr;
  292. case kAudioUnitProperty_ParameterInfo:
  293. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  294. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement < fParameterCount, inElement, kAudioUnitErr_InvalidElement);
  295. outDataSize = sizeof(AudioUnitParameterInfo);
  296. outWritable = false;
  297. return noErr;
  298. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  299. case kAudioUnitProperty_StreamFormat:
  300. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  301. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  302. if (inScope == kAudioUnitScope_Input)
  303. {
  304. outDataSize = sizeof(AudioStreamBasicDescription);
  305. outWritable = true;
  306. return noErr;
  307. }
  308. #endif
  309. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  310. if (inScope == kAudioUnitScope_Output)
  311. {
  312. outDataSize = sizeof(AudioStreamBasicDescription);
  313. outWritable = true;
  314. return noErr;
  315. }
  316. #endif
  317. return kAudioUnitErr_InvalidScope;
  318. #endif
  319. case kAudioUnitProperty_ElementCount:
  320. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  321. outDataSize = sizeof(UInt32);
  322. outWritable = false;
  323. return noErr;
  324. case kAudioUnitProperty_Latency:
  325. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  326. #if DISTRHO_PLUGIN_WANT_LATENCY
  327. if (inScope == kAudioUnitScope_Global)
  328. {
  329. outDataSize = sizeof(Float64);
  330. outWritable = false;
  331. return noErr;
  332. }
  333. #endif
  334. return kAudioUnitErr_InvalidProperty;
  335. case kAudioUnitProperty_SupportedNumChannels:
  336. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  337. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  338. outDataSize = sizeof(AUChannelInfo);
  339. outWritable = false;
  340. return noErr;
  341. case kAudioUnitProperty_MaximumFramesPerSlice:
  342. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  343. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  344. outDataSize = sizeof(UInt32);
  345. outWritable = true;
  346. return noErr;
  347. case kAudioUnitProperty_BypassEffect:
  348. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  349. if (inScope == kAudioUnitScope_Global && fBypassParameterIndex != UINT32_MAX)
  350. {
  351. outDataSize = sizeof(UInt32);
  352. outWritable = false;
  353. return noErr;
  354. }
  355. return kAudioUnitErr_InvalidProperty;
  356. case kAudioUnitProperty_LastRenderError:
  357. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  358. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  359. outDataSize = sizeof(OSStatus);
  360. outWritable = false;
  361. return noErr;
  362. case kAudioUnitProperty_SetRenderCallback:
  363. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Input, inScope, kAudioUnitErr_InvalidScope);
  364. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  365. outDataSize = sizeof(AURenderCallbackStruct);
  366. outWritable = true;
  367. return noErr;
  368. case kAudioUnitProperty_InPlaceProcessing:
  369. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  370. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  371. outDataSize = sizeof(UInt32);
  372. outWritable = false;
  373. return noErr;
  374. case kAudioUnitProperty_PresentPreset:
  375. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  376. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  377. outDataSize = sizeof(AUPreset);
  378. outWritable = true;
  379. return noErr;
  380. case kAudioUnitProperty_CocoaUI:
  381. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  382. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  383. #if DISTRHO_PLUGIN_HAS_UI
  384. outDataSize = sizeof(AudioUnitCocoaViewInfo);
  385. outWritable = false;
  386. return noErr;
  387. #else
  388. return kAudioUnitErr_InvalidProperty;
  389. #endif
  390. case kAudioUnitProperty_MIDIOutputCallbackInfo:
  391. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  392. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  393. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  394. outDataSize = sizeof(CFArrayRef);
  395. outWritable = false;
  396. return noErr;
  397. #else
  398. return kAudioUnitErr_InvalidProperty;
  399. #endif
  400. case kAudioUnitProperty_MIDIOutputCallback:
  401. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  402. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  403. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  404. outDataSize = sizeof(AUMIDIOutputCallbackStruct);
  405. outWritable = true;
  406. return noErr;
  407. #else
  408. return kAudioUnitErr_InvalidProperty;
  409. #endif
  410. case kAudioUnitProperty_AudioUnitMIDIProtocol:
  411. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  412. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  413. // FIXME implement the event list stuff
  414. #if 0 && (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT)
  415. outDataSize = sizeof(SInt32);
  416. outWritable = false;
  417. return noErr;
  418. #else
  419. return kAudioUnitErr_InvalidProperty;
  420. #endif
  421. #if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  422. case 'DPFa':
  423. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  424. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  425. outDataSize = sizeof(void*);
  426. outWritable = false;
  427. return noErr;
  428. #endif
  429. case 'DPFe':
  430. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  431. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement < fParameterCount, inElement, kAudioUnitErr_InvalidElement);
  432. outDataSize = sizeof(bool);
  433. outWritable = true;
  434. return noErr;
  435. case 'DPFp':
  436. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  437. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement < fParameterCount, inElement, kAudioUnitErr_InvalidElement);
  438. outDataSize = sizeof(float);
  439. outWritable = true;
  440. return noErr;
  441. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT && DISTRHO_PLUGIN_HAS_UI
  442. case 'DPFn':
  443. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  444. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  445. outDataSize = sizeof(uint8_t) * 3;
  446. outWritable = true;
  447. return noErr;
  448. #endif
  449. #if DISTRHO_PLUGIN_WANT_STATE
  450. case 'DPFs':
  451. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  452. DISTRHO_SAFE_ASSERT_RETURN(inElement != 0, kAudioUnitErr_InvalidElement);
  453. outDataSize = inElement;
  454. outWritable = true;
  455. return noErr;
  456. #endif
  457. // unwanted properties
  458. case kAudioUnitProperty_CPULoad:
  459. case kAudioUnitProperty_RenderContextObserver:
  460. case kAudioUnitProperty_TailTime:
  461. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS == 0
  462. case kAudioUnitProperty_SampleRate:
  463. case kAudioUnitProperty_StreamFormat:
  464. #endif
  465. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  466. return kAudioUnitErr_InvalidProperty;
  467. }
  468. d_stdout("TODO GetPropertyInfo(%2d:%s, %d:%s, %d, ...)", inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement);
  469. return kAudioUnitErr_InvalidProperty;
  470. }
  471. OSStatus auGetProperty(const AudioUnitPropertyID inProp,
  472. const AudioUnitScope inScope,
  473. const AudioUnitElement inElement,
  474. void* const outData)
  475. {
  476. switch (inProp)
  477. {
  478. case kAudioUnitProperty_ClassInfo:
  479. {
  480. CFPropertyListRef* const propList = static_cast<CFPropertyListRef*>(outData);
  481. CFMutableDictionaryRef clsInfo = CFDictionaryCreateMutable(nullptr,
  482. 0,
  483. &kCFTypeDictionaryKeyCallBacks,
  484. &kCFTypeDictionaryValueCallBacks);
  485. SInt32 value;
  486. value = 0;
  487. if (const CFNumberRef num = CFNumberCreate(nullptr, kCFNumberSInt32Type, &value))
  488. {
  489. CFDictionarySetValue(clsInfo, CFSTR(kAUPresetVersionKey), num);
  490. CFRelease(num);
  491. }
  492. value = kType;
  493. if (const CFNumberRef num = CFNumberCreate(nullptr, kCFNumberSInt32Type, &value))
  494. {
  495. CFDictionarySetValue(clsInfo, CFSTR(kAUPresetTypeKey), num);
  496. CFRelease(num);
  497. }
  498. value = kSubType;
  499. if (const CFNumberRef num = CFNumberCreate(nullptr, kCFNumberSInt32Type, &value))
  500. {
  501. CFDictionarySetValue(clsInfo, CFSTR(kAUPresetSubtypeKey), num);
  502. CFRelease(num);
  503. }
  504. value = kManufacturer;
  505. if (const CFNumberRef num = CFNumberCreate(nullptr, kCFNumberSInt32Type, &value))
  506. {
  507. CFDictionarySetValue(clsInfo, CFSTR(kAUPresetManufacturerKey), num);
  508. CFRelease(num);
  509. }
  510. if (const CFMutableDictionaryRef data = CFDictionaryCreateMutable(nullptr,
  511. 0,
  512. &kCFTypeDictionaryKeyCallBacks,
  513. &kCFTypeDictionaryValueCallBacks))
  514. {
  515. // TODO save plugin state here
  516. d_stdout("WIP GetProperty(%d:%s, %d:%s, %d, ...)",
  517. inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement);
  518. if (fParameterCount != 0)
  519. {
  520. CFMutableArrayRef params = CFArrayCreateMutable(nullptr, fParameterCount, &kCFTypeArrayCallBacks);
  521. for (uint32_t i=0; i<fParameterCount; ++i)
  522. {
  523. if (fPlugin.isParameterOutputOrTrigger(i))
  524. continue;
  525. const float valuef = fPlugin.getParameterValue(i);
  526. CFStringRef key = CFStringCreateWithCString(nullptr,
  527. fPlugin.getParameterSymbol(i),
  528. kCFStringEncodingASCII);
  529. CFNumberRef value = CFNumberCreate(nullptr, kCFNumberFloat32Type, &valuef);
  530. CFDictionaryRef dict = CFDictionaryCreate(nullptr,
  531. reinterpret_cast<const void**>(&key),
  532. reinterpret_cast<const void**>(&value),
  533. 1,
  534. &kCFTypeDictionaryKeyCallBacks,
  535. &kCFTypeDictionaryValueCallBacks);
  536. CFArrayAppendValue(params, dict);
  537. CFRelease(key);
  538. CFRelease(value);
  539. CFRelease(dict);
  540. }
  541. CFDictionarySetValue(data, CFSTR("params"), params);
  542. CFRelease(params);
  543. }
  544. CFDictionarySetValue(clsInfo, CFSTR(kAUPresetDataKey), data);
  545. CFRelease(data);
  546. }
  547. CFDictionarySetValue(clsInfo, CFSTR(kAUPresetNameKey), CFSTR("Default"));
  548. *propList = clsInfo;
  549. }
  550. return noErr;
  551. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  552. case kAudioUnitProperty_SampleRate:
  553. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  554. if (inScope == kAudioUnitScope_Input)
  555. {
  556. *static_cast<Float64*>(outData) = fSampleRateForInput;
  557. }
  558. else
  559. #endif
  560. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  561. if (inScope == kAudioUnitScope_Output)
  562. {
  563. *static_cast<Float64*>(outData) = fSampleRateForOutput;
  564. }
  565. else
  566. #endif
  567. {
  568. return kAudioUnitErr_InvalidScope;
  569. }
  570. return noErr;
  571. #endif
  572. case kAudioUnitProperty_ParameterList:
  573. {
  574. AudioUnitParameterID* const paramList = static_cast<AudioUnitParameterID*>(outData);
  575. for (uint32_t i=0; i<fParameterCount; ++i)
  576. paramList[i] = i;
  577. }
  578. return noErr;
  579. case kAudioUnitProperty_ParameterInfo:
  580. {
  581. AudioUnitParameterInfo* const info = static_cast<AudioUnitParameterInfo*>(outData);
  582. std::memset(info, 0, sizeof(*info));
  583. const ParameterRanges& ranges(fPlugin.getParameterRanges(inElement));
  584. info->flags = kAudioUnitParameterFlag_IsHighResolution
  585. | kAudioUnitParameterFlag_IsReadable
  586. | kAudioUnitParameterFlag_HasCFNameString;
  587. if (fPlugin.getParameterDesignation(inElement) == kParameterDesignationBypass)
  588. {
  589. info->flags |= kAudioUnitParameterFlag_IsWritable;
  590. info->unit = kAudioUnitParameterUnit_Generic;
  591. d_strncpy(info->name, "Bypass", sizeof(info->name));
  592. info->cfNameString = CFSTR("Bypass");
  593. }
  594. else
  595. {
  596. const uint32_t hints = fPlugin.getParameterHints(inElement);
  597. info->flags |= kAudioUnitParameterFlag_CFNameRelease;
  598. if (hints & kParameterIsOutput)
  599. {
  600. info->flags |= kAudioUnitParameterFlag_MeterReadOnly;
  601. }
  602. else
  603. {
  604. info->flags |= kAudioUnitParameterFlag_IsWritable;
  605. if ((hints & kParameterIsAutomatable) == 0x0)
  606. info->flags |= kAudioUnitParameterFlag_NonRealTime;
  607. }
  608. if (hints & kParameterIsBoolean)
  609. info->unit = kAudioUnitParameterUnit_Boolean;
  610. else if (hints & kParameterIsInteger)
  611. info->unit = kAudioUnitParameterUnit_Indexed;
  612. else
  613. info->unit = kAudioUnitParameterUnit_Generic;
  614. // | kAudioUnitParameterFlag_ValuesHaveStrings;
  615. const String& name(fPlugin.getParameterName(inElement));
  616. d_strncpy(info->name, name, sizeof(info->name));
  617. info->cfNameString = CFStringCreateWithCString(nullptr, name, kCFStringEncodingUTF8);
  618. }
  619. info->minValue = ranges.min;
  620. info->maxValue = ranges.max;
  621. info->defaultValue = ranges.def;
  622. }
  623. return noErr;
  624. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  625. case kAudioUnitProperty_StreamFormat:
  626. {
  627. AudioStreamBasicDescription* const desc = static_cast<AudioStreamBasicDescription*>(outData);
  628. std::memset(desc, 0, sizeof(*desc));
  629. if (inElement != 0)
  630. return kAudioUnitErr_InvalidElement;
  631. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  632. if (inScope == kAudioUnitScope_Input)
  633. {
  634. desc->mChannelsPerFrame = DISTRHO_PLUGIN_NUM_INPUTS;
  635. }
  636. else
  637. #endif
  638. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  639. if (inScope == kAudioUnitScope_Output)
  640. {
  641. desc->mChannelsPerFrame = DISTRHO_PLUGIN_NUM_OUTPUTS;
  642. }
  643. else
  644. #endif
  645. {
  646. return kAudioUnitErr_InvalidScope;
  647. }
  648. desc->mFormatID = kAudioFormatLinearPCM;
  649. desc->mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved;
  650. desc->mSampleRate = fPlugin.getSampleRate();
  651. desc->mBitsPerChannel = 32;
  652. desc->mBytesPerFrame = sizeof(float);
  653. desc->mBytesPerPacket = sizeof(float);
  654. desc->mFramesPerPacket = 1;
  655. }
  656. return noErr;
  657. #endif
  658. case kAudioUnitProperty_ElementCount:
  659. switch (inScope)
  660. {
  661. case kAudioUnitScope_Global:
  662. *static_cast<UInt32*>(outData) = 1;
  663. break;
  664. case kAudioUnitScope_Input:
  665. *static_cast<UInt32*>(outData) = DISTRHO_PLUGIN_NUM_INPUTS != 0 ? 1 : 0;
  666. break;
  667. case kAudioUnitScope_Output:
  668. *static_cast<UInt32*>(outData) = DISTRHO_PLUGIN_NUM_OUTPUTS != 0 ? 1 : 0;
  669. break;
  670. default:
  671. *static_cast<UInt32*>(outData) = 0;
  672. break;
  673. }
  674. return noErr;
  675. #if DISTRHO_PLUGIN_WANT_LATENCY
  676. case kAudioUnitProperty_Latency:
  677. *static_cast<Float64*>(outData) = static_cast<double>(fPlugin.getLatency()) / fPlugin.getSampleRate();
  678. return noErr;
  679. #endif
  680. case kAudioUnitProperty_SupportedNumChannels:
  681. *static_cast<AUChannelInfo*>(outData) = { DISTRHO_PLUGIN_NUM_INPUTS, DISTRHO_PLUGIN_NUM_OUTPUTS };
  682. return noErr;
  683. case kAudioUnitProperty_MaximumFramesPerSlice:
  684. *static_cast<UInt32*>(outData) = fPlugin.getBufferSize();
  685. return noErr;
  686. case kAudioUnitProperty_LastRenderError:
  687. *static_cast<OSStatus*>(outData) = fLastRenderError;
  688. fLastRenderError = noErr;
  689. return noErr;
  690. case kAudioUnitProperty_BypassEffect:
  691. *static_cast<OSStatus*>(outData) = fPlugin.getParameterValue(fBypassParameterIndex) > 0.5f ? 1 : 0;
  692. return noErr;
  693. case kAudioUnitProperty_SetRenderCallback:
  694. d_stdout("WIP GetProperty(%d:%s, %d:%s, %d, ...)", inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement);
  695. // TODO
  696. break;
  697. case kAudioUnitProperty_InPlaceProcessing:
  698. *static_cast<UInt32*>(outData) = 1;
  699. return noErr;
  700. case kAudioUnitProperty_PresentPreset:
  701. {
  702. AUPreset* const preset = static_cast<AUPreset*>(outData);
  703. std::memset(preset, 0, sizeof(*preset));
  704. preset->presetName = CFStringCreateWithCString(nullptr, "Default", kCFStringEncodingUTF8);
  705. }
  706. return noErr;
  707. #if DISTRHO_PLUGIN_HAS_UI
  708. case kAudioUnitProperty_CocoaUI:
  709. {
  710. AudioUnitCocoaViewInfo* const info = static_cast<AudioUnitCocoaViewInfo*>(outData);
  711. std::memset(info, 0, sizeof(*info));
  712. NSString* const bundlePathString = [[NSString alloc]
  713. initWithBytes:d_nextBundlePath
  714. length:strlen(d_nextBundlePath)
  715. encoding:NSUTF8StringEncoding];
  716. info->mCocoaAUViewBundleLocation = static_cast<CFURLRef>([[NSURL fileURLWithPath: bundlePathString] retain]);
  717. #define MACRO_STR3(a, b, c) a "_" b "_" c
  718. #define MACRO_STR2(a, b, c) MACRO_STR3(#a, #b, #c)
  719. #define MACRO_STR(a, b, c) MACRO_STR2(a, b, c)
  720. info->mCocoaAUViewClass[0] = CFSTR("CocoaAUView_" MACRO_STR(DISTRHO_PLUGIN_AU_TYPE,
  721. DISTRHO_PLUGIN_AU_SUBTYPE,
  722. DISTRHO_PLUGIN_AU_MANUFACTURER));
  723. #undef MACRO_STR
  724. #undef MACRO_STR2
  725. #undef MACRO_STR3
  726. [bundlePathString release];
  727. }
  728. return noErr;
  729. #endif
  730. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  731. case kAudioUnitProperty_MIDIOutputCallbackInfo:
  732. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  733. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  734. {
  735. CFStringRef refs[1] = { CFSTR("MIDI Output") };
  736. *static_cast<CFArrayRef*>(outData) = CFArrayCreate(nullptr,
  737. reinterpret_cast<const void**>(refs),
  738. 1,
  739. &kCFTypeArrayCallBacks);
  740. }
  741. return noErr;
  742. #endif
  743. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  744. /* FIXME implement the event list stuff
  745. case kAudioUnitProperty_AudioUnitMIDIProtocol:
  746. *static_cast<SInt32*>(outData) = kMIDIProtocol_1_0;
  747. return noErr;
  748. */
  749. #endif
  750. #if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  751. case 'DPFa':
  752. *static_cast<void**>(outData) = fPlugin.getInstancePointer();
  753. return noErr;
  754. #endif
  755. }
  756. d_stdout("TODO GetProperty(%d:%s, %d:%s, %d, ...)", inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement);
  757. return kAudioUnitErr_InvalidProperty;
  758. }
  759. OSStatus auSetProperty(const AudioUnitPropertyID inProp,
  760. const AudioUnitScope inScope,
  761. const AudioUnitElement inElement,
  762. const void* const inData,
  763. const UInt32 inDataSize)
  764. {
  765. switch (inProp)
  766. {
  767. case kAudioUnitProperty_ClassInfo:
  768. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  769. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  770. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(CFPropertyListRef), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  771. {
  772. const CFPropertyListRef propList = *static_cast<const CFPropertyListRef*>(inData);
  773. DISTRHO_SAFE_ASSERT_RETURN(CFGetTypeID(propList) == CFDictionaryGetTypeID(), kAudioUnitErr_InvalidPropertyValue);
  774. const CFDictionaryRef clsInfo = static_cast<CFDictionaryRef>(propList);
  775. CFDictionaryRef data = nullptr;
  776. if (CFDictionaryGetValueIfPresent(clsInfo, CFSTR(kAUPresetDataKey), reinterpret_cast<const void**>(&data)))
  777. {
  778. DISTRHO_SAFE_ASSERT_RETURN(CFGetTypeID(data) == CFDictionaryGetTypeID(), kAudioUnitErr_InvalidPropertyValue);
  779. CFArrayRef params = nullptr;
  780. if (CFDictionaryGetValueIfPresent(data, CFSTR("params"), reinterpret_cast<const void**>(&params))
  781. && CFGetTypeID(params) == CFArrayGetTypeID())
  782. {
  783. const CFIndex numParams = CFArrayGetCount(params);
  784. CFStringRef keyRef;
  785. CFNumberRef valueRef;
  786. uint32_t index;
  787. float value;
  788. char* symbol = nullptr;
  789. CFIndex symbolLen = -1;
  790. for (CFIndex i=0; i<numParams; ++i)
  791. {
  792. const CFDictionaryRef param = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(params, i));
  793. DISTRHO_SAFE_ASSERT_BREAK(CFGetTypeID(param) == CFDictionaryGetTypeID());
  794. DISTRHO_SAFE_ASSERT_BREAK(CFDictionaryGetCount(param) == 1);
  795. keyRef = nullptr;
  796. valueRef = nullptr;
  797. CFDictionaryGetKeysAndValues(param,
  798. reinterpret_cast<const void**>(&keyRef),
  799. reinterpret_cast<const void**>(&valueRef));
  800. DISTRHO_SAFE_ASSERT_BREAK(keyRef != nullptr);
  801. DISTRHO_SAFE_ASSERT_BREAK(valueRef != nullptr);
  802. DISTRHO_SAFE_ASSERT_BREAK(CFGetTypeID(keyRef) == CFStringGetTypeID());
  803. DISTRHO_SAFE_ASSERT_BREAK(CFGetTypeID(valueRef) == CFNumberGetTypeID());
  804. DISTRHO_SAFE_ASSERT_BREAK(CFNumberGetValue(valueRef, kCFNumberFloat32Type, &value));
  805. const CFIndex keyLen = CFStringGetLength(keyRef);
  806. if (symbolLen < keyLen)
  807. {
  808. symbolLen = keyLen;
  809. symbol = static_cast<char*>(std::realloc(symbol, symbolLen + 1));
  810. }
  811. DISTRHO_SAFE_ASSERT_BREAK(CFStringGetCString(keyRef, symbol, symbolLen + 1, kCFStringEncodingASCII));
  812. DISTRHO_SAFE_ASSERT_BREAK(fPlugin.getParameterIndexForSymbol(symbol, index));
  813. fLastParameterValues[index] = value;
  814. fPlugin.setParameterValue(index, value);
  815. notifyListeners('DPFP', kAudioUnitScope_Global, index);
  816. }
  817. }
  818. }
  819. }
  820. // TODO
  821. d_stdout("WIP SetProperty(%d:%s, %d:%s, %d, %p, %u)",
  822. inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement, inData, inDataSize);
  823. return noErr;
  824. case kAudioUnitProperty_MakeConnection:
  825. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global || inScope == kAudioUnitScope_Input, inScope, kAudioUnitErr_InvalidScope);
  826. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  827. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(AudioUnitConnection), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  828. d_stdout("WIP SetProperty(%d:%s, %d:%s, %d, %p, %u)", inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement, inData, inDataSize);
  829. // TODO
  830. return noErr;
  831. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  832. case kAudioUnitProperty_SampleRate:
  833. #if DISTRHO_PLUGIN_NUM_INPUTS != 0 && DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  834. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Output, inScope, kAudioUnitErr_InvalidScope);
  835. #elif DISTRHO_PLUGIN_NUM_INPUTS != 0
  836. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Input, inScope, kAudioUnitErr_InvalidScope);
  837. #else
  838. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Output, inScope, kAudioUnitErr_InvalidScope);
  839. #endif
  840. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  841. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(Float64), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  842. {
  843. const Float64 sampleRate = *static_cast<const Float64*>(inData);
  844. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  845. if (inScope == kAudioUnitScope_Input)
  846. {
  847. if (d_isNotEqual(fSampleRateForInput, sampleRate))
  848. {
  849. fSampleRateForInput = sampleRate;
  850. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  851. if (d_isEqual(fSampleRateForOutput, sampleRate))
  852. #endif
  853. {
  854. fPlugin.setSampleRate(sampleRate, true);
  855. }
  856. notifyListeners(inProp, inScope, inElement);
  857. }
  858. return noErr;
  859. }
  860. #endif
  861. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  862. if (inScope == kAudioUnitScope_Output)
  863. {
  864. if (d_isNotEqual(fSampleRateForOutput, sampleRate))
  865. {
  866. fSampleRateForOutput = sampleRate;
  867. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  868. if (d_isEqual(fSampleRateForInput, sampleRate))
  869. #endif
  870. {
  871. fPlugin.setSampleRate(sampleRate, true);
  872. }
  873. notifyListeners(inProp, inScope, inElement);
  874. }
  875. return noErr;
  876. }
  877. #endif
  878. }
  879. return kAudioUnitErr_InvalidScope;
  880. #endif
  881. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  882. case kAudioUnitProperty_StreamFormat:
  883. #if DISTRHO_PLUGIN_NUM_INPUTS != 0 && DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  884. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Input || inScope == kAudioUnitScope_Output, inScope, kAudioUnitErr_InvalidScope);
  885. #elif DISTRHO_PLUGIN_NUM_INPUTS != 0
  886. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Input, inScope, kAudioUnitErr_InvalidScope);
  887. #else
  888. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Output, inScope, kAudioUnitErr_InvalidScope);
  889. #endif
  890. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  891. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(AudioStreamBasicDescription), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  892. {
  893. const AudioStreamBasicDescription* const desc = static_cast<const AudioStreamBasicDescription*>(inData);
  894. if (desc->mFormatID != kAudioFormatLinearPCM)
  895. return kAudioUnitErr_FormatNotSupported;
  896. if (desc->mBitsPerChannel != 32)
  897. return kAudioUnitErr_FormatNotSupported;
  898. if (desc->mBytesPerFrame != sizeof(float))
  899. return kAudioUnitErr_FormatNotSupported;
  900. if (desc->mBytesPerPacket != sizeof(float))
  901. return kAudioUnitErr_FormatNotSupported;
  902. if (desc->mFramesPerPacket != 1)
  903. return kAudioUnitErr_FormatNotSupported;
  904. #if 1
  905. // dont allow interleaved data
  906. if (desc->mFormatFlags != (kAudioFormatFlagsNativeFloatPacked|kAudioFormatFlagIsNonInterleaved))
  907. #else
  908. // allow interleaved data
  909. if ((desc->mFormatFlags & ~kAudioFormatFlagIsNonInterleaved) != kAudioFormatFlagsNativeFloatPacked)
  910. #endif
  911. return kAudioUnitErr_FormatNotSupported;
  912. if (desc->mChannelsPerFrame != (inScope == kAudioUnitScope_Input ? DISTRHO_PLUGIN_NUM_INPUTS
  913. : DISTRHO_PLUGIN_NUM_OUTPUTS))
  914. return kAudioUnitErr_FormatNotSupported;
  915. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  916. if (inScope == kAudioUnitScope_Input)
  917. {
  918. if (d_isNotEqual(fSampleRateForInput, desc->mSampleRate))
  919. {
  920. fSampleRateForInput = desc->mSampleRate;
  921. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  922. if (d_isEqual(fSampleRateForOutput, desc->mSampleRate))
  923. #endif
  924. {
  925. fPlugin.setSampleRate(desc->mSampleRate, true);
  926. }
  927. notifyListeners(inProp, inScope, inElement);
  928. }
  929. return noErr;
  930. }
  931. #endif
  932. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  933. if (inScope == kAudioUnitScope_Output)
  934. {
  935. if (d_isNotEqual(fSampleRateForOutput, desc->mSampleRate))
  936. {
  937. fSampleRateForOutput = desc->mSampleRate;
  938. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  939. if (d_isEqual(fSampleRateForInput, desc->mSampleRate))
  940. #endif
  941. {
  942. fPlugin.setSampleRate(desc->mSampleRate, true);
  943. }
  944. notifyListeners(inProp, inScope, inElement);
  945. }
  946. return noErr;
  947. }
  948. #endif
  949. }
  950. return kAudioUnitErr_InvalidScope;
  951. #endif
  952. case kAudioUnitProperty_MaximumFramesPerSlice:
  953. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  954. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  955. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(UInt32), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  956. if (fPlugin.setBufferSize(*static_cast<const UInt32*>(inData), true))
  957. notifyListeners(inProp, inScope, inElement);
  958. return noErr;
  959. case kAudioUnitProperty_BypassEffect:
  960. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  961. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  962. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(UInt32), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  963. DISTRHO_SAFE_ASSERT_RETURN(fBypassParameterIndex != UINT32_MAX, kAudioUnitErr_InvalidPropertyValue);
  964. {
  965. const bool bypass = *static_cast<const UInt32*>(inData) != 0;
  966. if ((fLastParameterValues[fBypassParameterIndex] > 0.5f) != bypass)
  967. {
  968. const float value = bypass ? 1.f : 0.f;
  969. fLastParameterValues[fBypassParameterIndex] = value;
  970. fPlugin.setParameterValue(fBypassParameterIndex, value);
  971. notifyListeners(inProp, inScope, inElement);
  972. }
  973. }
  974. return noErr;
  975. case kAudioUnitProperty_SetRenderCallback:
  976. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Input, inScope, kAudioUnitErr_InvalidScope);
  977. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  978. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(AURenderCallbackStruct), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  979. d_stdout("WIP SetProperty(%d:%s, %d:%s, %d, %p, %u)", inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement, inData, inDataSize);
  980. // TODO
  981. return noErr;
  982. case kAudioUnitProperty_PresentPreset:
  983. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  984. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  985. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(AUPreset), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  986. d_stdout("WIP SetProperty(%d:%s, %d:%s, %d, %p, %u)", inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement, inData, inDataSize);
  987. // TODO
  988. return noErr;
  989. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  990. case kAudioUnitProperty_MIDIOutputCallback:
  991. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  992. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  993. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(AUMIDIOutputCallbackStruct), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  994. std::memcpy(&fMidiOutput, inData, sizeof(AUMIDIOutputCallbackStruct));
  995. return noErr;
  996. #endif
  997. case 'DPFe':
  998. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  999. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement < fParameterCount, inElement, kAudioUnitErr_InvalidElement);
  1000. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(bool), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  1001. {
  1002. const bool started = *static_cast<const bool*>(inData);
  1003. AudioUnitEvent event;
  1004. std::memset(&event, 0, sizeof(event));
  1005. event.mEventType = started ? kAudioUnitEvent_BeginParameterChangeGesture
  1006. : kAudioUnitEvent_EndParameterChangeGesture;
  1007. event.mArgument.mParameter.mAudioUnit = fComponent;
  1008. event.mArgument.mParameter.mParameterID = inElement;
  1009. event.mArgument.mParameter.mScope = kAudioUnitScope_Global;
  1010. AUEventListenerNotify(NULL, NULL, &event);
  1011. }
  1012. return noErr;
  1013. case 'DPFp':
  1014. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  1015. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement < fParameterCount, inElement, kAudioUnitErr_InvalidElement);
  1016. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(float), inDataSize, kAudioUnitErr_InvalidPropertyValue);
  1017. {
  1018. const float value = *static_cast<const float*>(inData);
  1019. DISTRHO_SAFE_ASSERT_RETURN(std::isfinite(value), kAudioUnitErr_InvalidParameterValue);
  1020. fLastParameterValues[inElement] = value;
  1021. fPlugin.setParameterValue(inElement, value);
  1022. AudioUnitEvent event;
  1023. std::memset(&event, 0, sizeof(event));
  1024. event.mEventType = kAudioUnitEvent_ParameterValueChange;
  1025. event.mArgument.mParameter.mAudioUnit = fComponent;
  1026. event.mArgument.mParameter.mParameterID = inElement;
  1027. event.mArgument.mParameter.mScope = kAudioUnitScope_Global;
  1028. AUEventListenerNotify(NULL, NULL, &event);
  1029. }
  1030. return noErr;
  1031. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT && DISTRHO_PLUGIN_HAS_UI
  1032. case 'DPFn':
  1033. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  1034. DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement);
  1035. DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(uint8_t) * 3, inDataSize, kAudioUnitErr_InvalidPropertyValue);
  1036. {
  1037. const uint8_t* const midiData = static_cast<const uint8_t*>(inData);
  1038. fNotesRingBuffer.writeCustomData(midiData, 3);
  1039. fNotesRingBuffer.commitWrite();
  1040. }
  1041. return noErr;
  1042. #endif
  1043. #if DISTRHO_PLUGIN_WANT_STATE
  1044. case 'DPFs':
  1045. DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope);
  1046. DISTRHO_SAFE_ASSERT_RETURN(inElement != 0, kAudioUnitErr_InvalidElement);
  1047. DISTRHO_SAFE_ASSERT_UINT2_RETURN(inDataSize == inElement, inDataSize, inElement, kAudioUnitErr_InvalidPropertyValue);
  1048. {
  1049. const char* const key = static_cast<const char*>(inData);
  1050. const char* const value = key + std::strlen(key) + 1;
  1051. fPlugin.setState(key, value);
  1052. }
  1053. return noErr;
  1054. #endif
  1055. }
  1056. d_stdout("TODO SetProperty(%d:%s, %d:%s, %d, %p, %u)", inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement, inData, inDataSize);
  1057. return kAudioUnitErr_InvalidProperty;
  1058. }
  1059. OSStatus auAddPropertyListener(const AudioUnitPropertyID prop,
  1060. const AudioUnitPropertyListenerProc proc,
  1061. void* const userData)
  1062. {
  1063. const PropertyListener pl = {
  1064. prop, proc, userData
  1065. };
  1066. if (fPropertyListeners.empty())
  1067. fPropertyListeners.reserve(32);
  1068. fPropertyListeners.push_back(pl);
  1069. return noErr;
  1070. }
  1071. OSStatus auRemovePropertyListener(const AudioUnitPropertyID prop, const AudioUnitPropertyListenerProc proc)
  1072. {
  1073. for (PropertyListeners::iterator it = fPropertyListeners.begin(); it != fPropertyListeners.end(); ++it)
  1074. {
  1075. const PropertyListener& pl(*it);
  1076. if (pl.prop == prop && pl.proc == proc)
  1077. {
  1078. fPropertyListeners.erase(it);
  1079. return auRemovePropertyListener(prop, proc);
  1080. }
  1081. }
  1082. return noErr;
  1083. }
  1084. OSStatus auRemovePropertyListenerWithUserData(const AudioUnitPropertyID prop,
  1085. const AudioUnitPropertyListenerProc proc,
  1086. void* const userData)
  1087. {
  1088. for (PropertyListeners::iterator it = fPropertyListeners.begin(); it != fPropertyListeners.end(); ++it)
  1089. {
  1090. const PropertyListener& pl(*it);
  1091. if (pl.prop == prop && pl.proc == proc && pl.userData == userData)
  1092. {
  1093. fPropertyListeners.erase(it);
  1094. return auRemovePropertyListenerWithUserData(prop, proc, userData);
  1095. }
  1096. }
  1097. return noErr;
  1098. }
  1099. OSStatus auAddRenderNotify(const AURenderCallback proc, void* const userData)
  1100. {
  1101. d_stdout("WIP AddRenderNotify(%p, %p)", proc, userData);
  1102. // TODO
  1103. return noErr;
  1104. }
  1105. OSStatus auRemoveRenderNotify(const AURenderCallback proc, void* const userData)
  1106. {
  1107. d_stdout("WIP RemoveRenderNotify(%p, %p)", proc, userData);
  1108. // TODO
  1109. return noErr;
  1110. }
  1111. OSStatus auGetParameter(const AudioUnitParameterID param,
  1112. const AudioUnitScope scope,
  1113. const AudioUnitElement elem,
  1114. AudioUnitParameterValue* const value)
  1115. {
  1116. DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global, scope, kAudioUnitErr_InvalidScope);
  1117. DISTRHO_SAFE_ASSERT_UINT_RETURN(param < fParameterCount, param, kAudioUnitErr_InvalidElement);
  1118. DISTRHO_SAFE_ASSERT_UINT_RETURN(elem == 0, elem, kAudioUnitErr_InvalidElement);
  1119. DISTRHO_SAFE_ASSERT_RETURN(value != nullptr, kAudio_ParamError);
  1120. *value = fPlugin.getParameterValue(param);
  1121. return noErr;
  1122. }
  1123. OSStatus auSetParameter(const AudioUnitParameterID param,
  1124. const AudioUnitScope scope,
  1125. const AudioUnitElement elem,
  1126. const AudioUnitParameterValue value,
  1127. const UInt32 bufferOffset)
  1128. {
  1129. DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global, scope, kAudioUnitErr_InvalidScope);
  1130. DISTRHO_SAFE_ASSERT_UINT_RETURN(param < fParameterCount, param, kAudioUnitErr_InvalidElement);
  1131. DISTRHO_SAFE_ASSERT_UINT_RETURN(elem == 0, elem, kAudioUnitErr_InvalidElement);
  1132. DISTRHO_SAFE_ASSERT_RETURN(std::isfinite(value), kAudioUnitErr_InvalidParameterValue);
  1133. if (d_isNotEqual(fLastParameterValues[param], value))
  1134. {
  1135. fLastParameterValues[param] = value;
  1136. fPlugin.setParameterValue(param, value);
  1137. // TODO flag param only, notify listeners later on bg thread (sem_post etc)
  1138. notifyListeners('DPFP', kAudioUnitScope_Global, param);
  1139. }
  1140. return noErr;
  1141. }
  1142. OSStatus auScheduleParameters(const AudioUnitParameterEvent* const events, const UInt32 numEvents)
  1143. {
  1144. for (UInt32 i=0; i<numEvents; ++i)
  1145. {
  1146. const AudioUnitParameterEvent& event(events[i]);
  1147. if (event.eventType == kParameterEvent_Immediate)
  1148. {
  1149. auSetParameter(event.parameter,
  1150. event.scope,
  1151. event.element,
  1152. event.eventValues.immediate.value,
  1153. event.eventValues.immediate.bufferOffset);
  1154. }
  1155. else
  1156. {
  1157. // TODO?
  1158. d_stdout("WIP ScheduleParameters(%p, %u)", events, numEvents);
  1159. }
  1160. }
  1161. return noErr;
  1162. }
  1163. OSStatus auReset(const AudioUnitScope scope, const AudioUnitElement elem)
  1164. {
  1165. DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global || scope == kAudioUnitScope_Input || scope == kAudioUnitScope_Output, scope, kAudioUnitErr_InvalidScope);
  1166. DISTRHO_SAFE_ASSERT_UINT_RETURN(elem == 0, elem, kAudioUnitErr_InvalidElement);
  1167. if (fPlugin.isActive())
  1168. {
  1169. fPlugin.deactivate();
  1170. fPlugin.activate();
  1171. }
  1172. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1173. fMidiEventCount = 0;
  1174. #endif
  1175. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  1176. fMidiOutputPackets.numPackets = 0;
  1177. #endif
  1178. return noErr;
  1179. }
  1180. OSStatus auRender(AudioUnitRenderActionFlags& ioActionFlags,
  1181. const AudioTimeStamp& inTimeStamp,
  1182. const UInt32 inBusNumber,
  1183. const UInt32 inFramesToProcess,
  1184. AudioBufferList& ioData)
  1185. {
  1186. DISTRHO_SAFE_ASSERT_UINT_RETURN(inBusNumber == 0, inBusNumber, kAudioUnitErr_InvalidElement);
  1187. DISTRHO_SAFE_ASSERT_UINT_RETURN(ioData.mNumberBuffers == std::max<uint>(DISTRHO_PLUGIN_NUM_INPUTS, DISTRHO_PLUGIN_NUM_OUTPUTS), ioData.mNumberBuffers, kAudio_ParamError);
  1188. if (inFramesToProcess > fPlugin.getBufferSize())
  1189. {
  1190. setLastRenderError(kAudioUnitErr_TooManyFramesToProcess);
  1191. return kAudioUnitErr_TooManyFramesToProcess;
  1192. }
  1193. for (uint i=0; i<ioData.mNumberBuffers; ++i)
  1194. {
  1195. AudioBuffer& buffer(ioData.mBuffers[i]);
  1196. // TODO there must be something more to this...
  1197. if (buffer.mData == nullptr)
  1198. return noErr;
  1199. DISTRHO_SAFE_ASSERT_UINT_RETURN(buffer.mDataByteSize == inFramesToProcess * sizeof(float), buffer.mDataByteSize, kAudio_ParamError);
  1200. }
  1201. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  1202. const float* inputs[DISTRHO_PLUGIN_NUM_INPUTS];
  1203. for (uint16_t i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i)
  1204. {
  1205. inputs[i] = static_cast<const float*>(ioData.mBuffers[i].mData);
  1206. }
  1207. #else
  1208. constexpr const float** inputs = nullptr;
  1209. #endif
  1210. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1211. float* outputs[DISTRHO_PLUGIN_NUM_OUTPUTS];
  1212. for (uint16_t i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
  1213. {
  1214. outputs[i] = static_cast<float*>(ioData.mBuffers[i].mData);
  1215. }
  1216. #else
  1217. constexpr float** outputs = nullptr;
  1218. #endif
  1219. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  1220. fMidiOutputPackets.numPackets = 0;
  1221. #endif
  1222. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1223. #if DISTRHO_PLUGIN_HAS_UI
  1224. importRingBufferNotes();
  1225. #endif
  1226. fPlugin.run(inputs, outputs, inFramesToProcess, fMidiEvents, fMidiEventCount);
  1227. fMidiEventCount = 0;
  1228. #else
  1229. fPlugin.run(inputs, outputs, inFramesToProcess);
  1230. #endif
  1231. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  1232. if (fMidiOutputPackets.numPackets != 0 && fMidiOutput.midiOutputCallback != nullptr)
  1233. {
  1234. fMidiOutput.midiOutputCallback(fMidiOutput.userData,
  1235. &inTimeStamp,
  1236. 0,
  1237. reinterpret_cast<const ::MIDIPacketList*>(&fMidiOutputPackets));
  1238. }
  1239. #endif
  1240. float value;
  1241. AudioUnitEvent event;
  1242. std::memset(&event, 0, sizeof(event));
  1243. event.mEventType = kAudioUnitEvent_ParameterValueChange;
  1244. event.mArgument.mParameter.mAudioUnit = fComponent;
  1245. event.mArgument.mParameter.mScope = kAudioUnitScope_Global;
  1246. for (uint32_t i=0; i<fParameterCount; ++i)
  1247. {
  1248. if (fPlugin.isParameterOutputOrTrigger(i))
  1249. {
  1250. value = fPlugin.getParameterValue(i);
  1251. if (d_isEqual(fLastParameterValues[i], value))
  1252. continue;
  1253. fLastParameterValues[i] = value;
  1254. // TODO flag param only, notify listeners later on bg thread (sem_post etc)
  1255. event.mArgument.mParameter.mParameterID = i;
  1256. AUEventListenerNotify(NULL, NULL, &event);
  1257. notifyListeners('DPFP', kAudioUnitScope_Global, i);
  1258. }
  1259. }
  1260. return noErr;
  1261. #if ! DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  1262. // unused
  1263. (void)inTimeStamp;
  1264. #endif
  1265. }
  1266. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1267. OSStatus auMIDIEvent(const UInt32 inStatus,
  1268. const UInt32 inData1,
  1269. const UInt32 inData2,
  1270. const UInt32 inOffsetSampleFrame)
  1271. {
  1272. if (fMidiEventCount >= kMaxMidiEvents)
  1273. return noErr;
  1274. MidiEvent& midiEvent(fMidiEvents[fMidiEventCount++]);
  1275. midiEvent.frame = inOffsetSampleFrame;
  1276. midiEvent.data[0] = inStatus;
  1277. midiEvent.data[1] = inData1;
  1278. midiEvent.data[2] = inData2;
  1279. switch (inStatus)
  1280. {
  1281. case 0x80:
  1282. case 0x90:
  1283. case 0xA0:
  1284. case 0xB0:
  1285. case 0xD0:
  1286. case 0xE0:
  1287. midiEvent.size = 3;
  1288. break;
  1289. case 0xC0:
  1290. midiEvent.size = 2;
  1291. break;
  1292. default:
  1293. midiEvent.size = 1;
  1294. break;
  1295. }
  1296. // if plugin has no audio, assume render function is not going to be called
  1297. #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS == 0
  1298. #if DISTRHO_PLUGIN_HAS_UI
  1299. importRingBufferNotes();
  1300. #endif
  1301. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  1302. fMidiOutputPackets.numPackets = 0;
  1303. #endif
  1304. fPlugin.run(nullptr, nullptr, std::max(1u, inOffsetSampleFrame), fMidiEvents, fMidiEventCount);
  1305. fMidiEventCount = 0;
  1306. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  1307. if (fMidiOutputPackets.numPackets != 0 && fMidiOutput.midiOutputCallback != nullptr)
  1308. {
  1309. fMidiOutput.midiOutputCallback(fMidiOutput.userData,
  1310. nullptr, 0, // FIXME do we need a valid timestamp?
  1311. reinterpret_cast<const ::MIDIPacketList*>(&fMidiOutputPackets));
  1312. }
  1313. #endif
  1314. #endif
  1315. return noErr;
  1316. }
  1317. OSStatus auSysEx(const UInt8* const inData, const UInt32 inLength)
  1318. {
  1319. // TODO
  1320. return kAudioUnitErr_PropertyNotInUse;
  1321. }
  1322. #endif
  1323. // ----------------------------------------------------------------------------------------------------------------
  1324. private:
  1325. PluginExporter fPlugin;
  1326. // AU component
  1327. const AudioUnit fComponent;
  1328. // AUv2 related fields
  1329. OSStatus fLastRenderError;
  1330. PropertyListeners fPropertyListeners;
  1331. #if DISTRHO_PLUGIN_NUM_INPUTS != 0
  1332. Float64 fSampleRateForInput;
  1333. #endif
  1334. #if DISTRHO_PLUGIN_NUM_OUTPUTS != 0
  1335. Float64 fSampleRateForOutput;
  1336. #endif
  1337. // Caching
  1338. const uint32_t fParameterCount;
  1339. float* fLastParameterValues;
  1340. uint32_t fBypassParameterIndex;
  1341. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1342. uint32_t fMidiEventCount;
  1343. MidiEvent fMidiEvents[kMaxMidiEvents];
  1344. #if DISTRHO_PLUGIN_HAS_UI
  1345. SmallStackRingBuffer fNotesRingBuffer;
  1346. #endif
  1347. #endif
  1348. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  1349. AUMIDIOutputCallbackStruct fMidiOutput;
  1350. MIDIPacketList fMidiOutputPackets;
  1351. #endif
  1352. // ----------------------------------------------------------------------------------------------------------------
  1353. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT && DISTRHO_PLUGIN_HAS_UI
  1354. void importRingBufferNotes()
  1355. {
  1356. if (fMidiEventCount != kMaxMidiEvents && fNotesRingBuffer.isDataAvailableForReading())
  1357. {
  1358. uint8_t midiData[3];
  1359. const uint32_t frame = fMidiEventCount != 0 ? fMidiEvents[fMidiEventCount - 1].frame : 0;
  1360. while (fNotesRingBuffer.isDataAvailableForReading())
  1361. {
  1362. if (! fNotesRingBuffer.readCustomData(midiData, 3))
  1363. break;
  1364. MidiEvent& midiEvent(fMidiEvents[fMidiEventCount++]);
  1365. midiEvent.frame = frame;
  1366. midiEvent.size = 3;
  1367. std::memcpy(midiEvent.data, midiData, 3);
  1368. if (fMidiEventCount == kMaxMidiEvents)
  1369. break;
  1370. }
  1371. }
  1372. }
  1373. #endif
  1374. void notifyListeners(const AudioUnitPropertyID prop, const AudioUnitScope scope, const AudioUnitElement elem)
  1375. {
  1376. for (PropertyListeners::iterator it = fPropertyListeners.begin(); it != fPropertyListeners.end(); ++it)
  1377. {
  1378. const PropertyListener& pl(*it);
  1379. if (pl.prop == prop)
  1380. pl.proc(pl.userData, fComponent, prop, scope, elem);
  1381. }
  1382. }
  1383. void setLastRenderError(const OSStatus err)
  1384. {
  1385. if (fLastRenderError != noErr)
  1386. return;
  1387. fLastRenderError = err;
  1388. notifyListeners(kAudioUnitProperty_LastRenderError, kAudioUnitScope_Global, 0);
  1389. }
  1390. // ----------------------------------------------------------------------------------------------------------------
  1391. // DPF callbacks
  1392. #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  1393. bool writeMidi(const MidiEvent& midiEvent)
  1394. {
  1395. DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN("MIDI output unsupported", fMidiOutput.midiOutputCallback != nullptr, false);
  1396. if (midiEvent.size > sizeof(MIDIPacket::data))
  1397. return true;
  1398. if (fMidiOutputPackets.numPackets == kMaxMidiEvents)
  1399. return false;
  1400. const uint8_t* const midiData = midiEvent.size > MidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data;
  1401. MIDIPacket& packet(fMidiOutputPackets.packets[fMidiOutputPackets.numPackets++]);
  1402. packet.timeStamp = midiEvent.frame;
  1403. packet.length = midiEvent.size;
  1404. std::memcpy(packet.data, midiData, midiEvent.size);
  1405. return true;
  1406. }
  1407. static bool writeMidiCallback(void* const ptr, const MidiEvent& midiEvent)
  1408. {
  1409. return static_cast<PluginAU*>(ptr)->writeMidi(midiEvent);
  1410. }
  1411. #endif
  1412. #if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST
  1413. bool requestParameterValueChange(const uint32_t index, const float value)
  1414. {
  1415. AudioUnitEvent event;
  1416. std::memset(&event, 0, sizeof(event));
  1417. event.mEventType = kAudioUnitEvent_ParameterValueChange;
  1418. event.mArgument.mParameter.mAudioUnit = fComponent;
  1419. event.mArgument.mParameter.mParameterID = index;
  1420. event.mArgument.mParameter.mScope = kAudioUnitScope_Global;
  1421. fLastParameterValues[index] = value;
  1422. AUEventListenerNotify(NULL, NULL, &event);
  1423. notifyListeners('DPFP', kAudioUnitScope_Global, index);
  1424. return true;
  1425. }
  1426. static bool requestParameterValueChangeCallback(void* const ptr, const uint32_t index, const float value)
  1427. {
  1428. return static_cast<PluginAU*>(ptr)->requestParameterValueChange(index, value);
  1429. }
  1430. #endif
  1431. #if DISTRHO_PLUGIN_WANT_STATE
  1432. bool updateState(const char*, const char*)
  1433. {
  1434. return true;
  1435. }
  1436. static bool updateStateValueCallback(void* const ptr, const char* const key, const char* const value)
  1437. {
  1438. return static_cast<PluginAU*>(ptr)->updateState(key, value);
  1439. }
  1440. #endif
  1441. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginAU)
  1442. };
  1443. // --------------------------------------------------------------------------------------------------------------------
  1444. struct AudioComponentPlugInInstance {
  1445. AudioComponentPlugInInterface acpi;
  1446. PluginAU* plugin;
  1447. AudioComponentPlugInInstance() noexcept
  1448. : acpi(),
  1449. plugin(nullptr)
  1450. {
  1451. std::memset(&acpi, 0, sizeof(acpi));
  1452. acpi.Open = Open;
  1453. acpi.Close = Close;
  1454. acpi.Lookup = Lookup;
  1455. acpi.reserved = nullptr;
  1456. }
  1457. ~AudioComponentPlugInInstance()
  1458. {
  1459. delete plugin;
  1460. }
  1461. static OSStatus Open(void* const self, const AudioUnit component)
  1462. {
  1463. static_cast<AudioComponentPlugInInstance*>(self)->plugin = new PluginAU(component);
  1464. return noErr;
  1465. }
  1466. static OSStatus Close(void* const self)
  1467. {
  1468. delete static_cast<AudioComponentPlugInInstance*>(self);
  1469. return noErr;
  1470. }
  1471. static AudioComponentMethod Lookup(const SInt16 selector)
  1472. {
  1473. d_debug("AudioComponentPlugInInstance::Lookup(%3d:%s)", selector, AudioUnitSelector2Str(selector));
  1474. switch (selector)
  1475. {
  1476. case kAudioUnitInitializeSelect:
  1477. return reinterpret_cast<AudioComponentMethod>(Initialize);
  1478. case kAudioUnitUninitializeSelect:
  1479. return reinterpret_cast<AudioComponentMethod>(Uninitialize);
  1480. case kAudioUnitGetPropertyInfoSelect:
  1481. return reinterpret_cast<AudioComponentMethod>(GetPropertyInfo);
  1482. case kAudioUnitGetPropertySelect:
  1483. return reinterpret_cast<AudioComponentMethod>(GetProperty);
  1484. case kAudioUnitSetPropertySelect:
  1485. return reinterpret_cast<AudioComponentMethod>(SetProperty);
  1486. case kAudioUnitAddPropertyListenerSelect:
  1487. return reinterpret_cast<AudioComponentMethod>(AddPropertyListener);
  1488. case kAudioUnitRemovePropertyListenerSelect:
  1489. return reinterpret_cast<AudioComponentMethod>(RemovePropertyListener);
  1490. case kAudioUnitRemovePropertyListenerWithUserDataSelect:
  1491. return reinterpret_cast<AudioComponentMethod>(RemovePropertyListenerWithUserData);
  1492. case kAudioUnitAddRenderNotifySelect:
  1493. return reinterpret_cast<AudioComponentMethod>(AddRenderNotify);
  1494. case kAudioUnitRemoveRenderNotifySelect:
  1495. return reinterpret_cast<AudioComponentMethod>(RemoveRenderNotify);
  1496. case kAudioUnitGetParameterSelect:
  1497. return reinterpret_cast<AudioComponentMethod>(GetParameter);
  1498. case kAudioUnitSetParameterSelect:
  1499. return reinterpret_cast<AudioComponentMethod>(SetParameter);
  1500. case kAudioUnitScheduleParametersSelect:
  1501. return reinterpret_cast<AudioComponentMethod>(ScheduleParameters);
  1502. case kAudioUnitRenderSelect:
  1503. return reinterpret_cast<AudioComponentMethod>(Render);
  1504. /*
  1505. case kAudioUnitComplexRenderSelect:
  1506. return reinterpret_cast<AudioComponentMethod>(ComplexRender);
  1507. */
  1508. case kAudioUnitResetSelect:
  1509. return reinterpret_cast<AudioComponentMethod>(Reset);
  1510. /*
  1511. case kAudioUnitProcessSelect:
  1512. return reinterpret_cast<AudioComponentMethod>(Process);
  1513. case kAudioUnitProcessMultipleSelect:
  1514. return reinterpret_cast<AudioComponentMethod>(ProcessMultiple);
  1515. */
  1516. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1517. case kMusicDeviceMIDIEventSelect:
  1518. return reinterpret_cast<AudioComponentMethod>(MIDIEvent);
  1519. case kMusicDeviceSysExSelect:
  1520. return reinterpret_cast<AudioComponentMethod>(SysEx);
  1521. #endif
  1522. }
  1523. d_stdout("TODO Lookup(%3d:%s)", selector, AudioUnitSelector2Str(selector));
  1524. return nullptr;
  1525. }
  1526. static OSStatus Initialize(AudioComponentPlugInInstance* const self)
  1527. {
  1528. d_debug("AudioComponentPlugInInstance::Initialize(%p)", self);
  1529. return self->plugin->auInitialize();
  1530. }
  1531. static OSStatus Uninitialize(AudioComponentPlugInInstance* const self)
  1532. {
  1533. d_debug("AudioComponentPlugInInstance::Uninitialize(%p)", self);
  1534. return self->plugin->auUninitialize();
  1535. }
  1536. static OSStatus GetPropertyInfo(AudioComponentPlugInInstance* const self,
  1537. const AudioUnitPropertyID inProp,
  1538. const AudioUnitScope inScope,
  1539. const AudioUnitElement inElement,
  1540. UInt32* const outDataSize,
  1541. Boolean* const outWritable)
  1542. {
  1543. d_debug("AudioComponentPlugInInstance::GetPropertyInfo(%p, %2d:%s, %d:%s, %d, ...)",
  1544. self, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement);
  1545. UInt32 dataSize = 0;
  1546. Boolean writable = false;
  1547. const OSStatus res = self->plugin->auGetPropertyInfo(inProp, inScope, inElement, dataSize, writable);
  1548. if (outDataSize != nullptr)
  1549. *outDataSize = dataSize;
  1550. if (outWritable != nullptr)
  1551. *outWritable = writable;
  1552. return res;
  1553. }
  1554. static OSStatus GetProperty(AudioComponentPlugInInstance* const self,
  1555. const AudioUnitPropertyID inProp,
  1556. const AudioUnitScope inScope,
  1557. const AudioUnitElement inElement,
  1558. void* const outData,
  1559. UInt32* const ioDataSize)
  1560. {
  1561. d_debug("AudioComponentPlugInInstance::GetProperty (%p, %2d:%s, %d:%s, %d, ...)",
  1562. self, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement);
  1563. DISTRHO_SAFE_ASSERT_RETURN(ioDataSize != nullptr, kAudio_ParamError);
  1564. Boolean writable;
  1565. UInt32 outDataSize = 0;
  1566. OSStatus res;
  1567. if (outData == nullptr)
  1568. {
  1569. res = self->plugin->auGetPropertyInfo(inProp, inScope, inElement, outDataSize, writable);
  1570. *ioDataSize = outDataSize;
  1571. return res;
  1572. }
  1573. const UInt32 inDataSize = *ioDataSize;
  1574. if (inDataSize == 0)
  1575. return kAudio_ParamError;
  1576. res = self->plugin->auGetPropertyInfo(inProp, inScope, inElement, outDataSize, writable);
  1577. if (res != noErr)
  1578. return res;
  1579. void* outBuffer;
  1580. uint8_t* tmpBuffer;
  1581. if (inDataSize < outDataSize)
  1582. {
  1583. tmpBuffer = new uint8_t[outDataSize];
  1584. outBuffer = tmpBuffer;
  1585. }
  1586. else
  1587. {
  1588. tmpBuffer = nullptr;
  1589. outBuffer = outData;
  1590. }
  1591. res = self->plugin->auGetProperty(inProp, inScope, inElement, outBuffer);
  1592. if (res != noErr)
  1593. {
  1594. *ioDataSize = 0;
  1595. return res;
  1596. }
  1597. if (tmpBuffer != nullptr)
  1598. {
  1599. memcpy(outData, tmpBuffer, inDataSize);
  1600. delete[] tmpBuffer;
  1601. }
  1602. else
  1603. {
  1604. *ioDataSize = outDataSize;
  1605. }
  1606. return noErr;
  1607. }
  1608. static OSStatus SetProperty(AudioComponentPlugInInstance* const self,
  1609. const AudioUnitPropertyID inProp,
  1610. const AudioUnitScope inScope,
  1611. const AudioUnitElement inElement,
  1612. const void* const inData,
  1613. const UInt32 inDataSize)
  1614. {
  1615. d_debug("AudioComponentPlugInInstance::SetProperty(%p, %d:%s, %d:%s, %d, %p, %u)",
  1616. self, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement, inData, inDataSize);
  1617. return self->plugin->auSetProperty(inProp, inScope, inElement, inData, inDataSize);
  1618. }
  1619. static OSStatus AddPropertyListener(AudioComponentPlugInInstance* const self,
  1620. const AudioUnitPropertyID prop,
  1621. const AudioUnitPropertyListenerProc proc,
  1622. void* const userData)
  1623. {
  1624. d_debug("AudioComponentPlugInInstance::AddPropertyListener(%p, %d:%s, %p, %p)",
  1625. self, prop, AudioUnitPropertyID2Str(prop), proc, userData);
  1626. return self->plugin->auAddPropertyListener(prop, proc, userData);
  1627. }
  1628. static OSStatus RemovePropertyListener(AudioComponentPlugInInstance* const self,
  1629. const AudioUnitPropertyID prop,
  1630. const AudioUnitPropertyListenerProc proc)
  1631. {
  1632. d_debug("AudioComponentPlugInInstance::RemovePropertyListener(%p, %d:%s, %p)",
  1633. self, prop, AudioUnitPropertyID2Str(prop), proc);
  1634. return self->plugin->auRemovePropertyListener(prop, proc);
  1635. }
  1636. static OSStatus RemovePropertyListenerWithUserData(AudioComponentPlugInInstance* const self,
  1637. const AudioUnitPropertyID prop,
  1638. const AudioUnitPropertyListenerProc proc,
  1639. void* const userData)
  1640. {
  1641. d_debug("AudioComponentPlugInInstance::RemovePropertyListenerWithUserData(%p, %d:%s, %p, %p)",
  1642. self, prop, AudioUnitPropertyID2Str(prop), proc, userData);
  1643. return self->plugin->auRemovePropertyListenerWithUserData(prop, proc, userData);
  1644. }
  1645. static OSStatus AddRenderNotify(AudioComponentPlugInInstance* const self,
  1646. const AURenderCallback proc,
  1647. void* const userData)
  1648. {
  1649. d_debug("AudioComponentPlugInInstance::AddRenderNotify(%p, %p, %p)", self, proc, userData);
  1650. return self->plugin->auAddRenderNotify(proc, userData);
  1651. }
  1652. static OSStatus RemoveRenderNotify(AudioComponentPlugInInstance* const self,
  1653. const AURenderCallback proc,
  1654. void* const userData)
  1655. {
  1656. d_debug("AudioComponentPlugInInstance::RemoveRenderNotify(%p, %p, %p)", self, proc, userData);
  1657. return self->plugin->auRemoveRenderNotify(proc, userData);
  1658. }
  1659. static OSStatus GetParameter(AudioComponentPlugInInstance* const self,
  1660. const AudioUnitParameterID param,
  1661. const AudioUnitScope scope,
  1662. const AudioUnitElement elem,
  1663. AudioUnitParameterValue* const value)
  1664. {
  1665. d_debug("AudioComponentPlugInInstance::GetParameter(%p, %d, %d:%s, %d, %p)",
  1666. self, param, scope, AudioUnitScope2Str(scope), elem, value);
  1667. return self->plugin->auGetParameter(param, scope, elem, value);
  1668. }
  1669. static OSStatus SetParameter(AudioComponentPlugInInstance* const self,
  1670. const AudioUnitParameterID param,
  1671. const AudioUnitScope scope,
  1672. const AudioUnitElement elem,
  1673. const AudioUnitParameterValue value,
  1674. const UInt32 bufferOffset)
  1675. {
  1676. d_debug("AudioComponentPlugInInstance::SetParameter(%p, %d %d:%s, %d, %f, %u)",
  1677. self, param, scope, AudioUnitScope2Str(scope), elem, value, bufferOffset);
  1678. return self->plugin->auSetParameter(param, scope, elem, value, bufferOffset);
  1679. }
  1680. static OSStatus ScheduleParameters(AudioComponentPlugInInstance* const self,
  1681. const AudioUnitParameterEvent* const events,
  1682. const UInt32 numEvents)
  1683. {
  1684. d_debug("AudioComponentPlugInInstance::ScheduleParameters(%p, %p, %u)", self, events, numEvents);
  1685. return self->plugin->auScheduleParameters(events, numEvents);
  1686. }
  1687. static OSStatus Reset(AudioComponentPlugInInstance* const self,
  1688. const AudioUnitScope scope,
  1689. const AudioUnitElement elem)
  1690. {
  1691. d_debug("AudioComponentPlugInInstance::Reset(%p, %d:%s, %d)", self, scope, AudioUnitScope2Str(scope), elem);
  1692. return self->plugin->auReset(scope, elem);
  1693. }
  1694. static OSStatus Render(AudioComponentPlugInInstance* const self,
  1695. AudioUnitRenderActionFlags* ioActionFlags,
  1696. const AudioTimeStamp* const inTimeStamp,
  1697. const UInt32 inOutputBusNumber,
  1698. const UInt32 inNumberFrames,
  1699. AudioBufferList* const ioData)
  1700. {
  1701. DISTRHO_SAFE_ASSERT_RETURN(inTimeStamp != nullptr, kAudio_ParamError);
  1702. DISTRHO_SAFE_ASSERT_RETURN(ioData != nullptr, kAudio_ParamError);
  1703. AudioUnitRenderActionFlags tmpFlags;
  1704. if (ioActionFlags == nullptr)
  1705. {
  1706. tmpFlags = 0;
  1707. ioActionFlags = &tmpFlags;
  1708. }
  1709. return self->plugin->auRender(*ioActionFlags, *inTimeStamp, inOutputBusNumber, inNumberFrames, *ioData);
  1710. }
  1711. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  1712. static OSStatus MIDIEvent(AudioComponentPlugInInstance* const self,
  1713. const UInt32 inStatus,
  1714. const UInt32 inData1,
  1715. const UInt32 inData2,
  1716. const UInt32 inOffsetSampleFrame)
  1717. {
  1718. return self->plugin->auMIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame);
  1719. }
  1720. static OSStatus SysEx(AudioComponentPlugInInstance* const self, const UInt8* const inData, const UInt32 inLength)
  1721. {
  1722. return self->plugin->auSysEx(inData, inLength);
  1723. }
  1724. #endif
  1725. DISTRHO_DECLARE_NON_COPYABLE(AudioComponentPlugInInstance)
  1726. };
  1727. // --------------------------------------------------------------------------------------------------------------------
  1728. END_NAMESPACE_DISTRHO
  1729. DISTRHO_PLUGIN_EXPORT
  1730. void* PluginAUFactory(const AudioComponentDescription* const desc)
  1731. {
  1732. USE_NAMESPACE_DISTRHO
  1733. DISTRHO_SAFE_ASSERT_UINT2_RETURN(desc->componentType == kType, desc->componentType, kType, nullptr);
  1734. DISTRHO_SAFE_ASSERT_UINT2_RETURN(desc->componentSubType == kSubType, desc->componentSubType, kSubType, nullptr);
  1735. DISTRHO_SAFE_ASSERT_UINT2_RETURN(desc->componentManufacturer == kManufacturer, desc->componentManufacturer, kManufacturer, nullptr);
  1736. if (d_nextBufferSize == 0)
  1737. d_nextBufferSize = 1156;
  1738. if (d_isZero(d_nextSampleRate))
  1739. d_nextSampleRate = 44100.0;
  1740. if (d_nextBundlePath == nullptr)
  1741. {
  1742. static String bundlePath;
  1743. String tmpPath(getBinaryFilename());
  1744. tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP));
  1745. tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP));
  1746. if (tmpPath.endsWith(DISTRHO_OS_SEP_STR "Contents"))
  1747. {
  1748. tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP));
  1749. bundlePath = tmpPath;
  1750. }
  1751. else
  1752. {
  1753. bundlePath = "error";
  1754. }
  1755. d_nextBundlePath = bundlePath.buffer();
  1756. }
  1757. d_nextCanRequestParameterValueChanges = true;
  1758. return new AudioComponentPlugInInstance();
  1759. }
  1760. // --------------------------------------------------------------------------------------------------------------------