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.

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