JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_AudioProcessor.cpp
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - 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 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-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
26namespace juce
27{
28
29static ThreadLocalValue<AudioProcessor::WrapperType> wrapperTypeBeingCreated;
30
31void JUCE_CALLTYPE AudioProcessor::setTypeOfNextNewPlugin (AudioProcessor::WrapperType type)
32{
33 wrapperTypeBeingCreated = type;
34}
35
37 : AudioProcessor (BusesProperties().withInput ("Input", AudioChannelSet::stereo(), false)
38 .withOutput ("Output", AudioChannelSet::stereo(), false))
39{
40}
41
43 : wrapperType (wrapperTypeBeingCreated.get())
44{
45 for (auto& layout : ioConfig.inputLayouts) createBus (true, layout);
46 for (auto& layout : ioConfig.outputLayouts) createBus (false, layout);
47
48 updateSpeakerFormatStrings();
49}
50
52{
53 {
54 const ScopedLock sl (activeEditorLock);
55
56 // ooh, nasty - the editor should have been deleted before its AudioProcessor.
57 jassert (activeEditor == nullptr);
58 }
59
60 #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
61 // This will fail if you've called beginParameterChangeGesture() for one
62 // or more parameters without having made a corresponding call to endParameterChangeGesture...
63 jassert (changingParams.countNumberOfSetBits() == 0);
64 #endif
65}
66
67//==============================================================================
69
70//==============================================================================
71bool AudioProcessor::addBus (bool isInput)
72{
73 if (! canAddBus (isInput))
74 return false;
75
77
78 if (! canApplyBusCountChange (isInput, true, busesProps))
79 return false;
80
81 createBus (isInput, busesProps);
82 return true;
83}
84
86{
88
89 if (numBuses == 0)
90 return false;
91
92 if (! canRemoveBus (inputBus))
93 return false;
94
96
98 return false;
99
100 auto busIndex = numBuses - 1;
101 auto numChannels = getChannelCountOfBus (inputBus, busIndex);
102 (inputBus ? inputBuses : outputBuses).remove (busIndex);
103
104 audioIOChanged (true, numChannels > 0);
105 return true;
106}
107
108//==============================================================================
110{
111 jassert (arr.inputBuses. size() == getBusCount (true)
112 && arr.outputBuses.size() == getBusCount (false));
113
114 if (arr == getBusesLayout())
115 return true;
116
117 auto copy = arr;
118
119 if (! canApplyBusesLayout (copy))
120 return false;
121
122 return applyBusLayouts (copy);
123}
124
126{
127 auto numIns = getBusCount (true);
128 auto numOuts = getBusCount (false);
129
130 jassert (arr.inputBuses. size() == numIns
131 && arr.outputBuses.size() == numOuts);
132
133 auto request = arr;
134 auto current = getBusesLayout();
135
136 for (int i = 0; i < numIns; ++i)
137 if (request.getNumChannels (true, i) == 0)
138 request.getChannelSet (true, i) = current.getChannelSet (true, i);
139
140 for (int i = 0; i < numOuts; ++i)
141 if (request.getNumChannels (false, i) == 0)
142 request.getChannelSet (false, i) = current.getChannelSet (false, i);
143
144 if (! checkBusesLayoutSupported (request))
145 return false;
146
147 for (int dir = 0; dir < 2; ++dir)
148 {
149 const bool isInput = (dir != 0);
150
151 for (int i = 0; i < (isInput ? numIns : numOuts); ++i)
152 {
153 auto& bus = *getBus (isInput, i);
154 auto& set = request.getChannelSet (isInput, i);
155
156 if (! bus.isEnabled())
157 {
158 if (! set.isDisabled())
159 bus.lastLayout = set;
160
162 }
163 }
164 }
165
166 return setBusesLayout (request);
167}
168
170{
172
173 for (auto& i : inputBuses) layouts.inputBuses.add (i->getCurrentLayout());
174 for (auto& i : outputBuses) layouts.outputBuses.add (i->getCurrentLayout());
175
176 return layouts;
177}
178
179AudioChannelSet AudioProcessor::getChannelLayoutOfBus (bool isInput, int busIndex) const noexcept
180{
181 if (auto* bus = (isInput ? inputBuses : outputBuses)[busIndex])
182 return bus->getCurrentLayout();
183
184 return {};
185}
186
188{
189 if (auto* bus = getBus (isInputBus, busIndex))
190 {
191 auto layouts = bus->getBusesLayoutForLayoutChangeOfBus (layout);
192
193 if (layouts.getChannelSet (isInputBus, busIndex) == layout)
194 return applyBusLayouts (layouts);
195
196 return false;
197 }
198
199 jassertfalse; // busIndex parameter is invalid
200 return false;
201}
202
204{
206
207 for (auto& i : inputBuses) layouts.inputBuses.add (i->lastLayout);
208 for (auto& i : outputBuses) layouts.outputBuses.add (i->lastLayout);
209
210 return setBusesLayout (layouts);
211}
212
214{
215 if (layouts.inputBuses.size() == inputBuses.size()
216 && layouts.outputBuses.size() == outputBuses.size())
218
219 return false;
220}
221
222void AudioProcessor::getNextBestLayout (const BusesLayout& desiredLayout, BusesLayout& actualLayouts) const
223{
224 // if you are hitting this assertion then you are requesting a next
225 // best layout which does not have the same number of buses as the
226 // audio processor.
227 jassert (desiredLayout.inputBuses.size() == inputBuses.size()
228 && desiredLayout.outputBuses.size() == outputBuses.size());
229
231 {
233 return;
234 }
235
237 auto currentState = originalState;
238 auto bestSupported = currentState;
239
240 for (int dir = 0; dir < 2; ++dir)
241 {
242 const bool isInput = (dir > 0);
243
244 auto& currentLayouts = (isInput ? currentState.inputBuses : currentState.outputBuses);
245 auto& bestLayouts = (isInput ? bestSupported.inputBuses : bestSupported.outputBuses);
246 auto& requestedLayouts = (isInput ? desiredLayout.inputBuses : desiredLayout.outputBuses);
247 auto& originalLayouts = (isInput ? originalState.inputBuses : originalState.outputBuses);
248
249 for (int busIndex = 0; busIndex < requestedLayouts.size(); ++busIndex)
250 {
251 auto& best = bestLayouts .getReference (busIndex);
252 auto& requested = requestedLayouts.getReference (busIndex);
253 auto& original = originalLayouts .getReference (busIndex);
254
255 // do we need to do anything
256 if (original == requested)
257 continue;
258
259 currentState = bestSupported;
260 auto& current = currentLayouts .getReference (busIndex);
261
262 // already supported?
263 current = requested;
264
265 if (checkBusesLayoutSupported (currentState))
266 {
267 bestSupported = currentState;
268 continue;
269 }
270
271 // try setting the opposite bus to the identical layout
272 const bool oppositeDirection = ! isInput;
273
274 if (getBusCount (oppositeDirection) > busIndex)
275 {
276 auto& oppositeLayout = (oppositeDirection ? currentState.inputBuses : currentState.outputBuses).getReference (busIndex);
278
279 if (checkBusesLayoutSupported (currentState))
280 {
281 bestSupported = currentState;
282 continue;
283 }
284
285 // try setting the default layout
287
288 if (checkBusesLayoutSupported (currentState))
289 {
290 bestSupported = currentState;
291 continue;
292 }
293 }
294
295 // try setting all other buses to the identical layout
296 BusesLayout allTheSame;
297 allTheSame.inputBuses.insertMultiple (-1, requested, getBusCount (true));
298 allTheSame.outputBuses.insertMultiple (-1, requested, getBusCount (false));
299
301 {
303 continue;
304 }
305
306 // what is closer the default or the current layout?
307 auto distance = std::abs (best.size() - requested.size());
308 auto& defaultLayout = getBus (isInput, busIndex)->getDefaultLayout();
309
310 if (std::abs (defaultLayout.size() - requested.size()) < distance)
311 {
312 current = defaultLayout;
313
314 if (checkBusesLayoutSupported (currentState))
315 bestSupported = currentState;
316 }
317 }
318 }
319
321}
322
323//==============================================================================
328
330{
331 const ScopedLock sl (listenerLock);
332 listeners.addIfNotAlreadyThere (newListener);
333}
334
336{
337 const ScopedLock sl (listenerLock);
338 listeners.removeFirstMatchingValue (listenerToRemove);
339}
340
342{
343 [[maybe_unused]] bool success = true;
344
347
348 // failed to find a compatible input configuration
349 jassert (success);
350
353
354 // failed to find a compatible output configuration
355 jassert (success);
356
357 // if the user is using this method then they do not want any side-buses or aux outputs
358 success &= disableNonMainBuses();
359 jassert (success);
360
361 // the processor may not support this arrangement at all
363
365}
366
368{
369 currentSampleRate = newSampleRate;
370 blockSize = newBlockSize;
371}
372
373//==============================================================================
377
378int AudioProcessor::getChannelIndexInProcessBlockBuffer (bool isInput, int busIndex, int channelIndex) const noexcept
379{
380 auto& ioBus = isInput ? inputBuses : outputBuses;
381 jassert (isPositiveAndBelow (busIndex, ioBus.size()));
382
383 for (int i = 0; i < ioBus.size() && i < busIndex; ++i)
384 channelIndex += getChannelCountOfBus (isInput, i);
385
386 return channelIndex;
387}
388
390{
391 auto numBuses = getBusCount (isInput);
392 int numChannels = 0;
393
394 for (busIndex = 0; busIndex < numBuses && absoluteChannelIndex >= (numChannels = getChannelLayoutOfBus (isInput, busIndex).size()); ++busIndex)
395 absoluteChannelIndex -= numChannels;
396
397 return busIndex >= numBuses ? -1 : absoluteChannelIndex;
398}
399
400//==============================================================================
402{
403 nonRealtime = newNonRealtime;
404}
405
407{
408 if (latencySamples != newLatency)
409 {
410 latencySamples = newLatency;
411 updateHostDisplay (AudioProcessorListener::ChangeDetails().withLatencyChanged (true));
412 }
413}
414
415//==============================================================================
416AudioProcessorListener* AudioProcessor::getListenerLocked (int index) const noexcept
417{
418 const ScopedLock sl (listenerLock);
419 return listeners[index];
420}
421
423{
424 for (int i = listeners.size(); --i >= 0;)
425 if (auto l = getListenerLocked (i))
426 l->audioProcessorChanged (this, details);
427}
428
429void AudioProcessor::validateParameter (AudioProcessorParameter* param)
430{
431 checkForDuplicateParamID (param);
432 checkForDuplicateTrimmedParamID (param);
433
434 /* If you're building this plugin as an AudioUnit, and you intend to use the plugin in
435 Logic Pro or GarageBand, it's a good idea to set version hints on all of your parameters
436 so that you can add parameters safely in future versions of the plugin.
437 See the documentation for AudioProcessorParameter (int) for more information.
438 */
439 #if JucePlugin_Build_AU
440 static std::once_flag flag;
441 if (wrapperType != wrapperType_Undefined && param->getVersionHint() == 0)
442 std::call_once (flag, [] { jassertfalse; });
443 #endif
444}
445
446void AudioProcessor::checkForDuplicateTrimmedParamID ([[maybe_unused]] AudioProcessorParameter* param)
447{
448 #if JUCE_DEBUG && ! JUCE_DISABLE_CAUTIOUS_PARAMETER_ID_CHECKING
449 if (auto* withID = dynamic_cast<HostedAudioProcessorParameter*> (param))
450 {
451 [[maybe_unused]] constexpr auto maximumSafeAAXParameterIdLength = 31;
452
453 const auto paramID = withID->getParameterID();
454
455 // If you hit this assertion, a parameter name is too long to be supported
456 // by the AAX plugin format.
457 // If there's a chance that you'll release this plugin in AAX format, you
458 // should consider reducing the length of this paramID.
459 // If you need to retain backwards-compatibility and are unable to change
460 // the paramID for this reason, you can add JUCE_DISABLE_CAUTIOUS_PARAMETER_ID_CHECKING
461 // to your preprocessor definitions to silence this assertion.
462 jassert (paramID.length() <= maximumSafeAAXParameterIdLength);
463
464 // If you hit this assertion, two or more parameters have duplicate paramIDs
465 // after they have been truncated to support the AAX format.
466 // This is a serious issue, and will prevent the duplicated parameters from
467 // being automated when running as an AAX plugin.
468 // If there's a chance that you'll release this plugin in AAX format, you
469 // should reduce the length of this paramID.
470 // If you need to retain backwards-compatibility and are unable to change
471 // the paramID for this reason, you can add JUCE_DISABLE_CAUTIOUS_PARAMETER_ID_CHECKING
472 // to your preprocessor definitions to silence this assertion.
473 jassert (trimmedParamIDs.insert (paramID.substring (0, maximumSafeAAXParameterIdLength)).second);
474 }
475 #endif
476}
477
478void AudioProcessor::checkForDuplicateParamID ([[maybe_unused]] AudioProcessorParameter* param)
479{
480 #if JUCE_DEBUG
481 if (auto* withID = dynamic_cast<HostedAudioProcessorParameter*> (param))
482 {
483 auto insertResult = paramIDs.insert (withID->getParameterID());
484
485 // If you hit this assertion then the parameter ID is not unique
486 jassert (insertResult.second);
487 }
488 #endif
489}
490
491void AudioProcessor::checkForDuplicateGroupIDs ([[maybe_unused]] const AudioProcessorParameterGroup& newGroup)
492{
493 #if JUCE_DEBUG
494 auto groups = newGroup.getSubgroups (true);
495 groups.add (&newGroup);
496
497 for (auto* group : groups)
498 {
499 auto insertResult = groupIDs.insert (group->getID());
500
501 // If you hit this assertion then a group ID is not unique
502 jassert (insertResult.second);
503 }
504 #endif
505}
506
507const Array<AudioProcessorParameter*>& AudioProcessor::getParameters() const { return flatParameterList; }
509
511{
512 jassert (param != nullptr);
514
515 param->processor = this;
516 param->parameterIndex = flatParameterList.size();
517 flatParameterList.add (param);
518
519 validateParameter (param);
520}
521
523{
524 jassert (group != nullptr);
525 checkForDuplicateGroupIDs (*group);
526
527 auto oldSize = flatParameterList.size();
528 flatParameterList.addArray (group->getParameters (true));
529
530 for (int i = oldSize; i < flatParameterList.size(); ++i)
531 {
532 auto p = flatParameterList.getUnchecked (i);
533 p->processor = this;
534 p->parameterIndex = i;
535
536 validateParameter (p);
537 }
538
539 parameterTree.addChild (std::move (group));
540}
541
543{
544 #if JUCE_DEBUG
545 paramIDs.clear();
546 groupIDs.clear();
547 #if ! JUCE_DISABLE_CAUTIOUS_PARAMETER_ID_CHECKING
548 trimmedParamIDs.clear();
549 #endif
550 #endif
551
552 parameterTree = std::move (newTree);
553 checkForDuplicateGroupIDs (parameterTree);
554
555 flatParameterList = parameterTree.getParameters (true);
556
557 for (int i = 0; i < flatParameterList.size(); ++i)
558 {
559 auto p = flatParameterList.getUnchecked (i);
560 p->processor = this;
561 p->parameterIndex = i;
562
563 validateParameter (p);
564 }
565}
566
568
570{
571 return 0x7fffffff;
572}
573
575{
576 const ScopedLock sl (callbackLock);
577 suspended = shouldBeSuspended;
578}
579
581
582template <typename floatType>
583void AudioProcessor::processBypassed (AudioBuffer<floatType>& buffer, MidiBuffer&)
584{
585 // If you hit this assertion then your plug-in is reporting that it introduces
586 // some latency, but you haven't overridden processBlockBypassed to produce
587 // an identical amount of latency. Without identical latency in
588 // processBlockBypassed a host's latency compensation could shift the audio
589 // passing through your bypassed plug-in forward in time.
590 jassert (getLatencySamples() == 0);
591
593 buffer.clear (ch, 0, buffer.getNumSamples());
594}
595
596void AudioProcessor::processBlockBypassed (AudioBuffer<float>& buffer, MidiBuffer& midi) { processBypassed (buffer, midi); }
597void AudioProcessor::processBlockBypassed (AudioBuffer<double>& buffer, MidiBuffer& midi) { processBypassed (buffer, midi); }
598
601{
602 // If you hit this assertion then either the caller called the double
603 // precision version of processBlock on a processor which does not support it
604 // (i.e. supportsDoublePrecisionProcessing() returns false), or the implementation
605 // of the AudioProcessor forgot to override the double precision version of this method
607}
608
610{
611 return false;
612}
613
614void AudioProcessor::setProcessingPrecision (ProcessingPrecision precision) noexcept
615{
616 // If you hit this assertion then you're trying to use double precision
617 // processing on a processor which does not support it!
618 jassert (precision != doublePrecision || supportsDoublePrecisionProcessing());
619
620 processingPrecision = precision;
621}
622
623//==============================================================================
624static String getChannelName (const OwnedArray<AudioProcessor::Bus>& buses, int index)
625{
626 return buses.size() > 0 ? AudioChannelSet::getChannelTypeName (buses[0]->getCurrentLayout().getTypeOfChannel (index)) : String();
627}
628
629const String AudioProcessor::getInputChannelName (int index) const { return getChannelName (inputBuses, index); }
630const String AudioProcessor::getOutputChannelName (int index) const { return getChannelName (outputBuses, index); }
631
632static bool isStereoPair (const OwnedArray<AudioProcessor::Bus>& buses, int index)
633{
634 return index < 2
635 && buses.size() > 0
636 && buses[0]->getCurrentLayout() == AudioChannelSet::stereo();
637}
638
639bool AudioProcessor::isInputChannelStereoPair (int index) const { return isStereoPair (inputBuses, index); }
640bool AudioProcessor::isOutputChannelStereoPair (int index) const { return isStereoPair (outputBuses, index); }
641
642//==============================================================================
643void AudioProcessor::createBus (bool inputBus, const BusProperties& ioConfig)
644{
645 (inputBus ? inputBuses : outputBuses).add (new Bus (*this, ioConfig.busName, ioConfig.defaultLayout, ioConfig.isActivatedByDefault));
646
647 audioIOChanged (true, ioConfig.isActivatedByDefault);
648}
649
650//==============================================================================
651AudioProcessor::BusesProperties AudioProcessor::busesPropertiesFromLayoutArray (const Array<InOutChannelPair>& config)
652{
653 BusesProperties ioProps;
654
655 if (config[0].inChannels > 0)
656 ioProps.addBus (true, "Input", AudioChannelSet::canonicalChannelSet (config[0].inChannels));
657
658 if (config[0].outChannels > 0)
659 ioProps.addBus (false, "Output", AudioChannelSet::canonicalChannelSet (config[0].outChannels));
660
661 return ioProps;
662}
663
664AudioProcessor::BusesLayout AudioProcessor::getNextBestLayoutInList (const BusesLayout& layouts,
666{
667 auto numChannelConfigs = legacyLayouts.size();
669
670 bool hasInputs = false, hasOutputs = false;
671
672 for (int i = 0; i < numChannelConfigs; ++i)
673 {
674 if (legacyLayouts[i].inChannels > 0)
675 {
676 hasInputs = true;
677 break;
678 }
679 }
680
681 for (int i = 0; i < numChannelConfigs; ++i)
682 {
683 if (legacyLayouts[i].outChannels > 0)
684 {
685 hasOutputs = true;
686 break;
687 }
688 }
689
690 auto nearest = layouts;
691 nearest.inputBuses .resize (hasInputs ? 1 : 0);
692 nearest.outputBuses.resize (hasOutputs ? 1 : 0);
693
694 auto* inBus = (hasInputs ? &nearest.inputBuses. getReference (0) : nullptr);
695 auto* outBus = (hasOutputs ? &nearest.outputBuses.getReference (0) : nullptr);
696
697 auto inNumChannelsRequested = static_cast<int16> (inBus != nullptr ? inBus->size() : 0);
698 auto outNumChannelsRequested = static_cast<int16> (outBus != nullptr ? outBus->size() : 0);
699
701 int bestConfiguration = 0;
702
703 for (int i = 0; i < numChannelConfigs; ++i)
704 {
705 auto inChannels = legacyLayouts.getReference (i).inChannels;
706 auto outChannels = legacyLayouts.getReference (i).outChannels;
707
708 auto channelDifference = ((std::abs (inChannels - inNumChannelsRequested) & 0xffff) << 16)
709 | ((std::abs (outChannels - outNumChannelsRequested) & 0xffff) << 0);
710
711 if (channelDifference < distance)
712 {
715
716 // we can exit if we found a perfect match
717 if (distance == 0)
718 return nearest;
719 }
720 }
721
722 auto inChannels = legacyLayouts.getReference (bestConfiguration).inChannels;
723 auto outChannels = legacyLayouts.getReference (bestConfiguration).outChannels;
724
725 auto currentState = getBusesLayout();
726 auto currentInLayout = (getBusCount (true) > 0 ? currentState.inputBuses .getReference (0) : AudioChannelSet());
727 auto currentOutLayout = (getBusCount (false) > 0 ? currentState.outputBuses.getReference (0) : AudioChannelSet());
728
729 if (inBus != nullptr)
730 {
731 if (inChannels == 0) *inBus = AudioChannelSet::disabled();
732 else if (inChannels == currentInLayout. size()) *inBus = currentInLayout;
733 else if (inChannels == currentOutLayout.size()) *inBus = currentOutLayout;
734 else *inBus = AudioChannelSet::canonicalChannelSet (inChannels);
735 }
736
737 if (outBus != nullptr)
738 {
739 if (outChannels == 0) *outBus = AudioChannelSet::disabled();
740 else if (outChannels == currentOutLayout.size()) *outBus = currentOutLayout;
741 else if (outChannels == currentInLayout .size()) *outBus = currentInLayout;
742 else *outBus = AudioChannelSet::canonicalChannelSet (outChannels);
743 }
744
745 return nearest;
746}
747
749{
750 if (layouts.inputBuses.size() > 1 || layouts.outputBuses.size() > 1)
751 return false;
752
753 const InOutChannelPair mainLayout (static_cast<int16> (layouts.getNumChannels (true, 0)),
754 static_cast<int16> (layouts.getNumChannels (false, 0)));
755
756 return channelLayouts.contains (mainLayout);
757}
758
759//==============================================================================
761{
762 auto layouts = getBusesLayout();
763
764 for (int busIndex = 1; busIndex < layouts.inputBuses.size(); ++busIndex)
765 layouts.inputBuses.getReference (busIndex) = AudioChannelSet::disabled();
766
767 for (int busIndex = 1; busIndex < layouts.outputBuses.size(); ++busIndex)
768 layouts.outputBuses.getReference (busIndex) = AudioChannelSet::disabled();
769
770 return setBusesLayout (layouts);
771}
772
773// Unfortunately the deprecated getInputSpeakerArrangement/getOutputSpeakerArrangement return
774// references to strings. Therefore we need to keep a copy. Once getInputSpeakerArrangement is
775// removed, we can also remove this function
776void AudioProcessor::updateSpeakerFormatStrings()
777{
778 cachedInputSpeakerArrString.clear();
779 cachedOutputSpeakerArrString.clear();
780
781 if (getBusCount (true) > 0)
782 cachedInputSpeakerArrString = getBus (true, 0)->getCurrentLayout().getSpeakerArrangementAsString();
783
784 if (getBusCount (false) > 0)
785 cachedOutputSpeakerArrString = getBus (false, 0)->getCurrentLayout().getSpeakerArrangementAsString();
786}
787
789{
790 if (layouts == getBusesLayout())
791 return true;
792
793 auto numInputBuses = getBusCount (true);
794 auto numOutputBuses = getBusCount (false);
795
798
799 if (layouts.inputBuses. size() != numInputBuses
800 || layouts.outputBuses.size() != numOutputBuses)
801 return false;
802
803 int newNumberOfIns = 0, newNumberOfOuts = 0;
804
805 for (int busIndex = 0; busIndex < numInputBuses; ++busIndex)
806 {
807 auto& bus = *getBus (true, busIndex);
808 const auto& set = layouts.getChannelSet (true, busIndex);
809 bus.layout = set;
810
811 if (! set.isDisabled())
812 bus.lastLayout = set;
813
814 newNumberOfIns += set.size();
815 }
816
817 for (int busIndex = 0; busIndex < numOutputBuses; ++busIndex)
818 {
819 auto& bus = *getBus (false, busIndex);
820 const auto& set = layouts.getChannelSet (false, busIndex);
821 bus.layout = set;
822
823 if (! set.isDisabled())
824 bus.lastLayout = set;
825
826 newNumberOfOuts += set.size();
827 }
828
830 audioIOChanged (false, channelNumChanged);
831
832 return true;
833}
834
835void AudioProcessor::audioIOChanged (bool busNumberChanged, bool channelNumChanged)
836{
837 auto numInputBuses = getBusCount (true);
838 auto numOutputBuses = getBusCount (false);
839
840 for (int dir = 0; dir < 2; ++dir)
841 {
842 const bool isInput = (dir == 0);
843 auto num = (isInput ? numInputBuses : numOutputBuses);
844
845 for (int i = 0; i < num; ++i)
846 if (auto* bus = getBus (isInput, i))
847 bus->updateChannelCount();
848 }
849
851 {
852 int n = 0;
853
854 for (auto* bus : buses)
855 n += bus->getNumberOfChannels();
856
857 return n;
858 };
859
860 cachedTotalIns = countTotalChannels (inputBuses);
861 cachedTotalOuts = countTotalChannels (outputBuses);
862
863 updateSpeakerFormatStrings();
864
867
870
872}
873
874//==============================================================================
876{
877 const ScopedLock sl (activeEditorLock);
878
879 if (activeEditor == editor)
880 activeEditor = nullptr;
881}
882
884{
885 const ScopedLock sl (activeEditorLock);
886 return activeEditor;
887}
888
890{
891 const ScopedLock sl (activeEditorLock);
892
893 if (activeEditor != nullptr)
894 return activeEditor;
895
896 auto* ed = createEditor();
897
898 if (ed != nullptr)
899 {
900 // you must give your editor comp a size before returning it..
901 jassert (ed->getWidth() > 0 && ed->getHeight() > 0);
902 activeEditor = ed;
903 }
904
905 // You must make your hasEditor() method return a consistent result!
906 jassert (hasEditor() == (ed != nullptr));
907
908 return ed;
909}
910
911//==============================================================================
916
917void AudioProcessor::setCurrentProgramStateInformation (const void* data, int sizeInBytes)
918{
919 setStateInformation (data, sizeInBytes);
920}
921
922//==============================================================================
924
925//==============================================================================
926// magic number to identify memory blocks that we've stored as XML
927const uint32 magicXmlNumber = 0x21324356;
928
930{
931 {
932 MemoryOutputStream out (destData, false);
933 out.writeInt (magicXmlNumber);
934 out.writeInt (0);
935 xml.writeTo (out, XmlElement::TextFormat().singleLine());
936 out.writeByte (0);
937 }
938
939 // go back and write the string length..
940 static_cast<uint32*> (destData.getData())[1]
941 = ByteOrder::swapIfBigEndian ((uint32) destData.getSize() - 9);
942}
943
944std::unique_ptr<XmlElement> AudioProcessor::getXmlFromBinary (const void* data, const int sizeInBytes)
945{
946 if (sizeInBytes > 8 && ByteOrder::littleEndianInt (data) == magicXmlNumber)
947 {
949
950 if (stringLength > 0)
951 return parseXML (String::fromUTF8 (static_cast<const char*> (data) + 8,
952 jmin ((sizeInBytes - 8), stringLength)));
953 }
954
955 return {};
956}
957
960{
961 if ( isAdding && ! canAddBus (isInput)) return false;
962 if (! isAdding && ! canRemoveBus (isInput)) return false;
963
964 auto num = getBusCount (isInput);
965
966 // No way for me to find out the default layout if there are no other busses!!
967 if (num == 0)
968 return false;
969
970 if (isAdding)
971 {
972 outProperties.busName = String (isInput ? "Input #" : "Output #") + String (getBusCount (isInput));
973 outProperties.defaultLayout = (num > 0 ? getBus (isInput, num - 1)->getDefaultLayout() : AudioChannelSet());
974 outProperties.isActivatedByDefault = true;
975 }
976
977 return true;
978}
979
980//==============================================================================
981AudioProcessor::Bus::Bus (AudioProcessor& processor, const String& busName,
982 const AudioChannelSet& defaultLayout, bool isDfltEnabled)
983 : owner (processor), name (busName),
984 layout (isDfltEnabled ? defaultLayout : AudioChannelSet()),
985 dfltLayout (defaultLayout), lastLayout (defaultLayout),
986 enabledByDefault (isDfltEnabled)
987{
988 // Your default layout cannot be disabled
989 jassert (! dfltLayout.isDisabled());
990}
991
992bool AudioProcessor::Bus::isInput() const noexcept { return owner.inputBuses.contains (this); }
993int AudioProcessor::Bus::getBusIndex() const noexcept { return getDirectionAndIndex().index; }
994
995AudioProcessor::Bus::BusDirectionAndIndex AudioProcessor::Bus::getDirectionAndIndex() const noexcept
996{
997 BusDirectionAndIndex di;
998 di.index = owner.inputBuses.indexOf (this);
999 di.isInput = (di.index >= 0);
1000
1001 if (! di.isInput)
1002 di.index = owner.outputBuses.indexOf (this);
1003
1004 return di;
1005}
1006
1008{
1009 auto di = getDirectionAndIndex();
1010 return owner.setChannelLayoutOfBus (di.isInput, di.index, busLayout);
1011}
1012
1014{
1015 if (! set.isDisabled())
1016 {
1017 if (isEnabled())
1018 return setCurrentLayout (set);
1019
1020 if (isLayoutSupported (set))
1021 {
1022 lastLayout = set;
1023 return true;
1024 }
1025
1026 return false;
1027 }
1028
1029 return isLayoutSupported (set);
1030}
1031
1033{
1034 auto di = getDirectionAndIndex();
1035
1036 if (owner.setChannelLayoutOfBus (di.isInput, di.index, AudioChannelSet::canonicalChannelSet (channels)))
1037 return true;
1038
1039 if (channels == 0)
1040 return false;
1041
1043
1044 if (! namedSet.isDisabled() && owner.setChannelLayoutOfBus (di.isInput, di.index, namedSet))
1045 return true;
1046
1047 return owner.setChannelLayoutOfBus (di.isInput, di.index, AudioChannelSet::discreteChannels (channels));
1048}
1049
1051{
1052 if (isEnabled() == shouldEnable)
1053 return true;
1054
1055 return setCurrentLayout (shouldEnable ? lastLayout : AudioChannelSet::disabled());
1056}
1057
1059{
1060 for (int ch = limit; ch > 0; --ch)
1061 if (isNumberOfChannelsSupported (ch))
1062 return ch;
1063
1064 return (isMain() && isLayoutSupported (AudioChannelSet::disabled())) ? 0 : -1;
1065}
1066
1068{
1069 auto di = getDirectionAndIndex();
1070
1071 // check that supplied ioLayout is actually valid
1072 if (ioLayout != nullptr)
1073 {
1074 if (! owner.checkBusesLayoutSupported (*ioLayout))
1075 {
1076 *ioLayout = owner.getBusesLayout();
1077
1078 // the current layout you supplied is not a valid layout
1080 }
1081 }
1082
1083 auto currentLayout = (ioLayout != nullptr ? *ioLayout : owner.getBusesLayout());
1084 auto& actualBuses = (di.isInput ? currentLayout.inputBuses : currentLayout.outputBuses);
1085
1086 if (actualBuses.getReference (di.index) == set)
1087 return true;
1088
1090
1091 (di.isInput ? desiredLayout.inputBuses
1092 : desiredLayout.outputBuses).getReference (di.index) = set;
1093
1094 owner.getNextBestLayout (desiredLayout, currentLayout);
1095
1096 if (ioLayout != nullptr)
1098
1099 // Nearest layout has a different number of buses. JUCE plug-ins MUST
1100 // have fixed number of buses.
1101 jassert (currentLayout.inputBuses. size() == owner.getBusCount (true)
1102 && currentLayout.outputBuses.size() == owner.getBusCount (false));
1103
1104 return actualBuses.getReference (di.index) == set;
1105}
1106
1108{
1109 if (channels == 0)
1110 return isLayoutSupported (AudioChannelSet::disabled());
1111
1112 auto set = supportedLayoutWithChannels (channels);
1113 return (! set.isDisabled()) && isLayoutSupported (set);
1114}
1115
1117{
1118 if (channels == 0)
1120
1121 {
1122 AudioChannelSet set;
1123
1124 if (! (set = AudioChannelSet::namedChannelSet (channels)).isDisabled() && isLayoutSupported (set))
1125 return set;
1126
1127 if (! (set = AudioChannelSet::discreteChannels (channels)).isDisabled() && isLayoutSupported (set))
1128 return set;
1129 }
1130
1131 for (auto& set : AudioChannelSet::channelSetsWithNumberOfChannels (channels))
1132 if (isLayoutSupported (set))
1133 return set;
1134
1136}
1137
1139{
1140 auto layouts = owner.getBusesLayout();
1141 isLayoutSupported (set, &layouts);
1142 return layouts;
1143}
1144
1146{
1147 auto di = getDirectionAndIndex();
1148 return owner.getChannelIndexInProcessBlockBuffer (di.isInput, di.index, channelIndex);
1149}
1150
1151void AudioProcessor::Bus::updateChannelCount() noexcept
1152{
1153 cachedChannelCount = layout.size();
1154}
1155
1156//==============================================================================
1157void AudioProcessor::BusesProperties::addBus (bool isInput, const String& name,
1158 const AudioChannelSet& dfltLayout, bool isActivatedByDefault)
1159{
1160 jassert (! dfltLayout.isDisabled());
1161
1162 BusProperties props;
1163
1164 props.busName = name;
1165 props.defaultLayout = dfltLayout;
1166 props.isActivatedByDefault = isActivatedByDefault;
1167
1168 (isInput ? inputLayouts : outputLayouts).add (props);
1169}
1170
1171AudioProcessor::BusesProperties AudioProcessor::BusesProperties::withInput (const String& name,
1172 const AudioChannelSet& dfltLayout,
1173 bool isActivatedByDefault) const
1174{
1175 auto retval = *this;
1176 retval.addBus (true, name, dfltLayout, isActivatedByDefault);
1177 return retval;
1178}
1179
1180AudioProcessor::BusesProperties AudioProcessor::BusesProperties::withOutput (const String& name,
1181 const AudioChannelSet& dfltLayout,
1182 bool isActivatedByDefault) const
1183{
1184 auto retval = *this;
1185 retval.addBus (false, name, dfltLayout, isActivatedByDefault);
1186 return retval;
1187}
1188
1189//==============================================================================
1191{
1192 switch (type)
1193 {
1194 case AudioProcessor::wrapperType_Undefined: return "Undefined";
1195 case AudioProcessor::wrapperType_VST: return "VST";
1196 case AudioProcessor::wrapperType_VST3: return "VST3";
1197 case AudioProcessor::wrapperType_AudioUnit: return "AU";
1198 case AudioProcessor::wrapperType_AudioUnitv3: return "AUv3";
1199 case AudioProcessor::wrapperType_AAX: return "AAX";
1200 case AudioProcessor::wrapperType_Standalone: return "Standalone";
1201 case AudioProcessor::wrapperType_Unity: return "Unity";
1202 case AudioProcessor::wrapperType_LV2: return "LV2";
1203 default: jassertfalse; return {};
1204 }
1205}
1206
1207//==============================================================================
1209{
1210 if (auto* extensions = dynamic_cast<VST2ClientExtensions*> (this))
1211 {
1212 // To silence this jassert there are two options:
1213 //
1214 // 1. - Override AudioProcessor::getVST2ClientExtensions() and
1215 // return the "this" pointer.
1216 //
1217 // - This option has the advantage of being quick and easy,
1218 // and avoids the above dynamic_cast.
1219 //
1220 // 2. - Create a new object that inherits from VST2ClientExtensions.
1221 //
1222 // - Port your existing functionality from the AudioProcessor
1223 // to the new object.
1224 //
1225 // - Return a pointer to the object in AudioProcessor::getVST2ClientExtensions().
1226 //
1227 // - This option has the advantage of allowing you to break
1228 // up your AudioProcessor into smaller composable objects.
1230 return extensions;
1231 }
1232
1233 return nullptr;
1234}
1235
1237{
1238 if (auto* extensions = dynamic_cast<VST3ClientExtensions*> (this))
1239 {
1240 // To silence this jassert there are two options:
1241 //
1242 // 1. - Override AudioProcessor::getVST3ClientExtensions() and
1243 // return the "this" pointer.
1244 //
1245 // - This option has the advantage of being quick and easy,
1246 // and avoids the above dynamic_cast.
1247 //
1248 // 2. - Create a new object that inherits from VST3ClientExtensions.
1249 //
1250 // - Port your existing functionality from the AudioProcessor
1251 // to the new object.
1252 //
1253 // - Return a pointer to the object in AudioProcessor::getVST3ClientExtensions().
1254 //
1255 // - This option has the advantage of allowing you to break
1256 // up your AudioProcessor into smaller composable objects.
1258 return extensions;
1259 }
1260
1261 return nullptr;
1262}
1263
1264//==============================================================================
1265JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
1266JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4996)
1267
1268void AudioProcessor::setParameterNotifyingHost (int parameterIndex, float newValue)
1269{
1270 if (auto* param = getParameters()[parameterIndex])
1271 {
1272 param->setValueNotifyingHost (newValue);
1273 }
1274 else if (isPositiveAndBelow (parameterIndex, getNumParameters()))
1275 {
1276 setParameter (parameterIndex, newValue);
1277 sendParamChangeMessageToListeners (parameterIndex, newValue);
1278 }
1279}
1280
1281void AudioProcessor::sendParamChangeMessageToListeners (int parameterIndex, float newValue)
1282{
1283 if (auto* param = getParameters()[parameterIndex])
1284 {
1285 param->sendValueChangedMessageToListeners (newValue);
1286 }
1287 else
1288 {
1289 if (isPositiveAndBelow (parameterIndex, getNumParameters()))
1290 {
1291 for (int i = listeners.size(); --i >= 0;)
1292 if (auto* l = getListenerLocked (i))
1293 l->audioProcessorParameterChanged (this, parameterIndex, newValue);
1294 }
1295 else
1296 {
1297 jassertfalse; // called with an out-of-range parameter index!
1298 }
1299 }
1300}
1301
1302void AudioProcessor::beginParameterChangeGesture (int parameterIndex)
1303{
1304 if (auto* param = getParameters()[parameterIndex])
1305 {
1306 param->beginChangeGesture();
1307 }
1308 else
1309 {
1310 if (isPositiveAndBelow (parameterIndex, getNumParameters()))
1311 {
1312 #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
1313 // This means you've called beginParameterChangeGesture twice in succession without a matching
1314 // call to endParameterChangeGesture. That might be fine in most hosts, but better to avoid doing it.
1315 jassert (! changingParams[parameterIndex]);
1316 changingParams.setBit (parameterIndex);
1317 #endif
1318
1319 for (int i = listeners.size(); --i >= 0;)
1320 if (auto* l = getListenerLocked (i))
1321 l->audioProcessorParameterChangeGestureBegin (this, parameterIndex);
1322 }
1323 else
1324 {
1325 jassertfalse; // called with an out-of-range parameter index!
1326 }
1327 }
1328}
1329
1330void AudioProcessor::endParameterChangeGesture (int parameterIndex)
1331{
1332 if (auto* param = getParameters()[parameterIndex])
1333 {
1334 param->endChangeGesture();
1335 }
1336 else
1337 {
1338 if (isPositiveAndBelow (parameterIndex, getNumParameters()))
1339 {
1340 #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
1341 // This means you've called endParameterChangeGesture without having previously called
1342 // beginParameterChangeGesture. That might be fine in most hosts, but better to keep the
1343 // calls matched correctly.
1344 jassert (changingParams[parameterIndex]);
1345 changingParams.clearBit (parameterIndex);
1346 #endif
1347
1348 for (int i = listeners.size(); --i >= 0;)
1349 if (auto* l = getListenerLocked (i))
1350 l->audioProcessorParameterChangeGestureEnd (this, parameterIndex);
1351 }
1352 else
1353 {
1354 jassertfalse; // called with an out-of-range parameter index!
1355 }
1356 }
1357}
1358
1359String AudioProcessor::getParameterName (int index, int maximumStringLength)
1360{
1361 if (auto* p = getParameters()[index])
1362 return p->getName (maximumStringLength);
1363
1364 return isPositiveAndBelow (index, getNumParameters()) ? getParameterName (index).substring (0, maximumStringLength)
1365 : String();
1366}
1367
1368const String AudioProcessor::getParameterText (int index)
1369{
1370 #if JUCE_DEBUG
1371 // if you hit this, then you're probably using the old parameter control methods,
1372 // but have forgotten to implement either of the getParameterText() methods.
1375 #endif
1376
1377 return isPositiveAndBelow (index, getNumParameters()) ? getParameterText (index, 1024)
1378 : String();
1379}
1380
1381String AudioProcessor::getParameterText (int index, int maximumStringLength)
1382{
1383 if (auto* p = getParameters()[index])
1384 return p->getText (p->getValue(), maximumStringLength);
1385
1386 return isPositiveAndBelow (index, getNumParameters()) ? getParameterText (index).substring (0, maximumStringLength)
1387 : String();
1388}
1389
1390int AudioProcessor::getNumParameters()
1391{
1392 return getParameters().size();
1393}
1394
1395float AudioProcessor::getParameter (int index)
1396{
1397 if (auto* p = getParamChecked (index))
1398 return p->getValue();
1399
1400 return 0;
1401}
1402
1403void AudioProcessor::setParameter (int index, float newValue)
1404{
1405 if (auto* p = getParamChecked (index))
1406 p->setValue (newValue);
1407}
1408
1409float AudioProcessor::getParameterDefaultValue (int index)
1410{
1411 if (auto* p = getParameters()[index])
1412 return p->getDefaultValue();
1413
1414 return 0;
1415}
1416
1417const String AudioProcessor::getParameterName (int index)
1418{
1419 if (auto* p = getParamChecked (index))
1420 return p->getName (512);
1421
1422 return {};
1423}
1424
1425String AudioProcessor::getParameterID (int index)
1426{
1427 // Don't use getParamChecked here, as this must also work for legacy plug-ins
1428 if (auto* p = dynamic_cast<HostedAudioProcessorParameter*> (getParameters()[index]))
1429 return p->getParameterID();
1430
1431 return String (index);
1432}
1433
1434int AudioProcessor::getParameterNumSteps (int index)
1435{
1436 if (auto* p = getParameters()[index])
1437 return p->getNumSteps();
1438
1440}
1441
1442bool AudioProcessor::isParameterDiscrete (int index) const
1443{
1444 if (auto* p = getParameters()[index])
1445 return p->isDiscrete();
1446
1447 return false;
1448}
1449
1450String AudioProcessor::getParameterLabel (int index) const
1451{
1452 if (auto* p = getParameters()[index])
1453 return p->getLabel();
1454
1455 return {};
1456}
1457
1458bool AudioProcessor::isParameterAutomatable (int index) const
1459{
1460 if (auto* p = getParameters()[index])
1461 return p->isAutomatable();
1462
1463 return true;
1464}
1465
1466bool AudioProcessor::isParameterOrientationInverted (int index) const
1467{
1468 if (auto* p = getParameters()[index])
1469 return p->isOrientationInverted();
1470
1471 return false;
1472}
1473
1474bool AudioProcessor::isMetaParameter (int index) const
1475{
1476 if (auto* p = getParameters()[index])
1477 return p->isMetaParameter();
1478
1479 return false;
1480}
1481
1482AudioProcessorParameter::Category AudioProcessor::getParameterCategory (int index) const
1483{
1484 if (auto* p = getParameters()[index])
1485 return p->getCategory();
1486
1488}
1489
1490AudioProcessorParameter* AudioProcessor::getParamChecked (int index) const
1491{
1492 auto p = getParameters()[index];
1493
1494 // If you hit this, then you're either trying to access parameters that are out-of-range,
1495 // or you're not using addParameter and the managed parameter list, but have failed
1496 // to override some essential virtual methods and implement them appropriately.
1497 jassert (p != nullptr);
1498 return p;
1499}
1500
1501bool AudioProcessor::canAddBus ([[maybe_unused]] bool isInput) const { return false; }
1502bool AudioProcessor::canRemoveBus ([[maybe_unused]] bool isInput) const { return false; }
1503
1504JUCE_END_IGNORE_WARNINGS_GCC_LIKE
1505JUCE_END_IGNORE_WARNINGS_MSVC
1506
1507//==============================================================================
1510
1511//==============================================================================
1513{
1514 #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
1515 // This will fail if you've called beginChangeGesture() without having made
1516 // a corresponding call to endChangeGesture...
1518 #endif
1519}
1520
1522{
1523 setValue (newValue);
1524 sendValueChangedMessageToListeners (newValue);
1525}
1526
1528{
1529 // This method can't be used until the parameter has been attached to a processor!
1530 jassert (processor != nullptr && parameterIndex >= 0);
1531
1532 #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
1533 // This means you've called beginChangeGesture twice in succession without
1534 // a matching call to endChangeGesture. That might be fine in most hosts,
1535 // but it would be better to avoid doing it.
1537 isPerformingGesture = true;
1538 #endif
1539
1540 ScopedLock lock (listenerLock);
1541
1542 for (int i = listeners.size(); --i >= 0;)
1543 if (auto* l = listeners[i])
1544 l->parameterGestureChanged (getParameterIndex(), true);
1545
1546 if (processor != nullptr && parameterIndex >= 0)
1547 {
1548 // audioProcessorParameterChangeGestureBegin callbacks will shortly be deprecated and
1549 // this code will be removed.
1550 for (int i = processor->listeners.size(); --i >= 0;)
1551 if (auto* l = processor->listeners[i])
1552 l->audioProcessorParameterChangeGestureBegin (processor, getParameterIndex());
1553 }
1554}
1555
1557{
1558 // This method can't be used until the parameter has been attached to a processor!
1559 jassert (processor != nullptr && parameterIndex >= 0);
1560
1561 #if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
1562 // This means you've called endChangeGesture without having previously
1563 // called beginChangeGesture. That might be fine in most hosts, but it
1564 // would be better to keep the calls matched correctly.
1566 isPerformingGesture = false;
1567 #endif
1568
1569 ScopedLock lock (listenerLock);
1570
1571 for (int i = listeners.size(); --i >= 0;)
1572 if (auto* l = listeners[i])
1573 l->parameterGestureChanged (getParameterIndex(), false);
1574
1575 if (processor != nullptr && parameterIndex >= 0)
1576 {
1577 // audioProcessorParameterChangeGestureEnd callbacks will shortly be deprecated and
1578 // this code will be removed.
1579 for (int i = processor->listeners.size(); --i >= 0;)
1580 if (auto* l = processor->listeners[i])
1581 l->audioProcessorParameterChangeGestureEnd (processor, getParameterIndex());
1582 }
1583}
1584
1585void AudioProcessorParameter::sendValueChangedMessageToListeners (float newValue)
1586{
1587 ScopedLock lock (listenerLock);
1588
1589 for (int i = listeners.size(); --i >= 0;)
1590 if (auto* l = listeners [i])
1591 l->parameterValueChanged (getParameterIndex(), newValue);
1592
1593 if (processor != nullptr && parameterIndex >= 0)
1594 {
1595 // audioProcessorParameterChanged callbacks will shortly be deprecated and
1596 // this code will be removed.
1597 for (int i = processor->listeners.size(); --i >= 0;)
1598 if (auto* l = processor->listeners[i])
1599 l->audioProcessorParameterChanged (processor, getParameterIndex(), newValue);
1600 }
1601}
1602
1604bool AudioProcessorParameter::isAutomatable() const { return true; }
1605bool AudioProcessorParameter::isMetaParameter() const { return false; }
1608bool AudioProcessorParameter::isDiscrete() const { return false; }
1609bool AudioProcessorParameter::isBoolean() const { return false; }
1610
1611String AudioProcessorParameter::getText (float value, int /*maximumStringLength*/) const
1612{
1613 return String (value, 2);
1614}
1615
1617{
1618 return getText (getValue(), 1024);
1619}
1620
1622{
1623 if (isDiscrete() && valueStrings.isEmpty())
1624 {
1625 auto maxIndex = getNumSteps() - 1;
1626
1627 for (int i = 0; i < getNumSteps(); ++i)
1628 valueStrings.add (getText ((float) i / (float) maxIndex, 1024));
1629 }
1630
1631 return valueStrings;
1632}
1633
1635{
1636 const ScopedLock sl (listenerLock);
1637 listeners.addIfNotAlreadyThere (newListener);
1638}
1639
1641{
1642 const ScopedLock sl (listenerLock);
1643 listeners.removeFirstMatchingValue (listenerToRemove);
1644}
1645
1646} // namespace juce
T call_once(T... args)
Holds a resizable array of primitive or copy-by-value objects.
Definition juce_Array.h:56
A multi-channel buffer containing floating point audio samples.
int getNumSamples() const noexcept
Returns the number of samples allocated in each of the buffer's channels.
void clear() noexcept
Clears all the samples in all channels and marks the buffer as cleared.
Represents a set of audio channel types.
static AudioChannelSet JUCE_CALLTYPE namedChannelSet(int numChannels)
Create a channel set for a given number of channels which is non-discrete.
static AudioChannelSet JUCE_CALLTYPE disabled()
Creates a zero-channel set which can be used to indicate that a bus is disabled.
bool isDisabled() const noexcept
Returns true if there are no channels in the set.
static Array< AudioChannelSet > JUCE_CALLTYPE channelSetsWithNumberOfChannels(int numChannels)
Return an array of channel sets which have a given number of channels.
static AudioChannelSet JUCE_CALLTYPE stereo()
Creates a set containing a stereo set (left, right).
static String JUCE_CALLTYPE getChannelTypeName(ChannelType)
Returns the name of a given channel type.
String getSpeakerArrangementAsString() const
Returns a string containing a whitespace-separated list of speaker types corresponding to each channe...
static AudioChannelSet JUCE_CALLTYPE canonicalChannelSet(int numChannels)
Create a canonical channel set for a given number of channels.
static AudioChannelSet JUCE_CALLTYPE discreteChannels(int numChannels)
Creates a set of untyped discrete channels.
A subclass of AudioPlayHead can supply information about the position and status of a moving play hea...
Base class for the component that acts as the GUI for an AudioProcessor.
Base class for listeners that want to know about changes to an AudioProcessor.
virtual void audioProcessorParameterChangeGestureBegin(AudioProcessor *processor, int parameterIndex)
Indicates that a parameter change gesture has started.
virtual void audioProcessorParameterChangeGestureEnd(AudioProcessor *processor, int parameterIndex)
Indicates that a parameter change gesture has finished.
A class encapsulating a group of AudioProcessorParameters and nested AudioProcessorParameterGroups.
void addChild(std::unique_ptr< ParameterOrGroup > child)
Adds a child to the group.
Array< AudioProcessorParameter * > getParameters(bool recursive) const
Returns all the parameters in this group.
A base class for listeners that want to know about changes to an AudioProcessorParameter.
An abstract base class for parameter objects that can be added to an AudioProcessor.
virtual String getCurrentValueAsText() const
Returns the current value of the parameter as a String.
virtual String getText(float normalisedValue, int) const
Returns a textual version of the supplied normalised parameter value.
virtual int getNumSteps() const
Returns the number of steps that this parameter's range should be quantised into.
virtual bool isMetaParameter() const
Should return true if this parameter is a "meta" parameter.
virtual bool isAutomatable() const
Returns true if the host can automate this parameter.
virtual ~AudioProcessorParameter()
Destructor.
void beginChangeGesture()
Sends a signal to the host to tell it that the user is about to start changing this parameter.
void removeListener(Listener *listener)
Removes a previously registered parameter listener.
virtual StringArray getAllValueStrings() const
Returns the set of strings which represent the possible states a parameter can be in.
@ genericParameter
If your parameter is not a meter then you should use this category.
void setValueNotifyingHost(float newValue)
A processor should call this when it needs to change one of its parameters.
void endChangeGesture()
Tells the host that the user has finished changing this parameter.
virtual bool isDiscrete() const
Returns whether the parameter uses discrete values, based on the result of getNumSteps,...
virtual bool isOrientationInverted() const
This can be overridden to tell the host that this parameter operates in the reverse direction.
void addListener(Listener *newListener)
Registers a listener to receive events when the parameter's state changes.
virtual bool isBoolean() const
Returns whether the parameter represents a boolean switch, typically with "On" and "Off" states.
virtual Category getCategory() const
Returns the parameter's category.
AudioChannelSet supportedLayoutWithChannels(int channels) const
Returns a ChannelSet that the bus supports with a given number of channels.
const AudioChannelSet & getCurrentLayout() const noexcept
The bus's current layout.
bool enable(bool shouldEnable=true)
Enable or disable this bus.
bool isNumberOfChannelsSupported(int channels) const
Checks if this bus can support a given number of channels.
bool setCurrentLayoutWithoutEnabling(const AudioChannelSet &layout)
Sets the bus's current layout without changing the enabled state.
const AudioChannelSet & getDefaultLayout() const noexcept
Get the default layout of this bus.
bool setCurrentLayout(const AudioChannelSet &layout)
Sets the bus's current layout.
int getBusIndex() const noexcept
Returns the index of this bus.
int getChannelIndexInProcessBlockBuffer(int channelIndex) const noexcept
Returns the position of a bus's channels within the processBlock buffer.
bool setNumberOfChannels(int channels)
Set the number of channels of this bus.
int getMaxSupportedChannels(int limit=AudioChannelSet::maxChannelsOfNamedLayout) const
Returns the maximum number of channels that this bus can support.
bool isLayoutSupported(const AudioChannelSet &set, BusesLayout *currentLayout=nullptr) const
Checks if a particular layout is supported.
bool isInput() const noexcept
Returns true if this bus is an input bus.
BusesLayout getBusesLayoutForLayoutChangeOfBus(const AudioChannelSet &set) const
Returns the resulting layouts of all buses after changing the layout of this bus.
Base class for audio processing classes or plugins.
virtual bool canApplyBusesLayout(const BusesLayout &layouts) const
Callback to check if a certain bus layout can now be applied.
int getTotalNumInputChannels() const noexcept
Returns the total number of input channels.
int getChannelIndexInProcessBlockBuffer(bool isInput, int busIndex, int channelIndex) const noexcept
Returns the position of a bus's channels within the processBlock buffer.
bool enableAllBuses()
Enables all buses.
WrapperType
Flags to indicate the type of plugin context in which a processor is being used.
void setProcessingPrecision(ProcessingPrecision newPrecision) noexcept
Changes the processing precision of the receiver.
virtual void processBlockBypassed(AudioBuffer< float > &buffer, MidiBuffer &midiMessages)
Renders the next block when the processor is being bypassed.
Bus * getBus(bool isInput, int busIndex) noexcept
Returns the audio bus with a given index and direction.
const WrapperType wrapperType
When loaded by a plugin wrapper, this flag will be set to indicate the type of plugin within which th...
void updateHostDisplay(const ChangeDetails &details=ChangeDetails::getDefaultFlags())
The processor can call this when something (apart from a parameter value) has changed.
int getLatencySamples() const noexcept
This returns the number of samples delay that the processor imposes on the audio passing through it.
void setParameterTree(AudioProcessorParameterGroup &&newTree)
Sets the group of parameters managed by this AudioProcessor.
virtual void setNonRealtime(bool isNonRealtime) noexcept
Called by the host to tell this processor whether it's being used in a non-realtime capacity for offl...
BusesLayout getBusesLayout() const
Provides the current channel layouts of this audio processor.
bool disableNonMainBuses()
Disables all non-main buses (aux and sidechains).
bool checkBusesLayoutSupported(const BusesLayout &) const
Returns true if the Audio processor is likely to support a given layout.
void addParameter(AudioProcessorParameter *)
Adds a parameter to the AudioProcessor.
virtual bool supportsDoublePrecisionProcessing() const
Returns true if the Audio processor supports double precision floating point processing.
virtual bool applyBusLayouts(const BusesLayout &layouts)
This method will be called when a new bus layout needs to be applied.
virtual void removeListener(AudioProcessorListener *listenerToRemove)
Removes a previously added listener.
virtual void updateTrackProperties(const TrackProperties &properties)
Informs the AudioProcessor that track properties such as the track's name or colour has been changed.
void setLatencySamples(int newLatency)
Your processor subclass should call this to set the number of samples delay that it introduces.
bool removeBus(bool isInput)
Dynamically remove the latest added bus.
int getBusCount(bool isInput) const noexcept
Returns the number of buses on the input or output side.
virtual void getStateInformation(juce::MemoryBlock &destData)=0
The host will call this method when it wants to save the processor's internal state.
static std::unique_ptr< XmlElement > getXmlFromBinary(const void *data, int sizeInBytes)
Retrieves an XML element that was stored as binary with the copyXmlToBinary() method.
int getOffsetInBusBufferForAbsoluteChannelIndex(bool isInput, int absoluteChannelIndex, int &busIndex) const noexcept
Returns the offset in a bus's buffer from an absolute channel index.
void suspendProcessing(bool shouldBeSuspended)
Enables and disables the processing callback.
virtual void setPlayHead(AudioPlayHead *newPlayHead)
Tells the processor to use this playhead object.
virtual AudioProcessorEditor * createEditor()=0
Creates the processor's GUI.
virtual void numBusesChanged()
This method is called when the number of buses is changed.
virtual void processBlock(AudioBuffer< float > &buffer, MidiBuffer &midiMessages)=0
Renders the next block.
AudioProcessorEditor * getActiveEditor() const noexcept
Returns the active editor, if there is one.
virtual const String getName() const =0
Returns the name of this processor.
AudioProcessorEditor * createEditorIfNeeded()
Returns the active editor, or if there isn't one, it will create one.
bool addBus(bool isInput)
Dynamically request an additional bus.
void editorBeingDeleted(AudioProcessorEditor *) noexcept
Not for public use - this is called before deleting an editor component.
const AudioProcessorParameterGroup & getParameterTree() const
Returns the group of parameters managed by this AudioProcessor.
virtual void addListener(AudioProcessorListener *newListener)
Adds a listener that will be called when an aspect of this processor changes.
int getChannelCountOfBus(bool isInput, int busIndex) const noexcept
Provides the number of channels of the bus with a given index and direction.
const Array< AudioProcessorParameter * > & getParameters() const
Returns a flat list of the parameters in the current tree.
virtual bool hasEditor() const =0
Your processor subclass must override this and return true if it can create an editor component.
static bool containsLayout(const BusesLayout &layouts, const std::initializer_list< const short[2]> &channelLayoutList)
Returns true if the channel layout map contains a certain layout.
virtual void processorLayoutsChanged()
This method is called when the layout of the audio processor changes.
static void copyXmlToBinary(const XmlElement &xml, juce::MemoryBlock &destData)
Helper function that just converts an xml element into a binary blob.
virtual void setStateInformation(const void *data, int sizeInBytes)=0
This must restore the processor's state from a block of data previously created using getStateInforma...
static int getDefaultNumParameterSteps() noexcept
Returns the default number of steps for a parameter.
void addParameterGroup(std::unique_ptr< AudioProcessorParameterGroup >)
Adds a group of parameters to the AudioProcessor.
void setPlayConfigDetails(int numIns, int numOuts, double sampleRate, int blockSize)
This is called by the processor to specify its details before being played.
virtual bool isBusesLayoutSupported(const BusesLayout &) const
Callback to query if the AudioProcessor supports a specific layout.
AudioChannelSet getChannelLayoutOfBus(bool isInput, int busIndex) const noexcept
Provides the channel layout of the bus with a given index and direction.
virtual void numChannelsChanged()
This method is called when the total number of input or output channels is changed.
virtual void refreshParameterList()
A processor should implement this method so that the host can ask it to rebuild its parameter tree.
virtual VST2ClientExtensions * getVST2ClientExtensions()
Returns a non-owning pointer to an object that implements VST2 specific information regarding this Au...
bool setChannelLayoutOfBus(bool isInput, int busIndex, const AudioChannelSet &layout)
Set the channel layout of the bus with a given index and direction.
virtual StringArray getAlternateDisplayNames() const
Returns a list of alternative names to use for this processor.
virtual bool canAddBus(bool isInput) const
Callback to query if a bus can currently be added.
bool setBusesLayoutWithoutEnabling(const BusesLayout &)
Set the channel layouts of this audio processor without changing the enablement state of the buses.
int getTotalNumOutputChannels() const noexcept
Returns the total number of output channels.
virtual VST3ClientExtensions * getVST3ClientExtensions()
Returns a non-owning pointer to an object that implements VST3 specific information regarding this Au...
virtual bool canApplyBusCountChange(bool isInput, bool isAddingBuses, BusProperties &outNewBusProperties)
Callback to query if adding/removing buses currently possible.
virtual ~AudioProcessor()
Destructor.
virtual void reset()
A plugin can override this to be told when it should reset any playing voices.
static const char * getWrapperTypeDescription(AudioProcessor::WrapperType) noexcept
Returns a textual description of a WrapperType value.
bool setBusesLayout(const BusesLayout &)
Set the channel layouts of this audio processor.
virtual bool canRemoveBus(bool isInput) const
Callback to query if the last bus can currently be removed.
int getMainBusNumInputChannels() const noexcept
Returns the number of input channels on the main bus.
virtual void setCurrentProgramStateInformation(const void *data, int sizeInBytes)
The host will call this method if it wants to restore the state of just the processor's current progr...
void setRateAndBufferSizeDetails(double sampleRate, int blockSize) noexcept
This is called by the processor to specify its details before being played.
virtual void getCurrentProgramStateInformation(juce::MemoryBlock &destData)
The host will call this method if it wants to save the state of just the processor's current program.
Structure used for AudioProcessor Callbacks.
A struct containing information about the DAW track inside which your AudioProcessor is loaded.
static constexpr uint32 littleEndianInt(const void *bytes) noexcept
Turns 4 bytes into a little-endian integer.
static Type swapIfBigEndian(Type value) noexcept
Swaps the byte order of a signed or unsigned integer if the CPU is big-endian.
Automatically locks and unlocks a mutex object.
A class to hold a resizable block of raw data.
void * getData() noexcept
Returns a void pointer to the data.
size_t getSize() const noexcept
Returns the block's current allocated size, in bytes.
Writes data to an internal memory buffer, which grows as required.
Holds a sequence of time-stamped midi events.
virtual bool writeByte(char byte)
Writes a single byte to the stream.
virtual bool writeInt(int value)
Writes a 32-bit integer to the stream in a little-endian byte order.
An array designed for holding objects.
A special array for holding a list of strings.
void add(String stringToAdd)
Appends a string at the end of the array.
The JUCE String class!
Definition juce_String.h:53
void clear() noexcept
Resets this string to be empty.
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
Creates a String from a UTF-8 encoded buffer.
Used to build a tree of elements representing an XML document.
void writeTo(OutputStream &output, const TextFormat &format={}) const
Writes the document to a stream as UTF-8.
T distance(T... args)
#define jassert(expression)
Platform-independent assertion macro.
#define jassertfalse
This will always cause an assertion failure.
#define JUCE_CALLTYPE
This macro defines the C calling convention used as the standard for JUCE calls.
typedef int
T max(T... args)
JUCE Namespace.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
signed short int16
A platform-independent 16-bit signed integer type.
std::unique_ptr< XmlElement > parseXML(const String &textToParse)
Attempts to parse some XML text, returning a new XmlElement if it was valid.
Type * addBytesToPointer(Type *basePointer, IntegerType bytes) noexcept
A handy function which adds a number of bytes to any type of pointer and returns the result.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
bool isPositiveAndBelow(Type1 valueToTest, Type2 upperLimit) noexcept
Returns true if a value is at least zero, and also below a specified upper limit.
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
remove
T size(T... args)
Provides details about aspects of an AudioProcessor which have changed.
Represents the bus layout state of a plug-in.
Array< AudioChannelSet > inputBuses
An array containing the list of input buses that this processor supports.
Structure used for AudioProcessor Callbacks.
An interface to allow an AudioProcessor to implement extended VST2-specific functionality.
An interface to allow an AudioProcessor to implement extended VST3-specific functionality.
A struct containing options for formatting the text when representing an XML element as a string.