Browse Source

VST3 hosting - added context menu support.

tags/2021-05-28
jules 11 years ago
parent
commit
6588d04be0
1 changed files with 209 additions and 10 deletions
  1. +209
    -10
      modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp

+ 209
- 10
modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp View File

@@ -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)
};


Loading…
Cancel
Save