1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - Raw Material Software Limited
6 
7    JUCE is an open source library subject to commercial or open-source
8    licensing.
9 
10    By using JUCE, you agree to the terms of both the JUCE 6 End-User License
11    Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
12 
13    End User License Agreement: www.juce.com/juce-6-licence
14    Privacy Policy: www.juce.com/juce-privacy-policy
15 
16    Or: You may also use this code under the terms of the GPL v3 (see
17    www.gnu.org/licenses).
18 
19    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21    DISCLAIMED.
22 
23   ==============================================================================
24 */
25 
26 namespace juce
27 {
28 
29 static ThreadLocalValue<AudioProcessor::WrapperType> wrapperTypeBeingCreated;
30 
setTypeOfNextNewPlugin(AudioProcessor::WrapperType type)31 void JUCE_CALLTYPE AudioProcessor::setTypeOfNextNewPlugin (AudioProcessor::WrapperType type)
32 {
33     wrapperTypeBeingCreated = type;
34 }
35 
AudioProcessor()36 AudioProcessor::AudioProcessor()
37     : AudioProcessor (BusesProperties().withInput  ("Input",  AudioChannelSet::stereo(), false)
38                                        .withOutput ("Output", AudioChannelSet::stereo(), false))
39 {
40 }
41 
AudioProcessor(const BusesProperties & ioConfig)42 AudioProcessor::AudioProcessor (const BusesProperties& ioConfig)
43 {
44     wrapperType = wrapperTypeBeingCreated.get();
45 
46     for (auto& layout : ioConfig.inputLayouts)   createBus (true,  layout);
47     for (auto& layout : ioConfig.outputLayouts)  createBus (false, layout);
48 
49     updateSpeakerFormatStrings();
50 }
51 
~AudioProcessor()52 AudioProcessor::~AudioProcessor()
53 {
54    #if ! JUCE_AUDIOPROCESSOR_NO_GUI
55     {
56         const ScopedLock sl (activeEditorLock);
57 
58         // ooh, nasty - the editor should have been deleted before its AudioProcessor.
59         jassert (activeEditor == nullptr);
60     }
61    #endif
62 
63    #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
64     // This will fail if you've called beginParameterChangeGesture() for one
65     // or more parameters without having made a corresponding call to endParameterChangeGesture...
66     jassert (changingParams.countNumberOfSetBits() == 0);
67    #endif
68 }
69 
70 //==============================================================================
getAlternateDisplayNames() const71 StringArray AudioProcessor::getAlternateDisplayNames() const     { return StringArray (getName()); }
72 
73 //==============================================================================
addBus(bool isInput)74 bool AudioProcessor::addBus (bool isInput)
75 {
76     if (! canAddBus (isInput))
77         return false;
78 
79     BusProperties busesProps;
80 
81     if (! canApplyBusCountChange (isInput, true, busesProps))
82         return false;
83 
84     createBus (isInput, busesProps);
85     return true;
86 }
87 
removeBus(bool inputBus)88 bool AudioProcessor::removeBus (bool inputBus)
89 {
90     auto numBuses = getBusCount (inputBus);
91 
92     if (numBuses == 0)
93         return false;
94 
95     if (! canRemoveBus (inputBus))
96         return false;
97 
98     BusProperties busesProps;
99 
100     if (! canApplyBusCountChange (inputBus, false, busesProps))
101         return false;
102 
103     auto busIndex = numBuses - 1;
104     auto numChannels = getChannelCountOfBus (inputBus, busIndex);
105     (inputBus ? inputBuses : outputBuses).remove (busIndex);
106 
107     audioIOChanged (true, numChannels > 0);
108     return true;
109 }
110 
111 //==============================================================================
setBusesLayout(const BusesLayout & arr)112 bool AudioProcessor::setBusesLayout (const BusesLayout& arr)
113 {
114     jassert (arr.inputBuses. size() == getBusCount (true)
115           && arr.outputBuses.size() == getBusCount (false));
116 
117     if (arr == getBusesLayout())
118         return true;
119 
120     auto copy = arr;
121 
122     if (! canApplyBusesLayout (copy))
123         return false;
124 
125     return applyBusLayouts (copy);
126 }
127 
setBusesLayoutWithoutEnabling(const BusesLayout & arr)128 bool AudioProcessor::setBusesLayoutWithoutEnabling (const BusesLayout& arr)
129 {
130     auto numIns  = getBusCount (true);
131     auto numOuts = getBusCount (false);
132 
133     jassert (arr.inputBuses. size() == numIns
134           && arr.outputBuses.size() == numOuts);
135 
136     auto request = arr;
137     auto current = getBusesLayout();
138 
139     for (int i = 0; i < numIns; ++i)
140         if (request.getNumChannels (true, i) == 0)
141             request.getChannelSet (true, i) = current.getChannelSet (true, i);
142 
143     for (int i = 0; i < numOuts; ++i)
144         if (request.getNumChannels (false, i) == 0)
145             request.getChannelSet (false, i) = current.getChannelSet (false, i);
146 
147     if (! checkBusesLayoutSupported (request))
148         return false;
149 
150     for (int dir = 0; dir < 2; ++dir)
151     {
152         const bool isInput = (dir != 0);
153 
154         for (int i = 0; i < (isInput ? numIns : numOuts); ++i)
155         {
156             auto& bus = *getBus (isInput, i);
157             auto& set = request.getChannelSet (isInput, i);
158 
159             if (! bus.isEnabled())
160             {
161                 if (! set.isDisabled())
162                     bus.lastLayout = set;
163 
164                 set = AudioChannelSet::disabled();
165             }
166         }
167     }
168 
169     return setBusesLayout (request);
170 }
171 
getBusesLayout() const172 AudioProcessor::BusesLayout AudioProcessor::getBusesLayout() const
173 {
174     BusesLayout layouts;
175 
176     for (auto& i : inputBuses)   layouts.inputBuses.add (i->getCurrentLayout());
177     for (auto& i : outputBuses)  layouts.outputBuses.add (i->getCurrentLayout());
178 
179     return layouts;
180 }
181 
getChannelLayoutOfBus(bool isInput,int busIndex) const182 AudioChannelSet AudioProcessor::getChannelLayoutOfBus (bool isInput, int busIndex) const noexcept
183 {
184     if (auto* bus = (isInput ? inputBuses : outputBuses)[busIndex])
185         return bus->getCurrentLayout();
186 
187     return {};
188 }
189 
setChannelLayoutOfBus(bool isInputBus,int busIndex,const AudioChannelSet & layout)190 bool AudioProcessor::setChannelLayoutOfBus (bool isInputBus, int busIndex, const AudioChannelSet& layout)
191 {
192     if (auto* bus = getBus (isInputBus, busIndex))
193     {
194         auto layouts = bus->getBusesLayoutForLayoutChangeOfBus (layout);
195 
196         if (layouts.getChannelSet (isInputBus, busIndex) == layout)
197             return applyBusLayouts (layouts);
198 
199         return false;
200     }
201 
202     jassertfalse;  // busIndex parameter is invalid
203     return false;
204 }
205 
enableAllBuses()206 bool AudioProcessor::enableAllBuses()
207 {
208     BusesLayout layouts;
209 
210     for (auto& i : inputBuses)   layouts.inputBuses.add (i->lastLayout);
211     for (auto& i : outputBuses)  layouts.outputBuses.add (i->lastLayout);
212 
213     return setBusesLayout (layouts);
214 }
215 
checkBusesLayoutSupported(const BusesLayout & layouts) const216 bool AudioProcessor::checkBusesLayoutSupported (const BusesLayout& layouts) const
217 {
218     if (layouts.inputBuses.size() == inputBuses.size()
219           && layouts.outputBuses.size() == outputBuses.size())
220         return isBusesLayoutSupported (layouts);
221 
222     return false;
223 }
224 
getNextBestLayout(const BusesLayout & desiredLayout,BusesLayout & actualLayouts) const225 void AudioProcessor::getNextBestLayout (const BusesLayout& desiredLayout, BusesLayout& actualLayouts) const
226 {
227     // if you are hitting this assertion then you are requesting a next
228     // best layout which does not have the same number of buses as the
229     // audio processor.
230     jassert (desiredLayout.inputBuses.size() == inputBuses.size()
231           && desiredLayout.outputBuses.size() == outputBuses.size());
232 
233     if (checkBusesLayoutSupported (desiredLayout))
234     {
235         actualLayouts = desiredLayout;
236         return;
237     }
238 
239     auto originalState = actualLayouts;
240     auto currentState = originalState;
241     auto bestSupported = currentState;
242 
243     for (int dir = 0; dir < 2; ++dir)
244     {
245         const bool isInput = (dir > 0);
246 
247         auto& currentLayouts   = (isInput ? currentState.inputBuses  : currentState.outputBuses);
248         auto& bestLayouts      = (isInput ? bestSupported.inputBuses : bestSupported.outputBuses);
249         auto& requestedLayouts = (isInput ? desiredLayout.inputBuses : desiredLayout.outputBuses);
250         auto& originalLayouts  = (isInput ? originalState.inputBuses : originalState.outputBuses);
251 
252         for (int busIndex = 0; busIndex < requestedLayouts.size(); ++busIndex)
253         {
254             auto& best       = bestLayouts     .getReference (busIndex);
255             auto& requested  = requestedLayouts.getReference (busIndex);
256             auto& original   = originalLayouts .getReference (busIndex);
257 
258             // do we need to do anything
259             if (original == requested)
260                 continue;
261 
262             currentState = bestSupported;
263             auto& current = currentLayouts  .getReference (busIndex);
264 
265             // already supported?
266             current = requested;
267 
268             if (checkBusesLayoutSupported (currentState))
269             {
270                 bestSupported = currentState;
271                 continue;
272             }
273 
274             // try setting the opposite bus to the identical layout
275             const bool oppositeDirection = ! isInput;
276 
277             if (getBusCount (oppositeDirection) > busIndex)
278             {
279                 auto& oppositeLayout = (oppositeDirection ? currentState.inputBuses : currentState.outputBuses).getReference (busIndex);
280                 oppositeLayout = requested;
281 
282                 if (checkBusesLayoutSupported (currentState))
283                 {
284                     bestSupported = currentState;
285                     continue;
286                 }
287 
288                 // try setting the default layout
289                 oppositeLayout = getBus (oppositeDirection, busIndex)->getDefaultLayout();
290 
291                 if (checkBusesLayoutSupported (currentState))
292                 {
293                     bestSupported = currentState;
294                     continue;
295                 }
296             }
297 
298             // try setting all other buses to the identical layout
299             BusesLayout allTheSame;
300             allTheSame.inputBuses.insertMultiple (-1, requested, getBusCount (true));
301             allTheSame.outputBuses.insertMultiple (-1, requested, getBusCount (false));
302 
303             if (checkBusesLayoutSupported (allTheSame))
304             {
305                 bestSupported = allTheSame;
306                 continue;
307             }
308 
309             // what is closer the default or the current layout?
310             auto distance = std::abs (best.size() - requested.size());
311             auto& defaultLayout = getBus (isInput, busIndex)->getDefaultLayout();
312 
313             if (std::abs (defaultLayout.size() - requested.size()) < distance)
314             {
315                 current = defaultLayout;
316 
317                 if (checkBusesLayoutSupported (currentState))
318                     bestSupported = currentState;
319             }
320         }
321     }
322 
323     actualLayouts = bestSupported;
324 }
325 
326 //==============================================================================
setPlayHead(AudioPlayHead * newPlayHead)327 void AudioProcessor::setPlayHead (AudioPlayHead* newPlayHead)
328 {
329     playHead = newPlayHead;
330 }
331 
addListener(AudioProcessorListener * newListener)332 void AudioProcessor::addListener (AudioProcessorListener* newListener)
333 {
334     const ScopedLock sl (listenerLock);
335     listeners.addIfNotAlreadyThere (newListener);
336 }
337 
removeListener(AudioProcessorListener * listenerToRemove)338 void AudioProcessor::removeListener (AudioProcessorListener* listenerToRemove)
339 {
340     const ScopedLock sl (listenerLock);
341     listeners.removeFirstMatchingValue (listenerToRemove);
342 }
343 
setPlayConfigDetails(int newNumIns,int newNumOuts,double newSampleRate,int newBlockSize)344 void AudioProcessor::setPlayConfigDetails (int newNumIns, int newNumOuts, double newSampleRate, int newBlockSize)
345 {
346     bool success = true;
347 
348     if (getTotalNumInputChannels() != newNumIns)
349         success &= setChannelLayoutOfBus (true,  0, AudioChannelSet::canonicalChannelSet (newNumIns));
350 
351     // failed to find a compatible input configuration
352     jassert (success);
353 
354     if (getTotalNumOutputChannels() != newNumOuts)
355         success &= setChannelLayoutOfBus (false, 0, AudioChannelSet::canonicalChannelSet (newNumOuts));
356 
357     // failed to find a compatible output configuration
358     jassert (success);
359 
360     // if the user is using this method then they do not want any side-buses or aux outputs
361     success &= disableNonMainBuses();
362     jassert (success);
363 
364     // the processor may not support this arrangement at all
365     jassert (success && newNumIns == getTotalNumInputChannels() && newNumOuts == getTotalNumOutputChannels());
366 
367     setRateAndBufferSizeDetails (newSampleRate, newBlockSize);
368     ignoreUnused (success);
369 }
370 
setRateAndBufferSizeDetails(double newSampleRate,int newBlockSize)371 void AudioProcessor::setRateAndBufferSizeDetails (double newSampleRate, int newBlockSize) noexcept
372 {
373     currentSampleRate = newSampleRate;
374     blockSize = newBlockSize;
375 }
376 
377 //==============================================================================
numChannelsChanged()378 void AudioProcessor::numChannelsChanged()      {}
numBusesChanged()379 void AudioProcessor::numBusesChanged()         {}
processorLayoutsChanged()380 void AudioProcessor::processorLayoutsChanged() {}
381 
getChannelIndexInProcessBlockBuffer(bool isInput,int busIndex,int channelIndex) const382 int AudioProcessor::getChannelIndexInProcessBlockBuffer (bool isInput, int busIndex, int channelIndex) const noexcept
383 {
384     auto& ioBus = isInput ? inputBuses : outputBuses;
385     jassert (isPositiveAndBelow (busIndex, ioBus.size()));
386 
387     for (int i = 0; i < ioBus.size() && i < busIndex; ++i)
388         channelIndex += getChannelCountOfBus (isInput, i);
389 
390     return channelIndex;
391 }
392 
getOffsetInBusBufferForAbsoluteChannelIndex(bool isInput,int absoluteChannelIndex,int & busIndex) const393 int AudioProcessor::getOffsetInBusBufferForAbsoluteChannelIndex (bool isInput, int absoluteChannelIndex, int& busIndex) const noexcept
394 {
395     auto numBuses = getBusCount (isInput);
396     int numChannels = 0;
397 
398     for (busIndex = 0; busIndex < numBuses && absoluteChannelIndex >= (numChannels = getChannelLayoutOfBus (isInput, busIndex).size()); ++busIndex)
399         absoluteChannelIndex -= numChannels;
400 
401     return busIndex >= numBuses ? -1 : absoluteChannelIndex;
402 }
403 
404 //==============================================================================
setNonRealtime(bool newNonRealtime)405 void AudioProcessor::setNonRealtime (bool newNonRealtime) noexcept
406 {
407     nonRealtime = newNonRealtime;
408 }
409 
setLatencySamples(int newLatency)410 void AudioProcessor::setLatencySamples (int newLatency)
411 {
412     if (latencySamples != newLatency)
413     {
414         latencySamples = newLatency;
415         updateHostDisplay();
416     }
417 }
418 
419 //==============================================================================
getListenerLocked(int index) const420 AudioProcessorListener* AudioProcessor::getListenerLocked (int index) const noexcept
421 {
422     const ScopedLock sl (listenerLock);
423     return listeners[index];
424 }
425 
updateHostDisplay()426 void AudioProcessor::updateHostDisplay()
427 {
428     for (int i = listeners.size(); --i >= 0;)
429         if (auto l = getListenerLocked (i))
430             l->audioProcessorChanged (this);
431 }
432 
checkForDuplicateParamID(AudioProcessorParameter * param)433 void AudioProcessor::checkForDuplicateParamID (AudioProcessorParameter* param)
434 {
435     ignoreUnused (param);
436 
437    #if JUCE_DEBUG
438     if (auto* withID = dynamic_cast<AudioProcessorParameterWithID*> (param))
439     {
440         auto insertResult = paramIDs.insert (withID->paramID);
441 
442         // If you hit this assertion then the parameter ID is not unique
443         jassert (insertResult.second);
444     }
445    #endif
446 }
447 
getParameters() const448 const Array<AudioProcessorParameter*>& AudioProcessor::getParameters() const   { return flatParameterList; }
getParameterTree() const449 const AudioProcessorParameterGroup& AudioProcessor::getParameterTree() const   { return parameterTree; }
450 
addParameter(AudioProcessorParameter * param)451 void AudioProcessor::addParameter (AudioProcessorParameter* param)
452 {
453     jassert (param != nullptr);
454     parameterTree.addChild (std::unique_ptr<AudioProcessorParameter> (param));
455 
456     param->processor = this;
457     param->parameterIndex = flatParameterList.size();
458     flatParameterList.add (param);
459 
460     checkForDuplicateParamID (param);
461 }
462 
addParameterGroup(std::unique_ptr<AudioProcessorParameterGroup> group)463 void AudioProcessor::addParameterGroup (std::unique_ptr<AudioProcessorParameterGroup> group)
464 {
465     jassert (group != nullptr);
466 
467     auto oldSize = flatParameterList.size();
468     flatParameterList.addArray (group->getParameters (true));
469 
470     for (int i = oldSize; i < flatParameterList.size(); ++i)
471     {
472         auto p = flatParameterList.getUnchecked (i);
473         p->processor = this;
474         p->parameterIndex = i;
475 
476         checkForDuplicateParamID (p);
477     }
478 
479     parameterTree.addChild (std::move (group));
480 }
481 
setParameterTree(AudioProcessorParameterGroup && newTree)482 void AudioProcessor::setParameterTree (AudioProcessorParameterGroup&& newTree)
483 {
484    #if JUCE_DEBUG
485     paramIDs.clear();
486    #endif
487 
488     parameterTree = std::move (newTree);
489     flatParameterList = parameterTree.getParameters (true);
490 
491     for (int i = 0; i < flatParameterList.size(); ++i)
492     {
493         auto p = flatParameterList.getUnchecked (i);
494         p->processor = this;
495         p->parameterIndex = i;
496 
497         checkForDuplicateParamID (p);
498     }
499 }
500 
refreshParameterList()501 void AudioProcessor::refreshParameterList() {}
502 
getDefaultNumParameterSteps()503 int AudioProcessor::getDefaultNumParameterSteps() noexcept
504 {
505     return 0x7fffffff;
506 }
507 
suspendProcessing(const bool shouldBeSuspended)508 void AudioProcessor::suspendProcessing (const bool shouldBeSuspended)
509 {
510     const ScopedLock sl (callbackLock);
511     suspended = shouldBeSuspended;
512 }
513 
reset()514 void AudioProcessor::reset() {}
515 
516 template <typename floatType>
processBypassed(AudioBuffer<floatType> & buffer,MidiBuffer &)517 void AudioProcessor::processBypassed (AudioBuffer<floatType>& buffer, MidiBuffer&)
518 {
519     // If you hit this assertion then your plug-in is reporting that it introduces
520     // some latency, but you haven't overridden processBlockBypassed to produce
521     // an identical amount of latency. Without identical latency in
522     // processBlockBypassed a host's latency compensation could shift the audio
523     // passing through your bypassed plug-in forward in time.
524     jassert (getLatencySamples() == 0);
525 
526     for (int ch = getMainBusNumInputChannels(); ch < getTotalNumOutputChannels(); ++ch)
527         buffer.clear (ch, 0, buffer.getNumSamples());
528 }
529 
processBlockBypassed(AudioBuffer<float> & buffer,MidiBuffer & midi)530 void AudioProcessor::processBlockBypassed (AudioBuffer<float>&  buffer, MidiBuffer& midi)    { processBypassed (buffer, midi); }
processBlockBypassed(AudioBuffer<double> & buffer,MidiBuffer & midi)531 void AudioProcessor::processBlockBypassed (AudioBuffer<double>& buffer, MidiBuffer& midi)    { processBypassed (buffer, midi); }
532 
processBlock(AudioBuffer<double> & buffer,MidiBuffer & midiMessages)533 void AudioProcessor::processBlock (AudioBuffer<double>& buffer, MidiBuffer& midiMessages)
534 {
535     ignoreUnused (buffer, midiMessages);
536 
537     // If you hit this assertion then either the caller called the double
538     // precision version of processBlock on a processor which does not support it
539     // (i.e. supportsDoublePrecisionProcessing() returns false), or the implementation
540     // of the AudioProcessor forgot to override the double precision version of this method
541     jassertfalse;
542 }
543 
supportsDoublePrecisionProcessing() const544 bool AudioProcessor::supportsDoublePrecisionProcessing() const
545 {
546     return false;
547 }
548 
setProcessingPrecision(ProcessingPrecision precision)549 void AudioProcessor::setProcessingPrecision (ProcessingPrecision precision) noexcept
550 {
551     // If you hit this assertion then you're trying to use double precision
552     // processing on a processor which does not support it!
553     jassert (precision != doublePrecision || supportsDoublePrecisionProcessing());
554 
555     processingPrecision = precision;
556 }
557 
558 //==============================================================================
getChannelName(const OwnedArray<AudioProcessor::Bus> & buses,int index)559 static String getChannelName (const OwnedArray<AudioProcessor::Bus>& buses, int index)
560 {
561     return buses.size() > 0 ? AudioChannelSet::getChannelTypeName (buses[0]->getCurrentLayout().getTypeOfChannel (index)) : String();
562 }
563 
getInputChannelName(int index) const564 const String AudioProcessor::getInputChannelName (int index) const   { return getChannelName (inputBuses,  index); }
getOutputChannelName(int index) const565 const String AudioProcessor::getOutputChannelName (int index) const  { return getChannelName (outputBuses, index); }
566 
isStereoPair(const OwnedArray<AudioProcessor::Bus> & buses,int index)567 static bool isStereoPair (const OwnedArray<AudioProcessor::Bus>& buses, int index)
568 {
569     return index < 2
570             && buses.size() > 0
571             && buses[0]->getCurrentLayout() == AudioChannelSet::stereo();
572 }
573 
isInputChannelStereoPair(int index) const574 bool AudioProcessor::isInputChannelStereoPair  (int index) const    { return isStereoPair (inputBuses, index); }
isOutputChannelStereoPair(int index) const575 bool AudioProcessor::isOutputChannelStereoPair (int index) const    { return isStereoPair (outputBuses, index); }
576 
577 //==============================================================================
createBus(bool inputBus,const BusProperties & ioConfig)578 void AudioProcessor::createBus (bool inputBus, const BusProperties& ioConfig)
579 {
580     (inputBus ? inputBuses : outputBuses).add (new Bus (*this, ioConfig.busName, ioConfig.defaultLayout, ioConfig.isActivatedByDefault));
581 
582     audioIOChanged (true, ioConfig.isActivatedByDefault);
583 }
584 
585 //==============================================================================
busesPropertiesFromLayoutArray(const Array<InOutChannelPair> & config)586 AudioProcessor::BusesProperties AudioProcessor::busesPropertiesFromLayoutArray (const Array<InOutChannelPair>& config)
587 {
588     BusesProperties ioProps;
589 
590     if (config[0].inChannels > 0)
591         ioProps.addBus (true, "Input", AudioChannelSet::canonicalChannelSet (config[0].inChannels));
592 
593     if (config[0].outChannels > 0)
594         ioProps.addBus (false, "Output", AudioChannelSet::canonicalChannelSet (config[0].outChannels));
595 
596     return ioProps;
597 }
598 
getNextBestLayoutInList(const BusesLayout & layouts,const Array<InOutChannelPair> & legacyLayouts) const599 AudioProcessor::BusesLayout AudioProcessor::getNextBestLayoutInList (const BusesLayout& layouts,
600                                                                      const Array<InOutChannelPair>& legacyLayouts) const
601 {
602     auto numChannelConfigs = legacyLayouts.size();
603     jassert (numChannelConfigs > 0);
604 
605     bool hasInputs = false, hasOutputs = false;
606 
607     for (int i = 0; i < numChannelConfigs; ++i)
608     {
609         if (legacyLayouts[i].inChannels > 0)
610         {
611             hasInputs = true;
612             break;
613         }
614     }
615 
616     for (int i = 0; i < numChannelConfigs; ++i)
617     {
618         if (legacyLayouts[i].outChannels > 0)
619         {
620             hasOutputs = true;
621             break;
622         }
623     }
624 
625     auto nearest = layouts;
626     nearest.inputBuses .resize (hasInputs  ? 1 : 0);
627     nearest.outputBuses.resize (hasOutputs ? 1 : 0);
628 
629     auto* inBus  = (hasInputs  ? &nearest.inputBuses. getReference (0) : nullptr);
630     auto* outBus = (hasOutputs ? &nearest.outputBuses.getReference (0) : nullptr);
631 
632     auto inNumChannelsRequested  = static_cast<int16> (inBus  != nullptr ? inBus->size()  : 0);
633     auto outNumChannelsRequested = static_cast<int16> (outBus != nullptr ? outBus->size() : 0);
634 
635     auto distance = std::numeric_limits<int32>::max();
636     int bestConfiguration = 0;
637 
638     for (int i = 0; i < numChannelConfigs; ++i)
639     {
640         auto inChannels  = legacyLayouts.getReference (i).inChannels;
641         auto outChannels = legacyLayouts.getReference (i).outChannels;
642 
643         auto channelDifference = ((std::abs (inChannels  - inNumChannelsRequested)  & 0xffff) << 16)
644                                     | ((std::abs (outChannels - outNumChannelsRequested) & 0xffff) << 0);
645 
646         if (channelDifference < distance)
647         {
648             distance = channelDifference;
649             bestConfiguration = i;
650 
651             // we can exit if we found a perfect match
652             if (distance == 0)
653                 return nearest;
654         }
655     }
656 
657     auto inChannels  = legacyLayouts.getReference (bestConfiguration).inChannels;
658     auto outChannels = legacyLayouts.getReference (bestConfiguration).outChannels;
659 
660     auto currentState = getBusesLayout();
661     auto currentInLayout  = (getBusCount (true)  > 0 ? currentState.inputBuses .getReference(0) : AudioChannelSet());
662     auto currentOutLayout = (getBusCount (false) > 0 ? currentState.outputBuses.getReference(0) : AudioChannelSet());
663 
664     if (inBus != nullptr)
665     {
666         if      (inChannels == 0)                       *inBus = AudioChannelSet::disabled();
667         else if (inChannels == currentInLayout. size()) *inBus = currentInLayout;
668         else if (inChannels == currentOutLayout.size()) *inBus = currentOutLayout;
669         else                                            *inBus = AudioChannelSet::canonicalChannelSet (inChannels);
670     }
671 
672     if (outBus != nullptr)
673     {
674         if      (outChannels == 0)                       *outBus = AudioChannelSet::disabled();
675         else if (outChannels == currentOutLayout.size()) *outBus = currentOutLayout;
676         else if (outChannels == currentInLayout .size()) *outBus = currentInLayout;
677         else                                             *outBus = AudioChannelSet::canonicalChannelSet (outChannels);
678     }
679 
680     return nearest;
681 }
682 
containsLayout(const BusesLayout & layouts,const Array<InOutChannelPair> & channelLayouts)683 bool AudioProcessor::containsLayout (const BusesLayout& layouts, const Array<InOutChannelPair>& channelLayouts)
684 {
685     if (layouts.inputBuses.size() > 1 || layouts.outputBuses.size() > 1)
686         return false;
687 
688     const InOutChannelPair mainLayout (static_cast<int16> (layouts.getNumChannels (true, 0)),
689                                        static_cast<int16> (layouts.getNumChannels (false, 0)));
690 
691     return channelLayouts.contains (mainLayout);
692 }
693 
694 //==============================================================================
disableNonMainBuses()695 bool AudioProcessor::disableNonMainBuses()
696 {
697     auto layouts = getBusesLayout();
698 
699     for (int busIndex = 1; busIndex < layouts.inputBuses.size(); ++busIndex)
700         layouts.inputBuses.getReference (busIndex) = AudioChannelSet::disabled();
701 
702     for (int busIndex = 1; busIndex < layouts.outputBuses.size(); ++busIndex)
703         layouts.outputBuses.getReference (busIndex) = AudioChannelSet::disabled();
704 
705     return setBusesLayout (layouts);
706 }
707 
708 // Unfortunately the deprecated getInputSpeakerArrangement/getOutputSpeakerArrangement return
709 // references to strings. Therefore we need to keep a copy. Once getInputSpeakerArrangement is
710 // removed, we can also remove this function
updateSpeakerFormatStrings()711 void AudioProcessor::updateSpeakerFormatStrings()
712 {
713     cachedInputSpeakerArrString.clear();
714     cachedOutputSpeakerArrString.clear();
715 
716     if (getBusCount (true) > 0)
717         cachedInputSpeakerArrString  = getBus (true,  0)->getCurrentLayout().getSpeakerArrangementAsString();
718 
719     if (getBusCount (false) > 0)
720         cachedOutputSpeakerArrString = getBus (false, 0)->getCurrentLayout().getSpeakerArrangementAsString();
721 }
722 
applyBusLayouts(const BusesLayout & layouts)723 bool AudioProcessor::applyBusLayouts (const BusesLayout& layouts)
724 {
725     if (layouts == getBusesLayout())
726         return true;
727 
728     auto numInputBuses  = getBusCount (true);
729     auto numOutputBuses = getBusCount (false);
730 
731     auto oldNumberOfIns  = getTotalNumInputChannels();
732     auto oldNumberOfOuts = getTotalNumOutputChannels();
733 
734     if (layouts.inputBuses. size() != numInputBuses
735      || layouts.outputBuses.size() != numOutputBuses)
736         return false;
737 
738     int newNumberOfIns = 0, newNumberOfOuts = 0;
739 
740     for (int busIndex = 0; busIndex < numInputBuses;  ++busIndex)
741     {
742         auto& bus = *getBus (true, busIndex);
743         const auto& set = layouts.getChannelSet (true, busIndex);
744         bus.layout = set;
745 
746         if (! set.isDisabled())
747             bus.lastLayout = set;
748 
749         newNumberOfIns += set.size();
750     }
751 
752     for (int busIndex = 0; busIndex < numOutputBuses;  ++busIndex)
753     {
754         auto& bus = *getBus (false, busIndex);
755         const auto& set = layouts.getChannelSet (false, busIndex);
756         bus.layout = set;
757 
758         if (! set.isDisabled())
759             bus.lastLayout = set;
760 
761         newNumberOfOuts += set.size();
762     }
763 
764     const bool channelNumChanged = (oldNumberOfIns != newNumberOfIns || oldNumberOfOuts != newNumberOfOuts);
765     audioIOChanged (false, channelNumChanged);
766 
767     return true;
768 }
769 
audioIOChanged(bool busNumberChanged,bool channelNumChanged)770 void AudioProcessor::audioIOChanged (bool busNumberChanged, bool channelNumChanged)
771 {
772     auto numInputBuses  = getBusCount (true);
773     auto numOutputBuses = getBusCount (false);
774 
775     for (int dir = 0; dir < 2; ++dir)
776     {
777         const bool isInput = (dir == 0);
778         auto num = (isInput ? numInputBuses : numOutputBuses);
779 
780         for (int i = 0; i < num; ++i)
781             if (auto* bus = getBus (isInput, i))
782                 bus->updateChannelCount();
783     }
784 
785     auto countTotalChannels = [] (const OwnedArray<AudioProcessor::Bus>& buses) noexcept
786     {
787         int n = 0;
788 
789         for (auto* bus : buses)
790             n += bus->getNumberOfChannels();
791 
792         return n;
793     };
794 
795     cachedTotalIns  = countTotalChannels (inputBuses);
796     cachedTotalOuts = countTotalChannels (outputBuses);
797 
798     updateSpeakerFormatStrings();
799 
800     if (busNumberChanged)
801         numBusesChanged();
802 
803     if (channelNumChanged)
804         numChannelsChanged();
805 
806     processorLayoutsChanged();
807 }
808 
809 #if ! JUCE_AUDIOPROCESSOR_NO_GUI
810 //==============================================================================
editorBeingDeleted(AudioProcessorEditor * const editor)811 void AudioProcessor::editorBeingDeleted (AudioProcessorEditor* const editor) noexcept
812 {
813     const ScopedLock sl (activeEditorLock);
814 
815     if (activeEditor == editor)
816         activeEditor = nullptr;
817 }
818 
getActiveEditor() const819 AudioProcessorEditor* AudioProcessor::getActiveEditor() const noexcept
820 {
821     const ScopedLock sl (activeEditorLock);
822     return activeEditor;
823 }
824 
createEditorIfNeeded()825 AudioProcessorEditor* AudioProcessor::createEditorIfNeeded()
826 {
827     const ScopedLock sl (activeEditorLock);
828 
829     if (activeEditor != nullptr)
830         return activeEditor;
831 
832     auto* ed = createEditor();
833 
834     if (ed != nullptr)
835     {
836         // you must give your editor comp a size before returning it..
837         jassert (ed->getWidth() > 0 && ed->getHeight() > 0);
838         activeEditor = ed;
839     }
840 
841     // You must make your hasEditor() method return a consistent result!
842     jassert (hasEditor() == (ed != nullptr));
843 
844     return ed;
845 }
846 #endif
847 
848 //==============================================================================
getCurrentProgramStateInformation(juce::MemoryBlock & destData)849 void AudioProcessor::getCurrentProgramStateInformation (juce::MemoryBlock& destData)
850 {
851     getStateInformation (destData);
852 }
853 
setCurrentProgramStateInformation(const void * data,int sizeInBytes)854 void AudioProcessor::setCurrentProgramStateInformation (const void* data, int sizeInBytes)
855 {
856     setStateInformation (data, sizeInBytes);
857 }
858 
859 //==============================================================================
updateTrackProperties(const AudioProcessor::TrackProperties &)860 void AudioProcessor::updateTrackProperties (const AudioProcessor::TrackProperties&)    {}
861 
862 //==============================================================================
863 // magic number to identify memory blocks that we've stored as XML
864 const uint32 magicXmlNumber = 0x21324356;
865 
copyXmlToBinary(const XmlElement & xml,juce::MemoryBlock & destData)866 void AudioProcessor::copyXmlToBinary (const XmlElement& xml, juce::MemoryBlock& destData)
867 {
868     {
869         MemoryOutputStream out (destData, false);
870         out.writeInt (magicXmlNumber);
871         out.writeInt (0);
872         xml.writeTo (out, XmlElement::TextFormat().singleLine());
873         out.writeByte (0);
874     }
875 
876     // go back and write the string length..
877     static_cast<uint32*> (destData.getData())[1]
878         = ByteOrder::swapIfBigEndian ((uint32) destData.getSize() - 9);
879 }
880 
getXmlFromBinary(const void * data,const int sizeInBytes)881 std::unique_ptr<XmlElement> AudioProcessor::getXmlFromBinary (const void* data, const int sizeInBytes)
882 {
883     if (sizeInBytes > 8 && ByteOrder::littleEndianInt (data) == magicXmlNumber)
884     {
885         auto stringLength = (int) ByteOrder::littleEndianInt (addBytesToPointer (data, 4));
886 
887         if (stringLength > 0)
888             return parseXML (String::fromUTF8 (static_cast<const char*> (data) + 8,
889                                                 jmin ((sizeInBytes - 8), stringLength)));
890     }
891 
892     return {};
893 }
894 
canApplyBusCountChange(bool isInput,bool isAdding,AudioProcessor::BusProperties & outProperties)895 bool AudioProcessor::canApplyBusCountChange (bool isInput, bool isAdding,
896                                              AudioProcessor::BusProperties& outProperties)
897 {
898     if (  isAdding && ! canAddBus    (isInput)) return false;
899     if (! isAdding && ! canRemoveBus (isInput)) return false;
900 
901     auto num = getBusCount (isInput);
902 
903     // No way for me to find out the default layout if there are no other busses!!
904     if (num == 0)
905         return false;
906 
907     if (isAdding)
908     {
909         outProperties.busName = String (isInput ? "Input #" : "Output #") + String (getBusCount (isInput));
910         outProperties.defaultLayout = (num > 0 ? getBus (isInput, num - 1)->getDefaultLayout() : AudioChannelSet());
911         outProperties.isActivatedByDefault = true;
912     }
913 
914     return true;
915 }
916 
917 //==============================================================================
Bus(AudioProcessor & processor,const String & busName,const AudioChannelSet & defaultLayout,bool isDfltEnabled)918 AudioProcessor::Bus::Bus (AudioProcessor& processor, const String& busName,
919                           const AudioChannelSet& defaultLayout, bool isDfltEnabled)
920     : owner (processor), name (busName),
921       layout (isDfltEnabled ? defaultLayout : AudioChannelSet()),
922       dfltLayout (defaultLayout), lastLayout (defaultLayout),
923       enabledByDefault (isDfltEnabled)
924 {
925     // Your default layout cannot be disabled
926     jassert (! dfltLayout.isDisabled());
927 }
928 
isInput() const929 bool AudioProcessor::Bus::isInput() const noexcept      { return owner.inputBuses.contains (this); }
getBusIndex() const930 int AudioProcessor::Bus::getBusIndex() const noexcept   { return getDirectionAndIndex().index; }
931 
getDirectionAndIndex() const932 AudioProcessor::Bus::BusDirectionAndIndex AudioProcessor::Bus::getDirectionAndIndex() const noexcept
933 {
934     BusDirectionAndIndex di;
935     di.index = owner.inputBuses.indexOf (this);
936     di.isInput = (di.index >= 0);
937 
938     if (! di.isInput)
939         di.index = owner.outputBuses.indexOf (this);
940 
941     return di;
942 }
943 
setCurrentLayout(const AudioChannelSet & busLayout)944 bool AudioProcessor::Bus::setCurrentLayout (const AudioChannelSet& busLayout)
945 {
946     auto di = getDirectionAndIndex();
947     return owner.setChannelLayoutOfBus (di.isInput, di.index, busLayout);
948 }
949 
setCurrentLayoutWithoutEnabling(const AudioChannelSet & set)950 bool AudioProcessor::Bus::setCurrentLayoutWithoutEnabling (const AudioChannelSet& set)
951 {
952     if (! set.isDisabled())
953     {
954         if (isEnabled())
955             return setCurrentLayout (set);
956 
957         if (isLayoutSupported (set))
958         {
959             lastLayout = set;
960             return true;
961         }
962 
963         return false;
964     }
965 
966     return isLayoutSupported (set);
967 }
968 
setNumberOfChannels(int channels)969 bool AudioProcessor::Bus::setNumberOfChannels (int channels)
970 {
971     auto di = getDirectionAndIndex();
972 
973     if (owner.setChannelLayoutOfBus (di.isInput, di.index, AudioChannelSet::canonicalChannelSet (channels)))
974         return true;
975 
976     if (channels == 0)
977         return false;
978 
979     auto namedSet = AudioChannelSet::namedChannelSet (channels);
980 
981     if (! namedSet.isDisabled() && owner.setChannelLayoutOfBus (di.isInput, di.index, namedSet))
982         return true;
983 
984     return owner.setChannelLayoutOfBus (di.isInput, di.index, AudioChannelSet::discreteChannels (channels));
985 }
986 
enable(bool shouldEnable)987 bool AudioProcessor::Bus::enable (bool shouldEnable)
988 {
989     if (isEnabled() == shouldEnable)
990         return true;
991 
992     return setCurrentLayout (shouldEnable ? lastLayout : AudioChannelSet::disabled());
993 }
994 
getMaxSupportedChannels(int limit) const995 int AudioProcessor::Bus::getMaxSupportedChannels (int limit) const
996 {
997     for (int ch = limit; ch > 0; --ch)
998         if (isNumberOfChannelsSupported (ch))
999             return ch;
1000 
1001     return (isMain() && isLayoutSupported (AudioChannelSet::disabled())) ? 0 : -1;
1002 }
1003 
isLayoutSupported(const AudioChannelSet & set,BusesLayout * ioLayout) const1004 bool AudioProcessor::Bus::isLayoutSupported (const AudioChannelSet& set, BusesLayout* ioLayout) const
1005 {
1006     auto di = getDirectionAndIndex();
1007 
1008     // check that supplied ioLayout is actually valid
1009     if (ioLayout != nullptr)
1010     {
1011         if (! owner.checkBusesLayoutSupported (*ioLayout))
1012         {
1013             *ioLayout = owner.getBusesLayout();
1014 
1015             // the current layout you supplied is not a valid layout
1016             jassertfalse;
1017         }
1018     }
1019 
1020     auto currentLayout = (ioLayout != nullptr ? *ioLayout : owner.getBusesLayout());
1021     auto& actualBuses = (di.isInput ? currentLayout.inputBuses : currentLayout.outputBuses);
1022 
1023     if (actualBuses.getReference (di.index) == set)
1024         return true;
1025 
1026     auto desiredLayout = currentLayout;
1027 
1028     (di.isInput ? desiredLayout.inputBuses
1029                 : desiredLayout.outputBuses).getReference (di.index) = set;
1030 
1031     owner.getNextBestLayout (desiredLayout, currentLayout);
1032 
1033     if (ioLayout != nullptr)
1034         *ioLayout = currentLayout;
1035 
1036     // Nearest layout has a different number of buses. JUCE plug-ins MUST
1037     // have fixed number of buses.
1038     jassert (currentLayout.inputBuses. size() == owner.getBusCount (true)
1039           && currentLayout.outputBuses.size() == owner.getBusCount (false));
1040 
1041     return actualBuses.getReference (di.index) == set;
1042 }
1043 
isNumberOfChannelsSupported(int channels) const1044 bool AudioProcessor::Bus::isNumberOfChannelsSupported (int channels) const
1045 {
1046     if (channels == 0)
1047         return isLayoutSupported(AudioChannelSet::disabled());
1048 
1049     auto set = supportedLayoutWithChannels (channels);
1050     return (! set.isDisabled()) && isLayoutSupported (set);
1051 }
1052 
supportedLayoutWithChannels(int channels) const1053 AudioChannelSet AudioProcessor::Bus::supportedLayoutWithChannels (int channels) const
1054 {
1055     if (channels == 0)
1056         return AudioChannelSet::disabled();
1057 
1058     {
1059         AudioChannelSet set;
1060 
1061         if (! (set = AudioChannelSet::namedChannelSet  (channels)).isDisabled() && isLayoutSupported (set))
1062             return set;
1063 
1064         if (! (set = AudioChannelSet::discreteChannels (channels)).isDisabled() && isLayoutSupported (set))
1065             return set;
1066     }
1067 
1068     for (auto& set : AudioChannelSet::channelSetsWithNumberOfChannels (channels))
1069         if (isLayoutSupported (set))
1070             return set;
1071 
1072     return AudioChannelSet::disabled();
1073 }
1074 
getBusesLayoutForLayoutChangeOfBus(const AudioChannelSet & set) const1075 AudioProcessor::BusesLayout AudioProcessor::Bus::getBusesLayoutForLayoutChangeOfBus (const AudioChannelSet& set) const
1076 {
1077     auto layouts = owner.getBusesLayout();
1078     isLayoutSupported (set, &layouts);
1079     return layouts;
1080 }
1081 
getChannelIndexInProcessBlockBuffer(int channelIndex) const1082 int AudioProcessor::Bus::getChannelIndexInProcessBlockBuffer (int channelIndex) const noexcept
1083 {
1084     auto di = getDirectionAndIndex();
1085     return owner.getChannelIndexInProcessBlockBuffer (di.isInput, di.index, channelIndex);
1086 }
1087 
updateChannelCount()1088 void AudioProcessor::Bus::updateChannelCount() noexcept
1089 {
1090     cachedChannelCount = layout.size();
1091 }
1092 
1093 //==============================================================================
addBus(bool isInput,const String & name,const AudioChannelSet & dfltLayout,bool isActivatedByDefault)1094 void AudioProcessor::BusesProperties::addBus (bool isInput, const String& name,
1095                                               const AudioChannelSet& dfltLayout, bool isActivatedByDefault)
1096 {
1097     jassert (dfltLayout.size() != 0);
1098 
1099     BusProperties props;
1100 
1101     props.busName = name;
1102     props.defaultLayout = dfltLayout;
1103     props.isActivatedByDefault = isActivatedByDefault;
1104 
1105     (isInput ? inputLayouts : outputLayouts).add (props);
1106 }
1107 
withInput(const String & name,const AudioChannelSet & dfltLayout,bool isActivatedByDefault) const1108 AudioProcessor::BusesProperties AudioProcessor::BusesProperties::withInput  (const String& name,
1109                                                                              const AudioChannelSet& dfltLayout,
1110                                                                              bool isActivatedByDefault) const
1111 {
1112     auto retval = *this;
1113     retval.addBus (true, name, dfltLayout, isActivatedByDefault);
1114     return retval;
1115 }
1116 
withOutput(const String & name,const AudioChannelSet & dfltLayout,bool isActivatedByDefault) const1117 AudioProcessor::BusesProperties AudioProcessor::BusesProperties::withOutput (const String& name,
1118                                                                              const AudioChannelSet& dfltLayout,
1119                                                                              bool isActivatedByDefault) const
1120 {
1121     auto retval = *this;
1122     retval.addBus (false, name, dfltLayout, isActivatedByDefault);
1123     return retval;
1124 }
1125 
1126 //==============================================================================
getAAXPluginIDForMainBusConfig(const AudioChannelSet & mainInputLayout,const AudioChannelSet & mainOutputLayout,const bool idForAudioSuite) const1127 int32 AudioProcessor::getAAXPluginIDForMainBusConfig (const AudioChannelSet& mainInputLayout,
1128                                                       const AudioChannelSet& mainOutputLayout,
1129                                                       const bool idForAudioSuite) const
1130 {
1131     int uniqueFormatId = 0;
1132 
1133     for (int dir = 0; dir < 2; ++dir)
1134     {
1135         const bool isInput = (dir == 0);
1136         auto& set = (isInput ? mainInputLayout : mainOutputLayout);
1137         int aaxFormatIndex = 0;
1138 
1139         if      (set == AudioChannelSet::disabled())             aaxFormatIndex = 0;
1140         else if (set == AudioChannelSet::mono())                 aaxFormatIndex = 1;
1141         else if (set == AudioChannelSet::stereo())               aaxFormatIndex = 2;
1142         else if (set == AudioChannelSet::createLCR())            aaxFormatIndex = 3;
1143         else if (set == AudioChannelSet::createLCRS())           aaxFormatIndex = 4;
1144         else if (set == AudioChannelSet::quadraphonic())         aaxFormatIndex = 5;
1145         else if (set == AudioChannelSet::create5point0())        aaxFormatIndex = 6;
1146         else if (set == AudioChannelSet::create5point1())        aaxFormatIndex = 7;
1147         else if (set == AudioChannelSet::create6point0())        aaxFormatIndex = 8;
1148         else if (set == AudioChannelSet::create6point1())        aaxFormatIndex = 9;
1149         else if (set == AudioChannelSet::create7point0())        aaxFormatIndex = 10;
1150         else if (set == AudioChannelSet::create7point1())        aaxFormatIndex = 11;
1151         else if (set == AudioChannelSet::create7point0SDDS())    aaxFormatIndex = 12;
1152         else if (set == AudioChannelSet::create7point1SDDS())    aaxFormatIndex = 13;
1153         else if (set == AudioChannelSet::create7point0point2())  aaxFormatIndex = 14;
1154         else if (set == AudioChannelSet::create7point1point2())  aaxFormatIndex = 15;
1155         else if (set == AudioChannelSet::ambisonic (1))          aaxFormatIndex = 16;
1156         else if (set == AudioChannelSet::ambisonic (2))          aaxFormatIndex = 17;
1157         else if (set == AudioChannelSet::ambisonic (3))          aaxFormatIndex = 18;
1158         else
1159         {
1160             // AAX does not support this format and the wrapper should not have
1161             // called this method with this layout
1162             jassertfalse;
1163         }
1164 
1165         uniqueFormatId = (uniqueFormatId << 8) | aaxFormatIndex;
1166     }
1167 
1168     return (idForAudioSuite ? 0x6a796161 /* 'jyaa' */ : 0x6a636161 /* 'jcaa' */) + uniqueFormatId;
1169 }
1170 
1171 //==============================================================================
getWrapperTypeDescription(AudioProcessor::WrapperType type)1172 const char* AudioProcessor::getWrapperTypeDescription (AudioProcessor::WrapperType type) noexcept
1173 {
1174     switch (type)
1175     {
1176         case AudioProcessor::wrapperType_Undefined:     return "Undefined";
1177         case AudioProcessor::wrapperType_VST:           return "VST";
1178         case AudioProcessor::wrapperType_VST3:          return "VST3";
1179         case AudioProcessor::wrapperType_AudioUnit:     return "AU";
1180         case AudioProcessor::wrapperType_AudioUnitv3:   return "AUv3";
1181         case AudioProcessor::wrapperType_RTAS:          return "RTAS";
1182         case AudioProcessor::wrapperType_AAX:           return "AAX";
1183         case AudioProcessor::wrapperType_Standalone:    return "Standalone";
1184         case AudioProcessor::wrapperType_Unity:         return "Unity";
1185         default:                                        jassertfalse; return {};
1186     }
1187 }
1188 
1189 //==============================================================================
1190 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
1191 JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
1192 
setParameterNotifyingHost(int parameterIndex,float newValue)1193 void AudioProcessor::setParameterNotifyingHost (int parameterIndex, float newValue)
1194 {
1195     if (auto* param = getParameters()[parameterIndex])
1196     {
1197         param->setValueNotifyingHost (newValue);
1198     }
1199     else if (isPositiveAndBelow (parameterIndex, getNumParameters()))
1200     {
1201         setParameter (parameterIndex, newValue);
1202         sendParamChangeMessageToListeners (parameterIndex, newValue);
1203     }
1204 }
1205 
sendParamChangeMessageToListeners(int parameterIndex,float newValue)1206 void AudioProcessor::sendParamChangeMessageToListeners (int parameterIndex, float newValue)
1207 {
1208     if (auto* param = getParameters()[parameterIndex])
1209     {
1210         param->sendValueChangedMessageToListeners (newValue);
1211     }
1212     else
1213     {
1214         if (isPositiveAndBelow (parameterIndex, getNumParameters()))
1215         {
1216             for (int i = listeners.size(); --i >= 0;)
1217                 if (auto* l = getListenerLocked (i))
1218                     l->audioProcessorParameterChanged (this, parameterIndex, newValue);
1219         }
1220         else
1221         {
1222             jassertfalse; // called with an out-of-range parameter index!
1223         }
1224     }
1225 }
1226 
beginParameterChangeGesture(int parameterIndex)1227 void AudioProcessor::beginParameterChangeGesture (int parameterIndex)
1228 {
1229     if (auto* param = getParameters()[parameterIndex])
1230     {
1231         param->beginChangeGesture();
1232     }
1233     else
1234     {
1235         if (isPositiveAndBelow (parameterIndex, getNumParameters()))
1236         {
1237            #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
1238             // This means you've called beginParameterChangeGesture twice in succession without a matching
1239             // call to endParameterChangeGesture. That might be fine in most hosts, but better to avoid doing it.
1240             jassert (! changingParams[parameterIndex]);
1241             changingParams.setBit (parameterIndex);
1242            #endif
1243 
1244             for (int i = listeners.size(); --i >= 0;)
1245                 if (auto* l = getListenerLocked (i))
1246                     l->audioProcessorParameterChangeGestureBegin (this, parameterIndex);
1247         }
1248         else
1249         {
1250             jassertfalse; // called with an out-of-range parameter index!
1251         }
1252     }
1253 }
1254 
endParameterChangeGesture(int parameterIndex)1255 void AudioProcessor::endParameterChangeGesture (int parameterIndex)
1256 {
1257     if (auto* param = getParameters()[parameterIndex])
1258     {
1259         param->endChangeGesture();
1260     }
1261     else
1262     {
1263         if (isPositiveAndBelow (parameterIndex, getNumParameters()))
1264         {
1265            #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
1266             // This means you've called endParameterChangeGesture without having previously called
1267             // beginParameterChangeGesture. That might be fine in most hosts, but better to keep the
1268             // calls matched correctly.
1269             jassert (changingParams[parameterIndex]);
1270             changingParams.clearBit (parameterIndex);
1271            #endif
1272 
1273             for (int i = listeners.size(); --i >= 0;)
1274                 if (auto* l = getListenerLocked (i))
1275                     l->audioProcessorParameterChangeGestureEnd (this, parameterIndex);
1276         }
1277         else
1278         {
1279             jassertfalse; // called with an out-of-range parameter index!
1280         }
1281     }
1282 }
1283 
getParameterName(int index,int maximumStringLength)1284 String AudioProcessor::getParameterName (int index, int maximumStringLength)
1285 {
1286     if (auto* p = getParameters()[index])
1287         return p->getName (maximumStringLength);
1288 
1289     return isPositiveAndBelow (index, getNumParameters()) ? getParameterName (index).substring (0, maximumStringLength)
1290                                                           : String();
1291 }
1292 
getParameterText(int index)1293 const String AudioProcessor::getParameterText (int index)
1294 {
1295    #if JUCE_DEBUG
1296     // if you hit this, then you're probably using the old parameter control methods,
1297     // but have forgotten to implement either of the getParameterText() methods.
1298     jassert (! textRecursionCheck);
1299     ScopedValueSetter<bool> sv (textRecursionCheck, true, false);
1300    #endif
1301 
1302     return isPositiveAndBelow (index, getNumParameters()) ? getParameterText (index, 1024)
1303                                                           : String();
1304 }
1305 
getParameterText(int index,int maximumStringLength)1306 String AudioProcessor::getParameterText (int index, int maximumStringLength)
1307 {
1308     if (auto* p = getParameters()[index])
1309         return p->getText (p->getValue(), maximumStringLength);
1310 
1311     return isPositiveAndBelow (index, getNumParameters()) ? getParameterText (index).substring (0, maximumStringLength)
1312                                                           : String();
1313 }
1314 
getNumParameters()1315 int AudioProcessor::getNumParameters()
1316 {
1317     return getParameters().size();
1318 }
1319 
getParameter(int index)1320 float AudioProcessor::getParameter (int index)
1321 {
1322     if (auto* p = getParamChecked (index))
1323         return p->getValue();
1324 
1325     return 0;
1326 }
1327 
setParameter(int index,float newValue)1328 void AudioProcessor::setParameter (int index, float newValue)
1329 {
1330     if (auto* p = getParamChecked (index))
1331         p->setValue (newValue);
1332 }
1333 
getParameterDefaultValue(int index)1334 float AudioProcessor::getParameterDefaultValue (int index)
1335 {
1336     if (auto* p = getParameters()[index])
1337         return p->getDefaultValue();
1338 
1339     return 0;
1340 }
1341 
getParameterName(int index)1342 const String AudioProcessor::getParameterName (int index)
1343 {
1344     if (auto* p = getParamChecked (index))
1345         return p->getName (512);
1346 
1347     return {};
1348 }
1349 
getParameterID(int index)1350 String AudioProcessor::getParameterID (int index)
1351 {
1352     // Don't use getParamChecked here, as this must also work for legacy plug-ins
1353     if (auto* p = dynamic_cast<AudioProcessorParameterWithID*> (getParameters()[index]))
1354         return p->paramID;
1355 
1356     return String (index);
1357 }
1358 
getParameterNumSteps(int index)1359 int AudioProcessor::getParameterNumSteps (int index)
1360 {
1361     if (auto* p = getParameters()[index])
1362         return p->getNumSteps();
1363 
1364     return AudioProcessor::getDefaultNumParameterSteps();
1365 }
1366 
isParameterDiscrete(int index) const1367 bool AudioProcessor::isParameterDiscrete (int index) const
1368 {
1369     if (auto* p = getParameters()[index])
1370         return p->isDiscrete();
1371 
1372     return false;
1373 }
1374 
getParameterLabel(int index) const1375 String AudioProcessor::getParameterLabel (int index) const
1376 {
1377     if (auto* p = getParameters()[index])
1378         return p->getLabel();
1379 
1380     return {};
1381 }
1382 
isParameterAutomatable(int index) const1383 bool AudioProcessor::isParameterAutomatable (int index) const
1384 {
1385     if (auto* p = getParameters()[index])
1386         return p->isAutomatable();
1387 
1388     return true;
1389 }
1390 
isParameterOrientationInverted(int index) const1391 bool AudioProcessor::isParameterOrientationInverted (int index) const
1392 {
1393     if (auto* p = getParameters()[index])
1394         return p->isOrientationInverted();
1395 
1396     return false;
1397 }
1398 
isMetaParameter(int index) const1399 bool AudioProcessor::isMetaParameter (int index) const
1400 {
1401     if (auto* p = getParameters()[index])
1402         return p->isMetaParameter();
1403 
1404     return false;
1405 }
1406 
getParameterCategory(int index) const1407 AudioProcessorParameter::Category AudioProcessor::getParameterCategory (int index) const
1408 {
1409     if (auto* p = getParameters()[index])
1410         return p->getCategory();
1411 
1412     return AudioProcessorParameter::genericParameter;
1413 }
1414 
getParamChecked(int index) const1415 AudioProcessorParameter* AudioProcessor::getParamChecked (int index) const
1416 {
1417     auto p = getParameters()[index];
1418 
1419     // If you hit this, then you're either trying to access parameters that are out-of-range,
1420     // or you're not using addParameter and the managed parameter list, but have failed
1421     // to override some essential virtual methods and implement them appropriately.
1422     jassert (p != nullptr);
1423     return p;
1424 }
1425 
1426 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
1427 JUCE_END_IGNORE_WARNINGS_MSVC
1428 
1429 //==============================================================================
audioProcessorParameterChangeGestureBegin(AudioProcessor *,int)1430 void AudioProcessorListener::audioProcessorParameterChangeGestureBegin (AudioProcessor*, int) {}
audioProcessorParameterChangeGestureEnd(AudioProcessor *,int)1431 void AudioProcessorListener::audioProcessorParameterChangeGestureEnd   (AudioProcessor*, int) {}
1432 
1433 //==============================================================================
AudioProcessorParameter()1434 AudioProcessorParameter::AudioProcessorParameter() noexcept {}
1435 
~AudioProcessorParameter()1436 AudioProcessorParameter::~AudioProcessorParameter()
1437 {
1438    #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
1439     // This will fail if you've called beginChangeGesture() without having made
1440     // a corresponding call to endChangeGesture...
1441     jassert (! isPerformingGesture);
1442    #endif
1443 }
1444 
setValueNotifyingHost(float newValue)1445 void AudioProcessorParameter::setValueNotifyingHost (float newValue)
1446 {
1447     setValue (newValue);
1448     sendValueChangedMessageToListeners (newValue);
1449 }
1450 
beginChangeGesture()1451 void AudioProcessorParameter::beginChangeGesture()
1452 {
1453     // This method can't be used until the parameter has been attached to a processor!
1454     jassert (processor != nullptr && parameterIndex >= 0);
1455 
1456    #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
1457     // This means you've called beginChangeGesture twice in succession without
1458     // a matching call to endChangeGesture. That might be fine in most hosts,
1459     // but it would be better to avoid doing it.
1460     jassert (! isPerformingGesture);
1461     isPerformingGesture = true;
1462    #endif
1463 
1464     ScopedLock lock (listenerLock);
1465 
1466     for (int i = listeners.size(); --i >= 0;)
1467         if (auto* l = listeners[i])
1468             l->parameterGestureChanged (getParameterIndex(), true);
1469 
1470     if (processor != nullptr && parameterIndex >= 0)
1471     {
1472         // audioProcessorParameterChangeGestureBegin callbacks will shortly be deprecated and
1473         // this code will be removed.
1474         for (int i = processor->listeners.size(); --i >= 0;)
1475             if (auto* l = processor->listeners[i])
1476                 l->audioProcessorParameterChangeGestureBegin (processor, getParameterIndex());
1477     }
1478 }
1479 
endChangeGesture()1480 void AudioProcessorParameter::endChangeGesture()
1481 {
1482     // This method can't be used until the parameter has been attached to a processor!
1483     jassert (processor != nullptr && parameterIndex >= 0);
1484 
1485    #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
1486     // This means you've called endChangeGesture without having previously
1487     // called beginChangeGesture. That might be fine in most hosts, but it
1488     // would be better to keep the calls matched correctly.
1489     jassert (isPerformingGesture);
1490     isPerformingGesture = false;
1491    #endif
1492 
1493     ScopedLock lock (listenerLock);
1494 
1495     for (int i = listeners.size(); --i >= 0;)
1496         if (auto* l = listeners[i])
1497             l->parameterGestureChanged (getParameterIndex(), false);
1498 
1499     if (processor != nullptr && parameterIndex >= 0)
1500     {
1501         // audioProcessorParameterChangeGestureEnd callbacks will shortly be deprecated and
1502         // this code will be removed.
1503         for (int i = processor->listeners.size(); --i >= 0;)
1504             if (auto* l = processor->listeners[i])
1505                 l->audioProcessorParameterChangeGestureEnd (processor, getParameterIndex());
1506     }
1507 }
1508 
sendValueChangedMessageToListeners(float newValue)1509 void AudioProcessorParameter::sendValueChangedMessageToListeners (float newValue)
1510 {
1511     ScopedLock lock (listenerLock);
1512 
1513     for (int i = listeners.size(); --i >= 0;)
1514         if (auto* l = listeners [i])
1515             l->parameterValueChanged (getParameterIndex(), newValue);
1516 
1517     if (processor != nullptr && parameterIndex >= 0)
1518     {
1519         // audioProcessorParameterChanged callbacks will shortly be deprecated and
1520         // this code will be removed.
1521         for (int i = processor->listeners.size(); --i >= 0;)
1522             if (auto* l = processor->listeners[i])
1523                 l->audioProcessorParameterChanged (processor, getParameterIndex(), newValue);
1524     }
1525 }
1526 
isOrientationInverted() const1527 bool AudioProcessorParameter::isOrientationInverted() const                      { return false; }
isAutomatable() const1528 bool AudioProcessorParameter::isAutomatable() const                              { return true; }
isMetaParameter() const1529 bool AudioProcessorParameter::isMetaParameter() const                            { return false; }
getCategory() const1530 AudioProcessorParameter::Category AudioProcessorParameter::getCategory() const   { return genericParameter; }
getNumSteps() const1531 int AudioProcessorParameter::getNumSteps() const                                 { return AudioProcessor::getDefaultNumParameterSteps(); }
isDiscrete() const1532 bool AudioProcessorParameter::isDiscrete() const                                 { return false; }
isBoolean() const1533 bool AudioProcessorParameter::isBoolean() const                                  { return false; }
1534 
getText(float value,int) const1535 String AudioProcessorParameter::getText (float value, int /*maximumStringLength*/) const
1536 {
1537     return String (value, 2);
1538 }
1539 
getCurrentValueAsText() const1540 String AudioProcessorParameter::getCurrentValueAsText() const
1541 {
1542     return getText (getValue(), 1024);
1543 }
1544 
getAllValueStrings() const1545 StringArray AudioProcessorParameter::getAllValueStrings() const
1546 {
1547     if (isDiscrete() && valueStrings.isEmpty())
1548     {
1549         auto maxIndex = getNumSteps() - 1;
1550 
1551         for (int i = 0; i < getNumSteps(); ++i)
1552             valueStrings.add (getText ((float) i / (float) maxIndex, 1024));
1553     }
1554 
1555     return valueStrings;
1556 }
1557 
addListener(AudioProcessorParameter::Listener * newListener)1558 void AudioProcessorParameter::addListener (AudioProcessorParameter::Listener* newListener)
1559 {
1560     const ScopedLock sl (listenerLock);
1561     listeners.addIfNotAlreadyThere (newListener);
1562 }
1563 
removeListener(AudioProcessorParameter::Listener * listenerToRemove)1564 void AudioProcessorParameter::removeListener (AudioProcessorParameter::Listener* listenerToRemove)
1565 {
1566     const ScopedLock sl (listenerLock);
1567     listeners.removeFirstMatchingValue (listenerToRemove);
1568 }
1569 
1570 } // namespace juce
1571