The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

2481 lines
97KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 7 technical preview.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For the technical preview this file cannot be licensed commercially.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. #include <juce_core/system/juce_TargetPlatform.h>
  14. #include <juce_core/system/juce_CompilerWarnings.h>
  15. #include "../utility/juce_CheckSettingMacros.h"
  16. #if JucePlugin_Build_AU
  17. JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wshorten-64-to-32",
  18. "-Wunused-parameter",
  19. "-Wdeprecated-declarations",
  20. "-Wsign-conversion",
  21. "-Wconversion",
  22. "-Woverloaded-virtual",
  23. "-Wextra-semi",
  24. "-Wcast-align",
  25. "-Wshadow",
  26. "-Wswitch-enum",
  27. "-Wzero-as-null-pointer-constant",
  28. "-Wnullable-to-nonnull-conversion",
  29. "-Wgnu-zero-variadic-macro-arguments",
  30. "-Wformat-pedantic",
  31. "-Wdeprecated-anon-enum-enum-conversion")
  32. #include "../utility/juce_IncludeSystemHeaders.h"
  33. #include <AudioUnit/AUCocoaUIView.h>
  34. #include <AudioUnit/AudioUnit.h>
  35. #include <AudioToolbox/AudioUnitUtilities.h>
  36. #include <CoreMIDI/MIDIServices.h>
  37. #include <QuartzCore/QuartzCore.h>
  38. #include "CoreAudioUtilityClasses/MusicDeviceBase.h"
  39. JUCE_END_IGNORE_WARNINGS_GCC_LIKE
  40. #define JUCE_CORE_INCLUDE_OBJC_HELPERS 1
  41. #include "../utility/juce_IncludeModuleHeaders.h"
  42. #include <juce_audio_basics/native/juce_mac_CoreAudioLayouts.h>
  43. #include <juce_audio_basics/native/juce_mac_CoreAudioTimeConversions.h>
  44. #include <juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp>
  45. #include <juce_audio_processors/format_types/juce_AU_Shared.h>
  46. #if JucePlugin_Enable_ARA
  47. #include <juce_audio_processors/utilities/ARA/juce_AudioProcessor_ARAExtensions.h>
  48. #include <ARA_API/ARAAudioUnit.h>
  49. #if ARA_SUPPORT_VERSION_1
  50. #error "Unsupported ARA version - only ARA version 2 and onward are supported by the current JUCE ARA implementation"
  51. #endif
  52. #endif
  53. //==============================================================================
  54. using namespace juce;
  55. static Array<void*> activePlugins, activeUIs;
  56. static const AudioUnitPropertyID juceFilterObjectPropertyID = 0x1a45ffe9;
  57. template <> struct ContainerDeletePolicy<const __CFString> { static void destroy (const __CFString* o) { if (o != nullptr) CFRelease (o); } };
  58. // make sure the audio processor is initialized before the AUBase class
  59. struct AudioProcessorHolder
  60. {
  61. AudioProcessorHolder (bool initialiseGUI)
  62. {
  63. if (initialiseGUI)
  64. initialiseJuce_GUI();
  65. juceFilter.reset (createPluginFilterOfType (AudioProcessor::wrapperType_AudioUnit));
  66. // audio units do not have a notion of enabled or un-enabled buses
  67. juceFilter->enableAllBuses();
  68. }
  69. std::unique_ptr<AudioProcessor> juceFilter;
  70. };
  71. //==============================================================================
  72. class JuceAU : public AudioProcessorHolder,
  73. public MusicDeviceBase,
  74. public AudioProcessorListener,
  75. public AudioPlayHead,
  76. public AudioProcessorParameter::Listener
  77. {
  78. public:
  79. JuceAU (AudioUnit component)
  80. : AudioProcessorHolder (activePlugins.size() + activeUIs.size() == 0),
  81. MusicDeviceBase (component,
  82. (UInt32) AudioUnitHelpers::getBusCountForWrapper (*juceFilter, true),
  83. (UInt32) AudioUnitHelpers::getBusCountForWrapper (*juceFilter, false))
  84. {
  85. inParameterChangedCallback = false;
  86. #ifdef JucePlugin_PreferredChannelConfigurations
  87. short configs[][2] = {JucePlugin_PreferredChannelConfigurations};
  88. const int numConfigs = sizeof (configs) / sizeof (short[2]);
  89. jassert (numConfigs > 0 && (configs[0][0] > 0 || configs[0][1] > 0));
  90. juceFilter->setPlayConfigDetails (configs[0][0], configs[0][1], 44100.0, 1024);
  91. for (int i = 0; i < numConfigs; ++i)
  92. {
  93. AUChannelInfo info;
  94. info.inChannels = configs[i][0];
  95. info.outChannels = configs[i][1];
  96. channelInfo.add (info);
  97. }
  98. #else
  99. channelInfo = AudioUnitHelpers::getAUChannelInfo (*juceFilter);
  100. #endif
  101. AddPropertyListener (kAudioUnitProperty_ContextName, auPropertyListenerDispatcher, this);
  102. totalInChannels = juceFilter->getTotalNumInputChannels();
  103. totalOutChannels = juceFilter->getTotalNumOutputChannels();
  104. juceFilter->setPlayHead (this);
  105. juceFilter->addListener (this);
  106. addParameters();
  107. activePlugins.add (this);
  108. zerostruct (auEvent);
  109. auEvent.mArgument.mParameter.mAudioUnit = GetComponentInstance();
  110. auEvent.mArgument.mParameter.mScope = kAudioUnitScope_Global;
  111. auEvent.mArgument.mParameter.mElement = 0;
  112. zerostruct (midiCallback);
  113. CreateElements();
  114. if (syncAudioUnitWithProcessor() != noErr)
  115. jassertfalse;
  116. }
  117. ~JuceAU() override
  118. {
  119. if (bypassParam != nullptr)
  120. bypassParam->removeListener (this);
  121. deleteActiveEditors();
  122. juceFilter = nullptr;
  123. clearPresetsArray();
  124. jassert (activePlugins.contains (this));
  125. activePlugins.removeFirstMatchingValue (this);
  126. if (activePlugins.size() + activeUIs.size() == 0)
  127. shutdownJuce_GUI();
  128. }
  129. //==============================================================================
  130. ComponentResult Initialize() override
  131. {
  132. ComponentResult err;
  133. if ((err = syncProcessorWithAudioUnit()) != noErr)
  134. return err;
  135. if ((err = MusicDeviceBase::Initialize()) != noErr)
  136. return err;
  137. mapper.alloc (*juceFilter);
  138. pulledSucceeded.calloc (static_cast<size_t> (AudioUnitHelpers::getBusCountForWrapper (*juceFilter, true)));
  139. prepareToPlay();
  140. return noErr;
  141. }
  142. void Cleanup() override
  143. {
  144. MusicDeviceBase::Cleanup();
  145. pulledSucceeded.free();
  146. mapper.release();
  147. if (juceFilter != nullptr)
  148. juceFilter->releaseResources();
  149. audioBuffer.release();
  150. midiEvents.clear();
  151. incomingEvents.clear();
  152. prepared = false;
  153. }
  154. ComponentResult Reset (AudioUnitScope inScope, AudioUnitElement inElement) override
  155. {
  156. if (! prepared)
  157. prepareToPlay();
  158. if (juceFilter != nullptr)
  159. juceFilter->reset();
  160. return MusicDeviceBase::Reset (inScope, inElement);
  161. }
  162. //==============================================================================
  163. void prepareToPlay()
  164. {
  165. if (juceFilter != nullptr)
  166. {
  167. juceFilter->setRateAndBufferSizeDetails (getSampleRate(), (int) GetMaxFramesPerSlice());
  168. audioBuffer.prepare (AudioUnitHelpers::getBusesLayout (juceFilter.get()), (int) GetMaxFramesPerSlice() + 32);
  169. juceFilter->prepareToPlay (getSampleRate(), (int) GetMaxFramesPerSlice());
  170. midiEvents.ensureSize (2048);
  171. midiEvents.clear();
  172. incomingEvents.ensureSize (2048);
  173. incomingEvents.clear();
  174. prepared = true;
  175. }
  176. }
  177. //==============================================================================
  178. static OSStatus ComponentEntryDispatch (ComponentParameters* params, JuceAU* effect)
  179. {
  180. if (effect == nullptr)
  181. return paramErr;
  182. switch (params->what)
  183. {
  184. case kMusicDeviceMIDIEventSelect:
  185. case kMusicDeviceSysExSelect:
  186. return AUMIDIBase::ComponentEntryDispatch (params, effect);
  187. default:
  188. break;
  189. }
  190. return MusicDeviceBase::ComponentEntryDispatch (params, effect);
  191. }
  192. //==============================================================================
  193. bool BusCountWritable (AudioUnitScope scope) override
  194. {
  195. #ifdef JucePlugin_PreferredChannelConfigurations
  196. ignoreUnused (scope);
  197. return false;
  198. #else
  199. bool isInput;
  200. if (scopeToDirection (scope, isInput) != noErr)
  201. return false;
  202. #if JucePlugin_IsMidiEffect
  203. return false;
  204. #elif JucePlugin_IsSynth
  205. if (isInput) return false;
  206. #endif
  207. const int busCount = AudioUnitHelpers::getBusCount (*juceFilter, isInput);
  208. return (juceFilter->canAddBus (isInput) || (busCount > 0 && juceFilter->canRemoveBus (isInput)));
  209. #endif
  210. }
  211. OSStatus SetBusCount (AudioUnitScope scope, UInt32 count) override
  212. {
  213. OSStatus err = noErr;
  214. bool isInput;
  215. if ((err = scopeToDirection (scope, isInput)) != noErr)
  216. return err;
  217. if (count != (UInt32) AudioUnitHelpers::getBusCount (*juceFilter, isInput))
  218. {
  219. #ifdef JucePlugin_PreferredChannelConfigurations
  220. return kAudioUnitErr_PropertyNotWritable;
  221. #else
  222. const int busCount = AudioUnitHelpers::getBusCount (*juceFilter, isInput);
  223. if ((! juceFilter->canAddBus (isInput)) && ((busCount == 0) || (! juceFilter->canRemoveBus (isInput))))
  224. return kAudioUnitErr_PropertyNotWritable;
  225. // we need to already create the underlying elements so that we can change their formats
  226. err = MusicDeviceBase::SetBusCount (scope, count);
  227. if (err != noErr)
  228. return err;
  229. // however we do need to update the format tag: we need to do the same thing in SetFormat, for example
  230. const int requestedNumBus = static_cast<int> (count);
  231. {
  232. (isInput ? currentInputLayout : currentOutputLayout).resize (requestedNumBus);
  233. int busNr;
  234. for (busNr = (busCount - 1); busNr != (requestedNumBus - 1); busNr += (requestedNumBus > busCount ? 1 : -1))
  235. {
  236. if (requestedNumBus > busCount)
  237. {
  238. if (! juceFilter->addBus (isInput))
  239. break;
  240. err = syncAudioUnitWithChannelSet (isInput, busNr,
  241. juceFilter->getBus (isInput, busNr + 1)->getDefaultLayout());
  242. if (err != noErr)
  243. break;
  244. }
  245. else
  246. {
  247. if (! juceFilter->removeBus (isInput))
  248. break;
  249. }
  250. }
  251. err = (busNr == (requestedNumBus - 1) ? (OSStatus) noErr : (OSStatus) kAudioUnitErr_FormatNotSupported);
  252. }
  253. // was there an error?
  254. if (err != noErr)
  255. {
  256. // restore bus state
  257. const int newBusCount = AudioUnitHelpers::getBusCount (*juceFilter, isInput);
  258. for (int i = newBusCount; i != busCount; i += (busCount > newBusCount ? 1 : -1))
  259. {
  260. if (busCount > newBusCount)
  261. juceFilter->addBus (isInput);
  262. else
  263. juceFilter->removeBus (isInput);
  264. }
  265. (isInput ? currentInputLayout : currentOutputLayout).resize (busCount);
  266. MusicDeviceBase::SetBusCount (scope, static_cast<UInt32> (busCount));
  267. return kAudioUnitErr_FormatNotSupported;
  268. }
  269. // update total channel count
  270. totalInChannels = juceFilter->getTotalNumInputChannels();
  271. totalOutChannels = juceFilter->getTotalNumOutputChannels();
  272. addSupportedLayoutTagsForDirection (isInput);
  273. if (err != noErr)
  274. return err;
  275. #endif
  276. }
  277. return noErr;
  278. }
  279. UInt32 SupportedNumChannels (const AUChannelInfo** outInfo) override
  280. {
  281. if (outInfo != nullptr)
  282. *outInfo = channelInfo.getRawDataPointer();
  283. return (UInt32) channelInfo.size();
  284. }
  285. //==============================================================================
  286. ComponentResult GetPropertyInfo (AudioUnitPropertyID inID,
  287. AudioUnitScope inScope,
  288. AudioUnitElement inElement,
  289. UInt32& outDataSize,
  290. Boolean& outWritable) override
  291. {
  292. if (inScope == kAudioUnitScope_Global)
  293. {
  294. switch (inID)
  295. {
  296. case juceFilterObjectPropertyID:
  297. outWritable = false;
  298. outDataSize = sizeof (void*) * 2;
  299. return noErr;
  300. case kAudioUnitProperty_OfflineRender:
  301. outWritable = true;
  302. outDataSize = sizeof (UInt32);
  303. return noErr;
  304. case kMusicDeviceProperty_InstrumentCount:
  305. outDataSize = sizeof (UInt32);
  306. outWritable = false;
  307. return noErr;
  308. case kAudioUnitProperty_CocoaUI:
  309. outDataSize = sizeof (AudioUnitCocoaViewInfo);
  310. outWritable = true;
  311. return noErr;
  312. #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect
  313. case kAudioUnitProperty_MIDIOutputCallbackInfo:
  314. outDataSize = sizeof (CFArrayRef);
  315. outWritable = false;
  316. return noErr;
  317. case kAudioUnitProperty_MIDIOutputCallback:
  318. outDataSize = sizeof (AUMIDIOutputCallbackStruct);
  319. outWritable = true;
  320. return noErr;
  321. #endif
  322. case kAudioUnitProperty_ParameterStringFromValue:
  323. outDataSize = sizeof (AudioUnitParameterStringFromValue);
  324. outWritable = false;
  325. return noErr;
  326. case kAudioUnitProperty_ParameterValueFromString:
  327. outDataSize = sizeof (AudioUnitParameterValueFromString);
  328. outWritable = false;
  329. return noErr;
  330. case kAudioUnitProperty_BypassEffect:
  331. outDataSize = sizeof (UInt32);
  332. outWritable = true;
  333. return noErr;
  334. case kAudioUnitProperty_SupportsMPE:
  335. outDataSize = sizeof (UInt32);
  336. outWritable = false;
  337. return noErr;
  338. #if JucePlugin_Enable_ARA
  339. case ARA::kAudioUnitProperty_ARAFactory:
  340. outWritable = false;
  341. outDataSize = sizeof (ARA::ARAAudioUnitFactory);
  342. return noErr;
  343. case ARA::kAudioUnitProperty_ARAPlugInExtensionBindingWithRoles:
  344. outWritable = false;
  345. outDataSize = sizeof (ARA::ARAAudioUnitPlugInExtensionBinding);
  346. return noErr;
  347. #endif
  348. default: break;
  349. }
  350. }
  351. return MusicDeviceBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
  352. }
  353. ComponentResult GetProperty (AudioUnitPropertyID inID,
  354. AudioUnitScope inScope,
  355. AudioUnitElement inElement,
  356. void* outData) override
  357. {
  358. if (inScope == kAudioUnitScope_Global)
  359. {
  360. switch (inID)
  361. {
  362. case kAudioUnitProperty_ParameterClumpName:
  363. if (auto* clumpNameInfo = (AudioUnitParameterNameInfo*) outData)
  364. {
  365. if (juceFilter != nullptr)
  366. {
  367. auto clumpIndex = clumpNameInfo->inID - 1;
  368. const auto* group = parameterGroups[(int) clumpIndex];
  369. auto name = group->getName();
  370. while (group->getParent() != &juceFilter->getParameterTree())
  371. {
  372. group = group->getParent();
  373. name = group->getName() + group->getSeparator() + name;
  374. }
  375. clumpNameInfo->outName = name.toCFString();
  376. return noErr;
  377. }
  378. }
  379. // Failed to find a group corresponding to the clump ID.
  380. jassertfalse;
  381. break;
  382. //==============================================================================
  383. #if JucePlugin_Enable_ARA
  384. case ARA::kAudioUnitProperty_ARAFactory:
  385. {
  386. auto auFactory = static_cast<ARA::ARAAudioUnitFactory*> (outData);
  387. if (auFactory->inOutMagicNumber != ARA::kARAAudioUnitMagic)
  388. return kAudioUnitErr_InvalidProperty; // if the magic value isn't found, the property ID is re-used outside the ARA context with different, unsupported sematics
  389. auFactory->outFactory = createARAFactory();
  390. return noErr;
  391. }
  392. case ARA::kAudioUnitProperty_ARAPlugInExtensionBindingWithRoles:
  393. {
  394. auto binding = static_cast<ARA::ARAAudioUnitPlugInExtensionBinding*> (outData);
  395. if (binding->inOutMagicNumber != ARA::kARAAudioUnitMagic)
  396. return kAudioUnitErr_InvalidProperty; // if the magic value isn't found, the property ID is re-used outside the ARA context with different, unsupported sematics
  397. AudioProcessorARAExtension* araAudioProcessorExtension = dynamic_cast<AudioProcessorARAExtension*> (juceFilter.get());
  398. binding->outPlugInExtension = araAudioProcessorExtension->bindToARA (binding->inDocumentControllerRef, binding->knownRoles, binding->assignedRoles);
  399. if (binding->outPlugInExtension == nullptr)
  400. return kAudioUnitErr_CannotDoInCurrentContext; // bindToARA() returns null if binding is already established
  401. return noErr;
  402. }
  403. #endif
  404. case juceFilterObjectPropertyID:
  405. ((void**) outData)[0] = (void*) static_cast<AudioProcessor*> (juceFilter.get());
  406. ((void**) outData)[1] = (void*) this;
  407. return noErr;
  408. case kAudioUnitProperty_OfflineRender:
  409. *(UInt32*) outData = (juceFilter != nullptr && juceFilter->isNonRealtime()) ? 1 : 0;
  410. return noErr;
  411. case kMusicDeviceProperty_InstrumentCount:
  412. *(UInt32*) outData = 1;
  413. return noErr;
  414. case kAudioUnitProperty_BypassEffect:
  415. if (bypassParam != nullptr)
  416. *(UInt32*) outData = (bypassParam->getValue() != 0.0f ? 1 : 0);
  417. else
  418. *(UInt32*) outData = isBypassed ? 1 : 0;
  419. return noErr;
  420. case kAudioUnitProperty_SupportsMPE:
  421. *(UInt32*) outData = (juceFilter != nullptr && juceFilter->supportsMPE()) ? 1 : 0;
  422. return noErr;
  423. case kAudioUnitProperty_CocoaUI:
  424. {
  425. JUCE_AUTORELEASEPOOL
  426. {
  427. static JuceUICreationClass cls;
  428. // (NB: this may be the host's bundle, not necessarily the component's)
  429. NSBundle* bundle = [NSBundle bundleForClass: cls.cls];
  430. AudioUnitCocoaViewInfo* info = static_cast<AudioUnitCocoaViewInfo*> (outData);
  431. info->mCocoaAUViewClass[0] = (CFStringRef) [juceStringToNS (class_getName (cls.cls)) retain];
  432. info->mCocoaAUViewBundleLocation = (CFURLRef) [[NSURL fileURLWithPath: [bundle bundlePath]] retain];
  433. }
  434. return noErr;
  435. }
  436. break;
  437. #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect
  438. case kAudioUnitProperty_MIDIOutputCallbackInfo:
  439. {
  440. CFStringRef strs[1];
  441. strs[0] = CFSTR ("MIDI Callback");
  442. CFArrayRef callbackArray = CFArrayCreate (nullptr, (const void**) strs, 1, &kCFTypeArrayCallBacks);
  443. *(CFArrayRef*) outData = callbackArray;
  444. return noErr;
  445. }
  446. #endif
  447. case kAudioUnitProperty_ParameterValueFromString:
  448. {
  449. if (AudioUnitParameterValueFromString* pv = (AudioUnitParameterValueFromString*) outData)
  450. {
  451. if (juceFilter != nullptr)
  452. {
  453. if (auto* param = getParameterForAUParameterID (pv->inParamID))
  454. {
  455. const String text (String::fromCFString (pv->inString));
  456. if (LegacyAudioParameter::isLegacy (param))
  457. pv->outValue = text.getFloatValue();
  458. else
  459. pv->outValue = param->getValueForText (text) * getMaximumParameterValue (param);
  460. return noErr;
  461. }
  462. }
  463. }
  464. }
  465. break;
  466. case kAudioUnitProperty_ParameterStringFromValue:
  467. {
  468. if (AudioUnitParameterStringFromValue* pv = (AudioUnitParameterStringFromValue*) outData)
  469. {
  470. if (juceFilter != nullptr)
  471. {
  472. if (auto* param = getParameterForAUParameterID (pv->inParamID))
  473. {
  474. const float value = (float) *(pv->inValue);
  475. String text;
  476. if (LegacyAudioParameter::isLegacy (param))
  477. text = String (value);
  478. else
  479. text = param->getText (value / getMaximumParameterValue (param), 0);
  480. pv->outString = text.toCFString();
  481. return noErr;
  482. }
  483. }
  484. }
  485. }
  486. break;
  487. default:
  488. break;
  489. }
  490. }
  491. return MusicDeviceBase::GetProperty (inID, inScope, inElement, outData);
  492. }
  493. ComponentResult SetProperty (AudioUnitPropertyID inID,
  494. AudioUnitScope inScope,
  495. AudioUnitElement inElement,
  496. const void* inData,
  497. UInt32 inDataSize) override
  498. {
  499. if (inScope == kAudioUnitScope_Global)
  500. {
  501. switch (inID)
  502. {
  503. #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect
  504. case kAudioUnitProperty_MIDIOutputCallback:
  505. if (inDataSize < sizeof (AUMIDIOutputCallbackStruct))
  506. return kAudioUnitErr_InvalidPropertyValue;
  507. if (AUMIDIOutputCallbackStruct* callbackStruct = (AUMIDIOutputCallbackStruct*) inData)
  508. midiCallback = *callbackStruct;
  509. return noErr;
  510. #endif
  511. case kAudioUnitProperty_BypassEffect:
  512. {
  513. if (inDataSize < sizeof (UInt32))
  514. return kAudioUnitErr_InvalidPropertyValue;
  515. const bool newBypass = *((UInt32*) inData) != 0;
  516. const bool currentlyBypassed = (bypassParam != nullptr ? (bypassParam->getValue() != 0.0f) : isBypassed);
  517. if (newBypass != currentlyBypassed)
  518. {
  519. if (bypassParam != nullptr)
  520. bypassParam->setValueNotifyingHost (newBypass ? 1.0f : 0.0f);
  521. else
  522. isBypassed = newBypass;
  523. if (! currentlyBypassed && IsInitialized()) // turning bypass off and we're initialized
  524. Reset (0, 0);
  525. }
  526. return noErr;
  527. }
  528. case kAudioUnitProperty_OfflineRender:
  529. {
  530. const auto shouldBeOffline = (*reinterpret_cast<const UInt32*> (inData) != 0);
  531. if (juceFilter != nullptr)
  532. {
  533. const auto isOffline = juceFilter->isNonRealtime();
  534. if (isOffline != shouldBeOffline)
  535. {
  536. const ScopedLock sl (juceFilter->getCallbackLock());
  537. juceFilter->setNonRealtime (shouldBeOffline);
  538. if (prepared)
  539. juceFilter->prepareToPlay (getSampleRate(), (int) GetMaxFramesPerSlice());
  540. }
  541. }
  542. return noErr;
  543. }
  544. #if defined (MAC_OS_X_VERSION_10_12)
  545. case kAudioUnitProperty_AUHostIdentifier:
  546. {
  547. if (inDataSize < sizeof (AUHostVersionIdentifier))
  548. return kAudioUnitErr_InvalidPropertyValue;
  549. const auto* identifier = static_cast<const AUHostVersionIdentifier*> (inData);
  550. PluginHostType::hostIdReportedByWrapper = String::fromCFString (identifier->hostName);
  551. return noErr;
  552. }
  553. #endif
  554. default: break;
  555. }
  556. }
  557. return MusicDeviceBase::SetProperty (inID, inScope, inElement, inData, inDataSize);
  558. }
  559. //==============================================================================
  560. ComponentResult SaveState (CFPropertyListRef* outData) override
  561. {
  562. ComponentResult err = MusicDeviceBase::SaveState (outData);
  563. if (err != noErr)
  564. return err;
  565. jassert (CFGetTypeID (*outData) == CFDictionaryGetTypeID());
  566. CFMutableDictionaryRef dict = (CFMutableDictionaryRef) *outData;
  567. if (juceFilter != nullptr)
  568. {
  569. juce::MemoryBlock state;
  570. #if JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES
  571. juceFilter->getCurrentProgramStateInformation (state);
  572. #else
  573. juceFilter->getStateInformation (state);
  574. #endif
  575. if (state.getSize() > 0)
  576. {
  577. CFUniquePtr<CFDataRef> ourState (CFDataCreate (kCFAllocatorDefault, (const UInt8*) state.getData(), (CFIndex) state.getSize()));
  578. CFUniquePtr<CFStringRef> key (CFStringCreateWithCString (kCFAllocatorDefault, JUCE_STATE_DICTIONARY_KEY, kCFStringEncodingUTF8));
  579. CFDictionarySetValue (dict, key.get(), ourState.get());
  580. }
  581. }
  582. return noErr;
  583. }
  584. ComponentResult RestoreState (CFPropertyListRef inData) override
  585. {
  586. const ScopedValueSetter<bool> scope { restoringState, true };
  587. {
  588. // Remove the data entry from the state to prevent the superclass loading the parameters
  589. CFUniquePtr<CFMutableDictionaryRef> copyWithoutData (CFDictionaryCreateMutableCopy (nullptr, 0, (CFDictionaryRef) inData));
  590. CFDictionaryRemoveValue (copyWithoutData.get(), CFSTR (kAUPresetDataKey));
  591. ComponentResult err = MusicDeviceBase::RestoreState (copyWithoutData.get());
  592. if (err != noErr)
  593. return err;
  594. }
  595. if (juceFilter != nullptr)
  596. {
  597. CFDictionaryRef dict = (CFDictionaryRef) inData;
  598. CFDataRef data = nullptr;
  599. CFUniquePtr<CFStringRef> key (CFStringCreateWithCString (kCFAllocatorDefault, JUCE_STATE_DICTIONARY_KEY, kCFStringEncodingUTF8));
  600. bool valuePresent = CFDictionaryGetValueIfPresent (dict, key.get(), (const void**) &data);
  601. if (valuePresent)
  602. {
  603. if (data != nullptr)
  604. {
  605. const int numBytes = (int) CFDataGetLength (data);
  606. const juce::uint8* const rawBytes = CFDataGetBytePtr (data);
  607. if (numBytes > 0)
  608. {
  609. #if JUCE_AU_WRAPPERS_SAVE_PROGRAM_STATES
  610. juceFilter->setCurrentProgramStateInformation (rawBytes, numBytes);
  611. #else
  612. juceFilter->setStateInformation (rawBytes, numBytes);
  613. #endif
  614. }
  615. }
  616. }
  617. }
  618. return noErr;
  619. }
  620. //==============================================================================
  621. bool busIgnoresLayout (bool isInput, int busNr) const
  622. {
  623. #ifdef JucePlugin_PreferredChannelConfigurations
  624. ignoreUnused (isInput, busNr);
  625. return true;
  626. #else
  627. if (const AudioProcessor::Bus* bus = juceFilter->getBus (isInput, busNr))
  628. {
  629. AudioChannelSet discreteRangeSet;
  630. const int n = bus->getDefaultLayout().size();
  631. for (int i = 0; i < n; ++i)
  632. discreteRangeSet.addChannel ((AudioChannelSet::ChannelType) (256 + i));
  633. // if the audioprocessor supports this it cannot
  634. // really be interested in the bus layouts
  635. return bus->isLayoutSupported (discreteRangeSet);
  636. }
  637. return true;
  638. #endif
  639. }
  640. UInt32 GetAudioChannelLayout (AudioUnitScope scope, AudioUnitElement element,
  641. AudioChannelLayout* outLayoutPtr, Boolean& outWritable) override
  642. {
  643. outWritable = false;
  644. const auto info = getElementInfo (scope, element);
  645. if (info.error != noErr)
  646. return 0;
  647. if (busIgnoresLayout (info.isInput, info.busNr))
  648. return 0;
  649. outWritable = true;
  650. const size_t sizeInBytes = sizeof (AudioChannelLayout) - sizeof (AudioChannelDescription);
  651. if (outLayoutPtr != nullptr)
  652. {
  653. zeromem (outLayoutPtr, sizeInBytes);
  654. outLayoutPtr->mChannelLayoutTag = getCurrentLayout (info.isInput, info.busNr);
  655. }
  656. return sizeInBytes;
  657. }
  658. UInt32 GetChannelLayoutTags (AudioUnitScope scope, AudioUnitElement element, AudioChannelLayoutTag* outLayoutTags) override
  659. {
  660. const auto info = getElementInfo (scope, element);
  661. if (info.error != noErr)
  662. return 0;
  663. if (busIgnoresLayout (info.isInput, info.busNr))
  664. return 0;
  665. const Array<AudioChannelLayoutTag>& layouts = getSupportedBusLayouts (info.isInput, info.busNr);
  666. if (outLayoutTags != nullptr)
  667. std::copy (layouts.begin(), layouts.end(), outLayoutTags);
  668. return (UInt32) layouts.size();
  669. }
  670. OSStatus SetAudioChannelLayout (AudioUnitScope scope, AudioUnitElement element, const AudioChannelLayout* inLayout) override
  671. {
  672. const auto info = getElementInfo (scope, element);
  673. if (info.error != noErr)
  674. return info.error;
  675. if (busIgnoresLayout (info.isInput, info.busNr))
  676. return kAudioUnitErr_PropertyNotWritable;
  677. if (inLayout == nullptr)
  678. return kAudioUnitErr_InvalidPropertyValue;
  679. if (const AUIOElement* ioElement = GetIOElement (info.isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, element))
  680. {
  681. const AudioChannelSet newChannelSet = CoreAudioLayouts::fromCoreAudio (*inLayout);
  682. const int currentNumChannels = static_cast<int> (ioElement->GetStreamFormat().NumberChannels());
  683. const int newChannelNum = newChannelSet.size();
  684. if (currentNumChannels != newChannelNum)
  685. return kAudioUnitErr_InvalidPropertyValue;
  686. // check if the new layout could be potentially set
  687. #ifdef JucePlugin_PreferredChannelConfigurations
  688. short configs[][2] = {JucePlugin_PreferredChannelConfigurations};
  689. if (! AudioUnitHelpers::isLayoutSupported (*juceFilter, info.isInput, info.busNr, newChannelNum, configs))
  690. return kAudioUnitErr_FormatNotSupported;
  691. #else
  692. if (! juceFilter->getBus (info.isInput, info.busNr)->isLayoutSupported (newChannelSet))
  693. return kAudioUnitErr_FormatNotSupported;
  694. #endif
  695. getCurrentLayout (info.isInput, info.busNr) = CoreAudioLayouts::toCoreAudio (newChannelSet);
  696. return noErr;
  697. }
  698. else
  699. jassertfalse;
  700. return kAudioUnitErr_InvalidElement;
  701. }
  702. //==============================================================================
  703. // When parameters are discrete we need to use integer values.
  704. float getMaximumParameterValue (AudioProcessorParameter* juceParam)
  705. {
  706. #if JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
  707. ignoreUnused (juceParam);
  708. return 1.0f;
  709. #else
  710. return juceParam->isDiscrete() ? (float) (juceParam->getNumSteps() - 1) : 1.0f;
  711. #endif
  712. }
  713. ComponentResult GetParameterInfo (AudioUnitScope inScope,
  714. AudioUnitParameterID inParameterID,
  715. AudioUnitParameterInfo& outParameterInfo) override
  716. {
  717. if (inScope == kAudioUnitScope_Global && juceFilter != nullptr)
  718. {
  719. if (auto* param = getParameterForAUParameterID (inParameterID))
  720. {
  721. outParameterInfo.unit = kAudioUnitParameterUnit_Generic;
  722. outParameterInfo.flags = (UInt32) (kAudioUnitParameterFlag_IsWritable
  723. | kAudioUnitParameterFlag_IsReadable
  724. | kAudioUnitParameterFlag_HasCFNameString
  725. | kAudioUnitParameterFlag_ValuesHaveStrings);
  726. #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
  727. outParameterInfo.flags |= (UInt32) kAudioUnitParameterFlag_IsHighResolution;
  728. #endif
  729. const String name = param->getName (1024);
  730. // Set whether the param is automatable (unnamed parameters aren't allowed to be automated)
  731. if (name.isEmpty() || ! param->isAutomatable())
  732. outParameterInfo.flags |= kAudioUnitParameterFlag_NonRealTime;
  733. const bool isParameterDiscrete = param->isDiscrete();
  734. if (! isParameterDiscrete)
  735. outParameterInfo.flags |= kAudioUnitParameterFlag_CanRamp;
  736. if (param->isMetaParameter())
  737. outParameterInfo.flags |= kAudioUnitParameterFlag_IsGlobalMeta;
  738. auto parameterGroupHierarchy = juceFilter->getParameterTree().getGroupsForParameter (param);
  739. if (! parameterGroupHierarchy.isEmpty())
  740. {
  741. outParameterInfo.flags |= kAudioUnitParameterFlag_HasClump;
  742. outParameterInfo.clumpID = (UInt32) parameterGroups.indexOf (parameterGroupHierarchy.getLast()) + 1;
  743. }
  744. // Is this a meter?
  745. if ((((unsigned int) param->getCategory() & 0xffff0000) >> 16) == 2)
  746. {
  747. outParameterInfo.flags &= ~kAudioUnitParameterFlag_IsWritable;
  748. outParameterInfo.flags |= kAudioUnitParameterFlag_MeterReadOnly | kAudioUnitParameterFlag_DisplayLogarithmic;
  749. outParameterInfo.unit = kAudioUnitParameterUnit_LinearGain;
  750. }
  751. else
  752. {
  753. #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
  754. if (isParameterDiscrete)
  755. outParameterInfo.unit = param->isBoolean() ? kAudioUnitParameterUnit_Boolean
  756. : kAudioUnitParameterUnit_Indexed;
  757. #endif
  758. }
  759. MusicDeviceBase::FillInParameterName (outParameterInfo, name.toCFString(), true);
  760. outParameterInfo.minValue = 0.0f;
  761. outParameterInfo.maxValue = getMaximumParameterValue (param);
  762. outParameterInfo.defaultValue = param->getDefaultValue() * getMaximumParameterValue (param);
  763. jassert (outParameterInfo.defaultValue >= outParameterInfo.minValue
  764. && outParameterInfo.defaultValue <= outParameterInfo.maxValue);
  765. return noErr;
  766. }
  767. }
  768. return kAudioUnitErr_InvalidParameter;
  769. }
  770. ComponentResult GetParameterValueStrings (AudioUnitScope inScope,
  771. AudioUnitParameterID inParameterID,
  772. CFArrayRef *outStrings) override
  773. {
  774. if (outStrings == nullptr)
  775. return noErr;
  776. if (inScope == kAudioUnitScope_Global && juceFilter != nullptr)
  777. {
  778. if (auto* param = getParameterForAUParameterID (inParameterID))
  779. {
  780. if (param->isDiscrete())
  781. {
  782. auto index = LegacyAudioParameter::getParamIndex (*juceFilter, param);
  783. if (auto* valueStrings = parameterValueStringArrays[index])
  784. {
  785. *outStrings = CFArrayCreate (nullptr,
  786. (const void **) valueStrings->getRawDataPointer(),
  787. valueStrings->size(),
  788. nullptr);
  789. return noErr;
  790. }
  791. }
  792. }
  793. }
  794. return kAudioUnitErr_InvalidParameter;
  795. }
  796. ComponentResult GetParameter (AudioUnitParameterID inID,
  797. AudioUnitScope inScope,
  798. AudioUnitElement inElement,
  799. Float32& outValue) override
  800. {
  801. if (inScope == kAudioUnitScope_Global && juceFilter != nullptr)
  802. {
  803. if (auto* param = getParameterForAUParameterID (inID))
  804. {
  805. const auto normValue = param->getValue();
  806. outValue = normValue * getMaximumParameterValue (param);
  807. return noErr;
  808. }
  809. }
  810. return MusicDeviceBase::GetParameter (inID, inScope, inElement, outValue);
  811. }
  812. ComponentResult SetParameter (AudioUnitParameterID inID,
  813. AudioUnitScope inScope,
  814. AudioUnitElement inElement,
  815. Float32 inValue,
  816. UInt32 inBufferOffsetInFrames) override
  817. {
  818. if (inScope == kAudioUnitScope_Global && juceFilter != nullptr)
  819. {
  820. if (auto* param = getParameterForAUParameterID (inID))
  821. {
  822. auto value = inValue / getMaximumParameterValue (param);
  823. if (value != param->getValue())
  824. {
  825. inParameterChangedCallback = true;
  826. param->setValueNotifyingHost (value);
  827. }
  828. return noErr;
  829. }
  830. }
  831. return MusicDeviceBase::SetParameter (inID, inScope, inElement, inValue, inBufferOffsetInFrames);
  832. }
  833. // No idea what this method actually does or what it should return. Current Apple docs say nothing about it.
  834. // (Note that this isn't marked 'override' in case older versions of the SDK don't include it)
  835. bool CanScheduleParameters() const override { return false; }
  836. //==============================================================================
  837. ComponentResult Version() override { return JucePlugin_VersionCode; }
  838. bool SupportsTail() override { return true; }
  839. Float64 GetTailTime() override { return juceFilter->getTailLengthSeconds(); }
  840. double getSampleRate()
  841. {
  842. if (AudioUnitHelpers::getBusCountForWrapper (*juceFilter, false) > 0)
  843. return GetOutput (0)->GetStreamFormat().mSampleRate;
  844. return 44100.0;
  845. }
  846. Float64 GetLatency() override
  847. {
  848. const double rate = getSampleRate();
  849. jassert (rate > 0);
  850. #if JucePlugin_Enable_ARA
  851. jassert (juceFilter->getLatencySamples() == 0 || ! dynamic_cast<AudioProcessorARAExtension*> (juceFilter.get())->isBoundToARA());
  852. #endif
  853. return rate > 0 ? juceFilter->getLatencySamples() / rate : 0;
  854. }
  855. //==============================================================================
  856. bool getCurrentPosition (AudioPlayHead::CurrentPositionInfo& info) override
  857. {
  858. info.timeSigNumerator = 0;
  859. info.timeSigDenominator = 0;
  860. info.editOriginTime = 0;
  861. info.ppqPositionOfLastBarStart = 0;
  862. info.isRecording = false;
  863. info.frameRate = [this]
  864. {
  865. switch (lastTimeStamp.mSMPTETime.mType)
  866. {
  867. case kSMPTETimeType2398: return FrameRate().withBaseRate (24).withPullDown();
  868. case kSMPTETimeType24: return FrameRate().withBaseRate (24);
  869. case kSMPTETimeType25: return FrameRate().withBaseRate (25);
  870. case kSMPTETimeType30Drop: return FrameRate().withBaseRate (30).withDrop();
  871. case kSMPTETimeType30: return FrameRate().withBaseRate (30);
  872. case kSMPTETimeType2997: return FrameRate().withBaseRate (30).withPullDown();
  873. case kSMPTETimeType2997Drop: return FrameRate().withBaseRate (30).withPullDown().withDrop();
  874. case kSMPTETimeType60: return FrameRate().withBaseRate (60);
  875. case kSMPTETimeType60Drop: return FrameRate().withBaseRate (60).withDrop();
  876. case kSMPTETimeType5994: return FrameRate().withBaseRate (60).withPullDown();
  877. case kSMPTETimeType5994Drop: return FrameRate().withBaseRate (60).withPullDown().withDrop();
  878. case kSMPTETimeType50: return FrameRate().withBaseRate (50);
  879. default: break;
  880. }
  881. return FrameRate();
  882. }();
  883. if (CallHostBeatAndTempo (&info.ppqPosition, &info.bpm) != noErr)
  884. {
  885. info.ppqPosition = 0;
  886. info.bpm = 0;
  887. }
  888. UInt32 outDeltaSampleOffsetToNextBeat;
  889. double outCurrentMeasureDownBeat;
  890. float num;
  891. UInt32 den;
  892. if (CallHostMusicalTimeLocation (&outDeltaSampleOffsetToNextBeat, &num, &den,
  893. &outCurrentMeasureDownBeat) == noErr)
  894. {
  895. info.timeSigNumerator = (int) num;
  896. info.timeSigDenominator = (int) den;
  897. info.ppqPositionOfLastBarStart = outCurrentMeasureDownBeat;
  898. }
  899. double outCurrentSampleInTimeLine, outCycleStartBeat = 0, outCycleEndBeat = 0;
  900. Boolean playing = false, looping = false, playchanged;
  901. if (CallHostTransportState (&playing,
  902. &playchanged,
  903. &outCurrentSampleInTimeLine,
  904. &looping,
  905. &outCycleStartBeat,
  906. &outCycleEndBeat) != noErr)
  907. {
  908. // If the host doesn't support this callback, then use the sample time from lastTimeStamp:
  909. outCurrentSampleInTimeLine = lastTimeStamp.mSampleTime;
  910. }
  911. info.isPlaying = playing;
  912. info.timeInSamples = (int64) (outCurrentSampleInTimeLine + 0.5);
  913. info.timeInSeconds = info.timeInSamples / getSampleRate();
  914. info.isLooping = looping;
  915. info.ppqLoopStart = outCycleStartBeat;
  916. info.ppqLoopEnd = outCycleEndBeat;
  917. return true;
  918. }
  919. void sendAUEvent (const AudioUnitEventType type, const int juceParamIndex)
  920. {
  921. if (restoringState)
  922. return;
  923. auEvent.mEventType = type;
  924. auEvent.mArgument.mParameter.mParameterID = getAUParameterIDForIndex (juceParamIndex);
  925. AUEventListenerNotify (nullptr, nullptr, &auEvent);
  926. }
  927. void audioProcessorParameterChanged (AudioProcessor*, int index, float /*newValue*/) override
  928. {
  929. if (inParameterChangedCallback.get())
  930. {
  931. inParameterChangedCallback = false;
  932. return;
  933. }
  934. sendAUEvent (kAudioUnitEvent_ParameterValueChange, index);
  935. }
  936. void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) override
  937. {
  938. sendAUEvent (kAudioUnitEvent_BeginParameterChangeGesture, index);
  939. }
  940. void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) override
  941. {
  942. sendAUEvent (kAudioUnitEvent_EndParameterChangeGesture, index);
  943. }
  944. void audioProcessorChanged (AudioProcessor*, const ChangeDetails& details) override
  945. {
  946. audioProcessorChangedUpdater.update (details);
  947. }
  948. //==============================================================================
  949. // this will only ever be called by the bypass parameter
  950. void parameterValueChanged (int, float) override
  951. {
  952. if (! restoringState)
  953. PropertyChanged (kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0);
  954. }
  955. void parameterGestureChanged (int, bool) override {}
  956. //==============================================================================
  957. bool StreamFormatWritable (AudioUnitScope scope, AudioUnitElement element) override
  958. {
  959. const auto info = getElementInfo (scope, element);
  960. return ((! IsInitialized()) && (info.error == noErr));
  961. }
  962. bool ValidFormat (AudioUnitScope scope, AudioUnitElement element, const CAStreamBasicDescription& format) override
  963. {
  964. // DSP Quattro incorrectly uses global scope for the ValidFormat call
  965. if (scope == kAudioUnitScope_Global)
  966. return ValidFormat (kAudioUnitScope_Input, element, format)
  967. || ValidFormat (kAudioUnitScope_Output, element, format);
  968. const auto info = getElementInfo (scope, element);
  969. if (info.error != noErr)
  970. return false;
  971. if (info.kind == BusKind::wrapperOnly)
  972. return true;
  973. const int newNumChannels = static_cast<int> (format.NumberChannels());
  974. const int oldNumChannels = juceFilter->getChannelCountOfBus (info.isInput, info.busNr);
  975. if (newNumChannels == oldNumChannels)
  976. return true;
  977. if (AudioProcessor::Bus* bus = juceFilter->getBus (info.isInput, info.busNr))
  978. {
  979. if (! MusicDeviceBase::ValidFormat (scope, element, format))
  980. return false;
  981. #ifdef JucePlugin_PreferredChannelConfigurations
  982. short configs[][2] = {JucePlugin_PreferredChannelConfigurations};
  983. ignoreUnused (bus);
  984. return AudioUnitHelpers::isLayoutSupported (*juceFilter, info.isInput, info.busNr, newNumChannels, configs);
  985. #else
  986. return bus->isNumberOfChannelsSupported (newNumChannels);
  987. #endif
  988. }
  989. return false;
  990. }
  991. // AU requires us to override this for the sole reason that we need to find a default layout tag if the number of channels have changed
  992. OSStatus ChangeStreamFormat (AudioUnitScope scope, AudioUnitElement element, const CAStreamBasicDescription& old, const CAStreamBasicDescription& format) override
  993. {
  994. const auto info = getElementInfo (scope, element);
  995. if (info.error != noErr)
  996. return info.error;
  997. AudioChannelLayoutTag& currentTag = getCurrentLayout (info.isInput, info.busNr);
  998. const int newNumChannels = static_cast<int> (format.NumberChannels());
  999. const int oldNumChannels = juceFilter->getChannelCountOfBus (info.isInput, info.busNr);
  1000. #ifdef JucePlugin_PreferredChannelConfigurations
  1001. short configs[][2] = {JucePlugin_PreferredChannelConfigurations};
  1002. if (! AudioUnitHelpers::isLayoutSupported (*juceFilter, info.isInput, info.busNr, newNumChannels, configs))
  1003. return kAudioUnitErr_FormatNotSupported;
  1004. #endif
  1005. // predict channel layout
  1006. const auto set = [&]
  1007. {
  1008. if (info.kind == BusKind::wrapperOnly)
  1009. return AudioChannelSet::discreteChannels (newNumChannels);
  1010. if (newNumChannels != oldNumChannels)
  1011. return juceFilter->getBus (info.isInput, info.busNr)->supportedLayoutWithChannels (newNumChannels);
  1012. return juceFilter->getChannelLayoutOfBus (info.isInput, info.busNr);
  1013. }();
  1014. if (set == AudioChannelSet())
  1015. return kAudioUnitErr_FormatNotSupported;
  1016. const auto err = MusicDeviceBase::ChangeStreamFormat (scope, element, old, format);
  1017. if (err == noErr)
  1018. currentTag = CoreAudioLayouts::toCoreAudio (set);
  1019. return err;
  1020. }
  1021. //==============================================================================
  1022. ComponentResult Render (AudioUnitRenderActionFlags& ioActionFlags,
  1023. const AudioTimeStamp& inTimeStamp,
  1024. const UInt32 nFrames) override
  1025. {
  1026. lastTimeStamp = inTimeStamp;
  1027. jassert (! juceFilter->getHostTimeNs());
  1028. if ((inTimeStamp.mFlags & kAudioTimeStampHostTimeValid) != 0)
  1029. {
  1030. const auto timestamp = timeConversions.hostTimeToNanos (inTimeStamp.mHostTime);
  1031. juceFilter->setHostTimeNanos (&timestamp);
  1032. }
  1033. struct AtEndOfScope
  1034. {
  1035. ~AtEndOfScope() { proc.setHostTimeNanos (nullptr); }
  1036. AudioProcessor& proc;
  1037. };
  1038. const AtEndOfScope scope { *juceFilter };
  1039. // prepare buffers
  1040. {
  1041. pullInputAudio (ioActionFlags, inTimeStamp, nFrames);
  1042. prepareOutputBuffers (nFrames);
  1043. audioBuffer.reset();
  1044. }
  1045. ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence;
  1046. const int numInputBuses = AudioUnitHelpers::getBusCount (*juceFilter, true);
  1047. const int numOutputBuses = AudioUnitHelpers::getBusCount (*juceFilter, false);
  1048. // set buffer pointers to minimize copying
  1049. {
  1050. int chIdx = 0, numChannels = 0;
  1051. bool interleaved = false;
  1052. AudioBufferList* buffer = nullptr;
  1053. // use output pointers
  1054. for (int busIdx = 0; busIdx < numOutputBuses; ++busIdx)
  1055. {
  1056. GetAudioBufferList (false, busIdx, buffer, interleaved, numChannels);
  1057. const int* outLayoutMap = mapper.get (false, busIdx);
  1058. for (int ch = 0; ch < numChannels; ++ch)
  1059. audioBuffer.setBuffer (chIdx++, interleaved ? nullptr : static_cast<float*> (buffer->mBuffers[outLayoutMap[ch]].mData));
  1060. }
  1061. // use input pointers on remaining channels
  1062. for (int busIdx = 0; chIdx < totalInChannels;)
  1063. {
  1064. int channelIndexInBus = juceFilter->getOffsetInBusBufferForAbsoluteChannelIndex (true, chIdx, busIdx);
  1065. const bool badData = ! pulledSucceeded[busIdx];
  1066. if (! badData)
  1067. GetAudioBufferList (true, busIdx, buffer, interleaved, numChannels);
  1068. const int* inLayoutMap = mapper.get (true, busIdx);
  1069. const int n = juceFilter->getChannelCountOfBus (true, busIdx);
  1070. for (int ch = channelIndexInBus; ch < n; ++ch)
  1071. audioBuffer.setBuffer (chIdx++, interleaved || badData ? nullptr : static_cast<float*> (buffer->mBuffers[inLayoutMap[ch]].mData));
  1072. }
  1073. }
  1074. // copy input
  1075. {
  1076. for (int busIdx = 0; busIdx < numInputBuses; ++busIdx)
  1077. {
  1078. if (pulledSucceeded[busIdx])
  1079. audioBuffer.set (busIdx, GetInput ((UInt32) busIdx)->GetBufferList(), mapper.get (true, busIdx));
  1080. else
  1081. audioBuffer.clearInputBus (busIdx, (int) nFrames);
  1082. }
  1083. audioBuffer.clearUnusedChannels ((int) nFrames);
  1084. }
  1085. // swap midi buffers
  1086. {
  1087. const ScopedLock sl (incomingMidiLock);
  1088. midiEvents.clear();
  1089. incomingEvents.swapWith (midiEvents);
  1090. }
  1091. // process audio
  1092. processBlock (audioBuffer.getBuffer (nFrames), midiEvents);
  1093. // copy back
  1094. {
  1095. for (int busIdx = 0; busIdx < numOutputBuses; ++busIdx)
  1096. audioBuffer.get (busIdx, GetOutput ((UInt32) busIdx)->GetBufferList(), mapper.get (false, busIdx));
  1097. }
  1098. // process midi output
  1099. #if JucePlugin_ProducesMidiOutput || JucePlugin_IsMidiEffect
  1100. if (! midiEvents.isEmpty() && midiCallback.midiOutputCallback != nullptr)
  1101. pushMidiOutput (nFrames);
  1102. #endif
  1103. midiEvents.clear();
  1104. return noErr;
  1105. }
  1106. //==============================================================================
  1107. ComponentResult StartNote (MusicDeviceInstrumentID, MusicDeviceGroupID, NoteInstanceID*, UInt32, const MusicDeviceNoteParams&) override { return noErr; }
  1108. ComponentResult StopNote (MusicDeviceGroupID, NoteInstanceID, UInt32) override { return noErr; }
  1109. //==============================================================================
  1110. OSStatus HandleMidiEvent (UInt8 nStatus, UInt8 inChannel, UInt8 inData1, UInt8 inData2, UInt32 inStartFrame) override
  1111. {
  1112. #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect
  1113. const juce::uint8 data[] = { (juce::uint8) (nStatus | inChannel),
  1114. (juce::uint8) inData1,
  1115. (juce::uint8) inData2 };
  1116. const ScopedLock sl (incomingMidiLock);
  1117. incomingEvents.addEvent (data, 3, (int) inStartFrame);
  1118. return noErr;
  1119. #else
  1120. ignoreUnused (nStatus, inChannel, inData1);
  1121. ignoreUnused (inData2, inStartFrame);
  1122. return kAudioUnitErr_PropertyNotInUse;
  1123. #endif
  1124. }
  1125. OSStatus HandleSysEx (const UInt8* inData, UInt32 inLength) override
  1126. {
  1127. #if JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect
  1128. const ScopedLock sl (incomingMidiLock);
  1129. incomingEvents.addEvent (inData, (int) inLength, 0);
  1130. return noErr;
  1131. #else
  1132. ignoreUnused (inData, inLength);
  1133. return kAudioUnitErr_PropertyNotInUse;
  1134. #endif
  1135. }
  1136. //==============================================================================
  1137. ComponentResult GetPresets (CFArrayRef* outData) const override
  1138. {
  1139. if (outData != nullptr)
  1140. {
  1141. const int numPrograms = juceFilter->getNumPrograms();
  1142. clearPresetsArray();
  1143. presetsArray.insertMultiple (0, AUPreset(), numPrograms);
  1144. CFMutableArrayRef presetsArrayRef = CFArrayCreateMutable (nullptr, numPrograms, nullptr);
  1145. for (int i = 0; i < numPrograms; ++i)
  1146. {
  1147. String name (juceFilter->getProgramName(i));
  1148. if (name.isEmpty())
  1149. name = "Untitled";
  1150. AUPreset& p = presetsArray.getReference(i);
  1151. p.presetNumber = i;
  1152. p.presetName = name.toCFString();
  1153. CFArrayAppendValue (presetsArrayRef, &p);
  1154. }
  1155. *outData = (CFArrayRef) presetsArrayRef;
  1156. }
  1157. return noErr;
  1158. }
  1159. OSStatus NewFactoryPresetSet (const AUPreset& inNewFactoryPreset) override
  1160. {
  1161. const int numPrograms = juceFilter->getNumPrograms();
  1162. const SInt32 chosenPresetNumber = (int) inNewFactoryPreset.presetNumber;
  1163. if (chosenPresetNumber >= numPrograms)
  1164. return kAudioUnitErr_InvalidProperty;
  1165. AUPreset chosenPreset;
  1166. chosenPreset.presetNumber = chosenPresetNumber;
  1167. chosenPreset.presetName = juceFilter->getProgramName (chosenPresetNumber).toCFString();
  1168. juceFilter->setCurrentProgram (chosenPresetNumber);
  1169. SetAFactoryPresetAsCurrent (chosenPreset);
  1170. return noErr;
  1171. }
  1172. //==============================================================================
  1173. class EditorCompHolder : public Component
  1174. {
  1175. public:
  1176. EditorCompHolder (AudioProcessorEditor* const editor)
  1177. {
  1178. addAndMakeVisible (editor);
  1179. #if ! JucePlugin_EditorRequiresKeyboardFocus
  1180. setWantsKeyboardFocus (false);
  1181. #else
  1182. setWantsKeyboardFocus (true);
  1183. #endif
  1184. setBounds (getSizeToContainChild());
  1185. lastBounds = getBounds();
  1186. }
  1187. ~EditorCompHolder() override
  1188. {
  1189. deleteAllChildren(); // note that we can't use a std::unique_ptr because the editor may
  1190. // have been transferred to another parent which takes over ownership.
  1191. }
  1192. Rectangle<int> getSizeToContainChild()
  1193. {
  1194. if (auto* editor = getChildComponent (0))
  1195. return getLocalArea (editor, editor->getLocalBounds());
  1196. return {};
  1197. }
  1198. static NSView* createViewFor (AudioProcessor* filter, JuceAU* au, AudioProcessorEditor* const editor)
  1199. {
  1200. auto* editorCompHolder = new EditorCompHolder (editor);
  1201. auto r = convertToHostBounds (makeNSRect (editorCompHolder->getSizeToContainChild()));
  1202. static JuceUIViewClass cls;
  1203. auto* view = [[cls.createInstance() initWithFrame: r] autorelease];
  1204. JuceUIViewClass::setFilter (view, filter);
  1205. JuceUIViewClass::setAU (view, au);
  1206. JuceUIViewClass::setEditor (view, editorCompHolder);
  1207. [view setHidden: NO];
  1208. [view setPostsFrameChangedNotifications: YES];
  1209. [[NSNotificationCenter defaultCenter] addObserver: view
  1210. selector: @selector (applicationWillTerminate:)
  1211. name: NSApplicationWillTerminateNotification
  1212. object: nil];
  1213. activeUIs.add (view);
  1214. editorCompHolder->addToDesktop (0, (void*) view);
  1215. editorCompHolder->setVisible (view);
  1216. return view;
  1217. }
  1218. void parentSizeChanged() override
  1219. {
  1220. resizeHostWindow();
  1221. if (auto* editor = getChildComponent (0))
  1222. editor->repaint();
  1223. }
  1224. void childBoundsChanged (Component*) override
  1225. {
  1226. auto b = getSizeToContainChild();
  1227. if (lastBounds != b)
  1228. {
  1229. lastBounds = b;
  1230. setSize (jmax (32, b.getWidth()), jmax (32, b.getHeight()));
  1231. resizeHostWindow();
  1232. }
  1233. }
  1234. bool keyPressed (const KeyPress&) override
  1235. {
  1236. if (getHostType().isAbletonLive())
  1237. {
  1238. static NSTimeInterval lastEventTime = 0; // check we're not recursively sending the same event
  1239. NSTimeInterval eventTime = [[NSApp currentEvent] timestamp];
  1240. if (lastEventTime != eventTime)
  1241. {
  1242. lastEventTime = eventTime;
  1243. NSView* view = (NSView*) getWindowHandle();
  1244. NSView* hostView = [view superview];
  1245. NSWindow* hostWindow = [hostView window];
  1246. [hostWindow makeFirstResponder: hostView];
  1247. [hostView keyDown: (NSEvent*) [NSApp currentEvent]];
  1248. [hostWindow makeFirstResponder: view];
  1249. }
  1250. }
  1251. return false;
  1252. }
  1253. void resizeHostWindow()
  1254. {
  1255. [CATransaction begin];
  1256. [CATransaction setValue:(id) kCFBooleanTrue forKey:kCATransactionDisableActions];
  1257. auto rect = convertToHostBounds (makeNSRect (lastBounds));
  1258. auto* view = (NSView*) getWindowHandle();
  1259. auto superRect = [[view superview] frame];
  1260. superRect.size.width = rect.size.width;
  1261. superRect.size.height = rect.size.height;
  1262. [[view superview] setFrame: superRect];
  1263. [view setFrame: rect];
  1264. [CATransaction commit];
  1265. [view setNeedsDisplay: YES];
  1266. }
  1267. private:
  1268. Rectangle<int> lastBounds;
  1269. JUCE_DECLARE_NON_COPYABLE (EditorCompHolder)
  1270. };
  1271. void deleteActiveEditors()
  1272. {
  1273. for (int i = activeUIs.size(); --i >= 0;)
  1274. {
  1275. id ui = (id) activeUIs.getUnchecked(i);
  1276. if (JuceUIViewClass::getAU (ui) == this)
  1277. JuceUIViewClass::deleteEditor (ui);
  1278. }
  1279. }
  1280. //==============================================================================
  1281. struct JuceUIViewClass : public ObjCClass<NSView>
  1282. {
  1283. JuceUIViewClass() : ObjCClass<NSView> ("JUCEAUView_")
  1284. {
  1285. addIvar<AudioProcessor*> ("filter");
  1286. addIvar<JuceAU*> ("au");
  1287. addIvar<EditorCompHolder*> ("editor");
  1288. addMethod (@selector (dealloc), dealloc);
  1289. addMethod (@selector (applicationWillTerminate:), applicationWillTerminate);
  1290. addMethod (@selector (viewDidMoveToWindow), viewDidMoveToWindow);
  1291. addMethod (@selector (mouseDownCanMoveWindow), mouseDownCanMoveWindow);
  1292. registerClass();
  1293. }
  1294. static void deleteEditor (id self)
  1295. {
  1296. std::unique_ptr<EditorCompHolder> editorComp (getEditor (self));
  1297. if (editorComp != nullptr)
  1298. {
  1299. if (editorComp->getChildComponent(0) != nullptr
  1300. && activePlugins.contains (getAU (self))) // plugin may have been deleted before the UI
  1301. {
  1302. AudioProcessor* const filter = getIvar<AudioProcessor*> (self, "filter");
  1303. filter->editorBeingDeleted ((AudioProcessorEditor*) editorComp->getChildComponent(0));
  1304. }
  1305. editorComp = nullptr;
  1306. setEditor (self, nullptr);
  1307. }
  1308. }
  1309. static JuceAU* getAU (id self) { return getIvar<JuceAU*> (self, "au"); }
  1310. static EditorCompHolder* getEditor (id self) { return getIvar<EditorCompHolder*> (self, "editor"); }
  1311. static void setFilter (id self, AudioProcessor* filter) { object_setInstanceVariable (self, "filter", filter); }
  1312. static void setAU (id self, JuceAU* au) { object_setInstanceVariable (self, "au", au); }
  1313. static void setEditor (id self, EditorCompHolder* e) { object_setInstanceVariable (self, "editor", e); }
  1314. private:
  1315. static void dealloc (id self, SEL)
  1316. {
  1317. if (activeUIs.contains (self))
  1318. shutdown (self);
  1319. sendSuperclassMessage<void> (self, @selector (dealloc));
  1320. }
  1321. static void applicationWillTerminate (id self, SEL, NSNotification*)
  1322. {
  1323. shutdown (self);
  1324. }
  1325. static void shutdown (id self)
  1326. {
  1327. [[NSNotificationCenter defaultCenter] removeObserver: self];
  1328. deleteEditor (self);
  1329. jassert (activeUIs.contains (self));
  1330. activeUIs.removeFirstMatchingValue (self);
  1331. if (activePlugins.size() + activeUIs.size() == 0)
  1332. {
  1333. // there's some kind of component currently modal, but the host
  1334. // is trying to delete our plugin..
  1335. jassert (Component::getCurrentlyModalComponent() == nullptr);
  1336. shutdownJuce_GUI();
  1337. }
  1338. }
  1339. static void viewDidMoveToWindow (id self, SEL)
  1340. {
  1341. if (NSWindow* w = [(NSView*) self window])
  1342. {
  1343. [w setAcceptsMouseMovedEvents: YES];
  1344. if (EditorCompHolder* const editorComp = getEditor (self))
  1345. [w makeFirstResponder: (NSView*) editorComp->getWindowHandle()];
  1346. }
  1347. }
  1348. static BOOL mouseDownCanMoveWindow (id, SEL)
  1349. {
  1350. return NO;
  1351. }
  1352. };
  1353. //==============================================================================
  1354. struct JuceUICreationClass : public ObjCClass<NSObject>
  1355. {
  1356. JuceUICreationClass() : ObjCClass<NSObject> ("JUCE_AUCocoaViewClass_")
  1357. {
  1358. addMethod (@selector (interfaceVersion), interfaceVersion);
  1359. addMethod (@selector (description), description);
  1360. addMethod (@selector (uiViewForAudioUnit:withSize:), uiViewForAudioUnit);
  1361. addProtocol (@protocol (AUCocoaUIBase));
  1362. registerClass();
  1363. }
  1364. private:
  1365. static unsigned int interfaceVersion (id, SEL) { return 0; }
  1366. static NSString* description (id, SEL)
  1367. {
  1368. return [NSString stringWithString: nsStringLiteral (JucePlugin_Name)];
  1369. }
  1370. static NSView* uiViewForAudioUnit (id, SEL, AudioUnit inAudioUnit, NSSize)
  1371. {
  1372. void* pointers[2];
  1373. UInt32 propertySize = sizeof (pointers);
  1374. if (AudioUnitGetProperty (inAudioUnit, juceFilterObjectPropertyID,
  1375. kAudioUnitScope_Global, 0, pointers, &propertySize) == noErr)
  1376. {
  1377. if (AudioProcessor* filter = static_cast<AudioProcessor*> (pointers[0]))
  1378. if (AudioProcessorEditor* editorComp = filter->createEditorIfNeeded())
  1379. {
  1380. #if JucePlugin_Enable_ARA
  1381. jassert (dynamic_cast<AudioProcessorEditorARAExtension*> (editorComp) != nullptr);
  1382. // for proper view embedding, ARA plug-ins must be resizable
  1383. jassert (editorComp->isResizable());
  1384. #endif
  1385. return EditorCompHolder::createViewFor (filter, static_cast<JuceAU*> (pointers[1]), editorComp);
  1386. }
  1387. }
  1388. return nil;
  1389. }
  1390. };
  1391. private:
  1392. //==============================================================================
  1393. /* The call to AUBase::PropertyChanged may allocate hence the need for this class */
  1394. class AudioProcessorChangedUpdater final : private AsyncUpdater
  1395. {
  1396. public:
  1397. explicit AudioProcessorChangedUpdater (JuceAU& o) : owner (o) {}
  1398. ~AudioProcessorChangedUpdater() override { cancelPendingUpdate(); }
  1399. void update (const ChangeDetails& details)
  1400. {
  1401. int flags = 0;
  1402. if (details.latencyChanged)
  1403. flags |= latencyChangedFlag;
  1404. if (details.parameterInfoChanged)
  1405. flags |= parameterInfoChangedFlag;
  1406. if (details.programChanged)
  1407. flags |= programChangedFlag;
  1408. if (flags != 0)
  1409. {
  1410. callbackFlags.fetch_or (flags);
  1411. if (MessageManager::getInstance()->isThisTheMessageThread())
  1412. handleAsyncUpdate();
  1413. else
  1414. triggerAsyncUpdate();
  1415. }
  1416. }
  1417. private:
  1418. void handleAsyncUpdate() override
  1419. {
  1420. const auto flags = callbackFlags.exchange (0);
  1421. if ((flags & latencyChangedFlag) != 0)
  1422. owner.PropertyChanged (kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0);
  1423. if ((flags & parameterInfoChangedFlag) != 0)
  1424. {
  1425. owner.PropertyChanged (kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0);
  1426. owner.PropertyChanged (kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, 0);
  1427. }
  1428. owner.PropertyChanged (kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, 0);
  1429. if ((flags & programChangedFlag) != 0)
  1430. {
  1431. owner.refreshCurrentPreset();
  1432. owner.PropertyChanged (kAudioUnitProperty_PresentPreset, kAudioUnitScope_Global, 0);
  1433. }
  1434. }
  1435. JuceAU& owner;
  1436. static constexpr int latencyChangedFlag = 1 << 0,
  1437. parameterInfoChangedFlag = 1 << 1,
  1438. programChangedFlag = 1 << 2;
  1439. std::atomic<int> callbackFlags { 0 };
  1440. };
  1441. //==============================================================================
  1442. AudioUnitHelpers::CoreAudioBufferList audioBuffer;
  1443. MidiBuffer midiEvents, incomingEvents;
  1444. bool prepared = false, isBypassed = false, restoringState = false;
  1445. //==============================================================================
  1446. #if JUCE_FORCE_USE_LEGACY_PARAM_IDS
  1447. static constexpr bool forceUseLegacyParamIDs = true;
  1448. #else
  1449. static constexpr bool forceUseLegacyParamIDs = false;
  1450. #endif
  1451. //==============================================================================
  1452. LegacyAudioParametersWrapper juceParameters;
  1453. std::unordered_map<int32, AudioProcessorParameter*> paramMap;
  1454. Array<AudioUnitParameterID> auParamIDs;
  1455. Array<const AudioProcessorParameterGroup*> parameterGroups;
  1456. // Stores the parameter IDs in the order that they will be reported to the host.
  1457. std::vector<AudioUnitParameterID> cachedParameterList;
  1458. //==============================================================================
  1459. // According to the docs, this is the maximum size of a MIDIPacketList.
  1460. static constexpr UInt32 packetListBytes = 65536;
  1461. CoreAudioTimeConversions timeConversions;
  1462. AudioUnitEvent auEvent;
  1463. mutable Array<AUPreset> presetsArray;
  1464. CriticalSection incomingMidiLock;
  1465. AUMIDIOutputCallbackStruct midiCallback;
  1466. AudioTimeStamp lastTimeStamp;
  1467. int totalInChannels, totalOutChannels;
  1468. HeapBlock<bool> pulledSucceeded;
  1469. HeapBlock<MIDIPacketList> packetList { packetListBytes, 1 };
  1470. ThreadLocalValue<bool> inParameterChangedCallback;
  1471. AudioProcessorChangedUpdater audioProcessorChangedUpdater { *this };
  1472. //==============================================================================
  1473. Array<AUChannelInfo> channelInfo;
  1474. Array<Array<AudioChannelLayoutTag>> supportedInputLayouts, supportedOutputLayouts;
  1475. Array<AudioChannelLayoutTag> currentInputLayout, currentOutputLayout;
  1476. //==============================================================================
  1477. AudioUnitHelpers::ChannelRemapper mapper;
  1478. //==============================================================================
  1479. OwnedArray<OwnedArray<const __CFString>> parameterValueStringArrays;
  1480. //==============================================================================
  1481. AudioProcessorParameter* bypassParam = nullptr;
  1482. //==============================================================================
  1483. static NSRect convertToHostBounds (NSRect pluginRect)
  1484. {
  1485. auto desktopScale = Desktop::getInstance().getGlobalScaleFactor();
  1486. if (approximatelyEqual (desktopScale, 1.0f))
  1487. return pluginRect;
  1488. return NSMakeRect (static_cast<CGFloat> (pluginRect.origin.x * desktopScale),
  1489. static_cast<CGFloat> (pluginRect.origin.y * desktopScale),
  1490. static_cast<CGFloat> (pluginRect.size.width * desktopScale),
  1491. static_cast<CGFloat> (pluginRect.size.height * desktopScale));
  1492. }
  1493. static NSRect convertFromHostBounds (NSRect hostRect)
  1494. {
  1495. auto desktopScale = Desktop::getInstance().getGlobalScaleFactor();
  1496. if (approximatelyEqual (desktopScale, 1.0f))
  1497. return hostRect;
  1498. return NSMakeRect (static_cast<CGFloat> (hostRect.origin.x / desktopScale),
  1499. static_cast<CGFloat> (hostRect.origin.y / desktopScale),
  1500. static_cast<CGFloat> (hostRect.size.width / desktopScale),
  1501. static_cast<CGFloat> (hostRect.size.height / desktopScale));
  1502. }
  1503. //==============================================================================
  1504. void pullInputAudio (AudioUnitRenderActionFlags& flags, const AudioTimeStamp& timestamp, const UInt32 nFrames) noexcept
  1505. {
  1506. const unsigned int numInputBuses = GetScope (kAudioUnitScope_Input).GetNumberOfElements();
  1507. for (unsigned int i = 0; i < numInputBuses; ++i)
  1508. {
  1509. if (AUInputElement* input = GetInput (i))
  1510. {
  1511. const bool succeeded = (input->PullInput (flags, timestamp, i, nFrames) == noErr);
  1512. if ((flags & kAudioUnitRenderAction_OutputIsSilence) != 0 && succeeded)
  1513. AudioUnitHelpers::clearAudioBuffer (input->GetBufferList());
  1514. pulledSucceeded[i] = succeeded;
  1515. }
  1516. }
  1517. }
  1518. void prepareOutputBuffers (const UInt32 nFrames) noexcept
  1519. {
  1520. const auto numProcessorBuses = AudioUnitHelpers::getBusCount (*juceFilter, false);
  1521. const auto numWrapperBuses = GetScope (kAudioUnitScope_Output).GetNumberOfElements();
  1522. for (UInt32 busIdx = 0; busIdx < numWrapperBuses; ++busIdx)
  1523. {
  1524. AUOutputElement* output = GetOutput (busIdx);
  1525. if (output->WillAllocateBuffer())
  1526. output->PrepareBuffer (nFrames);
  1527. if (busIdx >= (UInt32) numProcessorBuses)
  1528. AudioUnitHelpers::clearAudioBuffer (output->GetBufferList());
  1529. }
  1530. }
  1531. void processBlock (juce::AudioBuffer<float>& buffer, MidiBuffer& midiBuffer) noexcept
  1532. {
  1533. const ScopedLock sl (juceFilter->getCallbackLock());
  1534. if (juceFilter->isSuspended())
  1535. {
  1536. buffer.clear();
  1537. }
  1538. else if (bypassParam == nullptr && isBypassed)
  1539. {
  1540. juceFilter->processBlockBypassed (buffer, midiBuffer);
  1541. }
  1542. else
  1543. {
  1544. juceFilter->processBlock (buffer, midiBuffer);
  1545. }
  1546. }
  1547. void pushMidiOutput (UInt32 nFrames) noexcept
  1548. {
  1549. MIDIPacket* end = nullptr;
  1550. const auto init = [&]
  1551. {
  1552. end = MIDIPacketListInit (packetList);
  1553. };
  1554. const auto send = [&]
  1555. {
  1556. midiCallback.midiOutputCallback (midiCallback.userData, &lastTimeStamp, 0, packetList);
  1557. };
  1558. const auto add = [&] (const MidiMessageMetadata& metadata)
  1559. {
  1560. end = MIDIPacketListAdd (packetList,
  1561. packetListBytes,
  1562. end,
  1563. static_cast<MIDITimeStamp> (metadata.samplePosition),
  1564. static_cast<ByteCount> (metadata.numBytes),
  1565. metadata.data);
  1566. };
  1567. init();
  1568. for (const auto metadata : midiEvents)
  1569. {
  1570. jassert (isPositiveAndBelow (metadata.samplePosition, nFrames));
  1571. ignoreUnused (nFrames);
  1572. add (metadata);
  1573. if (end == nullptr)
  1574. {
  1575. send();
  1576. init();
  1577. add (metadata);
  1578. if (end == nullptr)
  1579. {
  1580. // If this is hit, the size of this midi packet exceeds the maximum size of
  1581. // a MIDIPacketList. Large SysEx messages should be broken up into smaller
  1582. // chunks.
  1583. jassertfalse;
  1584. init();
  1585. }
  1586. }
  1587. }
  1588. send();
  1589. }
  1590. void GetAudioBufferList (bool isInput, int busIdx, AudioBufferList*& bufferList, bool& interleaved, int& numChannels)
  1591. {
  1592. AUIOElement* element = GetElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, static_cast<UInt32> (busIdx))->AsIOElement();
  1593. jassert (element != nullptr);
  1594. bufferList = &element->GetBufferList();
  1595. jassert (bufferList->mNumberBuffers > 0);
  1596. interleaved = AudioUnitHelpers::isAudioBufferInterleaved (*bufferList);
  1597. numChannels = static_cast<int> (interleaved ? bufferList->mBuffers[0].mNumberChannels : bufferList->mNumberBuffers);
  1598. }
  1599. //==============================================================================
  1600. static OSStatus scopeToDirection (AudioUnitScope scope, bool& isInput) noexcept
  1601. {
  1602. isInput = (scope == kAudioUnitScope_Input);
  1603. return (scope != kAudioUnitScope_Input
  1604. && scope != kAudioUnitScope_Output)
  1605. ? (OSStatus) kAudioUnitErr_InvalidScope : (OSStatus) noErr;
  1606. }
  1607. enum class BusKind
  1608. {
  1609. processor,
  1610. wrapperOnly,
  1611. };
  1612. struct ElementInfo
  1613. {
  1614. int busNr;
  1615. BusKind kind;
  1616. bool isInput;
  1617. OSStatus error;
  1618. };
  1619. ElementInfo getElementInfo (AudioUnitScope scope, AudioUnitElement element) noexcept
  1620. {
  1621. bool isInput = false;
  1622. OSStatus err;
  1623. if ((err = scopeToDirection (scope, isInput)) != noErr)
  1624. return { {}, {}, {}, err };
  1625. const auto busIdx = static_cast<int> (element);
  1626. if (isPositiveAndBelow (busIdx, AudioUnitHelpers::getBusCount (*juceFilter, isInput)))
  1627. return { busIdx, BusKind::processor, isInput, noErr };
  1628. if (isPositiveAndBelow (busIdx, AudioUnitHelpers::getBusCountForWrapper (*juceFilter, isInput)))
  1629. return { busIdx, BusKind::wrapperOnly, isInput, noErr };
  1630. return { {}, {}, {}, kAudioUnitErr_InvalidElement };
  1631. }
  1632. OSStatus GetParameterList (AudioUnitScope inScope, AudioUnitParameterID* outParameterList, UInt32& outNumParameters) override
  1633. {
  1634. if (forceUseLegacyParamIDs || inScope != kAudioUnitScope_Global)
  1635. return MusicDeviceBase::GetParameterList (inScope, outParameterList, outNumParameters);
  1636. outNumParameters = (UInt32) juceParameters.size();
  1637. if (outParameterList == nullptr)
  1638. return noErr;
  1639. if (cachedParameterList.empty())
  1640. {
  1641. struct ParamInfo
  1642. {
  1643. AudioUnitParameterID identifier;
  1644. int versionHint;
  1645. };
  1646. std::vector<ParamInfo> vec;
  1647. vec.reserve (juceParameters.size());
  1648. for (const auto* param : juceParameters)
  1649. vec.push_back ({ generateAUParameterID (*param), param->getVersionHint() });
  1650. std::sort (vec.begin(), vec.end(), [] (auto a, auto b) { return a.identifier < b.identifier; });
  1651. std::stable_sort (vec.begin(), vec.end(), [] (auto a, auto b) { return a.versionHint < b.versionHint; });
  1652. std::transform (vec.begin(), vec.end(), std::back_inserter (cachedParameterList), [] (auto x) { return x.identifier; });
  1653. }
  1654. std::copy (cachedParameterList.begin(), cachedParameterList.end(), outParameterList);
  1655. return noErr;
  1656. }
  1657. //==============================================================================
  1658. void addParameters()
  1659. {
  1660. parameterGroups = juceFilter->getParameterTree().getSubgroups (true);
  1661. juceParameters.update (*juceFilter, forceUseLegacyParamIDs);
  1662. const int numParams = juceParameters.getNumParameters();
  1663. if (forceUseLegacyParamIDs)
  1664. {
  1665. Globals()->UseIndexedParameters (numParams);
  1666. }
  1667. else
  1668. {
  1669. for (auto* param : juceParameters)
  1670. {
  1671. const AudioUnitParameterID auParamID = generateAUParameterID (*param);
  1672. // Consider yourself very unlucky if you hit this assertion. The hash codes of your
  1673. // parameter ids are not unique.
  1674. jassert (paramMap.find (static_cast<int32> (auParamID)) == paramMap.end());
  1675. auParamIDs.add (auParamID);
  1676. paramMap.emplace (static_cast<int32> (auParamID), param);
  1677. Globals()->SetParameter (auParamID, param->getValue());
  1678. }
  1679. }
  1680. #if JUCE_DEBUG
  1681. // Some hosts can't handle the huge numbers of discrete parameter values created when
  1682. // using the default number of steps.
  1683. for (auto* param : juceParameters)
  1684. if (param->isDiscrete())
  1685. jassert (param->getNumSteps() != AudioProcessor::getDefaultNumParameterSteps());
  1686. #endif
  1687. parameterValueStringArrays.ensureStorageAllocated (numParams);
  1688. for (auto* param : juceParameters)
  1689. {
  1690. OwnedArray<const __CFString>* stringValues = nullptr;
  1691. auto initialValue = param->getValue();
  1692. bool paramIsLegacy = dynamic_cast<LegacyAudioParameter*> (param) != nullptr;
  1693. if (param->isDiscrete() && (! forceUseLegacyParamIDs))
  1694. {
  1695. const auto numSteps = param->getNumSteps();
  1696. stringValues = new OwnedArray<const __CFString>();
  1697. stringValues->ensureStorageAllocated (numSteps);
  1698. const auto maxValue = getMaximumParameterValue (param);
  1699. auto getTextValue = [param, paramIsLegacy] (float value)
  1700. {
  1701. if (paramIsLegacy)
  1702. {
  1703. param->setValue (value);
  1704. return param->getCurrentValueAsText();
  1705. }
  1706. return param->getText (value, 256);
  1707. };
  1708. for (int i = 0; i < numSteps; ++i)
  1709. {
  1710. auto value = (float) i / maxValue;
  1711. stringValues->add (CFStringCreateCopy (nullptr, (getTextValue (value).toCFString())));
  1712. }
  1713. }
  1714. if (paramIsLegacy)
  1715. param->setValue (initialValue);
  1716. parameterValueStringArrays.add (stringValues);
  1717. }
  1718. if ((bypassParam = juceFilter->getBypassParameter()) != nullptr)
  1719. bypassParam->addListener (this);
  1720. }
  1721. //==============================================================================
  1722. static AudioUnitParameterID generateAUParameterID (const AudioProcessorParameter& param)
  1723. {
  1724. const String& juceParamID = LegacyAudioParameter::getParamID (&param, forceUseLegacyParamIDs);
  1725. AudioUnitParameterID paramHash = static_cast<AudioUnitParameterID> (juceParamID.hashCode());
  1726. #if JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
  1727. // studio one doesn't like negative parameters
  1728. paramHash &= ~(((AudioUnitParameterID) 1) << (sizeof (AudioUnitParameterID) * 8 - 1));
  1729. #endif
  1730. return forceUseLegacyParamIDs ? static_cast<AudioUnitParameterID> (juceParamID.getIntValue())
  1731. : paramHash;
  1732. }
  1733. inline AudioUnitParameterID getAUParameterIDForIndex (int paramIndex) const noexcept
  1734. {
  1735. return forceUseLegacyParamIDs ? static_cast<AudioUnitParameterID> (paramIndex)
  1736. : auParamIDs.getReference (paramIndex);
  1737. }
  1738. AudioProcessorParameter* getParameterForAUParameterID (AudioUnitParameterID address) const noexcept
  1739. {
  1740. const auto index = static_cast<int32> (address);
  1741. if (forceUseLegacyParamIDs)
  1742. return juceParameters.getParamForIndex (index);
  1743. const auto iter = paramMap.find (index);
  1744. return iter != paramMap.end() ? iter->second : nullptr;
  1745. }
  1746. //==============================================================================
  1747. OSStatus syncAudioUnitWithProcessor()
  1748. {
  1749. OSStatus err = noErr;
  1750. const auto numWrapperInputs = AudioUnitHelpers::getBusCountForWrapper (*juceFilter, true);
  1751. const auto numWrapperOutputs = AudioUnitHelpers::getBusCountForWrapper (*juceFilter, false);
  1752. if ((err = MusicDeviceBase::SetBusCount (kAudioUnitScope_Input, static_cast<UInt32> (numWrapperInputs))) != noErr)
  1753. return err;
  1754. if ((err = MusicDeviceBase::SetBusCount (kAudioUnitScope_Output, static_cast<UInt32> (numWrapperOutputs))) != noErr)
  1755. return err;
  1756. addSupportedLayoutTags();
  1757. const auto numProcessorInputs = AudioUnitHelpers::getBusCount (*juceFilter, true);
  1758. const auto numProcessorOutputs = AudioUnitHelpers::getBusCount (*juceFilter, false);
  1759. for (int i = 0; i < numProcessorInputs; ++i)
  1760. if ((err = syncAudioUnitWithChannelSet (true, i, juceFilter->getChannelLayoutOfBus (true, i))) != noErr)
  1761. return err;
  1762. for (int i = 0; i < numProcessorOutputs; ++i)
  1763. if ((err = syncAudioUnitWithChannelSet (false, i, juceFilter->getChannelLayoutOfBus (false, i))) != noErr)
  1764. return err;
  1765. return noErr;
  1766. }
  1767. OSStatus syncProcessorWithAudioUnit()
  1768. {
  1769. const int numInputBuses = AudioUnitHelpers::getBusCount (*juceFilter, true);
  1770. const int numOutputBuses = AudioUnitHelpers::getBusCount (*juceFilter, false);
  1771. const int numInputElements = static_cast<int> (GetScope(kAudioUnitScope_Input). GetNumberOfElements());
  1772. const int numOutputElements = static_cast<int> (GetScope(kAudioUnitScope_Output).GetNumberOfElements());
  1773. AudioProcessor::BusesLayout requestedLayouts;
  1774. for (int dir = 0; dir < 2; ++dir)
  1775. {
  1776. const bool isInput = (dir == 0);
  1777. const int n = (isInput ? numInputBuses : numOutputBuses);
  1778. const int numAUElements = (isInput ? numInputElements : numOutputElements);
  1779. Array<AudioChannelSet>& requestedBuses = (isInput ? requestedLayouts.inputBuses : requestedLayouts.outputBuses);
  1780. for (int busIdx = 0; busIdx < n; ++busIdx)
  1781. {
  1782. const AUIOElement* element = (busIdx < numAUElements ? GetIOElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, (UInt32) busIdx) : nullptr);
  1783. const int numChannels = (element != nullptr ? static_cast<int> (element->GetStreamFormat().NumberChannels()) : 0);
  1784. AudioChannelLayoutTag currentLayoutTag = isInput ? currentInputLayout[busIdx] : currentOutputLayout[busIdx];
  1785. const int tagNumChannels = currentLayoutTag & 0xffff;
  1786. if (numChannels != tagNumChannels)
  1787. return kAudioUnitErr_FormatNotSupported;
  1788. requestedBuses.add (CoreAudioLayouts::fromCoreAudio (currentLayoutTag));
  1789. }
  1790. }
  1791. #ifdef JucePlugin_PreferredChannelConfigurations
  1792. short configs[][2] = {JucePlugin_PreferredChannelConfigurations};
  1793. if (! AudioProcessor::containsLayout (requestedLayouts, configs))
  1794. return kAudioUnitErr_FormatNotSupported;
  1795. #endif
  1796. if (! AudioUnitHelpers::setBusesLayout (juceFilter.get(), requestedLayouts))
  1797. return kAudioUnitErr_FormatNotSupported;
  1798. // update total channel count
  1799. totalInChannels = juceFilter->getTotalNumInputChannels();
  1800. totalOutChannels = juceFilter->getTotalNumOutputChannels();
  1801. return noErr;
  1802. }
  1803. OSStatus syncAudioUnitWithChannelSet (bool isInput, int busNr, const AudioChannelSet& channelSet)
  1804. {
  1805. const int numChannels = channelSet.size();
  1806. getCurrentLayout (isInput, busNr) = CoreAudioLayouts::toCoreAudio (channelSet);
  1807. // is this bus activated?
  1808. if (numChannels == 0)
  1809. return noErr;
  1810. if (AUIOElement* element = GetIOElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, (UInt32) busNr))
  1811. {
  1812. element->SetName ((CFStringRef) juceStringToNS (juceFilter->getBus (isInput, busNr)->getName()));
  1813. CAStreamBasicDescription streamDescription;
  1814. streamDescription.mSampleRate = getSampleRate();
  1815. streamDescription.SetCanonical ((UInt32) numChannels, false);
  1816. return element->SetStreamFormat (streamDescription);
  1817. }
  1818. else
  1819. jassertfalse;
  1820. return kAudioUnitErr_InvalidElement;
  1821. }
  1822. //==============================================================================
  1823. void clearPresetsArray() const
  1824. {
  1825. for (int i = presetsArray.size(); --i >= 0;)
  1826. CFRelease (presetsArray.getReference(i).presetName);
  1827. presetsArray.clear();
  1828. }
  1829. void refreshCurrentPreset()
  1830. {
  1831. // this will make the AU host re-read and update the current preset name
  1832. // in case it was changed here in the plug-in:
  1833. const int currentProgramNumber = juceFilter->getCurrentProgram();
  1834. const String currentProgramName = juceFilter->getProgramName (currentProgramNumber);
  1835. AUPreset currentPreset;
  1836. currentPreset.presetNumber = currentProgramNumber;
  1837. currentPreset.presetName = currentProgramName.toCFString();
  1838. SetAFactoryPresetAsCurrent (currentPreset);
  1839. }
  1840. //==============================================================================
  1841. Array<AudioChannelLayoutTag>& getSupportedBusLayouts (bool isInput, int bus) noexcept { return (isInput ? supportedInputLayouts : supportedOutputLayouts).getReference (bus); }
  1842. const Array<AudioChannelLayoutTag>& getSupportedBusLayouts (bool isInput, int bus) const noexcept { return (isInput ? supportedInputLayouts : supportedOutputLayouts).getReference (bus); }
  1843. AudioChannelLayoutTag& getCurrentLayout (bool isInput, int bus) noexcept { return (isInput ? currentInputLayout : currentOutputLayout).getReference (bus); }
  1844. AudioChannelLayoutTag getCurrentLayout (bool isInput, int bus) const noexcept { return (isInput ? currentInputLayout : currentOutputLayout)[bus]; }
  1845. //==============================================================================
  1846. void addSupportedLayoutTagsForBus (bool isInput, int busNum, Array<AudioChannelLayoutTag>& tags)
  1847. {
  1848. if (AudioProcessor::Bus* bus = juceFilter->getBus (isInput, busNum))
  1849. {
  1850. #ifndef JucePlugin_PreferredChannelConfigurations
  1851. auto& knownTags = CoreAudioLayouts::getKnownCoreAudioTags();
  1852. for (auto tag : knownTags)
  1853. if (bus->isLayoutSupported (CoreAudioLayouts::fromCoreAudio (tag)))
  1854. tags.addIfNotAlreadyThere (tag);
  1855. #endif
  1856. // add discrete layout tags
  1857. int n = bus->getMaxSupportedChannels (maxChannelsToProbeFor());
  1858. for (int ch = 0; ch < n; ++ch)
  1859. {
  1860. #ifdef JucePlugin_PreferredChannelConfigurations
  1861. const short configs[][2] = { JucePlugin_PreferredChannelConfigurations };
  1862. if (AudioUnitHelpers::isLayoutSupported (*juceFilter, isInput, busNum, ch, configs))
  1863. tags.addIfNotAlreadyThere (static_cast<AudioChannelLayoutTag> ((int) kAudioChannelLayoutTag_DiscreteInOrder | ch));
  1864. #else
  1865. if (bus->isLayoutSupported (AudioChannelSet::discreteChannels (ch)))
  1866. tags.addIfNotAlreadyThere (static_cast<AudioChannelLayoutTag> ((int) kAudioChannelLayoutTag_DiscreteInOrder | ch));
  1867. #endif
  1868. }
  1869. }
  1870. }
  1871. void addSupportedLayoutTagsForDirection (bool isInput)
  1872. {
  1873. auto& layouts = isInput ? supportedInputLayouts : supportedOutputLayouts;
  1874. layouts.clearQuick();
  1875. auto numBuses = AudioUnitHelpers::getBusCount (*juceFilter, isInput);
  1876. for (int busNr = 0; busNr < numBuses; ++busNr)
  1877. {
  1878. Array<AudioChannelLayoutTag> busLayouts;
  1879. addSupportedLayoutTagsForBus (isInput, busNr, busLayouts);
  1880. layouts.add (busLayouts);
  1881. }
  1882. }
  1883. void addSupportedLayoutTags()
  1884. {
  1885. currentInputLayout.clear(); currentOutputLayout.clear();
  1886. currentInputLayout. resize (AudioUnitHelpers::getBusCountForWrapper (*juceFilter, true));
  1887. currentOutputLayout.resize (AudioUnitHelpers::getBusCountForWrapper (*juceFilter, false));
  1888. addSupportedLayoutTagsForDirection (true);
  1889. addSupportedLayoutTagsForDirection (false);
  1890. }
  1891. static int maxChannelsToProbeFor()
  1892. {
  1893. return (getHostType().isLogic() ? 8 : 64);
  1894. }
  1895. //==============================================================================
  1896. void auPropertyListener (AudioUnitPropertyID propId, AudioUnitScope scope, AudioUnitElement)
  1897. {
  1898. if (scope == kAudioUnitScope_Global && propId == kAudioUnitProperty_ContextName
  1899. && juceFilter != nullptr && mContextName != nullptr)
  1900. {
  1901. AudioProcessor::TrackProperties props;
  1902. props.name = String::fromCFString (mContextName);
  1903. juceFilter->updateTrackProperties (props);
  1904. }
  1905. }
  1906. static void auPropertyListenerDispatcher (void* inRefCon, AudioUnit, AudioUnitPropertyID propId,
  1907. AudioUnitScope scope, AudioUnitElement element)
  1908. {
  1909. static_cast<JuceAU*> (inRefCon)->auPropertyListener (propId, scope, element);
  1910. }
  1911. JUCE_DECLARE_NON_COPYABLE (JuceAU)
  1912. };
  1913. //==============================================================================
  1914. #define JUCE_COMPONENT_ENTRYX(Class, Name, Suffix) \
  1915. extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj); \
  1916. extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj) \
  1917. { \
  1918. PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_AudioUnit; \
  1919. return ComponentEntryPoint<Class>::Dispatch (params, obj); \
  1920. }
  1921. #if JucePlugin_ProducesMidiOutput || JucePlugin_WantsMidiInput || JucePlugin_IsMidiEffect
  1922. #define FACTORY_BASE_CLASS AUMIDIEffectFactory
  1923. #else
  1924. #define FACTORY_BASE_CLASS AUBaseFactory
  1925. #endif
  1926. #define JUCE_FACTORY_ENTRYX(Class, Name) \
  1927. extern "C" __attribute__((visibility("default"))) void* Name ## Factory (const AudioComponentDescription* desc); \
  1928. extern "C" __attribute__((visibility("default"))) void* Name ## Factory (const AudioComponentDescription* desc) \
  1929. { \
  1930. PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_AudioUnit; \
  1931. return FACTORY_BASE_CLASS<Class>::Factory (desc); \
  1932. }
  1933. #define JUCE_COMPONENT_ENTRY(Class, Name, Suffix) JUCE_COMPONENT_ENTRYX(Class, Name, Suffix)
  1934. #define JUCE_FACTORY_ENTRY(Class, Name) JUCE_FACTORY_ENTRYX(Class, Name)
  1935. //==============================================================================
  1936. JUCE_COMPONENT_ENTRY (JuceAU, JucePlugin_AUExportPrefix, Entry)
  1937. #ifndef AUDIOCOMPONENT_ENTRY
  1938. #define JUCE_DISABLE_AU_FACTORY_ENTRY 1
  1939. #endif
  1940. #if ! JUCE_DISABLE_AU_FACTORY_ENTRY // (You might need to disable this for old Xcode 3 builds)
  1941. JUCE_FACTORY_ENTRY (JuceAU, JucePlugin_AUExportPrefix)
  1942. #endif
  1943. #if ! JUCE_DISABLE_AU_FACTORY_ENTRY
  1944. JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wcast-align", "-Wzero-as-null-pointer-constant")
  1945. #include "CoreAudioUtilityClasses/AUPlugInDispatch.cpp"
  1946. JUCE_END_IGNORE_WARNINGS_GCC_LIKE
  1947. #endif
  1948. #endif