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.

1067 lines
36KB

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