|
|
@@ -380,6 +380,11 @@ 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 paramID) override
|
|
|
|
{
|
|
|
@@ -414,11 +419,31 @@ public: |
|
|
|
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))
|
|
|
|
{
|
|
|
|
double sampleRate = owner->getSampleRate();
|
|
|
|
int numSamples = owner->getBlockSize();
|
|
|
|
|
|
|
|
if (sampleRate <= 8000.0)
|
|
|
|
sampleRate = 44100.0;
|
|
|
|
|
|
|
|
if (numSamples <= 0)
|
|
|
|
numSamples = 1024;
|
|
|
|
|
|
|
|
owner->prepareToPlay (owner->getSampleRate(), owner->getBlockSize());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hasFlag (flags, Vst::kLatencyChanged))
|
|
|
|
if (owner->processor != nullptr)
|
|
|
|
owner->setLatencySamples (jmax (0, (int) owner->processor->getLatencySamples()));
|
|
|
|
|
|
|
|
owner->updateHostDisplay();
|
|
|
|
return kResultTrue;
|
|
|
|
}
|
|
|
@@ -452,9 +477,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;
|
|
|
|
}
|
|
|
|
|
|
|
@@ -565,7 +752,7 @@ public: |
|
|
|
private:
|
|
|
|
//==============================================================================
|
|
|
|
VST3PluginInstance* const owner;
|
|
|
|
Atomic<int32> refCount;
|
|
|
|
Atomic<int> refCount;
|
|
|
|
String appName;
|
|
|
|
|
|
|
|
typedef std::map<Vst::ParamID, int> ParamMapType;
|
|
|
@@ -635,7 +822,7 @@ private: |
|
|
|
VST3HostContext& owner;
|
|
|
|
ComSmartPtr<Vst::IAttributeList> attributeList;
|
|
|
|
String messageId;
|
|
|
|
Atomic<int32> refCount;
|
|
|
|
Atomic<int> refCount;
|
|
|
|
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Message)
|
|
|
|
};
|
|
|
@@ -763,7 +950,7 @@ private: |
|
|
|
|
|
|
|
private:
|
|
|
|
VST3HostContext* owner;
|
|
|
|
Atomic<int32> refCount;
|
|
|
|
Atomic<int> refCount;
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
template<typename Type>
|
|
|
@@ -1567,6 +1754,8 @@ public: |
|
|
|
|
|
|
|
setStateForAllBusses (true);
|
|
|
|
|
|
|
|
setLatencySamples (jmax (0, (int) processor->getLatencySamples()));
|
|
|
|
|
|
|
|
warnOnFailure (component->setActive (true));
|
|
|
|
warnOnFailure (processor->setProcessing (true));
|
|
|
|
}
|
|
|
@@ -1756,6 +1945,16 @@ public: |
|
|
|
return toString (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
void reset() override
|
|
|
|
{
|
|
|
|
if (component != nullptr)
|
|
|
|
{
|
|
|
|
component->setActive (false);
|
|
|
|
component->setActive (true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
void getStateInformation (MemoryBlock& destData) override
|
|
|
|
{
|
|
|
@@ -1879,21 +2078,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)
|
|
|
|
};
|
|
|
|