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.

2036 lines
85KB

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