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.

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