1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

AudioPluginHost: Added an application-level setting for scaling plug-ins on Windows

This commit is contained in:
ed 2021-03-01 16:43:01 +00:00
parent b1253bfc74
commit 3a0af69eff
8 changed files with 233 additions and 75 deletions

View file

@ -155,5 +155,118 @@ bool isOnTouchDevice()
return isTouch;
}
//==============================================================================
static AutoScale autoScaleFromString (StringRef str)
{
if (str.isEmpty()) return AutoScale::useDefault;
if (str == CharPointer_ASCII { "0" }) return AutoScale::scaled;
if (str == CharPointer_ASCII { "1" }) return AutoScale::unscaled;
jassertfalse;
return AutoScale::useDefault;
}
static const char* autoScaleToString (AutoScale autoScale)
{
if (autoScale == AutoScale::scaled) return "0";
if (autoScale == AutoScale::unscaled) return "1";
return {};
}
AutoScale getAutoScaleValueForPlugin (const String& identifier)
{
if (identifier.isNotEmpty())
{
auto plugins = StringArray::fromLines (getAppProperties().getUserSettings()->getValue ("autoScalePlugins"));
plugins.removeEmptyStrings();
for (auto& plugin : plugins)
{
auto fromIdentifier = plugin.fromFirstOccurrenceOf (identifier, false, false);
if (fromIdentifier.isNotEmpty())
return autoScaleFromString (fromIdentifier.fromFirstOccurrenceOf (":", false, false));
}
}
return AutoScale::useDefault;
}
void setAutoScaleValueForPlugin (const String& identifier, AutoScale s)
{
auto plugins = StringArray::fromLines (getAppProperties().getUserSettings()->getValue ("autoScalePlugins"));
plugins.removeEmptyStrings();
auto index = [identifier, plugins]
{
auto it = std::find_if (plugins.begin(), plugins.end(),
[&] (const String& str) { return str.startsWith (identifier); });
return (int) std::distance (plugins.begin(), it);
}();
if (s == AutoScale::useDefault && index != plugins.size())
{
plugins.remove (index);
}
else
{
auto str = identifier + ":" + autoScaleToString (s);
if (index != plugins.size())
plugins.getReference (index) = str;
else
plugins.add (str);
}
getAppProperties().getUserSettings()->setValue ("autoScalePlugins", plugins.joinIntoString ("\n"));
}
bool shouldAutoScalePlugin (const String& identifier)
{
if (! autoScaleOptionAvailable)
return false;
const auto scaleValue = getAutoScaleValueForPlugin (identifier);
return (scaleValue == AutoScale::scaled
|| (scaleValue == AutoScale::useDefault
&& getAppProperties().getUserSettings()->getBoolValue ("autoScalePluginWindows")));
}
void addPluginAutoScaleOptionsSubMenu (AudioPluginInstance* pluginInstance,
PopupMenu& menu)
{
if (pluginInstance == nullptr)
return;
auto description = pluginInstance->getPluginDescription();
if (! description.pluginFormatName.contains ("VST"))
return;
auto identifier = description.fileOrIdentifier;
PopupMenu autoScaleMenu;
autoScaleMenu.addItem ("Default",
true,
getAutoScaleValueForPlugin (identifier) == AutoScale::useDefault,
[identifier] { setAutoScaleValueForPlugin (identifier, AutoScale::useDefault); });
autoScaleMenu.addItem ("Enabled",
true,
getAutoScaleValueForPlugin (identifier) == AutoScale::scaled,
[identifier] { setAutoScaleValueForPlugin (identifier, AutoScale::scaled); });
autoScaleMenu.addItem ("Disabled",
true,
getAutoScaleValueForPlugin (identifier) == AutoScale::unscaled,
[identifier] { setAutoScaleValueForPlugin (identifier, AutoScale::unscaled); });
menu.addSubMenu ("Auto-scale window", autoScaleMenu);
}
// This kicks the whole thing off..
START_JUCE_APPLICATION (PluginHostApp)

View file

@ -29,6 +29,11 @@
#include "InternalPlugins.h"
#include "../UI/GraphEditorPanel.h"
static std::unique_ptr<ScopedDPIAwarenessDisabler> makeDPIAwarenessDisablerForPlugin (StringRef identifier)
{
return shouldAutoScalePlugin (identifier) ? std::make_unique<ScopedDPIAwarenessDisabler>()
: nullptr;
}
//==============================================================================
PluginGraph::PluginGraph (AudioPluginFormatManager& fm)
@ -76,10 +81,12 @@ AudioProcessorGraph::Node::Ptr PluginGraph::getNodeForName (const String& name)
void PluginGraph::addPlugin (const PluginDescription& desc, Point<double> pos)
{
std::shared_ptr<ScopedDPIAwarenessDisabler> dpiDisabler = makeDPIAwarenessDisablerForPlugin (desc.fileOrIdentifier);
formatManager.createPluginInstanceAsync (desc,
graph.getSampleRate(),
graph.getBlockSize(),
[this, pos] (std::unique_ptr<AudioPluginInstance> instance, const String& error)
[this, pos, dpiDisabler] (std::unique_ptr<AudioPluginInstance> instance, const String& error)
{
addPluginCallback (std::move (instance), error, pos);
});
@ -156,18 +163,10 @@ PluginWindow* PluginGraph::getOrCreateWindowFor (AudioProcessorGraph::Node* node
getCommandManager().invokeDirectly (CommandIDs::showAudioSettings, false);
return nullptr;
}
}
#if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE
if (! node->properties["DPIAware"]
&& ! node->getProcessor()->getName().contains ("Kontakt")) // Kontakt doesn't behave correctly in DPI unaware mode...
{
ScopedDPIAwarenessDisabler disableDPIAwareness;
auto localDpiDisabler = makeDPIAwarenessDisablerForPlugin (description.fileOrIdentifier);
return activePluginWindows.add (new PluginWindow (node, type, activePluginWindows));
}
#endif
return activePluginWindows.add (new PluginWindow (node, type, activePluginWindows));
}
return nullptr;
@ -332,9 +331,6 @@ static XmlElement* createNodeXml (AudioProcessorGraph::Node* const node) noexcep
e->setAttribute ("uid", (int) node->nodeID.uid);
e->setAttribute ("x", node->properties ["x"].toString());
e->setAttribute ("y", node->properties ["y"].toString());
#if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE
e->setAttribute ("DPIAware", node->properties["DPIAware"].toString());
#endif
for (int i = 0; i < (int) PluginWindow::Type::numTypes; ++i)
{
@ -383,10 +379,16 @@ void PluginGraph::createNodeFromXml (const XmlElement& xml)
break;
}
String errorMessage;
auto createInstance = [this, pd]
{
String errorMessage;
if (auto instance = formatManager.createPluginInstance (pd, graph.getSampleRate(),
graph.getBlockSize(), errorMessage))
auto localDpiDisabler = makeDPIAwarenessDisablerForPlugin (pd.fileOrIdentifier);
return formatManager.createPluginInstance (pd, graph.getSampleRate(),
graph.getBlockSize(), errorMessage);
};
if (auto instance = createInstance())
{
if (auto* layoutEntity = xml.getChildByName ("LAYOUT"))
{
@ -408,11 +410,8 @@ void PluginGraph::createNodeFromXml (const XmlElement& xml)
node->getProcessor()->setStateInformation (m.getData(), (int) m.getSize());
}
node->properties.set ("x", xml.getDoubleAttribute ("x"));
node->properties.set ("y", xml.getDoubleAttribute ("y"));
#if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE
node->properties.set ("DPIAware", xml.getDoubleAttribute ("DPIAware"));
#endif
node->properties.set ("x", xml.getDoubleAttribute ("x"));
node->properties.set ("y", xml.getDoubleAttribute ("y"));
for (int i = 0; i < (int) PluginWindow::Type::numTypes; ++i)
{

View file

@ -403,21 +403,14 @@ struct GraphEditorPanel::PluginComponent : public Component,
menu->addItem (2, "Disconnect all pins");
menu->addItem (3, "Toggle Bypass");
if (getProcessor()->hasEditor())
{
menu->addSeparator();
menu->addItem (10, "Show plugin GUI");
menu->addItem (11, "Show all programs");
menu->addItem (12, "Show all parameters");
#if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE
auto isTicked = false;
if (auto* node = graph.graph.getNodeForId (pluginID))
isTicked = node->properties["DPIAware"];
menu->addSeparator();
menu->addItem (10, "Show plugin GUI");
menu->addItem (11, "Show all programs");
menu->addItem (12, "Show all parameters");
menu->addItem (13, "Show debug log");
menu->addItem (13, "Enable DPI awareness", true, isTicked);
#endif
menu->addItem (14, "Show debug log");
}
if (autoScaleOptionAvailable)
addPluginAutoScaleOptionsSubMenu (dynamic_cast<AudioPluginInstance*> (getProcessor()), *menu);
menu->addSeparator();
menu->addItem (20, "Configure Audio I/O");
@ -441,15 +434,7 @@ struct GraphEditorPanel::PluginComponent : public Component,
case 10: showWindow (PluginWindow::Type::normal); break;
case 11: showWindow (PluginWindow::Type::programs); break;
case 12: showWindow (PluginWindow::Type::generic) ; break;
#if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE
case 13:
{
if (auto* node = graph.graph.getNodeForId (pluginID))
node->properties.set ("DPIAware", ! node->properties ["DPIAware"]);
break;
}
#endif
case 14: showWindow (PluginWindow::Type::debug); break;
case 13: showWindow (PluginWindow::Type::debug); break;
case 20: showWindow (PluginWindow::Type::audioIO); break;
case 21: testStateSaveLoad(); break;

View file

@ -277,9 +277,9 @@ PopupMenu MainHostWindow::getMenuForIndex (int topLevelMenuIndex, const String&
// "Plugins" menu
PopupMenu pluginsMenu;
addPluginsToMenu (pluginsMenu);
menu.addSubMenu ("Create plugin", pluginsMenu);
menu.addSubMenu ("Create Plug-in", pluginsMenu);
menu.addSeparator();
menu.addItem (250, "Delete all plugins");
menu.addItem (250, "Delete All Plug-ins");
}
else if (topLevelMenuIndex == 2)
{
@ -288,17 +288,20 @@ PopupMenu MainHostWindow::getMenuForIndex (int topLevelMenuIndex, const String&
menu.addCommandItem (&getCommandManager(), CommandIDs::showPluginListEditor);
PopupMenu sortTypeMenu;
sortTypeMenu.addItem (200, "List plugins in default order", true, pluginSortMethod == KnownPluginList::defaultOrder);
sortTypeMenu.addItem (201, "List plugins in alphabetical order", true, pluginSortMethod == KnownPluginList::sortAlphabetically);
sortTypeMenu.addItem (202, "List plugins by category", true, pluginSortMethod == KnownPluginList::sortByCategory);
sortTypeMenu.addItem (203, "List plugins by manufacturer", true, pluginSortMethod == KnownPluginList::sortByManufacturer);
sortTypeMenu.addItem (204, "List plugins based on the directory structure", true, pluginSortMethod == KnownPluginList::sortByFileSystemLocation);
menu.addSubMenu ("Plugin menu type", sortTypeMenu);
sortTypeMenu.addItem (200, "List Plug-ins in Default Order", true, pluginSortMethod == KnownPluginList::defaultOrder);
sortTypeMenu.addItem (201, "List Plug-ins in Alphabetical Order", true, pluginSortMethod == KnownPluginList::sortAlphabetically);
sortTypeMenu.addItem (202, "List Plug-ins by Category", true, pluginSortMethod == KnownPluginList::sortByCategory);
sortTypeMenu.addItem (203, "List Plug-ins by Manufacturer", true, pluginSortMethod == KnownPluginList::sortByManufacturer);
sortTypeMenu.addItem (204, "List Plug-ins Based on the Directory Structure", true, pluginSortMethod == KnownPluginList::sortByFileSystemLocation);
menu.addSubMenu ("Plug-in Menu Type", sortTypeMenu);
menu.addSeparator();
menu.addCommandItem (&getCommandManager(), CommandIDs::showAudioSettings);
menu.addCommandItem (&getCommandManager(), CommandIDs::toggleDoublePrecision);
if (autoScaleOptionAvailable)
menu.addCommandItem (&getCommandManager(), CommandIDs::autoScalePluginWindows);
menu.addSeparator();
menu.addCommandItem (&getCommandManager(), CommandIDs::aboutBox);
}
@ -414,7 +417,8 @@ void MainHostWindow::getAllCommands (Array<CommandID>& commands)
CommandIDs::showAudioSettings,
CommandIDs::toggleDoublePrecision,
CommandIDs::aboutBox,
CommandIDs::allWindowsForward
CommandIDs::allWindowsForward,
CommandIDs::autoScalePluginWindows
};
commands.addArray (ids, numElementsInArray (ids));
@ -451,12 +455,12 @@ void MainHostWindow::getCommandInfo (const CommandID commandID, ApplicationComma
#endif
case CommandIDs::showPluginListEditor:
result.setInfo ("Edit the list of available plug-Ins...", String(), category, 0);
result.setInfo ("Edit the List of Available Plug-ins...", {}, category, 0);
result.addDefaultKeypress ('p', ModifierKeys::commandModifier);
break;
case CommandIDs::showAudioSettings:
result.setInfo ("Change the audio device settings", String(), category, 0);
result.setInfo ("Change the Audio Device Settings", {}, category, 0);
result.addDefaultKeypress ('a', ModifierKeys::commandModifier);
break;
@ -465,7 +469,7 @@ void MainHostWindow::getCommandInfo (const CommandID commandID, ApplicationComma
break;
case CommandIDs::aboutBox:
result.setInfo ("About...", String(), category, 0);
result.setInfo ("About...", {}, category, 0);
break;
case CommandIDs::allWindowsForward:
@ -473,6 +477,10 @@ void MainHostWindow::getCommandInfo (const CommandID commandID, ApplicationComma
result.addDefaultKeypress ('w', ModifierKeys::commandModifier);
break;
case CommandIDs::autoScalePluginWindows:
updateAutoScaleMenuItem (result);
break;
default:
break;
}
@ -518,20 +526,30 @@ bool MainHostWindow::perform (const InvocationInfo& info)
case CommandIDs::toggleDoublePrecision:
if (auto* props = getAppProperties().getUserSettings())
{
bool newIsDoublePrecision = ! isDoublePrecisionProcessing();
auto newIsDoublePrecision = ! isDoublePrecisionProcessingEnabled();
props->setValue ("doublePrecisionProcessing", var (newIsDoublePrecision));
{
ApplicationCommandInfo cmdInfo (info.commandID);
updatePrecisionMenuItem (cmdInfo);
menuItemsChanged();
}
ApplicationCommandInfo cmdInfo (info.commandID);
updatePrecisionMenuItem (cmdInfo);
menuItemsChanged();
if (graphHolder != nullptr)
graphHolder->setDoublePrecision (newIsDoublePrecision);
}
break;
case CommandIDs::autoScalePluginWindows:
if (auto* props = getAppProperties().getUserSettings())
{
auto newAutoScale = ! isAutoScalePluginWindowsEnabled();
props->setValue ("autoScalePluginWindows", var (newAutoScale));
ApplicationCommandInfo cmdInfo (info.commandID);
updateAutoScaleMenuItem (cmdInfo);
menuItemsChanged();
}
break;
case CommandIDs::aboutBox:
// TODO
break;
@ -633,7 +651,7 @@ void MainHostWindow::filesDropped (const StringArray& files, int x, int y)
}
}
bool MainHostWindow::isDoublePrecisionProcessing()
bool MainHostWindow::isDoublePrecisionProcessingEnabled()
{
if (auto* props = getAppProperties().getUserSettings())
return props->getBoolValue ("doublePrecisionProcessing", false);
@ -641,8 +659,22 @@ bool MainHostWindow::isDoublePrecisionProcessing()
return false;
}
bool MainHostWindow::isAutoScalePluginWindowsEnabled()
{
if (auto* props = getAppProperties().getUserSettings())
return props->getBoolValue ("autoScalePluginWindows", false);
return false;
}
void MainHostWindow::updatePrecisionMenuItem (ApplicationCommandInfo& info)
{
info.setInfo ("Double floating point precision rendering", String(), "General", 0);
info.setTicked (isDoublePrecisionProcessing());
info.setInfo ("Double Floating-Point Precision Rendering", {}, "General", 0);
info.setTicked (isDoublePrecisionProcessingEnabled());
}
void MainHostWindow::updateAutoScaleMenuItem (ApplicationCommandInfo& info)
{
info.setInfo ("Auto-Scale Plug-in Windows", {}, "General", 0);
info.setTicked (isAutoScalePluginWindowsEnabled());
}

View file

@ -43,12 +43,34 @@ namespace CommandIDs
static const int aboutBox = 0x30300;
static const int allWindowsForward = 0x30400;
static const int toggleDoublePrecision = 0x30500;
static const int autoScalePluginWindows = 0x30600;
}
//==============================================================================
ApplicationCommandManager& getCommandManager();
ApplicationProperties& getAppProperties();
bool isOnTouchDevice();
//==============================================================================
enum class AutoScale
{
scaled,
unscaled,
useDefault
};
constexpr bool autoScaleOptionAvailable =
#if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE
true;
#else
false;
#endif
AutoScale getAutoScaleValueForPlugin (const String&);
void setAutoScaleValueForPlugin (const String&, AutoScale);
bool shouldAutoScalePlugin (const String&);
void addPluginAutoScaleOptionsSubMenu (AudioPluginInstance*, PopupMenu&);
//==============================================================================
class MainHostWindow : public DocumentWindow,
public MenuBarModel,
@ -88,12 +110,18 @@ public:
void addPluginsToMenu (PopupMenu&);
PluginDescription getChosenType (int menuID) const;
bool isDoublePrecisionProcessing();
void updatePrecisionMenuItem (ApplicationCommandInfo& info);
std::unique_ptr<GraphDocumentComponent> graphHolder;
private:
//==============================================================================
static bool isDoublePrecisionProcessingEnabled();
static bool isAutoScalePluginWindowsEnabled();
static void updatePrecisionMenuItem (ApplicationCommandInfo& info);
static void updateAutoScaleMenuItem (ApplicationCommandInfo& info);
void showAudioSettings();
//==============================================================================
AudioDeviceManager deviceManager;
AudioPluginFormatManager formatManager;
@ -106,7 +134,5 @@ private:
class PluginListWindow;
std::unique_ptr<PluginListWindow> pluginListWindow;
void showAudioSettings();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainHostWindow)
};

View file

@ -27,7 +27,7 @@
#include <juce_audio_plugin_client/AAX/juce_AAX_Modifier_Injector.h>
#endif
#if JUCE_WIN_PER_MONITOR_DPI_AWARE && JUCE_MODULE_AVAILABLE_juce_gui_extra
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
#include <juce_gui_extra/embedding/juce_ScopedDPIAwarenessDisabler.h>
#endif
@ -470,7 +470,7 @@ static double getGlobalDPI()
}
//==============================================================================
#if JUCE_WIN_PER_MONITOR_DPI_AWARE && JUCE_MODULE_AVAILABLE_juce_gui_extra
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
ScopedDPIAwarenessDisabler::ScopedDPIAwarenessDisabler()
{
if (! isPerMonitorDPIAwareThread())

View file

@ -26,8 +26,6 @@
namespace juce
{
#if (JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE) || DOXYGEN
//==============================================================================
/**
A Windows-specific class that temporarily sets the DPI awareness context of
@ -52,6 +50,5 @@ public:
private:
void* previousContext = nullptr;
};
#endif
} // namespace juce

View file

@ -188,3 +188,9 @@
#include "native/juce_android_WebBrowserComponent.cpp"
#endif
#endif
//==============================================================================
#if ! JUCE_WINDOWS
juce::ScopedDPIAwarenessDisabler::ScopedDPIAwarenessDisabler() { ignoreUnused (previousContext); }
juce::ScopedDPIAwarenessDisabler::~ScopedDPIAwarenessDisabler() {}
#endif