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.

2079 lines
86KB

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