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.

1050 lines
35KB

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