mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-11 23:54:18 +00:00
Added an AudioProcessorParameter listener class
This commit is contained in:
parent
d0c2c025ce
commit
d3d1eeb770
3 changed files with 197 additions and 37 deletions
|
|
@ -416,8 +416,15 @@ void AudioProcessor::setLatencySamples (const int newLatency)
|
|||
|
||||
void AudioProcessor::setParameterNotifyingHost (int parameterIndex, float newValue)
|
||||
{
|
||||
setParameter (parameterIndex, newValue);
|
||||
sendParamChangeMessageToListeners (parameterIndex, newValue);
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
{
|
||||
param->setValueNotifyingHost (newValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
setParameter (parameterIndex, newValue);
|
||||
sendParamChangeMessageToListeners (parameterIndex, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
AudioProcessorListener* AudioProcessor::getListenerLocked (int index) const noexcept
|
||||
|
|
@ -428,58 +435,79 @@ AudioProcessorListener* AudioProcessor::getListenerLocked (int index) const noex
|
|||
|
||||
void AudioProcessor::sendParamChangeMessageToListeners (int parameterIndex, float newValue)
|
||||
{
|
||||
if (isPositiveAndBelow (parameterIndex, getNumParameters()))
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
{
|
||||
for (int i = listeners.size(); --i >= 0;)
|
||||
if (auto* l = getListenerLocked (i))
|
||||
l->audioProcessorParameterChanged (this, parameterIndex, newValue);
|
||||
param->sendValueChangedMessageToListeners (newValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
jassertfalse; // called with an out-of-range parameter index!
|
||||
if (isPositiveAndBelow (parameterIndex, getNumParameters()))
|
||||
{
|
||||
for (int i = listeners.size(); --i >= 0;)
|
||||
if (auto* l = getListenerLocked (i))
|
||||
l->audioProcessorParameterChanged (this, parameterIndex, newValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
jassertfalse; // called with an out-of-range parameter index!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioProcessor::beginParameterChangeGesture (int parameterIndex)
|
||||
{
|
||||
if (isPositiveAndBelow (parameterIndex, getNumParameters()))
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
{
|
||||
#if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
|
||||
// This means you've called beginParameterChangeGesture twice in succession without a matching
|
||||
// call to endParameterChangeGesture. That might be fine in most hosts, but better to avoid doing it.
|
||||
jassert (! changingParams[parameterIndex]);
|
||||
changingParams.setBit (parameterIndex);
|
||||
#endif
|
||||
|
||||
for (int i = listeners.size(); --i >= 0;)
|
||||
if (auto* l = getListenerLocked (i))
|
||||
l->audioProcessorParameterChangeGestureBegin (this, parameterIndex);
|
||||
param->beginChangeGesture();
|
||||
}
|
||||
else
|
||||
{
|
||||
jassertfalse; // called with an out-of-range parameter index!
|
||||
if (isPositiveAndBelow (parameterIndex, getNumParameters()))
|
||||
{
|
||||
#if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
|
||||
// This means you've called beginParameterChangeGesture twice in succession without a matching
|
||||
// call to endParameterChangeGesture. That might be fine in most hosts, but better to avoid doing it.
|
||||
jassert (! changingParams[parameterIndex]);
|
||||
changingParams.setBit (parameterIndex);
|
||||
#endif
|
||||
|
||||
for (int i = listeners.size(); --i >= 0;)
|
||||
if (auto* l = getListenerLocked (i))
|
||||
l->audioProcessorParameterChangeGestureBegin (this, parameterIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
jassertfalse; // called with an out-of-range parameter index!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioProcessor::endParameterChangeGesture (int parameterIndex)
|
||||
{
|
||||
if (isPositiveAndBelow (parameterIndex, getNumParameters()))
|
||||
if (auto* param = getParameters()[parameterIndex])
|
||||
{
|
||||
#if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
|
||||
// This means you've called endParameterChangeGesture without having previously called
|
||||
// beginParameterChangeGesture. That might be fine in most hosts, but better to keep the
|
||||
// calls matched correctly.
|
||||
jassert (changingParams[parameterIndex]);
|
||||
changingParams.clearBit (parameterIndex);
|
||||
#endif
|
||||
|
||||
for (int i = listeners.size(); --i >= 0;)
|
||||
if (auto* l = getListenerLocked (i))
|
||||
l->audioProcessorParameterChangeGestureEnd (this, parameterIndex);
|
||||
param->endChangeGesture();
|
||||
}
|
||||
else
|
||||
{
|
||||
jassertfalse; // called with an out-of-range parameter index!
|
||||
if (isPositiveAndBelow (parameterIndex, getNumParameters()))
|
||||
{
|
||||
#if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
|
||||
// This means you've called endParameterChangeGesture without having previously called
|
||||
// beginParameterChangeGesture. That might be fine in most hosts, but better to keep the
|
||||
// calls matched correctly.
|
||||
jassert (changingParams[parameterIndex]);
|
||||
changingParams.clearBit (parameterIndex);
|
||||
#endif
|
||||
|
||||
for (int i = listeners.size(); --i >= 0;)
|
||||
if (auto* l = getListenerLocked (i))
|
||||
l->audioProcessorParameterChangeGestureEnd (this, parameterIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
jassertfalse; // called with an out-of-range parameter index!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1340,7 +1368,8 @@ void AudioProcessorParameter::setValueNotifyingHost (float newValue)
|
|||
// This method can't be used until the parameter has been attached to a processor!
|
||||
jassert (processor != nullptr && parameterIndex >= 0);
|
||||
|
||||
return processor->setParameterNotifyingHost (parameterIndex, newValue);
|
||||
setValue (newValue);
|
||||
sendValueChangedMessageToListeners (newValue);
|
||||
}
|
||||
|
||||
void AudioProcessorParameter::beginChangeGesture()
|
||||
|
|
@ -1348,7 +1377,25 @@ void AudioProcessorParameter::beginChangeGesture()
|
|||
// This method can't be used until the parameter has been attached to a processor!
|
||||
jassert (processor != nullptr && parameterIndex >= 0);
|
||||
|
||||
processor->beginParameterChangeGesture (parameterIndex);
|
||||
#if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
|
||||
// This means you've called beginChangeGesture twice in succession without
|
||||
// a matching call to endChangeGesture. That might be fine in most hosts,
|
||||
// but it would be better to avoid doing it.
|
||||
jassert (! isPerformingGesture);
|
||||
isPerformingGesture = true;
|
||||
#endif
|
||||
|
||||
ScopedLock lock (listenerLock);
|
||||
|
||||
for (int i = listeners.size(); --i >= 0;)
|
||||
if (auto* l = listeners[i])
|
||||
l->parameterGestureChanged (getParameterIndex(), true);
|
||||
|
||||
// audioProcessorParameterChangeGestureBegin callbacks will shortly be deprecated and
|
||||
// this code will be removed.
|
||||
for (int i = processor->listeners.size(); --i >= 0;)
|
||||
if (auto* l = processor->listeners[i])
|
||||
l->audioProcessorParameterChangeGestureBegin (processor, getParameterIndex());
|
||||
}
|
||||
|
||||
void AudioProcessorParameter::endChangeGesture()
|
||||
|
|
@ -1356,7 +1403,40 @@ void AudioProcessorParameter::endChangeGesture()
|
|||
// This method can't be used until the parameter has been attached to a processor!
|
||||
jassert (processor != nullptr && parameterIndex >= 0);
|
||||
|
||||
processor->endParameterChangeGesture (parameterIndex);
|
||||
#if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
|
||||
// This means you've called endChangeGesture without having previously
|
||||
// called beginChangeGesture. That might be fine in most hosts, but it
|
||||
// would be better to keep the calls matched correctly.
|
||||
jassert (isPerformingGesture);
|
||||
isPerformingGesture = false;
|
||||
#endif
|
||||
|
||||
ScopedLock lock (listenerLock);
|
||||
|
||||
for (int i = listeners.size(); --i >= 0;)
|
||||
if (auto* l = listeners[i])
|
||||
l->parameterGestureChanged (getParameterIndex(), false);
|
||||
|
||||
// audioProcessorParameterChangeGestureEnd callbacks will shortly be deprecated and
|
||||
// this code will be removed.
|
||||
for (int i = processor->listeners.size(); --i >= 0;)
|
||||
if (auto* l = processor->listeners[i])
|
||||
l->audioProcessorParameterChangeGestureEnd (processor, getParameterIndex());
|
||||
}
|
||||
|
||||
void AudioProcessorParameter::sendValueChangedMessageToListeners (float newValue)
|
||||
{
|
||||
ScopedLock lock (listenerLock);
|
||||
|
||||
for (int i = listeners.size(); --i >= 0;)
|
||||
if (auto* l = listeners [i])
|
||||
l->parameterValueChanged (getParameterIndex(), newValue);
|
||||
|
||||
// audioProcessorParameterChanged callbacks will shortly be deprecated and
|
||||
// this code will be removed.
|
||||
for (int i = processor->listeners.size(); --i >= 0;)
|
||||
if (auto* l = processor->listeners[i])
|
||||
l->audioProcessorParameterChanged (processor, getParameterIndex(), newValue);
|
||||
}
|
||||
|
||||
bool AudioProcessorParameter::isOrientationInverted() const { return false; }
|
||||
|
|
@ -1372,6 +1452,18 @@ String AudioProcessorParameter::getText (float value, int /*maximumStringLength*
|
|||
return String (value, 2);
|
||||
}
|
||||
|
||||
void AudioProcessorParameter::addListener (AudioProcessorParameter::Listener* newListener)
|
||||
{
|
||||
const ScopedLock sl (listenerLock);
|
||||
listeners.addIfNotAlreadyThere (newListener);
|
||||
}
|
||||
|
||||
void AudioProcessorParameter::removeListener (AudioProcessorParameter::Listener* listenerToRemove)
|
||||
{
|
||||
const ScopedLock sl (listenerLock);
|
||||
listeners.removeFirstMatchingValue (listenerToRemove);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool AudioPlayHead::CurrentPositionInfo::operator== (const CurrentPositionInfo& other) const noexcept
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1616,10 +1616,10 @@ private:
|
|||
template <typename floatType>
|
||||
void processBypassed (AudioBuffer<floatType>&, MidiBuffer&);
|
||||
|
||||
#if JucePlugin_Build_VST3
|
||||
friend class AudioProcessorParameter;
|
||||
|
||||
friend class JuceVST3EditController;
|
||||
friend class JuceVST3Component;
|
||||
#endif
|
||||
|
||||
Atomic<int> vst3IsPlaying { 0 };
|
||||
|
||||
|
|
|
|||
|
|
@ -199,10 +199,78 @@ public:
|
|||
/** Returns the index of this parameter in its parent processor's parameter list. */
|
||||
int getParameterIndex() const noexcept { return parameterIndex; }
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A base class for listeners that want to know about changes to an
|
||||
AudioProcessorParameter.
|
||||
|
||||
Use AudioProcessorParameter::addListener() to register your listener with
|
||||
an AudioProcessorParameter.
|
||||
|
||||
This Listener replaces most of the functionality in the
|
||||
AudioProcessorListener class, which will be deprecated and removed.
|
||||
*/
|
||||
class JUCE_API Listener
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~Listener() {}
|
||||
|
||||
/** Receives a callback when a parameter has been changed.
|
||||
|
||||
IMPORTANT NOTE: this will be called synchronously when a parameter changes, and
|
||||
many audio processors will change their parameter during their audio callback.
|
||||
This means that not only has your handler code got to be completely thread-safe,
|
||||
but it's also got to be VERY fast, and avoid blocking. If you need to handle
|
||||
this event on your message thread, use this callback to trigger an AsyncUpdater
|
||||
or ChangeBroadcaster which you can respond to on the message thread.
|
||||
*/
|
||||
virtual void parameterValueChanged (int parameterIndex, float newValue) = 0;
|
||||
|
||||
/** Indicates that a parameter change gesture has started.
|
||||
|
||||
E.g. if the user is dragging a slider, this would be called with gestureIsStarting
|
||||
being true when they first press the mouse button, and it will be called again with
|
||||
gestureIsStarting being false when they release it.
|
||||
|
||||
IMPORTANT NOTE: this will be called synchronously, and many audio processors will
|
||||
call it during their audio callback. This means that not only has your handler code
|
||||
got to be completely thread-safe, but it's also got to be VERY fast, and avoid
|
||||
blocking. If you need to handle this event on your message thread, use this callback
|
||||
to trigger an AsyncUpdater or ChangeBroadcaster which you can respond to later on the
|
||||
message thread.
|
||||
*/
|
||||
virtual void parameterGestureChanged (int parameterIndex, bool gestureIsStarting) = 0;
|
||||
};
|
||||
|
||||
/** Registers a listener to receive events when the parameter's state changes.
|
||||
If the listener is already registered, this will not register it again.
|
||||
|
||||
@see removeListener
|
||||
*/
|
||||
void addListener (Listener* newListener);
|
||||
|
||||
/** Removes a previously registered parameter listener
|
||||
|
||||
@see addListener
|
||||
*/
|
||||
void removeListener (Listener* listener);
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void sendValueChangedMessageToListeners (float newValue);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
friend class AudioProcessor;
|
||||
AudioProcessor* processor = nullptr;
|
||||
int parameterIndex = -1;
|
||||
CriticalSection listenerLock;
|
||||
Array<Listener*> listeners;
|
||||
|
||||
#if JUCE_DEBUG
|
||||
bool isPerformingGesture = false;
|
||||
#endif
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorParameter)
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue