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.

1014 lines
34KB

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