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.

946 lines
30KB

  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. CharacterFunctions::copy ((char*) outParameterInfo.name,
  200. (const char*) name.toUTF8(),
  201. sizeof (outParameterInfo.name) - 1);
  202. // set whether the param is automatable (unnamed parameters aren't allowed to be automated)
  203. if (name.isEmpty() || ! juceFilter->isParameterAutomatable (index))
  204. outParameterInfo.flags |= kAudioUnitParameterFlag_NonRealTime;
  205. outParameterInfo.cfNameString = PlatformUtilities::juceStringToCFString (name);
  206. outParameterInfo.minValue = 0.0f;
  207. outParameterInfo.maxValue = 1.0f;
  208. outParameterInfo.defaultValue = 0.0f;
  209. outParameterInfo.unit = kAudioUnitParameterUnit_Generic;
  210. return noErr;
  211. }
  212. else
  213. {
  214. return kAudioUnitErr_InvalidParameter;
  215. }
  216. }
  217. ComponentResult GetParameter (AudioUnitParameterID inID,
  218. AudioUnitScope inScope,
  219. AudioUnitElement inElement,
  220. Float32& outValue)
  221. {
  222. if (inScope == kAudioUnitScope_Global && juceFilter != 0)
  223. {
  224. outValue = juceFilter->getParameter ((int) inID);
  225. return noErr;
  226. }
  227. return AUBase::GetParameter (inID, inScope, inElement, outValue);
  228. }
  229. ComponentResult SetParameter (AudioUnitParameterID inID,
  230. AudioUnitScope inScope,
  231. AudioUnitElement inElement,
  232. Float32 inValue,
  233. UInt32 inBufferOffsetInFrames)
  234. {
  235. if (inScope == kAudioUnitScope_Global && juceFilter != 0)
  236. {
  237. juceFilter->setParameter ((int) inID, inValue);
  238. return noErr;
  239. }
  240. return AUBase::SetParameter (inID, inScope, inElement, inValue, inBufferOffsetInFrames);
  241. }
  242. //==============================================================================
  243. ComponentResult Version() { return JucePlugin_VersionCode; }
  244. bool SupportsTail() { return true; }
  245. Float64 GetTailTime() { return 0; }
  246. Float64 GetSampleRate()
  247. {
  248. return GetOutput(0)->GetStreamFormat().mSampleRate;
  249. }
  250. Float64 GetLatency()
  251. {
  252. jassert (GetSampleRate() > 0);
  253. if (GetSampleRate() <= 0)
  254. return 0.0;
  255. return juceFilter->getLatencySamples() / GetSampleRate();
  256. }
  257. //==============================================================================
  258. int GetNumCustomUIComponents() { return 1; }
  259. void GetUIComponentDescs (ComponentDescription* inDescArray)
  260. {
  261. inDescArray[0].componentType = kAudioUnitCarbonViewComponentType;
  262. inDescArray[0].componentSubType = JucePlugin_AUSubType;
  263. inDescArray[0].componentManufacturer = JucePlugin_AUManufacturerCode;
  264. inDescArray[0].componentFlags = 0;
  265. inDescArray[0].componentFlagsMask = 0;
  266. }
  267. //==============================================================================
  268. bool getCurrentPositionInfo (AudioFilterBase::CurrentPositionInfo& info)
  269. {
  270. info.timeSigNumerator = 0;
  271. info.timeSigDenominator = 0;
  272. info.timeInSeconds = 0;
  273. info.editOriginTime = 0;
  274. info.ppqPositionOfLastBarStart = 0;
  275. info.isPlaying = false;
  276. info.isRecording = false;
  277. switch (lastSMPTETime.mType)
  278. {
  279. case kSMPTETimeType24:
  280. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps24;
  281. break;
  282. case kSMPTETimeType25:
  283. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps25;
  284. break;
  285. case kSMPTETimeType30Drop:
  286. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps30drop;
  287. break;
  288. case kSMPTETimeType30:
  289. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps30;
  290. break;
  291. case kSMPTETimeType2997:
  292. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps2997;
  293. break;
  294. case kSMPTETimeType2997Drop:
  295. info.frameRate = AudioFilterBase::CurrentPositionInfo::fps2997drop;
  296. break;
  297. //case kSMPTETimeType60:
  298. //case kSMPTETimeType5994:
  299. default:
  300. info.frameRate = AudioFilterBase::CurrentPositionInfo::fpsUnknown;
  301. break;
  302. }
  303. if (CallHostBeatAndTempo (&info.ppqPosition, &info.bpm) != noErr)
  304. {
  305. info.ppqPosition = 0;
  306. info.bpm = 0;
  307. }
  308. UInt32 outDeltaSampleOffsetToNextBeat;
  309. double outCurrentMeasureDownBeat;
  310. float num;
  311. UInt32 den;
  312. if (CallHostMusicalTimeLocation (&outDeltaSampleOffsetToNextBeat, &num, &den,
  313. &outCurrentMeasureDownBeat) == noErr)
  314. {
  315. info.timeSigNumerator = (int) num;
  316. info.timeSigDenominator = den;
  317. info.ppqPositionOfLastBarStart = outCurrentMeasureDownBeat;
  318. }
  319. double outCurrentSampleInTimeLine, outCycleStartBeat, outCycleEndBeat;
  320. Boolean playing, playchanged, looping;
  321. if (CallHostTransportState (&playing,
  322. &playchanged,
  323. &outCurrentSampleInTimeLine,
  324. &looping,
  325. &outCycleStartBeat,
  326. &outCycleEndBeat) == noErr)
  327. {
  328. info.isPlaying = playing;
  329. info.timeInSeconds = outCurrentSampleInTimeLine / GetSampleRate();
  330. }
  331. return true;
  332. }
  333. void sendAUEvent (const AudioUnitEventType type, const int index) throw()
  334. {
  335. if (AUEventListenerNotify != 0)
  336. {
  337. auEvent.mEventType = type;
  338. auEvent.mArgument.mParameter.mParameterID = (AudioUnitParameterID) index;
  339. AUEventListenerNotify (0, 0, &auEvent);
  340. }
  341. }
  342. void informHostOfParameterChange (int index, float newValue)
  343. {
  344. if (juceFilter != 0)
  345. {
  346. juceFilter->setParameter (index, newValue);
  347. sendAUEvent (kAudioUnitEvent_ParameterValueChange, index);
  348. }
  349. }
  350. void informHostOfParameterGestureBegin (int index)
  351. {
  352. if (juceFilter != 0)
  353. sendAUEvent (kAudioUnitEvent_BeginParameterChangeGesture, index);
  354. }
  355. void informHostOfParameterGestureEnd (int index)
  356. {
  357. if (juceFilter != 0)
  358. sendAUEvent (kAudioUnitEvent_EndParameterChangeGesture, index);
  359. }
  360. void informHostOfStateChange()
  361. {
  362. // xxx is there an AU equivalent?
  363. }
  364. bool StreamFormatWritable (AudioUnitScope inScope, AudioUnitElement element)
  365. {
  366. return ! IsInitialized();
  367. }
  368. ComponentResult StartNote (MusicDeviceInstrumentID, MusicDeviceGroupID, NoteInstanceID&, UInt32, const MusicDeviceNoteParams&)
  369. {
  370. return noErr;
  371. }
  372. ComponentResult StopNote (MusicDeviceGroupID, NoteInstanceID, UInt32)
  373. {
  374. return noErr;
  375. }
  376. //==============================================================================
  377. ComponentResult Initialize()
  378. {
  379. #if ! JucePlugin_IsSynth
  380. const int numIns = GetInput(0) != 0 ? GetInput(0)->GetStreamFormat().mChannelsPerFrame : 0;
  381. #endif
  382. const int numOuts = GetOutput(0) != 0 ? GetOutput(0)->GetStreamFormat().mChannelsPerFrame : 0;
  383. bool isValidChannelConfig = false;
  384. for (int i = 0; i < numChannelConfigs; ++i)
  385. #if JucePlugin_IsSynth
  386. if (numOuts == channelConfigs[i][1])
  387. #else
  388. if (numIns == channelConfigs[i][0] && numOuts == channelConfigs[i][1])
  389. #endif
  390. isValidChannelConfig = true;
  391. if (! isValidChannelConfig)
  392. return kAudioUnitErr_FormatNotSupported;
  393. JuceAUBaseClass::Initialize();
  394. prepareToPlay();
  395. return noErr;
  396. }
  397. void Cleanup()
  398. {
  399. JuceAUBaseClass::Cleanup();
  400. if (juceFilter != 0)
  401. juceFilter->releaseResources();
  402. bufferSpace.setSize (2, 16);
  403. midiEvents.clear();
  404. prepared = false;
  405. }
  406. ComponentResult Reset (AudioUnitScope inScope, AudioUnitElement inElement)
  407. {
  408. if (! prepared)
  409. prepareToPlay();
  410. return JuceAUBaseClass::Reset (inScope, inElement);
  411. }
  412. void prepareToPlay()
  413. {
  414. if (juceFilter != 0)
  415. {
  416. #if ! JucePlugin_IsSynth
  417. juceFilter->setPlayConfigDetails (GetInput(0)->GetStreamFormat().mChannelsPerFrame,
  418. #else
  419. juceFilter->setPlayConfigDetails (0,
  420. #endif
  421. GetOutput(0)->GetStreamFormat().mChannelsPerFrame,
  422. GetSampleRate(),
  423. GetMaxFramesPerSlice());
  424. bufferSpace.setSize (juceFilter->getNumInputChannels() + juceFilter->getNumOutputChannels(),
  425. GetMaxFramesPerSlice() + 32);
  426. juceFilter->prepareToPlay (GetSampleRate(),
  427. GetMaxFramesPerSlice());
  428. midiEvents.clear();
  429. juce_free (channels);
  430. channels = (float**) juce_calloc (sizeof (float*) * jmax (juceFilter->getNumInputChannels(),
  431. juceFilter->getNumOutputChannels()) + 4);
  432. prepared = true;
  433. }
  434. }
  435. ComponentResult Render (AudioUnitRenderActionFlags &ioActionFlags,
  436. const AudioTimeStamp& inTimeStamp,
  437. UInt32 nFrames)
  438. {
  439. lastSMPTETime = inTimeStamp.mSMPTETime;
  440. #if ! JucePlugin_IsSynth
  441. return JuceAUBaseClass::Render (ioActionFlags, inTimeStamp, nFrames);
  442. #else
  443. // synths can't have any inputs..
  444. AudioBufferList inBuffer;
  445. inBuffer.mNumberBuffers = 0;
  446. return ProcessBufferLists (ioActionFlags, inBuffer, GetOutput(0)->GetBufferList(), nFrames);
  447. #endif
  448. }
  449. OSStatus ProcessBufferLists (AudioUnitRenderActionFlags& ioActionFlags,
  450. const AudioBufferList& inBuffer,
  451. AudioBufferList& outBuffer,
  452. UInt32 numSamples)
  453. {
  454. if (juceFilter != 0)
  455. {
  456. jassert (prepared);
  457. int numOutChans = 0;
  458. int nextSpareBufferChan = 0;
  459. bool needToReinterleave = false;
  460. const int numIn = juceFilter->getNumInputChannels();
  461. const int numOut = juceFilter->getNumOutputChannels();
  462. unsigned int i;
  463. for (i = 0; i < outBuffer.mNumberBuffers; ++i)
  464. {
  465. AudioBuffer& buf = outBuffer.mBuffers[i];
  466. if (buf.mNumberChannels == 1)
  467. {
  468. channels [numOutChans++] = (float*) buf.mData;
  469. }
  470. else
  471. {
  472. needToReinterleave = true;
  473. for (unsigned int subChan = 0; subChan < buf.mNumberChannels && numOutChans < numOut; ++subChan)
  474. channels [numOutChans++] = bufferSpace.getSampleData (nextSpareBufferChan++);
  475. }
  476. if (numOutChans >= numOut)
  477. break;
  478. }
  479. int numInChans = 0;
  480. for (i = 0; i < inBuffer.mNumberBuffers; ++i)
  481. {
  482. const AudioBuffer& buf = inBuffer.mBuffers[i];
  483. if (buf.mNumberChannels == 1)
  484. {
  485. if (numInChans < numOut)
  486. memcpy (channels [numInChans], (const float*) buf.mData, sizeof (float) * numSamples);
  487. else
  488. channels [numInChans] = (float*) buf.mData;
  489. }
  490. else
  491. {
  492. // need to de-interleave..
  493. for (unsigned int subChan = 0; subChan < buf.mNumberChannels && numInChans < numIn; ++subChan)
  494. {
  495. float* dest;
  496. if (numInChans >= numOut)
  497. {
  498. dest = bufferSpace.getSampleData (nextSpareBufferChan++);
  499. channels [numInChans++] = dest;
  500. }
  501. else
  502. {
  503. dest = channels [numInChans++];
  504. }
  505. const float* src = ((const float*) buf.mData) + subChan;
  506. for (int j = numSamples; --j >= 0;)
  507. {
  508. *dest++ = *src;
  509. src += buf.mNumberChannels;
  510. }
  511. }
  512. }
  513. if (numInChans >= numIn)
  514. break;
  515. }
  516. {
  517. AudioSampleBuffer buffer (channels, jmax (numIn, numOut), numSamples);
  518. const ScopedLock sl (juceFilter->getCallbackLock());
  519. if (juceFilter->isSuspended())
  520. {
  521. for (int i = 0; i < numOut; ++i)
  522. zeromem (channels [i], sizeof (float) * numSamples);
  523. }
  524. else
  525. {
  526. juceFilter->processBlock (buffer, midiEvents);
  527. }
  528. }
  529. if (! midiEvents.isEmpty())
  530. {
  531. #if JucePlugin_ProducesMidiOutput
  532. const uint8* midiEventData;
  533. int midiEventSize, midiEventPosition;
  534. MidiBuffer::Iterator i (midiEvents);
  535. while (i.getNextEvent (midiEventData, midiEventSize, midiEventPosition))
  536. {
  537. jassert (midiEventPosition >= 0 && midiEventPosition < (int) numSamples);
  538. //xxx
  539. }
  540. #else
  541. // if your plugin creates midi messages, you'll need to set
  542. // the JucePlugin_ProducesMidiOutput macro to 1 in your
  543. // JucePluginCharacteristics.h file
  544. //jassert (midiEvents.getNumEvents() <= numMidiEventsComingIn);
  545. #endif
  546. midiEvents.clear();
  547. }
  548. if (needToReinterleave)
  549. {
  550. nextSpareBufferChan = 0;
  551. for (i = 0; i < outBuffer.mNumberBuffers; ++i)
  552. {
  553. AudioBuffer& buf = outBuffer.mBuffers[i];
  554. if (buf.mNumberChannels > 1)
  555. {
  556. for (unsigned int subChan = 0; subChan < buf.mNumberChannels; ++subChan)
  557. {
  558. const float* src = bufferSpace.getSampleData (nextSpareBufferChan++);
  559. float* dest = ((float*) buf.mData) + subChan;
  560. for (int j = numSamples; --j >= 0;)
  561. {
  562. *dest = *src++;
  563. dest += buf.mNumberChannels;
  564. }
  565. }
  566. }
  567. }
  568. }
  569. #if ! JucePlugin_SilenceInProducesSilenceOut
  570. ioActionFlags &= ~kAudioUnitRenderAction_OutputIsSilence;
  571. #endif
  572. }
  573. return noErr;
  574. }
  575. protected:
  576. OSStatus HandleMidiEvent (UInt8 nStatus,
  577. UInt8 inChannel,
  578. UInt8 inData1,
  579. UInt8 inData2,
  580. long inStartFrame)
  581. {
  582. #if JucePlugin_WantsMidiInput
  583. uint8 data [4];
  584. data[0] = nStatus | inChannel;
  585. data[1] = inData1;
  586. data[2] = inData2;
  587. midiEvents.addEvent (data, 3, inStartFrame);
  588. #endif
  589. return noErr;
  590. }
  591. //==============================================================================
  592. private:
  593. AudioFilterBase* juceFilter;
  594. AudioSampleBuffer bufferSpace;
  595. float** channels;
  596. MidiBuffer midiEvents;
  597. bool prepared;
  598. SMPTETime lastSMPTETime;
  599. AUChannelInfo channelInfo [numChannelConfigs];
  600. AudioUnitEvent auEvent;
  601. };
  602. //==============================================================================
  603. class JuceAUComponentHolder : public Component
  604. {
  605. public:
  606. JuceAUComponentHolder (Component* const editorComp)
  607. {
  608. addAndMakeVisible (editorComp);
  609. setOpaque (true);
  610. setVisible (true);
  611. setBroughtToFrontOnMouseClick (true);
  612. #if ! JucePlugin_EditorRequiresKeyboardFocus
  613. setWantsKeyboardFocus (false);
  614. #endif
  615. }
  616. ~JuceAUComponentHolder()
  617. {
  618. }
  619. void resized()
  620. {
  621. if (getNumChildComponents() > 0)
  622. getChildComponent (0)->setBounds (0, 0, getWidth(), getHeight());
  623. }
  624. void paint (Graphics& g)
  625. {
  626. }
  627. };
  628. //==============================================================================
  629. class JuceAUView : public AUCarbonViewBase,
  630. public ComponentListener,
  631. public MouseListener,
  632. public Timer
  633. {
  634. AudioFilterBase* juceFilter;
  635. AudioFilterEditor* editorComp;
  636. Component* windowComp;
  637. bool recursive;
  638. int mx, my;
  639. public:
  640. JuceAUView (AudioUnitCarbonView auview)
  641. : AUCarbonViewBase (auview),
  642. juceFilter (0),
  643. editorComp (0),
  644. windowComp (0),
  645. recursive (false),
  646. mx (0),
  647. my (0)
  648. {
  649. }
  650. ~JuceAUView()
  651. {
  652. deleteUI();
  653. }
  654. ComponentResult CreateUI (Float32 inXOffset, Float32 inYOffset)
  655. {
  656. if (juceFilter == 0)
  657. {
  658. UInt32 propertySize = sizeof (&juceFilter);
  659. AudioUnitGetProperty (GetEditAudioUnit(),
  660. juceFilterObjectPropertyID,
  661. kAudioUnitScope_Global,
  662. 0,
  663. &juceFilter,
  664. &propertySize);
  665. }
  666. if (juceFilter != 0)
  667. {
  668. deleteUI();
  669. editorComp = juceFilter->createEditorIfNeeded();
  670. const int w = editorComp->getWidth();
  671. const int h = editorComp->getHeight();
  672. editorComp->setOpaque (true);
  673. editorComp->setVisible (true);
  674. windowComp = new JuceAUComponentHolder (editorComp);
  675. windowComp->setBounds ((int) inXOffset, (int) inYOffset, w, h);
  676. windowComp->addToDesktop (0, (void*) mCarbonPane);
  677. SizeControl (mCarbonPane, w, h);
  678. editorComp->addComponentListener (this);
  679. windowComp->addMouseListener (this, true);
  680. startTimer (20);
  681. }
  682. else
  683. {
  684. jassertfalse // can't get a pointer to our effect
  685. }
  686. return noErr;
  687. }
  688. void componentMovedOrResized (Component& component,
  689. bool wasMoved,
  690. bool wasResized)
  691. {
  692. if (! recursive)
  693. {
  694. recursive = true;
  695. if (editorComp != 0 && wasResized)
  696. {
  697. const int w = jmax (32, editorComp->getWidth());
  698. const int h = jmax (32, editorComp->getHeight());
  699. SizeControl (mCarbonPane, w, h);
  700. if (windowComp->getWidth() != w
  701. || windowComp->getHeight() != h)
  702. {
  703. windowComp->setSize (w, h);
  704. }
  705. editorComp->repaint();
  706. }
  707. recursive = false;
  708. }
  709. }
  710. void timerCallback()
  711. {
  712. // for some stupid Apple-related reason, mouse move events just don't seem to get sent
  713. // to the windows in an AU, so we have to bodge it here and simulate them with a
  714. // timer..
  715. if (editorComp != 0)
  716. {
  717. int x, y;
  718. Desktop::getInstance().getMousePosition (x, y);
  719. if (x != mx || y != my)
  720. {
  721. mx = x;
  722. my = y;
  723. if (! ModifierKeys::getCurrentModifiers().isAnyMouseButtonDown())
  724. {
  725. for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
  726. {
  727. ComponentPeer* const peer = ComponentPeer::getPeer (i);
  728. int rx = x, ry = y;
  729. peer->getComponent()->globalPositionToRelative (rx, ry);
  730. if (peer->contains (rx, ry, false) && peer->getComponent()->isShowing())
  731. {
  732. peer->handleMouseMove (rx, ry, Time::currentTimeMillis());
  733. break;
  734. }
  735. }
  736. }
  737. }
  738. }
  739. }
  740. void mouseMove (const MouseEvent& e)
  741. {
  742. Desktop::getInstance().getMousePosition (mx, my);
  743. startTimer (20);
  744. }
  745. private:
  746. void deleteUI()
  747. {
  748. PopupMenu::dismissAllActiveMenus();
  749. // there's some kind of component currently modal, but the host
  750. // is trying to delete our plugin..
  751. jassert (Component::getCurrentlyModalComponent() == 0);
  752. if (editorComp != 0)
  753. juceFilter->editorBeingDeleted (editorComp);
  754. deleteAndZero (editorComp);
  755. deleteAndZero (windowComp);
  756. }
  757. };
  758. //==============================================================================
  759. #define JUCE_COMPONENT_ENTRYX(Class, Name, Suffix) \
  760. extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj); \
  761. extern "C" __attribute__((visibility("default"))) ComponentResult Name ## Suffix (ComponentParameters* params, Class* obj) \
  762. { \
  763. return ComponentEntryPoint<Class>::Dispatch(params, obj); \
  764. }
  765. #define JUCE_COMPONENT_ENTRY(Class, Name, Suffix) JUCE_COMPONENT_ENTRYX(Class, Name, Suffix)
  766. JUCE_COMPONENT_ENTRY (JuceAU, JucePlugin_AUExportPrefix, Entry)
  767. JUCE_COMPONENT_ENTRY (JuceAUView, JucePlugin_AUExportPrefix, ViewEntry)