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.

1953 lines
82KB

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