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.

1873 lines
82KB

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