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.

1827 lines
80KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. #include "../../juce_core/system/juce_TargetPlatform.h"
  20. #include "../utility/juce_CheckSettingMacros.h"
  21. #if JucePlugin_Build_AUv3
  22. #import <CoreAudioKit/CoreAudioKit.h>
  23. #import <AudioToolbox/AudioToolbox.h>
  24. #import <AVFoundation/AVFoundation.h>
  25. #if JUCE_MAC
  26. #if (! defined MAC_OS_X_VERSION_MIN_REQUIRED) || (! defined MAC_OS_X_VERSION_10_11) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11)
  27. #error AUv3 needs Deployment Target OS X 10.11 or higher to compile
  28. #endif
  29. #if (defined MAC_OS_X_VERSION_10_13) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_13)
  30. #define JUCE_AUV3_MIDI_OUTPUT_SUPPORTED 1
  31. #define JUCE_AUV3_VIEW_CONFIG_SUPPORTED 1
  32. #endif
  33. #endif
  34. #if JUCE_IOS
  35. #if (! defined __IPHONE_OS_VERSION_MIN_REQUIRED) || (! defined __IPHONE_9_0) || (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
  36. #error AUv3 needs Deployment Target iOS 9.0 or higher to compile
  37. #endif
  38. #if (defined __IPHONE_11_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_11_0)
  39. #define JUCE_AUV3_MIDI_OUTPUT_SUPPORTED 1
  40. #define JUCE_AUV3_VIEW_CONFIG_SUPPORTED 1
  41. #endif
  42. #endif
  43. #ifndef __OBJC2__
  44. #error AUv3 needs Objective-C 2 support (compile with 64-bit)
  45. #endif
  46. #define JUCE_CORE_INCLUDE_OBJC_HELPERS 1
  47. #include "../utility/juce_IncludeSystemHeaders.h"
  48. #include "../utility/juce_IncludeModuleHeaders.h"
  49. #include "../../juce_graphics/native/juce_mac_CoreGraphicsHelpers.h"
  50. #include "../../juce_audio_basics/native/juce_mac_CoreAudioLayouts.h"
  51. #include "../../juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp"
  52. #include "../../juce_audio_processors/format_types/juce_AU_Shared.h"
  53. #define JUCE_VIEWCONTROLLER_OBJC_NAME(x) JUCE_JOIN_MACRO (x, FactoryAUv3)
  54. #if JUCE_IOS
  55. #define JUCE_IOS_MAC_VIEW UIView
  56. #else
  57. #define JUCE_IOS_MAC_VIEW NSView
  58. #endif
  59. #define JUCE_AUDIOUNIT_OBJC_NAME(x) JUCE_JOIN_MACRO (x, AUv3)
  60. #pragma clang diagnostic push
  61. #pragma clang diagnostic ignored "-Wnullability-completeness"
  62. using namespace juce;
  63. // TODO: use SFINAE to automatically generate this for all NSObjects
  64. template <> struct ContainerDeletePolicy<AUAudioUnitBusArray> { static void destroy (NSObject* o) { [o release]; } };
  65. template <> struct ContainerDeletePolicy<AUParameterTree> { static void destroy (NSObject* o) { [o release]; } };
  66. template <> struct ContainerDeletePolicy<NSMutableArray<AUParameterNode*>> { static void destroy (NSObject* o) { [o release]; } };
  67. template <> struct ContainerDeletePolicy<AUParameter> { static void destroy (NSObject* o) { [o release]; } };
  68. template <> struct ContainerDeletePolicy<NSMutableArray<AUAudioUnitBus*>> { static void destroy (NSObject* o) { [o release]; } };
  69. template <> struct ContainerDeletePolicy<AUAudioUnitBus> { static void destroy (NSObject* o) { [o release]; } };
  70. template <> struct ContainerDeletePolicy<AVAudioFormat> { static void destroy (NSObject* o) { [o release]; } };
  71. template <> struct ContainerDeletePolicy<AVAudioPCMBuffer> { static void destroy (NSObject* o) { [o release]; } };
  72. template <> struct ContainerDeletePolicy<NSMutableArray<NSNumber*>> { static void destroy (NSObject* o) { [o release]; } };
  73. template <> struct ContainerDeletePolicy<NSNumber> { static void destroy (NSObject* o) { [o release]; } };
  74. template <> struct ContainerDeletePolicy<NSMutableArray<AUAudioUnitPreset*>> { static void destroy (NSObject* o) { [o release]; } };
  75. template <> struct ContainerDeletePolicy<AUAudioUnitPreset> { static void destroy (NSObject* o) { [o release]; } };
  76. //==============================================================================
  77. struct AudioProcessorHolder : public ReferenceCountedObject
  78. {
  79. AudioProcessorHolder() {}
  80. AudioProcessorHolder (AudioProcessor* p) : processor (p) {}
  81. AudioProcessor& operator*() noexcept { return *processor; }
  82. AudioProcessor* operator->() noexcept { return processor; }
  83. AudioProcessor* get() noexcept { return processor; }
  84. struct ViewConfig
  85. {
  86. double width;
  87. double height;
  88. bool hostHasMIDIController;
  89. };
  90. ScopedPointer<ViewConfig> viewConfiguration;
  91. typedef ReferenceCountedObjectPtr<AudioProcessorHolder> Ptr;
  92. private:
  93. ScopedPointer<AudioProcessor> processor;
  94. AudioProcessorHolder& operator= (AudioProcessor*) = delete;
  95. AudioProcessorHolder (AudioProcessorHolder&) = delete;
  96. AudioProcessorHolder& operator= (AudioProcessorHolder&) = delete;
  97. };
  98. //==============================================================================
  99. class JuceAudioUnitv3Base
  100. {
  101. public:
  102. JuceAudioUnitv3Base (const AudioComponentDescription& descr,
  103. AudioComponentInstantiationOptions options,
  104. NSError** error)
  105. #pragma clang diagnostic push
  106. #pragma clang diagnostic ignored "-Wobjc-method-access"
  107. : au ([audioUnitObjCClass.createInstance() initWithComponentDescription: descr
  108. options: options
  109. error: error
  110. juceClass: this])
  111. #pragma clang diagnostic pop
  112. {}
  113. JuceAudioUnitv3Base (AUAudioUnit* audioUnit) : au (audioUnit)
  114. {
  115. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  116. initialiseJuce_GUI();
  117. }
  118. virtual ~JuceAudioUnitv3Base() {}
  119. //==============================================================================
  120. AUAudioUnit* getAudioUnit() noexcept { return au; }
  121. //==============================================================================
  122. virtual void reset() = 0;
  123. //==============================================================================
  124. virtual AUAudioUnitPreset* getCurrentPreset() = 0;
  125. virtual void setCurrentPreset(AUAudioUnitPreset*) = 0;
  126. virtual NSArray<AUAudioUnitPreset*>* getFactoryPresets() = 0;
  127. virtual NSDictionary<NSString*, id>* getFullState()
  128. {
  129. objc_super s = { getAudioUnit(), [AUAudioUnit class] };
  130. return ObjCMsgSendSuper<NSDictionary<NSString*, id>*> (&s, @selector (fullState));
  131. }
  132. virtual void setFullState (NSDictionary<NSString*, id>* state)
  133. {
  134. objc_super s = { getAudioUnit(), [AUAudioUnit class] };
  135. ObjCMsgSendSuper<void, NSDictionary<NSString*, id>*> (&s, @selector (setFullState:), state);
  136. }
  137. virtual AUParameterTree* getParameterTree() = 0;
  138. virtual NSArray<NSNumber*>* parametersForOverviewWithCount (int) = 0;
  139. //==============================================================================
  140. virtual NSTimeInterval getLatency() = 0;
  141. virtual NSTimeInterval getTailTime() = 0;
  142. //==============================================================================
  143. virtual AUAudioUnitBusArray* getInputBusses() = 0;
  144. virtual AUAudioUnitBusArray* getOutputBusses() = 0;
  145. virtual NSArray<NSNumber*>* getChannelCapabilities() = 0;
  146. virtual bool shouldChangeToFormat (AVAudioFormat*, AUAudioUnitBus*) = 0;
  147. //==============================================================================
  148. virtual int getVirtualMIDICableCount() = 0;
  149. virtual bool getSupportsMPE() = 0;
  150. virtual NSArray<NSString*>* getMIDIOutputNames() = 0;
  151. //==============================================================================
  152. virtual AUInternalRenderBlock getInternalRenderBlock() = 0;
  153. virtual bool getCanProcessInPlace() { return false; }
  154. virtual bool getRenderingOffline() = 0;
  155. virtual void setRenderingOffline (bool offline) = 0;
  156. //==============================================================================
  157. virtual NSString* getContextName() const = 0;
  158. virtual void setContextName (NSString*) = 0;
  159. virtual bool allocateRenderResourcesAndReturnError (NSError **outError)
  160. {
  161. objc_super s = { getAudioUnit(), [AUAudioUnit class] };
  162. return (ObjCMsgSendSuper<BOOL, NSError**> (&s, @selector (allocateRenderResourcesAndReturnError:), outError) == YES);
  163. }
  164. virtual void deallocateRenderResources()
  165. {
  166. objc_super s = { getAudioUnit(), [AUAudioUnit class] };
  167. ObjCMsgSendSuper<void> (&s, @selector (deallocateRenderResources));
  168. }
  169. //==============================================================================
  170. #if JUCE_AUV3_VIEW_CONFIG_SUPPORTED
  171. virtual NSIndexSet* getSupportedViewConfigurations (NSArray<AUAudioUnitViewConfiguration*>*) = 0;
  172. virtual void selectViewConfiguration (AUAudioUnitViewConfiguration*) = 0;
  173. #endif
  174. private:
  175. struct Class : public ObjCClass<AUAudioUnit>
  176. {
  177. Class() : ObjCClass<AUAudioUnit> ("AUAudioUnit_")
  178. {
  179. addIvar<JuceAudioUnitv3Base*> ("cppObject");
  180. #pragma clang diagnostic push
  181. #pragma clang diagnostic ignored "-Wundeclared-selector"
  182. addMethod (@selector (initWithComponentDescription:options:error:juceClass:),
  183. initWithComponentDescriptionAndJuceClass, "@@:",
  184. @encode (AudioComponentDescription),
  185. @encode (AudioComponentInstantiationOptions), "^@@");
  186. #pragma clang diagnostic pop
  187. addMethod (@selector (initWithComponentDescription:options:error:),
  188. initWithComponentDescription, "@@:",
  189. @encode (AudioComponentDescription),
  190. @encode (AudioComponentInstantiationOptions), "^@");
  191. addMethod (@selector (dealloc), dealloc, "v@:");
  192. //==============================================================================
  193. addMethod (@selector (reset), reset, "v@:");
  194. //==============================================================================
  195. addMethod (@selector (currentPreset), getCurrentPreset, "@@:");
  196. addMethod (@selector (setCurrentPreset:), setCurrentPreset, "v@:@");
  197. addMethod (@selector (factoryPresets), getFactoryPresets, "@@:");
  198. addMethod (@selector (fullState), getFullState, "@@:");
  199. addMethod (@selector (setFullState:), setFullState, "v@:@");
  200. addMethod (@selector (parameterTree), getParameterTree, "@@:");
  201. addMethod (@selector (parametersForOverviewWithCount:), parametersForOverviewWithCount, "@@:", @encode (NSInteger));
  202. //==============================================================================
  203. addMethod (@selector (latency), getLatency, @encode (NSTimeInterval), "@:");
  204. addMethod (@selector (tailTime), getTailTime, @encode (NSTimeInterval), "@:");
  205. //==============================================================================
  206. addMethod (@selector (inputBusses), getInputBusses, "@@:");
  207. addMethod (@selector (outputBusses), getOutputBusses, "@@:");
  208. addMethod (@selector (channelCapabilities), getChannelCapabilities, "@@:");
  209. addMethod (@selector (shouldChangeToFormat:forBus:), shouldChangeToFormat, "B@:@@");
  210. //==============================================================================
  211. addMethod (@selector (virtualMIDICableCount), getVirtualMIDICableCount, @encode (NSInteger), "@:");
  212. addMethod (@selector (supportsMPE), getSupportsMPE, @encode (BOOL), "@:");
  213. #if JUCE_AUV3_MIDI_OUTPUT_SUPPORTED
  214. addMethod (@selector (MIDIOutputNames), getMIDIOutputNames, "@@:");
  215. #endif
  216. //==============================================================================
  217. addMethod (@selector (internalRenderBlock), getInternalRenderBlock, @encode (AUInternalRenderBlock), "@:");
  218. addMethod (@selector (canProcessInPlace), getCanProcessInPlace, @encode (BOOL), "@:");
  219. addMethod (@selector (isRenderingOffline), getRenderingOffline, @encode (BOOL), "@:");
  220. addMethod (@selector (setRenderingOffline:), setRenderingOffline, "v@:", @encode (BOOL));
  221. addMethod (@selector (allocateRenderResourcesAndReturnError:), allocateRenderResourcesAndReturnError, "B@:^@");
  222. addMethod (@selector (deallocateRenderResources), deallocateRenderResources, "v@:");
  223. //==============================================================================
  224. addMethod (@selector (contextName), getContextName, "@@:");
  225. addMethod (@selector (setContextName:), setContextName, "v@:@");
  226. //==============================================================================
  227. #if JUCE_AUV3_VIEW_CONFIG_SUPPORTED
  228. addMethod (@selector (supportedViewConfigurations:), getSupportedViewConfigurations, "@@:@");
  229. addMethod (@selector (selectViewConfiguration:), selectViewConfiguration, "v@:@");
  230. #endif
  231. registerClass();
  232. }
  233. //==============================================================================
  234. static JuceAudioUnitv3Base* _this (id self) { return getIvar<JuceAudioUnitv3Base*> (self, "cppObject"); }
  235. static void setThis (id self, JuceAudioUnitv3Base* cpp) { object_setInstanceVariable (self, "cppObject", cpp); }
  236. //==============================================================================
  237. static id initWithComponentDescription (id _self, SEL, AudioComponentDescription descr, AudioComponentInstantiationOptions options, NSError** error)
  238. {
  239. AUAudioUnit* self = _self;
  240. objc_super s = { self, [AUAudioUnit class] };
  241. self = ObjCMsgSendSuper<AUAudioUnit*, AudioComponentDescription,
  242. AudioComponentInstantiationOptions, NSError**> (&s, @selector(initWithComponentDescription:options:error:), descr, options, error);
  243. JuceAudioUnitv3Base* juceAU = JuceAudioUnitv3Base::create (self, descr, options, error);
  244. setThis (self, juceAU);
  245. return self;
  246. }
  247. static id initWithComponentDescriptionAndJuceClass (id _self, SEL, AudioComponentDescription descr, AudioComponentInstantiationOptions options, NSError** error, JuceAudioUnitv3Base* juceAU)
  248. {
  249. AUAudioUnit* self = _self;
  250. objc_super s = { self, [AUAudioUnit class] };
  251. self = ObjCMsgSendSuper<AUAudioUnit*, AudioComponentDescription,
  252. AudioComponentInstantiationOptions, NSError**> (&s, @selector(initWithComponentDescription:options:error:), descr, options, error);
  253. setThis (self, juceAU);
  254. return self;
  255. }
  256. static void dealloc (id self, SEL)
  257. {
  258. if (! MessageManager::getInstance()->isThisTheMessageThread())
  259. {
  260. WaitableEvent deletionEvent;
  261. struct AUDeleter : public CallbackMessage
  262. {
  263. AUDeleter (id selfToDelete, WaitableEvent& event)
  264. : parentSelf (selfToDelete), parentDeletionEvent (event)
  265. {
  266. }
  267. void messageCallback() override
  268. {
  269. delete _this (parentSelf);
  270. parentDeletionEvent.signal();
  271. }
  272. id parentSelf;
  273. WaitableEvent& parentDeletionEvent;
  274. };
  275. (new AUDeleter (self, deletionEvent))->post();
  276. deletionEvent.wait (-1);
  277. }
  278. else
  279. {
  280. delete _this (self);
  281. }
  282. }
  283. //==============================================================================
  284. static void reset (id self, SEL) { _this (self)->reset(); }
  285. //==============================================================================
  286. static AUAudioUnitPreset* getCurrentPreset (id self, SEL) { return _this (self)->getCurrentPreset(); }
  287. static void setCurrentPreset (id self, SEL, AUAudioUnitPreset* preset) { return _this (self)->setCurrentPreset (preset); }
  288. static NSArray<AUAudioUnitPreset*>* getFactoryPresets (id self, SEL) { return _this (self)->getFactoryPresets(); }
  289. static NSDictionary<NSString*, id>* getFullState (id self, SEL) { return _this (self)->getFullState(); }
  290. static void setFullState (id self, SEL, NSDictionary<NSString *, id>* state) { return _this (self)->setFullState (state); }
  291. static AUParameterTree* getParameterTree (id self, SEL) { return _this (self)->getParameterTree(); }
  292. static NSArray<NSNumber*>* parametersForOverviewWithCount (id self, SEL, NSInteger count) { return _this (self)->parametersForOverviewWithCount (static_cast<int> (count)); }
  293. //==============================================================================
  294. static NSTimeInterval getLatency (id self, SEL) { return _this (self)->getLatency(); }
  295. static NSTimeInterval getTailTime (id self, SEL) { return _this (self)->getTailTime(); }
  296. //==============================================================================
  297. static AUAudioUnitBusArray* getInputBusses (id self, SEL) { return _this (self)->getInputBusses(); }
  298. static AUAudioUnitBusArray* getOutputBusses (id self, SEL) { return _this (self)->getOutputBusses(); }
  299. static NSArray<NSNumber*>* getChannelCapabilities (id self, SEL) { return _this (self)->getChannelCapabilities(); }
  300. static BOOL shouldChangeToFormat (id self, SEL, AVAudioFormat* format, AUAudioUnitBus* bus) { return _this (self)->shouldChangeToFormat (format, bus) ? YES : NO; }
  301. //==============================================================================
  302. static NSInteger getVirtualMIDICableCount (id self, SEL) { return _this (self)->getVirtualMIDICableCount(); }
  303. static BOOL getSupportsMPE (id self, SEL) { return _this (self)->getSupportsMPE() ? YES : NO; }
  304. static NSArray<NSString*>* getMIDIOutputNames (id self, SEL) { return _this (self)->getMIDIOutputNames(); }
  305. //==============================================================================
  306. static AUInternalRenderBlock getInternalRenderBlock (id self, SEL) { return _this (self)->getInternalRenderBlock(); }
  307. static BOOL getCanProcessInPlace (id self, SEL) { return _this (self)->getCanProcessInPlace() ? YES : NO; }
  308. static BOOL getRenderingOffline (id self, SEL) { return _this (self)->getRenderingOffline() ? YES : NO; }
  309. static void setRenderingOffline (id self, SEL, BOOL renderingOffline) { _this (self)->setRenderingOffline (renderingOffline); }
  310. static BOOL allocateRenderResourcesAndReturnError (id self, SEL, NSError** error) { return _this (self)->allocateRenderResourcesAndReturnError (error) ? YES : NO; }
  311. static void deallocateRenderResources (id self, SEL) { _this (self)->deallocateRenderResources(); }
  312. //==============================================================================
  313. static NSString* getContextName (id self, SEL) { return _this (self)->getContextName(); }
  314. static void setContextName (id self, SEL, NSString* str) { return _this (self)->setContextName (str); }
  315. //==============================================================================
  316. #if JUCE_AUV3_VIEW_CONFIG_SUPPORTED
  317. static NSIndexSet* getSupportedViewConfigurations (id self, SEL, NSArray<AUAudioUnitViewConfiguration*>* configs) { return _this (self)->getSupportedViewConfigurations (configs); }
  318. static void selectViewConfiguration (id self, SEL, AUAudioUnitViewConfiguration* config) { _this (self)->selectViewConfiguration (config); }
  319. #endif
  320. };
  321. static JuceAudioUnitv3Base* create (AUAudioUnit*, AudioComponentDescription, AudioComponentInstantiationOptions, NSError**);
  322. //==============================================================================
  323. static Class audioUnitObjCClass;
  324. protected:
  325. AUAudioUnit* au;
  326. };
  327. //==============================================================================
  328. JuceAudioUnitv3Base::Class JuceAudioUnitv3Base::audioUnitObjCClass;
  329. //==============================================================================
  330. //=========================== The actual AudioUnit =============================
  331. //==============================================================================
  332. class JuceAudioUnitv3 : public JuceAudioUnitv3Base,
  333. public AudioProcessorListener,
  334. public AudioPlayHead
  335. {
  336. public:
  337. JuceAudioUnitv3 (const AudioProcessorHolder::Ptr& processor,
  338. const AudioComponentDescription& descr,
  339. AudioComponentInstantiationOptions options,
  340. NSError** error)
  341. : JuceAudioUnitv3Base (descr, options, error),
  342. processorHolder (processor),
  343. mapper (*processorHolder->get())
  344. {
  345. init();
  346. }
  347. JuceAudioUnitv3 (AUAudioUnit* audioUnit, AudioComponentDescription, AudioComponentInstantiationOptions, NSError**)
  348. : JuceAudioUnitv3Base (audioUnit),
  349. processorHolder (new AudioProcessorHolder (createPluginFilterOfType (AudioProcessor::wrapperType_AudioUnitv3))),
  350. mapper (*processorHolder->get())
  351. {
  352. init();
  353. }
  354. ~JuceAudioUnitv3()
  355. {
  356. auto& processor = getAudioProcessor();
  357. processor.removeListener (this);
  358. removeEditor (processor);
  359. if (editorObserverToken != nullptr)
  360. {
  361. [paramTree removeParameterObserver: editorObserverToken];
  362. editorObserverToken = nullptr;
  363. }
  364. }
  365. //==============================================================================
  366. void init()
  367. {
  368. inParameterChangedCallback = false;
  369. AudioProcessor& processor = getAudioProcessor();
  370. const AUAudioFrameCount maxFrames = [getAudioUnit() maximumFramesToRender];
  371. #ifdef JucePlugin_PreferredChannelConfigurations
  372. short configs[][2] = {JucePlugin_PreferredChannelConfigurations};
  373. const int numConfigs = sizeof (configs) / sizeof (short[2]);
  374. jassert (numConfigs > 0 && (configs[0][0] > 0 || configs[0][1] > 0));
  375. processor.setPlayConfigDetails (configs[0][0], configs[0][1], kDefaultSampleRate, static_cast<int> (maxFrames));
  376. Array<AUChannelInfo> channelInfos;
  377. for (int i = 0; i < numConfigs; ++i)
  378. {
  379. AUChannelInfo channelInfo;
  380. channelInfo.inChannels = configs[i][0];
  381. channelInfo.outChannels = configs[i][1];
  382. channelInfos.add (channelInfo);
  383. }
  384. #else
  385. Array<AUChannelInfo> channelInfos = AudioUnitHelpers::getAUChannelInfo (processor);
  386. #endif
  387. processor.setPlayHead (this);
  388. totalInChannels = processor.getTotalNumInputChannels();
  389. totalOutChannels = processor.getTotalNumOutputChannels();
  390. {
  391. channelCapabilities = [[NSMutableArray<NSNumber*> alloc] init];
  392. for (int i = 0; i < channelInfos.size(); ++i)
  393. {
  394. AUChannelInfo& info = channelInfos.getReference (i);
  395. [channelCapabilities addObject: [NSNumber numberWithInteger: info.inChannels]];
  396. [channelCapabilities addObject: [NSNumber numberWithInteger: info.outChannels]];
  397. }
  398. }
  399. editorObserverToken = nullptr;
  400. internalRenderBlock = CreateObjCBlock (this, &JuceAudioUnitv3::renderCallback);
  401. processor.setRateAndBufferSizeDetails (kDefaultSampleRate, static_cast<int> (maxFrames));
  402. processor.prepareToPlay (kDefaultSampleRate, static_cast<int> (maxFrames));
  403. processor.addListener (this);
  404. addParameters();
  405. addPresets();
  406. addAudioUnitBusses (true);
  407. addAudioUnitBusses (false);
  408. }
  409. AudioProcessor& getAudioProcessor() const noexcept { return **processorHolder; }
  410. //==============================================================================
  411. void reset() override
  412. {
  413. midiMessages.clear();
  414. lastTimeStamp.mSampleTime = std::numeric_limits<Float64>::max();
  415. }
  416. //==============================================================================
  417. AUAudioUnitPreset* getCurrentPreset() override
  418. {
  419. const int n = static_cast<int> ([factoryPresets count]);
  420. const int idx = static_cast<int> (getAudioProcessor().getCurrentProgram());
  421. if (idx < n)
  422. return [factoryPresets objectAtIndex:static_cast<unsigned int> (idx)];
  423. return nullptr;
  424. }
  425. void setCurrentPreset(AUAudioUnitPreset* preset) override
  426. {
  427. const int n = static_cast<int> ([factoryPresets count]);
  428. const int idx = static_cast<int> ([preset number]);
  429. if (isPositiveAndBelow (idx, n))
  430. getAudioProcessor().setCurrentProgram (idx);
  431. }
  432. NSArray<AUAudioUnitPreset*>* getFactoryPresets() override
  433. {
  434. return factoryPresets;
  435. }
  436. NSDictionary<NSString*, id>* getFullState() override
  437. {
  438. NSMutableDictionary<NSString*, id>* retval = [[NSMutableDictionary<NSString*, id> alloc] init];
  439. {
  440. NSDictionary<NSString*, id>* superRetval = JuceAudioUnitv3Base::getFullState();
  441. if (superRetval != nullptr)
  442. [retval addEntriesFromDictionary:superRetval];
  443. }
  444. juce::MemoryBlock state;
  445. getAudioProcessor().getCurrentProgramStateInformation (state);
  446. if (state.getSize() > 0)
  447. {
  448. NSData* ourState = [[NSData alloc] initWithBytes: state.getData()
  449. length: state.getSize()];
  450. NSString* nsKey = [[NSString alloc] initWithUTF8String: JUCE_STATE_DICTIONARY_KEY];
  451. [retval setObject: ourState
  452. forKey: nsKey];
  453. [nsKey release];
  454. [ourState release];
  455. }
  456. return [retval autorelease];
  457. }
  458. void setFullState (NSDictionary<NSString*, id>* state) override
  459. {
  460. if (state == nullptr)
  461. return;
  462. NSMutableDictionary<NSString*, id>* modifiedState = [[NSMutableDictionary<NSString*, id> alloc] init];
  463. [modifiedState addEntriesFromDictionary: state];
  464. NSString* nsPresetKey = [[NSString alloc] initWithUTF8String: kAUPresetDataKey];
  465. [modifiedState removeObjectForKey: nsPresetKey];
  466. [nsPresetKey release];
  467. JuceAudioUnitv3Base::setFullState (modifiedState);
  468. NSString* nsKey = [[NSString alloc] initWithUTF8String: JUCE_STATE_DICTIONARY_KEY];
  469. NSObject* obj = [modifiedState objectForKey: nsKey];
  470. [nsKey release];
  471. if (obj != nullptr)
  472. {
  473. if ([obj isKindOfClass:[NSData class]])
  474. {
  475. NSData* data = reinterpret_cast<NSData*> (obj);
  476. const int numBytes = static_cast<int> ([data length]);
  477. const juce::uint8* const rawBytes = reinterpret_cast< const juce::uint8* const> ([data bytes]);
  478. if (numBytes > 0)
  479. getAudioProcessor().setCurrentProgramStateInformation (rawBytes, numBytes);
  480. }
  481. }
  482. [modifiedState release];
  483. }
  484. AUParameterTree* getParameterTree() override
  485. {
  486. return paramTree;
  487. }
  488. NSArray<NSNumber*>* parametersForOverviewWithCount (int count) override
  489. {
  490. const int n = static_cast<int> ([overviewParams count]);
  491. if (count >= n)
  492. return overviewParams;
  493. NSMutableArray<NSNumber*>* retval = [[NSMutableArray<NSNumber*>alloc] initWithArray: overviewParams];
  494. [retval removeObjectsInRange: NSMakeRange (static_cast<unsigned int> (count), static_cast<unsigned int> (n - count))];
  495. return [retval autorelease];
  496. }
  497. //==============================================================================
  498. NSTimeInterval getLatency() override
  499. {
  500. auto& p = getAudioProcessor();
  501. return p.getLatencySamples() / p.getSampleRate();
  502. }
  503. NSTimeInterval getTailTime() override
  504. {
  505. return getAudioProcessor().getTailLengthSeconds();
  506. }
  507. //==============================================================================
  508. AUAudioUnitBusArray* getInputBusses() override { return inputBusses; }
  509. AUAudioUnitBusArray* getOutputBusses() override { return outputBusses; }
  510. NSArray<NSNumber*>* getChannelCapabilities() override { return channelCapabilities; }
  511. bool shouldChangeToFormat (AVAudioFormat* format, AUAudioUnitBus* auBus) override
  512. {
  513. const bool isInput = ([auBus busType] == AUAudioUnitBusTypeInput);
  514. const int busIdx = static_cast<int> ([auBus index]);
  515. const int newNumChannels = static_cast<int> ([format channelCount]);
  516. AudioProcessor& processor = getAudioProcessor();
  517. if (AudioProcessor::Bus* bus = processor.getBus (isInput, busIdx))
  518. {
  519. #ifdef JucePlugin_PreferredChannelConfigurations
  520. ignoreUnused (bus);
  521. short configs[][2] = {JucePlugin_PreferredChannelConfigurations};
  522. if (! AudioUnitHelpers::isLayoutSupported (processor, isInput, busIdx, newNumChannels, configs))
  523. return false;
  524. #else
  525. const AVAudioChannelLayout* layout = [format channelLayout];
  526. const AudioChannelLayoutTag layoutTag = (layout != nullptr ? [layout layoutTag] : 0);
  527. if (layoutTag != 0)
  528. {
  529. AudioChannelSet newLayout = CoreAudioLayouts::fromCoreAudio (layoutTag);
  530. if (newLayout.size() != newNumChannels)
  531. return false;
  532. if (! bus->isLayoutSupported (newLayout))
  533. return false;
  534. }
  535. else
  536. {
  537. if (! bus->isNumberOfChannelsSupported (newNumChannels))
  538. return false;
  539. }
  540. #endif
  541. return true;
  542. }
  543. return false;
  544. }
  545. //==============================================================================
  546. int getVirtualMIDICableCount() override
  547. {
  548. #if JucePlugin_WantsMidiInput
  549. return 1;
  550. #else
  551. return 0;
  552. #endif
  553. }
  554. bool getSupportsMPE() override
  555. {
  556. return getAudioProcessor().supportsMPE();
  557. }
  558. NSArray<NSString*>* getMIDIOutputNames() override
  559. {
  560. #if JucePlugin_ProducesMidiOutput
  561. return @[@"MIDI Out"];
  562. #else
  563. return @[];
  564. #endif
  565. }
  566. //==============================================================================
  567. AUInternalRenderBlock getInternalRenderBlock() override { return internalRenderBlock; }
  568. bool getRenderingOffline() override { return getAudioProcessor().isNonRealtime(); }
  569. void setRenderingOffline (bool offline) override
  570. {
  571. auto& processor = getAudioProcessor();
  572. auto isCurrentlyNonRealtime = processor.isNonRealtime();
  573. if (isCurrentlyNonRealtime != offline)
  574. {
  575. ScopedLock callbackLock (processor.getCallbackLock());
  576. processor.setNonRealtime (offline);
  577. processor.prepareToPlay (processor.getSampleRate(), processor.getBlockSize());
  578. }
  579. }
  580. //==============================================================================
  581. NSString* getContextName() const override { return juceStringToNS (contextName); }
  582. void setContextName (NSString* str) override
  583. {
  584. if (str != nullptr)
  585. {
  586. AudioProcessor::TrackProperties props;
  587. props.name = nsStringToJuce (str);
  588. getAudioProcessor().updateTrackProperties (props);
  589. }
  590. }
  591. //==============================================================================
  592. bool allocateRenderResourcesAndReturnError (NSError **outError) override
  593. {
  594. AudioProcessor& processor = getAudioProcessor();
  595. const AUAudioFrameCount maxFrames = [getAudioUnit() maximumFramesToRender];
  596. if (! JuceAudioUnitv3Base::allocateRenderResourcesAndReturnError (outError))
  597. return false;
  598. if (outError != nullptr)
  599. *outError = nullptr;
  600. AudioProcessor::BusesLayout layouts;
  601. for (int dir = 0; dir < 2; ++dir)
  602. {
  603. const bool isInput = (dir == 0);
  604. const int n = AudioUnitHelpers::getBusCount (&processor, isInput);
  605. Array<AudioChannelSet>& channelSets = (isInput ? layouts.inputBuses : layouts.outputBuses);
  606. AUAudioUnitBusArray* auBuses = (isInput ? [getAudioUnit() inputBusses] : [getAudioUnit() outputBusses]);
  607. jassert ([auBuses count] == static_cast<NSUInteger> (n));
  608. for (int busIdx = 0; busIdx < n; ++busIdx)
  609. {
  610. AudioProcessor::Bus* bus = processor.getBus (isInput, busIdx);
  611. AVAudioFormat* format = [[auBuses objectAtIndexedSubscript:static_cast<NSUInteger> (busIdx)] format];
  612. AudioChannelSet newLayout;
  613. const AVAudioChannelLayout* layout = [format channelLayout];
  614. const AudioChannelLayoutTag layoutTag = (layout != nullptr ? [layout layoutTag] : 0);
  615. if (layoutTag != 0)
  616. newLayout = CoreAudioLayouts::fromCoreAudio (layoutTag);
  617. else
  618. newLayout = bus->supportedLayoutWithChannels (static_cast<int> ([format channelCount]));
  619. if (newLayout.isDisabled())
  620. return false;
  621. channelSets.add (newLayout);
  622. }
  623. }
  624. #ifdef JucePlugin_PreferredChannelConfigurations
  625. short configs[][2] = {JucePlugin_PreferredChannelConfigurations};
  626. if (! AudioProcessor::containsLayout (layouts, configs))
  627. {
  628. if (outError != nullptr)
  629. *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:kAudioUnitErr_FormatNotSupported userInfo:nullptr];
  630. return false;
  631. }
  632. #endif
  633. if (! AudioUnitHelpers::setBusesLayout (&getAudioProcessor(), layouts))
  634. {
  635. if (outError != nullptr)
  636. *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:kAudioUnitErr_FormatNotSupported userInfo:nullptr];
  637. return false;
  638. }
  639. totalInChannels = processor.getTotalNumInputChannels();
  640. totalOutChannels = processor.getTotalNumOutputChannels();
  641. allocateBusBuffer (true);
  642. allocateBusBuffer (false);
  643. mapper.alloc();
  644. audioBuffer.prepare (totalInChannels, totalOutChannels, static_cast<int> (maxFrames));
  645. double sampleRate = (jmax (AudioUnitHelpers::getBusCount (&processor, true), AudioUnitHelpers::getBusCount (&processor, false)) > 0 ?
  646. [[[([inputBusses count] > 0 ? inputBusses : outputBusses) objectAtIndexedSubscript: 0] format] sampleRate] : 44100.0);
  647. processor.setRateAndBufferSizeDetails (sampleRate, static_cast<int> (maxFrames));
  648. processor.prepareToPlay (sampleRate, static_cast<int> (maxFrames));
  649. zeromem (&lastAudioHead, sizeof (lastAudioHead));
  650. hostMusicalContextCallback = [getAudioUnit() musicalContextBlock];
  651. hostTransportStateCallback = [getAudioUnit() transportStateBlock];
  652. reset();
  653. return true;
  654. }
  655. void deallocateRenderResources() override
  656. {
  657. hostMusicalContextCallback = nullptr;
  658. hostTransportStateCallback = nullptr;
  659. getAudioProcessor().releaseResources();
  660. audioBuffer.release();
  661. inBusBuffers. clear();
  662. outBusBuffers.clear();
  663. mapper.release();
  664. JuceAudioUnitv3Base::deallocateRenderResources();
  665. }
  666. //==============================================================================
  667. #if JUCE_AUV3_VIEW_CONFIG_SUPPORTED
  668. NSIndexSet* getSupportedViewConfigurations (NSArray<AUAudioUnitViewConfiguration*>* configs) override
  669. {
  670. auto supportedViewIndecies = [[NSMutableIndexSet alloc] init];
  671. auto n = [configs count];
  672. if (auto* editor = getAudioProcessor().createEditorIfNeeded())
  673. {
  674. // If you hit this assertion then your plug-in's editor is reporting that it doesn't support
  675. // any host MIDI controller configurations!
  676. jassert (editor->supportsHostMIDIControllerPresence (true) || editor->supportsHostMIDIControllerPresence (false));
  677. for (auto i = 0u; i < n; ++i)
  678. {
  679. if (auto* viewConfiguration = [configs objectAtIndex:i])
  680. {
  681. if (editor->supportsHostMIDIControllerPresence ([viewConfiguration hostHasController] == YES))
  682. {
  683. auto* constrainer = editor->getConstrainer();
  684. auto height = (int) [viewConfiguration height];
  685. auto width = (int) [viewConfiguration width];
  686. if (height <= constrainer->getMaximumHeight() && height >= constrainer->getMinimumHeight()
  687. && width <= constrainer->getMaximumWidth() && width >= constrainer->getMinimumWidth())
  688. [supportedViewIndecies addIndex: i];
  689. }
  690. }
  691. }
  692. }
  693. return [supportedViewIndecies autorelease];
  694. }
  695. void selectViewConfiguration (AUAudioUnitViewConfiguration* config) override
  696. {
  697. processorHolder->viewConfiguration = new AudioProcessorHolder::ViewConfig { [config width], [config height], [config hostHasController] == YES };
  698. }
  699. #endif
  700. //==============================================================================
  701. void audioProcessorChanged (AudioProcessor* processor) override
  702. {
  703. ignoreUnused (processor);
  704. [au willChangeValueForKey: @"allParameterValues"];
  705. addPresets();
  706. [au didChangeValueForKey: @"allParameterValues"];
  707. }
  708. void audioProcessorParameterChanged (AudioProcessor*, int idx, float newValue) override
  709. {
  710. if (inParameterChangedCallback.get())
  711. {
  712. inParameterChangedCallback = false;
  713. return;
  714. }
  715. if (isPositiveAndBelow (idx, juceParameters.getNumParameters()))
  716. {
  717. if (AUParameter* param = [paramTree parameterWithAddress: getAUParameterAddressForIndex (idx)])
  718. {
  719. if (editorObserverToken != nullptr)
  720. [param setValue: newValue originator: editorObserverToken];
  721. else
  722. [param setValue: newValue];
  723. }
  724. }
  725. }
  726. //==============================================================================
  727. bool getCurrentPosition (CurrentPositionInfo& info) override
  728. {
  729. bool musicContextCallSucceeded = false;
  730. bool transportStateCallSucceeded = false;
  731. info = lastAudioHead;
  732. info.timeInSamples = (int64) (lastTimeStamp.mSampleTime + 0.5);
  733. info.timeInSeconds = info.timeInSamples / getAudioProcessor().getSampleRate();
  734. switch (lastTimeStamp.mSMPTETime.mType)
  735. {
  736. case kSMPTETimeType2398: info.frameRate = AudioPlayHead::fps23976; break;
  737. case kSMPTETimeType24: info.frameRate = AudioPlayHead::fps24; break;
  738. case kSMPTETimeType25: info.frameRate = AudioPlayHead::fps25; break;
  739. case kSMPTETimeType2997: info.frameRate = AudioPlayHead::fps2997; break;
  740. case kSMPTETimeType2997Drop: info.frameRate = AudioPlayHead::fps2997drop; break;
  741. case kSMPTETimeType30Drop: info.frameRate = AudioPlayHead::fps30drop; break;
  742. case kSMPTETimeType30: info.frameRate = AudioPlayHead::fps30; break;
  743. case kSMPTETimeType60Drop: info.frameRate = AudioPlayHead::fps60drop; break;
  744. case kSMPTETimeType60: info.frameRate = AudioPlayHead::fps60; break;
  745. default: info.frameRate = AudioPlayHead::fpsUnknown; break;
  746. }
  747. double num;
  748. NSInteger den;
  749. NSInteger outDeltaSampleOffsetToNextBeat;
  750. double outCurrentMeasureDownBeat, bpm;
  751. double ppqPosition;
  752. if (hostMusicalContextCallback != nullptr)
  753. {
  754. AUHostMusicalContextBlock musicalContextCallback = hostMusicalContextCallback;
  755. if (musicalContextCallback (&bpm, &num, &den, &ppqPosition, &outDeltaSampleOffsetToNextBeat, &outCurrentMeasureDownBeat))
  756. {
  757. musicContextCallSucceeded = true;
  758. info.timeSigNumerator = (int) num;
  759. info.timeSigDenominator = (int) den;
  760. info.ppqPositionOfLastBarStart = outCurrentMeasureDownBeat;
  761. info.bpm = bpm;
  762. info.ppqPosition = ppqPosition;
  763. info.ppqPositionOfLastBarStart = outCurrentMeasureDownBeat;
  764. }
  765. }
  766. double outCurrentSampleInTimeLine, outCycleStartBeat = 0, outCycleEndBeat = 0;
  767. AUHostTransportStateFlags flags;
  768. if (hostTransportStateCallback != nullptr)
  769. {
  770. AUHostTransportStateBlock transportStateCallback = hostTransportStateCallback;
  771. if (transportStateCallback (&flags, &outCurrentSampleInTimeLine, &outCycleStartBeat, &outCycleEndBeat))
  772. {
  773. transportStateCallSucceeded = true;
  774. info.timeInSamples = (int64) (outCurrentSampleInTimeLine + 0.5);
  775. info.timeInSeconds = info.timeInSamples / getAudioProcessor().getSampleRate();
  776. info.isPlaying = ((flags & AUHostTransportStateMoving) != 0);
  777. info.isLooping = ((flags & AUHostTransportStateCycling) != 0);
  778. info.isRecording = ((flags & AUHostTransportStateRecording) != 0);
  779. info.ppqLoopStart = outCycleStartBeat;
  780. info.ppqLoopEnd = outCycleEndBeat;
  781. }
  782. }
  783. if (musicContextCallSucceeded && transportStateCallSucceeded)
  784. lastAudioHead = info;
  785. return true;
  786. }
  787. //==============================================================================
  788. static void removeEditor (AudioProcessor& processor)
  789. {
  790. ScopedLock editorLock (processor.getCallbackLock());
  791. if (AudioProcessorEditor* editor = processor.getActiveEditor())
  792. {
  793. processor.editorBeingDeleted (editor);
  794. delete editor;
  795. }
  796. }
  797. private:
  798. //==============================================================================
  799. struct BusBuffer
  800. {
  801. BusBuffer (AUAudioUnitBus* bus, int maxFramesPerBuffer)
  802. : auBus (bus),
  803. maxFrames (maxFramesPerBuffer),
  804. numberOfChannels (static_cast<int> ([[auBus format] channelCount])),
  805. isInterleaved ([[auBus format] isInterleaved])
  806. {
  807. alloc();
  808. }
  809. //==============================================================================
  810. void alloc()
  811. {
  812. const int numBuffers = isInterleaved ? 1 : numberOfChannels;
  813. int bytes = static_cast<int> (sizeof (AudioBufferList))
  814. + ((numBuffers - 1) * static_cast<int> (sizeof (::AudioBuffer)));
  815. jassert (bytes > 0);
  816. bufferListStorage.calloc (static_cast<size_t> (bytes));
  817. bufferList = reinterpret_cast<AudioBufferList*> (bufferListStorage.getData());
  818. const int bufferChannels = isInterleaved ? numberOfChannels : 1;
  819. scratchBuffer.setSize (numBuffers, bufferChannels * maxFrames);
  820. }
  821. void dealloc()
  822. {
  823. bufferList = nullptr;
  824. bufferListStorage.free();
  825. scratchBuffer.setSize (0, 0);
  826. }
  827. //==============================================================================
  828. int numChannels() const noexcept { return numberOfChannels; }
  829. bool interleaved() const noexcept { return isInterleaved; }
  830. AudioBufferList* get() const noexcept { return bufferList; }
  831. //==============================================================================
  832. void prepare (UInt32 nFrames, const AudioBufferList* other = nullptr) noexcept
  833. {
  834. const int numBuffers = isInterleaved ? 1 : numberOfChannels;
  835. const bool isCompatible = isCompatibleWith (other);
  836. bufferList->mNumberBuffers = static_cast<UInt32> (numBuffers);
  837. for (int i = 0; i < numBuffers; ++i)
  838. {
  839. const UInt32 bufferChannels = static_cast<UInt32> (isInterleaved ? numberOfChannels : 1);
  840. bufferList->mBuffers[i].mNumberChannels = bufferChannels;
  841. bufferList->mBuffers[i].mData = (isCompatible ? other->mBuffers[i].mData
  842. : scratchBuffer.getWritePointer (i));
  843. bufferList->mBuffers[i].mDataByteSize = nFrames * bufferChannels * sizeof (float);
  844. }
  845. }
  846. //==============================================================================
  847. bool isCompatibleWith (const AudioBufferList* other) const noexcept
  848. {
  849. if (other == nullptr)
  850. return false;
  851. if (other->mNumberBuffers > 0)
  852. {
  853. const bool otherInterleaved = AudioUnitHelpers::isAudioBufferInterleaved (*other);
  854. const int otherChannels = static_cast<int> (otherInterleaved ? other->mBuffers[0].mNumberChannels
  855. : other->mNumberBuffers);
  856. return otherInterleaved == isInterleaved
  857. && numberOfChannels == otherChannels;
  858. }
  859. return numberOfChannels == 0;
  860. }
  861. private:
  862. AUAudioUnitBus* auBus;
  863. HeapBlock<char> bufferListStorage;
  864. AudioBufferList* bufferList = nullptr;
  865. int maxFrames, numberOfChannels;
  866. bool isInterleaved;
  867. AudioBuffer<float> scratchBuffer;
  868. };
  869. //==============================================================================
  870. void addAudioUnitBusses (bool isInput)
  871. {
  872. ScopedPointer<NSMutableArray<AUAudioUnitBus*>> array = [[NSMutableArray<AUAudioUnitBus*> alloc] init];
  873. AudioProcessor& processor = getAudioProcessor();
  874. const int n = AudioUnitHelpers::getBusCount (&processor, isInput);
  875. for (int i = 0; i < n; ++i)
  876. {
  877. ScopedPointer<AUAudioUnitBus> audioUnitBus;
  878. {
  879. ScopedPointer<AVAudioFormat> defaultFormat = [[AVAudioFormat alloc] initStandardFormatWithSampleRate: kDefaultSampleRate
  880. channels: static_cast<AVAudioChannelCount> (processor.getChannelCountOfBus (isInput, i))];
  881. audioUnitBus = [[AUAudioUnitBus alloc] initWithFormat: defaultFormat
  882. error: nullptr];
  883. }
  884. [array addObject: audioUnitBus];
  885. }
  886. (isInput ? inputBusses : outputBusses) = [[AUAudioUnitBusArray alloc] initWithAudioUnit: au
  887. busType: (isInput ? AUAudioUnitBusTypeInput : AUAudioUnitBusTypeOutput)
  888. busses: array];
  889. }
  890. // When parameters are discrete we need to use integer values.
  891. float getMaximumParameterValue (AudioProcessorParameter* juceParam)
  892. {
  893. #if JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
  894. ignoreUnused (juceParam);
  895. return 1.0f;
  896. #else
  897. return juceParam->isDiscrete() ? (float) (juceParam->getNumSteps() - 1) : 1.0f;
  898. #endif
  899. }
  900. void addParameters()
  901. {
  902. ScopedPointer<NSMutableArray<AUParameterNode*>> params = [[NSMutableArray<AUParameterNode*> alloc] init];
  903. overviewParams = [[NSMutableArray<NSNumber*> alloc] init];
  904. auto& processor = getAudioProcessor();
  905. juceParameters.update (processor, forceLegacyParamIDs);
  906. const int n = juceParameters.getNumParameters();
  907. for (int idx = 0; idx < n; ++idx)
  908. {
  909. auto* juceParam = juceParameters.getParamForIndex (idx);
  910. const String identifier (idx);
  911. const String name = juceParam->getName (512);
  912. AudioUnitParameterUnit unit = kAudioUnitParameterUnit_Generic;
  913. AudioUnitParameterOptions flags = (UInt32) (kAudioUnitParameterFlag_IsWritable
  914. | kAudioUnitParameterFlag_IsReadable
  915. | kAudioUnitParameterFlag_HasCFNameString
  916. | kAudioUnitParameterFlag_ValuesHaveStrings);
  917. if (! forceLegacyParamIDs)
  918. flags |= (UInt32) kAudioUnitParameterFlag_IsHighResolution;
  919. // set whether the param is automatable (unnamed parameters aren't allowed to be automated)
  920. if (name.isEmpty() || ! juceParam->isAutomatable())
  921. flags |= kAudioUnitParameterFlag_NonRealTime;
  922. const bool isParameterDiscrete = juceParam->isDiscrete();
  923. if (! isParameterDiscrete)
  924. flags |= kAudioUnitParameterFlag_CanRamp;
  925. if (juceParam->isMetaParameter())
  926. flags |= kAudioUnitParameterFlag_IsGlobalMeta;
  927. auto deleter = [](NSMutableArray* arr) { [arr release]; };
  928. std::unique_ptr<NSMutableArray, decltype (deleter)> valueStrings (nullptr, deleter);
  929. // is this a meter?
  930. if (((juceParam->getCategory() & 0xffff0000) >> 16) == 2)
  931. {
  932. flags &= ~kAudioUnitParameterFlag_IsWritable;
  933. flags |= kAudioUnitParameterFlag_MeterReadOnly | kAudioUnitParameterFlag_DisplayLogarithmic;
  934. unit = kAudioUnitParameterUnit_LinearGain;
  935. }
  936. else
  937. {
  938. if (! forceLegacyParamIDs)
  939. {
  940. if (juceParam->isDiscrete())
  941. {
  942. unit = juceParam->isBoolean() ? kAudioUnitParameterUnit_Boolean : kAudioUnitParameterUnit_Indexed;
  943. auto maxValue = getMaximumParameterValue (juceParam);
  944. auto numSteps = juceParam->getNumSteps();
  945. // Some hosts can't handle the huge numbers of discrete parameter values created when
  946. // using the default number of steps.
  947. jassert (numSteps != AudioProcessor::getDefaultNumParameterSteps());
  948. valueStrings.reset ([NSMutableArray new]);
  949. for (int i = 0; i < numSteps; ++i)
  950. [valueStrings.get() addObject: juceStringToNS (juceParam->getText ((float) i / maxValue, 0))];
  951. }
  952. }
  953. }
  954. AUParameterAddress address = forceLegacyParamIDs ? static_cast<AUParameterAddress> (idx)
  955. : generateAUParameterAddress (juceParam);
  956. #if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
  957. // Consider yourself very unlucky if you hit this assertion. The hash codes of your
  958. // parameter ids are not unique.
  959. jassert (! paramMap.contains (static_cast<int64> (address)));
  960. paramAddresses.add (address);
  961. paramMap.set (static_cast<int64> (address), idx);
  962. #endif
  963. // create methods in AUParameterTree return unretained objects (!) -> see Apple header AUAudioUnitImplementation.h
  964. ScopedPointer<AUParameter> param = [[AUParameterTree createParameterWithIdentifier: juceStringToNS (identifier)
  965. name: juceStringToNS (name)
  966. address: address
  967. min: 0.0f
  968. max: getMaximumParameterValue (juceParam)
  969. unit: unit
  970. unitName: nullptr
  971. flags: flags
  972. valueStrings: valueStrings.get()
  973. dependentParameters: nullptr] retain];
  974. [param.get() setValue: juceParam->getDefaultValue()];
  975. [params addObject: param];
  976. [overviewParams addObject: [NSNumber numberWithUnsignedLongLong:address]];
  977. }
  978. // create methods in AUParameterTree return unretained objects (!) -> see Apple header AUAudioUnitImplementation.h
  979. paramTree = [[AUParameterTree createTreeWithChildren: params] retain];
  980. paramObserver = CreateObjCBlock (this, &JuceAudioUnitv3::valueChangedFromHost);
  981. paramProvider = CreateObjCBlock (this, &JuceAudioUnitv3::getValue);
  982. stringFromValueProvider = CreateObjCBlock (this, &JuceAudioUnitv3::stringFromValue);
  983. valueFromStringProvider = CreateObjCBlock (this, &JuceAudioUnitv3::valueFromString);
  984. [paramTree setImplementorValueObserver: paramObserver];
  985. [paramTree setImplementorValueProvider: paramProvider];
  986. [paramTree setImplementorStringFromValueCallback: stringFromValueProvider];
  987. [paramTree setImplementorValueFromStringCallback: valueFromStringProvider];
  988. if (processor.hasEditor())
  989. {
  990. editorParamObserver = CreateObjCBlock (this, &JuceAudioUnitv3::valueChangedForObserver);
  991. editorObserverToken = [paramTree tokenByAddingParameterObserver: editorParamObserver];
  992. }
  993. }
  994. void setAudioProcessorParameter (AudioProcessorParameter* juceParam, float value)
  995. {
  996. if (value != juceParam->getValue())
  997. {
  998. juceParam->setValue (value);
  999. inParameterChangedCallback = true;
  1000. juceParam->sendValueChangedMessageToListeners (value);
  1001. }
  1002. }
  1003. void addPresets()
  1004. {
  1005. factoryPresets = [[NSMutableArray<AUAudioUnitPreset*> alloc] init];
  1006. const int n = getAudioProcessor().getNumPrograms();
  1007. for (int idx = 0; idx < n; ++idx)
  1008. {
  1009. String name = getAudioProcessor().getProgramName (idx);
  1010. ScopedPointer<AUAudioUnitPreset> preset = [[AUAudioUnitPreset alloc] init];
  1011. [preset setName: juceStringToNS (name)];
  1012. [preset setNumber: static_cast<NSInteger> (idx)];
  1013. [factoryPresets addObject: preset];
  1014. }
  1015. }
  1016. //==============================================================================
  1017. void allocateBusBuffer (bool isInput)
  1018. {
  1019. OwnedArray<BusBuffer>& busBuffers = isInput ? inBusBuffers : outBusBuffers;
  1020. busBuffers.clear();
  1021. const int n = AudioUnitHelpers::getBusCount (&getAudioProcessor(), isInput);
  1022. const AUAudioFrameCount maxFrames = [getAudioUnit() maximumFramesToRender];
  1023. for (int busIdx = 0; busIdx < n; ++busIdx)
  1024. busBuffers.add (new BusBuffer ([(isInput ? inputBusses : outputBusses) objectAtIndexedSubscript: static_cast<unsigned int> (busIdx)],
  1025. static_cast<int> (maxFrames)));
  1026. }
  1027. //==============================================================================
  1028. void processEvents (const AURenderEvent *__nullable realtimeEventListHead, int numParams, AUEventSampleTime startTime)
  1029. {
  1030. ignoreUnused (numParams);
  1031. for (const AURenderEvent* event = realtimeEventListHead; event != nullptr; event = event->head.next)
  1032. {
  1033. switch (event->head.eventType)
  1034. {
  1035. case AURenderEventMIDI:
  1036. {
  1037. const AUMIDIEvent& midiEvent = event->MIDI;
  1038. midiMessages.addEvent (midiEvent.data, midiEvent.length, static_cast<int> (midiEvent.eventSampleTime - startTime));
  1039. }
  1040. break;
  1041. case AURenderEventParameter:
  1042. case AURenderEventParameterRamp:
  1043. {
  1044. const AUParameterEvent& paramEvent = event->parameter;
  1045. if (auto* p = getJuceParameterForAUAddress (paramEvent.parameterAddress))
  1046. setAudioProcessorParameter (p, paramEvent.value);
  1047. }
  1048. break;
  1049. default:
  1050. break;
  1051. }
  1052. }
  1053. }
  1054. AUAudioUnitStatus renderCallback (AudioUnitRenderActionFlags* actionFlags, const AudioTimeStamp* timestamp, AUAudioFrameCount frameCount,
  1055. NSInteger outputBusNumber, AudioBufferList* outputData, const AURenderEvent *__nullable realtimeEventListHead,
  1056. AURenderPullInputBlock __nullable pullInputBlock)
  1057. {
  1058. auto& processor = getAudioProcessor();
  1059. jassert (static_cast<int> (frameCount) <= getAudioProcessor().getBlockSize());
  1060. // process params
  1061. const int numParams = juceParameters.getNumParameters();
  1062. processEvents (realtimeEventListHead, numParams, static_cast<AUEventSampleTime> (timestamp->mSampleTime));
  1063. if (lastTimeStamp.mSampleTime != timestamp->mSampleTime)
  1064. {
  1065. lastTimeStamp = *timestamp;
  1066. const int numInputBuses = inBusBuffers. size();
  1067. const int numOutputBuses = outBusBuffers.size();
  1068. // prepare buffers
  1069. {
  1070. for (int busIdx = 0; busIdx < numOutputBuses; ++busIdx)
  1071. {
  1072. BusBuffer& busBuffer = *outBusBuffers[busIdx];
  1073. const bool canUseDirectOutput =
  1074. (busIdx == outputBusNumber && outputData != nullptr && outputData->mNumberBuffers > 0);
  1075. busBuffer.prepare (frameCount, canUseDirectOutput ? outputData : nullptr);
  1076. }
  1077. for (int busIdx = 0; busIdx < numInputBuses; ++busIdx)
  1078. {
  1079. BusBuffer& busBuffer = *inBusBuffers[busIdx];
  1080. busBuffer.prepare (frameCount, busIdx < numOutputBuses ? outBusBuffers[busIdx]->get() : nullptr);
  1081. }
  1082. audioBuffer.reset();
  1083. }
  1084. // pull inputs
  1085. {
  1086. for (int busIdx = 0; busIdx < numInputBuses; ++busIdx)
  1087. {
  1088. BusBuffer& busBuffer = *inBusBuffers[busIdx];
  1089. AudioBufferList* buffer = busBuffer.get();
  1090. if (pullInputBlock == nullptr || pullInputBlock (actionFlags, timestamp, frameCount, busIdx, buffer) != noErr)
  1091. AudioUnitHelpers::clearAudioBuffer (*buffer);
  1092. if (actionFlags != nullptr && (*actionFlags & kAudioUnitRenderAction_OutputIsSilence) != 0)
  1093. AudioUnitHelpers::clearAudioBuffer (*buffer);
  1094. }
  1095. }
  1096. // set buffer pointer to minimize copying
  1097. {
  1098. int chIdx = 0;
  1099. for (int busIdx = 0; busIdx < numOutputBuses; ++busIdx)
  1100. {
  1101. BusBuffer& busBuffer = *outBusBuffers[busIdx];
  1102. AudioBufferList* buffer = busBuffer.get();
  1103. const bool interleaved = busBuffer.interleaved();
  1104. const int numChannels = busBuffer.numChannels();
  1105. const int* outLayoutMap = mapper.get (false, busIdx);
  1106. for (int ch = 0; ch < numChannels; ++ch)
  1107. audioBuffer.setBuffer (chIdx++, interleaved ? nullptr : static_cast<float*> (buffer->mBuffers[outLayoutMap[ch]].mData));
  1108. }
  1109. // use input pointers on remaining channels
  1110. for (int busIdx = 0; chIdx < totalInChannels;)
  1111. {
  1112. const int channelOffset = processor.getOffsetInBusBufferForAbsoluteChannelIndex (true, chIdx, busIdx);
  1113. BusBuffer& busBuffer = *inBusBuffers[busIdx];
  1114. AudioBufferList* buffer = busBuffer.get();
  1115. const int* inLayoutMap = mapper.get (true, busIdx);
  1116. audioBuffer.setBuffer (chIdx++, busBuffer.interleaved() ? nullptr : static_cast<float*> (buffer->mBuffers[inLayoutMap[channelOffset]].mData));
  1117. }
  1118. }
  1119. // copy input
  1120. {
  1121. for (int busIdx = 0; busIdx < numInputBuses; ++busIdx)
  1122. audioBuffer.push (*inBusBuffers[busIdx]->get(), mapper.get (true, busIdx));
  1123. // clear remaining channels
  1124. for (int i = totalInChannels; i < totalOutChannels; ++i)
  1125. zeromem (audioBuffer.push(), sizeof (float) * frameCount);
  1126. }
  1127. // process audio
  1128. processBlock (audioBuffer.getBuffer (frameCount), midiMessages);
  1129. // send MIDI
  1130. #if JucePlugin_ProducesMidiOutput && JUCE_AUV3_MIDI_OUTPUT_SUPPORTED
  1131. auto midiOut = [au MIDIOutputEventBlock];
  1132. MidiMessage msg;
  1133. int samplePosition;
  1134. for (MidiBuffer::Iterator it (midiMessages); it.getNextEvent (msg, samplePosition);)
  1135. midiOut (samplePosition, 0, msg.getRawDataSize(), msg.getRawData());
  1136. #endif
  1137. midiMessages.clear();
  1138. }
  1139. // copy back
  1140. audioBuffer.pop (*outBusBuffers[(int) outputBusNumber]->get(),
  1141. mapper.get (false, (int) outputBusNumber));
  1142. return noErr;
  1143. }
  1144. void processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiBuffer) noexcept
  1145. {
  1146. auto& processor = getAudioProcessor();
  1147. const ScopedLock sl (processor.getCallbackLock());
  1148. if (processor.isSuspended())
  1149. buffer.clear();
  1150. else if ([au shouldBypassEffect])
  1151. processor.processBlockBypassed (buffer, midiBuffer);
  1152. else
  1153. processor.processBlock (buffer, midiBuffer);
  1154. }
  1155. //==============================================================================
  1156. void valueChangedFromHost (AUParameter* param, AUValue value)
  1157. {
  1158. if (param != nullptr)
  1159. {
  1160. if (auto* p = getJuceParameterForAUAddress ([param address]))
  1161. {
  1162. auto normalisedValue = value / getMaximumParameterValue (p);
  1163. setAudioProcessorParameter (p, normalisedValue);
  1164. }
  1165. }
  1166. }
  1167. AUValue getValue (AUParameter* param)
  1168. {
  1169. if (param != nullptr)
  1170. {
  1171. if (auto* p = getJuceParameterForAUAddress ([param address]))
  1172. return p->getValue() * getMaximumParameterValue (p);
  1173. }
  1174. return 0;
  1175. }
  1176. void valueChangedForObserver (AUParameterAddress, AUValue)
  1177. {
  1178. // this will have already been handled by valueChangedFromHost
  1179. }
  1180. NSString* stringFromValue (AUParameter* param, const AUValue* value)
  1181. {
  1182. String text;
  1183. if (param != nullptr && value != nullptr)
  1184. {
  1185. if (auto* p = getJuceParameterForAUAddress ([param address]))
  1186. {
  1187. if (LegacyAudioParameter::isLegacy (p))
  1188. text = String (*value);
  1189. else
  1190. text = p->getText (*value / getMaximumParameterValue (p), 0);
  1191. }
  1192. }
  1193. return juceStringToNS (text);
  1194. }
  1195. AUValue valueFromString (AUParameter* param, NSString* str)
  1196. {
  1197. if (param != nullptr && str != nullptr)
  1198. {
  1199. if (auto* p = getJuceParameterForAUAddress ([param address]))
  1200. {
  1201. const String text (nsStringToJuce (str));
  1202. if (LegacyAudioParameter::isLegacy (p))
  1203. return text.getFloatValue();
  1204. else
  1205. return p->getValueForText (text) * getMaximumParameterValue (p);
  1206. }
  1207. }
  1208. return 0;
  1209. }
  1210. //==============================================================================
  1211. #if JUCE_FORCE_USE_LEGACY_PARAM_IDS
  1212. inline AUParameterAddress getAUParameterAddressForIndex (int paramIndex) const noexcept { return static_cast<AUParameterAddress> (paramIndex); }
  1213. inline int getJuceParameterIndexForAUAddress (AUParameterAddress address) const noexcept { return static_cast<int> (address); }
  1214. #else
  1215. inline AUParameterAddress getAUParameterAddressForIndex (int paramIndex) const noexcept
  1216. {
  1217. return juceParameters.isUsingManagedParameters() ? paramAddresses.getReference (paramIndex)
  1218. : static_cast<AUParameterAddress> (paramIndex);
  1219. }
  1220. inline int getJuceParameterIndexForAUAddress (AUParameterAddress address) const noexcept
  1221. {
  1222. return juceParameters.isUsingManagedParameters() ? paramMap[static_cast<int64> (address)]
  1223. : static_cast<int> (address);
  1224. }
  1225. #endif
  1226. AUParameterAddress generateAUParameterAddress (AudioProcessorParameter* param) const
  1227. {
  1228. const String& juceParamID = LegacyAudioParameter::getParamID (param, forceLegacyParamIDs);
  1229. return juceParameters.isUsingManagedParameters() ? static_cast<AUParameterAddress> (juceParamID.hashCode64())
  1230. : static_cast<AUParameterAddress> (juceParamID.getIntValue());
  1231. }
  1232. AudioProcessorParameter* getJuceParameterForAUAddress (AUParameterAddress address) const noexcept
  1233. {
  1234. return juceParameters.getParamForIndex (getJuceParameterIndexForAUAddress (address));
  1235. }
  1236. //==============================================================================
  1237. static const double kDefaultSampleRate;
  1238. AudioProcessorHolder::Ptr processorHolder;
  1239. int totalInChannels, totalOutChannels;
  1240. ScopedPointer<AUAudioUnitBusArray> inputBusses;
  1241. ScopedPointer<AUAudioUnitBusArray> outputBusses;
  1242. ObjCBlock<AUImplementorValueObserver> paramObserver;
  1243. ObjCBlock<AUImplementorValueProvider> paramProvider;
  1244. ObjCBlock<AUImplementorStringFromValueCallback> stringFromValueProvider;
  1245. ObjCBlock<AUImplementorValueFromStringCallback> valueFromStringProvider;
  1246. #if ! JUCE_FORCE_USE_LEGACY_PARAM_IDS
  1247. Array<AUParameterAddress> paramAddresses;
  1248. HashMap<int64, int> paramMap;
  1249. #endif
  1250. LegacyAudioParametersWrapper juceParameters;
  1251. // to avoid recursion on parameter changes, we need to add an
  1252. // editor observer to do the parameter changes
  1253. ObjCBlock<AUParameterObserver> editorParamObserver;
  1254. AUParameterObserverToken editorObserverToken;
  1255. ScopedPointer<AUParameterTree> paramTree;
  1256. ScopedPointer<NSMutableArray<NSNumber*>> overviewParams;
  1257. ScopedPointer<NSMutableArray<NSNumber*>> channelCapabilities;
  1258. ScopedPointer<NSMutableArray<AUAudioUnitPreset*>> factoryPresets;
  1259. ObjCBlock<AUInternalRenderBlock> internalRenderBlock;
  1260. AudioUnitHelpers::CoreAudioBufferList audioBuffer;
  1261. AudioUnitHelpers::ChannelRemapper mapper;
  1262. OwnedArray<BusBuffer> inBusBuffers, outBusBuffers;
  1263. MidiBuffer midiMessages;
  1264. ObjCBlock<AUHostMusicalContextBlock> hostMusicalContextCallback;
  1265. ObjCBlock<AUHostTransportStateBlock> hostTransportStateCallback;
  1266. AudioTimeStamp lastTimeStamp;
  1267. CurrentPositionInfo lastAudioHead;
  1268. String contextName;
  1269. ThreadLocalValue<bool> inParameterChangedCallback;
  1270. #if JUCE_FORCE_USE_LEGACY_PARAM_IDS
  1271. static constexpr bool forceLegacyParamIDs = true;
  1272. #else
  1273. static constexpr bool forceLegacyParamIDs = false;
  1274. #endif
  1275. };
  1276. const double JuceAudioUnitv3::kDefaultSampleRate = 44100.0;
  1277. JuceAudioUnitv3Base* JuceAudioUnitv3Base::create (AUAudioUnit* audioUnit, AudioComponentDescription descr, AudioComponentInstantiationOptions options, NSError** error)
  1278. {
  1279. PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_AudioUnitv3;
  1280. return new JuceAudioUnitv3 (audioUnit, descr, options, error);
  1281. }
  1282. //==============================================================================
  1283. class JuceAUViewController
  1284. {
  1285. public:
  1286. JuceAUViewController (AUViewController<AUAudioUnitFactory>* p)
  1287. : myself (p)
  1288. {
  1289. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  1290. PluginHostType::jucePlugInClientCurrentWrapperType = AudioProcessor::wrapperType_AudioUnitv3;
  1291. initialiseJuce_GUI();
  1292. }
  1293. ~JuceAUViewController()
  1294. {
  1295. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  1296. if (processorHolder != nullptr)
  1297. JuceAudioUnitv3::removeEditor (getAudioProcessor());
  1298. }
  1299. //==============================================================================
  1300. void loadView()
  1301. {
  1302. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  1303. if (AudioProcessor* p = createPluginFilterOfType (AudioProcessor::wrapperType_AudioUnitv3))
  1304. {
  1305. processorHolder = new AudioProcessorHolder (p);
  1306. auto& processor = getAudioProcessor();
  1307. if (processor.hasEditor())
  1308. {
  1309. if (AudioProcessorEditor* editor = processor.createEditorIfNeeded())
  1310. {
  1311. preferredSize = editor->getBounds();
  1312. JUCE_IOS_MAC_VIEW* view = [[[JUCE_IOS_MAC_VIEW alloc] initWithFrame: convertToCGRect (editor->getBounds())] autorelease];
  1313. [myself setView: view];
  1314. #if JUCE_IOS
  1315. editor->setVisible (false);
  1316. #else
  1317. editor->setVisible (true);
  1318. #endif
  1319. editor->addToDesktop (0, view);
  1320. #if JUCE_IOS
  1321. if (JUCE_IOS_MAC_VIEW* peerView = [[[myself view] subviews] objectAtIndex: 0])
  1322. [peerView setContentMode: UIViewContentModeTop];
  1323. #endif
  1324. }
  1325. }
  1326. }
  1327. }
  1328. void viewDidLayoutSubviews()
  1329. {
  1330. if (processorHolder != nullptr && [myself view] != nullptr)
  1331. {
  1332. if (AudioProcessorEditor* editor = getAudioProcessor().getActiveEditor())
  1333. {
  1334. if (processorHolder->viewConfiguration != nullptr)
  1335. editor->hostMIDIControllerIsAvailable (processorHolder->viewConfiguration->hostHasMIDIController);
  1336. editor->setBounds (convertToRectInt ([[myself view] bounds]));
  1337. if (JUCE_IOS_MAC_VIEW* peerView = [[[myself view] subviews] objectAtIndex: 0])
  1338. {
  1339. #if JUCE_IOS
  1340. [peerView setNeedsDisplay];
  1341. #else
  1342. [peerView setNeedsDisplay: YES];
  1343. #endif
  1344. }
  1345. }
  1346. }
  1347. }
  1348. void didReceiveMemoryWarning()
  1349. {
  1350. if (processorHolder != nullptr)
  1351. if (auto* processor = processorHolder->get())
  1352. processor->memoryWarningReceived();
  1353. }
  1354. void viewDidAppear (bool)
  1355. {
  1356. if (processorHolder != nullptr)
  1357. if (AudioProcessorEditor* editor = getAudioProcessor().getActiveEditor())
  1358. editor->setVisible (true);
  1359. }
  1360. void viewDidDisappear (bool)
  1361. {
  1362. if (processorHolder != nullptr)
  1363. if (AudioProcessorEditor* editor = getAudioProcessor().getActiveEditor())
  1364. editor->setVisible (false);
  1365. }
  1366. CGSize getPreferredContentSize() const
  1367. {
  1368. return CGSizeMake (static_cast<float> (preferredSize.getWidth()),
  1369. static_cast<float> (preferredSize.getHeight()));
  1370. }
  1371. //==============================================================================
  1372. AUAudioUnit* createAudioUnit (const AudioComponentDescription& descr, NSError** error)
  1373. {
  1374. AUAudioUnit* retval = nil;
  1375. if (! MessageManager::getInstance()->isThisTheMessageThread())
  1376. {
  1377. WaitableEvent creationEvent;
  1378. // AUv3 headers say that we may block this thread and that the message thread is guaranteed
  1379. // to be unblocked
  1380. struct AUCreator : public CallbackMessage
  1381. {
  1382. JuceAUViewController& owner;
  1383. AudioComponentDescription pDescr;
  1384. NSError** pError;
  1385. AUAudioUnit*& outAU;
  1386. WaitableEvent& e;
  1387. AUCreator (JuceAUViewController& parent, const AudioComponentDescription& paramDescr, NSError** paramError,
  1388. AUAudioUnit*& outputAU, WaitableEvent& event)
  1389. : owner (parent), pDescr (paramDescr), pError (paramError), outAU (outputAU), e (event)
  1390. {}
  1391. void messageCallback() override
  1392. {
  1393. outAU = owner.createAudioUnitOnMessageThread (pDescr, pError);
  1394. e.signal();
  1395. }
  1396. };
  1397. (new AUCreator (*this, descr, error, retval, creationEvent))->post();
  1398. creationEvent.wait (-1);
  1399. }
  1400. else
  1401. {
  1402. retval = createAudioUnitOnMessageThread (descr, error);
  1403. }
  1404. return [retval autorelease];
  1405. }
  1406. private:
  1407. //==============================================================================
  1408. AUViewController<AUAudioUnitFactory>* myself;
  1409. AudioProcessorHolder::Ptr processorHolder = nullptr;
  1410. Rectangle<int> preferredSize { 1, 1 };
  1411. //==============================================================================
  1412. AUAudioUnit* createAudioUnitOnMessageThread (const AudioComponentDescription& descr, NSError** error)
  1413. {
  1414. jassert (MessageManager::getInstance()->isThisTheMessageThread());
  1415. [myself view]; // this will call [view load] and ensure that the AudioProcessor has been instantiated
  1416. if (processorHolder == nullptr)
  1417. return nullptr;
  1418. return (new JuceAudioUnitv3 (processorHolder, descr, 0, error))->getAudioUnit();
  1419. }
  1420. AudioProcessor& getAudioProcessor() const noexcept { return **processorHolder; }
  1421. };
  1422. //==============================================================================
  1423. // necessary glue code
  1424. @interface JUCE_VIEWCONTROLLER_OBJC_NAME (JucePlugin_AUExportPrefix) : AUViewController<AUAudioUnitFactory>
  1425. @end
  1426. @implementation JUCE_VIEWCONTROLLER_OBJC_NAME (JucePlugin_AUExportPrefix)
  1427. {
  1428. ScopedPointer<JuceAUViewController> cpp;
  1429. }
  1430. - (instancetype) initWithNibName: (nullable NSString*) nib bundle: (nullable NSBundle*) bndl { self = [super initWithNibName: nib bundle: bndl]; cpp = new JuceAUViewController (self); return self; }
  1431. - (void) loadView { cpp->loadView(); }
  1432. - (AUAudioUnit *) createAudioUnitWithComponentDescription: (AudioComponentDescription) desc error: (NSError **) error { return cpp->createAudioUnit (desc, error); }
  1433. - (CGSize) preferredContentSize { return cpp->getPreferredContentSize(); }
  1434. - (void) viewDidLayoutSubviews { cpp->viewDidLayoutSubviews(); }
  1435. - (void) didReceiveMemoryWarning { cpp->didReceiveMemoryWarning(); }
  1436. #if JUCE_IOS
  1437. - (void) viewDidAppear: (BOOL) animated { cpp->viewDidAppear (animated); [super viewDidAppear:animated]; }
  1438. - (void) viewDidDisappear: (BOOL) animated { cpp->viewDidDisappear (animated); [super viewDidDisappear:animated]; }
  1439. #endif
  1440. @end
  1441. //==============================================================================
  1442. #if JUCE_IOS
  1443. bool JUCE_CALLTYPE juce_isInterAppAudioConnected() { return false; }
  1444. void JUCE_CALLTYPE juce_switchToHostApplication() {}
  1445. #if JUCE_MODULE_AVAILABLE_juce_gui_basics
  1446. Image JUCE_CALLTYPE juce_getIAAHostIcon (int) { return {}; }
  1447. #endif
  1448. #endif
  1449. #pragma clang diagnostic pop
  1450. #endif