- Library code update

- project update (added Eigen)

git-svn-id: http://moon:8086/svn/software/trunk/projects/mpsk_rx_gui@94 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
2014-12-20 20:59:48 +00:00
parent 1b4d8e9f54
commit dc5560392f
312 changed files with 6349 additions and 4195 deletions
@@ -54,7 +54,7 @@ public:
(e.g. VST shells) can use a single DLL to create a set of different plugin
subtypes, so in that case, each subtype is returned as a separate object.
*/
virtual void findAllTypesForFile (OwnedArray <PluginDescription>& results,
virtual void findAllTypesForFile (OwnedArray<PluginDescription>& results,
const String& fileOrIdentifier) = 0;
/** Tries to recreate a type from a previously generated PluginDescription.
@@ -89,7 +89,7 @@ public:
private:
//==============================================================================
OwnedArray <AudioPluginFormat> formats;
OwnedArray<AudioPluginFormat> formats;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginFormatManager)
};
@@ -37,7 +37,7 @@ public:
//==============================================================================
String getName() const override { return "AudioUnit"; }
void findAllTypesForFile (OwnedArray <PluginDescription>&, const String& fileOrIdentifier) override;
void findAllTypesForFile (OwnedArray<PluginDescription>&, const String& fileOrIdentifier) override;
AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc, double, int) override;
bool fileMightContainThisPluginType (const String& fileOrIdentifier) override;
String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) override;
@@ -62,7 +62,7 @@ namespace AudioUnitFormatHelpers
static ThreadLocalValue<int> insideCallback;
#endif
String osTypeToString (OSType type)
String osTypeToString (OSType type) noexcept
{
const juce_wchar s[4] = { (juce_wchar) ((type >> 24) & 0xff),
(juce_wchar) ((type >> 16) & 0xff),
@@ -88,9 +88,6 @@ namespace AudioUnitFormatHelpers
String createPluginIdentifier (const AudioComponentDescription& desc)
{
jassert (osTypeToString ('abcd') == "abcd"); // agh, must have got the endianness wrong..
jassert (stringToOSType ("abcd") == (OSType) 'abcd'); // ditto
String s (auIdentifierPrefix);
if (desc.componentType == kAudioUnitType_MusicDevice)
@@ -138,7 +135,7 @@ namespace AudioUnitFormatHelpers
fileOrIdentifier.lastIndexOfChar ('/')) + 1));
StringArray tokens;
tokens.addTokens (s, ",", String());
tokens.addTokens (s, ",", StringRef());
tokens.removeEmptyStrings();
if (tokens.size() == 3)
@@ -215,9 +212,11 @@ namespace AudioUnitFormatHelpers
const short resFileId = CFBundleOpenBundleResourceMap (bundleRef);
UseResFile (resFileId);
for (ResourceIndex i = 1; i <= Count1Resources ('thng'); ++i)
const OSType thngType = stringToOSType ("thng");
for (ResourceIndex i = 1; i <= Count1Resources (thngType); ++i)
{
if (Handle h = Get1IndResource ('thng', i))
if (Handle h = Get1IndResource (thngType, i))
{
HLock (h);
const uint32* const types = (const uint32*) *h;
@@ -346,11 +345,21 @@ public:
refreshParameterList();
updateNumChannels();
producesMidiMessages = canProduceMidiOutput();
setPluginCallbacks();
setPlayConfigDetails (numInputBusChannels * numInputBusses,
numOutputBusChannels * numOutputBusses,
rate, blockSize);
setLatencySamples (0);
if (parameters.size() == 0)
{
// some plugins crash if initialiseAudioUnit() is called too soon (sigh..), so we'll
// only call it here if it seems like they it's one of the awkward plugins that can
// only create their parameters after it has been initialised.
initialiseAudioUnit();
refreshParameterList();
}
setPluginCallbacks();
}
//==============================================================================
@@ -915,7 +924,7 @@ private:
bool automatable;
};
OwnedArray <ParamInfo> parameters;
OwnedArray<ParamInfo> parameters;
MidiDataConcatenator midiConcatenator;
CriticalSection midiInLock;
@@ -972,16 +981,11 @@ private:
for (int i = 0; i < parameters.size(); ++i)
{
const ParamInfo& p = *parameters.getUnchecked(i);
AudioUnitParameter paramToAdd;
paramToAdd.mAudioUnit = audioUnit;
paramToAdd.mParameterID = p.paramID;
paramToAdd.mScope = kAudioUnitScope_Global;
paramToAdd.mElement = 0;
AudioUnitEvent event;
event.mArgument.mParameter = paramToAdd;
event.mArgument.mParameter.mAudioUnit = audioUnit;
event.mArgument.mParameter.mParameterID = parameters.getUnchecked(i)->paramID;
event.mArgument.mParameter.mScope = kAudioUnitScope_Global;
event.mArgument.mParameter.mElement = 0;
event.mEventType = kAudioUnitEvent_ParameterValueChange;
AUEventListenerAddEventType (eventListenerRef, nullptr, &event);
@@ -992,6 +996,16 @@ private:
event.mEventType = kAudioUnitEvent_EndParameterChangeGesture;
AUEventListenerAddEventType (eventListenerRef, nullptr, &event);
}
// Add a listener for program changes
AudioUnitEvent event;
event.mArgument.mProperty.mAudioUnit = audioUnit;
event.mArgument.mProperty.mPropertyID = kAudioUnitProperty_PresentPreset;
event.mArgument.mProperty.mScope = kAudioUnitScope_Global;
event.mArgument.mProperty.mElement = 0;
event.mEventType = kAudioUnitEvent_PropertyChange;
AUEventListenerAddEventType (eventListenerRef, nullptr, &event);
}
}
@@ -1022,6 +1036,7 @@ private:
break;
default:
sendAllParametersChangedEvents();
break;
}
}
@@ -1600,7 +1615,7 @@ AudioUnitPluginFormat::~AudioUnitPluginFormat()
{
}
void AudioUnitPluginFormat::findAllTypesForFile (OwnedArray <PluginDescription>& results,
void AudioUnitPluginFormat::findAllTypesForFile (OwnedArray<PluginDescription>& results,
const String& fileOrIdentifier)
{
if (! fileMightContainThisPluginType (fileOrIdentifier))
@@ -118,8 +118,8 @@ class LADSPAPluginInstance : public AudioPluginInstance
{
public:
LADSPAPluginInstance (const LADSPAModuleHandle::Ptr& m)
: plugin (nullptr), handle (nullptr), initialised (false),
tempBuffer (1, 1), module (m)
: module (m), plugin (nullptr), handle (nullptr),
initialised (false), tempBuffer (1, 1)
{
++insideLADSPACallback;
@@ -85,6 +85,18 @@ static Steinberg::Vst::TChar* toString (const juce::String& source) noexcept
//==============================================================================
static Steinberg::Vst::SpeakerArrangement getArrangementForBus (Steinberg::Vst::IAudioProcessor* processor,
bool isInput, int busIndex)
{
Steinberg::Vst::SpeakerArrangement arrangement = Steinberg::Vst::SpeakerArr::kEmpty;
if (processor != nullptr)
processor->getBusArrangement (isInput ? Steinberg::Vst::kInput : Steinberg::Vst::kOutput,
(Steinberg::int32) busIndex, arrangement);
return arrangement;
}
/** For the sake of simplicity, there can only be 1 arrangement type per channel count.
i.e.: 4 channels == k31Cine OR k40Cine
*/
@@ -126,9 +138,9 @@ class ComSmartPtr
{
public:
ComSmartPtr() noexcept : source (nullptr) {}
ComSmartPtr (ObjectType* object) noexcept : source (object) { if (source != nullptr) source->addRef(); }
ComSmartPtr (const ComSmartPtr& other) noexcept : source (other.source) { if (source != nullptr) source->addRef(); }
~ComSmartPtr() { if (source != nullptr) source->release(); }
ComSmartPtr (ObjectType* object, bool autoAddRef = true) noexcept : source (object) { if (source != nullptr && autoAddRef) source->addRef(); }
ComSmartPtr (const ComSmartPtr& other) noexcept : source (other.source) { if (source != nullptr) source->addRef(); }
~ComSmartPtr() { if (source != nullptr) source->release(); }
operator ObjectType*() const noexcept { return source; }
ObjectType* get() const noexcept { return source; }
@@ -341,7 +353,7 @@ namespace VST3BufferExchange
Bus& bus,
AudioSampleBuffer& buffer,
int numChannels, int channelStartOffset,
int sampleOffset = 0) noexcept
int sampleOffset = 0)
{
const int channelEnd = numChannels + channelStartOffset;
jassert (channelEnd >= 0 && channelEnd <= buffer.getNumChannels());
@@ -356,37 +368,52 @@ namespace VST3BufferExchange
vstBuffers.silenceFlags = 0;
}
static void mapArrangementToBusses (int& channelIndexOffset, int index,
Array<Steinberg::Vst::AudioBusBuffers>& result,
BusMap& busMapToUse, Steinberg::Vst::SpeakerArrangement arrangement,
AudioSampleBuffer& source)
{
const int numChansForBus = BigInteger ((juce::int64) arrangement).countNumberOfSetBits();
if (index >= result.size())
result.add (Steinberg::Vst::AudioBusBuffers());
if (index >= busMapToUse.size())
busMapToUse.add (Bus());
if (numChansForBus > 0)
{
associateBufferTo (result.getReference (index),
busMapToUse.getReference (index),
source, numChansForBus, channelIndexOffset);
}
channelIndexOffset += numChansForBus;
}
static void mapBufferToBusses (Array<Steinberg::Vst::AudioBusBuffers>& result, BusMap& busMapToUse,
const Array<Steinberg::Vst::SpeakerArrangement>& arrangements,
AudioSampleBuffer& source)
{
int channelIndexOffset = 0;
for (int i = 0; i < arrangements.size(); ++i)
mapArrangementToBusses (channelIndexOffset, i, result, busMapToUse,
arrangements.getUnchecked (i), source);
}
static void mapBufferToBusses (Array<Steinberg::Vst::AudioBusBuffers>& result,
Steinberg::Vst::IAudioProcessor& processor,
BusMap& busMapToUse,
bool isInput, int numBusses,
BusMap& busMapToUse, bool isInput, int numBusses,
AudioSampleBuffer& source)
{
int channelIndexOffset = 0;
for (int i = 0; i < numBusses; ++i)
{
Steinberg::Vst::SpeakerArrangement arrangement = 0;
processor.getBusArrangement (isInput ? Steinberg::Vst::kInput : Steinberg::Vst::kOutput,
(Steinberg::int32) i, arrangement);
const int numChansForBus = BigInteger ((juce::int64) arrangement).countNumberOfSetBits();
if (i >= result.size())
result.add (Steinberg::Vst::AudioBusBuffers());
if (i >= busMapToUse.size())
busMapToUse.add (Bus());
if (numChansForBus > 0)
{
associateBufferTo (result.getReference (i),
busMapToUse.getReference (i),
source, numChansForBus, channelIndexOffset);
}
channelIndexOffset += numChansForBus;
}
mapArrangementToBusses (channelIndexOffset, i,
result, busMapToUse,
getArrangementForBus (&processor, isInput, i),
source);
}
}
@@ -31,6 +31,7 @@
#define JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY 1
#endif
#include <map>
#include "juce_VST3Headers.h"
#undef JUCE_VST3HEADERS_INCLUDE_HEADERS_ONLY
@@ -111,6 +112,7 @@ static void createPluginDescription (PluginDescription& description,
description.lastFileModTime = pluginFile.getLastModificationTime();
description.manufacturerName = company;
description.name = name;
description.descriptiveName = name;
description.pluginFormatName = "VST3";
description.numInputChannels = numInputs;
description.numOutputChannels = numOutputs;
@@ -378,32 +380,65 @@ public:
FUnknown* getFUnknown() { return static_cast<Vst::IComponentHandler*> (this); }
static bool hasFlag (Steinberg::int32 source, Steinberg::int32 flag) noexcept
{
return (source & flag) == flag;
}
//==============================================================================
tresult PLUGIN_API beginEdit (Vst::ParamID) override
tresult PLUGIN_API beginEdit (Vst::ParamID paramID) override
{
// XXX todo..
return kResultFalse;
const int index = getIndexOfParamID (paramID);
if (index < 0)
return kResultFalse;
owner->beginParameterChangeGesture (index);
return kResultTrue;
}
tresult PLUGIN_API performEdit (Vst::ParamID id, Vst::ParamValue valueNormalized) override
tresult PLUGIN_API performEdit (Vst::ParamID paramID, Vst::ParamValue valueNormalized) override
{
if (owner != nullptr)
return owner->editController->setParamNormalized (id, valueNormalized);
const int index = getIndexOfParamID (paramID);
return kResultFalse;
if (index < 0)
return kResultFalse;
owner->sendParamChangeMessageToListeners (index, (float) valueNormalized);
return owner->editController->setParamNormalized (paramID, valueNormalized);
}
tresult PLUGIN_API endEdit (Vst::ParamID) override
tresult PLUGIN_API endEdit (Vst::ParamID paramID) override
{
// XXX todo..
return kResultFalse;
const int index = getIndexOfParamID (paramID);
if (index < 0)
return kResultFalse;
owner->endParameterChangeGesture (index);
return kResultTrue;
}
tresult PLUGIN_API restartComponent (Steinberg::int32) override
tresult PLUGIN_API restartComponent (Steinberg::int32 flags) override
{
if (owner != nullptr)
{
owner->reset();
if (hasFlag (flags, Vst::kReloadComponent))
owner->reset();
if (hasFlag (flags, Vst::kIoChanged))
{
const double sampleRate = owner->getSampleRate();
const int blockSize = owner->getBlockSize();
owner->prepareToPlay (sampleRate >= 8000 ? sampleRate : 44100.0,
blockSize > 0 ? blockSize : 1024);
}
if (hasFlag (flags, Vst::kLatencyChanged))
if (owner->processor != nullptr)
owner->setLatencySamples (jmax (0, (int) owner->processor->getLatencySamples()));
owner->updateHostDisplay();
return kResultTrue;
}
@@ -437,9 +472,171 @@ public:
return kResultFalse;
}
//==============================================================================
class ContextMenu : public Vst::IContextMenu
{
public:
ContextMenu (VST3PluginInstance& pluginInstance) : owner (pluginInstance) {}
virtual ~ContextMenu() {}
JUCE_DECLARE_VST3_COM_REF_METHODS
JUCE_DECLARE_VST3_COM_QUERY_METHODS
Steinberg::int32 PLUGIN_API getItemCount() override { return (Steinberg::int32) items.size(); }
tresult PLUGIN_API addItem (const Item& item, IContextMenuTarget* target) override
{
jassert (target != nullptr);
ItemAndTarget newItem;
newItem.item = item;
newItem.target = target;
items.add (newItem);
return kResultOk;
}
tresult PLUGIN_API removeItem (const Item& toRemove, IContextMenuTarget* target) override
{
for (int i = items.size(); --i >= 0;)
{
ItemAndTarget& item = items.getReference(i);
if (item.item.tag == toRemove.tag && item.target == target)
items.remove (i);
}
return kResultOk;
}
tresult PLUGIN_API getItem (Steinberg::int32 tag, Item& result, IContextMenuTarget** target) override
{
for (int i = 0; i < items.size(); ++i)
{
const ItemAndTarget& item = items.getReference(i);
if (item.item.tag == tag)
{
result = item.item;
if (target != nullptr)
*target = item.target;
return kResultTrue;
}
}
zerostruct (result);
return kResultFalse;
}
tresult PLUGIN_API popup (Steinberg::UCoord x, Steinberg::UCoord y) override
{
Array<const Item*> subItemStack;
OwnedArray<PopupMenu> menuStack;
PopupMenu* topLevelMenu = menuStack.add (new PopupMenu());
for (int i = 0; i < items.size(); ++i)
{
const Item& item = items.getReference (i).item;
PopupMenu* menuToUse = menuStack.getLast();
if (hasFlag (item.flags, Item::kIsGroupStart & ~Item::kIsDisabled))
{
subItemStack.add (&item);
menuStack.add (new PopupMenu());
}
else if (hasFlag (item.flags, Item::kIsGroupEnd))
{
if (const Item* subItem = subItemStack.getLast())
{
if (PopupMenu* m = menuStack [menuStack.size() - 2])
m->addSubMenu (toString (subItem->name), *menuToUse,
! hasFlag (subItem->flags, Item::kIsDisabled),
nullptr,
hasFlag (subItem->flags, Item::kIsChecked));
menuStack.removeLast (1);
subItemStack.removeLast (1);
}
}
else if (hasFlag (item.flags, Item::kIsSeparator))
{
menuToUse->addSeparator();
}
else
{
menuToUse->addItem (item.tag != 0 ? (int) item.tag : (int) zeroTagReplacement,
toString (item.name),
! hasFlag (item.flags, Item::kIsDisabled),
hasFlag (item.flags, Item::kIsChecked));
}
}
PopupMenu::Options options;
if (AudioProcessorEditor* ed = owner.getActiveEditor())
options = options.withTargetScreenArea (ed->getScreenBounds().translated ((int) x, (int) y).withSize (1, 1));
#if JUCE_MODAL_LOOPS_PERMITTED
// Unfortunately, Steinberg's docs explicitly say this should be modal..
handleResult (topLevelMenu->showMenu (options));
#else
topLevelMenu->showMenuAsync (options, ModalCallbackFunction::create (menuFinished, ComSmartPtr<ContextMenu> (this)));
#endif
return kResultOk;
}
#if ! JUCE_MODAL_LOOPS_PERMITTED
static void menuFinished (int modalResult, ComSmartPtr<ContextMenu> menu) { menu->handleResult (modalResult); }
#endif
private:
enum { zeroTagReplacement = 0x7fffffff };
Atomic<int> refCount;
VST3PluginInstance& owner;
struct ItemAndTarget
{
Item item;
ComSmartPtr<IContextMenuTarget> target;
};
Array<ItemAndTarget> items;
void handleResult (int result)
{
if (result == 0)
return;
if (result == zeroTagReplacement)
result = 0;
for (int i = 0; i < items.size(); ++i)
{
const ItemAndTarget& item = items.getReference(i);
if ((int) item.item.tag == result)
{
if (item.target != nullptr)
item.target->executeMenuItem ((Steinberg::int32) result);
break;
}
}
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ContextMenu)
};
Vst::IContextMenu* PLUGIN_API createContextMenu (IPlugView*, const Vst::ParamID*) override
{
jassertfalse;
if (owner != nullptr)
return new ContextMenu (*owner);
return nullptr;
}
@@ -549,9 +746,42 @@ public:
private:
//==============================================================================
Atomic<int32> refCount;
VST3PluginInstance* const owner;
Atomic<int> refCount;
String appName;
VST3PluginInstance* owner;
typedef std::map<Vst::ParamID, int> ParamMapType;
ParamMapType paramToIndexMap;
int getIndexOfParamID (Vst::ParamID paramID)
{
if (owner == nullptr || owner->editController == nullptr)
return -1;
int result = getMappedParamID (paramID);
if (result < 0)
{
const int numParams = owner->editController->getParameterCount();
for (int i = 0; i < numParams; ++i)
{
Vst::ParameterInfo paramInfo;
owner->editController->getParameterInfo (i, paramInfo);
paramToIndexMap[paramInfo.id] = i;
}
result = getMappedParamID (paramID);
}
return result;
}
int getMappedParamID (Vst::ParamID paramID)
{
const ParamMapType::iterator it (paramToIndexMap.find (paramID));
return it != paramToIndexMap.end() ? it->second : -1;
}
//==============================================================================
class Message : public Vst::IMessage
@@ -577,9 +807,9 @@ private:
JUCE_DECLARE_VST3_COM_REF_METHODS
JUCE_DECLARE_VST3_COM_QUERY_METHODS
FIDString PLUGIN_API getMessageID() { return messageId.toRawUTF8(); }
void PLUGIN_API setMessageID (FIDString id) { messageId = toString (id); }
Vst::IAttributeList* PLUGIN_API getAttributes() { return attributeList; }
FIDString PLUGIN_API getMessageID() override { return messageId.toRawUTF8(); }
void PLUGIN_API setMessageID (FIDString id) override { messageId = toString (id); }
Vst::IAttributeList* PLUGIN_API getAttributes() override { return attributeList; }
var value;
@@ -587,7 +817,7 @@ private:
VST3HostContext& owner;
ComSmartPtr<Vst::IAttributeList> attributeList;
String messageId;
Atomic<int32> refCount;
Atomic<int> refCount;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Message)
};
@@ -715,7 +945,7 @@ private:
private:
VST3HostContext* owner;
Atomic<int32> refCount;
Atomic<int> refCount;
//==============================================================================
template<typename Type>
@@ -1195,7 +1425,8 @@ public:
VST3PluginWindow (AudioProcessor* owner, IPlugView* pluginView)
: AudioProcessorEditor (owner),
ComponentMovementWatcher (this),
view (pluginView),
refCount (1),
view (pluginView, false),
pluginHandle (nullptr),
recursiveResize (false)
{
@@ -1213,7 +1444,9 @@ public:
~VST3PluginWindow()
{
warnOnFailure (view->removed());
getAudioProcessor()->editorBeingDeleted (this);
warnOnFailure (view->setFrame (nullptr));
processor.editorBeingDeleted (this);
#if JUCE_MAC
dummyComponent.setView (nullptr);
@@ -1266,20 +1499,32 @@ public:
{
rect.right = (Steinberg::int32) getWidth();
rect.bottom = (Steinberg::int32) getHeight();
view->checkSizeConstraint (&rect);
setSize ((int) rect.getWidth(), (int) rect.getHeight());
#if JUCE_WINDOWS
SetWindowPos (pluginHandle, 0,
pos.x, pos.y, rect.getWidth(), rect.getHeight(),
isVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW);
#elif JUCE_MAC
dummyComponent.setBounds (getLocalBounds());
#endif
view->onSize (&rect);
}
else
{
warnOnFailure (view->getSize (&rect));
}
#if JUCE_WINDOWS
SetWindowPos (pluginHandle, 0,
pos.x, pos.y, rect.getWidth(), rect.getHeight(),
isVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW);
#elif JUCE_MAC
dummyComponent.setBounds (0, 0, (int) rect.getWidth(), (int) rect.getHeight());
#endif
#if JUCE_WINDOWS
SetWindowPos (pluginHandle, 0,
pos.x, pos.y, rect.getWidth(), rect.getHeight(),
isVisible() ? SWP_SHOWWINDOW : SWP_HIDEWINDOW);
#elif JUCE_MAC
dummyComponent.setBounds (0, 0, (int) rect.getWidth(), (int) rect.getHeight());
#endif
}
// Some plugins don't update their cursor correctly when mousing out the window
Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate();
@@ -1364,7 +1609,7 @@ private:
if (peer != nullptr)
pluginHandle = (HandleFormat) peer->getNativeHandle();
#elif JUCE_MAC
dummyComponent.setBounds (getBounds().withZeroOrigin());
dummyComponent.setBounds (getLocalBounds());
addAndMakeVisible (dummyComponent);
pluginHandle = (NSView*) dummyComponent.getView();
jassert (pluginHandle != nil);
@@ -1391,7 +1636,8 @@ public:
midiInputs (new MidiEventList()),
midiOutputs (new MidiEventList()),
isComponentInitialised (false),
isControllerInitialised (false)
isControllerInitialised (false),
isActive (false)
{
host = new VST3HostContext (this);
}
@@ -1413,7 +1659,6 @@ public:
if (isControllerInitialised) editController->terminate();
if (isComponentInitialised) component->terminate();
//Deletion order appears to matter:
componentConnection = nullptr;
editControllerConnection = nullptr;
unitData = nullptr;
@@ -1425,6 +1670,8 @@ public:
editController2 = nullptr;
editController = nullptr;
component = nullptr;
host = nullptr;
module = nullptr;
}
bool initialise()
@@ -1478,8 +1725,27 @@ public:
return module != nullptr ? module->name : String::empty;
}
void repopulateArrangements()
{
inputArrangements.clearQuick();
outputArrangements.clearQuick();
// NB: Some plugins need a valid arrangement despite specifying 0 for their I/O busses
for (int i = 0; i < jmax (1, numInputAudioBusses); ++i)
inputArrangements.add (getArrangementForBus (processor, true, i));
for (int i = 0; i < jmax (1, numOutputAudioBusses); ++i)
outputArrangements.add (getArrangementForBus (processor, false, i));
}
void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock) override
{
// Avoid redundantly calling things like setActive, which can be a heavy-duty call for some plugins:
if (isActive
&& getSampleRate() == sampleRate
&& getBlockSize() == estimatedSamplesPerBlock)
return;
using namespace Vst;
ProcessSetup setup;
@@ -1495,20 +1761,25 @@ public:
editController->setComponentHandler (host);
Array<SpeakerArrangement> inArrangements, outArrangements;
if (inputArrangements.size() <= 0 || outputArrangements.size() <= 0)
repopulateArrangements();
for (int i = 0; i < numInputAudioBusses; ++i)
inArrangements.add (getArrangementForNumChannels (jmax (0, (int) getBusInfo (true, true, i).channelCount)));
for (int i = 0; i < numOutputAudioBusses; ++i)
outArrangements.add (getArrangementForNumChannels (jmax (0, (int) getBusInfo (false, true, i).channelCount)));
warnOnFailure (processor->setBusArrangements (inArrangements.getRawDataPointer(), numInputAudioBusses,
outArrangements.getRawDataPointer(), numOutputAudioBusses));
warnOnFailure (processor->setBusArrangements (inputArrangements.getRawDataPointer(), numInputAudioBusses,
outputArrangements.getRawDataPointer(), numOutputAudioBusses));
// Update the num. busses in case the configuration has been modified by the plugin. (May affect number of channels!):
numInputAudioBusses = getNumSingleDirectionBussesFor (component, true, true);
numOutputAudioBusses = getNumSingleDirectionBussesFor (component, false, true);
const int newNumInputAudioBusses = getNumSingleDirectionBussesFor (component, true, true);
const int newNumOutputAudioBusses = getNumSingleDirectionBussesFor (component, false, true);
// Repopulate arrangements if the number of busses have changed:
if (numInputAudioBusses != newNumInputAudioBusses
|| numOutputAudioBusses != newNumOutputAudioBusses)
{
numInputAudioBusses = newNumInputAudioBusses;
numOutputAudioBusses = newNumOutputAudioBusses;
repopulateArrangements();
}
// Needed for having the same sample rate in processBlock(); some plugins need this!
setPlayConfigDetails (getNumSingleDirectionChannelsFor (component, true, true),
@@ -1517,21 +1788,30 @@ public:
setStateForAllBusses (true);
setLatencySamples (jmax (0, (int) processor->getLatencySamples()));
warnOnFailure (component->setActive (true));
warnOnFailure (processor->setProcessing (true));
isActive = true;
}
void releaseResources() override
{
if (! isActive)
return; // Avoids redundantly calling things like setActive
JUCE_TRY
{
isActive = false;
setStateForAllBusses (false);
if (processor != nullptr)
processor->setProcessing (false);
warnOnFailure (processor->setProcessing (false));
if (component != nullptr)
component->setActive (false);
warnOnFailure (component->setActive (false));
}
JUCE_CATCH_ALL_ASSERT
}
@@ -1540,7 +1820,8 @@ public:
{
using namespace Vst;
if (processor != nullptr
if (isActive
&& processor != nullptr
&& processor->canProcessSampleSize (kSample32) == kResultTrue)
{
const int numSamples = buffer.getNumSamples();
@@ -1612,15 +1893,22 @@ public:
//==============================================================================
bool silenceInProducesSilenceOut() const override
{
return processor == nullptr;
if (processor != nullptr)
return processor->getTailSamples() == Vst::kNoTail;
return true;
}
/** May return a negative value as a means of informing us that the plugin has "infinite tail," or 0 for "no tail." */
double getTailLengthSeconds() const override
{
if (processor != nullptr)
return (double) jmin ((int) jmax ((Steinberg::uint32) 0, processor->getTailSamples()), 0x7fffffff)
* getSampleRate();
{
const double sampleRate = getSampleRate();
if (sampleRate > 0.0)
return jlimit (0, 0x7fffffff, (int) processor->getTailSamples()) / sampleRate;
}
return 0.0;
}
@@ -1640,7 +1928,7 @@ public:
if (getActiveEditor() != nullptr)
return true;
ComSmartPtr<IPlugView> view (tryCreatingView());
ComSmartPtr<IPlugView> view (tryCreatingView(), false);
return view != nullptr;
}
@@ -1706,6 +1994,16 @@ public:
return toString (result);
}
//==============================================================================
void reset() override
{
if (component != nullptr)
{
component->setActive (false);
component->setActive (true);
}
}
//==============================================================================
void getStateInformation (MemoryBlock& destData) override
{
@@ -1785,6 +2083,7 @@ private:
as very poorly specified by the Steinberg SDK
*/
int numInputAudioBusses, numOutputAudioBusses;
Array<Vst::SpeakerArrangement> inputArrangements, outputArrangements; // Caching to improve performance and to avoid possible non-thread-safe calls to getBusArrangements().
VST3BufferExchange::BusMap inputBusMap, outputBusMap;
Array<Vst::AudioBusBuffers> inputBusses, outputBusses;
@@ -1813,7 +2112,11 @@ private:
MemoryBlock mem;
if (mem.fromBase64Encoding (state->getAllSubText()))
stream = new Steinberg::MemoryStream (mem.getData(), (TSize) mem.getSize());
{
stream = new Steinberg::MemoryStream();
stream->setSize ((TSize) mem.getSize());
mem.copyTo (stream->getData(), 0, mem.getSize());
}
}
return stream;
@@ -1829,21 +2132,21 @@ private:
JUCE_DECLARE_VST3_COM_REF_METHODS
JUCE_DECLARE_VST3_COM_QUERY_METHODS
Steinberg::int32 PLUGIN_API getParameterCount() { return 0; }
Steinberg::int32 PLUGIN_API getParameterCount() override { return 0; }
Vst::IParamValueQueue* PLUGIN_API getParameterData (Steinberg::int32)
Vst::IParamValueQueue* PLUGIN_API getParameterData (Steinberg::int32) override
{
return nullptr;
}
Vst::IParamValueQueue* PLUGIN_API addParameterData (const Vst::ParamID&, Steinberg::int32& index)
Vst::IParamValueQueue* PLUGIN_API addParameterData (const Vst::ParamID&, Steinberg::int32& index) override
{
index = 0;
return nullptr;
}
private:
Atomic<int32> refCount;
Atomic<int> refCount;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParameterChangeList)
};
@@ -1851,7 +2154,7 @@ private:
ComSmartPtr<ParameterChangeList> inputParameterChanges, outputParameterChanges;
ComSmartPtr<MidiEventList> midiInputs, midiOutputs;
Vst::ProcessContext timingInfo; //< Only use this in processBlock()!
bool isComponentInitialised, isControllerInitialised;
bool isComponentInitialised, isControllerInitialised, isActive;
//==============================================================================
bool fetchComponentAndController (IPluginFactory* factory, const Steinberg::int32 numClasses)
@@ -2031,11 +2334,11 @@ private:
Vst::BusInfo getBusInfo (bool forInput, bool forAudio, int index = 0) const
{
Vst::BusInfo busInfo;
busInfo.mediaType = forAudio ? Vst::kAudio : Vst::kEvent;
busInfo.direction = forInput ? Vst::kInput : Vst::kOutput;
component->getBusInfo (forAudio ? Vst::kAudio : Vst::kEvent,
forInput ? Vst::kInput : Vst::kOutput,
component->getBusInfo (busInfo.mediaType, busInfo.direction,
(Steinberg::int32) index, busInfo);
return busInfo;
}
@@ -2056,11 +2359,8 @@ private:
{
using namespace VST3BufferExchange;
mapBufferToBusses (inputBusses, *processor, inputBusMap,
true, numInputAudioBusses, buffer);
mapBufferToBusses (outputBusses, *processor, outputBusMap,
false, numOutputAudioBusses, buffer);
mapBufferToBusses (inputBusses, inputBusMap, inputArrangements, buffer);
mapBufferToBusses (outputBusses, outputBusMap, outputArrangements, buffer);
destination.inputs = inputBusses.getRawDataPointer();
destination.outputs = outputBusses.getRawDataPointer();
@@ -29,13 +29,6 @@
#include "../../juce_gui_extra/native/juce_mac_CarbonViewWrapperComponent.h"
#endif
#if JUCE_MAC
static bool makeFSRefFromPath (FSRef* destFSRef, const String& path)
{
return FSPathMakeRef (reinterpret_cast<const UInt8*> (path.toRawUTF8()), destFSRef, 0) == noErr;
}
#endif
//==============================================================================
#undef PRAGMA_ALIGN_SUPPORTED
#define VST_FORCE_DEPRECATED 0
@@ -84,74 +77,68 @@
#endif
//==============================================================================
const int fxbVersionNum = 1;
struct fxProgram
{
VstInt32 chunkMagic; // 'CcnK'
VstInt32 byteSize; // of this chunk, excl. magic + byteSize
VstInt32 fxMagic; // 'FxCk'
VstInt32 version;
VstInt32 fxID; // fx unique id
VstInt32 fxVersion;
VstInt32 numParams;
char prgName[28];
float params[1]; // variable no. of parameters
};
struct fxSet
{
VstInt32 chunkMagic; // 'CcnK'
VstInt32 byteSize; // of this chunk, excl. magic + byteSize
VstInt32 fxMagic; // 'FxBk'
VstInt32 version;
VstInt32 fxID; // fx unique id
VstInt32 fxVersion;
VstInt32 numPrograms;
char future[128];
fxProgram programs[1]; // variable no. of programs
};
struct fxChunkSet
{
VstInt32 chunkMagic; // 'CcnK'
VstInt32 byteSize; // of this chunk, excl. magic + byteSize
VstInt32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh'
VstInt32 version;
VstInt32 fxID; // fx unique id
VstInt32 fxVersion;
VstInt32 numPrograms;
char future[128];
VstInt32 chunkSize;
char chunk[8]; // variable
};
struct fxProgramSet
{
VstInt32 chunkMagic; // 'CcnK'
VstInt32 byteSize; // of this chunk, excl. magic + byteSize
VstInt32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh'
VstInt32 version;
VstInt32 fxID; // fx unique id
VstInt32 fxVersion;
VstInt32 numPrograms;
char name[28];
VstInt32 chunkSize;
char chunk[8]; // variable
};
namespace
{
VstInt32 vst_swap (const VstInt32 x) noexcept
{
#ifdef JUCE_LITTLE_ENDIAN
return (VstInt32) ByteOrder::swap ((uint32) x);
#else
return x;
#endif
}
const int fxbVersionNum = 1;
float vst_swapFloat (const float x) noexcept
struct fxProgram
{
VstInt32 chunkMagic; // 'CcnK'
VstInt32 byteSize; // of this chunk, excl. magic + byteSize
VstInt32 fxMagic; // 'FxCk'
VstInt32 version;
VstInt32 fxID; // fx unique id
VstInt32 fxVersion;
VstInt32 numParams;
char prgName[28];
float params[1]; // variable no. of parameters
};
struct fxSet
{
VstInt32 chunkMagic; // 'CcnK'
VstInt32 byteSize; // of this chunk, excl. magic + byteSize
VstInt32 fxMagic; // 'FxBk'
VstInt32 version;
VstInt32 fxID; // fx unique id
VstInt32 fxVersion;
VstInt32 numPrograms;
char future[128];
fxProgram programs[1]; // variable no. of programs
};
struct fxChunkSet
{
VstInt32 chunkMagic; // 'CcnK'
VstInt32 byteSize; // of this chunk, excl. magic + byteSize
VstInt32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh'
VstInt32 version;
VstInt32 fxID; // fx unique id
VstInt32 fxVersion;
VstInt32 numPrograms;
char future[128];
VstInt32 chunkSize;
char chunk[8]; // variable
};
struct fxProgramSet
{
VstInt32 chunkMagic; // 'CcnK'
VstInt32 byteSize; // of this chunk, excl. magic + byteSize
VstInt32 fxMagic; // 'FxCh', 'FPCh', or 'FBCh'
VstInt32 version;
VstInt32 fxID; // fx unique id
VstInt32 fxVersion;
VstInt32 numPrograms;
char name[28];
VstInt32 chunkSize;
char chunk[8]; // variable
};
static VstInt32 fxbName (const char* name) noexcept { return (VstInt32) ByteOrder::bigEndianInt (name); }
static VstInt32 fxbSwap (const VstInt32 x) noexcept { return (VstInt32) ByteOrder::swapIfLittleEndian ((uint32) x); }
static float fxbSwapFloat (const float x) noexcept
{
#ifdef JUCE_LITTLE_ENDIAN
union { uint32 asInt; float asFloat; } n;
@@ -162,8 +149,12 @@ namespace
return x;
#endif
}
}
double getVSTHostTimeNanoseconds()
//==============================================================================
namespace
{
static double getVSTHostTimeNanoseconds() noexcept
{
#if JUCE_WINDOWS
return timeGetTime() * 1000000.0;
@@ -177,40 +168,52 @@ namespace
return micro.lo * 1000.0;
#endif
}
static int shellUIDToCreate = 0;
static int insideVSTCallback = 0;
struct IdleCallRecursionPreventer
{
IdleCallRecursionPreventer() : isMessageThread (MessageManager::getInstance()->isThisTheMessageThread())
{
if (isMessageThread)
++insideVSTCallback;
}
~IdleCallRecursionPreventer()
{
if (isMessageThread)
--insideVSTCallback;
}
const bool isMessageThread;
JUCE_DECLARE_NON_COPYABLE (IdleCallRecursionPreventer)
};
#if JUCE_MAC
static bool makeFSRefFromPath (FSRef* destFSRef, const String& path)
{
return FSPathMakeRef (reinterpret_cast<const UInt8*> (path.toRawUTF8()), destFSRef, 0) == noErr;
}
#endif
#if JUCE_MAC && JUCE_PPC
static void* newCFMFromMachO (void* const machofp) noexcept
{
void* result = (void*) new char[8];
((void**) result)[0] = machofp;
((void**) result)[1] = result;
return result;
}
#endif
}
//==============================================================================
typedef AEffect* (VSTCALLBACK *MainCall) (audioMasterCallback);
static VstIntPtr VSTCALLBACK audioMaster (AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt);
static int shellUIDToCreate = 0;
static int insideVSTCallback = 0;
class IdleCallRecursionPreventer
{
public:
IdleCallRecursionPreventer()
: isMessageThread (MessageManager::getInstance()->isThisTheMessageThread())
{
if (isMessageThread)
++insideVSTCallback;
}
~IdleCallRecursionPreventer()
{
if (isMessageThread)
--insideVSTCallback;
}
private:
const bool isMessageThread;
JUCE_DECLARE_NON_COPYABLE (IdleCallRecursionPreventer)
};
class VSTPluginWindow;
//==============================================================================
// Change this to disable logging of various VST activities
#ifndef VST_LOGGING
@@ -223,27 +226,12 @@ class VSTPluginWindow;
#define JUCE_VST_LOG(a)
#endif
//==============================================================================
#if JUCE_MAC && JUCE_PPC
static void* NewCFMFromMachO (void* const machofp) noexcept
{
void* result = (void*) new char[8];
((void**) result)[0] = machofp;
((void**) result)[1] = result;
return result;
}
#endif
//==============================================================================
#if JUCE_LINUX
extern Display* display;
extern XContext windowHandleXContext;
typedef void (*EventProcPtr) (XEvent* ev);
namespace
{
static bool xErrorTriggered = false;
@@ -254,6 +242,8 @@ namespace
return 0;
}
typedef void (*EventProcPtr) (XEvent* ev);
static EventProcPtr getPropertyFromXWindow (Window handle, Atom atom)
{
XErrorHandler oldErrorHandler = XSetErrorHandler (temporaryErrorHandler);
@@ -269,8 +259,7 @@ namespace
XSetErrorHandler (oldErrorHandler);
return (userCount == 1 && ! xErrorTriggered) ? *reinterpret_cast<EventProcPtr*> (data)
: 0;
return (userCount == 1 && ! xErrorTriggered) ? *reinterpret_cast<EventProcPtr*> (data) : nullptr;
}
Window getChildWindow (Window windowToCheck)
@@ -279,12 +268,7 @@ namespace
Window* childWindows;
unsigned int numChildren = 0;
XQueryTree (display,
windowToCheck,
&rootWindow,
&parentWindow,
&childWindows,
&numChildren);
XQueryTree (display, windowToCheck, &rootWindow, &parentWindow, &childWindows, &numChildren);
if (numChildren > 0)
return childWindows [0];
@@ -354,9 +338,9 @@ public:
typedef ReferenceCountedObjectPtr<ModuleHandle> Ptr;
static Array <ModuleHandle*>& getActiveModules()
static Array<ModuleHandle*>& getActiveModules()
{
static Array <ModuleHandle*> activeModules;
static Array<ModuleHandle*> activeModules;
return activeModules;
}
@@ -470,7 +454,7 @@ public:
{
if (HGLOBAL hGlob = LoadResource (dllModule, res))
{
const char* data = static_cast <const char*> (LockResource (hGlob));
const char* data = static_cast<const char*> (LockResource (hGlob));
return String::fromUTF8 (data, SizeofResource (dllModule, res));
}
}
@@ -552,7 +536,7 @@ public:
}
}
}
#if JUCE_PPC
#if JUCE_PPC
else
{
FSRef fn;
@@ -605,7 +589,7 @@ public:
}
}
}
#endif
#endif
return ok;
}
@@ -683,7 +667,7 @@ public:
static void disposeMachOFromCFM (void* ptr)
{
delete[] static_cast <UInt32*> (ptr);
delete[] static_cast<UInt32*> (ptr);
}
void coerceAEffectFunctionCalls (AEffect* eff)
@@ -715,11 +699,11 @@ class VSTPluginInstance : public AudioPluginInstance,
private AsyncUpdater
{
public:
VSTPluginInstance (const ModuleHandle::Ptr& module_)
VSTPluginInstance (const ModuleHandle::Ptr& mh)
: effect (nullptr),
module (module_),
module (mh),
usesCocoaNSView (false),
name (module_->pluginName),
name (mh->pluginName),
wantsMidiMessages (false),
initialised (false),
isPowerOn (false),
@@ -741,7 +725,7 @@ public:
{
static void* audioMasterCoerced = nullptr;
if (audioMasterCoerced == nullptr)
audioMasterCoerced = NewCFMFromMachO ((void*) &audioMaster);
audioMasterCoerced = newCFMFromMachO ((void*) &audioMaster);
effect = module->moduleMain ((audioMasterCallback) audioMasterCoerced);
}
@@ -803,7 +787,7 @@ public:
char buffer [512] = { 0 };
dispatch (effGetEffectName, 0, 0, buffer, 0);
desc.descriptiveName = String (buffer).trim();
desc.descriptiveName = String::fromUTF8 (buffer).trim();
if (desc.descriptiveName.isEmpty())
desc.descriptiveName = name;
@@ -818,7 +802,7 @@ public:
{
char buffer [kVstMaxVendorStrLen + 8] = { 0 };
dispatch (effGetVendorString, 0, 0, buffer, 0);
desc.manufacturerName = buffer;
desc.manufacturerName = String::fromUTF8 (buffer);
}
desc.version = getVersion();
@@ -1146,8 +1130,7 @@ public:
bool isValidChannel (int index, bool isInput) const
{
return isInput ? (index < getNumInputChannels())
: (index < getNumOutputChannels());
return isPositiveAndBelow (index, isInput ? getNumInputChannels() : getNumOutputChannels());
}
//==============================================================================
@@ -1214,7 +1197,7 @@ public:
char nm[264] = { 0 };
if (dispatch (effGetProgramNameIndexed, jlimit (0, getNumPrograms(), index), -1, nm, 0) != 0)
return String (CharPointer_UTF8 (nm)).trim();
return String::fromUTF8 (nm).trim();
}
}
@@ -1285,7 +1268,8 @@ public:
handleUpdateNowIfNeeded();
for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
ComponentPeer::getPeer(i)->performAnyPendingRepaintsNow();
if (ComponentPeer* p = ComponentPeer::getPeer(i))
p->performAnyPendingRepaintsNow();
}
break;
@@ -1448,20 +1432,20 @@ public:
const fxSet* const set = (const fxSet*) data;
if ((vst_swap (set->chunkMagic) != 'CcnK' && vst_swap (set->chunkMagic) != 'KncC')
|| vst_swap (set->version) > fxbVersionNum)
if ((set->chunkMagic != fxbName ("CcnK") && set->chunkMagic != fxbName ("KncC"))
|| fxbSwap (set->version) > fxbVersionNum)
return false;
if (vst_swap (set->fxMagic) == 'FxBk')
if (set->fxMagic == fxbName ("FxBk"))
{
// bank of programs
if (vst_swap (set->numPrograms) >= 0)
if (fxbSwap (set->numPrograms) >= 0)
{
const int oldProg = getCurrentProgram();
const int numParams = vst_swap (((const fxProgram*) (set->programs))->numParams);
const int numParams = fxbSwap (((const fxProgram*) (set->programs))->numParams);
const int progLen = sizeof (fxProgram) + (numParams - 1) * sizeof (float);
for (int i = 0; i < vst_swap (set->numPrograms); ++i)
for (int i = 0; i < fxbSwap (set->numPrograms); ++i)
{
if (i != oldProg)
{
@@ -1469,7 +1453,7 @@ public:
if (((const char*) prog) - ((const char*) set) >= (ssize_t) dataSize)
return false;
if (vst_swap (set->numPrograms) > 0)
if (fxbSwap (set->numPrograms) > 0)
setCurrentProgram (i);
if (! restoreProgramSettings (prog))
@@ -1477,7 +1461,7 @@ public:
}
}
if (vst_swap (set->numPrograms) > 0)
if (fxbSwap (set->numPrograms) > 0)
setCurrentProgram (oldProg);
const fxProgram* const prog = (const fxProgram*) (((const char*) (set->programs)) + oldProg * progLen);
@@ -1488,38 +1472,38 @@ public:
return false;
}
}
else if (vst_swap (set->fxMagic) == 'FxCk')
else if (set->fxMagic == fxbName ("FxCk"))
{
// single program
const fxProgram* const prog = (const fxProgram*) data;
if (vst_swap (prog->chunkMagic) != 'CcnK')
if (prog->chunkMagic != fxbName ("CcnK"))
return false;
changeProgramName (getCurrentProgram(), prog->prgName);
for (int i = 0; i < vst_swap (prog->numParams); ++i)
setParameter (i, vst_swapFloat (prog->params[i]));
for (int i = 0; i < fxbSwap (prog->numParams); ++i)
setParameter (i, fxbSwapFloat (prog->params[i]));
}
else if (vst_swap (set->fxMagic) == 'FBCh' || vst_swap (set->fxMagic) == 'hCBF')
else if (set->fxMagic == fxbName ("FBCh") || set->fxMagic == fxbName ("hCBF"))
{
// non-preset chunk
const fxChunkSet* const cset = (const fxChunkSet*) data;
if (vst_swap (cset->chunkSize) + sizeof (fxChunkSet) - 8 > (unsigned int) dataSize)
if (fxbSwap (cset->chunkSize) + sizeof (fxChunkSet) - 8 > (unsigned int) dataSize)
return false;
setChunkData (cset->chunk, vst_swap (cset->chunkSize), false);
setChunkData (cset->chunk, fxbSwap (cset->chunkSize), false);
}
else if (vst_swap (set->fxMagic) == 'FPCh' || vst_swap (set->fxMagic) == 'hCPF')
else if (set->fxMagic == fxbName ("FPCh") || set->fxMagic == fxbName ("hCPF"))
{
// preset chunk
const fxProgramSet* const cset = (const fxProgramSet*) data;
if (vst_swap (cset->chunkSize) + sizeof (fxProgramSet) - 8 > (unsigned int) dataSize)
if (fxbSwap (cset->chunkSize) + sizeof (fxProgramSet) - 8 > (unsigned int) dataSize)
return false;
setChunkData (cset->chunk, vst_swap (cset->chunkSize), true);
setChunkData (cset->chunk, fxbSwap (cset->chunkSize), true);
changeProgramName (getCurrentProgram(), cset->name);
}
@@ -1547,14 +1531,14 @@ public:
dest.setSize (totalLen, true);
fxChunkSet* const set = (fxChunkSet*) dest.getData();
set->chunkMagic = vst_swap ('CcnK');
set->chunkMagic = fxbName ("CcnK");
set->byteSize = 0;
set->fxMagic = vst_swap ('FBCh');
set->version = vst_swap (fxbVersionNum);
set->fxID = vst_swap (getUID());
set->fxVersion = vst_swap (getVersionNumber());
set->numPrograms = vst_swap (numPrograms);
set->chunkSize = vst_swap ((VstInt32) chunk.getSize());
set->fxMagic = fxbName ("FBCh");
set->version = fxbSwap (fxbVersionNum);
set->fxID = fxbSwap (getUID());
set->fxVersion = fxbSwap (getVersionNumber());
set->numPrograms = fxbSwap (numPrograms);
set->chunkSize = fxbSwap ((VstInt32) chunk.getSize());
chunk.copyTo (set->chunk, 0, chunk.getSize());
}
@@ -1564,14 +1548,14 @@ public:
dest.setSize (totalLen, true);
fxProgramSet* const set = (fxProgramSet*) dest.getData();
set->chunkMagic = vst_swap ('CcnK');
set->chunkMagic = fxbName ("CcnK");
set->byteSize = 0;
set->fxMagic = vst_swap ('FPCh');
set->version = vst_swap (fxbVersionNum);
set->fxID = vst_swap (getUID());
set->fxVersion = vst_swap (getVersionNumber());
set->numPrograms = vst_swap (numPrograms);
set->chunkSize = vst_swap ((VstInt32) chunk.getSize());
set->fxMagic = fxbName ("FPCh");
set->version = fxbSwap (fxbVersionNum);
set->fxID = fxbSwap (getUID());
set->fxVersion = fxbSwap (getVersionNumber());
set->numPrograms = fxbSwap (numPrograms);
set->chunkSize = fxbSwap ((VstInt32) chunk.getSize());
getCurrentProgramName().copyToUTF8 (set->name, sizeof (set->name) - 1);
chunk.copyTo (set->chunk, 0, chunk.getSize());
@@ -1586,13 +1570,13 @@ public:
dest.setSize (len, true);
fxSet* const set = (fxSet*) dest.getData();
set->chunkMagic = vst_swap ('CcnK');
set->chunkMagic = fxbName ("CcnK");
set->byteSize = 0;
set->fxMagic = vst_swap ('FxBk');
set->version = vst_swap (fxbVersionNum);
set->fxID = vst_swap (getUID());
set->fxVersion = vst_swap (getVersionNumber());
set->numPrograms = vst_swap (numPrograms);
set->fxMagic = fxbName ("FxBk");
set->version = fxbSwap (fxbVersionNum);
set->fxID = fxbSwap (getUID());
set->fxVersion = fxbSwap (getVersionNumber());
set->numPrograms = fxbSwap (numPrograms);
const int oldProgram = getCurrentProgram();
MemoryBlock oldSettings;
@@ -1687,12 +1671,12 @@ private:
bool restoreProgramSettings (const fxProgram* const prog)
{
if (vst_swap (prog->chunkMagic) == 'CcnK' && vst_swap (prog->fxMagic) == 'FxCk')
if (prog->chunkMagic == fxbName ("CcnK") && prog->fxMagic == fxbName ("FxCk"))
{
changeProgramName (getCurrentProgram(), prog->prgName);
for (int i = 0; i < vst_swap (prog->numParams); ++i)
setParameter (i, vst_swapFloat (prog->params[i]));
for (int i = 0; i < fxbSwap (prog->numParams); ++i)
setParameter (i, fxbSwapFloat (prog->params[i]));
return true;
}
@@ -1741,18 +1725,18 @@ private:
{
const int numParams = getNumParameters();
prog->chunkMagic = vst_swap ('CcnK');
prog->chunkMagic = fxbName ("CcnK");
prog->byteSize = 0;
prog->fxMagic = vst_swap ('FxCk');
prog->version = vst_swap (fxbVersionNum);
prog->fxID = vst_swap (getUID());
prog->fxVersion = vst_swap (getVersionNumber());
prog->numParams = vst_swap (numParams);
prog->fxMagic = fxbName ("FxCk");
prog->version = fxbSwap (fxbVersionNum);
prog->fxID = fxbSwap (getUID());
prog->fxVersion = fxbSwap (getVersionNumber());
prog->numParams = fxbSwap (numParams);
getCurrentProgramName().copyToUTF8 (prog->prgName, sizeof (prog->prgName) - 1);
for (int i = 0; i < numParams; ++i)
prog->params[i] = vst_swapFloat (getParameter (i));
prog->params[i] = fxbSwapFloat (getParameter (i));
}
void updateStoredProgramNames()
@@ -1894,7 +1878,8 @@ private:
};
//==============================================================================
static Array <VSTPluginWindow*> activeVSTWindows;
class VSTPluginWindow;
static Array<VSTPluginWindow*> activeVSTWindows;
//==============================================================================
class VSTPluginWindow : public AudioProcessorEditor,
@@ -2232,10 +2217,11 @@ private:
#pragma warning (push)
#pragma warning (disable: 4244)
originalWndProc = (void*) GetWindowLongPtr (pluginHWND, GWLP_WNDPROC);
if (! pluginWantsKeys)
{
originalWndProc = (void*) GetWindowLongPtr (pluginHWND, GWLP_WNDPROC);
SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) vstHookWndProc);
}
#pragma warning (pop)
@@ -2317,26 +2303,24 @@ private:
{
if (isOpen)
{
#if ! (JUCE_MAC && JUCE_SUPPORT_CARBON)
JUCE_VST_LOG ("Closing VST UI: " + plugin.getName());
isOpen = false;
dispatch (effEditClose, 0, 0, 0, 0);
stopTimer();
#if JUCE_WINDOWS
#pragma warning (push)
#pragma warning (disable: 4244)
if (pluginHWND != 0 && IsWindow (pluginHWND))
if (originalWndProc != 0 && pluginHWND != 0 && IsWindow (pluginHWND))
SetWindowLongPtr (pluginHWND, GWLP_WNDPROC, (LONG_PTR) originalWndProc);
#pragma warning (pop)
originalWndProc = 0;
pluginHWND = 0;
#elif JUCE_LINUX
pluginWindow = 0;
pluginProc = 0;
#endif
#endif
}
}
@@ -2845,7 +2829,7 @@ FileSearchPath VSTPluginFormat::getDefaultLocationsToSearch()
const XmlElement* VSTPluginFormat::getVSTXML (AudioPluginInstance* plugin)
{
if (VSTPluginInstance* const vst = dynamic_cast <VSTPluginInstance*> (plugin))
if (VSTPluginInstance* const vst = dynamic_cast<VSTPluginInstance*> (plugin))
if (vst->module != nullptr)
return vst->module->vstXml.get();
@@ -2854,7 +2838,7 @@ const XmlElement* VSTPluginFormat::getVSTXML (AudioPluginInstance* plugin)
bool VSTPluginFormat::loadFromFXBFile (AudioPluginInstance* plugin, const void* data, size_t dataSize)
{
if (VSTPluginInstance* vst = dynamic_cast <VSTPluginInstance*> (plugin))
if (VSTPluginInstance* vst = dynamic_cast<VSTPluginInstance*> (plugin))
return vst->loadFromFXBFile (data, dataSize);
return false;
@@ -2862,7 +2846,7 @@ bool VSTPluginFormat::loadFromFXBFile (AudioPluginInstance* plugin, const void*
bool VSTPluginFormat::saveToFXBFile (AudioPluginInstance* plugin, MemoryBlock& dest, bool asFXB)
{
if (VSTPluginInstance* vst = dynamic_cast <VSTPluginInstance*> (plugin))
if (VSTPluginInstance* vst = dynamic_cast<VSTPluginInstance*> (plugin))
return vst->saveToFXBFile (dest, asFXB);
return false;
@@ -2870,7 +2854,7 @@ bool VSTPluginFormat::saveToFXBFile (AudioPluginInstance* plugin, MemoryBlock& d
bool VSTPluginFormat::getChunkData (AudioPluginInstance* plugin, MemoryBlock& result, bool isPreset)
{
if (VSTPluginInstance* vst = dynamic_cast <VSTPluginInstance*> (plugin))
if (VSTPluginInstance* vst = dynamic_cast<VSTPluginInstance*> (plugin))
return vst->getChunkData (result, isPreset, 128);
return false;
@@ -2878,7 +2862,7 @@ bool VSTPluginFormat::getChunkData (AudioPluginInstance* plugin, MemoryBlock& re
bool VSTPluginFormat::setChunkData (AudioPluginInstance* plugin, const void* data, int size, bool isPreset)
{
if (VSTPluginInstance* vst = dynamic_cast <VSTPluginInstance*> (plugin))
if (VSTPluginInstance* vst = dynamic_cast<VSTPluginInstance*> (plugin))
return vst->setChunkData (data, size, isPreset);
return false;
@@ -2888,13 +2872,13 @@ void VSTPluginFormat::setExtraFunctions (AudioPluginInstance* plugin, ExtraFunct
{
ScopedPointer<ExtraFunctions> f (functions);
if (VSTPluginInstance* vst = dynamic_cast <VSTPluginInstance*> (plugin))
if (VSTPluginInstance* vst = dynamic_cast<VSTPluginInstance*> (plugin))
vst->extraFunctions = f;
}
VSTPluginFormat::VstIntPtr JUCE_CALLTYPE VSTPluginFormat::dispatcher (AudioPluginInstance* plugin, int32 opcode, int32 index, VstIntPtr value, void* ptr, float opt)
{
if (VSTPluginInstance* vst = dynamic_cast <VSTPluginInstance*> (plugin))
if (VSTPluginInstance* vst = dynamic_cast<VSTPluginInstance*> (plugin))
return vst->dispatch (opcode, index, value, ptr, opt);
return 0;
@@ -41,8 +41,9 @@
//==============================================================================
#if JUCE_MAC
#if (JUCE_PLUGINHOST_VST || JUCE_PLUGINHOST_AU) \
|| ! (defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6)
#if JUCE_SUPPORT_CARBON \
&& ((JUCE_PLUGINHOST_VST || JUCE_PLUGINHOST_AU) \
|| ! (defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6))
#define Point CarbonDummyPointName // (workaround to avoid definition of "Point" by old Carbon headers)
#define Component CarbonDummyCompName
#include <Carbon/Carbon.h>
@@ -112,27 +113,24 @@ struct AutoResizingNSViewComponentWithParent : public AutoResizingNSViewCompone
setView (v);
[v release];
startTimer (100);
startTimer (30);
}
NSView* getChildView() const
{
if (NSView* parent = (NSView*) getView())
if ([[parent subviews] count] > 0)
return [[parent subviews] objectAtIndex: 0];
return nil;
}
void timerCallback() override
{
if (NSView* parent = (NSView*) getView())
if (NSView* child = getChildView())
{
if ([[parent subviews] count] > 0)
{
if (NSView* child = [[parent subviews] objectAtIndex: 0])
{
NSRect f = [parent frame];
NSSize newSize = [child frame].size;
if (f.size.width != newSize.width || f.size.height != newSize.height)
{
f.size = newSize;
[parent setFrame: f];
}
}
}
stopTimer();
setView (child);
}
}
};
@@ -76,6 +76,7 @@ class AudioProcessor;
#include "processors/juce_AudioPlayHead.h"
#include "processors/juce_AudioProcessorEditor.h"
#include "processors/juce_AudioProcessorListener.h"
#include "processors/juce_AudioProcessorParameter.h"
#include "processors/juce_AudioProcessor.h"
#include "processors/juce_PluginDescription.h"
#include "processors/juce_AudioPluginInstance.h"
@@ -1,7 +1,7 @@
{
"id": "juce_audio_processors",
"name": "JUCE audio plugin hosting classes",
"version": "3.0.5",
"version": "3.0.8",
"description": "Classes for loading and playing VST, AU, or internally-generated audio processors.",
"website": "http://www.juce.com/juce",
"license": "GPL/Commercial",
@@ -118,19 +118,6 @@ void AudioProcessor::setParameterNotifyingHost (const int parameterIndex,
sendParamChangeMessageToListeners (parameterIndex, newValue);
}
String AudioProcessor::getParameterName (int parameterIndex, int maximumStringLength)
{
return getParameterName (parameterIndex).substring (0, maximumStringLength);
}
String AudioProcessor::getParameterText (int parameterIndex, int maximumStringLength)
{
return getParameterText (parameterIndex).substring (0, maximumStringLength);
}
int AudioProcessor::getParameterNumSteps (int /*parameterIndex*/) { return 0x7fffffff; }
float AudioProcessor::getParameterDefaultValue (int /*parameterIndex*/) { return 0.0f; }
AudioProcessorListener* AudioProcessor::getListenerLocked (const int index) const noexcept
{
const ScopedLock sl (listenerLock);
@@ -201,9 +188,129 @@ void AudioProcessor::updateHostDisplay()
l->audioProcessorChanged (this);
}
String AudioProcessor::getParameterLabel (int) const { return String(); }
bool AudioProcessor::isParameterAutomatable (int) const { return true; }
bool AudioProcessor::isMetaParameter (int) const { return false; }
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)
{
@@ -230,9 +337,6 @@ AudioProcessorEditor* AudioProcessor::createEditorIfNeeded()
AudioProcessorEditor* const ed = createEditor();
// You must make your hasEditor() method return a consistent result!
jassert (hasEditor() == (ed != nullptr));
if (ed != nullptr)
{
// you must give your editor comp a size before returning it..
@@ -242,6 +346,9 @@ AudioProcessorEditor* AudioProcessor::createEditorIfNeeded()
activeEditor = ed;
}
// You must make your hasEditor() method return a consistent result!
jassert (hasEditor() == (ed != nullptr));
return ed;
}
@@ -294,6 +401,47 @@ XmlElement* AudioProcessor::getXmlFromBinary (const void* data, const int sizeIn
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
{
@@ -44,11 +44,7 @@ class JUCE_API AudioProcessor
{
protected:
//==============================================================================
/** Constructor.
You can also do your initialisation tasks in the initialiseFilterInfo()
call, which will be made after this object has been created.
*/
/** Constructor. */
AudioProcessor();
public:
@@ -293,9 +289,9 @@ public:
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.
If you're going to use this, your processBlock() method must call isSuspended() and
check whether it's suspended or not. If it is, then it should skip doing any real
processing, either emitting silence or passing the input through unchanged.
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
*/
@@ -329,7 +325,7 @@ public:
/** Called by the host to tell this processor whether it's being used in a non-realtime
capacity for offline rendering or bouncing.
*/
void setNonRealtime (bool isNonRealtime) noexcept;
virtual void setNonRealtime (bool isNonRealtime) noexcept;
//==============================================================================
/** Creates the filter's UI.
@@ -381,10 +377,10 @@ public:
/** 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() = 0;
virtual int getNumParameters();
/** Returns the name of a particular parameter. */
virtual const String getParameterName (int parameterIndex) = 0;
virtual const String getParameterName (int parameterIndex);
/** Called by the host to find out the value of one of the filter's parameters.
@@ -394,10 +390,10 @@ public:
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) = 0;
virtual float getParameter (int parameterIndex);
/** Returns the value of a parameter as a text string. */
virtual const String getParameterText (int parameterIndex) = 0;
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
@@ -418,12 +414,18 @@ public:
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 0x7fffffff.
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.
@@ -435,6 +437,11 @@ public:
*/
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
@@ -448,7 +455,7 @@ public:
The value passed will be between 0 and 1.0.
*/
virtual void setParameter (int parameterIndex, float newValue) = 0;
virtual void setParameter (int parameterIndex, float newValue);
/** Your filter can call this when it needs to change one of its parameters.
@@ -463,16 +470,13 @@ public:
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;
@@ -503,6 +507,16 @@ public:
*/
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.
@@ -659,6 +673,9 @@ private:
CriticalSection callbackLock, listenerLock;
String inputSpeakerArrangement, outputSpeakerArrangement;
OwnedArray<AudioProcessorParameter> managedParameters;
AudioProcessorParameter* getParamChecked (int) const noexcept;
#if JUCE_DEBUG
BigInteger changingParams;
#endif
@@ -22,16 +22,22 @@
==============================================================================
*/
AudioProcessorEditor::AudioProcessorEditor (AudioProcessor* const p)
: owner (p)
AudioProcessorEditor::AudioProcessorEditor (AudioProcessor& p) noexcept : processor (p)
{
}
AudioProcessorEditor::AudioProcessorEditor (AudioProcessor* p) noexcept : processor (*p)
{
// the filter must be valid..
jassert (owner != nullptr);
jassert (p != nullptr);
}
AudioProcessorEditor::~AudioProcessorEditor()
{
// if this fails, then the wrapper hasn't called editorBeingDeleted() on the
// filter for some reason..
jassert (owner->getActiveEditor() != this);
jassert (processor.getActiveEditor() != this);
}
void AudioProcessorEditor::setControlHighlight (ParameterControlHighlightInfo) {}
int AudioProcessorEditor::getControlParameterIndex (Component&) { return -1; }
@@ -39,9 +39,11 @@ class JUCE_API AudioProcessorEditor : public Component
{
protected:
//==============================================================================
/** Creates an editor for the specified processor.
*/
AudioProcessorEditor (AudioProcessor* owner);
/** Creates an editor for the specified processor. */
AudioProcessorEditor (AudioProcessor&) noexcept;
/** Creates an editor for the specified processor. */
AudioProcessorEditor (AudioProcessor*) noexcept;
public:
/** Destructor. */
@@ -49,14 +51,40 @@ public:
//==============================================================================
/** Returns a pointer to the processor that this editor represents. */
AudioProcessor* getAudioProcessor() const noexcept { return owner; }
/** 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:
//==============================================================================
AudioProcessor* const owner;
JUCE_DECLARE_NON_COPYABLE (AudioProcessorEditor)
};
@@ -388,11 +388,11 @@ public:
private:
//==============================================================================
ReferenceCountedArray <Node> nodes;
OwnedArray <Connection> connections;
ReferenceCountedArray<Node> nodes;
OwnedArray<Connection> connections;
uint32 lastNodeId;
AudioSampleBuffer renderingBuffers;
OwnedArray <MidiBuffer> midiBuffers;
OwnedArray<MidiBuffer> midiBuffers;
Array<void*> renderingOps;
friend class AudioGraphIOProcessor;
@@ -27,12 +27,12 @@ class ProcessorParameterPropertyComp : public PropertyComponent,
private Timer
{
public:
ProcessorParameterPropertyComp (const String& name, AudioProcessor& p, const int index_)
ProcessorParameterPropertyComp (const String& name, AudioProcessor& p, int paramIndex)
: PropertyComponent (name),
owner (p),
index (index_),
index (paramIndex),
paramHasChanged (false),
slider (p, index_)
slider (p, paramIndex)
{
startTimer (100);
addAndMakeVisible (slider);
@@ -44,15 +44,19 @@ public:
owner.removeListener (this);
}
void refresh()
void refresh() override
{
paramHasChanged = false;
slider.setValue (owner.getParameter (index), dontSendNotification);
if (slider.getThumbBeingDragged() < 0)
slider.setValue (owner.getParameter (index), dontSendNotification);
slider.updateText();
}
void audioProcessorChanged (AudioProcessor*) {}
void audioProcessorChanged (AudioProcessor*) override {}
void audioProcessorParameterChanged (AudioProcessor*, int parameterIndex, float)
void audioProcessorParameterChanged (AudioProcessor*, int parameterIndex, float) override
{
if (parameterIndex == index)
paramHasChanged = true;
@@ -76,27 +80,34 @@ private:
class ParamSlider : public Slider
{
public:
ParamSlider (AudioProcessor& p, const int index_)
: owner (p),
index (index_)
ParamSlider (AudioProcessor& p, int paramIndex) : owner (p), index (paramIndex)
{
setRange (0.0, 1.0, 0.0);
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 (false);
setScrollWheelEnabled (true);
}
void valueChanged()
void valueChanged() override
{
const float newVal = (float) getValue();
if (owner.getParameter (index) != newVal)
{
owner.setParameterNotifyingHost (index, newVal);
updateText();
}
}
String getTextFromValue (double /*value*/)
String getTextFromValue (double /*value*/) override
{
return owner.getParameterText (index);
return owner.getParameterText (index) + " " + owner.getParameterLabel (index).trimEnd();
}
private:
@@ -71,18 +71,26 @@ PluginDescription& PluginDescription::operator= (const PluginDescription& other)
return *this;
}
bool PluginDescription::isDuplicateOf (const PluginDescription& other) const
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
+ "-" + String::toHexString (fileOrIdentifier.hashCode())
+ "-" + String::toHexString (uid);
return pluginFormatName + "-" + name + getPluginDescSuffix (*this);
}
XmlElement* PluginDescription::createXml() const
@@ -107,7 +107,15 @@ public:
This isn't quite as simple as them just having the same file (because of
shell plug-ins).
*/
bool isDuplicateOf (const PluginDescription& other) const;
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
@@ -46,7 +46,7 @@ PluginDescription* KnownPluginList::getTypeForFile (const String& fileOrIdentifi
PluginDescription* KnownPluginList::getTypeForIdentifierString (const String& identifierString) const
{
for (int i = 0; i < types.size(); ++i)
if (types.getUnchecked(i)->createIdentifierString() == identifierString)
if (types.getUnchecked(i)->matchesIdentifierString (identifierString))
return types.getUnchecked(i);
return nullptr;
@@ -259,15 +259,15 @@ struct PluginSorter
switch (method)
{
case KnownPluginList::sortByCategory: diff = first->category.compareLexicographically (second->category); break;
case KnownPluginList::sortByManufacturer: diff = first->manufacturerName.compareLexicographically (second->manufacturerName); break;
case KnownPluginList::sortByCategory: diff = first->category.compareNatural (second->category); break;
case KnownPluginList::sortByManufacturer: diff = first->manufacturerName.compareNatural (second->manufacturerName); break;
case KnownPluginList::sortByFormat: diff = first->pluginFormatName.compare (second->pluginFormatName); break;
case KnownPluginList::sortByFileSystemLocation: diff = lastPathPart (first->fileOrIdentifier).compare (lastPathPart (second->fileOrIdentifier)); break;
default: break;
}
if (diff == 0)
diff = first->name.compareLexicographically (second->name);
diff = first->name.compareNatural (second->name);
return diff * direction;
}