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.

1944 lines
82KB

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