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.

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