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.

1553 lines
56KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. // Your project must contain an AppConfig.h file with your project-specific settings in it,
  18. // and your header search path must make it accessible to the module's files.
  19. #include "AppConfig.h"
  20. #include "../utility/juce_CheckSettingMacros.h"
  21. #if JucePlugin_Build_AU
  22. #if __LP64__
  23. #undef JUCE_SUPPORT_CARBON
  24. #define JUCE_SUPPORT_CARBON 0
  25. #endif
  26. #ifdef __clang__
  27. #pragma clang diagnostic push
  28. #pragma clang diagnostic ignored "-Wshorten-64-to-32"
  29. #pragma clang diagnostic ignored "-Wunused-parameter"
  30. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  31. #pragma clang diagnostic ignored "-Wsign-conversion"
  32. #pragma clang diagnostic ignored "-Wconversion"
  33. #endif
  34. #include "../utility/juce_IncludeSystemHeaders.h"
  35. #include <AudioUnit/AUCocoaUIView.h>
  36. #include <AudioUnit/AudioUnit.h>
  37. #include <AudioToolbox/AudioUnitUtilities.h>
  38. #include <CoreMIDI/MIDIServices.h>
  39. #if JUCE_SUPPORT_CARBON
  40. #define Point CarbonDummyPointName
  41. #define Component CarbonDummyCompName
  42. #endif
  43. /*
  44. Got an include error here?
  45. You probably need to install Apple's AU classes - see the
  46. juce website for more info on how to get them:
  47. http://www.juce.com/forum/topic/aus-xcode
  48. */
  49. #include "AUMIDIEffectBase.h"
  50. #include "MusicDeviceBase.h"
  51. #undef Point
  52. #undef Component
  53. /** The BUILD_AU_CARBON_UI flag lets you specify whether old-school carbon hosts are supported as
  54. well as ones that can open a cocoa view. If this is enabled, you'll need to also add the AUCarbonBase
  55. files to your project.
  56. */
  57. #if ! (defined (BUILD_AU_CARBON_UI) || JUCE_64BIT)
  58. #define BUILD_AU_CARBON_UI 1
  59. #endif
  60. #ifdef __LP64__
  61. #undef BUILD_AU_CARBON_UI // (not possible in a 64-bit build)
  62. #endif
  63. #if BUILD_AU_CARBON_UI
  64. #undef Button
  65. #define Point CarbonDummyPointName
  66. #include "AUCarbonViewBase.h"
  67. #undef Point
  68. #endif
  69. #ifdef __clang__
  70. #pragma clang diagnostic pop
  71. #endif
  72. #define JUCE_MAC_WINDOW_VISIBITY_BODGE 1
  73. #include "../utility/juce_IncludeModuleHeaders.h"
  74. #include "../utility/juce_FakeMouseMoveGenerator.h"
  75. #include "../utility/juce_CarbonVisibility.h"
  76. #include "../../juce_core/native/juce_osx_ObjCHelpers.h"
  77. //==============================================================================
  78. static Array<void*> activePlugins, activeUIs;
  79. static const AudioUnitPropertyID juceFilterObjectPropertyID = 0x1a45ffe9;
  80. static const short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations };
  81. static const int numChannelConfigs = sizeof (channelConfigs) / sizeof (*channelConfigs);
  82. #if JucePlugin_IsSynth
  83. class JuceAUBaseClass : public MusicDeviceBase
  84. {
  85. public:
  86. JuceAUBaseClass (AudioComponentInstance comp) : MusicDeviceBase (comp, 0, 1) {}
  87. };
  88. #else
  89. class JuceAUBaseClass : public AUMIDIEffectBase
  90. {
  91. public:
  92. JuceAUBaseClass (AudioComponentInstance comp) : AUMIDIEffectBase (comp, false) {}
  93. OSStatus MIDIEvent (UInt32 inStatus, UInt32 inData1, UInt32 inData2, UInt32 inOffsetSampleFrame)
  94. {
  95. return AUMIDIBase::MIDIEvent (inStatus, inData1, inData2, inOffsetSampleFrame);
  96. }
  97. OSStatus SysEx (const UInt8* inData, UInt32 inLength)
  98. {
  99. return AUMIDIBase::SysEx (inData, inLength);
  100. }
  101. };
  102. #endif
  103. // This macro can be set if you need to override this internal name for some reason..
  104. #ifndef JUCE_STATE_DICTIONARY_KEY
  105. #define JUCE_STATE_DICTIONARY_KEY CFSTR("jucePluginState")
  106. #endif
  107. //==============================================================================
  108. class JuceAU : public JuceAUBaseClass,
  109. public AudioProcessorListener,
  110. public AudioPlayHead,
  111. public ComponentListener
  112. {
  113. public:
  114. //==============================================================================
  115. JuceAU (AudioUnit component)
  116. : JuceAUBaseClass (component),
  117. bufferSpace (2, 16),
  118. prepared (false)
  119. {
  120. if (activePlugins.size() + activeUIs.size() == 0)
  121. {
  122. #if BUILD_AU_CARBON_UI
  123. NSApplicationLoad();
  124. #endif
  125. initialiseJuce_GUI();
  126. }
  127. juceFilter = createPluginFilterOfType (AudioProcessor::wrapperType_AudioUnit);
  128. juceFilter->setPlayHead (this);
  129. juceFilter->addListener (this);
  130. Globals()->UseIndexedParameters (juceFilter->getNumParameters());
  131. activePlugins.add (this);
  132. zerostruct (auEvent);
  133. auEvent.mArgument.mParameter.mAudioUnit = GetComponentInstance();
  134. auEvent.mArgument.mParameter.mScope = kAudioUnitScope_Global;
  135. auEvent.mArgument.mParameter.mElement = 0;
  136. zerostruct (midiCallback);
  137. CreateElements();
  138. CAStreamBasicDescription streamDescription;
  139. streamDescription.mSampleRate = getSampleRate();
  140. streamDescription.SetCanonical ((UInt32) channelConfigs[0][1], false);
  141. Outputs().GetIOElement(0)->SetStreamFormat (streamDescription);
  142. #if ! JucePlugin_IsSynth
  143. streamDescription.SetCanonical ((UInt32) channelConfigs[0][0], false);
  144. Inputs().GetIOElement(0)->SetStreamFormat (streamDescription);
  145. #endif
  146. }
  147. ~JuceAU()
  148. {
  149. deleteActiveEditors();
  150. juceFilter = nullptr;
  151. clearPresetsArray();
  152. jassert (activePlugins.contains (this));
  153. activePlugins.removeFirstMatchingValue (this);
  154. if (activePlugins.size() + activeUIs.size() == 0)
  155. shutdownJuce_GUI();
  156. }
  157. void deleteActiveEditors()
  158. {
  159. for (int i = activeUIs.size(); --i >= 0;)
  160. {
  161. id ui = (id) activeUIs.getUnchecked(i);
  162. if (JuceUIViewClass::getAU (ui) == this)
  163. JuceUIViewClass::deleteEditor (ui);
  164. }
  165. }
  166. //==============================================================================
  167. ComponentResult GetPropertyInfo (AudioUnitPropertyID inID,
  168. AudioUnitScope inScope,
  169. AudioUnitElement inElement,
  170. UInt32& outDataSize,
  171. Boolean& outWritable) override
  172. {
  173. if (inScope == kAudioUnitScope_Global)
  174. {
  175. switch (inID)
  176. {
  177. case juceFilterObjectPropertyID:
  178. outWritable = false;
  179. outDataSize = sizeof (void*) * 2;
  180. return noErr;
  181. case kAudioUnitProperty_OfflineRender:
  182. outWritable = true;
  183. outDataSize = sizeof (UInt32);
  184. return noErr;
  185. case kMusicDeviceProperty_InstrumentCount:
  186. outDataSize = sizeof (UInt32);
  187. outWritable = false;
  188. return noErr;
  189. case kAudioUnitProperty_CocoaUI:
  190. #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
  191. // (On 10.4, there's a random obj-c dispatching crash when trying to load a cocoa UI)
  192. if (SystemStats::getOperatingSystemType() >= SystemStats::MacOSX_10_5)
  193. #endif
  194. {
  195. outDataSize = sizeof (AudioUnitCocoaViewInfo);
  196. outWritable = true;
  197. return noErr;
  198. }
  199. break;
  200. #if JucePlugin_ProducesMidiOutput
  201. case kAudioUnitProperty_MIDIOutputCallbackInfo:
  202. outDataSize = sizeof (CFArrayRef);
  203. outWritable = false;
  204. return noErr;
  205. case kAudioUnitProperty_MIDIOutputCallback:
  206. outDataSize = sizeof (AUMIDIOutputCallbackStruct);
  207. outWritable = true;
  208. return noErr;
  209. #endif
  210. default: break;
  211. }
  212. }
  213. return JuceAUBaseClass::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
  214. }
  215. ComponentResult GetProperty (AudioUnitPropertyID inID,
  216. AudioUnitScope inScope,
  217. AudioUnitElement inElement,
  218. void* outData) override
  219. {
  220. if (inScope == kAudioUnitScope_Global)
  221. {
  222. switch (inID)
  223. {
  224. case juceFilterObjectPropertyID:
  225. ((void**) outData)[0] = (void*) static_cast <AudioProcessor*> (juceFilter);
  226. ((void**) outData)[1] = (void*) this;
  227. return noErr;
  228. case kAudioUnitProperty_OfflineRender:
  229. *(UInt32*) outData = (juceFilter != nullptr && juceFilter->isNonRealtime()) ? 1 : 0;
  230. return noErr;
  231. case kMusicDeviceProperty_InstrumentCount:
  232. *(UInt32*) outData = 1;
  233. return noErr;
  234. case kAudioUnitProperty_CocoaUI:
  235. #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
  236. // (On 10.4, there's a random obj-c dispatching crash when trying to load a cocoa UI)
  237. if (SystemStats::getOperatingSystemType() >= SystemStats::MacOSX_10_5)
  238. #endif
  239. {
  240. JUCE_AUTORELEASEPOOL
  241. {
  242. static JuceUICreationClass cls;
  243. // (NB: this may be the host's bundle, not necessarily the component's)
  244. NSBundle* bundle = [NSBundle bundleForClass: cls.cls];
  245. AudioUnitCocoaViewInfo* info = static_cast <AudioUnitCocoaViewInfo*> (outData);
  246. info->mCocoaAUViewClass[0] = (CFStringRef) [juceStringToNS (class_getName (cls.cls)) retain];
  247. info->mCocoaAUViewBundleLocation = (CFURLRef) [[NSURL fileURLWithPath: [bundle bundlePath]] retain];
  248. }
  249. return noErr;
  250. }
  251. break;
  252. #if JucePlugin_ProducesMidiOutput
  253. case kAudioUnitProperty_MIDIOutputCallbackInfo:
  254. {
  255. CFStringRef strs[1];
  256. strs[0] = CFSTR ("MIDI Callback");
  257. CFArrayRef callbackArray = CFArrayCreate (nullptr, (const void**) strs, 1, &kCFTypeArrayCallBacks);
  258. *(CFArrayRef*) outData = callbackArray;
  259. return noErr;
  260. }
  261. #endif
  262. default: break;
  263. }
  264. }
  265. return JuceAUBaseClass::GetProperty (inID, inScope, inElement, outData);
  266. }
  267. ComponentResult SetProperty (AudioUnitPropertyID inID,
  268. AudioUnitScope inScope,
  269. AudioUnitElement inElement,
  270. const void* inData,
  271. UInt32 inDataSize) override
  272. {
  273. if (inScope == kAudioUnitScope_Global)
  274. {
  275. switch (inID)
  276. {
  277. #if JucePlugin_ProducesMidiOutput
  278. case kAudioUnitProperty_MIDIOutputCallback:
  279. if (inDataSize < sizeof (AUMIDIOutputCallbackStruct))
  280. return kAudioUnitErr_InvalidPropertyValue;
  281. if (AUMIDIOutputCallbackStruct* callbackStruct = (AUMIDIOutputCallbackStruct*) inData)
  282. midiCallback = *callbackStruct;
  283. return noErr;
  284. #endif
  285. case kAudioUnitProperty_OfflineRender:
  286. if (juceFilter != nullptr)
  287. juceFilter->setNonRealtime ((*(UInt32*) inData) != 0);
  288. return noErr;
  289. default: break;
  290. }
  291. }
  292. return JuceAUBaseClass::SetProperty (inID, inScope, inElement, inData, inDataSize);
  293. }
  294. ComponentResult SaveState (CFPropertyListRef* outData) override
  295. {
  296. ComponentResult err = JuceAUBaseClass::SaveState (outData);
  297. if (err != noErr)
  298. return err;
  299. jassert (CFGetTypeID (*outData) == CFDictionaryGetTypeID());
  300. CFMutableDictionaryRef dict = (CFMutableDictionaryRef) *outData;
  301. if (juceFilter != nullptr)
  302. {
  303. juce::MemoryBlock state;
  304. juceFilter->getCurrentProgramStateInformation (state);
  305. if (state.getSize() > 0)
  306. {
  307. CFDataRef ourState = CFDataCreate (kCFAllocatorDefault, (const UInt8*) state.getData(), (CFIndex) state.getSize());
  308. CFDictionarySetValue (dict, JUCE_STATE_DICTIONARY_KEY, ourState);
  309. CFRelease (ourState);
  310. }
  311. }
  312. return noErr;
  313. }
  314. ComponentResult RestoreState (CFPropertyListRef inData) override
  315. {
  316. {
  317. // Remove the data entry from the state to prevent the superclass loading the parameters
  318. CFMutableDictionaryRef copyWithoutData = CFDictionaryCreateMutableCopy (nullptr, 0, (CFDictionaryRef) inData);
  319. CFDictionaryRemoveValue (copyWithoutData, CFSTR (kAUPresetDataKey));
  320. ComponentResult err = JuceAUBaseClass::RestoreState (copyWithoutData);
  321. CFRelease (copyWithoutData);
  322. if (err != noErr)
  323. return err;
  324. }
  325. if (juceFilter != nullptr)
  326. {
  327. CFDictionaryRef dict = (CFDictionaryRef) inData;
  328. CFDataRef data = 0;
  329. if (CFDictionaryGetValueIfPresent (dict, JUCE_STATE_DICTIONARY_KEY, (const void**) &data))
  330. {
  331. if (data != 0)
  332. {
  333. const int numBytes = (int) CFDataGetLength (data);
  334. const juce::uint8* const rawBytes = CFDataGetBytePtr (data);
  335. if (numBytes > 0)
  336. juceFilter->setCurrentProgramStateInformation (rawBytes, numBytes);
  337. }
  338. }
  339. }
  340. return noErr;
  341. }
  342. UInt32 SupportedNumChannels (const AUChannelInfo** outInfo) override
  343. {
  344. // If you hit this, then you need to add some configurations to your
  345. // JucePlugin_PreferredChannelConfigurations setting..
  346. jassert (numChannelConfigs > 0);
  347. if (outInfo != nullptr)
  348. {
  349. *outInfo = channelInfo;
  350. for (int i = 0; i < numChannelConfigs; ++i)
  351. {
  352. #if JucePlugin_IsSynth
  353. channelInfo[i].inChannels = 0;
  354. #else
  355. channelInfo[i].inChannels = channelConfigs[i][0];
  356. #endif
  357. channelInfo[i].outChannels = channelConfigs[i][1];
  358. }
  359. }
  360. return numChannelConfigs;
  361. }
  362. //==============================================================================
  363. ComponentResult GetParameterInfo (AudioUnitScope inScope,
  364. AudioUnitParameterID inParameterID,
  365. AudioUnitParameterInfo& outParameterInfo) override
  366. {
  367. const int index = (int) inParameterID;
  368. if (inScope == kAudioUnitScope_Global
  369. && juceFilter != nullptr
  370. && index < juceFilter->getNumParameters())
  371. {
  372. outParameterInfo.flags = (UInt32) (kAudioUnitParameterFlag_IsWritable
  373. | kAudioUnitParameterFlag_IsReadable
  374. | kAudioUnitParameterFlag_HasCFNameString);
  375. const String name (juceFilter->getParameterName (index));
  376. // set whether the param is automatable (unnamed parameters aren't allowed to be automated)
  377. if (name.isEmpty() || ! juceFilter->isParameterAutomatable (index))
  378. outParameterInfo.flags |= kAudioUnitParameterFlag_NonRealTime;
  379. if (juceFilter->isMetaParameter (index))
  380. outParameterInfo.flags |= kAudioUnitParameterFlag_IsGlobalMeta;
  381. AUBase::FillInParameterName (outParameterInfo, name.toCFString(), true);
  382. outParameterInfo.minValue = 0.0f;
  383. outParameterInfo.maxValue = 1.0f;
  384. outParameterInfo.defaultValue = juceFilter->getParameterDefaultValue (index);
  385. outParameterInfo.unit = kAudioUnitParameterUnit_Generic;
  386. return noErr;
  387. }
  388. return kAudioUnitErr_InvalidParameter;
  389. }
  390. ComponentResult GetParameter (AudioUnitParameterID inID,
  391. AudioUnitScope inScope,
  392. AudioUnitElement inElement,
  393. Float32& outValue) override
  394. {
  395. if (inScope == kAudioUnitScope_Global && juceFilter != nullptr)
  396. {
  397. outValue = juceFilter->getParameter ((int) inID);
  398. return noErr;
  399. }
  400. return AUBase::GetParameter (inID, inScope, inElement, outValue);
  401. }
  402. ComponentResult SetParameter (AudioUnitParameterID inID,
  403. AudioUnitScope inScope,
  404. AudioUnitElement inElement,
  405. Float32 inValue,
  406. UInt32 inBufferOffsetInFrames) override
  407. {
  408. if (inScope == kAudioUnitScope_Global && juceFilter != nullptr)
  409. {
  410. juceFilter->setParameter ((int) inID, inValue);
  411. return noErr;
  412. }
  413. return AUBase::SetParameter (inID, inScope, inElement, inValue, inBufferOffsetInFrames);
  414. }
  415. //==============================================================================
  416. ComponentResult Version() override { return JucePlugin_VersionCode; }
  417. bool SupportsTail() override { return true; }
  418. Float64 GetTailTime() override { return juceFilter->getTailLengthSeconds(); }
  419. double getSampleRate() { return GetOutput(0)->GetStreamFormat().mSampleRate; }
  420. Float64 GetLatency() override
  421. {
  422. const double rate = getSampleRate();
  423. jassert (rate > 0);
  424. return rate > 0 ? juceFilter->getLatencySamples() / rate : 0;
  425. }
  426. //==============================================================================
  427. #if BUILD_AU_CARBON_UI
  428. int GetNumCustomUIComponents() override
  429. {
  430. return PluginHostType().isDigitalPerformer() ? 0 : 1;
  431. }
  432. void GetUIComponentDescs (ComponentDescription* inDescArray) override
  433. {
  434. inDescArray[0].componentType = kAudioUnitCarbonViewComponentType;
  435. inDescArray[0].componentSubType = JucePlugin_AUSubType;
  436. inDescArray[0].componentManufacturer = JucePlugin_AUManufacturerCode;
  437. inDescArray[0].componentFlags = 0;
  438. inDescArray[0].componentFlagsMask = 0;
  439. }
  440. #endif
  441. //==============================================================================
  442. bool getCurrentPosition (AudioPlayHead::CurrentPositionInfo& info) override
  443. {
  444. info.timeSigNumerator = 0;
  445. info.timeSigDenominator = 0;
  446. info.timeInSamples = 0;
  447. info.timeInSeconds = 0;
  448. info.editOriginTime = 0;
  449. info.ppqPositionOfLastBarStart = 0;
  450. info.isPlaying = false;
  451. info.isRecording = false;
  452. info.isLooping = false;
  453. info.ppqLoopStart = 0;
  454. info.ppqLoopEnd = 0;
  455. switch (lastTimeStamp.mSMPTETime.mType)
  456. {
  457. case kSMPTETimeType24: info.frameRate = AudioPlayHead::fps24; break;
  458. case kSMPTETimeType25: info.frameRate = AudioPlayHead::fps25; break;
  459. case kSMPTETimeType30Drop: info.frameRate = AudioPlayHead::fps30drop; break;
  460. case kSMPTETimeType30: info.frameRate = AudioPlayHead::fps30; break;
  461. case kSMPTETimeType2997: info.frameRate = AudioPlayHead::fps2997; break;
  462. case kSMPTETimeType2997Drop: info.frameRate = AudioPlayHead::fps2997drop; break;
  463. //case kSMPTETimeType60:
  464. //case kSMPTETimeType5994:
  465. default: info.frameRate = AudioPlayHead::fpsUnknown; break;
  466. }
  467. if (CallHostBeatAndTempo (&info.ppqPosition, &info.bpm) != noErr)
  468. {
  469. info.ppqPosition = 0;
  470. info.bpm = 0;
  471. }
  472. UInt32 outDeltaSampleOffsetToNextBeat;
  473. double outCurrentMeasureDownBeat;
  474. float num;
  475. UInt32 den;
  476. if (CallHostMusicalTimeLocation (&outDeltaSampleOffsetToNextBeat, &num, &den,
  477. &outCurrentMeasureDownBeat) == noErr)
  478. {
  479. info.timeSigNumerator = (int) num;
  480. info.timeSigDenominator = (int) den;
  481. info.ppqPositionOfLastBarStart = outCurrentMeasureDownBeat;
  482. }
  483. double outCurrentSampleInTimeLine, outCycleStartBeat, outCycleEndBeat;
  484. Boolean playing, playchanged, looping;
  485. if (CallHostTransportState (&playing,
  486. &playchanged,
  487. &outCurrentSampleInTimeLine,
  488. &looping,
  489. &outCycleStartBeat,
  490. &outCycleEndBeat) == noErr)
  491. {
  492. info.isPlaying = playing;
  493. info.timeInSamples = (int64) outCurrentSampleInTimeLine;
  494. info.timeInSeconds = outCurrentSampleInTimeLine / getSampleRate();
  495. }
  496. return true;
  497. }
  498. void sendAUEvent (const AudioUnitEventType type, const int index)
  499. {
  500. if (AUEventListenerNotify != 0)
  501. {
  502. auEvent.mEventType = type;
  503. auEvent.mArgument.mParameter.mParameterID = (AudioUnitParameterID) index;
  504. AUEventListenerNotify (0, 0, &auEvent);
  505. }
  506. }
  507. void audioProcessorParameterChanged (AudioProcessor*, int index, float /*newValue*/)
  508. {
  509. sendAUEvent (kAudioUnitEvent_ParameterValueChange, index);
  510. }
  511. void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index)
  512. {
  513. sendAUEvent (kAudioUnitEvent_BeginParameterChangeGesture, index);
  514. }
  515. void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index)
  516. {
  517. sendAUEvent (kAudioUnitEvent_EndParameterChangeGesture, index);
  518. }
  519. void audioProcessorChanged (AudioProcessor*)
  520. {
  521. PropertyChanged (kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0);
  522. }
  523. bool StreamFormatWritable (AudioUnitScope, AudioUnitElement) override
  524. {
  525. return ! IsInitialized();
  526. }
  527. // (these two slightly different versions are because the definition changed between 10.4 and 10.5)
  528. ComponentResult StartNote (MusicDeviceInstrumentID, MusicDeviceGroupID, NoteInstanceID&, UInt32, const MusicDeviceNoteParams&) { return noErr; }
  529. ComponentResult StartNote (MusicDeviceInstrumentID, MusicDeviceGroupID, NoteInstanceID*, UInt32, const MusicDeviceNoteParams&) { return noErr; }
  530. ComponentResult StopNote (MusicDeviceGroupID, NoteInstanceID, UInt32) { return noErr; }
  531. //==============================================================================
  532. ComponentResult Initialize() override
  533. {
  534. #if ! JucePlugin_IsSynth
  535. const int numIns = GetInput(0) != 0 ? (int) GetInput(0)->GetStreamFormat().mChannelsPerFrame : 0;
  536. #endif
  537. const int numOuts = GetOutput(0) != 0 ? (int) GetOutput(0)->GetStreamFormat().mChannelsPerFrame : 0;
  538. bool isValidChannelConfig = false;
  539. for (int i = 0; i < numChannelConfigs; ++i)
  540. #if JucePlugin_IsSynth
  541. if (numOuts == channelConfigs[i][1])
  542. #else
  543. if (numIns == channelConfigs[i][0] && numOuts == channelConfigs[i][1])
  544. #endif
  545. isValidChannelConfig = true;
  546. if (! isValidChannelConfig)
  547. return kAudioUnitErr_FormatNotSupported;
  548. JuceAUBaseClass::Initialize();
  549. prepareToPlay();
  550. return noErr;
  551. }
  552. void Cleanup() override
  553. {
  554. JuceAUBaseClass::Cleanup();
  555. if (juceFilter != nullptr)
  556. juceFilter->releaseResources();
  557. bufferSpace.setSize (2, 16);
  558. midiEvents.clear();
  559. incomingEvents.clear();
  560. prepared = false;
  561. }
  562. ComponentResult Reset (AudioUnitScope inScope, AudioUnitElement inElement) override
  563. {
  564. if (! prepared)
  565. prepareToPlay();
  566. if (juceFilter != nullptr)
  567. juceFilter->reset();
  568. return JuceAUBaseClass::Reset (inScope, inElement);
  569. }
  570. void prepareToPlay()
  571. {
  572. if (juceFilter != nullptr)
  573. {
  574. juceFilter->setPlayConfigDetails (
  575. #if ! JucePlugin_IsSynth
  576. (int) GetInput(0)->GetStreamFormat().mChannelsPerFrame,
  577. #else
  578. 0,
  579. #endif
  580. (int) GetOutput(0)->GetStreamFormat().mChannelsPerFrame,
  581. getSampleRate(),
  582. (int) GetMaxFramesPerSlice());
  583. bufferSpace.setSize (juceFilter->getNumInputChannels() + juceFilter->getNumOutputChannels(),
  584. (int) GetMaxFramesPerSlice() + 32);
  585. juceFilter->prepareToPlay (getSampleRate(), (int) GetMaxFramesPerSlice());
  586. midiEvents.ensureSize (2048);
  587. midiEvents.clear();
  588. incomingEvents.ensureSize (2048);
  589. incomingEvents.clear();
  590. channels.calloc ((size_t) jmax (juceFilter->getNumInputChannels(),
  591. juceFilter->getNumOutputChannels()) + 4);
  592. prepared = true;
  593. }
  594. }
  595. ComponentResult Render (AudioUnitRenderActionFlags &ioActionFlags,
  596. const AudioTimeStamp& inTimeStamp,
  597. UInt32 nFrames) override
  598. {
  599. lastTimeStamp = inTimeStamp;
  600. #if ! JucePlugin_IsSynth
  601. return JuceAUBaseClass::Render (ioActionFlags, inTimeStamp, nFrames);
  602. #else
  603. // synths can't have any inputs..
  604. AudioBufferList inBuffer;
  605. inBuffer.mNumberBuffers = 0;
  606. return ProcessBufferLists (ioActionFlags, inBuffer, GetOutput(0)->GetBufferList(), nFrames);
  607. #endif
  608. }
  609. OSStatus ProcessBufferLists (AudioUnitRenderActionFlags& ioActionFlags,
  610. const AudioBufferList& inBuffer,
  611. AudioBufferList& outBuffer,
  612. UInt32 numSamples) override
  613. {
  614. if (juceFilter != nullptr)
  615. {
  616. jassert (prepared);
  617. int numOutChans = 0;
  618. int nextSpareBufferChan = 0;
  619. bool needToReinterleave = false;
  620. const int numIn = juceFilter->getNumInputChannels();
  621. const int numOut = juceFilter->getNumOutputChannels();
  622. for (unsigned int i = 0; i < outBuffer.mNumberBuffers; ++i)
  623. {
  624. AudioBuffer& buf = outBuffer.mBuffers[i];
  625. if (buf.mNumberChannels == 1)
  626. {
  627. channels [numOutChans++] = (float*) buf.mData;
  628. }
  629. else
  630. {
  631. needToReinterleave = true;
  632. for (unsigned int subChan = 0; subChan < buf.mNumberChannels && numOutChans < numOut; ++subChan)
  633. channels [numOutChans++] = bufferSpace.getSampleData (nextSpareBufferChan++);
  634. }
  635. if (numOutChans >= numOut)
  636. break;
  637. }
  638. int numInChans = 0;
  639. for (unsigned int i = 0; i < inBuffer.mNumberBuffers; ++i)
  640. {
  641. const AudioBuffer& buf = inBuffer.mBuffers[i];
  642. if (buf.mNumberChannels == 1)
  643. {
  644. if (numInChans < numOutChans)
  645. memcpy (channels [numInChans], (const float*) buf.mData, sizeof (float) * numSamples);
  646. else
  647. channels [numInChans] = (float*) buf.mData;
  648. ++numInChans;
  649. }
  650. else
  651. {
  652. // need to de-interleave..
  653. for (unsigned int subChan = 0; subChan < buf.mNumberChannels && numInChans < numIn; ++subChan)
  654. {
  655. float* dest;
  656. if (numInChans < numOutChans)
  657. {
  658. dest = channels [numInChans++];
  659. }
  660. else
  661. {
  662. dest = bufferSpace.getSampleData (nextSpareBufferChan++);
  663. channels [numInChans++] = dest;
  664. }
  665. const float* src = ((const float*) buf.mData) + subChan;
  666. for (int j = (int) numSamples; --j >= 0;)
  667. {
  668. *dest++ = *src;
  669. src += buf.mNumberChannels;
  670. }
  671. }
  672. }
  673. if (numInChans >= numIn)
  674. break;
  675. }
  676. {
  677. const ScopedLock sl (incomingMidiLock);
  678. midiEvents.clear();
  679. incomingEvents.swapWith (midiEvents);
  680. }
  681. {
  682. AudioSampleBuffer buffer (channels, jmax (numIn, numOut), (int) numSamples);
  683. const ScopedLock sl (juceFilter->getCallbackLock());
  684. if (juceFilter->isSuspended())
  685. {
  686. for (int j = 0; j < numOut; ++j)
  687. zeromem (channels [j], sizeof (float) * numSamples);
  688. }
  689. #if ! JucePlugin_IsSynth
  690. else if (ShouldBypassEffect())
  691. {
  692. juceFilter->processBlockBypassed (buffer, midiEvents);
  693. }
  694. #endif
  695. else
  696. {
  697. juceFilter->processBlock (buffer, midiEvents);
  698. }
  699. }
  700. if (! midiEvents.isEmpty())
  701. {
  702. #if JucePlugin_ProducesMidiOutput
  703. if (midiCallback.midiOutputCallback != nullptr)
  704. {
  705. UInt32 numPackets = 0;
  706. size_t dataSize = 0;
  707. const juce::uint8* midiEventData;
  708. int midiEventSize, midiEventPosition;
  709. for (MidiBuffer::Iterator i (midiEvents); i.getNextEvent (midiEventData, midiEventSize, midiEventPosition);)
  710. {
  711. jassert (isPositiveAndBelow (midiEventPosition, (int) numSamples));
  712. dataSize += (size_t) midiEventSize;
  713. ++numPackets;
  714. }
  715. MIDIPacket* p;
  716. const size_t packetMembersSize = sizeof (MIDIPacket) - sizeof (p->data); // NB: GCC chokes on "sizeof (MidiMessage::data)"
  717. const size_t packetListMembersSize = sizeof (MIDIPacketList) - sizeof (p->data);
  718. HeapBlock<MIDIPacketList> packetList;
  719. packetList.malloc (packetListMembersSize + packetMembersSize * numPackets + dataSize, 1);
  720. packetList->numPackets = numPackets;
  721. p = packetList->packet;
  722. for (MidiBuffer::Iterator i (midiEvents); i.getNextEvent (midiEventData, midiEventSize, midiEventPosition);)
  723. {
  724. p->timeStamp = (MIDITimeStamp) midiEventPosition;
  725. p->length = (UInt16) midiEventSize;
  726. memcpy (p->data, midiEventData, (size_t) midiEventSize);
  727. p = MIDIPacketNext (p);
  728. }
  729. midiCallback.midiOutputCallback (midiCallback.userData, &lastTimeStamp, 0, packetList);
  730. }
  731. #endif
  732. midiEvents.clear();
  733. }
  734. if (needToReinterleave)
  735. {
  736. nextSpareBufferChan = 0;
  737. for (unsigned int i = 0; i < outBuffer.mNumberBuffers; ++i)
  738. {
  739. AudioBuffer& buf = outBuffer.mBuffers[i];
  740. if (buf.mNumberChannels > 1)
  741. {
  742. for (unsigned int subChan = 0; subChan < buf.mNumberChannels; ++subChan)
  743. {
  744. const float* src = bufferSpace.getSampleData (nextSpareBufferChan++);
  745. float* dest = ((float*) buf.mData) + subChan;
  746. for (int j = (int) numSamples; --j >= 0;)
  747. {
  748. *dest = *src++;
  749. dest += buf.mNumberChannels;
  750. }
  751. }
  752. }
  753. }
  754. }
  755. #if ! JucePlugin_SilenceInProducesSilenceOut
  756. ioActionFlags &= (AudioUnitRenderActionFlags) ~kAudioUnitRenderAction_OutputIsSilence;
  757. #endif
  758. }
  759. return noErr;
  760. }
  761. OSStatus HandleMidiEvent (UInt8 nStatus, UInt8 inChannel, UInt8 inData1, UInt8 inData2, UInt32 inStartFrame) override
  762. {
  763. #if JucePlugin_WantsMidiInput
  764. const ScopedLock sl (incomingMidiLock);
  765. const juce::uint8 data[] = { (juce::uint8) (nStatus | inChannel),
  766. (juce::uint8) inData1,
  767. (juce::uint8) inData2 };
  768. incomingEvents.addEvent (data, 3, (int) inStartFrame);
  769. return noErr;
  770. #else
  771. return kAudioUnitErr_PropertyNotInUse;
  772. #endif
  773. }
  774. OSStatus HandleSysEx (const UInt8* inData, UInt32 inLength) override
  775. {
  776. #if JucePlugin_WantsMidiInput
  777. const ScopedLock sl (incomingMidiLock);
  778. incomingEvents.addEvent (inData, (int) inLength, 0);
  779. return noErr;
  780. #else
  781. return kAudioUnitErr_PropertyNotInUse;
  782. #endif
  783. }
  784. //==============================================================================
  785. ComponentResult GetPresets (CFArrayRef* outData) const override
  786. {
  787. if (outData != nullptr)
  788. {
  789. const int numPrograms = juceFilter->getNumPrograms();
  790. clearPresetsArray();
  791. presetsArray.insertMultiple (0, AUPreset(), numPrograms);
  792. CFMutableArrayRef presetsArrayRef = CFArrayCreateMutable (0, numPrograms, 0);
  793. for (int i = 0; i < numPrograms; ++i)
  794. {
  795. String name (juceFilter->getProgramName(i));
  796. if (name.isEmpty())
  797. name = "Untitled";
  798. AUPreset& p = presetsArray.getReference(i);
  799. p.presetNumber = i;
  800. p.presetName = name.toCFString();
  801. CFArrayAppendValue (presetsArrayRef, &p);
  802. }
  803. *outData = (CFArrayRef) presetsArrayRef;
  804. }
  805. return noErr;
  806. }
  807. OSStatus NewFactoryPresetSet (const AUPreset& inNewFactoryPreset) override
  808. {
  809. const int numPrograms = juceFilter->getNumPrograms();
  810. const SInt32 chosenPresetNumber = (int) inNewFactoryPreset.presetNumber;
  811. if (chosenPresetNumber >= numPrograms)
  812. return kAudioUnitErr_InvalidProperty;
  813. AUPreset chosenPreset;
  814. chosenPreset.presetNumber = chosenPresetNumber;
  815. chosenPreset.presetName = juceFilter->getProgramName (chosenPresetNumber).toCFString();
  816. juceFilter->setCurrentProgram (chosenPresetNumber);
  817. SetAFactoryPresetAsCurrent (chosenPreset);
  818. return noErr;
  819. }
  820. void componentMovedOrResized (Component& component, bool /*wasMoved*/, bool /*wasResized*/) override
  821. {
  822. NSView* view = (NSView*) component.getWindowHandle();
  823. NSRect r = [[view superview] frame];
  824. r.origin.y = r.origin.y + r.size.height - component.getHeight();
  825. r.size.width = component.getWidth();
  826. r.size.height = component.getHeight();
  827. [[view superview] setFrame: r];
  828. [view setFrame: makeNSRect (component.getLocalBounds())];
  829. [view setNeedsDisplay: YES];
  830. }
  831. //==============================================================================
  832. class EditorCompHolder : public Component
  833. {
  834. public:
  835. EditorCompHolder (AudioProcessorEditor* const editor)
  836. {
  837. setSize (editor->getWidth(), editor->getHeight());
  838. addAndMakeVisible (editor);
  839. #if ! JucePlugin_EditorRequiresKeyboardFocus
  840. setWantsKeyboardFocus (false);
  841. #else
  842. setWantsKeyboardFocus (true);
  843. #endif
  844. }
  845. ~EditorCompHolder()
  846. {
  847. deleteAllChildren(); // note that we can't use a ScopedPointer because the editor may
  848. // have been transferred to another parent which takes over ownership.
  849. }
  850. static NSView* createViewFor (AudioProcessor* filter, JuceAU* au, AudioProcessorEditor* const editor)
  851. {
  852. EditorCompHolder* editorCompHolder = new EditorCompHolder (editor);
  853. NSRect r = makeNSRect (editorCompHolder->getLocalBounds());
  854. static JuceUIViewClass cls;
  855. NSView* view = [[cls.createInstance() initWithFrame: r] autorelease];
  856. JuceUIViewClass::setFilter (view, filter);
  857. JuceUIViewClass::setAU (view, au);
  858. JuceUIViewClass::setEditor (view, editorCompHolder);
  859. [view setHidden: NO];
  860. [view setPostsFrameChangedNotifications: YES];
  861. [[NSNotificationCenter defaultCenter] addObserver: view
  862. selector: @selector (applicationWillTerminate:)
  863. name: NSApplicationWillTerminateNotification
  864. object: nil];
  865. activeUIs.add (view);
  866. editorCompHolder->addToDesktop (0, (void*) view);
  867. editorCompHolder->setVisible (view);
  868. return view;
  869. }
  870. void childBoundsChanged (Component*) override
  871. {
  872. if (Component* editor = getChildComponent(0))
  873. {
  874. const int w = jmax (32, editor->getWidth());
  875. const int h = jmax (32, editor->getHeight());
  876. if (getWidth() != w || getHeight() != h)
  877. setSize (w, h);
  878. NSView* view = (NSView*) getWindowHandle();
  879. NSRect r = [[view superview] frame];
  880. r.size.width = editor->getWidth();
  881. r.size.height = editor->getHeight();
  882. [[view superview] setFrame: r];
  883. [view setFrame: makeNSRect (editor->getLocalBounds())];
  884. [view setNeedsDisplay: YES];
  885. }
  886. }
  887. bool keyPressed (const KeyPress&) override
  888. {
  889. if (PluginHostType().isAbletonLive())
  890. {
  891. static NSTimeInterval lastEventTime = 0; // check we're not recursively sending the same event
  892. NSTimeInterval eventTime = [[NSApp currentEvent] timestamp];
  893. if (lastEventTime != eventTime)
  894. {
  895. lastEventTime = eventTime;
  896. NSView* view = (NSView*) getWindowHandle();
  897. NSView* hostView = [view superview];
  898. NSWindow* hostWindow = [hostView window];
  899. [hostWindow makeFirstResponder: hostView];
  900. [hostView keyDown: [NSApp currentEvent]];
  901. [hostWindow makeFirstResponder: view];
  902. }
  903. }
  904. return false;
  905. }
  906. private:
  907. JUCE_DECLARE_NON_COPYABLE (EditorCompHolder)
  908. };
  909. //==============================================================================
  910. struct JuceUIViewClass : public ObjCClass <NSView>
  911. {
  912. JuceUIViewClass() : ObjCClass <NSView> ("JUCEAUView_")
  913. {
  914. addIvar<AudioProcessor*> ("filter");
  915. addIvar<JuceAU*> ("au");
  916. addIvar<EditorCompHolder*> ("editor");
  917. addMethod (@selector (dealloc), dealloc, "v@:");
  918. addMethod (@selector (applicationWillTerminate:), applicationWillTerminate, "v@:@");
  919. addMethod (@selector (viewDidMoveToWindow), viewDidMoveToWindow, "v@:");
  920. addMethod (@selector (mouseDownCanMoveWindow), mouseDownCanMoveWindow, "c@:");
  921. registerClass();
  922. }
  923. static void deleteEditor (id self)
  924. {
  925. ScopedPointer<EditorCompHolder> editorComp (getEditor (self));
  926. if (editorComp != nullptr)
  927. {
  928. if (editorComp->getChildComponent(0) != nullptr
  929. && activePlugins.contains (getAU (self))) // plugin may have been deleted before the UI
  930. {
  931. AudioProcessor* const filter = getIvar<AudioProcessor*> (self, "filter");
  932. filter->editorBeingDeleted ((AudioProcessorEditor*) editorComp->getChildComponent(0));
  933. }
  934. editorComp = nullptr;
  935. setEditor (self, nullptr);
  936. }
  937. }
  938. static JuceAU* getAU (id self) { return getIvar<JuceAU*> (self, "au"); }
  939. static EditorCompHolder* getEditor (id self) { return getIvar<EditorCompHolder*> (self, "editor"); }
  940. static void setFilter (id self, AudioProcessor* filter) { object_setInstanceVariable (self, "filter", filter); }
  941. static void setAU (id self, JuceAU* au) { object_setInstanceVariable (self, "au", au); }
  942. static void setEditor (id self, EditorCompHolder* e) { object_setInstanceVariable (self, "editor", e); }
  943. private:
  944. static void dealloc (id self, SEL)
  945. {
  946. if (activeUIs.contains (self))
  947. shutdown (self);
  948. sendSuperclassMessage (self, @selector (dealloc));
  949. }
  950. static void applicationWillTerminate (id self, SEL, NSNotification*)
  951. {
  952. shutdown (self);
  953. }
  954. static void shutdown (id self)
  955. {
  956. // there's some kind of component currently modal, but the host
  957. // is trying to delete our plugin..
  958. jassert (Component::getCurrentlyModalComponent() == nullptr);
  959. [[NSNotificationCenter defaultCenter] removeObserver: self];
  960. deleteEditor (self);
  961. jassert (activeUIs.contains (self));
  962. activeUIs.removeFirstMatchingValue (self);
  963. if (activePlugins.size() + activeUIs.size() == 0)
  964. shutdownJuce_GUI();
  965. }
  966. static void viewDidMoveToWindow (id self, SEL)
  967. {
  968. if (NSWindow* w = [(NSView*) self window])
  969. {
  970. [w setAcceptsMouseMovedEvents: YES];
  971. if (EditorCompHolder* const editorComp = getEditor (self))
  972. [w makeFirstResponder: (NSView*) editorComp->getWindowHandle()];
  973. }
  974. }
  975. static BOOL mouseDownCanMoveWindow (id, SEL)
  976. {
  977. return NO;
  978. }
  979. };
  980. //==============================================================================
  981. struct JuceUICreationClass : public ObjCClass <NSObject>
  982. {
  983. JuceUICreationClass() : ObjCClass <NSObject> ("JUCE_AUCocoaViewClass_")
  984. {
  985. addMethod (@selector (interfaceVersion), interfaceVersion, @encode (unsigned int), "@:");
  986. addMethod (@selector (description), description, @encode (NSString*), "@:");
  987. addMethod (@selector (uiViewForAudioUnit:withSize:), uiViewForAudioUnit, @encode (NSView*), "@:", @encode (AudioUnit), @encode (NSSize));
  988. addProtocol (@protocol (AUCocoaUIBase));
  989. registerClass();
  990. }
  991. private:
  992. static unsigned int interfaceVersion (id, SEL) { return 0; }
  993. static NSString* description (id, SEL)
  994. {
  995. return [NSString stringWithString: nsStringLiteral (JucePlugin_Name)];
  996. }
  997. static NSView* uiViewForAudioUnit (id, SEL, AudioUnit inAudioUnit, NSSize)
  998. {
  999. void* pointers[2];
  1000. UInt32 propertySize = sizeof (pointers);
  1001. if (AudioUnitGetProperty (inAudioUnit, juceFilterObjectPropertyID,
  1002. kAudioUnitScope_Global, 0, pointers, &propertySize) == noErr)
  1003. {
  1004. if (AudioProcessor* filter = static_cast <AudioProcessor*> (pointers[0]))
  1005. if (AudioProcessorEditor* editorComp = filter->createEditorIfNeeded())
  1006. return EditorCompHolder::createViewFor (filter, static_cast <JuceAU*> (pointers[1]), editorComp);
  1007. }
  1008. return nil;
  1009. }
  1010. };
  1011. private:
  1012. //==============================================================================
  1013. ScopedPointer<AudioProcessor> juceFilter;
  1014. AudioSampleBuffer bufferSpace;
  1015. HeapBlock <float*> channels;
  1016. MidiBuffer midiEvents, incomingEvents;
  1017. bool prepared;
  1018. AUChannelInfo channelInfo [numChannelConfigs];
  1019. AudioUnitEvent auEvent;
  1020. mutable Array<AUPreset> presetsArray;
  1021. CriticalSection incomingMidiLock;
  1022. AUMIDIOutputCallbackStruct midiCallback;
  1023. AudioTimeStamp lastTimeStamp;
  1024. void clearPresetsArray() const
  1025. {
  1026. for (int i = presetsArray.size(); --i >= 0;)
  1027. CFRelease (presetsArray.getReference(i).presetName);
  1028. presetsArray.clear();
  1029. }
  1030. JUCE_DECLARE_NON_COPYABLE (JuceAU)
  1031. };
  1032. //==============================================================================
  1033. #if BUILD_AU_CARBON_UI
  1034. class JuceAUView : public AUCarbonViewBase
  1035. {
  1036. public:
  1037. JuceAUView (AudioUnitCarbonView auview)
  1038. : AUCarbonViewBase (auview),
  1039. juceFilter (nullptr)
  1040. {
  1041. }
  1042. ~JuceAUView()
  1043. {
  1044. deleteUI();
  1045. }
  1046. ComponentResult CreateUI (Float32 /*inXOffset*/, Float32 /*inYOffset*/) override
  1047. {
  1048. JUCE_AUTORELEASEPOOL
  1049. {
  1050. if (juceFilter == nullptr)
  1051. {
  1052. void* pointers[2];
  1053. UInt32 propertySize = sizeof (pointers);
  1054. AudioUnitGetProperty (GetEditAudioUnit(),
  1055. juceFilterObjectPropertyID,
  1056. kAudioUnitScope_Global,
  1057. 0,
  1058. pointers,
  1059. &propertySize);
  1060. juceFilter = (AudioProcessor*) pointers[0];
  1061. }
  1062. if (juceFilter != nullptr)
  1063. {
  1064. deleteUI();
  1065. if (AudioProcessorEditor* editorComp = juceFilter->createEditorIfNeeded())
  1066. {
  1067. editorComp->setOpaque (true);
  1068. windowComp = new ComponentInHIView (editorComp, mCarbonPane);
  1069. }
  1070. }
  1071. else
  1072. {
  1073. jassertfalse // can't get a pointer to our effect
  1074. }
  1075. }
  1076. return noErr;
  1077. }
  1078. AudioUnitCarbonViewEventListener getEventListener() const { return mEventListener; }
  1079. void* getEventListenerUserData() const { return mEventListenerUserData; }
  1080. private:
  1081. //==============================================================================
  1082. AudioProcessor* juceFilter;
  1083. ScopedPointer<Component> windowComp;
  1084. FakeMouseMoveGenerator fakeMouseGenerator;
  1085. void deleteUI()
  1086. {
  1087. if (windowComp != nullptr)
  1088. {
  1089. PopupMenu::dismissAllActiveMenus();
  1090. /* This assertion is triggered when there's some kind of modal component active, and the
  1091. host is trying to delete our plugin.
  1092. If you must use modal components, always use them in a non-blocking way, by never
  1093. calling runModalLoop(), but instead using enterModalState() with a callback that
  1094. will be performed on completion. (Note that this assertion could actually trigger
  1095. a false alarm even if you're doing it correctly, but is here to catch people who
  1096. aren't so careful) */
  1097. jassert (Component::getCurrentlyModalComponent() == nullptr);
  1098. if (JuceAU::EditorCompHolder* editorCompHolder = dynamic_cast <JuceAU::EditorCompHolder*> (windowComp->getChildComponent(0)))
  1099. if (AudioProcessorEditor* audioProcessEditor = dynamic_cast <AudioProcessorEditor*> (editorCompHolder->getChildComponent(0)))
  1100. juceFilter->editorBeingDeleted (audioProcessEditor);
  1101. windowComp = nullptr;
  1102. }
  1103. }
  1104. //==============================================================================
  1105. // Uses a child NSWindow to sit in front of a HIView and display our component
  1106. class ComponentInHIView : public Component
  1107. {
  1108. public:
  1109. ComponentInHIView (AudioProcessorEditor* ed, HIViewRef parentHIView)
  1110. : parentView (parentHIView),
  1111. editor (ed),
  1112. recursive (false)
  1113. {
  1114. JUCE_AUTORELEASEPOOL
  1115. {
  1116. jassert (ed != nullptr);
  1117. addAndMakeVisible (editor);
  1118. setOpaque (true);
  1119. setVisible (true);
  1120. setBroughtToFrontOnMouseClick (true);
  1121. setSize (editor.getWidth(), editor.getHeight());
  1122. SizeControl (parentHIView, (SInt16) editor.getWidth(), (SInt16) editor.getHeight());
  1123. WindowRef windowRef = HIViewGetWindow (parentHIView);
  1124. hostWindow = [[NSWindow alloc] initWithWindowRef: windowRef];
  1125. [hostWindow retain];
  1126. [hostWindow setCanHide: YES];
  1127. [hostWindow setReleasedWhenClosed: YES];
  1128. updateWindowPos();
  1129. #if ! JucePlugin_EditorRequiresKeyboardFocus
  1130. addToDesktop (ComponentPeer::windowIsTemporary | ComponentPeer::windowIgnoresKeyPresses);
  1131. setWantsKeyboardFocus (false);
  1132. #else
  1133. addToDesktop (ComponentPeer::windowIsTemporary);
  1134. setWantsKeyboardFocus (true);
  1135. #endif
  1136. setVisible (true);
  1137. toFront (false);
  1138. addSubWindow();
  1139. NSWindow* pluginWindow = [((NSView*) getWindowHandle()) window];
  1140. [pluginWindow setNextResponder: hostWindow];
  1141. attachWindowHidingHooks (this, (WindowRef) windowRef, hostWindow);
  1142. }
  1143. }
  1144. ~ComponentInHIView()
  1145. {
  1146. JUCE_AUTORELEASEPOOL
  1147. {
  1148. removeWindowHidingHooks (this);
  1149. NSWindow* pluginWindow = [((NSView*) getWindowHandle()) window];
  1150. [hostWindow removeChildWindow: pluginWindow];
  1151. removeFromDesktop();
  1152. [hostWindow release];
  1153. hostWindow = nil;
  1154. }
  1155. }
  1156. void updateWindowPos()
  1157. {
  1158. HIPoint f;
  1159. f.x = f.y = 0;
  1160. HIPointConvert (&f, kHICoordSpaceView, parentView, kHICoordSpaceScreenPixel, 0);
  1161. setTopLeftPosition ((int) f.x, (int) f.y);
  1162. }
  1163. void addSubWindow()
  1164. {
  1165. NSWindow* pluginWindow = [((NSView*) getWindowHandle()) window];
  1166. [pluginWindow setExcludedFromWindowsMenu: YES];
  1167. [pluginWindow setCanHide: YES];
  1168. [hostWindow addChildWindow: pluginWindow
  1169. ordered: NSWindowAbove];
  1170. [hostWindow orderFront: nil];
  1171. [pluginWindow orderFront: nil];
  1172. }
  1173. void resized() override
  1174. {
  1175. if (Component* const child = getChildComponent (0))
  1176. child->setBounds (getLocalBounds());
  1177. }
  1178. void paint (Graphics&) override {}
  1179. void childBoundsChanged (Component*) override
  1180. {
  1181. if (! recursive)
  1182. {
  1183. recursive = true;
  1184. const int w = jmax (32, editor.getWidth());
  1185. const int h = jmax (32, editor.getHeight());
  1186. SizeControl (parentView, (SInt16) w, (SInt16) h);
  1187. if (getWidth() != w || getHeight() != h)
  1188. setSize (w, h);
  1189. editor.repaint();
  1190. updateWindowPos();
  1191. addSubWindow(); // (need this for AULab)
  1192. recursive = false;
  1193. }
  1194. }
  1195. bool keyPressed (const KeyPress& kp) override
  1196. {
  1197. if (! kp.getModifiers().isCommandDown())
  1198. {
  1199. // If we have an unused keypress, move the key-focus to a host window
  1200. // and re-inject the event..
  1201. static NSTimeInterval lastEventTime = 0; // check we're not recursively sending the same event
  1202. NSTimeInterval eventTime = [[NSApp currentEvent] timestamp];
  1203. if (lastEventTime != eventTime)
  1204. {
  1205. lastEventTime = eventTime;
  1206. [[hostWindow parentWindow] makeKeyWindow];
  1207. repostCurrentNSEvent();
  1208. }
  1209. }
  1210. return false;
  1211. }
  1212. private:
  1213. HIViewRef parentView;
  1214. NSWindow* hostWindow;
  1215. JuceAU::EditorCompHolder editor;
  1216. bool recursive;
  1217. };
  1218. };
  1219. #endif
  1220. //==============================================================================
  1221. #define JUCE_COMPONENT_ENTRYX(Class, Name, Suffix) \
  1222. extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj); \
  1223. extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj) \
  1224. { \
  1225. return ComponentEntryPoint<Class>::Dispatch (params, obj); \
  1226. }
  1227. #if JucePlugin_ProducesMidiOutput || JucePlugin_WantsMidiInput
  1228. #define FACTORY_BASE_CLASS AUMIDIEffectFactory
  1229. #else
  1230. #define FACTORY_BASE_CLASS AUBaseFactory
  1231. #endif
  1232. #define JUCE_FACTORY_ENTRYX(Class, Name) \
  1233. extern "C" __attribute__((visibility("default"))) void* Name ## Factory (const AudioComponentDescription* desc); \
  1234. extern "C" __attribute__((visibility("default"))) void* Name ## Factory (const AudioComponentDescription* desc) \
  1235. { \
  1236. return FACTORY_BASE_CLASS<Class>::Factory (desc); \
  1237. }
  1238. #define JUCE_COMPONENT_ENTRY(Class, Name, Suffix) JUCE_COMPONENT_ENTRYX(Class, Name, Suffix)
  1239. #define JUCE_FACTORY_ENTRY(Class, Name) JUCE_FACTORY_ENTRYX(Class, Name)
  1240. //==============================================================================
  1241. JUCE_COMPONENT_ENTRY (JuceAU, JucePlugin_AUExportPrefix, Entry)
  1242. #ifndef AUDIOCOMPONENT_ENTRY
  1243. #define JUCE_DISABLE_AU_FACTORY_ENTRY 1
  1244. #endif
  1245. #if ! JUCE_DISABLE_AU_FACTORY_ENTRY // (You might need to disable this for old Xcode 3 builds)
  1246. JUCE_FACTORY_ENTRY (JuceAU, JucePlugin_AUExportPrefix)
  1247. #endif
  1248. #if BUILD_AU_CARBON_UI
  1249. JUCE_COMPONENT_ENTRY (JuceAUView, JucePlugin_AUExportPrefix, ViewEntry)
  1250. #endif
  1251. #if ! JUCE_DISABLE_AU_FACTORY_ENTRY
  1252. #include "AUPlugInDispatch.cpp"
  1253. #endif
  1254. #endif