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.

945 lines
31KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include <AudioUnit/AudioUnit.h>
  24. #include "AUMIDIEffectBase.h"
  25. #include "MusicDeviceBase.h"
  26. #include "AUCarbonViewBase.h"
  27. #include "../../juce_AudioFilterBase.h"
  28. #include "../../juce_IncludeCharacteristics.h"
  29. //==============================================================================
  30. #define juceFilterObjectPropertyID 0x1a45ffe9
  31. static VoidArray activePlugins;
  32. static const short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations };
  33. static const int numChannelConfigs = numElementsInArray (channelConfigs);
  34. BEGIN_JUCE_NAMESPACE
  35. extern void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw();
  36. END_JUCE_NAMESPACE
  37. #if JucePlugin_IsSynth
  38. #define JuceAUBaseClass MusicDeviceBase
  39. #else
  40. #define JuceAUBaseClass AUMIDIEffectBase
  41. #endif
  42. //==============================================================================
  43. class JuceAU : public JuceAUBaseClass,
  44. public AudioFilterBase::HostCallbacks
  45. {
  46. public:
  47. //==============================================================================
  48. JuceAU (AudioUnit component)
  49. #if JucePlugin_IsSynth
  50. : MusicDeviceBase (component, 0, 1),
  51. #else
  52. : AUMIDIEffectBase (component),
  53. #endif
  54. juceFilter (0),
  55. bufferSpace (2, 16),
  56. channels (0),
  57. prepared (false)
  58. {
  59. CreateElements();
  60. if (activePlugins.size() == 0)
  61. {
  62. initialiseJuce_GUI();
  63. #ifdef JucePlugin_CFBundleIdentifier
  64. juce_setCurrentExecutableFileNameFromBundleId (JucePlugin_CFBundleIdentifier);
  65. #endif
  66. MessageManager::getInstance()->setTimeBeforeShowingWaitCursor (0);
  67. }
  68. juceFilter = createPluginFilter();
  69. juceFilter->setHostCallbacks (this);
  70. jassert (juceFilter != 0);
  71. Globals()->UseIndexedParameters (juceFilter->getNumParameters());
  72. activePlugins.add (this);
  73. zerostruct (auEvent);
  74. auEvent.mArgument.mParameter.mAudioUnit = GetComponentInstance();
  75. auEvent.mArgument.mParameter.mScope = kAudioUnitScope_Global;
  76. auEvent.mArgument.mParameter.mElement = 0;
  77. }
  78. ~JuceAU()
  79. {
  80. delete juceFilter;
  81. juceFilter = 0;
  82. juce_free (channels);
  83. channels = 0;
  84. jassert (activePlugins.contains (this));
  85. activePlugins.removeValue (this);
  86. if (activePlugins.size() == 0)
  87. shutdownJuce_GUI();
  88. }
  89. //==============================================================================
  90. ComponentResult GetPropertyInfo (AudioUnitPropertyID inID,
  91. AudioUnitScope inScope,
  92. AudioUnitElement inElement,
  93. UInt32& outDataSize,
  94. Boolean& outWritable)
  95. {
  96. if (inScope == kAudioUnitScope_Global)
  97. {
  98. if (inID == juceFilterObjectPropertyID)
  99. {
  100. outWritable = false;
  101. outDataSize = sizeof (void*);
  102. return noErr;
  103. }
  104. }
  105. return JuceAUBaseClass::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
  106. }
  107. ComponentResult GetProperty (AudioUnitPropertyID inID,
  108. AudioUnitScope inScope,
  109. AudioUnitElement inElement,
  110. void* outData)
  111. {
  112. if (inScope == kAudioUnitScope_Global)
  113. {
  114. if (inID == juceFilterObjectPropertyID)
  115. {
  116. *((void**) outData) = (void*) juceFilter;
  117. return noErr;
  118. }
  119. }
  120. return JuceAUBaseClass::GetProperty (inID, inScope, inElement, outData);
  121. }
  122. ComponentResult SaveState (CFPropertyListRef* outData)
  123. {
  124. ComponentResult err = JuceAUBaseClass::SaveState (outData);
  125. if (err != noErr)
  126. return err;
  127. jassert (CFGetTypeID (*outData) == CFDictionaryGetTypeID());
  128. CFMutableDictionaryRef dict = (CFMutableDictionaryRef) *outData;
  129. if (juceFilter != 0)
  130. {
  131. JUCE_NAMESPACE::MemoryBlock state;
  132. juceFilter->getStateInformation (state);
  133. if (state.getSize() > 0)
  134. {
  135. CFDataRef ourState = CFDataCreate (kCFAllocatorDefault, (const uint8*) state, state.getSize());
  136. CFDictionarySetValue (dict, CFSTR("jucePluginState"), ourState);
  137. CFRelease (ourState);
  138. }
  139. }
  140. return noErr;
  141. }
  142. ComponentResult RestoreState (CFPropertyListRef inData)
  143. {
  144. ComponentResult err = JuceAUBaseClass::RestoreState (inData);
  145. if (err != noErr)
  146. return err;
  147. if (juceFilter != 0)
  148. {
  149. CFDictionaryRef dict = (CFDictionaryRef) inData;
  150. CFDataRef data = 0;
  151. if (CFDictionaryGetValueIfPresent (dict, CFSTR("jucePluginState"),
  152. (const void**) &data))
  153. {
  154. if (data != 0)
  155. {
  156. const int numBytes = (int) CFDataGetLength (data);
  157. const uint8* const rawBytes = CFDataGetBytePtr (data);
  158. if (numBytes > 0)
  159. juceFilter->setStateInformation (rawBytes, numBytes);
  160. }
  161. }
  162. }
  163. return noErr;
  164. }
  165. UInt32 SupportedNumChannels (const AUChannelInfo** outInfo)
  166. {
  167. // You need to actually add some configurations to the JucePlugin_PreferredChannelConfigurations
  168. // value in your JucePluginCharacteristics.h file..
  169. jassert (numChannelConfigs > 0);
  170. if (outInfo != 0)
  171. {
  172. for (int i = 0; i < numChannelConfigs; ++i)
  173. {
  174. #if JucePlugin_IsSynth
  175. channelInfo[i].inChannels = 0;
  176. #else
  177. channelInfo[i].inChannels = channelConfigs[i][0];
  178. #endif
  179. channelInfo[i].outChannels = channelConfigs[i][1];
  180. outInfo[i] = channelInfo + i;
  181. }
  182. }
  183. return numChannelConfigs;
  184. }
  185. //==============================================================================
  186. ComponentResult GetParameterInfo (AudioUnitScope inScope,
  187. AudioUnitParameterID inParameterID,
  188. AudioUnitParameterInfo& outParameterInfo)
  189. {
  190. const int index = (int) inParameterID;
  191. if (inScope == kAudioUnitScope_Global
  192. && juceFilter != 0
  193. && index < juceFilter->getNumParameters())
  194. {
  195. outParameterInfo.flags = kAudioUnitParameterFlag_IsWritable
  196. | kAudioUnitParameterFlag_IsReadable
  197. | kAudioUnitParameterFlag_HasCFNameString;
  198. const String name (juceFilter->getParameterName (index));
  199. // set whether the param is automatable (unnamed parameters aren't allowed to be automated)
  200. if (name.isEmpty() || ! juceFilter->isParameterAutomatable (index))
  201. outParameterInfo.flags |= kAudioUnitParameterFlag_NonRealTime;
  202. AUBase::FillInParameterName (outParameterInfo,
  203. PlatformUtilities::juceStringToCFString (name),
  204. false);
  205. outParameterInfo.minValue = 0.0f;
  206. outParameterInfo.maxValue = 1.0f;
  207. outParameterInfo.defaultValue = 0.0f;
  208. outParameterInfo.unit = kAudioUnitParameterUnit_Generic;
  209. return noErr;
  210. }
  211. else
  212. {
  213. return kAudioUnitErr_InvalidParameter;
  214. }
  215. }
  216. ComponentResult GetParameter (AudioUnitParameterID inID,
  217. AudioUnitScope inScope,
  218. AudioUnitElement inElement,
  219. Float32& outValue)
  220. {
  221. if (inScope == kAudioUnitScope_Global && juceFilter != 0)
  222. {
  223. outValue = juceFilter->getParameter ((int) inID);
  224. return noErr;
  225. }
  226. return AUBase::GetParameter (inID, inScope, inElement, outValue);
  227. }
  228. ComponentResult SetParameter (AudioUnitParameterID inID,
  229. AudioUnitScope inScope,
  230. AudioUnitElement inElement,
  231. Float32 inValue,
  232. UInt32 inBufferOffsetInFrames)
  233. {
  234. if (inScope == kAudioUnitScope_Global && juceFilter != 0)
  235. {
  236. juceFilter->setParameter ((int) inID, inValue);
  237. return noErr;
  238. }
  239. return AUBase::SetParameter (inID, inScope, inElement, inValue, inBufferOffsetInFrames);
  240. }
  241. //==============================================================================
  242. ComponentResult Version() { return JucePlugin_VersionCode; }
  243. bool SupportsTail() { return true; }
  244. Float64 GetTailTime() { return 0; }
  245. Float64 GetSampleRate()
  246. {
  247. return GetOutput(0)->GetStreamFormat().mSampleRate;
  248. }
  249. Float64 GetLatency()
  250. {
  251. jassert (GetSampleRate() > 0);
  252. if (GetSampleRate() <= 0)
  253. return 0.0;
  254. return juceFilter->getLatencySamples() / GetSampleRate();
  255. }
  256. //==============================================================================
  257. int GetNumCustomUIComponents() { return 1; }
  258. void GetUIComponentDescs (ComponentDescription* inDescArray)
  259. {
  260. inDescArray[0].componentType = kAudioUnitCarbonViewComponentType;
  261. inDescArray[0].componentSubType = JucePlugin_AUSubType;
  262. inDescArray[0].componentManufacturer = JucePlugin_AUManufacturerCode;
  263. inDescArray[0].componentFlags = 0;
  264. inDescArray[0].componentFlagsMask = 0;
  265. }
  266. //==============================================================================
  267. bool getCurrentPositionInfo (AudioFilterBase::CurrentPositionInfo& info)
  268. {
  269. info.timeSigNumerator = 0;
  270. info.timeSigDenominator = 0;
  271. info.timeInSeconds = 0;
  272. info.editOriginTime = 0;
  273. info.ppqPositionOfLastBarStart = 0;
  274. info.isPlaying = false;
  275. info.isRecording = false;
  276. switch (lastSMPTETime.mType)
  277. {
  278. case kSMPTETimeType24:
  279. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps24;
  280. break;
  281. case kSMPTETimeType25:
  282. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps25;
  283. break;
  284. case kSMPTETimeType30Drop:
  285. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps30drop;
  286. break;
  287. case kSMPTETimeType30:
  288. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps30;
  289. break;
  290. case kSMPTETimeType2997:
  291. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps2997;
  292. break;
  293. case kSMPTETimeType2997Drop:
  294. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps2997drop;
  295. break;
  296. //case kSMPTETimeType60:
  297. //case kSMPTETimeType5994:
  298. default:
  299. info.frameRate = AudioFilterBase::CurrentPositionInfo::fpsUnknown;
  300. break;
  301. }
  302. if (CallHostBeatAndTempo (&info.ppqPosition, &info.bpm) != noErr)
  303. {
  304. info.ppqPosition = 0;
  305. info.bpm = 0;
  306. }
  307. UInt32 outDeltaSampleOffsetToNextBeat;
  308. double outCurrentMeasureDownBeat;
  309. float num;
  310. UInt32 den;
  311. if (CallHostMusicalTimeLocation (&outDeltaSampleOffsetToNextBeat, &num, &den,
  312. &outCurrentMeasureDownBeat) == noErr)
  313. {
  314. info.timeSigNumerator = (int) num;
  315. info.timeSigDenominator = den;
  316. info.ppqPositionOfLastBarStart = outCurrentMeasureDownBeat;
  317. }
  318. double outCurrentSampleInTimeLine, outCycleStartBeat, outCycleEndBeat;
  319. Boolean playing, playchanged, looping;
  320. if (CallHostTransportState (&playing,
  321. &playchanged,
  322. &outCurrentSampleInTimeLine,
  323. &looping,
  324. &outCycleStartBeat,
  325. &outCycleEndBeat) == noErr)
  326. {
  327. info.isPlaying = playing;
  328. info.timeInSeconds = outCurrentSampleInTimeLine / GetSampleRate();
  329. }
  330. return true;
  331. }
  332. void sendAUEvent (const AudioUnitEventType type, const int index) throw()
  333. {
  334. if (AUEventListenerNotify != 0)
  335. {
  336. auEvent.mEventType = type;
  337. auEvent.mArgument.mParameter.mParameterID = (AudioUnitParameterID) index;
  338. AUEventListenerNotify (0, 0, &auEvent);
  339. }
  340. }
  341. void informHostOfParameterChange (int index, float newValue)
  342. {
  343. if (juceFilter != 0)
  344. {
  345. juceFilter->setParameter (index, newValue);
  346. sendAUEvent (kAudioUnitEvent_ParameterValueChange, index);
  347. }
  348. }
  349. void informHostOfParameterGestureBegin (int index)
  350. {
  351. if (juceFilter != 0)
  352. sendAUEvent (kAudioUnitEvent_BeginParameterChangeGesture, index);
  353. }
  354. void informHostOfParameterGestureEnd (int index)
  355. {
  356. if (juceFilter != 0)
  357. sendAUEvent (kAudioUnitEvent_EndParameterChangeGesture, index);
  358. }
  359. void informHostOfStateChange()
  360. {
  361. // xxx is there an AU equivalent?
  362. }
  363. bool StreamFormatWritable (AudioUnitScope inScope, AudioUnitElement element)
  364. {
  365. return ! IsInitialized();
  366. }
  367. ComponentResult StartNote (MusicDeviceInstrumentID, MusicDeviceGroupID, NoteInstanceID&, UInt32, const MusicDeviceNoteParams&)
  368. {
  369. return noErr;
  370. }
  371. ComponentResult StopNote (MusicDeviceGroupID, NoteInstanceID, UInt32)
  372. {
  373. return noErr;
  374. }
  375. //==============================================================================
  376. ComponentResult Initialize()
  377. {
  378. #if ! JucePlugin_IsSynth
  379. const int numIns = GetInput(0) != 0 ? GetInput(0)->GetStreamFormat().mChannelsPerFrame : 0;
  380. #endif
  381. const int numOuts = GetOutput(0) != 0 ? GetOutput(0)->GetStreamFormat().mChannelsPerFrame : 0;
  382. bool isValidChannelConfig = false;
  383. for (int i = 0; i < numChannelConfigs; ++i)
  384. #if JucePlugin_IsSynth
  385. if (numOuts == channelConfigs[i][1])
  386. #else
  387. if (numIns == channelConfigs[i][0] && numOuts == channelConfigs[i][1])
  388. #endif
  389. isValidChannelConfig = true;
  390. if (! isValidChannelConfig)
  391. return kAudioUnitErr_FormatNotSupported;
  392. JuceAUBaseClass::Initialize();
  393. prepareToPlay();
  394. return noErr;
  395. }
  396. void Cleanup()
  397. {
  398. JuceAUBaseClass::Cleanup();
  399. if (juceFilter != 0)
  400. juceFilter->releaseResources();
  401. bufferSpace.setSize (2, 16);
  402. midiEvents.clear();
  403. prepared = false;
  404. }
  405. ComponentResult Reset (AudioUnitScope inScope, AudioUnitElement inElement)
  406. {
  407. if (! prepared)
  408. prepareToPlay();
  409. return JuceAUBaseClass::Reset (inScope, inElement);
  410. }
  411. void prepareToPlay()
  412. {
  413. if (juceFilter != 0)
  414. {
  415. #if ! JucePlugin_IsSynth
  416. juceFilter->setPlayConfigDetails (GetInput(0)->GetStreamFormat().mChannelsPerFrame,
  417. #else
  418. juceFilter->setPlayConfigDetails (0,
  419. #endif
  420. GetOutput(0)->GetStreamFormat().mChannelsPerFrame,
  421. GetSampleRate(),
  422. GetMaxFramesPerSlice());
  423. bufferSpace.setSize (juceFilter->getNumInputChannels() + juceFilter->getNumOutputChannels(),
  424. GetMaxFramesPerSlice() + 32);
  425. juceFilter->prepareToPlay (GetSampleRate(),
  426. GetMaxFramesPerSlice());
  427. midiEvents.clear();
  428. juce_free (channels);
  429. channels = (float**) juce_calloc (sizeof (float*) * jmax (juceFilter->getNumInputChannels(),
  430. juceFilter->getNumOutputChannels()) + 4);
  431. prepared = true;
  432. }
  433. }
  434. ComponentResult Render (AudioUnitRenderActionFlags &ioActionFlags,
  435. const AudioTimeStamp& inTimeStamp,
  436. UInt32 nFrames)
  437. {
  438. lastSMPTETime = inTimeStamp.mSMPTETime;
  439. #if ! JucePlugin_IsSynth
  440. return JuceAUBaseClass::Render (ioActionFlags, inTimeStamp, nFrames);
  441. #else
  442. // synths can't have any inputs..
  443. AudioBufferList inBuffer;
  444. inBuffer.mNumberBuffers = 0;
  445. return ProcessBufferLists (ioActionFlags, inBuffer, GetOutput(0)->GetBufferList(), nFrames);
  446. #endif
  447. }
  448. OSStatus ProcessBufferLists (AudioUnitRenderActionFlags& ioActionFlags,
  449. const AudioBufferList& inBuffer,
  450. AudioBufferList& outBuffer,
  451. UInt32 numSamples)
  452. {
  453. if (juceFilter != 0)
  454. {
  455. jassert (prepared);
  456. int numOutChans = 0;
  457. int nextSpareBufferChan = 0;
  458. bool needToReinterleave = false;
  459. const int numIn = juceFilter->getNumInputChannels();
  460. const int numOut = juceFilter->getNumOutputChannels();
  461. unsigned int i;
  462. for (i = 0; i < outBuffer.mNumberBuffers; ++i)
  463. {
  464. AudioBuffer& buf = outBuffer.mBuffers[i];
  465. if (buf.mNumberChannels == 1)
  466. {
  467. channels [numOutChans++] = (float*) buf.mData;
  468. }
  469. else
  470. {
  471. needToReinterleave = true;
  472. for (unsigned int subChan = 0; subChan < buf.mNumberChannels && numOutChans < numOut; ++subChan)
  473. channels [numOutChans++] = bufferSpace.getSampleData (nextSpareBufferChan++);
  474. }
  475. if (numOutChans >= numOut)
  476. break;
  477. }
  478. int numInChans = 0;
  479. for (i = 0; i < inBuffer.mNumberBuffers; ++i)
  480. {
  481. const AudioBuffer& buf = inBuffer.mBuffers[i];
  482. if (buf.mNumberChannels == 1)
  483. {
  484. if (numInChans < numOut)
  485. memcpy (channels [numInChans], (const float*) buf.mData, sizeof (float) * numSamples);
  486. else
  487. channels [numInChans] = (float*) buf.mData;
  488. }
  489. else
  490. {
  491. // need to de-interleave..
  492. for (unsigned int subChan = 0; subChan < buf.mNumberChannels && numInChans < numIn; ++subChan)
  493. {
  494. float* dest;
  495. if (numInChans >= numOut)
  496. {
  497. dest = bufferSpace.getSampleData (nextSpareBufferChan++);
  498. channels [numInChans++] = dest;
  499. }
  500. else
  501. {
  502. dest = channels [numInChans++];
  503. }
  504. const float* src = ((const float*) buf.mData) + subChan;
  505. for (int j = numSamples; --j >= 0;)
  506. {
  507. *dest++ = *src;
  508. src += buf.mNumberChannels;
  509. }
  510. }
  511. }
  512. if (numInChans >= numIn)
  513. break;
  514. }
  515. {
  516. AudioSampleBuffer buffer (channels, jmax (numIn, numOut), numSamples);
  517. const ScopedLock sl (juceFilter->getCallbackLock());
  518. if (juceFilter->isSuspended())
  519. {
  520. for (int i = 0; i < numOut; ++i)
  521. zeromem (channels [i], sizeof (float) * numSamples);
  522. }
  523. else
  524. {
  525. juceFilter->processBlock (buffer, midiEvents);
  526. }
  527. }
  528. if (! midiEvents.isEmpty())
  529. {
  530. #if JucePlugin_ProducesMidiOutput
  531. const uint8* midiEventData;
  532. int midiEventSize, midiEventPosition;
  533. MidiBuffer::Iterator i (midiEvents);
  534. while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition))
  535. {
  536. jassert (midiEventPosition >= 0 && midiEventPosition < (int) numSamples);
  537. //xxx
  538. }
  539. #else
  540. // if your plugin creates midi messages, you'll need to set
  541. // the JucePlugin_ProducesMidiOutput macro to 1 in your
  542. // JucePluginCharacteristics.h file
  543. //jassert (midiEvents.getNumEvents() <= numMidiEventsComingIn);
  544. #endif
  545. midiEvents.clear();
  546. }
  547. if (needToReinterleave)
  548. {
  549. nextSpareBufferChan = 0;
  550. for (i = 0; i < outBuffer.mNumberBuffers; ++i)
  551. {
  552. AudioBuffer& buf = outBuffer.mBuffers[i];
  553. if (buf.mNumberChannels > 1)
  554. {
  555. for (unsigned int subChan = 0; subChan < buf.mNumberChannels; ++subChan)
  556. {
  557. const float* src = bufferSpace.getSampleData (nextSpareBufferChan++);
  558. float* dest = ((float*) buf.mData) + subChan;
  559. for (int j = numSamples; --j >= 0;)
  560. {
  561. *dest = *src++;
  562. dest += buf.mNumberChannels;
  563. }
  564. }
  565. }
  566. }
  567. }
  568. #if ! JucePlugin_SilenceInProducesSilenceOut
  569. ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence;
  570. #endif
  571. }
  572. return noErr;
  573. }
  574. protected:
  575. OSStatus HandleMidiEvent (UInt8 nStatus,
  576. UInt8 inChannel,
  577. UInt8 inData1,
  578. UInt8 inData2,
  579. long inStartFrame)
  580. {
  581. #if JucePlugin_WantsMidiInput
  582. uint8 data [4];
  583. data[0] = nStatus | inChannel;
  584. data[1] = inData1;
  585. data[2] = inData2;
  586. midiEvents.addEvent (data, 3, inStartFrame);
  587. #endif
  588. return noErr;
  589. }
  590. //==============================================================================
  591. private:
  592. AudioFilterBase* juceFilter;
  593. AudioSampleBuffer bufferSpace;
  594. float** channels;
  595. MidiBuffer midiEvents;
  596. bool prepared;
  597. SMPTETime lastSMPTETime;
  598. AUChannelInfo channelInfo [numChannelConfigs];
  599. AudioUnitEvent auEvent;
  600. };
  601. //==============================================================================
  602. class JuceAUComponentHolder : public Component
  603. {
  604. public:
  605. JuceAUComponentHolder (Component* const editorComp)
  606. {
  607. addAndMakeVisible (editorComp);
  608. setOpaque (true);
  609. setVisible (true);
  610. setBroughtToFrontOnMouseClick (true);
  611. #if ! JucePlugin_EditorRequiresKeyboardFocus
  612. setWantsKeyboardFocus (false);
  613. #endif
  614. }
  615. ~JuceAUComponentHolder()
  616. {
  617. }
  618. void resized()
  619. {
  620. if (getNumChildComponents() > 0)
  621. getChildComponent (0)->setBounds (0, 0, getWidth(), getHeight());
  622. }
  623. void paint (Graphics& g)
  624. {
  625. }
  626. };
  627. //==============================================================================
  628. class JuceAUView : public AUCarbonViewBase,
  629. public ComponentListener,
  630. public MouseListener,
  631. public Timer
  632. {
  633. AudioFilterBase* juceFilter;
  634. AudioFilterEditor* editorComp;
  635. Component* windowComp;
  636. bool recursive;
  637. int mx, my;
  638. public:
  639. JuceAUView (AudioUnitCarbonView auview)
  640. : AUCarbonViewBase (auview),
  641. juceFilter (0),
  642. editorComp (0),
  643. windowComp (0),
  644. recursive (false),
  645. mx (0),
  646. my (0)
  647. {
  648. }
  649. ~JuceAUView()
  650. {
  651. deleteUI();
  652. }
  653. ComponentResult CreateUI (Float32 inXOffset, Float32 inYOffset)
  654. {
  655. if (juceFilter == 0)
  656. {
  657. UInt32 propertySize = sizeof (&juceFilter);
  658. AudioUnitGetProperty (GetEditAudioUnit(),
  659. juceFilterObjectPropertyID,
  660. kAudioUnitScope_Global,
  661. 0,
  662. &juceFilter,
  663. &propertySize);
  664. }
  665. if (juceFilter != 0)
  666. {
  667. deleteUI();
  668. editorComp = juceFilter->createEditorIfNeeded();
  669. const int w = editorComp->getWidth();
  670. const int h = editorComp->getHeight();
  671. editorComp->setOpaque (true);
  672. editorComp->setVisible (true);
  673. windowComp = new JuceAUComponentHolder (editorComp);
  674. windowComp->setBounds ((int) inXOffset, (int) inYOffset, w, h);
  675. windowComp->addToDesktop (0, (void*) mCarbonPane);
  676. SizeControl (mCarbonPane, w, h);
  677. editorComp->addComponentListener (this);
  678. windowComp->addMouseListener (this, true);
  679. startTimer (20);
  680. }
  681. else
  682. {
  683. jassertfalse // can't get a pointer to our effect
  684. }
  685. return noErr;
  686. }
  687. void componentMovedOrResized (Component& component,
  688. bool wasMoved,
  689. bool wasResized)
  690. {
  691. if (! recursive)
  692. {
  693. recursive = true;
  694. if (editorComp != 0 && wasResized)
  695. {
  696. const int w = jmax (32, editorComp->getWidth());
  697. const int h = jmax (32, editorComp->getHeight());
  698. SizeControl (mCarbonPane, w, h);
  699. if (windowComp->getWidth() != w
  700. || windowComp->getHeight() != h)
  701. {
  702. windowComp->setSize (w, h);
  703. }
  704. editorComp->repaint();
  705. }
  706. recursive = false;
  707. }
  708. }
  709. void timerCallback()
  710. {
  711. // for some stupid Apple-related reason, mouse move events just don't seem to get sent
  712. // to the windows in an AU, so we have to bodge it here and simulate them with a
  713. // timer..
  714. if (editorComp != 0)
  715. {
  716. int x, y;
  717. Desktop::getInstance().getMousePosition (x, y);
  718. if (x != mx || y != my)
  719. {
  720. mx = x;
  721. my = y;
  722. if (! ModifierKeys::getCurrentModifiers().isAnyMouseButtonDown())
  723. {
  724. for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
  725. {
  726. ComponentPeer* const peer = ComponentPeer::getPeer (i);
  727. int rx = x, ry = y;
  728. peer->getComponent()->globalPositionToRelative (rx, ry);
  729. if (peer->contains (rx, ry, false) && peer->getComponent()->isShowing())
  730. {
  731. peer->handleMouseMove (rx, ry, Time::currentTimeMillis());
  732. break;
  733. }
  734. }
  735. }
  736. }
  737. }
  738. }
  739. void mouseMove (const MouseEvent& e)
  740. {
  741. Desktop::getInstance().getMousePosition (mx, my);
  742. startTimer (20);
  743. }
  744. private:
  745. void deleteUI()
  746. {
  747. PopupMenu::dismissAllActiveMenus();
  748. // there's some kind of component currently modal, but the host
  749. // is trying to delete our plugin..
  750. jassert (Component::getCurrentlyModalComponent() == 0);
  751. if (editorComp != 0)
  752. juceFilter->editorBeingDeleted (editorComp);
  753. deleteAndZero (editorComp);
  754. deleteAndZero (windowComp);
  755. }
  756. };
  757. //==============================================================================
  758. #define JUCE_COMPONENT_ENTRYX(Class, Name, Suffix) \
  759. extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj); \
  760. extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj) \
  761. { \
  762. return ComponentEntryPoint<Class>::Dispatch(params, obj); \
  763. }
  764. #define JUCE_COMPONENT_ENTRY(Class, Name, Suffix) JUCE_COMPONENT_ENTRYX(Class, Name, Suffix)
  765. JUCE_COMPONENT_ENTRY (JuceAU, JucePlugin_AUExportPrefix, Entry)
  766. JUCE_COMPONENT_ENTRY (JuceAUView, JucePlugin_AUExportPrefix, ViewEntry)