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.

735 lines
27KB

  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_UtilsNative.h"
  49. #ifdef __clang__
  50. #pragma clang diagnostic pop
  51. #endif
  52. using juce::Component;
  53. const int32_t juceChunkType = 'juce';
  54. //==============================================================================
  55. struct AAXClasses
  56. {
  57. static void check (AAX_Result result)
  58. {
  59. jassert (result == AAX_SUCCESS); (void) result;
  60. }
  61. static AAX_EStemFormat getFormatForChans (const int numChans) noexcept
  62. {
  63. switch (numChans)
  64. {
  65. case 0: return AAX_eStemFormat_None;
  66. case 1: return AAX_eStemFormat_Mono;
  67. case 2: return AAX_eStemFormat_Stereo;
  68. case 3: return AAX_eStemFormat_LCR;
  69. case 4: return AAX_eStemFormat_Quad;
  70. case 5: return AAX_eStemFormat_5_0;
  71. case 6: return AAX_eStemFormat_5_1;
  72. case 7: return AAX_eStemFormat_6_1;
  73. case 8: return AAX_eStemFormat_7_1_DTS;
  74. default: jassertfalse; break; // hmm - not a valid number of chans..
  75. }
  76. return AAX_eStemFormat_None;
  77. }
  78. static int getNumChannelsForStemFormat (AAX_EStemFormat format) noexcept
  79. {
  80. switch (format)
  81. {
  82. case AAX_eStemFormat_None: return 0;
  83. case AAX_eStemFormat_Mono: return 1;
  84. case AAX_eStemFormat_Stereo: return 2;
  85. case AAX_eStemFormat_LCR: return 3;
  86. case AAX_eStemFormat_Quad: return 4;
  87. case AAX_eStemFormat_5_0: return 5;
  88. case AAX_eStemFormat_5_1: return 6;
  89. case AAX_eStemFormat_6_1: return 7;
  90. case AAX_eStemFormat_7_1_DTS: return 8;
  91. default: jassertfalse; break; // hmm - not a valid number of chans..
  92. }
  93. return 0;
  94. }
  95. //==============================================================================
  96. struct JUCELibraryRefCount
  97. {
  98. JUCELibraryRefCount() { if (getCount()++ == 0) initialise(); }
  99. ~JUCELibraryRefCount() { if (--getCount() == 0) shutdown(); }
  100. private:
  101. static void initialise()
  102. {
  103. initialiseJuce_GUI();
  104. }
  105. static void shutdown()
  106. {
  107. shutdownJuce_GUI();
  108. }
  109. int& getCount() noexcept
  110. {
  111. static int count = 0;
  112. return count;
  113. }
  114. };
  115. //==============================================================================
  116. class JuceAAX_Processor;
  117. struct PluginInstanceInfo
  118. {
  119. PluginInstanceInfo (JuceAAX_Processor& p) : parameters (p) {}
  120. JuceAAX_Processor& parameters;
  121. JUCE_DECLARE_NON_COPYABLE (PluginInstanceInfo)
  122. };
  123. //==============================================================================
  124. struct JUCEAlgorithmContext
  125. {
  126. float** inputChannels;
  127. float** outputChannels;
  128. int32_t* bufferSize;
  129. int32_t* bypass;
  130. PluginInstanceInfo* pluginInstance;
  131. int32_t* isPrepared;
  132. };
  133. struct JUCEAlgorithmIDs
  134. {
  135. enum
  136. {
  137. inputChannels = AAX_FIELD_INDEX (JUCEAlgorithmContext, inputChannels),
  138. outputChannels = AAX_FIELD_INDEX (JUCEAlgorithmContext, outputChannels),
  139. bufferSize = AAX_FIELD_INDEX (JUCEAlgorithmContext, bufferSize),
  140. bypass = AAX_FIELD_INDEX (JUCEAlgorithmContext, bypass),
  141. pluginInstance = AAX_FIELD_INDEX (JUCEAlgorithmContext, pluginInstance),
  142. preparedFlag = AAX_FIELD_INDEX (JUCEAlgorithmContext, isPrepared)
  143. };
  144. };
  145. //==============================================================================
  146. class JuceAAX_GUI : public AAX_CEffectGUI
  147. {
  148. public:
  149. JuceAAX_GUI() {}
  150. virtual ~JuceAAX_GUI() { DeleteViewContainer(); }
  151. static AAX_IEffectGUI* AAX_CALLBACK Create() { return new JuceAAX_GUI(); }
  152. void CreateViewContents()
  153. {
  154. if (component == nullptr)
  155. {
  156. if (JuceAAX_Processor* params = dynamic_cast <JuceAAX_Processor*> (GetEffectParameters()))
  157. component = new ContentWrapperComponent (*this, params->getPluginInstance());
  158. else
  159. jassertfalse;
  160. }
  161. }
  162. void CreateViewContainer()
  163. {
  164. CreateViewContents();
  165. if (void* nativeViewToAttachTo = GetViewContainerPtr())
  166. {
  167. #if JUCE_MAC
  168. if (GetViewContainerType() == AAX_eViewContainer_Type_NSView)
  169. #else
  170. if (GetViewContainerType() == AAX_eViewContainer_Type_HWND)
  171. #endif
  172. {
  173. component->setVisible (true);
  174. component->addToDesktop (0, nativeViewToAttachTo);
  175. }
  176. }
  177. }
  178. void DeleteViewContainer()
  179. {
  180. if (component != nullptr)
  181. {
  182. JUCE_AUTORELEASEPOOL
  183. component->removeFromDesktop();
  184. component = nullptr;
  185. }
  186. }
  187. virtual AAX_Result GetViewSize (AAX_Point* const viewSize) const
  188. {
  189. if (component != nullptr)
  190. {
  191. viewSize->horz = (float) component->getWidth();
  192. viewSize->vert = (float) component->getHeight();
  193. return AAX_SUCCESS;
  194. }
  195. return AAX_ERROR_NULL_OBJECT;
  196. }
  197. AAX_Result ParameterUpdated (AAX_CParamID /*paramID*/)
  198. {
  199. return AAX_SUCCESS;
  200. }
  201. AAX_Result SetControlHighlightInfo (AAX_CParamID /*paramID*/, AAX_CBoolean /*isHighlighted*/, AAX_EHighlightColor)
  202. {
  203. return AAX_SUCCESS;
  204. }
  205. private:
  206. class ContentWrapperComponent : public juce::Component
  207. {
  208. public:
  209. ContentWrapperComponent (JuceAAX_GUI& gui, AudioProcessor& plugin)
  210. : owner (gui)
  211. {
  212. setOpaque (true);
  213. addAndMakeVisible (pluginEditor = plugin.createEditorIfNeeded());
  214. setBounds (pluginEditor->getLocalBounds());
  215. setBroughtToFrontOnMouseClick (true);
  216. }
  217. ~ContentWrapperComponent()
  218. {
  219. if (pluginEditor != nullptr)
  220. {
  221. PopupMenu::dismissAllActiveMenus();
  222. pluginEditor->getAudioProcessor()->editorBeingDeleted (pluginEditor);
  223. }
  224. }
  225. void paint (Graphics& g)
  226. {
  227. g.fillAll (Colours::black);
  228. }
  229. void childBoundsChanged (Component*)
  230. {
  231. if (pluginEditor != nullptr)
  232. {
  233. const int w = pluginEditor->getWidth();
  234. const int h = pluginEditor->getHeight();
  235. setSize (w, h);
  236. AAX_Point newSize ((float) h, (float) w);
  237. owner.GetViewContainer()->SetViewSize (newSize);
  238. }
  239. }
  240. private:
  241. ScopedPointer<AudioProcessorEditor> pluginEditor;
  242. JuceAAX_GUI& owner;
  243. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContentWrapperComponent)
  244. };
  245. ScopedPointer<ContentWrapperComponent> component;
  246. JUCELibraryRefCount juceCount;
  247. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceAAX_GUI)
  248. };
  249. //==============================================================================
  250. class JuceAAX_Processor : public AAX_CEffectParameters,
  251. public juce::AudioPlayHead,
  252. public AudioProcessorListener
  253. {
  254. public:
  255. JuceAAX_Processor()
  256. {
  257. pluginInstance = createPluginFilterOfType (AudioProcessor::wrapperType_AAX);
  258. pluginInstance->setPlayHead (this);
  259. pluginInstance->addListener (this);
  260. AAX_CEffectParameters::GetNumberOfChunks (&juceChunkIndex);
  261. }
  262. static AAX_CEffectParameters* AAX_CALLBACK Create() { return new JuceAAX_Processor(); }
  263. AAX_Result EffectInit()
  264. {
  265. addBypassParameter();
  266. addAudioProcessorParameters();
  267. preparePlugin();
  268. return AAX_SUCCESS;
  269. }
  270. AAX_Result GetNumberOfChunks (int32_t* numChunks) const
  271. {
  272. // The juceChunk is the last chunk.
  273. *numChunks = juceChunkIndex + 1;
  274. return AAX_SUCCESS;
  275. }
  276. AAX_Result GetChunkIDFromIndex (int32_t index, AAX_CTypeID* chunkID) const
  277. {
  278. if (index != juceChunkIndex)
  279. return AAX_CEffectParameters::GetChunkIDFromIndex (index, chunkID);
  280. *chunkID = juceChunkType;
  281. return AAX_SUCCESS;
  282. }
  283. AAX_Result GetChunkSize (AAX_CTypeID chunkID, uint32_t* oSize) const
  284. {
  285. if (chunkID != juceChunkType)
  286. return AAX_CEffectParameters::GetChunkSize (chunkID, oSize);
  287. tempFilterData.setSize (0);
  288. pluginInstance->getStateInformation (tempFilterData);
  289. *oSize = (uint32_t) tempFilterData.getSize();
  290. return AAX_SUCCESS;
  291. }
  292. AAX_Result GetChunk (AAX_CTypeID chunkID, AAX_SPlugInChunk* oChunk) const
  293. {
  294. if (chunkID != juceChunkType)
  295. return AAX_CEffectParameters::GetChunk (chunkID, oChunk);
  296. if (tempFilterData.getSize() == 0)
  297. pluginInstance->getStateInformation (tempFilterData);
  298. oChunk->fSize = (uint32_t) tempFilterData.getSize();
  299. tempFilterData.copyTo (oChunk->fData, 0, tempFilterData.getSize());
  300. tempFilterData.setSize (0);
  301. return AAX_SUCCESS;
  302. }
  303. AAX_Result SetChunk (AAX_CTypeID chunkID, const AAX_SPlugInChunk* chunk)
  304. {
  305. if (chunkID != juceChunkType)
  306. return AAX_CEffectParameters::SetChunk (chunkID, chunk);
  307. pluginInstance->setStateInformation ((void*) chunk->fData, chunk->fSize);
  308. return AAX_SUCCESS;
  309. }
  310. AAX_Result ResetFieldData (AAX_CFieldIndex fieldIndex, void* data, uint32_t dataSize) const
  311. {
  312. switch (fieldIndex)
  313. {
  314. case JUCEAlgorithmIDs::pluginInstance:
  315. {
  316. const size_t numObjects = dataSize / sizeof (PluginInstanceInfo);
  317. PluginInstanceInfo* const objects = static_cast <PluginInstanceInfo*> (data);
  318. jassert (numObjects == 1); // not sure how to handle more than one..
  319. for (size_t i = 0; i < numObjects; ++i)
  320. new (objects + i) PluginInstanceInfo (const_cast<JuceAAX_Processor&> (*this));
  321. break;
  322. }
  323. case JUCEAlgorithmIDs::preparedFlag:
  324. {
  325. preparePlugin();
  326. const size_t numObjects = dataSize / sizeof (uint32_t);
  327. uint32_t* const objects = static_cast <uint32_t*> (data);
  328. for (size_t i = 0; i < numObjects; ++i)
  329. new (objects + i) uint32_t (1);
  330. break;
  331. }
  332. }
  333. return AAX_SUCCESS;
  334. //return AAX_ERROR_INVALID_FIELD_INDEX;
  335. }
  336. AAX_Result UpdateParameterNormalizedValue (AAX_CParamID paramID, double value, AAX_EUpdateSource source)
  337. {
  338. AAX_Result result = AAX_CEffectParameters::UpdateParameterNormalizedValue (paramID, value, source);
  339. if (AAX::IsParameterIDEqual (paramID, cDefaultMasterBypassID) == false)
  340. {
  341. const int parameterIndex = atoi (paramID);
  342. pluginInstance->setParameter (parameterIndex, (float) value);
  343. }
  344. return result;
  345. }
  346. AudioProcessor& getPluginInstance() const noexcept { return *pluginInstance; }
  347. bool getCurrentPosition (juce::AudioPlayHead::CurrentPositionInfo& info)
  348. {
  349. const AAX_ITransport& transport = *Transport();
  350. check (transport.GetCurrentTempo (&info.bpm));
  351. int32_t num, denom;
  352. transport.GetCurrentMeter (&num, &denom);
  353. info.timeSigNumerator = num;
  354. info.timeSigDenominator = denom;
  355. check (transport.GetCurrentNativeSampleLocation (&info.timeInSamples));
  356. info.timeInSeconds = info.timeInSamples / getSampleRate();
  357. int64_t ticks;
  358. check (transport.GetCurrentTickPosition (&ticks));
  359. info.ppqPosition = ticks / 960000.0;
  360. int64_t loopStartTick, loopEndTick;
  361. check (transport.GetCurrentLoopPosition (&info.isLooping, &loopStartTick, &loopEndTick));
  362. info.ppqLoopStart = loopStartTick / 960000.0;
  363. info.ppqLoopEnd = loopEndTick / 960000.0;
  364. // No way to get these: (?)
  365. info.isRecording = false;
  366. info.ppqPositionOfLastBarStart = 0;
  367. info.editOriginTime = 0;
  368. return true;
  369. }
  370. void audioProcessorParameterChanged (AudioProcessor* /*processor*/, int parameterIndex, float newValue)
  371. {
  372. SetParameterNormalizedValue (IndexAsParamID (parameterIndex), (double) newValue);
  373. }
  374. void audioProcessorChanged (AudioProcessor* /*processor*/)
  375. {
  376. // TODO
  377. }
  378. void audioProcessorParameterChangeGestureBegin (AudioProcessor* /*processor*/, int parameterIndex)
  379. {
  380. TouchParameter (IndexAsParamID (parameterIndex));
  381. }
  382. void audioProcessorParameterChangeGestureEnd (AudioProcessor* /*processor*/, int parameterIndex)
  383. {
  384. ReleaseParameter (IndexAsParamID (parameterIndex));
  385. }
  386. void process (const float* const* inputs, float* const* outputs, const int bufferSize, const bool bypass)
  387. {
  388. const int numIns = pluginInstance->getNumInputChannels();
  389. const int numOuts = pluginInstance->getNumOutputChannels();
  390. if (numOuts >= numIns)
  391. {
  392. for (int i = 0; i < numIns; ++i)
  393. memcpy (outputs[i], inputs[i], bufferSize * sizeof (float));
  394. process (outputs, numOuts, bufferSize, bypass);
  395. }
  396. else
  397. {
  398. if (channelList.size() <= numIns)
  399. channelList.insertMultiple (-1, nullptr, 1 + numIns - channelList.size());
  400. float** channels = channelList.getRawDataPointer();
  401. for (int i = 0; i < numOuts; ++i)
  402. {
  403. memcpy (outputs[i], inputs[i], bufferSize * sizeof (float));
  404. channels[i] = outputs[i];
  405. }
  406. for (int i = numOuts; i < numIns; ++i)
  407. channels[i] = const_cast <float*> (inputs[i]);
  408. process (channels, numIns, bufferSize, bypass);
  409. }
  410. }
  411. private:
  412. struct IndexAsParamID
  413. {
  414. inline explicit IndexAsParamID (int i) noexcept : index (i) {}
  415. operator AAX_CParamID() noexcept
  416. {
  417. jassert (index >= 0);
  418. char* t = name + sizeof (name);
  419. *--t = 0;
  420. int v = index;
  421. do
  422. {
  423. *--t = (char) ('0' + (v % 10));
  424. v /= 10;
  425. } while (v > 0);
  426. return static_cast <AAX_CParamID> (t);
  427. }
  428. private:
  429. int index;
  430. char name[32];
  431. JUCE_DECLARE_NON_COPYABLE (IndexAsParamID)
  432. };
  433. void process (float* const* channels, const int numChans, const int bufferSize, const bool bypass)
  434. {
  435. AudioSampleBuffer buffer (channels, numChans, bufferSize);
  436. // XXX need to do midi..
  437. midiBuffer.clear();
  438. {
  439. const ScopedLock sl (pluginInstance->getCallbackLock());
  440. if (bypass)
  441. pluginInstance->processBlockBypassed (buffer, midiBuffer);
  442. else
  443. pluginInstance->processBlock (buffer, midiBuffer);
  444. }
  445. }
  446. void addBypassParameter()
  447. {
  448. AAX_IParameter* masterBypass = new AAX_CParameter<bool> (cDefaultMasterBypassID,
  449. AAX_CString ("Master Bypass"),
  450. false,
  451. AAX_CBinaryTaperDelegate<bool>(),
  452. AAX_CBinaryDisplayDelegate<bool> ("bypass", "on"),
  453. true);
  454. masterBypass->SetNumberOfSteps (2);
  455. masterBypass->SetType (AAX_eParameterType_Discrete);
  456. mParameterManager.AddParameter (masterBypass);
  457. mPacketDispatcher.RegisterPacket (cDefaultMasterBypassID, JUCEAlgorithmIDs::bypass);
  458. }
  459. void addAudioProcessorParameters()
  460. {
  461. AudioProcessor& audioProcessor = getPluginInstance();
  462. const int numParameters = audioProcessor.getNumParameters();
  463. for (int parameterIndex = 0; parameterIndex < numParameters; ++parameterIndex)
  464. {
  465. if (audioProcessor.isParameterAutomatable (parameterIndex))
  466. {
  467. AAX_IParameter* parameter
  468. = new AAX_CParameter<float> (IndexAsParamID (parameterIndex),
  469. audioProcessor.getParameterName (parameterIndex).toUTF8().getAddress(),
  470. 0.0f,
  471. AAX_CLinearTaperDelegate<float, 0>(),
  472. AAX_CNumberDisplayDelegate<float, 3>(),
  473. true);
  474. parameter->SetNumberOfSteps (0x7FFFFFFF);
  475. parameter->SetType (AAX_eParameterType_Continuous);
  476. mParameterManager.AddParameter (parameter);
  477. }
  478. }
  479. }
  480. void preparePlugin() const
  481. {
  482. AAX_EStemFormat inputStemFormat = AAX_eStemFormat_None;
  483. check (Controller()->GetInputStemFormat (&inputStemFormat));
  484. const int numberOfInputChannels = getNumChannelsForStemFormat (inputStemFormat);
  485. AAX_EStemFormat outputStemFormat = AAX_eStemFormat_None;
  486. check (Controller()->GetOutputStemFormat (&outputStemFormat));
  487. const int numberOfOutputChannels = getNumChannelsForStemFormat (outputStemFormat);
  488. int32_t bufferSize = 0;
  489. check (Controller()->GetSignalLatency (&bufferSize));
  490. const AAX_CSampleRate sampleRate = getSampleRate();
  491. AudioProcessor& audioProcessor = getPluginInstance();
  492. audioProcessor.setPlayConfigDetails (numberOfInputChannels, numberOfOutputChannels, sampleRate, bufferSize);
  493. audioProcessor.prepareToPlay (sampleRate, bufferSize);
  494. }
  495. AAX_CSampleRate getSampleRate() const
  496. {
  497. AAX_CSampleRate sampleRate;
  498. check (Controller()->GetSampleRate (&sampleRate));
  499. return sampleRate;
  500. }
  501. JUCELibraryRefCount juceCount;
  502. ScopedPointer<AudioProcessor> pluginInstance;
  503. MidiBuffer midiBuffer;
  504. Array<float*> channelList;
  505. int32_t juceChunkIndex;
  506. // tempFilterData is initialized in GetChunkSize.
  507. // To avoid generating it again in GetChunk, we keep it as a member.
  508. mutable juce::MemoryBlock tempFilterData;
  509. JUCE_DECLARE_NON_COPYABLE (JuceAAX_Processor)
  510. };
  511. //==============================================================================
  512. static void AAX_CALLBACK algorithmProcessCallback (JUCEAlgorithmContext* const instancesBegin[],
  513. const void* const instancesEnd)
  514. {
  515. for (JUCEAlgorithmContext* const* iter = instancesBegin; iter < instancesEnd; ++iter)
  516. {
  517. const JUCEAlgorithmContext& i = **iter;
  518. i.pluginInstance->parameters.process (i.inputChannels, i.outputChannels,
  519. *(i.bufferSize), *(i.bypass) != 0);
  520. }
  521. }
  522. //==============================================================================
  523. static void createDescriptor (AAX_IComponentDescriptor& desc, int numInputs, int numOutputs)
  524. {
  525. check (desc.AddAudioIn (JUCEAlgorithmIDs::inputChannels));
  526. check (desc.AddAudioOut (JUCEAlgorithmIDs::outputChannels));
  527. check (desc.AddAudioBufferLength (JUCEAlgorithmIDs::bufferSize));
  528. check (desc.AddDataInPort (JUCEAlgorithmIDs::bypass, sizeof (int32_t)));
  529. check (desc.AddPrivateData (JUCEAlgorithmIDs::pluginInstance, sizeof (PluginInstanceInfo)));
  530. // Create a property map
  531. AAX_IPropertyMap* const properties = desc.NewPropertyMap();
  532. jassert (properties != nullptr);
  533. properties->AddProperty (AAX_eProperty_ManufacturerID, JucePlugin_AAXManufacturerCode);
  534. properties->AddProperty (AAX_eProperty_ProductID, JucePlugin_AAXProductId);
  535. #if JucePlugin_AAXDisableBypass
  536. properties->AddProperty (AAX_eProperty_CanBypass, false);
  537. #else
  538. properties->AddProperty (AAX_eProperty_CanBypass, true);
  539. #endif
  540. properties->AddProperty (AAX_eProperty_InputStemFormat, getFormatForChans (numInputs));
  541. properties->AddProperty (AAX_eProperty_OutputStemFormat, getFormatForChans (numOutputs));
  542. properties->AddProperty (AAX_eProperty_PlugInID_Native, JucePlugin_AAXPluginId + (numInputs + 256 * numOutputs));
  543. check (desc.AddProcessProc_Native (algorithmProcessCallback, properties));
  544. }
  545. static void getPlugInDescription (AAX_IEffectDescriptor& descriptor)
  546. {
  547. descriptor.AddName (JucePlugin_Desc);
  548. descriptor.AddName (JucePlugin_Name);
  549. descriptor.AddCategory (JucePlugin_AAXCategory);
  550. check (descriptor.AddProcPtr ((void*) JuceAAX_GUI::Create, kAAX_ProcPtrID_Create_EffectGUI));
  551. check (descriptor.AddProcPtr ((void*) JuceAAX_Processor::Create, kAAX_ProcPtrID_Create_EffectParameters));
  552. const short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations };
  553. const int numConfigs = numElementsInArray (channelConfigs);
  554. // You need to actually add some configurations to the JucePlugin_PreferredChannelConfigurations
  555. // value in your JucePluginCharacteristics.h file..
  556. jassert (numConfigs > 0);
  557. for (int i = 0; i < numConfigs; ++i)
  558. {
  559. if (AAX_IComponentDescriptor* const desc = descriptor.NewComponentDescriptor())
  560. {
  561. createDescriptor (*desc,
  562. channelConfigs [i][0],
  563. channelConfigs [i][1]);
  564. check (descriptor.AddComponent (desc));
  565. }
  566. }
  567. }
  568. };
  569. //==============================================================================
  570. AAX_Result JUCE_CDECL GetEffectDescriptions (AAX_ICollection*);
  571. AAX_Result JUCE_CDECL GetEffectDescriptions (AAX_ICollection* collection)
  572. {
  573. AAXClasses::JUCELibraryRefCount libraryRefCount;
  574. if (AAX_IEffectDescriptor* const descriptor = collection->NewDescriptor())
  575. {
  576. AAXClasses::getPlugInDescription (*descriptor);
  577. collection->AddEffect (JUCE_STRINGIFY (JucePlugin_AAXIdentifier), descriptor);
  578. collection->SetManufacturerName (JucePlugin_Manufacturer);
  579. collection->AddPackageName (JucePlugin_Desc);
  580. collection->AddPackageName (JucePlugin_Name);
  581. collection->SetPackageVersion (JucePlugin_VersionCode);
  582. return AAX_SUCCESS;
  583. }
  584. return AAX_ERROR_NULL_OBJECT;
  585. }
  586. #endif