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.

1954 lines
83KB

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