| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2015 - ROLI Ltd.
 - 
 -    Permission is granted to use this software under the terms of either:
 -    a) the GPL v2 (or any later version)
 -    b) the Affero GPL v3
 - 
 -    Details of these licenses can be found at: www.gnu.org/licenses
 - 
 -    JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
 -    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 -    A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 - 
 -    ------------------------------------------------------------------------------
 - 
 -    To release a closed-source product which uses JUCE, commercial licenses are
 -    available: visit www.juce.com for more information.
 - 
 -   ==============================================================================
 - */
 - 
 - struct PluginBusUtilities
 - {
 -     //==============================================================================
 -     typedef Array<AudioProcessor::AudioProcessorBus> AudioBusArray;
 - 
 -     //==============================================================================
 -     PluginBusUtilities (AudioProcessor& plugin, bool markDiscreteLayoutsAsSupported, int maxProbeChannels = kDefaultMaxChannels)
 -         : processor (plugin),
 -           dynamicInBuses (false),
 -           dynamicOutBuses (false),
 -           plugInFormatSupportsDiscreteLayouts (markDiscreteLayoutsAsSupported),
 -           maxChannelsToProbe (maxProbeChannels)
 -     {
 -     }
 - 
 -     // this will invoke setPreferredLayout many times
 -     void init()    { populateLayoutDetails(); }
 - 
 -     //==============================================================================
 -     // Useful short-cuts
 -     AudioBusArray&       getFilterBus (bool inputBus) noexcept         { return inputBus ? processor.busArrangement.inputBuses : processor.busArrangement.outputBuses; }
 -     const AudioBusArray& getFilterBus (bool inputBus) const noexcept   { return inputBus ? processor.busArrangement.inputBuses : processor.busArrangement.outputBuses; }
 -     int getBusCount (bool inputBus) const noexcept                     { return getFilterBus (inputBus).size(); }
 -     AudioChannelSet getChannelSet (bool inputBus, int bus) noexcept    { return getFilterBus (inputBus).getReference (bus).channels; }
 -     int getNumChannels (bool inp, int bus) const noexcept              { return isPositiveAndBelow (bus, getBusCount (inp)) ? getFilterBus (inp).getReference (bus).channels.size() : 0; }
 -     bool isBusEnabled (bool inputBus, int bus) const noexcept          { return (getNumChannels (inputBus, bus) > 0); }
 -     bool hasInputs  (int bus) const noexcept                           { return isBusEnabled (true,  bus); }
 -     bool hasOutputs (int bus) const noexcept                           { return isBusEnabled (false, bus); }
 -     bool hasDynamicInBuses()  const noexcept                           { return dynamicInBuses; }
 -     bool hasDynamicOutBuses() const noexcept                           { return dynamicOutBuses; }
 - 
 -     //==============================================================================
 -     // Channel Counters
 -     int getNumEnabledBuses (bool inputBus) const noexcept              { int i; for (i = 0; i < getBusCount (inputBus); ++i) if (! isBusEnabled (inputBus, i)) break; return i; }
 - 
 -     int findTotalNumChannels (bool isInput, int busOffset = 0) const noexcept
 -     {
 -         int total = 0;
 -         const AudioBusArray& ioBuses = getFilterBus (isInput);
 - 
 -         for (int i = busOffset; i < ioBuses.size(); ++i)
 -             total += ioBuses.getReference (i).channels.size();
 - 
 -         return total;
 -     }
 - 
 -     int getBusIdxForChannelIdx (bool isInput, int channelIdx, int& totalChannels, int startBusIdx)
 -     {
 -         const int numBuses = getBusCount (isInput);
 - 
 -         for (int busIdx = startBusIdx; busIdx < numBuses; ++busIdx)
 -         {
 -             const int numChannels = getNumChannels (isInput, busIdx);
 -             if ((totalChannels + numChannels) > channelIdx)
 -                 return busIdx;
 - 
 -             totalChannels += numChannels;
 -         }
 - 
 -         return -1;
 -     }
 - 
 -     int getBusIdxForChannelIdx (bool isInput, int channelIdx)
 -     {
 -         int totalChannels = 0;
 -         return getBusIdxForChannelIdx (isInput, channelIdx, totalChannels, 0);
 -     }
 - 
 -     //==============================================================================
 -     // Bus properties & defaults
 -     bool busIgnoresLayout (bool inp, int bus) const noexcept
 -     {
 -         return isPositiveAndBelow (bus, getLayoutDetails (inp).size()) ? getBusLayoutDetails (inp, bus).busIgnoresLayout : true;
 -     }
 - 
 -     bool busCanBeDisabled (bool inp, int bus) const noexcept
 -     {
 -         return isPositiveAndBelow (bus, getLayoutDetails (inp).size()) ? getBusLayoutDetails (inp, bus).canBeDisabled : false;
 -     }
 - 
 -     bool isBusEnabledByDefault (bool inp, int bus) const noexcept
 -     {
 -         return isPositiveAndBelow (bus, getLayoutDetails (inp).size()) ? getBusLayoutDetails (inp, bus).isEnabledByDefault : true;
 -     }
 - 
 -     bool checkBusFormatsAreNotDiscrete() const  { return (checkBusFormatsAreNotDiscrete (true) && checkBusFormatsAreNotDiscrete (false)); }
 - 
 -     const AudioChannelSet& getDefaultLayoutForBus (bool isInput, int busIdx) const noexcept    { return getBusLayoutDetails (isInput, busIdx).defaultLayout; }
 - 
 -     AudioChannelSet getDefaultLayoutForChannelNumAndBus (bool isInput, int busIdx, int channelNum) const noexcept
 -     {
 -         if (busIdx < 0 || busIdx >= getBusCount (isInput) || channelNum == 0)
 -             return AudioChannelSet::disabled();
 - 
 -         const BusLayoutDetails& layouts = getBusLayoutDetails (isInput, busIdx);
 - 
 -         const AudioChannelSet& dflt = layouts.defaultLayout;
 -         const AudioChannelSet discreteChannels = AudioChannelSet::discreteChannels (channelNum);
 - 
 -         if (dflt.size() == channelNum && (plugInFormatSupportsDiscreteLayouts || (! dflt.isDiscreteLayout())))
 -             return dflt;
 - 
 -         Array<AudioChannelSet> potentialLayouts = layoutListCompatibleWithChannelCount (channelNum);
 - 
 -         ScopedBusRestorer busRestorer (*this);
 - 
 -         // prefer non-discrete layouts if no explicit default layout is given
 -         const int n = potentialLayouts.size();
 -         for (int i = 0; i < n; ++i)
 -         {
 -             const AudioChannelSet& layout = potentialLayouts.getReference (i);
 -             if (processor.setPreferredBusArrangement (isInput, busIdx, layout))
 -                 return layout;
 -         }
 - 
 - 
 -         if (plugInFormatSupportsDiscreteLayouts && processor.setPreferredBusArrangement (isInput, busIdx, discreteChannels))
 -             return discreteChannels;
 - 
 -         // we are out of options, bail out
 -         return AudioChannelSet();
 -     }
 - 
 -     //==============================================================================
 -     // This function is quite heavy so please cache the return value
 -     int findMaxNumberOfChannelsForBus (bool isInput, int busNr, int upperlimit = std::numeric_limits<int>::max())
 -     {
 -         int maxChannelsPreprocessorDefs = -1;
 -        #ifdef  JucePlugin_MaxNumInputChannels
 -         if (isInput)
 -             maxChannelsPreprocessorDefs = jmin (upperlimit, JucePlugin_MaxNumInputChannels);
 -        #endif
 - 
 -        #ifdef  JucePlugin_MaxNumOutputChannels
 -         if (! isInput)
 -             maxChannelsPreprocessorDefs = jmin (upperlimit, JucePlugin_MaxNumOutputChannels);
 -        #endif
 - 
 -        #ifdef JucePlugin_PreferredChannelConfigurations
 -         if (busNr == 0)
 -         {
 -             int maxChannelCount = 0;
 -             const short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations };
 -             const int numChannelConfigs = sizeof (channelConfigs) / sizeof (*channelConfigs);
 - 
 -             for (int i = 0; i < numChannelConfigs; ++i)
 -             {
 -                 const int numChannels = channelConfigs [i][isInput ? 0 : 1];
 -                 if (numChannels < 0)
 -                     return -1;
 - 
 -                 maxChannelCount = jmax (maxChannelCount, numChannels);
 -             }
 - 
 -             return jmin (upperlimit, maxChannelCount);
 -         }
 -        #endif
 - 
 -         ScopedBusRestorer busRestorer (*this);
 - 
 -         if (plugInFormatSupportsDiscreteLayouts &&
 -                processor.setPreferredBusArrangement(isInput, busNr, AudioChannelSet::discreteChannels (insaneNumberOfChannels)))
 -             return -1; // no limit in channels
 - 
 -         int n = maxChannelsPreprocessorDefs > 0 ? maxChannelsPreprocessorDefs
 -                                                 : (plugInFormatSupportsDiscreteLayouts ? maxChannelsToProbe
 -                                                                                        : maxNumChannelsOfNonDiscreteLayouts);
 - 
 -         n = jmin (upperlimit, n);
 - 
 -         for (int i = n; i > 0; --i)
 -         {
 -             if (plugInFormatSupportsDiscreteLayouts && processor.setPreferredBusArrangement (isInput, busNr, AudioChannelSet::discreteChannels (i)))
 -                 return i;
 - 
 -             Array<AudioChannelSet> sets = layoutListCompatibleWithChannelCount (i);
 - 
 -             for (int j = 0; j < sets.size(); ++j)
 -             {
 -                 const AudioChannelSet& layout = sets.getReference (j);
 - 
 -                 if (processor.setPreferredBusArrangement (isInput, busNr, layout))
 -                     return i;
 -             }
 -         }
 - 
 -         return 0;
 -     }
 - 
 -     //==============================================================================
 -     void restoreBusArrangement (const AudioProcessor::AudioBusArrangement& original) const
 -     {
 -         const int numInputBuses  = getBusCount (true);
 -         const int numOutputBuses = getBusCount (false);
 - 
 -         jassert (original.inputBuses. size() == numInputBuses);
 -         jassert (original.outputBuses.size() == numOutputBuses);
 - 
 -         for (int busNr = 0; busNr < numInputBuses;  ++busNr)
 -             processor.setPreferredBusArrangement (true,  busNr, original.inputBuses.getReference  (busNr).channels);
 - 
 -         for (int busNr = 0; busNr < numOutputBuses; ++busNr)
 -             processor.setPreferredBusArrangement (false, busNr, original.outputBuses.getReference (busNr).channels);
 -     }
 - 
 -     void enableAllBuses()
 -     {
 -         for (int busIdx = 1; busIdx < getBusCount (true); ++busIdx)
 -             if (getChannelSet (true, busIdx) == AudioChannelSet::disabled())
 -                 processor.setPreferredBusArrangement (true, busIdx, getDefaultLayoutForBus (true, busIdx));
 - 
 -         for (int busIdx = 1; busIdx < getBusCount (false); ++busIdx)
 -             if (getChannelSet (false, busIdx) == AudioChannelSet::disabled())
 -                 processor.setPreferredBusArrangement (false, busIdx, getDefaultLayoutForBus (false, busIdx));
 -     }
 - 
 -     //==============================================================================
 -     // Helper class which restores the original arrangement when it leaves scope
 -     class ScopedBusRestorer
 -     {
 -     public:
 -         ScopedBusRestorer (const PluginBusUtilities& bUtils)
 -             : busUtils (bUtils),
 -               originalArr (bUtils.processor.busArrangement),
 -               shouldRestore (true)
 -         {}
 - 
 -         ~ScopedBusRestorer()
 -         {
 -             if (shouldRestore)
 -                 busUtils.restoreBusArrangement (originalArr);
 -         }
 - 
 -         void release() noexcept      { shouldRestore = false; }
 - 
 -     private:
 -         const PluginBusUtilities& busUtils;
 -         const AudioProcessor::AudioBusArrangement originalArr;
 -         bool shouldRestore;
 - 
 -         JUCE_DECLARE_NON_COPYABLE (ScopedBusRestorer)
 -     };
 - 
 -     //==============================================================================
 -     AudioProcessor& processor;
 - 
 -     enum
 -     {
 -         kDefaultMaxChannels = 64
 -     };
 - 
 - private:
 -     friend class ScopedBusRestorer;
 - 
 -     enum
 -     {
 -         maxNumChannelsOfNonDiscreteLayouts = 8, // surround 7.1 has the maximum amount of channels
 -         pseudoChannelBitNum = 90,                // use this bit index to check if plug-in really doesn't care about layouts
 -         insaneNumberOfChannels = 512
 -     };
 - 
 -     //==============================================================================
 -     // the first layout is the default layout
 -     struct BusLayoutDetails
 -     {
 -         BusLayoutDetails() : busIgnoresLayout (true), canBeDisabled (false), isEnabledByDefault (false) {}
 - 
 -         AudioChannelSet defaultLayout;
 -         bool busIgnoresLayout, canBeDisabled, isEnabledByDefault;
 -     };
 - 
 -     Array<BusLayoutDetails>&       getLayoutDetails (bool isInput) noexcept              { return isInput ? inputLayouts : outputLayouts; }
 -     const Array<BusLayoutDetails>& getLayoutDetails (bool isInput) const noexcept        { return isInput ? inputLayouts : outputLayouts; }
 -     BusLayoutDetails&       getBusLayoutDetails (bool isInput, int busNr) noexcept       { return getLayoutDetails (isInput).getReference (busNr); }
 -     const BusLayoutDetails& getBusLayoutDetails (bool isInput, int busNr) const noexcept { return getLayoutDetails (isInput).getReference (busNr); }
 - 
 -     //==============================================================================
 -     Array<BusLayoutDetails> inputLayouts, outputLayouts;
 -     bool dynamicInBuses, dynamicOutBuses, plugInFormatSupportsDiscreteLayouts;
 -     int maxChannelsToProbe;
 - 
 -     //==============================================================================
 -     void populateLayoutDetails()
 -     {
 -         clear (getBusCount (true), getBusCount (false));
 - 
 -         // save the default layouts
 -         for (int i = 0; i < getBusCount (true);   ++i)
 -             getBusLayoutDetails (true,  i).defaultLayout = getChannelSet (true,  i);
 - 
 -         for (int i = 0; i < getBusCount (false);  ++i)
 -             getBusLayoutDetails (false, i).defaultLayout = getChannelSet (false, i);
 - 
 -         {
 -             ScopedBusRestorer restorer (*this);
 - 
 - 
 -             for (int i = 0; i < getBusCount (true);  ++i) addLayoutDetails (true,  i);
 -             for (int i = 0; i < getBusCount (false); ++i) addLayoutDetails (false, i);
 - 
 -             // find the defaults
 -             for (int i = 0; i < getBusCount (true); ++i)
 -                 updateDefaultLayout (true, i);
 - 
 -             for (int i = 0; i < getBusCount (false); ++i)
 -                 updateDefaultLayout (false, i);
 -         }
 - 
 -         // can any of the buses be disabled/enabled
 -         dynamicInBuses  = doesPlugInHaveDynamicBuses (true);
 -         dynamicOutBuses = doesPlugInHaveDynamicBuses (false);
 -     }
 - 
 -     //==============================================================================
 -     bool busIgnoresLayoutForChannelNum (bool isInput, int busNr, int channelNum)
 -     {
 -         AudioChannelSet set;
 - 
 -         // If the plug-in does not complain about setting it's layout to an undefined layout
 -         // then we assume that the plug-in ignores the layout altogether
 -         for (int i = 0; i < channelNum; ++i)
 -             set.addChannel (static_cast<AudioChannelSet::ChannelType> (pseudoChannelBitNum + i));
 - 
 -         return processor.setPreferredBusArrangement (isInput, busNr, set);
 -     }
 - 
 -     void addLayoutDetails (bool isInput, int busNr)
 -     {
 -         BusLayoutDetails& layouts = getBusLayoutDetails (isInput, busNr);
 - 
 -         // check if the plug-in bus can be disabled
 -         layouts.canBeDisabled = processor.setPreferredBusArrangement (isInput, busNr, AudioChannelSet());
 -         layouts.busIgnoresLayout = true;
 - 
 -         for (int i = 1; i <= maxNumChannelsOfNonDiscreteLayouts; ++i)
 -         {
 -             const bool ignoresLayoutForChannel = busIgnoresLayoutForChannelNum (isInput, busNr, i);
 - 
 -             Array<AudioChannelSet> sets = layoutListCompatibleWithChannelCount (i);
 - 
 -             for (int j = 0; j < sets.size(); ++j)
 -             {
 -                 const AudioChannelSet& layout = sets.getReference (j);
 - 
 -                 if (processor.setPreferredBusArrangement (isInput, busNr, layout))
 -                 {
 -                     if (! ignoresLayoutForChannel)
 -                     {
 -                         layouts.busIgnoresLayout = false;
 -                         return;
 -                     }
 -                 }
 -             }
 -         }
 -     }
 - 
 -     bool doesPlugInHaveDynamicBuses (bool isInput) const
 -     {
 -         for (int i = 0; i < getBusCount (isInput); ++i)
 -             if (getBusLayoutDetails (isInput, i).canBeDisabled)
 -                 return true;
 - 
 -         return false;
 -     }
 - 
 -     bool checkBusFormatsAreNotDiscrete (bool isInput) const
 -     {
 -         const int n = getBusCount (isInput);
 -         const Array<AudioProcessor::AudioProcessorBus>& bus = isInput ? processor.busArrangement.inputBuses
 -                                                                       : processor.busArrangement.outputBuses;
 - 
 -         for (int busIdx = 0; busIdx < n; ++busIdx)
 -             if (bus.getReference (busIdx).channels.isDiscreteLayout())
 -                 return false;
 - 
 -         return true;
 -     }
 - 
 -     void updateDefaultLayout (bool isInput, int busIdx)
 -     {
 -         BusLayoutDetails& layouts = getBusLayoutDetails (isInput, busIdx);
 -         AudioChannelSet& dfltLayout = layouts.defaultLayout;
 - 
 -         layouts.isEnabledByDefault = (dfltLayout.size() > 0);
 - 
 -         // If you hit this assertion then you are disabling the main bus by default
 -         // which is unsupported
 -         jassert (layouts.isEnabledByDefault || busIdx >= 0);
 - 
 -         if ((! plugInFormatSupportsDiscreteLayouts) && dfltLayout.isDiscreteLayout())
 -         {
 -             // The default layout is a discrete channel layout, yet some plug-in formats (VST-3)
 -             // do not support this format. We need to find a different default with the same
 -             // number of channels
 - 
 -             dfltLayout = getDefaultLayoutForChannelNumAndBus (isInput, busIdx, dfltLayout.size());
 -         }
 - 
 -         // are we done?
 -         if (dfltLayout != AudioChannelSet())
 -             return;
 - 
 -         const bool mainBusHasInputs  = hasInputs (0);
 -         const bool mainBusHasOutputs = hasOutputs (0);
 - 
 -         if (busIdx != 0 && (mainBusHasInputs || mainBusHasOutputs))
 -         {
 -             // the AudioProcessor does not give us any default layout
 -             // for an aux bus. Use the same number of channels as the
 -             // default layout on the main bus as a sensible default for
 -             // the aux bus
 - 
 -             const bool useInput = mainBusHasInputs && mainBusHasOutputs ? isInput : mainBusHasInputs;
 -             dfltLayout = getBusLayoutDetails (useInput, 0).defaultLayout;
 - 
 -             const int numChannels = dfltLayout.size();
 -             const AudioChannelSet discreteChannelLayout = AudioChannelSet::discreteChannels (numChannels);
 - 
 -             if ((plugInFormatSupportsDiscreteLayouts || dfltLayout != discreteChannelLayout) &&
 -                 processor.setPreferredBusArrangement (isInput, busIdx, dfltLayout))
 -                 return;
 - 
 -             // no exact match: try at least to match the number of channels
 -             dfltLayout = getDefaultLayoutForChannelNumAndBus (isInput, busIdx, dfltLayout.size());
 -             if (dfltLayout != AudioChannelSet())
 -                 return;
 -         }
 - 
 -         // check stereo first as this is often the more sensible default than mono
 -         if (processor.setPreferredBusArrangement (isInput, busIdx, (dfltLayout = AudioChannelSet::stereo())))
 -             return;
 - 
 -         if (plugInFormatSupportsDiscreteLayouts &&
 -             processor.setPreferredBusArrangement (isInput, busIdx, (dfltLayout = AudioChannelSet::discreteChannels (2))))
 -             return;
 - 
 -         // let's guess
 -         for (int numChans = 1; numChans < findMaxNumberOfChannelsForBus (isInput, busIdx); ++numChans)
 -         {
 -             Array<AudioChannelSet> sets = layoutListCompatibleWithChannelCount (numChans);
 -             for (int j = 0; j < sets.size(); ++j)
 -                 if (processor.setPreferredBusArrangement (isInput, busIdx, (dfltLayout = sets.getReference (j))))
 -                     return;
 - 
 -             if (plugInFormatSupportsDiscreteLayouts &&
 -                 processor.setPreferredBusArrangement (isInput, busIdx, (dfltLayout = AudioChannelSet::discreteChannels (numChans))))
 -                 return;
 -         }
 - 
 -         // Your bus must support at least a single possible layout
 -         jassertfalse;
 -     }
 - 
 -     void clear (int inputCount, int outputCount)
 -     {
 -         inputLayouts.clear();
 -         inputLayouts.resize (inputCount);
 -         outputLayouts.clear();
 -         outputLayouts.resize (outputCount);
 -     }
 - 
 -     //==============================================================================
 -     static Array<AudioChannelSet> layoutListCompatibleWithChannelCount (const int channelCount) noexcept
 -     {
 -         jassert (channelCount > 0);
 - 
 -         Array<AudioChannelSet> sets;
 - 
 -         switch (channelCount)
 -         {
 -             case 1:
 -                 sets.add (AudioChannelSet::mono());
 -                 break;
 -             case 2:
 -                 sets.add (AudioChannelSet::stereo());
 -                 break;
 -             case 3:
 -                 sets.add (AudioChannelSet::createLCR());
 -                 sets.add (AudioChannelSet::createLRS());
 -                 break;
 -             case 4:
 -                 sets.add (AudioChannelSet::createLCRS());
 -                 sets.add (AudioChannelSet::quadraphonic());
 -                 sets.add (AudioChannelSet::ambisonic());
 -                 break;
 -             case 5:
 -                 sets.add (AudioChannelSet::pentagonal());
 -                 sets.add (AudioChannelSet::create5point0());
 -                 break;
 -             case 6:
 -                 sets.add (AudioChannelSet::hexagonal());
 -                 sets.add (AudioChannelSet::create5point1());
 -                 sets.add (AudioChannelSet::create6point0());
 -                 sets.add (AudioChannelSet::create6point0Music());
 -                 break;
 -             case 7:
 -                 sets.add (AudioChannelSet::create6point1());
 -                 sets.add (AudioChannelSet::create7point0());
 -                 break;
 -             case 8:
 -                 sets.add (AudioChannelSet::octagonal());
 -                 sets.add (AudioChannelSet::create7point1());
 -                 sets.add (AudioChannelSet::create7point1AC3());
 -                 sets.add (AudioChannelSet::createFront7point1());
 -                 break;
 -         }
 - 
 -         return sets;
 -     }
 - 
 -     JUCE_DECLARE_NON_COPYABLE (PluginBusUtilities)
 - };
 
 
  |