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.

788 lines
29KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. // Your project must contain an AppConfig.h file with your project-specific settings in it,
  19. // and your header search path must make it accessible to the module's files.
  20. #include "AppConfig.h"
  21. #include "../utility/juce_CheckSettingMacros.h"
  22. #if JucePlugin_Build_AAX && (JUCE_INCLUDED_AAX_IN_MM || defined (_WIN32) || defined (_WIN64))
  23. #ifdef _MSC_VER
  24. #include <windows.h>
  25. #else
  26. #include <Cocoa/Cocoa.h>
  27. #endif
  28. #include "../utility/juce_IncludeModuleHeaders.h"
  29. #undef Component
  30. #ifdef __clang__
  31. #pragma clang diagnostic push
  32. #pragma clang diagnostic ignored "-Wnon-virtual-dtor"
  33. #endif
  34. #include "AAX_Exports.cpp"
  35. #include "AAX_ICollection.h"
  36. #include "AAX_IComponentDescriptor.h"
  37. #include "AAX_IEffectDescriptor.h"
  38. #include "AAX_IPropertyMap.h"
  39. #include "AAX_CEffectParameters.h"
  40. #include "AAX_Errors.h"
  41. #include "AAX_CBinaryTaperDelegate.h"
  42. #include "AAX_CBinaryDisplayDelegate.h"
  43. #include "AAX_CLinearTaperDelegate.h"
  44. #include "AAX_CNumberDisplayDelegate.h"
  45. #include "AAX_CEffectGUI.h"
  46. #include "AAX_IViewContainer.h"
  47. #include "AAX_ITransport.h"
  48. #include "AAX_IMIDINode.h"
  49. #include "AAX_UtilsNative.h"
  50. #ifdef __clang__
  51. #pragma clang diagnostic pop
  52. #endif
  53. #if JUCE_WINDOWS
  54. #ifndef JucePlugin_AAXLibs_path
  55. #error "You need to define the JucePlugin_AAXLibs_path macro. (This is best done via the introjucer)"
  56. #endif
  57. #if JUCE_64BIT
  58. #define JUCE_AAX_LIB "AAXLibrary_x64"
  59. #else
  60. #define JUCE_AAX_LIB "AAXLibrary"
  61. #endif
  62. #if JUCE_DEBUG
  63. #define JUCE_AAX_LIB_PATH "\\Debug\\"
  64. #define JUCE_AAX_LIB_SUFFIX "_D"
  65. #else
  66. #define JUCE_AAX_LIB_PATH "\\Release\\"
  67. #define JUCE_AAX_LIB_SUFFIX ""
  68. #endif
  69. #pragma comment(lib, JucePlugin_AAXLibs_path JUCE_AAX_LIB_PATH JUCE_AAX_LIB JUCE_AAX_LIB_SUFFIX ".lib")
  70. #endif
  71. using juce::Component;
  72. const int32_t juceChunkType = 'juce';
  73. //==============================================================================
  74. struct AAXClasses
  75. {
  76. static void check (AAX_Result result)
  77. {
  78. jassert (result == AAX_SUCCESS); (void) result;
  79. }
  80. static AAX_EStemFormat getFormatForChans (const int numChans) noexcept
  81. {
  82. switch (numChans)
  83. {
  84. case 0: return AAX_eStemFormat_None;
  85. case 1: return AAX_eStemFormat_Mono;
  86. case 2: return AAX_eStemFormat_Stereo;
  87. case 3: return AAX_eStemFormat_LCR;
  88. case 4: return AAX_eStemFormat_Quad;
  89. case 5: return AAX_eStemFormat_5_0;
  90. case 6: return AAX_eStemFormat_5_1;
  91. case 7: return AAX_eStemFormat_6_1;
  92. case 8: return AAX_eStemFormat_7_1_DTS;
  93. default: jassertfalse; break; // hmm - not a valid number of chans..
  94. }
  95. return AAX_eStemFormat_None;
  96. }
  97. static int getNumChannelsForStemFormat (AAX_EStemFormat format) noexcept
  98. {
  99. switch (format)
  100. {
  101. case AAX_eStemFormat_None: return 0;
  102. case AAX_eStemFormat_Mono: return 1;
  103. case AAX_eStemFormat_Stereo: return 2;
  104. case AAX_eStemFormat_LCR: return 3;
  105. case AAX_eStemFormat_Quad: return 4;
  106. case AAX_eStemFormat_5_0: return 5;
  107. case AAX_eStemFormat_5_1: return 6;
  108. case AAX_eStemFormat_6_1: return 7;
  109. case AAX_eStemFormat_7_1_DTS: return 8;
  110. default: jassertfalse; break; // hmm - not a valid number of chans..
  111. }
  112. return 0;
  113. }
  114. //==============================================================================
  115. struct JUCELibraryRefCount
  116. {
  117. JUCELibraryRefCount() { if (getCount()++ == 0) initialise(); }
  118. ~JUCELibraryRefCount() { if (--getCount() == 0) shutdown(); }
  119. private:
  120. static void initialise()
  121. {
  122. initialiseJuce_GUI();
  123. }
  124. static void shutdown()
  125. {
  126. shutdownJuce_GUI();
  127. }
  128. int& getCount() noexcept
  129. {
  130. static int count = 0;
  131. return count;
  132. }
  133. };
  134. //==============================================================================
  135. class JuceAAX_Processor;
  136. struct PluginInstanceInfo
  137. {
  138. PluginInstanceInfo (JuceAAX_Processor& p) : parameters (p) {}
  139. JuceAAX_Processor& parameters;
  140. JUCE_DECLARE_NON_COPYABLE (PluginInstanceInfo)
  141. };
  142. //==============================================================================
  143. struct JUCEAlgorithmContext
  144. {
  145. float** inputChannels;
  146. float** outputChannels;
  147. int32_t* bufferSize;
  148. int32_t* bypass;
  149. AAX_IMIDINode* midiNodeIn;
  150. PluginInstanceInfo* pluginInstance;
  151. int32_t* isPrepared;
  152. };
  153. struct JUCEAlgorithmIDs
  154. {
  155. enum
  156. {
  157. inputChannels = AAX_FIELD_INDEX (JUCEAlgorithmContext, inputChannels),
  158. outputChannels = AAX_FIELD_INDEX (JUCEAlgorithmContext, outputChannels),
  159. bufferSize = AAX_FIELD_INDEX (JUCEAlgorithmContext, bufferSize),
  160. bypass = AAX_FIELD_INDEX (JUCEAlgorithmContext, bypass),
  161. midiNodeIn = AAX_FIELD_INDEX (JUCEAlgorithmContext, midiNodeIn),
  162. pluginInstance = AAX_FIELD_INDEX (JUCEAlgorithmContext, pluginInstance),
  163. preparedFlag = AAX_FIELD_INDEX (JUCEAlgorithmContext, isPrepared)
  164. };
  165. };
  166. //==============================================================================
  167. class JuceAAX_GUI : public AAX_CEffectGUI
  168. {
  169. public:
  170. JuceAAX_GUI() {}
  171. virtual ~JuceAAX_GUI() { DeleteViewContainer(); }
  172. static AAX_IEffectGUI* AAX_CALLBACK Create() { return new JuceAAX_GUI(); }
  173. void CreateViewContents()
  174. {
  175. if (component == nullptr)
  176. {
  177. if (JuceAAX_Processor* params = dynamic_cast <JuceAAX_Processor*> (GetEffectParameters()))
  178. component = new ContentWrapperComponent (*this, params->getPluginInstance());
  179. else
  180. jassertfalse;
  181. }
  182. }
  183. void CreateViewContainer()
  184. {
  185. CreateViewContents();
  186. if (void* nativeViewToAttachTo = GetViewContainerPtr())
  187. {
  188. #if JUCE_MAC
  189. if (GetViewContainerType() == AAX_eViewContainer_Type_NSView)
  190. #else
  191. if (GetViewContainerType() == AAX_eViewContainer_Type_HWND)
  192. #endif
  193. {
  194. component->setVisible (true);
  195. component->addToDesktop (0, nativeViewToAttachTo);
  196. }
  197. }
  198. }
  199. void DeleteViewContainer()
  200. {
  201. if (component != nullptr)
  202. {
  203. JUCE_AUTORELEASEPOOL
  204. component->removeFromDesktop();
  205. component = nullptr;
  206. }
  207. }
  208. virtual AAX_Result GetViewSize (AAX_Point* viewSize) const
  209. {
  210. if (component != nullptr)
  211. {
  212. viewSize->horz = (float) component->getWidth();
  213. viewSize->vert = (float) component->getHeight();
  214. return AAX_SUCCESS;
  215. }
  216. return AAX_ERROR_NULL_OBJECT;
  217. }
  218. AAX_Result ParameterUpdated (AAX_CParamID /*paramID*/)
  219. {
  220. return AAX_SUCCESS;
  221. }
  222. AAX_Result SetControlHighlightInfo (AAX_CParamID /*paramID*/, AAX_CBoolean /*isHighlighted*/, AAX_EHighlightColor)
  223. {
  224. return AAX_SUCCESS;
  225. }
  226. private:
  227. class ContentWrapperComponent : public juce::Component
  228. {
  229. public:
  230. ContentWrapperComponent (JuceAAX_GUI& gui, AudioProcessor& plugin)
  231. : owner (gui)
  232. {
  233. setOpaque (true);
  234. addAndMakeVisible (pluginEditor = plugin.createEditorIfNeeded());
  235. setBounds (pluginEditor->getLocalBounds());
  236. setBroughtToFrontOnMouseClick (true);
  237. }
  238. ~ContentWrapperComponent()
  239. {
  240. if (pluginEditor != nullptr)
  241. {
  242. PopupMenu::dismissAllActiveMenus();
  243. pluginEditor->getAudioProcessor()->editorBeingDeleted (pluginEditor);
  244. }
  245. }
  246. void paint (Graphics& g)
  247. {
  248. g.fillAll (Colours::black);
  249. }
  250. void childBoundsChanged (Component*)
  251. {
  252. if (pluginEditor != nullptr)
  253. {
  254. const int w = pluginEditor->getWidth();
  255. const int h = pluginEditor->getHeight();
  256. setSize (w, h);
  257. AAX_Point newSize ((float) h, (float) w);
  258. owner.GetViewContainer()->SetViewSize (newSize);
  259. }
  260. }
  261. private:
  262. ScopedPointer<AudioProcessorEditor> pluginEditor;
  263. JuceAAX_GUI& owner;
  264. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContentWrapperComponent)
  265. };
  266. ScopedPointer<ContentWrapperComponent> component;
  267. JUCELibraryRefCount juceCount;
  268. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceAAX_GUI)
  269. };
  270. //==============================================================================
  271. class JuceAAX_Processor : public AAX_CEffectParameters,
  272. public juce::AudioPlayHead,
  273. public AudioProcessorListener
  274. {
  275. public:
  276. JuceAAX_Processor()
  277. {
  278. pluginInstance = createPluginFilterOfType (AudioProcessor::wrapperType_AAX);
  279. pluginInstance->setPlayHead (this);
  280. pluginInstance->addListener (this);
  281. AAX_CEffectParameters::GetNumberOfChunks (&juceChunkIndex);
  282. }
  283. static AAX_CEffectParameters* AAX_CALLBACK Create() { return new JuceAAX_Processor(); }
  284. AAX_Result EffectInit()
  285. {
  286. addBypassParameter();
  287. addAudioProcessorParameters();
  288. preparePlugin();
  289. return AAX_SUCCESS;
  290. }
  291. AAX_Result GetNumberOfChunks (int32_t* numChunks) const
  292. {
  293. // The juceChunk is the last chunk.
  294. *numChunks = juceChunkIndex + 1;
  295. return AAX_SUCCESS;
  296. }
  297. AAX_Result GetChunkIDFromIndex (int32_t index, AAX_CTypeID* chunkID) const
  298. {
  299. if (index != juceChunkIndex)
  300. return AAX_CEffectParameters::GetChunkIDFromIndex (index, chunkID);
  301. *chunkID = juceChunkType;
  302. return AAX_SUCCESS;
  303. }
  304. AAX_Result GetChunkSize (AAX_CTypeID chunkID, uint32_t* oSize) const
  305. {
  306. if (chunkID != juceChunkType)
  307. return AAX_CEffectParameters::GetChunkSize (chunkID, oSize);
  308. tempFilterData.setSize (0);
  309. pluginInstance->getStateInformation (tempFilterData);
  310. *oSize = (uint32_t) tempFilterData.getSize();
  311. return AAX_SUCCESS;
  312. }
  313. AAX_Result GetChunk (AAX_CTypeID chunkID, AAX_SPlugInChunk* oChunk) const
  314. {
  315. if (chunkID != juceChunkType)
  316. return AAX_CEffectParameters::GetChunk (chunkID, oChunk);
  317. if (tempFilterData.getSize() == 0)
  318. pluginInstance->getStateInformation (tempFilterData);
  319. oChunk->fSize = (uint32_t) tempFilterData.getSize();
  320. tempFilterData.copyTo (oChunk->fData, 0, tempFilterData.getSize());
  321. tempFilterData.setSize (0);
  322. return AAX_SUCCESS;
  323. }
  324. AAX_Result SetChunk (AAX_CTypeID chunkID, const AAX_SPlugInChunk* chunk)
  325. {
  326. if (chunkID != juceChunkType)
  327. return AAX_CEffectParameters::SetChunk (chunkID, chunk);
  328. pluginInstance->setStateInformation ((void*) chunk->fData, chunk->fSize);
  329. return AAX_SUCCESS;
  330. }
  331. AAX_Result ResetFieldData (AAX_CFieldIndex fieldIndex, void* data, uint32_t dataSize) const
  332. {
  333. switch (fieldIndex)
  334. {
  335. case JUCEAlgorithmIDs::pluginInstance:
  336. {
  337. const size_t numObjects = dataSize / sizeof (PluginInstanceInfo);
  338. PluginInstanceInfo* const objects = static_cast <PluginInstanceInfo*> (data);
  339. jassert (numObjects == 1); // not sure how to handle more than one..
  340. for (size_t i = 0; i < numObjects; ++i)
  341. new (objects + i) PluginInstanceInfo (const_cast<JuceAAX_Processor&> (*this));
  342. break;
  343. }
  344. case JUCEAlgorithmIDs::preparedFlag:
  345. {
  346. preparePlugin();
  347. const size_t numObjects = dataSize / sizeof (uint32_t);
  348. uint32_t* const objects = static_cast <uint32_t*> (data);
  349. for (size_t i = 0; i < numObjects; ++i)
  350. new (objects + i) uint32_t (1);
  351. break;
  352. }
  353. }
  354. return AAX_SUCCESS;
  355. //return AAX_ERROR_INVALID_FIELD_INDEX;
  356. }
  357. AAX_Result UpdateParameterNormalizedValue (AAX_CParamID paramID, double value, AAX_EUpdateSource source)
  358. {
  359. AAX_Result result = AAX_CEffectParameters::UpdateParameterNormalizedValue (paramID, value, source);
  360. if (AAX::IsParameterIDEqual (paramID, cDefaultMasterBypassID) == false)
  361. {
  362. const int parameterIndex = atoi (paramID);
  363. pluginInstance->setParameter (parameterIndex, (float) value);
  364. }
  365. return result;
  366. }
  367. AudioProcessor& getPluginInstance() const noexcept { return *pluginInstance; }
  368. bool getCurrentPosition (juce::AudioPlayHead::CurrentPositionInfo& info)
  369. {
  370. const AAX_ITransport& transport = *Transport();
  371. check (transport.GetCurrentTempo (&info.bpm));
  372. int32_t num, denom;
  373. transport.GetCurrentMeter (&num, &denom);
  374. info.timeSigNumerator = num;
  375. info.timeSigDenominator = denom;
  376. check (transport.GetCurrentNativeSampleLocation (&info.timeInSamples));
  377. info.timeInSeconds = info.timeInSamples / getSampleRate();
  378. int64_t ticks;
  379. check (transport.GetCurrentTickPosition (&ticks));
  380. info.ppqPosition = ticks / 960000.0;
  381. int64_t loopStartTick, loopEndTick;
  382. check (transport.GetCurrentLoopPosition (&info.isLooping, &loopStartTick, &loopEndTick));
  383. info.ppqLoopStart = loopStartTick / 960000.0;
  384. info.ppqLoopEnd = loopEndTick / 960000.0;
  385. // No way to get these: (?)
  386. info.isRecording = false;
  387. info.ppqPositionOfLastBarStart = 0;
  388. info.editOriginTime = 0;
  389. return true;
  390. }
  391. void audioProcessorParameterChanged (AudioProcessor* /*processor*/, int parameterIndex, float newValue)
  392. {
  393. SetParameterNormalizedValue (IndexAsParamID (parameterIndex), (double) newValue);
  394. }
  395. void audioProcessorChanged (AudioProcessor* /*processor*/)
  396. {
  397. // TODO
  398. }
  399. void audioProcessorParameterChangeGestureBegin (AudioProcessor* /*processor*/, int parameterIndex)
  400. {
  401. TouchParameter (IndexAsParamID (parameterIndex));
  402. }
  403. void audioProcessorParameterChangeGestureEnd (AudioProcessor* /*processor*/, int parameterIndex)
  404. {
  405. ReleaseParameter (IndexAsParamID (parameterIndex));
  406. }
  407. void process (const float* const* inputs, float* const* outputs, const int bufferSize,
  408. const bool bypass, AAX_IMIDINode* midiNodeIn)
  409. {
  410. const int numIns = pluginInstance->getNumInputChannels();
  411. const int numOuts = pluginInstance->getNumOutputChannels();
  412. if (numOuts >= numIns)
  413. {
  414. for (int i = 0; i < numIns; ++i)
  415. memcpy (outputs[i], inputs[i], bufferSize * sizeof (float));
  416. process (outputs, numOuts, bufferSize, bypass, midiNodeIn);
  417. }
  418. else
  419. {
  420. if (channelList.size() <= numIns)
  421. channelList.insertMultiple (-1, nullptr, 1 + numIns - channelList.size());
  422. float** channels = channelList.getRawDataPointer();
  423. for (int i = 0; i < numOuts; ++i)
  424. {
  425. memcpy (outputs[i], inputs[i], bufferSize * sizeof (float));
  426. channels[i] = outputs[i];
  427. }
  428. for (int i = numOuts; i < numIns; ++i)
  429. channels[i] = const_cast <float*> (inputs[i]);
  430. process (channels, numIns, bufferSize, bypass, midiNodeIn);
  431. }
  432. }
  433. private:
  434. struct IndexAsParamID
  435. {
  436. inline explicit IndexAsParamID (int i) noexcept : index (i) {}
  437. operator AAX_CParamID() noexcept
  438. {
  439. jassert (index >= 0);
  440. char* t = name + sizeof (name);
  441. *--t = 0;
  442. int v = index;
  443. do
  444. {
  445. *--t = (char) ('0' + (v % 10));
  446. v /= 10;
  447. } while (v > 0);
  448. return static_cast <AAX_CParamID> (t);
  449. }
  450. private:
  451. int index;
  452. char name[32];
  453. JUCE_DECLARE_NON_COPYABLE (IndexAsParamID)
  454. };
  455. void process (float* const* channels, const int numChans, const int bufferSize,
  456. const bool bypass, AAX_IMIDINode* midiNodeIn)
  457. {
  458. AudioSampleBuffer buffer (channels, numChans, bufferSize);
  459. midiBuffer.clear();
  460. #if JucePlugin_WantsMidiInput
  461. {
  462. AAX_CMidiStream* const midiStream = midiNodeIn->GetNodeBuffer();
  463. const uint32_t numMidiEvents = midiStream->mBufferSize;
  464. for (uint32_t i = 0; i < numMidiEvents; ++i)
  465. {
  466. // (This 8-byte alignment is a workaround to a bug in the AAX SDK. Hopefully can be
  467. // removed in future when the packet structure size is fixed)
  468. const AAX_CMidiPacket& m = *addBytesToPointer (midiStream->mBuffer,
  469. i * ((sizeof (AAX_CMidiPacket) + 7) & ~7));
  470. jassert ((int) m.mTimestamp < bufferSize);
  471. midiBuffer.addEvent (m.mData, (int) m.mLength,
  472. jlimit (0, (int) bufferSize - 1, (int) m.mTimestamp));
  473. }
  474. }
  475. #endif
  476. {
  477. const ScopedLock sl (pluginInstance->getCallbackLock());
  478. if (bypass)
  479. pluginInstance->processBlockBypassed (buffer, midiBuffer);
  480. else
  481. pluginInstance->processBlock (buffer, midiBuffer);
  482. }
  483. }
  484. void addBypassParameter()
  485. {
  486. AAX_IParameter* masterBypass = new AAX_CParameter<bool> (cDefaultMasterBypassID,
  487. AAX_CString ("Master Bypass"),
  488. false,
  489. AAX_CBinaryTaperDelegate<bool>(),
  490. AAX_CBinaryDisplayDelegate<bool> ("bypass", "on"),
  491. true);
  492. masterBypass->SetNumberOfSteps (2);
  493. masterBypass->SetType (AAX_eParameterType_Discrete);
  494. mParameterManager.AddParameter (masterBypass);
  495. mPacketDispatcher.RegisterPacket (cDefaultMasterBypassID, JUCEAlgorithmIDs::bypass);
  496. }
  497. void addAudioProcessorParameters()
  498. {
  499. AudioProcessor& audioProcessor = getPluginInstance();
  500. const int numParameters = audioProcessor.getNumParameters();
  501. for (int parameterIndex = 0; parameterIndex < numParameters; ++parameterIndex)
  502. {
  503. if (audioProcessor.isParameterAutomatable (parameterIndex))
  504. {
  505. AAX_IParameter* parameter
  506. = new AAX_CParameter<float> (IndexAsParamID (parameterIndex),
  507. audioProcessor.getParameterName (parameterIndex).toUTF8().getAddress(),
  508. audioProcessor.getParameter (parameterIndex),
  509. AAX_CLinearTaperDelegate<float, 0>(),
  510. AAX_CNumberDisplayDelegate<float, 3>(),
  511. true);
  512. parameter->SetNumberOfSteps (0x7fffffff);
  513. parameter->SetType (AAX_eParameterType_Continuous);
  514. mParameterManager.AddParameter (parameter);
  515. }
  516. }
  517. }
  518. void preparePlugin() const
  519. {
  520. AAX_EStemFormat inputStemFormat = AAX_eStemFormat_None;
  521. check (Controller()->GetInputStemFormat (&inputStemFormat));
  522. const int numberOfInputChannels = getNumChannelsForStemFormat (inputStemFormat);
  523. AAX_EStemFormat outputStemFormat = AAX_eStemFormat_None;
  524. check (Controller()->GetOutputStemFormat (&outputStemFormat));
  525. const int numberOfOutputChannels = getNumChannelsForStemFormat (outputStemFormat);
  526. int32_t bufferSize = 0;
  527. check (Controller()->GetSignalLatency (&bufferSize));
  528. const AAX_CSampleRate sampleRate = getSampleRate();
  529. AudioProcessor& audioProcessor = getPluginInstance();
  530. audioProcessor.setPlayConfigDetails (numberOfInputChannels, numberOfOutputChannels, sampleRate, bufferSize);
  531. audioProcessor.prepareToPlay (sampleRate, bufferSize);
  532. }
  533. AAX_CSampleRate getSampleRate() const
  534. {
  535. AAX_CSampleRate sampleRate;
  536. check (Controller()->GetSampleRate (&sampleRate));
  537. return sampleRate;
  538. }
  539. JUCELibraryRefCount juceCount;
  540. ScopedPointer<AudioProcessor> pluginInstance;
  541. MidiBuffer midiBuffer;
  542. Array<float*> channelList;
  543. int32_t juceChunkIndex;
  544. // tempFilterData is initialized in GetChunkSize.
  545. // To avoid generating it again in GetChunk, we keep it as a member.
  546. mutable juce::MemoryBlock tempFilterData;
  547. JUCE_DECLARE_NON_COPYABLE (JuceAAX_Processor)
  548. };
  549. //==============================================================================
  550. static void AAX_CALLBACK algorithmProcessCallback (JUCEAlgorithmContext* const instancesBegin[],
  551. const void* const instancesEnd)
  552. {
  553. for (JUCEAlgorithmContext* const* iter = instancesBegin; iter < instancesEnd; ++iter)
  554. {
  555. const JUCEAlgorithmContext& i = **iter;
  556. i.pluginInstance->parameters.process (i.inputChannels, i.outputChannels,
  557. *(i.bufferSize), *(i.bypass) != 0,
  558. i.midiNodeIn);
  559. }
  560. }
  561. //==============================================================================
  562. static void createDescriptor (AAX_IComponentDescriptor& desc, int channelConfigIndex,
  563. int numInputs, int numOutputs)
  564. {
  565. check (desc.AddAudioIn (JUCEAlgorithmIDs::inputChannels));
  566. check (desc.AddAudioOut (JUCEAlgorithmIDs::outputChannels));
  567. check (desc.AddAudioBufferLength (JUCEAlgorithmIDs::bufferSize));
  568. check (desc.AddDataInPort (JUCEAlgorithmIDs::bypass, sizeof (int32_t)));
  569. #if JucePlugin_WantsMidiInput
  570. check (desc.AddMIDINode (JUCEAlgorithmIDs::midiNodeIn, AAX_eMIDINodeType_LocalInput,
  571. JucePlugin_Name, 0xffff));
  572. #endif
  573. check (desc.AddPrivateData (JUCEAlgorithmIDs::pluginInstance, sizeof (PluginInstanceInfo)));
  574. // Create a property map
  575. AAX_IPropertyMap* const properties = desc.NewPropertyMap();
  576. jassert (properties != nullptr);
  577. properties->AddProperty (AAX_eProperty_ManufacturerID, JucePlugin_AAXManufacturerCode);
  578. properties->AddProperty (AAX_eProperty_ProductID, JucePlugin_AAXProductId);
  579. #if JucePlugin_AAXDisableBypass
  580. properties->AddProperty (AAX_eProperty_CanBypass, false);
  581. #else
  582. properties->AddProperty (AAX_eProperty_CanBypass, true);
  583. #endif
  584. properties->AddProperty (AAX_eProperty_InputStemFormat, getFormatForChans (numInputs));
  585. properties->AddProperty (AAX_eProperty_OutputStemFormat, getFormatForChans (numOutputs));
  586. // This value needs to match the RTAS wrapper's Type ID, so that
  587. // the host knows that the RTAS/AAX plugins are equivalent.
  588. properties->AddProperty (AAX_eProperty_PlugInID_Native, 'jcaa' + channelConfigIndex);
  589. check (desc.AddProcessProc_Native (algorithmProcessCallback, properties));
  590. }
  591. static void getPlugInDescription (AAX_IEffectDescriptor& descriptor)
  592. {
  593. descriptor.AddName (JucePlugin_Desc);
  594. descriptor.AddName (JucePlugin_Name);
  595. descriptor.AddCategory (JucePlugin_AAXCategory);
  596. check (descriptor.AddProcPtr ((void*) JuceAAX_GUI::Create, kAAX_ProcPtrID_Create_EffectGUI));
  597. check (descriptor.AddProcPtr ((void*) JuceAAX_Processor::Create, kAAX_ProcPtrID_Create_EffectParameters));
  598. const short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations };
  599. const int numConfigs = numElementsInArray (channelConfigs);
  600. // You need to actually add some configurations to the JucePlugin_PreferredChannelConfigurations
  601. // value in your JucePluginCharacteristics.h file..
  602. jassert (numConfigs > 0);
  603. for (int i = 0; i < numConfigs; ++i)
  604. {
  605. if (AAX_IComponentDescriptor* const desc = descriptor.NewComponentDescriptor())
  606. {
  607. createDescriptor (*desc, i,
  608. channelConfigs [i][0],
  609. channelConfigs [i][1]);
  610. check (descriptor.AddComponent (desc));
  611. }
  612. }
  613. }
  614. };
  615. //==============================================================================
  616. AAX_Result JUCE_CDECL GetEffectDescriptions (AAX_ICollection*);
  617. AAX_Result JUCE_CDECL GetEffectDescriptions (AAX_ICollection* collection)
  618. {
  619. AAXClasses::JUCELibraryRefCount libraryRefCount;
  620. if (AAX_IEffectDescriptor* const descriptor = collection->NewDescriptor())
  621. {
  622. AAXClasses::getPlugInDescription (*descriptor);
  623. collection->AddEffect (JUCE_STRINGIFY (JucePlugin_AAXIdentifier), descriptor);
  624. collection->SetManufacturerName (JucePlugin_Manufacturer);
  625. collection->AddPackageName (JucePlugin_Desc);
  626. collection->AddPackageName (JucePlugin_Name);
  627. collection->SetPackageVersion (JucePlugin_VersionCode);
  628. return AAX_SUCCESS;
  629. }
  630. return AAX_ERROR_NULL_OBJECT;
  631. }
  632. #endif