- clean working copy for leaving SVN

This commit is contained in:
2022-06-28 19:04:46 +02:00
parent 62a2d47cb3
commit 762b8f0e7d
1966 changed files with 699872 additions and 126 deletions
@@ -0,0 +1,140 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_AUDIOPLAYHEAD_H_INCLUDED
#define JUCE_AUDIOPLAYHEAD_H_INCLUDED
//==============================================================================
/**
A subclass of AudioPlayHead can supply information about the position and
status of a moving play head during audio playback.
One of these can be supplied to an AudioProcessor object so that it can find
out about the position of the audio that it is rendering.
@see AudioProcessor::setPlayHead, AudioProcessor::getPlayHead
*/
class JUCE_API AudioPlayHead
{
protected:
//==============================================================================
AudioPlayHead() {}
public:
virtual ~AudioPlayHead() {}
//==============================================================================
/** Frame rate types. */
enum FrameRateType
{
fps24 = 0,
fps25 = 1,
fps2997 = 2,
fps30 = 3,
fps2997drop = 4,
fps30drop = 5,
fpsUnknown = 99
};
//==============================================================================
/** This structure is filled-in by the AudioPlayHead::getCurrentPosition() method.
*/
struct JUCE_API CurrentPositionInfo
{
/** The tempo in BPM */
double bpm;
/** Time signature numerator, e.g. the 3 of a 3/4 time sig */
int timeSigNumerator;
/** Time signature denominator, e.g. the 4 of a 3/4 time sig */
int timeSigDenominator;
/** The current play position, in samples from the start of the edit. */
int64 timeInSamples;
/** The current play position, in seconds from the start of the edit. */
double timeInSeconds;
/** For timecode, the position of the start of the edit, in seconds from 00:00:00:00. */
double editOriginTime;
/** The current play position, in pulses-per-quarter-note. */
double ppqPosition;
/** The position of the start of the last bar, in pulses-per-quarter-note.
This is the time from the start of the edit to the start of the current
bar, in ppq units.
Note - this value may be unavailable on some hosts, e.g. Pro-Tools. If
it's not available, the value will be 0.
*/
double ppqPositionOfLastBarStart;
/** The video frame rate, if applicable. */
FrameRateType frameRate;
/** True if the transport is currently playing. */
bool isPlaying;
/** True if the transport is currently recording.
(When isRecording is true, then isPlaying will also be true).
*/
bool isRecording;
/** The current cycle start position in pulses-per-quarter-note.
Note that not all hosts or plugin formats may provide this value.
@see isLooping
*/
double ppqLoopStart;
/** The current cycle end position in pulses-per-quarter-note.
Note that not all hosts or plugin formats may provide this value.
@see isLooping
*/
double ppqLoopEnd;
/** True if the transport is currently looping. */
bool isLooping;
//==============================================================================
bool operator== (const CurrentPositionInfo& other) const noexcept;
bool operator!= (const CurrentPositionInfo& other) const noexcept;
void resetToDefault();
};
//==============================================================================
/** Fills-in the given structure with details about the transport's
position at the start of the current processing block.
This method must ONLY be called from within your AudioProcessor::processBlock()
method. Calling it at any other time will probably cause a nasty crash.
*/
virtual bool getCurrentPosition (CurrentPositionInfo& result) = 0;
};
#endif // JUCE_AUDIOPLAYHEAD_H_INCLUDED
@@ -0,0 +1,86 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_AUDIOPLUGININSTANCE_H_INCLUDED
#define JUCE_AUDIOPLUGININSTANCE_H_INCLUDED
//==============================================================================
/**
Base class for an active instance of a plugin.
This derives from the AudioProcessor class, and adds some extra functionality
that helps when wrapping dynamically loaded plugins.
This class is not needed when writing plugins, and you should never need to derive
your own sub-classes from it. The plugin hosting classes use it internally and will
return AudioPluginInstance objects which wrap external plugins.
@see AudioProcessor, AudioPluginFormat
*/
class JUCE_API AudioPluginInstance : public AudioProcessor
{
public:
//==============================================================================
/** Destructor.
Make sure that you delete any UI components that belong to this plugin before
deleting the plugin.
*/
virtual ~AudioPluginInstance() {}
//==============================================================================
/** Fills-in the appropriate parts of this plugin description object. */
virtual void fillInPluginDescription (PluginDescription& description) const = 0;
/** Returns a PluginDescription for this plugin.
This is just a convenience method to avoid calling fillInPluginDescription.
*/
PluginDescription getPluginDescription() const
{
PluginDescription desc;
fillInPluginDescription (desc);
return desc;
}
/** Returns a pointer to some kind of platform-specific data about the plugin.
E.g. For a VST, this value can be cast to an AEffect*. For an AudioUnit, it can be
cast to an AudioUnit handle.
*/
virtual void* getPlatformSpecificData() { return nullptr; }
/** For some formats (currently AudioUnit), this forces a reload of the list of
available parameters.
*/
virtual void refreshParameterList() {}
protected:
//==============================================================================
AudioPluginInstance() {}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginInstance)
};
#endif // JUCE_AUDIOPLUGININSTANCE_H_INCLUDED
@@ -0,0 +1,474 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
static ThreadLocalValue<AudioProcessor::WrapperType> wrapperTypeBeingCreated;
void JUCE_CALLTYPE AudioProcessor::setTypeOfNextNewPlugin (AudioProcessor::WrapperType type)
{
wrapperTypeBeingCreated = type;
}
AudioProcessor::AudioProcessor()
: wrapperType (wrapperTypeBeingCreated.get()),
playHead (nullptr),
sampleRate (0),
blockSize (0),
numInputChannels (0),
numOutputChannels (0),
latencySamples (0),
suspended (false),
nonRealtime (false)
{
}
AudioProcessor::~AudioProcessor()
{
// ooh, nasty - the editor should have been deleted before the filter
// that it refers to is deleted..
jassert (activeEditor == nullptr);
#if JUCE_DEBUG
// This will fail if you've called beginParameterChangeGesture() for one
// or more parameters without having made a corresponding call to endParameterChangeGesture...
jassert (changingParams.countNumberOfSetBits() == 0);
#endif
}
void AudioProcessor::setPlayHead (AudioPlayHead* const newPlayHead)
{
playHead = newPlayHead;
}
void AudioProcessor::addListener (AudioProcessorListener* const newListener)
{
const ScopedLock sl (listenerLock);
listeners.addIfNotAlreadyThere (newListener);
}
void AudioProcessor::removeListener (AudioProcessorListener* const listenerToRemove)
{
const ScopedLock sl (listenerLock);
listeners.removeFirstMatchingValue (listenerToRemove);
}
void AudioProcessor::setPlayConfigDetails (const int newNumIns,
const int newNumOuts,
const double newSampleRate,
const int newBlockSize) noexcept
{
sampleRate = newSampleRate;
blockSize = newBlockSize;
if (numInputChannels != newNumIns || numOutputChannels != newNumOuts)
{
numInputChannels = newNumIns;
numOutputChannels = newNumOuts;
numChannelsChanged();
}
}
void AudioProcessor::numChannelsChanged() {}
void AudioProcessor::setSpeakerArrangement (const String& inputs, const String& outputs)
{
inputSpeakerArrangement = inputs;
outputSpeakerArrangement = outputs;
}
void AudioProcessor::setNonRealtime (const bool newNonRealtime) noexcept
{
nonRealtime = newNonRealtime;
}
void AudioProcessor::setLatencySamples (const int newLatency)
{
if (latencySamples != newLatency)
{
latencySamples = newLatency;
updateHostDisplay();
}
}
void AudioProcessor::setParameterNotifyingHost (const int parameterIndex,
const float newValue)
{
setParameter (parameterIndex, newValue);
sendParamChangeMessageToListeners (parameterIndex, newValue);
}
AudioProcessorListener* AudioProcessor::getListenerLocked (const int index) const noexcept
{
const ScopedLock sl (listenerLock);
return listeners [index];
}
void AudioProcessor::sendParamChangeMessageToListeners (const int parameterIndex, const float newValue)
{
if (isPositiveAndBelow (parameterIndex, getNumParameters()))
{
for (int i = listeners.size(); --i >= 0;)
if (AudioProcessorListener* 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 JUCE_DEBUG
// 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 (AudioProcessorListener* 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 JUCE_DEBUG
// This means you've called endParameterChangeGesture without having previously called
// endParameterChangeGesture. 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 (AudioProcessorListener* l = getListenerLocked (i))
l->audioProcessorParameterChangeGestureEnd (this, parameterIndex);
}
else
{
jassertfalse; // called with an out-of-range parameter index!
}
}
void AudioProcessor::updateHostDisplay()
{
for (int i = listeners.size(); --i >= 0;)
if (AudioProcessorListener* l = getListenerLocked (i))
l->audioProcessorChanged (this);
}
const OwnedArray<AudioProcessorParameter>& AudioProcessor::getParameters() const noexcept
{
return managedParameters;
}
int AudioProcessor::getNumParameters()
{
return managedParameters.size();
}
float AudioProcessor::getParameter (int index)
{
if (AudioProcessorParameter* p = getParamChecked (index))
return p->getValue();
return 0;
}
void AudioProcessor::setParameter (int index, float newValue)
{
if (AudioProcessorParameter* p = getParamChecked (index))
p->setValue (newValue);
}
float AudioProcessor::getParameterDefaultValue (int index)
{
if (AudioProcessorParameter* p = managedParameters[index])
return p->getDefaultValue();
return 0;
}
const String AudioProcessor::getParameterName (int index)
{
if (AudioProcessorParameter* p = getParamChecked (index))
return p->getName (512);
return String();
}
String AudioProcessor::getParameterName (int index, int maximumStringLength)
{
if (AudioProcessorParameter* p = managedParameters[index])
return p->getName (maximumStringLength);
return getParameterName (index).substring (0, maximumStringLength);
}
const String AudioProcessor::getParameterText (int index)
{
return getParameterText (index, 1024);
}
String AudioProcessor::getParameterText (int index, int maximumStringLength)
{
if (AudioProcessorParameter* p = managedParameters[index])
return p->getText (p->getValue(), maximumStringLength);
return getParameterText (index).substring (0, maximumStringLength);
}
int AudioProcessor::getParameterNumSteps (int index)
{
if (AudioProcessorParameter* p = managedParameters[index])
return p->getNumSteps();
return AudioProcessor::getDefaultNumParameterSteps();
}
int AudioProcessor::getDefaultNumParameterSteps() noexcept
{
return 0x7fffffff;
}
String AudioProcessor::getParameterLabel (int index) const
{
if (AudioProcessorParameter* p = managedParameters[index])
return p->getLabel();
return String();
}
bool AudioProcessor::isParameterAutomatable (int index) const
{
if (AudioProcessorParameter* p = managedParameters[index])
return p->isAutomatable();
return true;
}
bool AudioProcessor::isParameterOrientationInverted (int index) const
{
if (AudioProcessorParameter* p = managedParameters[index])
return p->isOrientationInverted();
return false;
}
bool AudioProcessor::isMetaParameter (int index) const
{
if (AudioProcessorParameter* p = managedParameters[index])
return p->isMetaParameter();
return false;
}
AudioProcessorParameter* AudioProcessor::getParamChecked (int index) const noexcept
{
AudioProcessorParameter* p = managedParameters[index];
// If you hit this, then you're either trying to access parameters that are out-of-range,
// or you're not using addParameter and the managed parameter list, but have failed
// to override some essential virtual methods and implement them appropriately.
jassert (p != nullptr);
return p;
}
void AudioProcessor::addParameter (AudioProcessorParameter* p)
{
p->processor = this;
p->parameterIndex = managedParameters.size();
managedParameters.add (p);
}
void AudioProcessor::suspendProcessing (const bool shouldBeSuspended)
{
const ScopedLock sl (callbackLock);
suspended = shouldBeSuspended;
}
void AudioProcessor::reset() {}
void AudioProcessor::processBlockBypassed (AudioSampleBuffer&, MidiBuffer&) {}
//==============================================================================
void AudioProcessor::editorBeingDeleted (AudioProcessorEditor* const editor) noexcept
{
const ScopedLock sl (callbackLock);
if (activeEditor == editor)
activeEditor = nullptr;
}
AudioProcessorEditor* AudioProcessor::createEditorIfNeeded()
{
if (activeEditor != nullptr)
return activeEditor;
AudioProcessorEditor* const ed = createEditor();
if (ed != nullptr)
{
// you must give your editor comp a size before returning it..
jassert (ed->getWidth() > 0 && ed->getHeight() > 0);
const ScopedLock sl (callbackLock);
activeEditor = ed;
}
// You must make your hasEditor() method return a consistent result!
jassert (hasEditor() == (ed != nullptr));
return ed;
}
//==============================================================================
void AudioProcessor::getCurrentProgramStateInformation (juce::MemoryBlock& destData)
{
getStateInformation (destData);
}
void AudioProcessor::setCurrentProgramStateInformation (const void* data, int sizeInBytes)
{
setStateInformation (data, sizeInBytes);
}
//==============================================================================
// magic number to identify memory blocks that we've stored as XML
const uint32 magicXmlNumber = 0x21324356;
void AudioProcessor::copyXmlToBinary (const XmlElement& xml, juce::MemoryBlock& destData)
{
{
MemoryOutputStream out (destData, false);
out.writeInt (magicXmlNumber);
out.writeInt (0);
xml.writeToStream (out, String(), true, false);
out.writeByte (0);
}
// go back and write the string length..
static_cast<uint32*> (destData.getData())[1]
= ByteOrder::swapIfBigEndian ((uint32) destData.getSize() - 9);
}
XmlElement* AudioProcessor::getXmlFromBinary (const void* data, const int sizeInBytes)
{
if (sizeInBytes > 8
&& ByteOrder::littleEndianInt (data) == magicXmlNumber)
{
const int stringLength = (int) ByteOrder::littleEndianInt (addBytesToPointer (data, 4));
if (stringLength > 0)
return XmlDocument::parse (String::fromUTF8 (static_cast<const char*> (data) + 8,
jmin ((sizeInBytes - 8), stringLength)));
}
return nullptr;
}
//==============================================================================
void AudioProcessorListener::audioProcessorParameterChangeGestureBegin (AudioProcessor*, int) {}
void AudioProcessorListener::audioProcessorParameterChangeGestureEnd (AudioProcessor*, int) {}
//==============================================================================
AudioProcessorParameter::AudioProcessorParameter() noexcept
: processor (nullptr), parameterIndex (-1)
{}
AudioProcessorParameter::~AudioProcessorParameter() {}
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);
}
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);
}
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);
}
bool AudioProcessorParameter::isOrientationInverted() const { return false; }
bool AudioProcessorParameter::isAutomatable() const { return true; }
bool AudioProcessorParameter::isMetaParameter() const { return false; }
int AudioProcessorParameter::getNumSteps() const { return AudioProcessor::getDefaultNumParameterSteps(); }
String AudioProcessorParameter::getText (float value, int /*maximumStringLength*/) const
{
return String (value, 2);
}
//==============================================================================
bool AudioPlayHead::CurrentPositionInfo::operator== (const CurrentPositionInfo& other) const noexcept
{
return timeInSamples == other.timeInSamples
&& ppqPosition == other.ppqPosition
&& editOriginTime == other.editOriginTime
&& ppqPositionOfLastBarStart == other.ppqPositionOfLastBarStart
&& frameRate == other.frameRate
&& isPlaying == other.isPlaying
&& isRecording == other.isRecording
&& bpm == other.bpm
&& timeSigNumerator == other.timeSigNumerator
&& timeSigDenominator == other.timeSigDenominator
&& ppqLoopStart == other.ppqLoopStart
&& ppqLoopEnd == other.ppqLoopEnd
&& isLooping == other.isLooping;
}
bool AudioPlayHead::CurrentPositionInfo::operator!= (const CurrentPositionInfo& other) const noexcept
{
return ! operator== (other);
}
void AudioPlayHead::CurrentPositionInfo::resetToDefault()
{
zerostruct (*this);
timeSigNumerator = 4;
timeSigDenominator = 4;
bpm = 120;
}
@@ -0,0 +1,689 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_AUDIOPROCESSOR_H_INCLUDED
#define JUCE_AUDIOPROCESSOR_H_INCLUDED
//==============================================================================
/**
Base class for audio processing filters or plugins.
This is intended to act as a base class of audio filter that is general enough to
be wrapped as a VST, AU, RTAS, etc, or used internally.
It is also used by the plugin hosting code as the wrapper around an instance
of a loaded plugin.
Derive your filter class from this base class, and if you're building a plugin,
you should implement a global function called createPluginFilter() which creates
and returns a new instance of your subclass.
*/
class JUCE_API AudioProcessor
{
protected:
//==============================================================================
/** Constructor. */
AudioProcessor();
public:
/** Destructor. */
virtual ~AudioProcessor();
//==============================================================================
/** Returns the name of this processor. */
virtual const String getName() const = 0;
//==============================================================================
/** Called before playback starts, to let the filter prepare itself.
The sample rate is the target sample rate, and will remain constant until
playback stops.
The estimatedSamplesPerBlock value is a HINT about the typical number of
samples that will be processed for each callback, but isn't any kind
of guarantee. The actual block sizes that the host uses may be different
each time the callback happens, and may be more or less than this value.
*/
virtual void prepareToPlay (double sampleRate,
int estimatedSamplesPerBlock) = 0;
/** Called after playback has stopped, to let the filter free up any resources it
no longer needs.
*/
virtual void releaseResources() = 0;
/** Renders the next block.
When this method is called, the buffer contains a number of channels which is
at least as great as the maximum number of input and output channels that
this filter is using. It will be filled with the filter's input data and
should be replaced with the filter's output.
So for example if your filter has 2 input channels and 4 output channels, then
the buffer will contain 4 channels, the first two being filled with the
input data. Your filter should read these, do its processing, and replace
the contents of all 4 channels with its output.
Or if your filter has 5 inputs and 2 outputs, the buffer will have 5 channels,
all filled with data, and your filter should overwrite the first 2 of these
with its output. But be VERY careful not to write anything to the last 3
channels, as these might be mapped to memory that the host assumes is read-only!
Note that if you have more outputs than inputs, then only those channels that
correspond to an input channel are guaranteed to contain sensible data - e.g.
in the case of 2 inputs and 4 outputs, the first two channels contain the input,
but the last two channels may contain garbage, so you should be careful not to
let this pass through without being overwritten or cleared.
Also note that the buffer may have more channels than are strictly necessary,
but you should only read/write from the ones that your filter is supposed to
be using.
The number of samples in these buffers is NOT guaranteed to be the same for every
callback, and may be more or less than the estimated value given to prepareToPlay().
Your code must be able to cope with variable-sized blocks, or you're going to get
clicks and crashes!
If the filter is receiving a midi input, then the midiMessages array will be filled
with the midi messages for this block. Each message's timestamp will indicate the
message's time, as a number of samples from the start of the block.
Any messages left in the midi buffer when this method has finished are assumed to
be the filter's midi output. This means that your filter should be careful to
clear any incoming messages from the array if it doesn't want them to be passed-on.
Be very careful about what you do in this callback - it's going to be called by
the audio thread, so any kind of interaction with the UI is absolutely
out of the question. If you change a parameter in here and need to tell your UI to
update itself, the best way is probably to inherit from a ChangeBroadcaster, let
the UI components register as listeners, and then call sendChangeMessage() inside the
processBlock() method to send out an asynchronous message. You could also use
the AsyncUpdater class in a similar way.
*/
virtual void processBlock (AudioSampleBuffer& buffer,
MidiBuffer& midiMessages) = 0;
/** Renders the next block when the processor is being bypassed.
The default implementation of this method will pass-through any incoming audio, but
you may override this method e.g. to add latency compensation to the data to match
the processor's latency characteristics. This will avoid situations where bypassing
will shift the signal forward in time, possibly creating pre-echo effects and odd timings.
Another use for this method would be to cross-fade or morph between the wet (not bypassed)
and dry (bypassed) signals.
*/
virtual void processBlockBypassed (AudioSampleBuffer& buffer,
MidiBuffer& midiMessages);
//==============================================================================
/** Returns the current AudioPlayHead object that should be used to find
out the state and position of the playhead.
You can call this from your processBlock() method, and use the AudioPlayHead
object to get the details about the time of the start of the block currently
being processed.
If the host hasn't supplied a playhead object, this will return nullptr.
*/
AudioPlayHead* getPlayHead() const noexcept { return playHead; }
//==============================================================================
/** Returns the current sample rate.
This can be called from your processBlock() method - it's not guaranteed
to be valid at any other time, and may return 0 if it's unknown.
*/
double getSampleRate() const noexcept { return sampleRate; }
/** Returns the current typical block size that is being used.
This can be called from your processBlock() method - it's not guaranteed
to be valid at any other time.
Remember it's not the ONLY block size that may be used when calling
processBlock, it's just the normal one. The actual block sizes used may be
larger or smaller than this, and will vary between successive calls.
*/
int getBlockSize() const noexcept { return blockSize; }
//==============================================================================
/** Returns the number of input channels that the host will be sending the filter.
If writing a plugin, your configuration macros should specify the number of
channels that your filter would prefer to have, and this method lets
you know how many the host is actually using.
Note that this method is only valid during or after the prepareToPlay()
method call. Until that point, the number of channels will be unknown.
*/
int getNumInputChannels() const noexcept { return numInputChannels; }
/** Returns the number of output channels that the host will be sending the filter.
If writing a plugin, your configuration macros should specify the number of
channels that your filter would prefer to have, and this method lets
you know how many the host is actually using.
Note that this method is only valid during or after the prepareToPlay()
method call. Until that point, the number of channels will be unknown.
*/
int getNumOutputChannels() const noexcept { return numOutputChannels; }
/** Returns a string containing a whitespace-separated list of speaker types
corresponding to each input channel.
For example in a 5.1 arrangement, the string may be "L R C Lfe Ls Rs"
If the speaker arrangement is unknown, the returned string will be empty.
*/
const String& getInputSpeakerArrangement() const noexcept { return inputSpeakerArrangement; }
/** Returns a string containing a whitespace-separated list of speaker types
corresponding to each output channel.
For example in a 5.1 arrangement, the string may be "L R C Lfe Ls Rs"
If the speaker arrangement is unknown, the returned string will be empty.
*/
const String& getOutputSpeakerArrangement() const noexcept { return outputSpeakerArrangement; }
//==============================================================================
/** Returns the name of one of the processor's input channels.
The processor might not supply very useful names for channels, and this might be
something like "1", "2", "left", "right", etc.
*/
virtual const String getInputChannelName (int channelIndex) const = 0;
/** Returns the name of one of the processor's output channels.
The processor might not supply very useful names for channels, and this might be
something like "1", "2", "left", "right", etc.
*/
virtual const String getOutputChannelName (int channelIndex) const = 0;
/** Returns true if the specified channel is part of a stereo pair with its neighbour. */
virtual bool isInputChannelStereoPair (int index) const = 0;
/** Returns true if the specified channel is part of a stereo pair with its neighbour. */
virtual bool isOutputChannelStereoPair (int index) const = 0;
/** This returns the number of samples delay that the filter imposes on the audio
passing through it.
The host will call this to find the latency - the filter itself should set this value
by calling setLatencySamples() as soon as it can during its initialisation.
*/
int getLatencySamples() const noexcept { return latencySamples; }
/** The filter should call this to set the number of samples delay that it introduces.
The filter should call this as soon as it can during initialisation, and can call it
later if the value changes.
*/
void setLatencySamples (int newLatency);
/** Returns true if a silent input always produces a silent output. */
virtual bool silenceInProducesSilenceOut() const = 0;
/** Returns the length of the filter's tail, in seconds. */
virtual double getTailLengthSeconds() const = 0;
/** Returns true if the processor wants midi messages. */
virtual bool acceptsMidi() const = 0;
/** Returns true if the processor produces midi messages. */
virtual bool producesMidi() const = 0;
//==============================================================================
/** This returns a critical section that will automatically be locked while the host
is calling the processBlock() method.
Use it from your UI or other threads to lock access to variables that are used
by the process callback, but obviously be careful not to keep it locked for
too long, because that could cause stuttering playback. If you need to do something
that'll take a long time and need the processing to stop while it happens, use the
suspendProcessing() method instead.
@see suspendProcessing
*/
const CriticalSection& getCallbackLock() const noexcept { return callbackLock; }
/** Enables and disables the processing callback.
If you need to do something time-consuming on a thread and would like to make sure
the audio processing callback doesn't happen until you've finished, use this
to disable the callback and re-enable it again afterwards.
E.g.
@code
void loadNewPatch()
{
suspendProcessing (true);
..do something that takes ages..
suspendProcessing (false);
}
@endcode
If the host tries to make an audio callback while processing is suspended, the
filter will return an empty buffer, but won't block the audio thread like it would
do if you use the getCallbackLock() critical section to synchronise access.
Any code that calls processBlock() should call isSuspended() before doing so, and
if the processor is suspended, it should avoid the call and emit silence or
whatever is appropriate.
@see getCallbackLock
*/
void suspendProcessing (bool shouldBeSuspended);
/** Returns true if processing is currently suspended.
@see suspendProcessing
*/
bool isSuspended() const noexcept { return suspended; }
/** A plugin can override this to be told when it should reset any playing voices.
The default implementation does nothing, but a host may call this to tell the
plugin that it should stop any tails or sounds that have been left running.
*/
virtual void reset();
//==============================================================================
/** Returns true if the processor is being run in an offline mode for rendering.
If the processor is being run live on realtime signals, this returns false.
If the mode is unknown, this will assume it's realtime and return false.
This value may be unreliable until the prepareToPlay() method has been called,
and could change each time prepareToPlay() is called.
@see setNonRealtime()
*/
bool isNonRealtime() const noexcept { return nonRealtime; }
/** Called by the host to tell this processor whether it's being used in a non-realtime
capacity for offline rendering or bouncing.
*/
virtual void setNonRealtime (bool isNonRealtime) noexcept;
//==============================================================================
/** Creates the filter's UI.
This can return nullptr if you want a UI-less filter, in which case the host may create
a generic UI that lets the user twiddle the parameters directly.
If you do want to pass back a component, the component should be created and set to
the correct size before returning it. If you implement this method, you must
also implement the hasEditor() method and make it return true.
Remember not to do anything silly like allowing your filter to keep a pointer to
the component that gets created - it could be deleted later without any warning, which
would make your pointer into a dangler. Use the getActiveEditor() method instead.
The correct way to handle the connection between an editor component and its
filter is to use something like a ChangeBroadcaster so that the editor can
register itself as a listener, and be told when a change occurs. This lets them
safely unregister themselves when they are deleted.
Here are a few things to bear in mind when writing an editor:
- Initially there won't be an editor, until the user opens one, or they might
not open one at all. Your filter mustn't rely on it being there.
- An editor object may be deleted and a replacement one created again at any time.
- It's safe to assume that an editor will be deleted before its filter.
@see hasEditor
*/
virtual AudioProcessorEditor* createEditor() = 0;
/** Your filter must override this and return true if it can create an editor component.
@see createEditor
*/
virtual bool hasEditor() const = 0;
//==============================================================================
/** Returns the active editor, if there is one.
Bear in mind this can return nullptr, even if an editor has previously been opened.
*/
AudioProcessorEditor* getActiveEditor() const noexcept { return activeEditor; }
/** Returns the active editor, or if there isn't one, it will create one.
This may call createEditor() internally to create the component.
*/
AudioProcessorEditor* createEditorIfNeeded();
//==============================================================================
/** This must return the correct value immediately after the object has been
created, and mustn't change the number of parameters later.
*/
virtual int getNumParameters();
/** Returns the name of a particular parameter. */
virtual const String getParameterName (int parameterIndex);
/** Called by the host to find out the value of one of the filter's parameters.
The host will expect the value returned to be between 0 and 1.0.
This could be called quite frequently, so try to make your code efficient.
It's also likely to be called by non-UI threads, so the code in here should
be thread-aware.
*/
virtual float getParameter (int parameterIndex);
/** Returns the value of a parameter as a text string. */
virtual const String getParameterText (int parameterIndex);
/** Returns the name of a parameter as a text string with a preferred maximum length.
If you want to provide customised short versions of your parameter names that
will look better in constrained spaces (e.g. the displays on hardware controller
devices or mixing desks) then you should implement this method.
If you don't override it, the default implementation will call getParameterText(int),
and truncate the result.
*/
virtual String getParameterName (int parameterIndex, int maximumStringLength);
/** Returns the value of a parameter as a text string with a preferred maximum length.
If you want to provide customised short versions of your parameter values that
will look better in constrained spaces (e.g. the displays on hardware controller
devices or mixing desks) then you should implement this method.
If you don't override it, the default implementation will call getParameterText(int),
and truncate the result.
*/
virtual String getParameterText (int parameterIndex, int maximumStringLength);
/** Returns the number of discrete steps that this parameter can represent.
The default return value if you don't implement this method is
AudioProcessor::getDefaultNumParameterSteps().
If your parameter is boolean, then you may want to make this return 2.
The value that is returned may or may not be used, depending on the host.
*/
virtual int getParameterNumSteps (int parameterIndex);
/** Returns the default number of steps for a parameter.
@see getParameterNumSteps
*/
static int getDefaultNumParameterSteps() noexcept;
/** Returns the default value for the parameter.
By default, this just returns 0.
The value that is returned may or may not be used, depending on the host.
*/
virtual float getParameterDefaultValue (int parameterIndex);
/** Some plugin types may be able to return a label string for a
parameter's units.
*/
virtual String getParameterLabel (int index) const;
/** This can be overridden to tell the host that particular parameters operate in the
reverse direction. (Not all plugin formats or hosts will actually use this information).
*/
virtual bool isParameterOrientationInverted (int index) const;
/** The host will call this method to change the value of one of the filter's parameters.
The host may call this at any time, including during the audio processing
callback, so the filter has to process this very fast and avoid blocking.
If you want to set the value of a parameter internally, e.g. from your
editor component, then don't call this directly - instead, use the
setParameterNotifyingHost() method, which will also send a message to
the host telling it about the change. If the message isn't sent, the host
won't be able to automate your parameters properly.
The value passed will be between 0 and 1.0.
*/
virtual void setParameter (int parameterIndex, float newValue);
/** Your filter can call this when it needs to change one of its parameters.
This could happen when the editor or some other internal operation changes
a parameter. This method will call the setParameter() method to change the
value, and will then send a message to the host telling it about the change.
Note that to make sure the host correctly handles automation, you should call
the beginParameterChangeGesture() and endParameterChangeGesture() methods to
tell the host when the user has started and stopped changing the parameter.
*/
void setParameterNotifyingHost (int parameterIndex, float newValue);
/** Returns true if the host can automate this parameter.
By default, this returns true for all parameters.
*/
virtual bool isParameterAutomatable (int parameterIndex) const;
/** Should return true if this parameter is a "meta" parameter.
A meta-parameter is a parameter that changes other params. It is used
by some hosts (e.g. AudioUnit hosts).
By default this returns false.
*/
virtual bool isMetaParameter (int parameterIndex) const;
/** Sends a signal to the host to tell it that the user is about to start changing this
parameter.
This allows the host to know when a parameter is actively being held by the user, and
it may use this information to help it record automation.
If you call this, it must be matched by a later call to endParameterChangeGesture().
*/
void beginParameterChangeGesture (int parameterIndex);
/** Tells the host that the user has finished changing this parameter.
This allows the host to know when a parameter is actively being held by the user, and
it may use this information to help it record automation.
A call to this method must follow a call to beginParameterChangeGesture().
*/
void endParameterChangeGesture (int parameterIndex);
/** The filter can call this when something (apart from a parameter value) has changed.
It sends a hint to the host that something like the program, number of parameters,
etc, has changed, and that it should update itself.
*/
void updateHostDisplay();
//==============================================================================
/** Adds a parameter to the list.
The parameter object will be managed and deleted automatically by the list
when no longer needed.
*/
void addParameter (AudioProcessorParameter*);
/** Returns the current list of parameters. */
const OwnedArray<AudioProcessorParameter>& getParameters() const noexcept;
//==============================================================================
/** Returns the number of preset programs the filter supports.
The value returned must be valid as soon as this object is created, and
must not change over its lifetime.
This value shouldn't be less than 1.
*/
virtual int getNumPrograms() = 0;
/** Returns the number of the currently active program. */
virtual int getCurrentProgram() = 0;
/** Called by the host to change the current program. */
virtual void setCurrentProgram (int index) = 0;
/** Must return the name of a given program. */
virtual const String getProgramName (int index) = 0;
/** Called by the host to rename a program. */
virtual void changeProgramName (int index, const String& newName) = 0;
//==============================================================================
/** The host will call this method when it wants to save the filter's internal state.
This must copy any info about the filter's state into the block of memory provided,
so that the host can store this and later restore it using setStateInformation().
Note that there's also a getCurrentProgramStateInformation() method, which only
stores the current program, not the state of the entire filter.
See also the helper function copyXmlToBinary() for storing settings as XML.
@see getCurrentProgramStateInformation
*/
virtual void getStateInformation (juce::MemoryBlock& destData) = 0;
/** The host will call this method if it wants to save the state of just the filter's
current program.
Unlike getStateInformation, this should only return the current program's state.
Not all hosts support this, and if you don't implement it, the base class
method just calls getStateInformation() instead. If you do implement it, be
sure to also implement getCurrentProgramStateInformation.
@see getStateInformation, setCurrentProgramStateInformation
*/
virtual void getCurrentProgramStateInformation (juce::MemoryBlock& destData);
/** This must restore the filter's state from a block of data previously created
using getStateInformation().
Note that there's also a setCurrentProgramStateInformation() method, which tries
to restore just the current program, not the state of the entire filter.
See also the helper function getXmlFromBinary() for loading settings as XML.
@see setCurrentProgramStateInformation
*/
virtual void setStateInformation (const void* data, int sizeInBytes) = 0;
/** The host will call this method if it wants to restore the state of just the filter's
current program.
Not all hosts support this, and if you don't implement it, the base class
method just calls setStateInformation() instead. If you do implement it, be
sure to also implement getCurrentProgramStateInformation.
@see setStateInformation, getCurrentProgramStateInformation
*/
virtual void setCurrentProgramStateInformation (const void* data, int sizeInBytes);
/** This method is called when the number of input or output channels is changed. */
virtual void numChannelsChanged();
//==============================================================================
/** Adds a listener that will be called when an aspect of this processor changes. */
virtual void addListener (AudioProcessorListener* newListener);
/** Removes a previously added listener. */
virtual void removeListener (AudioProcessorListener* listenerToRemove);
//==============================================================================
/** Tells the processor to use this playhead object.
The processor will not take ownership of the object, so the caller must delete it when
it is no longer being used.
*/
virtual void setPlayHead (AudioPlayHead* newPlayHead);
//==============================================================================
/** This is called by the processor to specify its details before being played. */
void setPlayConfigDetails (int numIns, int numOuts, double sampleRate, int blockSize) noexcept;
//==============================================================================
/** Not for public use - this is called before deleting an editor component. */
void editorBeingDeleted (AudioProcessorEditor*) noexcept;
/** Not for public use - this is called to initialise the processor before playing. */
void setSpeakerArrangement (const String& inputs, const String& outputs);
/** Flags to indicate the type of plugin context in which a processor is being used. */
enum WrapperType
{
wrapperType_Undefined = 0,
wrapperType_VST,
wrapperType_VST3,
wrapperType_AudioUnit,
wrapperType_RTAS,
wrapperType_AAX,
wrapperType_Standalone
};
/** When loaded by a plugin wrapper, this flag will be set to indicate the type
of plugin within which the processor is running.
*/
WrapperType wrapperType;
//==============================================================================
/** Helper function that just converts an xml element into a binary blob.
Use this in your filter's getStateInformation() method if you want to
store its state as xml.
Then use getXmlFromBinary() to reverse this operation and retrieve the XML
from a binary blob.
*/
static void copyXmlToBinary (const XmlElement& xml,
juce::MemoryBlock& destData);
/** Retrieves an XML element that was stored as binary with the copyXmlToBinary() method.
This might return nullptr if the data's unsuitable or corrupted. Otherwise it will return
an XmlElement object that the caller must delete when no longer needed.
*/
static XmlElement* getXmlFromBinary (const void* data, int sizeInBytes);
/** @internal */
static void JUCE_CALLTYPE setTypeOfNextNewPlugin (WrapperType);
protected:
/** @internal */
AudioPlayHead* playHead;
/** @internal */
void sendParamChangeMessageToListeners (int parameterIndex, float newValue);
private:
Array<AudioProcessorListener*> listeners;
Component::SafePointer<AudioProcessorEditor> activeEditor;
double sampleRate;
int blockSize, numInputChannels, numOutputChannels, latencySamples;
bool suspended, nonRealtime;
CriticalSection callbackLock, listenerLock;
String inputSpeakerArrangement, outputSpeakerArrangement;
OwnedArray<AudioProcessorParameter> managedParameters;
AudioProcessorParameter* getParamChecked (int) const noexcept;
#if JUCE_DEBUG
BigInteger changingParams;
#endif
AudioProcessorListener* getListenerLocked (int) const noexcept;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessor)
};
#endif // JUCE_AUDIOPROCESSOR_H_INCLUDED
@@ -0,0 +1,43 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
AudioProcessorEditor::AudioProcessorEditor (AudioProcessor& p) noexcept : processor (p)
{
}
AudioProcessorEditor::AudioProcessorEditor (AudioProcessor* p) noexcept : processor (*p)
{
// the filter must be valid..
jassert (p != nullptr);
}
AudioProcessorEditor::~AudioProcessorEditor()
{
// if this fails, then the wrapper hasn't called editorBeingDeleted() on the
// filter for some reason..
jassert (processor.getActiveEditor() != this);
}
void AudioProcessorEditor::setControlHighlight (ParameterControlHighlightInfo) {}
int AudioProcessorEditor::getControlParameterIndex (Component&) { return -1; }
@@ -0,0 +1,92 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_AUDIOPROCESSOREDITOR_H_INCLUDED
#define JUCE_AUDIOPROCESSOREDITOR_H_INCLUDED
//==============================================================================
/**
Base class for the component that acts as the GUI for an AudioProcessor.
Derive your editor component from this class, and create an instance of it
by overriding the AudioProcessor::createEditor() method.
@see AudioProcessor, GenericAudioProcessorEditor
*/
class JUCE_API AudioProcessorEditor : public Component
{
protected:
//==============================================================================
/** Creates an editor for the specified processor. */
AudioProcessorEditor (AudioProcessor&) noexcept;
/** Creates an editor for the specified processor. */
AudioProcessorEditor (AudioProcessor*) noexcept;
public:
/** Destructor. */
~AudioProcessorEditor();
//==============================================================================
/** The AudioProcessor that this editor represents. */
AudioProcessor& processor;
/** Returns a pointer to the processor that this editor represents.
This method is here to support legacy code, but it's easier to just use the
AudioProcessorEditor::processor member variable directly to get this object.
*/
AudioProcessor* getAudioProcessor() const noexcept { return &processor; }
//==============================================================================
/** Used by the setParameterHighlighting() method. */
struct ParameterControlHighlightInfo
{
int parameterIndex;
bool isHighlighted;
Colour suggestedColour;
};
/** Some types of plugin can call this to suggest that the control for a particular
parameter should be highlighted.
Currently only AAX plugins will call this, and implementing it is optional.
*/
virtual void setControlHighlight (ParameterControlHighlightInfo);
/** Called by certain plug-in wrappers to find out whether a component is used
to control a parameter.
If the given component represents a particular plugin parameter, then this
method should return the index of that parameter. If not, it should return -1.
Currently only AAX plugins will call this, and implementing it is optional.
*/
virtual int getControlParameterIndex (Component&);
private:
JUCE_DECLARE_NON_COPYABLE (AudioProcessorEditor)
};
#endif // JUCE_AUDIOPROCESSOREDITOR_H_INCLUDED
@@ -0,0 +1,413 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_AUDIOPROCESSORGRAPH_H_INCLUDED
#define JUCE_AUDIOPROCESSORGRAPH_H_INCLUDED
//==============================================================================
/**
A type of AudioProcessor which plays back a graph of other AudioProcessors.
Use one of these objects if you want to wire-up a set of AudioProcessors
and play back the result.
Processors can be added to the graph as "nodes" using addNode(), and once
added, you can connect any of their input or output channels to other
nodes using addConnection().
To play back a graph through an audio device, you might want to use an
AudioProcessorPlayer object.
*/
class JUCE_API AudioProcessorGraph : public AudioProcessor,
private AsyncUpdater
{
public:
//==============================================================================
/** Creates an empty graph. */
AudioProcessorGraph();
/** Destructor.
Any processor objects that have been added to the graph will also be deleted.
*/
~AudioProcessorGraph();
//==============================================================================
/** Represents one of the nodes, or processors, in an AudioProcessorGraph.
To create a node, call AudioProcessorGraph::addNode().
*/
class JUCE_API Node : public ReferenceCountedObject
{
public:
//==============================================================================
/** The ID number assigned to this node.
This is assigned by the graph that owns it, and can't be changed.
*/
const uint32 nodeId;
/** The actual processor object that this node represents. */
AudioProcessor* getProcessor() const noexcept { return processor; }
/** A set of user-definable properties that are associated with this node.
This can be used to attach values to the node for whatever purpose seems
useful. For example, you might store an x and y position if your application
is displaying the nodes on-screen.
*/
NamedValueSet properties;
//==============================================================================
/** A convenient typedef for referring to a pointer to a node object. */
typedef ReferenceCountedObjectPtr <Node> Ptr;
private:
//==============================================================================
friend class AudioProcessorGraph;
const ScopedPointer<AudioProcessor> processor;
bool isPrepared;
Node (uint32 nodeId, AudioProcessor*) noexcept;
void setParentGraph (AudioProcessorGraph*) const;
void prepare (double sampleRate, int blockSize, AudioProcessorGraph*);
void unprepare();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Node)
};
//==============================================================================
/** Represents a connection between two channels of two nodes in an AudioProcessorGraph.
To create a connection, use AudioProcessorGraph::addConnection().
*/
struct JUCE_API Connection
{
public:
//==============================================================================
Connection (uint32 sourceNodeId, int sourceChannelIndex,
uint32 destNodeId, int destChannelIndex) noexcept;
//==============================================================================
/** The ID number of the node which is the input source for this connection.
@see AudioProcessorGraph::getNodeForId
*/
uint32 sourceNodeId;
/** The index of the output channel of the source node from which this
connection takes its data.
If this value is the special number AudioProcessorGraph::midiChannelIndex, then
it is referring to the source node's midi output. Otherwise, it is the zero-based
index of an audio output channel in the source node.
*/
int sourceChannelIndex;
/** The ID number of the node which is the destination for this connection.
@see AudioProcessorGraph::getNodeForId
*/
uint32 destNodeId;
/** The index of the input channel of the destination node to which this
connection delivers its data.
If this value is the special number AudioProcessorGraph::midiChannelIndex, then
it is referring to the destination node's midi input. Otherwise, it is the zero-based
index of an audio input channel in the destination node.
*/
int destChannelIndex;
private:
//==============================================================================
JUCE_LEAK_DETECTOR (Connection)
};
//==============================================================================
/** Deletes all nodes and connections from this graph.
Any processor objects in the graph will be deleted.
*/
void clear();
/** Returns the number of nodes in the graph. */
int getNumNodes() const { return nodes.size(); }
/** Returns a pointer to one of the nodes in the graph.
This will return nullptr if the index is out of range.
@see getNodeForId
*/
Node* getNode (const int index) const { return nodes [index]; }
/** Searches the graph for a node with the given ID number and returns it.
If no such node was found, this returns nullptr.
@see getNode
*/
Node* getNodeForId (const uint32 nodeId) const;
/** Adds a node to the graph.
This creates a new node in the graph, for the specified processor. Once you have
added a processor to the graph, the graph owns it and will delete it later when
it is no longer needed.
The optional nodeId parameter lets you specify an ID to use for the node, but
if the value is already in use, this new node will overwrite the old one.
If this succeeds, it returns a pointer to the newly-created node.
*/
Node* addNode (AudioProcessor* newProcessor, uint32 nodeId = 0);
/** Deletes a node within the graph which has the specified ID.
This will also delete any connections that are attached to this node.
*/
bool removeNode (uint32 nodeId);
//==============================================================================
/** Returns the number of connections in the graph. */
int getNumConnections() const { return connections.size(); }
/** Returns a pointer to one of the connections in the graph. */
const Connection* getConnection (int index) const { return connections [index]; }
/** Searches for a connection between some specified channels.
If no such connection is found, this returns nullptr.
*/
const Connection* getConnectionBetween (uint32 sourceNodeId,
int sourceChannelIndex,
uint32 destNodeId,
int destChannelIndex) const;
/** Returns true if there is a connection between any of the channels of
two specified nodes.
*/
bool isConnected (uint32 possibleSourceNodeId,
uint32 possibleDestNodeId) const;
/** Returns true if it would be legal to connect the specified points. */
bool canConnect (uint32 sourceNodeId, int sourceChannelIndex,
uint32 destNodeId, int destChannelIndex) const;
/** Attempts to connect two specified channels of two nodes.
If this isn't allowed (e.g. because you're trying to connect a midi channel
to an audio one or other such nonsense), then it'll return false.
*/
bool addConnection (uint32 sourceNodeId, int sourceChannelIndex,
uint32 destNodeId, int destChannelIndex);
/** Deletes the connection with the specified index. */
void removeConnection (int index);
/** Deletes any connection between two specified points.
Returns true if a connection was actually deleted.
*/
bool removeConnection (uint32 sourceNodeId, int sourceChannelIndex,
uint32 destNodeId, int destChannelIndex);
/** Removes all connections from the specified node. */
bool disconnectNode (uint32 nodeId);
/** Returns true if the given connection's channel numbers map on to valid
channels at each end.
Even if a connection is valid when created, its status could change if
a node changes its channel config.
*/
bool isConnectionLegal (const Connection* connection) const;
/** Performs a sanity checks of all the connections.
This might be useful if some of the processors are doing things like changing
their channel counts, which could render some connections obsolete.
*/
bool removeIllegalConnections();
//==============================================================================
/** A special number that represents the midi channel of a node.
This is used as a channel index value if you want to refer to the midi input
or output instead of an audio channel.
*/
static const int midiChannelIndex;
//==============================================================================
/** A special type of AudioProcessor that can live inside an AudioProcessorGraph
in order to use the audio that comes into and out of the graph itself.
If you create an AudioGraphIOProcessor in "input" mode, it will act as a
node in the graph which delivers the audio that is coming into the parent
graph. This allows you to stream the data to other nodes and process the
incoming audio.
Likewise, one of these in "output" mode can be sent data which it will add to
the sum of data being sent to the graph's output.
@see AudioProcessorGraph
*/
class JUCE_API AudioGraphIOProcessor : public AudioPluginInstance
{
public:
/** Specifies the mode in which this processor will operate.
*/
enum IODeviceType
{
audioInputNode, /**< In this mode, the processor has output channels
representing all the audio input channels that are
coming into its parent audio graph. */
audioOutputNode, /**< In this mode, the processor has input channels
representing all the audio output channels that are
going out of its parent audio graph. */
midiInputNode, /**< In this mode, the processor has a midi output which
delivers the same midi data that is arriving at its
parent graph. */
midiOutputNode /**< In this mode, the processor has a midi input and
any data sent to it will be passed out of the parent
graph. */
};
//==============================================================================
/** Returns the mode of this processor. */
IODeviceType getType() const { return type; }
/** Returns the parent graph to which this processor belongs, or nullptr if it
hasn't yet been added to one. */
AudioProcessorGraph* getParentGraph() const { return graph; }
/** True if this is an audio or midi input. */
bool isInput() const;
/** True if this is an audio or midi output. */
bool isOutput() const;
//==============================================================================
AudioGraphIOProcessor (const IODeviceType type);
~AudioGraphIOProcessor();
const String getName() const;
void fillInPluginDescription (PluginDescription&) const;
void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock);
void releaseResources();
void processBlock (AudioSampleBuffer&, MidiBuffer&);
const String getInputChannelName (int channelIndex) const;
const String getOutputChannelName (int channelIndex) const;
bool isInputChannelStereoPair (int index) const;
bool isOutputChannelStereoPair (int index) const;
bool silenceInProducesSilenceOut() const;
double getTailLengthSeconds() const;
bool acceptsMidi() const;
bool producesMidi() const;
bool hasEditor() const;
AudioProcessorEditor* createEditor();
int getNumParameters();
const String getParameterName (int);
float getParameter (int);
const String getParameterText (int);
void setParameter (int, float);
int getNumPrograms();
int getCurrentProgram();
void setCurrentProgram (int);
const String getProgramName (int);
void changeProgramName (int, const String&);
void getStateInformation (juce::MemoryBlock& destData);
void setStateInformation (const void* data, int sizeInBytes);
/** @internal */
void setParentGraph (AudioProcessorGraph*);
private:
const IODeviceType type;
AudioProcessorGraph* graph;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioGraphIOProcessor)
};
//==============================================================================
// AudioProcessor methods:
const String getName() const;
void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock);
void releaseResources();
void processBlock (AudioSampleBuffer&, MidiBuffer&);
void reset();
const String getInputChannelName (int channelIndex) const;
const String getOutputChannelName (int channelIndex) const;
bool isInputChannelStereoPair (int index) const;
bool isOutputChannelStereoPair (int index) const;
bool silenceInProducesSilenceOut() const;
double getTailLengthSeconds() const;
bool acceptsMidi() const;
bool producesMidi() const;
bool hasEditor() const { return false; }
AudioProcessorEditor* createEditor() { return nullptr; }
int getNumParameters() { return 0; }
const String getParameterName (int) { return String(); }
float getParameter (int) { return 0; }
const String getParameterText (int) { return String(); }
void setParameter (int, float) { }
int getNumPrograms() { return 0; }
int getCurrentProgram() { return 0; }
void setCurrentProgram (int) { }
const String getProgramName (int) { return String(); }
void changeProgramName (int, const String&) { }
void getStateInformation (juce::MemoryBlock&);
void setStateInformation (const void* data, int sizeInBytes);
private:
//==============================================================================
ReferenceCountedArray<Node> nodes;
OwnedArray<Connection> connections;
uint32 lastNodeId;
AudioSampleBuffer renderingBuffers;
OwnedArray<MidiBuffer> midiBuffers;
Array<void*> renderingOps;
friend class AudioGraphIOProcessor;
AudioSampleBuffer* currentAudioInputBuffer;
AudioSampleBuffer currentAudioOutputBuffer;
MidiBuffer* currentMidiInputBuffer;
MidiBuffer currentMidiOutputBuffer;
void handleAsyncUpdate() override;
void clearRenderingSequence();
void buildRenderingSequence();
bool isAnInputTo (uint32 possibleInputId, uint32 possibleDestinationId, int recursionCheck) const;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorGraph)
};
#endif // JUCE_AUDIOPROCESSORGRAPH_H_INCLUDED
@@ -0,0 +1,106 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_AUDIOPROCESSORLISTENER_H_INCLUDED
#define JUCE_AUDIOPROCESSORLISTENER_H_INCLUDED
//==============================================================================
/**
Base class for listeners that want to know about changes to an AudioProcessor.
Use AudioProcessor::addListener() to register your listener with an AudioProcessor.
@see AudioProcessor
*/
class JUCE_API AudioProcessorListener
{
public:
//==============================================================================
/** Destructor. */
virtual ~AudioProcessorListener() {}
//==============================================================================
/** Receives a callback when a parameter is 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 audioProcessorParameterChanged (AudioProcessor* processor,
int parameterIndex,
float newValue) = 0;
/** Called to indicate that something else in the plugin has changed, like its
program, number of parameters, etc.
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 audioProcessorChanged (AudioProcessor* processor) = 0;
/** Indicates that a parameter change gesture has started.
E.g. if the user is dragging a slider, this would be called when they first
press the mouse button, and audioProcessorParameterChangeGestureEnd would be
called 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.
@see audioProcessorParameterChangeGestureEnd
*/
virtual void audioProcessorParameterChangeGestureBegin (AudioProcessor* processor,
int parameterIndex);
/** Indicates that a parameter change gesture has finished.
E.g. if the user is dragging a slider, this would be called when they release
the mouse button.
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.
@see audioProcessorParameterChangeGestureBegin
*/
virtual void audioProcessorParameterChangeGestureEnd (AudioProcessor* processor,
int parameterIndex);
};
#endif // JUCE_AUDIOPROCESSORLISTENER_H_INCLUDED
@@ -0,0 +1,158 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_AUDIOPROCESSORPARAMETER_H_INCLUDED
#define JUCE_AUDIOPROCESSORPARAMETER_H_INCLUDED
//==============================================================================
/** An abstract base class for parameter objects that can be added to an
AudioProcessor.
@see AudioProcessor::addParameter
*/
class JUCE_API AudioProcessorParameter
{
public:
AudioProcessorParameter() noexcept;
/** Destructor. */
virtual ~AudioProcessorParameter();
/** Called by the host to find out the value of this parameter.
Hosts will expect the value returned to be between 0 and 1.0.
This could be called quite frequently, so try to make your code efficient.
It's also likely to be called by non-UI threads, so the code in here should
be thread-aware.
*/
virtual float getValue() const = 0;
/** The host will call this method to change the value of one of the filter's parameters.
The host may call this at any time, including during the audio processing
callback, so the filter has to process this very fast and avoid blocking.
If you want to set the value of a parameter internally, e.g. from your
editor component, then don't call this directly - instead, use the
setValueNotifyingHost() method, which will also send a message to
the host telling it about the change. If the message isn't sent, the host
won't be able to automate your parameters properly.
The value passed will be between 0 and 1.0.
*/
virtual void setValue (float newValue) = 0;
/** Your filter can call this when it needs to change one of its parameters.
This could happen when the editor or some other internal operation changes
a parameter. This method will call the setParameter() method to change the
value, and will then send a message to the host telling it about the change.
Note that to make sure the host correctly handles automation, you should call
the beginChangeGesture() and endChangeGesture() methods to tell the host when
the user has started and stopped changing the parameter.
*/
void setValueNotifyingHost (float newValue);
/** Sends a signal to the host to tell it that the user is about to start changing this
parameter.
This allows the host to know when a parameter is actively being held by the user, and
it may use this information to help it record automation.
If you call this, it must be matched by a later call to endChangeGesture().
*/
void beginChangeGesture();
/** Tells the host that the user has finished changing this parameter.
This allows the host to know when a parameter is actively being held by the user,
and it may use this information to help it record automation.
A call to this method must follow a call to beginChangeGesture().
*/
void endChangeGesture();
/** This should return the default value for this parameter. */
virtual float getDefaultValue() const = 0;
/** Returns the name to display for this parameter, which should be made
to fit within the given string length.
*/
virtual String getName (int maximumStringLength) const = 0;
/** Some parameters may be able to return a label string for
their units. For example "Hz" or "%".
*/
virtual String getLabel() const = 0;
/** Returns the number of discrete interval steps that this parameter's range
should be quantised into.
If you want a continuous range of values, don't override this method, and allow
the default implementation to return AudioProcessor::getDefaultNumParameterSteps().
If your parameter is boolean, then you may want to make this return 2.
The value that is returned may or may not be used, depending on the host.
*/
virtual int getNumSteps() const;
/** Returns a textual version of the supplied parameter value.
The default implementation just returns the floating point value
as a string, but this could do anything you need for a custom type
of value.
*/
virtual String getText (float value, int /*maximumStringLength*/) const;
/** Should parse a string and return the appropriate value for it. */
virtual float getValueForText (const String& text) const = 0;
/** This can be overridden to tell the host that this parameter operates in the
reverse direction.
(Not all plugin formats or hosts will actually use this information).
*/
virtual bool isOrientationInverted() const;
/** Returns true if the host can automate this parameter.
By default, this returns true.
*/
virtual bool isAutomatable() const;
/** Should return true if this parameter is a "meta" parameter.
A meta-parameter is a parameter that changes other params. It is used
by some hosts (e.g. AudioUnit hosts).
By default this returns false.
*/
virtual bool isMetaParameter() const;
/** Returns the index of this parameter in its parent processor's parameter list. */
int getParameterIndex() const noexcept { return parameterIndex; }
private:
friend class AudioProcessor;
AudioProcessor* processor;
int parameterIndex;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorParameter)
};
#endif // JUCE_AUDIOPROCESSORPARAMETER_H_INCLUDED
@@ -0,0 +1,172 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
class ProcessorParameterPropertyComp : public PropertyComponent,
private AudioProcessorListener,
private Timer
{
public:
ProcessorParameterPropertyComp (const String& name, AudioProcessor& p, int paramIndex)
: PropertyComponent (name),
owner (p),
index (paramIndex),
paramHasChanged (false),
slider (p, paramIndex)
{
startTimer (100);
addAndMakeVisible (slider);
owner.addListener (this);
}
~ProcessorParameterPropertyComp()
{
owner.removeListener (this);
}
void refresh() override
{
paramHasChanged = false;
if (slider.getThumbBeingDragged() < 0)
slider.setValue (owner.getParameter (index), dontSendNotification);
slider.updateText();
}
void audioProcessorChanged (AudioProcessor*) override {}
void audioProcessorParameterChanged (AudioProcessor*, int parameterIndex, float) override
{
if (parameterIndex == index)
paramHasChanged = true;
}
void timerCallback() override
{
if (paramHasChanged)
{
refresh();
startTimerHz (50);
}
else
{
startTimer (jmin (1000 / 4, getTimerInterval() + 10));
}
}
private:
//==============================================================================
class ParamSlider : public Slider
{
public:
ParamSlider (AudioProcessor& p, int paramIndex) : owner (p), index (paramIndex)
{
const int steps = owner.getParameterNumSteps (index);
if (steps > 1 && steps < 0x7fffffff)
setRange (0.0, 1.0, 1.0 / (steps - 1.0));
else
setRange (0.0, 1.0);
setSliderStyle (Slider::LinearBar);
setTextBoxIsEditable (false);
setScrollWheelEnabled (true);
}
void valueChanged() override
{
const float newVal = (float) getValue();
if (owner.getParameter (index) != newVal)
{
owner.setParameterNotifyingHost (index, newVal);
updateText();
}
}
String getTextFromValue (double /*value*/) override
{
return owner.getParameterText (index) + " " + owner.getParameterLabel (index).trimEnd();
}
private:
//==============================================================================
AudioProcessor& owner;
const int index;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParamSlider)
};
AudioProcessor& owner;
const int index;
bool volatile paramHasChanged;
ParamSlider slider;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProcessorParameterPropertyComp)
};
//==============================================================================
GenericAudioProcessorEditor::GenericAudioProcessorEditor (AudioProcessor* const p)
: AudioProcessorEditor (p)
{
jassert (p != nullptr);
setOpaque (true);
addAndMakeVisible (panel);
Array <PropertyComponent*> params;
const int numParams = p->getNumParameters();
int totalHeight = 0;
for (int i = 0; i < numParams; ++i)
{
String name (p->getParameterName (i));
if (name.trim().isEmpty())
name = "Unnamed";
ProcessorParameterPropertyComp* const pc = new ProcessorParameterPropertyComp (name, *p, i);
params.add (pc);
totalHeight += pc->getPreferredHeight();
}
panel.addProperties (params);
setSize (400, jlimit (25, 400, totalHeight));
}
GenericAudioProcessorEditor::~GenericAudioProcessorEditor()
{
}
void GenericAudioProcessorEditor::paint (Graphics& g)
{
g.fillAll (Colours::white);
}
void GenericAudioProcessorEditor::resized()
{
panel.setBounds (getLocalBounds());
}
@@ -0,0 +1,58 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_GENERICAUDIOPROCESSOREDITOR_H_INCLUDED
#define JUCE_GENERICAUDIOPROCESSOREDITOR_H_INCLUDED
//==============================================================================
/**
A type of UI component that displays the parameters of an AudioProcessor as
a simple list of sliders.
This can be used for showing an editor for a processor that doesn't supply
its own custom editor.
@see AudioProcessor
*/
class JUCE_API GenericAudioProcessorEditor : public AudioProcessorEditor
{
public:
//==============================================================================
GenericAudioProcessorEditor (AudioProcessor* owner);
~GenericAudioProcessorEditor();
//==============================================================================
void paint (Graphics&) override;
void resized() override;
private:
//==============================================================================
PropertyPanel panel;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GenericAudioProcessorEditor)
};
#endif // JUCE_GENERICAUDIOPROCESSOREDITOR_H_INCLUDED
@@ -0,0 +1,140 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
PluginDescription::PluginDescription()
: uid (0),
isInstrument (false),
numInputChannels (0),
numOutputChannels (0),
hasSharedContainer (false)
{
}
PluginDescription::~PluginDescription()
{
}
PluginDescription::PluginDescription (const PluginDescription& other)
: name (other.name),
descriptiveName (other.descriptiveName),
pluginFormatName (other.pluginFormatName),
category (other.category),
manufacturerName (other.manufacturerName),
version (other.version),
fileOrIdentifier (other.fileOrIdentifier),
lastFileModTime (other.lastFileModTime),
uid (other.uid),
isInstrument (other.isInstrument),
numInputChannels (other.numInputChannels),
numOutputChannels (other.numOutputChannels),
hasSharedContainer (other.hasSharedContainer)
{
}
PluginDescription& PluginDescription::operator= (const PluginDescription& other)
{
name = other.name;
descriptiveName = other.descriptiveName;
pluginFormatName = other.pluginFormatName;
category = other.category;
manufacturerName = other.manufacturerName;
version = other.version;
fileOrIdentifier = other.fileOrIdentifier;
uid = other.uid;
isInstrument = other.isInstrument;
lastFileModTime = other.lastFileModTime;
numInputChannels = other.numInputChannels;
numOutputChannels = other.numOutputChannels;
hasSharedContainer = other.hasSharedContainer;
return *this;
}
bool PluginDescription::isDuplicateOf (const PluginDescription& other) const noexcept
{
return fileOrIdentifier == other.fileOrIdentifier
&& uid == other.uid;
}
static String getPluginDescSuffix (const PluginDescription& d)
{
return "-" + String::toHexString (d.fileOrIdentifier.hashCode())
+ "-" + String::toHexString (d.uid);
}
bool PluginDescription::matchesIdentifierString (const String& identifierString) const
{
return identifierString.endsWithIgnoreCase (getPluginDescSuffix (*this));
}
String PluginDescription::createIdentifierString() const
{
return pluginFormatName + "-" + name + getPluginDescSuffix (*this);
}
XmlElement* PluginDescription::createXml() const
{
XmlElement* const e = new XmlElement ("PLUGIN");
e->setAttribute ("name", name);
if (descriptiveName != name)
e->setAttribute ("descriptiveName", descriptiveName);
e->setAttribute ("format", pluginFormatName);
e->setAttribute ("category", category);
e->setAttribute ("manufacturer", manufacturerName);
e->setAttribute ("version", version);
e->setAttribute ("file", fileOrIdentifier);
e->setAttribute ("uid", String::toHexString (uid));
e->setAttribute ("isInstrument", isInstrument);
e->setAttribute ("fileTime", String::toHexString (lastFileModTime.toMilliseconds()));
e->setAttribute ("numInputs", numInputChannels);
e->setAttribute ("numOutputs", numOutputChannels);
e->setAttribute ("isShell", hasSharedContainer);
return e;
}
bool PluginDescription::loadFromXml (const XmlElement& xml)
{
if (xml.hasTagName ("PLUGIN"))
{
name = xml.getStringAttribute ("name");
descriptiveName = xml.getStringAttribute ("descriptiveName", name);
pluginFormatName = xml.getStringAttribute ("format");
category = xml.getStringAttribute ("category");
manufacturerName = xml.getStringAttribute ("manufacturer");
version = xml.getStringAttribute ("version");
fileOrIdentifier = xml.getStringAttribute ("file");
uid = xml.getStringAttribute ("uid").getHexValue32();
isInstrument = xml.getBoolAttribute ("isInstrument", false);
lastFileModTime = Time (xml.getStringAttribute ("fileTime").getHexValue64());
numInputChannels = xml.getIntAttribute ("numInputs");
numOutputChannels = xml.getIntAttribute ("numOutputs");
hasSharedContainer = xml.getBoolAttribute ("isShell", false);
return true;
}
return false;
}
@@ -0,0 +1,151 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_PLUGINDESCRIPTION_H_INCLUDED
#define JUCE_PLUGINDESCRIPTION_H_INCLUDED
//==============================================================================
/**
A small class to represent some facts about a particular type of plug-in.
This class is for storing and managing the details about a plug-in without
actually having to load an instance of it.
A KnownPluginList contains a list of PluginDescription objects.
@see KnownPluginList
*/
class JUCE_API PluginDescription
{
public:
//==============================================================================
PluginDescription();
PluginDescription (const PluginDescription& other);
PluginDescription& operator= (const PluginDescription& other);
~PluginDescription();
//==============================================================================
/** The name of the plug-in. */
String name;
/** A more descriptive name for the plug-in.
This may be the same as the 'name' field, but some plug-ins may provide an
alternative name.
*/
String descriptiveName;
/** The plug-in format, e.g. "VST", "AudioUnit", etc. */
String pluginFormatName;
/** A category, such as "Dynamics", "Reverbs", etc. */
String category;
/** The manufacturer. */
String manufacturerName;
/** The version. This string doesn't have any particular format. */
String version;
/** Either the file containing the plug-in module, or some other unique way
of identifying it.
E.g. for an AU, this would be an ID string that the component manager
could use to retrieve the plug-in. For a VST, it's the file path.
*/
String fileOrIdentifier;
/** The last time the plug-in file was changed.
This is handy when scanning for new or changed plug-ins.
*/
Time lastFileModTime;
/** A unique ID for the plug-in.
Note that this might not be unique between formats, e.g. a VST and some
other format might actually have the same id.
@see createIdentifierString
*/
int uid;
/** True if the plug-in identifies itself as a synthesiser. */
bool isInstrument;
/** The number of inputs. */
int numInputChannels;
/** The number of outputs. */
int numOutputChannels;
/** True if the plug-in is part of a multi-type container, e.g. a VST Shell. */
bool hasSharedContainer;
/** Returns true if the two descriptions refer to the same plug-in.
This isn't quite as simple as them just having the same file (because of
shell plug-ins).
*/
bool isDuplicateOf (const PluginDescription& other) const noexcept;
/** Return true if this description is equivalent to another one which created the
given identifier string.
Note that this isn't quite as simple as them just calling createIdentifierString()
and comparing the strings, because the identifers can differ (thanks to shell plug-ins).
*/
bool matchesIdentifierString (const String& identifierString) const;
//==============================================================================
/** Returns a string that can be saved and used to uniquely identify the
plugin again.
This contains less info than the XML encoding, and is independent of the
plug-in's file location, so can be used to store a plug-in ID for use
across different machines.
*/
String createIdentifierString() const;
//==============================================================================
/** Creates an XML object containing these details.
@see loadFromXml
*/
XmlElement* createXml() const;
/** Reloads the info in this structure from an XML record that was previously
saved with createXML().
Returns true if the XML was a valid plug-in description.
*/
bool loadFromXml (const XmlElement& xml);
private:
//==============================================================================
JUCE_LEAK_DETECTOR (PluginDescription)
};
#endif // JUCE_PLUGINDESCRIPTION_H_INCLUDED