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