1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-08-04 22:29:27 +02:00

Adds the ability to sort and group the Effects menus

Current options:

Publisher: name (the closest to what we have now)
Name (doesn't include the publisher, just a straigt up alpha sort
Publisher (creates submenus based on the publisher)
Type (creates submenus based on the type, VST, Nyquist, etc.)

And the Linux method of creating submenus based on number of items
is available to all and you can choose how menu you want per submenu.
I had to bring this back since I'd removed it when for the new effects
and I figured why limit it to only Linux...

Check it out in Preferences (effect page).

You'll also notice that the effects page is starting to talk about 
plugins.  That will progress further (baby steps) so bare with me
for just a bit more.
This commit is contained in:
lllucius 2014-11-04 01:38:13 +00:00
parent 0358e3eb09
commit 080b67ce9e
6 changed files with 359 additions and 182 deletions

View File

@ -213,9 +213,76 @@ void AudacityProjectCommandFunctor::operator()(int index, const wxEvent * evt)
#define FNI(X, I) new AudacityProjectCommandFunctor(this, &AudacityProject:: X, I)
#define FNS(X, S) new AudacityProjectCommandFunctor(this, &AudacityProject:: X, S)
static bool SortPlugs(const PluginDescriptor *a, const PluginDescriptor *b)
//
// Effects menu arrays
//
WX_DEFINE_ARRAY_PTR(const PluginDescriptor *, EffectPlugs);
static int SortPlugsByDefault(const PluginDescriptor **a, const PluginDescriptor **b)
{
return a->GetMenuName() < b->GetMenuName();
wxString akey = (*a)->GetVendor();
wxString bkey = (*b)->GetVendor();
if ((*a)->IsEffectDefault())
{
akey = wxEmptyString;
}
if ((*b)->IsEffectDefault())
{
bkey = wxEmptyString;
}
akey += (*a)->GetName();
bkey += (*b)->GetName();
return akey.CmpNoCase(bkey);
}
static int SortPlugsByName(const PluginDescriptor **a, const PluginDescriptor **b)
{
wxString akey = (*a)->GetName();
wxString bkey = (*b)->GetName();
return akey.CmpNoCase(bkey);
}
static int SortPlugsByPublisher(const PluginDescriptor **a, const PluginDescriptor **b)
{
wxString akey = (*a)->GetVendor();
wxString bkey = (*b)->GetVendor();
if (akey.IsEmpty())
{
akey = _("Uncategorized");
}
if (bkey.IsEmpty())
{
bkey = _("Uncategorized");
}
akey += (*a)->GetName();
bkey += (*b)->GetName();
return akey.CmpNoCase(bkey);
}
static int SortPlugsByFamily(const PluginDescriptor **a, const PluginDescriptor **b)
{
wxString akey = (*a)->GetEffectFamily();
wxString bkey = (*b)->GetEffectFamily();
if (akey.IsEmpty())
{
akey = _("Uncategorized");
}
if (bkey.IsEmpty())
{
bkey = _("Uncategorized");
}
akey += (*a)->GetName();
bkey += (*b)->GetName();
return akey.CmpNoCase(bkey);
}
/// CreateMenusAndCommands builds the menus, and also rebuilds them after
@ -866,8 +933,6 @@ void AudacityProject::CreateMenusAndCommands()
wxArrayString defaults;
PluginManager & pm = PluginManager::Get();
const PluginDescriptor *plug;
bool needsep;
//////////////////////////////////////////////////////////////////////////
// Generate Menu
@ -876,49 +941,11 @@ void AudacityProject::CreateMenusAndCommands()
c->BeginMenu(_("&Generate"));
c->SetDefaultFlags(AudioIONotBusyFlag, AudioIONotBusyFlag);
typedef std::set<const PluginDescriptor *, bool (*)(const PluginDescriptor *, const PluginDescriptor *)> SortedPlugs;
SortedPlugs defaultplugs(SortPlugs);
SortedPlugs extraplugs(SortPlugs);
#ifndef EFFECT_CATEGORIES
plug = pm.GetFirstPluginForEffectType(EffectTypeGenerate);
while (plug) {
if (plug->IsEffectDefault()) {
defaultplugs.insert(plug);
}
else {
extraplugs.insert(plug);
}
plug = pm.GetNextPluginForEffectType(EffectTypeGenerate);
}
for (SortedPlugs::iterator iter = defaultplugs.begin(); iter != defaultplugs.end(); iter++)
{
const PluginDescriptor *plug = *iter;
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
int flags = plug->IsEffectRealtimeCapable() ?
AudioIONotBusyFlag :
TracksExistFlag;
#else
int flags = TracksExistFlag;
#endif
c->AddItem(plug->GetName(),
plug->GetMenuName(),
FNS(OnEffect, plug->GetID()));
}
needsep = true;
for (SortedPlugs::iterator iter = extraplugs.begin(); iter != extraplugs.end(); iter++)
{
const PluginDescriptor *plug = *iter;
if (needsep) {
c->AddSeparator();
needsep = false;
}
c->AddItem(plug->GetName(),
plug->GetMenuName(),
FNS(OnEffect, plug->GetID()));
}
PopulateEffectsMenu(c,
EffectTypeGenerate,
AudioIONotBusyFlag,
AudioIONotBusyFlag);
#else
int flags;
@ -981,57 +1008,10 @@ void AudacityProject::CreateMenusAndCommands()
// effects at all in the menu when EFFECT_CATEGORIES is undefined
#ifndef EFFECT_CATEGORIES
defaultplugs.clear();
extraplugs.clear();
plug = pm.GetFirstPluginForEffectType(EffectTypeProcess);
while (plug) {
if (plug->IsEffectDefault()) {
defaultplugs.insert(plug);
}
else {
extraplugs.insert(plug);
}
plug = pm.GetNextPluginForEffectType(EffectTypeProcess);
}
for (SortedPlugs::iterator iter = defaultplugs.begin(); iter != defaultplugs.end(); iter++)
{
const PluginDescriptor *plug = *iter;
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
int flags = plug->IsEffectRealtimeCapable() ?
TracksExistFlag :
AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag;
#else
int flags = AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag;
#endif
c->AddItem(plug->GetName(),
plug->GetMenuName(),
FNS(OnEffect, plug->GetID()),
flags,
flags);
}
needsep = true;
for (SortedPlugs::iterator iter = extraplugs.begin(); iter != extraplugs.end(); iter++)
{
const PluginDescriptor *plug = *iter;
if (needsep) {
c->AddSeparator();
needsep = false;
}
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
int flags = plug->IsEffectRealtimeCapable() ?
TracksExistFlag :
AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag;
#else
int flags = AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag;
#endif
c->AddItem(plug->GetName(),
plug->GetMenuName(),
FNS(OnEffect, plug->GetID()),
flags,
flags);
}
PopulateEffectsMenu(c,
EffectTypeProcess,
AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag,
TracksExistFlag);
#else
int flags = PROCESS_EFFECT | BUILTIN_EFFECT | PLUGIN_EFFECT | ADVANCED_EFFECT;
// The categories form a DAG, so we start at the roots (the categories
@ -1075,57 +1055,10 @@ void AudacityProject::CreateMenusAndCommands()
AudioIONotBusyFlag | WaveTracksSelectedFlag | TimeSelectedFlag);
#ifndef EFFECT_CATEGORIES
defaultplugs.clear();
extraplugs.clear();
plug = pm.GetFirstPluginForEffectType(EffectTypeAnalyze);
while (plug) {
if (plug->IsEffectDefault()) {
defaultplugs.insert(plug);
}
else {
extraplugs.insert(plug);
}
plug = pm.GetNextPluginForEffectType(EffectTypeAnalyze);
}
for (SortedPlugs::iterator iter = defaultplugs.begin(); iter != defaultplugs.end(); iter++)
{
const PluginDescriptor *plug = *iter;
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
int flags = plug->IsEffectRealtimeCapable() ?
TracksExistFlag :
AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag;
#else
int flags = AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag;
#endif
c->AddItem(plug->GetName(),
plug->GetMenuName(),
FNS(OnEffect, plug->GetID()),
flags,
flags);
}
needsep = true;
for (SortedPlugs::iterator iter = extraplugs.begin(); iter != extraplugs.end(); iter++)
{
const PluginDescriptor *plug = *iter;
if (needsep) {
c->AddSeparator();
needsep = false;
}
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
int flags = plug->IsEffectRealtimeCapable() ?
TracksExistFlag :
AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag;
#else
int flags = AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag;
#endif
c->AddItem(plug->GetName(),
plug->GetMenuName(),
FNS(OnEffect, plug->GetID()),
flags,
flags);
}
PopulateEffectsMenu(c,
EffectTypeAnalyze,
AudioIONotBusyFlag | TimeSelectedFlag | WaveTracksSelectedFlag,
TracksExistFlag);
#else
flags = ANALYZE_EFFECT | BUILTIN_EFFECT | PLUGIN_EFFECT;
@ -1326,6 +1259,231 @@ void AudacityProject::CreateMenusAndCommands()
#endif
}
void AudacityProject::PopulateEffectsMenu(CommandManager* c,
EffectType type,
int batchflags,
int realflags)
{
PluginManager & pm = PluginManager::Get();
EffectPlugs defplugs;
EffectPlugs optplugs;
const PluginDescriptor *plug = pm.GetFirstPluginForEffectType(type);
while (plug)
{
if (plug->IsEffectDefault())
{
defplugs.Add(plug);
}
else
{
optplugs.Add(plug);
}
plug = pm.GetNextPluginForEffectType(type);
}
wxString groupby = gPrefs->Read(wxT("/Effects/GroupBy"), wxT("default"));
if (groupby == wxT("default"))
{
defplugs.Sort(SortPlugsByDefault);
optplugs.Sort(SortPlugsByDefault);
}
else if (groupby == wxT("publisher"))
{
defplugs.Sort(SortPlugsByPublisher);
optplugs.Sort(SortPlugsByPublisher);
}
else if (groupby == wxT("family"))
{
defplugs.Sort(SortPlugsByFamily);
optplugs.Sort(SortPlugsByFamily);
}
else // name
{
defplugs.Sort(SortPlugsByName);
optplugs.Sort(SortPlugsByName);
}
AddEffectMenuItems(c, defplugs, batchflags, realflags);
if (optplugs.GetCount())
{
c->AddSeparator();
}
AddEffectMenuItems(c, optplugs, batchflags, realflags);
return;
}
void AudacityProject::AddEffectMenuItems(CommandManager *c,
EffectPlugs & plugs,
int batchflags,
int realflags)
{
size_t pluginCnt = plugs.GetCount();
int perGroup;
#if defined(__WXGTK__)
gPrefs->Read(wxT("/Effects/MaxPerGroup"), &perGroup, 15);
#else
gPrefs->Read(wxT("/Effects/MaxPerGroup"), &perGroup, 0);
#endif
wxString groupBy = gPrefs->Read(wxT("/Effects/GroupBy"), wxT("default"));
bool grouped = true;
if (groupBy == wxT("default") || groupBy == wxT("name"))
{
grouped = false;
}
wxString last;
wxArrayString groupNames;
PluginIDList groupPlugs;
for (size_t i = 0; i < pluginCnt; i++)
{
const PluginDescriptor *plug = plugs[i];
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
if (plug->GetName() == wxT("Cross Fade In"))
{
int f = 1;
}
int flags = plug->IsEffectRealtimeCapable() ? realflags : batchflags;
#else
int flags = batchflags;
#endif
wxString name = plug->GetName();
wxString stripped;
if (name.EndsWith(wxT("..."), &stripped))
{
name = stripped;
}
if (plug->IsEffectInteractive())
{
name += wxT("...");
}
wxString current;
if (groupBy == wxT("default"))
{
current = plug->GetVendor();
if (plug->IsEffectDefault())
{
current = wxEmptyString;
}
if (!current.IsEmpty())
{
current += wxT(": ");
}
current += name;
name = current;
}
else if (groupBy == wxT("publisher"))
{
current = plug->GetVendor();
if (current.IsEmpty())
{
current = wxT("unknown");
}
}
else if (groupBy == wxT("family"))
{
current = plug->GetEffectFamily();
if (current.IsEmpty())
{
current = wxT("unknown");
}
}
else // name
{
current = plug->GetName();
name = current;
}
if (current != last || i + 1 == pluginCnt)
{
if (i + 1 == pluginCnt)
{
groupNames.Add(name);
groupPlugs.Add(plug->GetID());
}
size_t groupCnt = groupPlugs.GetCount();
if (grouped && groupCnt > 0 && i > 0)
{
c->BeginSubMenu(last);
}
if (grouped || i + 1 == pluginCnt)
{
int max = perGroup;
int items = perGroup;
if (max > groupCnt)
{
max = 0;
}
for (size_t j = 0; j < groupCnt; j++)
{
if (max > 0 && items == max)
{
int end = j + 1 + max;
if (end > groupCnt)
{
end = groupCnt;
}
c->BeginSubMenu(wxString::Format(_("Plug-ins %d to %d"),
j + 1,
end));
}
c->AddItem(groupNames[j],
groupNames[j],
FNS(OnEffect, groupPlugs[j]),
flags,
flags);
if (max > 0)
{
items--;
if (items == 0 || j + 1 == groupCnt)
{
c->EndSubMenu();
items = max;
}
}
}
}
if (grouped && groupCnt > 0 && i > 0)
{
c->EndSubMenu();
groupNames.Clear();
groupPlugs.Clear();
}
last = current;
}
groupNames.Add(name);
groupPlugs.Add(plug->GetID());
}
return;
}
#ifdef EFFECT_CATEGORIES
EffectSet AudacityProject::CreateEffectSubmenus(CommandManager* c,

View File

@ -38,6 +38,8 @@ void AddEffectsToMenu(CommandManager* c, const EffectSet& effects);
#endif
void PopulateEffectsMenu(CommandManager *c, EffectType type, int batchflags, int realflags);
void AddEffectMenuItems(CommandManager *c, EffectPlugs & plugs, int batchflags, int realflags);
void CreateRecentFilesMenu(CommandManager *c);
void ModifyUndoMenuItems();
void ModifyToolbarMenus();

View File

@ -1289,21 +1289,17 @@ PluginManager & PluginManager::Get()
void PluginManager::Initialize()
{
bool loaded = Load();
ModuleManager::Get().EarlyInit();
if (!loaded)
{
PluginRegistrationDialog dlg;
dlg.ShowModal();
}
ModuleManager::Get().EarlyInit();
CheckForUpdates();
bool doRescan;
gPrefs->Read(wxT("/VST/Rescan"), &doRescan, true);
if (doRescan)
gPrefs->Read(wxT("/Plugins/Rescan"), &doRescan, true);
if (!loaded || doRescan)
{
gPrefs->Write(wxT("/VST/Rescan"), false);
gPrefs->Write(wxT("/Plugins/Rescan"), false);
PluginRegistrationDialog dlg;
dlg.ShowModal();
}

View File

@ -54,6 +54,7 @@ class ODLock;
class RecordingRecoveryHandler;
class TrackList;
class Tags;
class EffectPlugs;
class TrackPanel;
class FreqWindow;

View File

@ -215,7 +215,7 @@ wxString Effect::GetVendor()
return mClient->GetVendor();
}
return wxEmptyString;
return _("Audacity");
}
wxString Effect::GetVersion()
@ -245,7 +245,7 @@ wxString Effect::GetFamily()
return mClient->GetFamily();
}
return wxT("Legacy");
return _("Audacity");
}
bool Effect::IsDefault()

View File

@ -97,33 +97,53 @@ void EffectsPrefs::PopulateOrExchange(ShuttleGui & S)
}
S.EndStatic();
#if USE_AUDIO_UNITS
S.StartStatic(_("Audio Unit Effects"));
S.StartStatic(_("Effect Options"));
{
S.TieCheckBox(_("Display Audio Unit effects in Graphical Mode"),
wxT("/AudioUnits/GUI"),
true);
#if 0
S.TieCheckBox(_("Rescan VST effects next time Audacity is started"),
wxT("/VST/Rescan"),
false);
#endif
}
S.EndStatic();
#endif
S.StartMultiColumn(2);
{
wxArrayString visualgroups;
wxArrayString prefsgroups;
#if USE_VST
S.StartStatic(_("VST Effects"));
{
S.TieCheckBox(_("&Display VST effects in Graphical Mode"),
wxT("/VST/GUI"),
visualgroups.Add(_("Publisher: Effect Name"));
visualgroups.Add(_("Name"));
visualgroups.Add(_("Publisher"));
visualgroups.Add(_("Type (Internal, Ladspa, VST, etc.)"));
prefsgroups.Add(wxT("default"));
prefsgroups.Add(wxT("name"));
prefsgroups.Add(wxT("publisher"));
prefsgroups.Add(wxT("family"));
S.TieChoice(_("Group effects in menus by:"),
wxT("/Effects/GroupBy"),
wxT("default"),
visualgroups,
prefsgroups);
S.TieNumericTextBox(_("Maximum effects per group (0 to disable):"),
wxT("/Effects/MaxPerGroup"),
0,
5);
}
S.EndMultiColumn();
S.AddSpace(5);
S.TieCheckBox(_("Display effects in graphical mode when supported"),
wxT("/Effects/GUI"),
true);
S.TieCheckBox(_("&Rescan VST effects next time Audacity is started"),
wxT("/VST/Rescan"),
}
S.EndStatic();
S.StartStatic(_("Plugin Options"));
{
S.TieCheckBox(_("Check for updated plugins when Audacity starts"),
wxT("/Plugins/CheckForUpdates"),
true);
S.TieCheckBox(_("Rescan plugins next time Audacity is started"),
wxT("/Plugins/Rescan"),
false);
}
S.EndStatic();
#endif
#ifdef EXPERIMENTAL_EQ_SSE_THREADED
S.StartStatic(_("Instruction Set"));