- 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:
@@ -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.
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ public:
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
OwnedArray <AudioPluginFormat> formats;
|
||||
OwnedArray<AudioPluginFormat> formats;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginFormatManager)
|
||||
};
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+34
-19
@@ -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))
|
||||
|
||||
+2
-2
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+365
-65
@@ -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();
|
||||
|
||||
+186
-202
@@ -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
|
||||
|
||||
+10
-4
@@ -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; }
|
||||
|
||||
+36
-8
@@ -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;
|
||||
|
||||
+26
-15
@@ -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:
|
||||
|
||||
+13
-5
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user