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.

854 lines
28KB

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