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.

828 lines
27KB

  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 "AUCarbonViewBase.h"
  26. #include "../../juce_AudioFilterBase.h"
  27. #include "../../juce_IncludeCharacteristics.h"
  28. //==============================================================================
  29. #define juceFilterObjectPropertyID 0x1a45ffe9
  30. static VoidArray activePlugins;
  31. static const short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations };
  32. static const int numChannelConfigs = numElementsInArray (channelConfigs);
  33. BEGIN_JUCE_NAMESPACE
  34. extern void juce_setCurrentExecutableFileNameFromBundleId (const String& bundleId) throw();
  35. END_JUCE_NAMESPACE
  36. //==============================================================================
  37. class JuceAU : public AUMIDIEffectBase,
  38. public AudioFilterBase::FilterNativeCallbacks
  39. {
  40. public:
  41. //==============================================================================
  42. JuceAU (AudioUnit component)
  43. : AUMIDIEffectBase (component),
  44. juceFilter (0),
  45. bufferSpace (2, 16),
  46. prepared (false)
  47. {
  48. CreateElements();
  49. if (activePlugins.size() == 0)
  50. {
  51. initialiseJuce_GUI();
  52. #ifdef JucePlugin_CFBundleIdentifier
  53. juce_setCurrentExecutableFileNameFromBundleId (JucePlugin_CFBundleIdentifier);
  54. #endif
  55. MessageManager::getInstance()->setTimeBeforeShowingWaitCursor (0);
  56. }
  57. juceFilter = createPluginFilter();
  58. juceFilter->initialiseInternal (this);
  59. jassert (juceFilter != 0);
  60. Globals()->UseIndexedParameters (juceFilter->getNumParameters());
  61. activePlugins.add (this);
  62. }
  63. ~JuceAU()
  64. {
  65. delete juceFilter;
  66. juceFilter = 0;
  67. jassert (activePlugins.contains (this));
  68. activePlugins.removeValue (this);
  69. if (activePlugins.size() == 0)
  70. shutdownJuce_GUI();
  71. }
  72. //==============================================================================
  73. ComponentResult GetPropertyInfo (AudioUnitPropertyID inID,
  74. AudioUnitScope inScope,
  75. AudioUnitElement inElement,
  76. UInt32& outDataSize,
  77. Boolean& outWritable)
  78. {
  79. if (inScope == kAudioUnitScope_Global)
  80. {
  81. if (inID == juceFilterObjectPropertyID)
  82. {
  83. outWritable = false;
  84. outDataSize = sizeof (void*);
  85. return noErr;
  86. }
  87. }
  88. return AUMIDIEffectBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
  89. }
  90. ComponentResult GetProperty (AudioUnitPropertyID inID,
  91. AudioUnitScope inScope,
  92. AudioUnitElement inElement,
  93. void* outData)
  94. {
  95. if (inScope == kAudioUnitScope_Global)
  96. {
  97. if (inID == juceFilterObjectPropertyID)
  98. {
  99. *((void**) outData) = (void*) juceFilter;
  100. return noErr;
  101. }
  102. }
  103. return AUMIDIEffectBase::GetProperty (inID, inScope, inElement, outData);
  104. }
  105. ComponentResult SaveState (CFPropertyListRef* outData)
  106. {
  107. ComponentResult err = AUMIDIEffectBase::SaveState (outData);
  108. if (err != noErr)
  109. return err;
  110. jassert (CFGetTypeID (*outData) == CFDictionaryGetTypeID());
  111. CFMutableDictionaryRef dict = (CFMutableDictionaryRef) *outData;
  112. if (juceFilter != 0)
  113. {
  114. JUCE_NAMESPACE::MemoryBlock state;
  115. juceFilter->getStateInformation (state);
  116. if (state.getSize() > 0)
  117. {
  118. CFDataRef ourState = CFDataCreate (kCFAllocatorDefault, (const uint8*) state, state.getSize());
  119. CFDictionarySetValue (dict, CFSTR("jucePluginState"), ourState);
  120. CFRelease (ourState);
  121. }
  122. }
  123. return noErr;
  124. }
  125. ComponentResult RestoreState (CFPropertyListRef inData)
  126. {
  127. ComponentResult err = AUMIDIEffectBase::RestoreState (inData);
  128. if (err != noErr)
  129. return err;
  130. if (juceFilter != 0)
  131. {
  132. CFDictionaryRef dict = (CFDictionaryRef) inData;
  133. CFDataRef data = 0;
  134. if (CFDictionaryGetValueIfPresent (dict, CFSTR("jucePluginState"),
  135. (const void**) &data))
  136. {
  137. if (data != 0)
  138. {
  139. const int numBytes = (int) CFDataGetLength (data);
  140. const uint8* const rawBytes = CFDataGetBytePtr (data);
  141. if (numBytes > 0)
  142. juceFilter->setStateInformation (rawBytes, numBytes);
  143. }
  144. }
  145. }
  146. return noErr;
  147. }
  148. UInt32 SupportedNumChannels (const AUChannelInfo** outInfo)
  149. {
  150. if (juceFilter == 0)
  151. return 0;
  152. // You need to actually add some configurations to the JucePlugin_PreferredChannelConfigurations
  153. // value in your JucePluginCharacteristics.h file..
  154. jassert (numChannelConfigs > 0);
  155. if (outInfo != 0)
  156. {
  157. for (int i = 0; i < numChannelConfigs; ++i)
  158. {
  159. channelInfo[i].inChannels = channelConfigs[i][0];
  160. channelInfo[i].outChannels = channelConfigs[i][1];
  161. outInfo[i] = channelInfo + i;
  162. }
  163. }
  164. return numChannelConfigs;
  165. }
  166. //==============================================================================
  167. ComponentResult GetParameterInfo (AudioUnitScope inScope,
  168. AudioUnitParameterID inParameterID,
  169. AudioUnitParameterInfo& outParameterInfo)
  170. {
  171. if (inScope == kAudioUnitScope_Global && juceFilter != 0)
  172. {
  173. outParameterInfo.flags = kAudioUnitParameterFlag_IsWritable
  174. | kAudioUnitParameterFlag_IsReadable
  175. | kAudioUnitParameterFlag_HasCFNameString;
  176. outParameterInfo.name[0] = 0;
  177. outParameterInfo.cfNameString = PlatformUtilities::juceStringToCFString (juceFilter->getParameterName ((int) inParameterID));
  178. outParameterInfo.minValue = 0.0f;
  179. outParameterInfo.maxValue = 1.0f;
  180. outParameterInfo.defaultValue = 0.0f;
  181. outParameterInfo.unit = kAudioUnitParameterUnit_Generic;
  182. return noErr;
  183. }
  184. else
  185. {
  186. return kAudioUnitErr_InvalidParameter;
  187. }
  188. }
  189. ComponentResult GetParameter (AudioUnitParameterID inID,
  190. AudioUnitScope inScope,
  191. AudioUnitElement inElement,
  192. Float32& outValue)
  193. {
  194. if (inScope == kAudioUnitScope_Global && juceFilter != 0)
  195. {
  196. outValue = juceFilter->getParameter ((int) inID);
  197. return noErr;
  198. }
  199. return AUBase::GetParameter (inID, inScope, inElement, outValue);
  200. }
  201. ComponentResult SetParameter (AudioUnitParameterID inID,
  202. AudioUnitScope inScope,
  203. AudioUnitElement inElement,
  204. Float32 inValue,
  205. UInt32 inBufferOffsetInFrames)
  206. {
  207. if (inScope == kAudioUnitScope_Global && juceFilter != 0)
  208. {
  209. juceFilter->setParameter ((int) inID, inValue);
  210. return noErr;
  211. }
  212. return AUBase::SetParameter (inID, inScope, inElement, inValue, inBufferOffsetInFrames);
  213. }
  214. //==============================================================================
  215. ComponentResult Version() { return JucePlugin_VersionCode; }
  216. bool SupportsTail() { return true; }
  217. Float64 GetTailTime() { return 0; }
  218. Float64 GetLatency()
  219. {
  220. jassert (GetSampleRate() > 0);
  221. if (GetSampleRate() <= 0)
  222. return 0.0;
  223. return (JucePlugin_Latency) / GetSampleRate();
  224. }
  225. //==============================================================================
  226. int GetNumCustomUIComponents() { return 1; }
  227. void GetUIComponentDescs (ComponentDescription* inDescArray)
  228. {
  229. inDescArray[0].componentType = kAudioUnitCarbonViewComponentType;
  230. inDescArray[0].componentSubType = JucePlugin_AUSubType;
  231. inDescArray[0].componentManufacturer = JucePlugin_AUManufacturerCode;
  232. inDescArray[0].componentFlags = 0;
  233. inDescArray[0].componentFlagsMask = 0;
  234. }
  235. //==============================================================================
  236. bool getCurrentPositionInfo (AudioFilterBase::CurrentPositionInfo& info)
  237. {
  238. info.timeSigNumerator = 0;
  239. info.timeSigDenominator = 0;
  240. info.timeInSeconds = 0;
  241. info.editOriginTime = 0;
  242. info.ppqPositionOfLastBarStart = 0;
  243. info.isPlaying = false;
  244. info.isRecording = false;
  245. switch (lastSMPTETime.mType)
  246. {
  247. case kSMPTETimeType24:
  248. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps24;
  249. break;
  250. case kSMPTETimeType25:
  251. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps25;
  252. break;
  253. case kSMPTETimeType30Drop:
  254. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps30drop;
  255. break;
  256. case kSMPTETimeType30:
  257. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps30;
  258. break;
  259. case kSMPTETimeType2997:
  260. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps2997;
  261. break;
  262. case kSMPTETimeType2997Drop:
  263. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps2997drop;
  264. break;
  265. //case kSMPTETimeType60:
  266. //case kSMPTETimeType5994:
  267. default:
  268. info.frameRate = AudioFilterBase::CurrentPositionInfo::fpsUnknown;
  269. break;
  270. }
  271. if (CallHostBeatAndTempo (&info.ppqPosition, &info.bpm) != noErr)
  272. {
  273. info.ppqPosition = 0;
  274. info.bpm = 0;
  275. }
  276. UInt32 outDeltaSampleOffsetToNextBeat;
  277. double outCurrentMeasureDownBeat;
  278. float num;
  279. UInt32 den;
  280. if (CallHostMusicalTimeLocation (&outDeltaSampleOffsetToNextBeat, &num, &den,
  281. &outCurrentMeasureDownBeat) == noErr)
  282. {
  283. info.timeSigNumerator = (int) num;
  284. info.timeSigDenominator = den;
  285. info.ppqPositionOfLastBarStart = outCurrentMeasureDownBeat;
  286. }
  287. double outCurrentSampleInTimeLine, outCycleStartBeat, outCycleEndBeat;
  288. Boolean playing, playchanged, looping;
  289. if (CallHostTransportState (&playing,
  290. &playchanged,
  291. &outCurrentSampleInTimeLine,
  292. &looping,
  293. &outCycleStartBeat,
  294. &outCycleEndBeat) == noErr)
  295. {
  296. info.isPlaying = playing;
  297. info.timeInSeconds = outCurrentSampleInTimeLine / GetSampleRate();
  298. }
  299. return true;
  300. }
  301. void informHostOfParameterChange (int index, float newValue)
  302. {
  303. if (juceFilter != 0)
  304. {
  305. juceFilter->setParameter (index, newValue);
  306. if (AUEventListenerNotify != 0)
  307. {
  308. AudioUnitEvent e;
  309. e.mEventType = kAudioUnitEvent_ParameterValueChange;
  310. e.mArgument.mParameter.mAudioUnit = GetComponentInstance();
  311. e.mArgument.mParameter.mParameterID = (AudioUnitParameterID) index;
  312. e.mArgument.mParameter.mScope = kAudioUnitScope_Global;
  313. e.mArgument.mParameter.mElement = 0;
  314. AUEventListenerNotify (0, 0, &e);
  315. }
  316. }
  317. }
  318. //==============================================================================
  319. ComponentResult Initialize()
  320. {
  321. AUMIDIEffectBase::Initialize();
  322. prepareToPlay();
  323. return noErr;
  324. }
  325. void Cleanup()
  326. {
  327. AUMIDIEffectBase::Cleanup();
  328. if (juceFilter != 0)
  329. juceFilter->releaseResources();
  330. bufferSpace.setSize (2, 16);
  331. midiEvents.clear();
  332. prepared = false;
  333. }
  334. ComponentResult Reset (AudioUnitScope inScope, AudioUnitElement inElement)
  335. {
  336. if (! prepared)
  337. prepareToPlay();
  338. return AUMIDIEffectBase::Reset (inScope, inElement);
  339. }
  340. void prepareToPlay()
  341. {
  342. if (juceFilter != 0)
  343. {
  344. juceFilter->numInputChannels = GetInput(0)->GetStreamFormat().mChannelsPerFrame;
  345. juceFilter->numOutputChannels = GetOutput(0)->GetStreamFormat().mChannelsPerFrame;
  346. bufferSpace.setSize (juceFilter->numInputChannels + juceFilter->numOutputChannels,
  347. GetMaxFramesPerSlice() + 32);
  348. juceFilter->prepareToPlay (GetSampleRate(),
  349. GetMaxFramesPerSlice());
  350. midiEvents.clear();
  351. prepared = true;
  352. }
  353. }
  354. ComponentResult Render (AudioUnitRenderActionFlags &ioActionFlags,
  355. const AudioTimeStamp& inTimeStamp,
  356. UInt32 nFrames)
  357. {
  358. lastSMPTETime = inTimeStamp.mSMPTETime;
  359. return AUMIDIEffectBase::Render (ioActionFlags, inTimeStamp, nFrames);
  360. }
  361. OSStatus ProcessBufferLists (AudioUnitRenderActionFlags& ioActionFlags,
  362. const AudioBufferList& inBuffer,
  363. AudioBufferList& outBuffer,
  364. UInt32 inFramesToProcess)
  365. {
  366. if (juceFilter != 0)
  367. {
  368. jassert (prepared);
  369. float* inChans [64];
  370. int numInChans = 0;
  371. float* outChans [64];
  372. int numOutChans = 0;
  373. int nextSpareBufferChan = 0;
  374. bool needToReinterleave = false;
  375. unsigned int i;
  376. for (i = 0; i < inBuffer.mNumberBuffers; ++i)
  377. {
  378. const AudioBuffer& buf = inBuffer.mBuffers[i];
  379. if (buf.mNumberChannels == 1)
  380. {
  381. inChans [numInChans++] = (float*) buf.mData;
  382. }
  383. else
  384. {
  385. // need to de-interleave..
  386. for (unsigned int subChan = 0; subChan < buf.mNumberChannels; ++subChan)
  387. {
  388. float* dest = bufferSpace.getSampleData (nextSpareBufferChan++);
  389. inChans [numInChans++] = dest;
  390. const float* src = ((const float*) buf.mData) + subChan;
  391. for (int j = inFramesToProcess; --j >= 0;)
  392. {
  393. *dest++ = *src;
  394. src += buf.mNumberChannels;
  395. }
  396. }
  397. }
  398. if (numInChans >= juceFilter->numInputChannels)
  399. break;
  400. }
  401. const int firstBufferedOutChan = nextSpareBufferChan;
  402. for (i = 0; i < outBuffer.mNumberBuffers; ++i)
  403. {
  404. AudioBuffer& buf = outBuffer.mBuffers[i];
  405. if (buf.mNumberChannels == 1)
  406. {
  407. outChans [numOutChans++] = (float*) buf.mData;
  408. }
  409. else
  410. {
  411. needToReinterleave = true;
  412. for (unsigned int subChan = 0; subChan < buf.mNumberChannels; ++subChan)
  413. {
  414. float* dest = bufferSpace.getSampleData (nextSpareBufferChan++);
  415. outChans [numOutChans++] = dest;
  416. }
  417. }
  418. if (numOutChans >= juceFilter->numOutputChannels)
  419. break;
  420. }
  421. const bool accumulate = false;
  422. {
  423. const AudioSampleBuffer input (inChans, numInChans, inFramesToProcess);
  424. AudioSampleBuffer output (outChans, numOutChans, inFramesToProcess);
  425. const ScopedLock sl (juceFilter->getCallbackLock());
  426. if (juceFilter->suspended)
  427. output.clear();
  428. else
  429. juceFilter->processBlock (input, output, accumulate, midiEvents);
  430. }
  431. if (! midiEvents.isEmpty())
  432. {
  433. #if JucePlugin_ProducesMidiOutput
  434. const uint8* midiEventData;
  435. int midiEventSize, midiEventPosition;
  436. MidiBuffer::Iterator i (midiEvents);
  437. while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition))
  438. {
  439. jassert (midiEventPosition >= 0 && midiEventPosition < (int) inFramesToProcess);
  440. //xxx
  441. }
  442. #else
  443. // if your plugin creates midi messages, you'll need to set
  444. // the JucePlugin_ProducesMidiOutput macro to 1 in your
  445. // JucePluginCharacteristics.h file
  446. //jassert (midiEvents.getNumEvents() <= numMidiEventsComingIn);
  447. #endif
  448. midiEvents.clear();
  449. }
  450. if (needToReinterleave)
  451. {
  452. nextSpareBufferChan = firstBufferedOutChan;
  453. for (i = 0; i < outBuffer.mNumberBuffers; ++i)
  454. {
  455. AudioBuffer& buf = outBuffer.mBuffers[i];
  456. if (buf.mNumberChannels > 1)
  457. {
  458. for (unsigned int subChan = 0; subChan < buf.mNumberChannels; ++subChan)
  459. {
  460. const float* src = bufferSpace.getSampleData (nextSpareBufferChan++);
  461. float* dest = ((float*) buf.mData) + subChan;
  462. for (int j = inFramesToProcess; --j >= 0;)
  463. {
  464. *dest = *src++;
  465. dest += buf.mNumberChannels;
  466. }
  467. }
  468. }
  469. }
  470. }
  471. #if ! JucePlugin_SilenceInProducesSilenceOut
  472. ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence;
  473. #endif
  474. }
  475. return noErr;
  476. }
  477. protected:
  478. OSStatus HandleMidiEvent (UInt8 nStatus,
  479. UInt8 inChannel,
  480. UInt8 inData1,
  481. UInt8 inData2,
  482. long inStartFrame)
  483. {
  484. #if JucePlugin_WantsMidiInput
  485. uint8 data [4];
  486. data[0] = nStatus | inChannel;
  487. data[1] = inData1;
  488. data[2] = inData2;
  489. midiEvents.addEvent (data, 3, inStartFrame);
  490. #endif
  491. return noErr;
  492. }
  493. //==============================================================================
  494. private:
  495. AudioFilterBase* juceFilter;
  496. AudioSampleBuffer bufferSpace;
  497. MidiBuffer midiEvents;
  498. bool prepared;
  499. SMPTETime lastSMPTETime;
  500. AUChannelInfo channelInfo [numChannelConfigs];
  501. };
  502. //==============================================================================
  503. class JuceAUComponentHolder : public Component
  504. {
  505. public:
  506. JuceAUComponentHolder (Component* const editorComp)
  507. {
  508. addAndMakeVisible (editorComp);
  509. setOpaque (true);
  510. setVisible (true);
  511. setBroughtToFrontOnMouseClick (true);
  512. #if ! JucePlugin_EditorRequiresKeyboardFocus
  513. setWantsKeyboardFocus (false);
  514. #endif
  515. }
  516. ~JuceAUComponentHolder()
  517. {
  518. }
  519. void resized()
  520. {
  521. if (getNumChildComponents() > 0)
  522. getChildComponent (0)->setBounds (0, 0, getWidth(), getHeight());
  523. }
  524. void paint (Graphics& g)
  525. {
  526. }
  527. };
  528. //==============================================================================
  529. class JuceAUView : public AUCarbonViewBase,
  530. public ComponentListener,
  531. public MouseListener,
  532. public Timer
  533. {
  534. AudioFilterBase* juceFilter;
  535. AudioFilterEditor* editorComp;
  536. Component* windowComp;
  537. bool recursive;
  538. int mx, my;
  539. public:
  540. JuceAUView (AudioUnitCarbonView auview)
  541. : AUCarbonViewBase (auview),
  542. juceFilter (0),
  543. editorComp (0),
  544. windowComp (0),
  545. recursive (false),
  546. mx (0),
  547. my (0)
  548. {
  549. }
  550. ~JuceAUView()
  551. {
  552. deleteUI();
  553. }
  554. ComponentResult CreateUI (Float32 inXOffset, Float32 inYOffset)
  555. {
  556. if (juceFilter == 0)
  557. {
  558. UInt32 propertySize = sizeof (&juceFilter);
  559. AudioUnitGetProperty (GetEditAudioUnit(),
  560. juceFilterObjectPropertyID,
  561. kAudioUnitScope_Global,
  562. 0,
  563. &juceFilter,
  564. &propertySize);
  565. }
  566. if (juceFilter != 0)
  567. {
  568. deleteUI();
  569. editorComp = juceFilter->createEditorIfNeeded();
  570. const int w = editorComp->getWidth();
  571. const int h = editorComp->getHeight();
  572. editorComp->setOpaque (true);
  573. editorComp->setVisible (true);
  574. windowComp = new JuceAUComponentHolder (editorComp);
  575. windowComp->setBounds ((int) inXOffset, (int) inYOffset, w, h);
  576. windowComp->addToDesktop (0, (void*) mCarbonPane);
  577. SizeControl (mCarbonPane, w, h);
  578. editorComp->addComponentListener (this);
  579. windowComp->addMouseListener (this, true);
  580. startTimer (20);
  581. }
  582. else
  583. {
  584. jassertfalse // can't get a pointer to our effect
  585. }
  586. return noErr;
  587. }
  588. void componentMovedOrResized (Component& component,
  589. bool wasMoved,
  590. bool wasResized)
  591. {
  592. if (! recursive)
  593. {
  594. recursive = true;
  595. if (editorComp != 0 && wasResized)
  596. {
  597. const int w = jmax (32, editorComp->getWidth());
  598. const int h = jmax (32, editorComp->getHeight());
  599. SizeControl (mCarbonPane, w, h);
  600. if (windowComp->getWidth() != w
  601. || windowComp->getHeight() != h)
  602. {
  603. windowComp->setSize (w, h);
  604. }
  605. editorComp->repaint();
  606. }
  607. recursive = false;
  608. }
  609. }
  610. void timerCallback()
  611. {
  612. // for some stupid Apple-related reason, mouse move events just don't seem to get sent
  613. // to the windows in an AU, so we have to bodge it here and simulate them with a
  614. // timer..
  615. if (editorComp != 0)
  616. {
  617. int x, y;
  618. Desktop::getInstance().getMousePosition (x, y);
  619. if (x != mx || y != my)
  620. {
  621. mx = x;
  622. my = y;
  623. if (! ModifierKeys::getCurrentModifiers().isAnyMouseButtonDown())
  624. {
  625. for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
  626. {
  627. ComponentPeer* const peer = ComponentPeer::getPeer (i);
  628. const int rx = x - peer->getComponent()->getX();
  629. const int ry = y - peer->getComponent()->getY();
  630. if (peer->contains (rx, ry, false) && peer->getComponent()->isShowing())
  631. {
  632. peer->handleMouseMove (rx, ry, Time::currentTimeMillis());
  633. break;
  634. }
  635. }
  636. }
  637. }
  638. }
  639. }
  640. void mouseMove (const MouseEvent& e)
  641. {
  642. Desktop::getInstance().getMousePosition (mx, my);
  643. startTimer (20);
  644. }
  645. private:
  646. void deleteUI()
  647. {
  648. PopupMenu::dismissAllActiveMenus();
  649. // there's some kind of component currently modal, but the host
  650. // is trying to delete our plugin..
  651. jassert (Component::getCurrentlyModalComponent() == 0);
  652. if (editorComp != 0)
  653. juceFilter->editorBeingDeleted (editorComp);
  654. deleteAndZero (editorComp);
  655. deleteAndZero (windowComp);
  656. }
  657. };
  658. //==============================================================================
  659. #define JUCE_COMPONENT_ENTRYX(Class, Name, Suffix) \
  660. extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj); \
  661. extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj) \
  662. { \
  663. return ComponentEntryPoint<Class>::Dispatch(params, obj); \
  664. }
  665. #define JUCE_COMPONENT_ENTRY(Class, Name, Suffix) JUCE_COMPONENT_ENTRYX(Class, Name, Suffix)
  666. JUCE_COMPONENT_ENTRY (JuceAU, JucePlugin_AUExportPrefix, Entry)
  667. JUCE_COMPONENT_ENTRY (JuceAUView, JucePlugin_AUExportPrefix, ViewEntry)