Browse Source

Another round of effects bashing.

I've added some of the new plugin stuff to LV2, Nyquist, and
Vamp so that they play better in the new system.  They no
longer get bunched in with the Audacity effects when sorting
or grouping the menus.  They have not been fully converted
but they should be good for 2.1.0.

Nyquist plugins now include ";author" and ";copyright"
statements.

Added the 4 new Nyquist plugins to the Windows build.

Audiounits are still coming...had to push them to the back
burner to get this other stuff out of the way.

Scanning for new plugins has been improved so that newly
discovered ones will be shown to the user when Audacity starts.

Effects menu sorting has been fixed and improved.

Disabling effect types in Preferences works again and you
no longer have to restart Audacity for them the change to work.

Effect usage in chains works again.

Plugin registration dialog code simplified a bit.

Group names in the pluginregistry are now base64 encoded.  I
never really thought about it, but wxFileConfig group names
are case insensitive and since I was using the group name as
the plugin ID, I ran into a conflict on Linux where there
were two plugins with the same name, just different case.  (And
they were different plugins.)  Hoping all of this will change
when/if the config file gets converted to XML.  (wx3 if finally
including XML support)

A fair amount of cleanup of this new code has been done and
will continue as more stuff is converted.
mac-2.1.1-vi
lllucius 8 years ago
parent
commit
41083f74cc
  1. 2
      include/audacity/EffectAutomationParameters.h
  2. 6
      include/audacity/ModuleInterface.h
  3. 68
      include/audacity/Types.h
  4. 2
      plug-ins/SilenceMarker.ny
  5. 3
      plug-ins/SoundFinder.ny
  6. 2
      plug-ins/SpectralEditMulti.ny
  7. 2
      plug-ins/SpectralEditParametricEQ.ny
  8. 2
      plug-ins/SpectralEditShelves.ny
  9. 2
      plug-ins/StudioFadeOut.ny
  10. 2
      plug-ins/adjustable-fade.ny
  11. 2
      plug-ins/beat.ny
  12. 2
      plug-ins/clicktrack.ny
  13. 2
      plug-ins/clipfix.ny
  14. 3
      plug-ins/crossfadein.ny
  15. 3
      plug-ins/crossfadeout.ny
  16. 2
      plug-ins/delay.ny
  17. 2
      plug-ins/equalabel.ny
  18. 2
      plug-ins/highpass.ny
  19. 2
      plug-ins/lowpass.ny
  20. 2
      plug-ins/notch.ny
  21. 2
      plug-ins/pluck.ny
  22. 2
      plug-ins/rissetdrum.ny
  23. 2
      plug-ins/sample-data-export.ny
  24. 2
      plug-ins/tremolo.ny
  25. 2
      plug-ins/vocalremover.ny
  26. 2
      plug-ins/vocoder.ny
  27. 2
      src/AudacityApp.cpp
  28. 1
      src/BatchCommandDialog.cpp
  29. 4
      src/BatchCommands.cpp
  30. 304
      src/Menus.cpp
  31. 1
      src/Menus.h
  32. 138
      src/ModuleManager.cpp
  33. 10
      src/ModuleManager.h
  34. 567
      src/PluginManager.cpp
  35. 36
      src/PluginManager.h
  36. 23
      src/effects/Effect.cpp
  37. 19
      src/effects/EffectManager.cpp
  38. 1
      src/effects/EffectManager.h
  39. 4
      src/effects/EffectRack.cpp
  40. 35
      src/effects/LoadEffects.cpp
  41. 6
      src/effects/VST/VSTEffect.cpp
  42. 2
      src/effects/VST/VSTEffect.h
  43. 25
      src/effects/ladspa/LadspaEffect.cpp
  44. 2
      src/effects/ladspa/LadspaEffect.h
  45. 97
      src/effects/lv2/LV2Effect.cpp
  46. 23
      src/effects/lv2/LV2Effect.h
  47. 223
      src/effects/lv2/LoadLV2.cpp
  48. 46
      src/effects/lv2/LoadLV2.h
  49. 175
      src/effects/nyquist/LoadNyquist.cpp
  50. 45
      src/effects/nyquist/LoadNyquist.h
  51. 1143
      src/effects/nyquist/Nyquist.cpp
  52. 47
      src/effects/nyquist/Nyquist.h
  53. 222
      src/effects/vamp/LoadVamp.cpp
  54. 47
      src/effects/vamp/LoadVamp.h
  55. 85
      src/effects/vamp/VampEffect.cpp
  56. 24
      src/effects/vamp/VampEffect.h
  57. 47
      src/prefs/EffectsPrefs.cpp
  58. 1
      src/prefs/EffectsPrefs.h
  59. 4
      win/Projects/Audacity/Audacity.vcxproj
  60. 12
      win/Projects/Audacity/Audacity.vcxproj.filters

2
include/audacity/EffectAutomationParameters.h

@ -172,6 +172,8 @@ public:
return false;
}
}
return true;
}
};

6
include/audacity/ModuleInterface.h

@ -74,7 +74,7 @@ public:
virtual void Terminate() = 0;
// Modules providing a single or static set of plugins may use
// AutoRegisterPlugins() to register those plugins.
// AutoRegisterPlugins() to register those plugins.
virtual bool AutoRegisterPlugins(PluginManagerInterface & pluginManager) = 0;
// For modules providing an interface to other dynamically loaded plugins,
@ -89,6 +89,10 @@ public:
virtual bool RegisterPlugin(PluginManagerInterface & pluginManager,
const wxString & path) = 0;
// For modules providing an interface to other dynamically loaded plugins,
// the module returns true if the plugin is still valid, otherwise false.
virtual bool IsPluginValid(const PluginID & ID, const wxString & path) = 0;
// When appropriate, CreateInstance() will be called to instantiate the plugin.
virtual IdentInterface *CreateInstance(const PluginID & ID, const wxString & path) = 0;

68
include/audacity/Types.h

@ -122,9 +122,69 @@ typedef enum
ChannelNameBottomFrontRight,
} ChannelName;
// ----------------------------------------------------------------------------
// Convenience macro to suppress unused parameter warnings
// ----------------------------------------------------------------------------
#define AUNUSED(p)
// LLL FIXME: Until a complete API is devised, we have to use
// AUDACITY_DLL_API when defining API classes. This
// it ugly, but a part of the game. Remove it when
// the API is complete.
#if !defined(AUDACITY_DLL_API)
// This was copied from "Audacity.h" so these headers wouldn't have
// to include it.
/* Magic for dynamic library import and export. This is unfortunately
* compiler-specific because there isn't a standard way to do it. Currently it
* works with the Visual Studio compiler for windows, and for GCC 4+. Anything
* else gets all symbols made public, which gets messy */
/* The Visual Studio implementation */
#ifdef _MSC_VER
#ifndef AUDACITY_DLL_API
#ifdef BUILDING_AUDACITY
#define AUDACITY_DLL_API _declspec(dllexport)
#else
#ifdef _DLL
#define AUDACITY_DLL_API _declspec(dllimport)
#else
#define AUDACITY_DLL_API
#endif
#endif
#endif
#endif //_MSC_VER
#ifdef __GNUC__
#include "configunix.h"
#endif
/* The GCC-elf implementation */
#ifdef HAVE_VISIBILITY // this is provided by the configure script, is only
// enabled for suitable GCC versions
/* The incantation is a bit weird here because it uses ELF symbol stuff. If we
* make a symbol "default" it makes it visible (for import or export). Making it
* "hidden" means it is invisible outside the shared object. */
#ifndef AUDACITY_DLL_API
#ifdef BUILDING_AUDACITY
#define AUDACITY_DLL_API __attribute__((visibility("default")))
#else
#define AUDACITY_DLL_API __attribute__((visibility("default")))
#endif
#endif
#endif
/* The GCC-win32 implementation */
// bizzarely, GCC-for-win32 supports Visual Studio style symbol visibility, so
// we use that if building on Cygwin
#if defined __CYGWIN__ && defined __GNUC__
#ifndef AUDACITY_DLL_API
#ifdef BUILDING_AUDACITY
#define AUDACITY_DLL_API _declspec(dllexport)
#else
#ifdef _DLL
#define AUDACITY_DLL_API _declspec(dllimport)
#else
#define AUDACITY_DLL_API
#endif
#endif
#endif
#endif
#endif
#endif // __AUDACITY_TYPES_H__

2
plug-ins/SilenceMarker.ny

@ -5,6 +5,8 @@
;name "Silence Finder..."
;action "Finding silence..."
;info "Adds point labels in areas of silence according to the specified\nlevel and duration of silence. If too many silences are detected,\nincrease the silence level and duration; if too few are detected,\nreduce the level and duration."
;author "Alex S. Brown"
;copyright "Released under terms of the GNU General Public License version 2"
;; by Alex S. Brown, PMP (http://www.alexsbrown.com)
;; Released under terms of the GNU General Public License version 2:

3
plug-ins/SoundFinder.ny

@ -5,7 +5,8 @@
;name "Sound Finder..."
;action "Finding sound..."
;info "Adds region labels for areas of sound according to the specified level\nand duration of surrounding silence. If too many labels are produced,\nincrease the silence level and duration; if too few are produced,\nreduce the level and duration."
;author "Jeremy R. Brown"
;copyright "Released under terms of the GNU General Public License version 2"
;; by Jeremy R. Brown (http://www.jeremy-brown.com/)
;; based on the Silence Finder script by Alex S. Brown (http://www.alexsbrown.com)

2
plug-ins/SpectralEditMulti.ny

@ -3,6 +3,8 @@
;type process
;name "Spectral edit multi tool"
;action "Calculating..."
;author "Paul Licameli"
;copyright "Unknown"
(defun wet (sig)
(cond

2
plug-ins/SpectralEditParametricEQ.ny

@ -3,6 +3,8 @@
;type process
;name "Spectral edit parametric EQ..."
;action "Calculating..."
;author "Paul Licameli"
;copyright "Unknown"
;control control-gain "Gain (dB)" real "" 0 -24 24

2
plug-ins/SpectralEditShelves.ny

@ -3,6 +3,8 @@
;type process
;name "Spectral edit shelves..."
;action "Calculating..."
;author "Paul Licameli"
;copyright "Unknown"
;control control-gain "Gain (dB)" real "" 0 -24 24

2
plug-ins/StudioFadeOut.ny

@ -4,6 +4,8 @@
;categories "http://lv2plug.in/ns/lv2core#MixerPlugin"
;name "Studio Fade Out"
;action "Applying Fade..."
;author "Steve Daulton"
;copyright "Released under terms of the GNU General Public License version 2"
;; StudioFadeOut.ny by Steve Daulton December 2012.
;; Released under terms of the GNU General Public License version 2:

2
plug-ins/adjustable-fade.ny

@ -4,6 +4,8 @@
;categories "http://lv2plug.in/ns/lv2core#MixerPlugin"
;name "Adjustable Fade..."
;action "Applying Fade..."
;author "Steve Daulton"
;copyright "Released under terms of the GNU General Public License version 2"
;; adjustable-fade.ny by Steve Daulton Dec 2012
;; Released under terms of the GNU General Public License version 2:

2
plug-ins/beat.ny

@ -4,6 +4,8 @@
;categories "http://audacityteam.org/namespace#OnsetDetector"
;name "Beat Finder..."
;action "Finding beats..."
;author "Audacity"
;copyright "Released under terms of the GNU General Public License version 2"
;; Released under terms of the GNU General Public License version 2:
;; http://www.gnu.org/licenses/old-licenses/gpl-2.0.html

2
plug-ins/clicktrack.ny

@ -5,6 +5,8 @@
;name "Click Track..."
;action "Generating Click Track..."
;info "For help, select one of two help screens in 'Action choice' below."
;author "Dominic Mazzoni"
;copyright "Released under terms of the GNU General Public License version 2"
;; by Dominic Mazzoni, modified by David R. Sky and Steve Daulton.
;; Released under terms of the GNU General Public License version 2:

2
plug-ins/clipfix.ny

@ -5,6 +5,8 @@
;categories "http://audacityteam.org/namespace#NoiseRemoval"
;name "Clip Fix..."
;action "Reconstructing clips..."
;author "Benjamin Schwartz"
;copyright "Licensing confirmed under terms of the GNU General Public License version 2"
;; clipfix.ny by Benjamin Schwartz.
;; Licensing confirmed under terms of the GNU General Public License version 2:

3
plug-ins/crossfadein.ny

@ -4,4 +4,7 @@
;categories "http://lv2plug.in/ns/lv2core#MixerPlugin"
;name "Cross Fade In"
;action "Cross-Fading In..."
;author "Audacity"
;copyright "Unknown"
(mult s (control-srate-abs *sound-srate* (s-sqrt (pwlv 0 1 1))))

3
plug-ins/crossfadeout.ny

@ -4,6 +4,9 @@
;categories "http://lv2plug.in/ns/lv2core#MixerPlugin"
;name "Cross Fade Out"
;action "Cross-Fading Out..."
;author "Audacity"
;copyright "Unknown"
(mult s (snd-exp
(snd-scale 0.5 (snd-log
(sum 1 (snd-scale -1 (ramp)))))))

2
plug-ins/delay.ny

@ -5,6 +5,8 @@
;categories "http://lv2plug.in/ns/lv2core#DelayPlugin"
;name "Delay..."
;action "Applying Delay Effect..."
;author "Steve Daulton"
;copyright "Released under terms of the GNU General Public License version 2"
;; by Steve Daulton, July 2012.
;; based on 'Delay' by David R. Sky

2
plug-ins/equalabel.ny

@ -3,6 +3,8 @@
;type analyze
;name "Regular Interval Labels..."
;action "Adding equally-spaced labels to the label track..."
;author "David R. Sky"
;copyright "Released under terms of the GNU General Public License version 2"
;; by David R. Sky (http://www.garyallendj.com/davidsky/), June-October 2007.
;; Code for label placement based on silencemarker.ny by Alex S.Brown.

2
plug-ins/highpass.ny

@ -5,6 +5,8 @@
;categories "http://lv2plug.in/ns/lv2core#HighpassPlugin"
;name "High Pass Filter..."
;action "Performing High Pass Filter..."
;author "Dominic Mazzoni"
;copyright "Released under terms of the GNU General Public License version 2"
;; highpass.ny by Dominic Mazzoni
;; Modified by David R. Sky

2
plug-ins/lowpass.ny

@ -5,6 +5,8 @@
;categories "http://lv2plug.in/ns/lv2core#LowpassPlugin"
;name "Low Pass Filter..."
;action "Performing Low Pass Filter..."
;author "Dominic Mazzoni"
;copyright "Released under terms of the GNU General Public License version 2"
;; lowpass.ny by Dominic Mazzoni
;; Modified by David R. Sky

2
plug-ins/notch.ny

@ -5,6 +5,8 @@
;categories "http://lv2plug.in/ns/lv2core/#FilterPlugin"
;name "Notch Filter..."
;action "Performing Notch Filter..."
;author "Steve Daulton and Bill Wharrie"
;copyright "Released under terms of the GNU General Public License version 2"
;control freq "Frequency" real "Hz" 60 0 10000
;control q "Q (higher value reduces width)" real "" 1 0.1 20

2
plug-ins/pluck.ny

@ -6,6 +6,8 @@
;name "Pluck..."
;action "Generating pluck sound..."
;info "MIDI values for C notes: 36, 48, 60 [middle C], 72, 84, 96."
;author "David R.Sky"
;copyright "Released under terms of the GNU General Public License version 2"
;; Released under terms of the GNU General Public License version 2:
;; http://www.gnu.org/licenses/old-licenses/gpl-2.0.html .

2
plug-ins/rissetdrum.ny

@ -4,6 +4,8 @@
;categories "http://lv2plug.in/ns/lv2core#GeneratorPlugin"
;name "Risset Drum..."
;action "Generating Risset Drum..."
;author "Steven Jones"
;copyright "Released under terms of the GNU General Public License version 2"
;; rissetdrum.ny by Steven Jones, after Jean Claude Risset.
;; Updated by Steve Daulton July 2012.

2
plug-ins/sample-data-export.ny

@ -4,6 +4,8 @@
;name "Sample Data Export..."
;action "Analyzing..."
;categories "http://lv2plug.in/ns/lv2core#AnalyserPlugin"
;author "Steve Daulton"
;copyright "Released under terms of the GNU General Public License version 2"
;; sample-data-export.ny by Steve Daulton June 2012.
;; Updated July 16 2012.

2
plug-ins/tremolo.ny

@ -5,6 +5,8 @@
;categories "http://lv2plug.in/ns/lv2core#ModulatorPlugin"
;name "Tremolo..."
;action "Applying Tremolo..."
;author "Steve Daulton"
;copyright "Released under terms of the GNU General Public License version 2"
;; tremolo.ny by Steve Daulton (www.easyspacepro.com) July 2012.
;; Based on Tremolo by Dominic Mazzoni and David R. Sky."

2
plug-ins/vocalremover.ny

@ -6,6 +6,8 @@
;name "Vocal Remover..."
;action "Removing center-panned audio..."
;info "For reducing center-panned vocals"
;author "Steve Daulton"
;copyright "Released under terms of the GNU General Public License version 2"
;; This version of vocalremover.ny by Steve Daulton June 2013.
;;

2
plug-ins/vocoder.ny

@ -5,6 +5,8 @@
;categories "http://lv2plug.in/ns/lv2core#SpectralPlugin"
;name "Vocoder..."
;action "Processing Vocoder..."
;author "Edgar-RFT"
;copyright "Released under terms of the GNU General Public License version 2"
;; vocoder.ny by Edgar-RFT
;; a bit of code added by David R. Sky

2
src/AudacityApp.cpp

@ -17,7 +17,7 @@ It handles initialization and termination by subclassing wxApp.
#if 0
// This may be used to debug memory leaks.
// See: Visual Leak Dectector @ http://dmoulding.googlepages.com/vld
// See: Visual Leak Dectector @ http://vld.codeplex.com/
#include <vld.h>
#endif

1
src/BatchCommandDialog.cpp

@ -177,6 +177,7 @@ void BatchCommandDialog::OnEditParams(wxCommandEvent & WXUNUSED(event))
{
wxString command = mCommand->GetValue();
wxString params = mParameters->GetValue();
if (BatchCommands::SetCurrentParametersFor( command, params ))
{
if( BatchCommands::PromptForParamsFor( command, this ))

4
src/BatchCommands.cpp

@ -288,12 +288,14 @@ wxArrayString BatchCommands::GetAllCommands()
command = em.GetEffectIdentifier(plug->GetID());
if (!command.IsEmpty())
{
commands.Add( command);
commands.Add(command);
}
}
plug = pm.GetNextPlugin(PluginTypeEffect);
}
commands.Sort();
/* This is for later in development: include the menu commands.
CommandManager * mManager = project->GetCommandManager();
wxArrayString mNames;

304
src/Menus.cpp

@ -264,7 +264,36 @@ static int SortEffectsByPublisherAndName(const PluginDescriptor **a, const Plugi
return akey.CmpNoCase(bkey);
}
static int SortEffectsByFamily(const PluginDescriptor **a, const PluginDescriptor **b)
static int SortEffectsByTypeAndName(const PluginDescriptor **a, const PluginDescriptor **b)
{
wxString akey = (*a)->GetEffectFamily();
wxString bkey = (*b)->GetEffectFamily();
if (akey.IsEmpty())
{
akey = _("Uncategorized");
}
if (bkey.IsEmpty())
{
bkey = _("Uncategorized");
}
if ((*a)->IsEffectDefault())
{
akey = wxEmptyString;
}
if ((*b)->IsEffectDefault())
{
bkey = wxEmptyString;
}
akey += (*a)->GetName();
bkey += (*b)->GetName();
return akey.CmpNoCase(bkey);
}
static int SortEffectsByType(const PluginDescriptor **a, const PluginDescriptor **b)
{
wxString akey = (*a)->GetEffectFamily();
wxString bkey = (*b)->GetEffectFamily();
@ -1284,27 +1313,32 @@ void AudacityProject::PopulateEffectsMenu(CommandManager* c,
plug = pm.GetNextPluginForEffectType(type);
}
wxString groupby = gPrefs->Read(wxT("/Effects/GroupBy"), wxT("default"));
wxString groupby = gPrefs->Read(wxT("/Effects/GroupBy"), wxT("name"));
if (groupby == wxT("name"))
if (groupby == wxT("sortby:name"))
{
defplugs.Sort(SortEffectsByName);
optplugs.Sort(SortEffectsByName);
}
else if (groupby == wxT("publisher"))
else if (groupby == wxT("sortby:publisher:name"))
{
defplugs.Sort(SortEffectsByPublisher);
optplugs.Sort(SortEffectsByPublisher);
defplugs.Sort(SortEffectsByName);
optplugs.Sort(SortEffectsByPublisherAndName);
}
else if (groupby == wxT("publisher:name"))
else if (groupby == wxT("sortby:type:name"))
{
defplugs.Sort(SortEffectsByPublisherAndName);
optplugs.Sort(SortEffectsByPublisherAndName);
defplugs.Sort(SortEffectsByName);
optplugs.Sort(SortEffectsByTypeAndName);
}
else if (groupby == wxT("groupby:publisher"))
{
defplugs.Sort(SortEffectsByPublisher);
optplugs.Sort(SortEffectsByPublisher);
}
else if (groupby == wxT("family"))
else if (groupby == wxT("groupby:type"))
{
defplugs.Sort(SortEffectsByFamily);
optplugs.Sort(SortEffectsByFamily);
defplugs.Sort(SortEffectsByType);
optplugs.Sort(SortEffectsByType);
}
else // name
{
@ -1341,151 +1375,193 @@ void AudacityProject::AddEffectMenuItems(CommandManager *c,
wxString groupBy = gPrefs->Read(wxT("/Effects/GroupBy"), wxT("name"));
bool grouped = false;
if (groupBy == wxT("publisher") || groupBy == wxT("family"))
if (groupBy.StartsWith(wxT("groupby")))
{
grouped = true;
}
wxString last;
wxArrayString groupNames;
PluginIDList groupPlugs;
for (size_t i = 0; i < pluginCnt; i++)
wxArrayInt groupFlags;
if (grouped)
{
const PluginDescriptor *plug = plugs[i];
#if defined(EXPERIMENTAL_REALTIME_EFFECTS)
int flags = plug->IsEffectRealtime() ? realflags : batchflags;
#else
int flags = batchflags;
#endif
wxString name = plug->GetName();
wxString last;
wxString current;
wxString stripped;
if (name.EndsWith(wxT("..."), &stripped))
for (size_t i = 0; i < pluginCnt; i++)
{
name = stripped;
}
const PluginDescriptor *plug = plugs[i];
if (plug->IsEffectInteractive())
{
name += wxT("...");
}
wxString name = plug->GetName();
wxString current;
if (groupBy == wxT("publisher:name"))
{
current = plug->GetVendor();
if (plug->IsEffectDefault())
// This goes away once everything has been converted to new format
wxString stripped;
if (name.EndsWith(wxT("..."), &stripped))
{
current = wxEmptyString;
name = stripped;
}
if (!current.IsEmpty())
if (plug->IsEffectInteractive())
{
current += wxT(": ");
name += wxT("...");
}
current += name;
name = current;
}
else if (groupBy == wxT("publisher"))
{
current = plug->GetVendor();
if (current.IsEmpty())
if (groupBy == wxT("groupby:publisher"))
{
current = _("Unknown");
current = plug->GetVendor();
if (current.IsEmpty())
{
current = _("Unknown");
}
}
}
else if (groupBy == wxT("family"))
{
current = plug->GetEffectFamily();
if (current.IsEmpty())
else if (groupBy == wxT("groupby:type"))
{
current = _("Unknown");
current = plug->GetEffectFamily();
if (current.IsEmpty())
{
current = _("Unknown");
}
}
if (current != last)
{
if (!last.IsEmpty())
{
c->BeginSubMenu(last);
}
AddEffectMenuItemGroup(c, groupNames, groupPlugs, groupFlags);
if (!last.IsEmpty())
{
c->EndSubMenu();
}
groupNames.Clear();
groupPlugs.Clear();
groupFlags.Clear();
last = current;
}
groupNames.Add(name);
groupPlugs.Add(plug->GetID());
groupFlags.Add(plug->IsEffectRealtime() ? realflags : batchflags);
}
else if (groupBy == wxT("name"))
if (groupNames.GetCount() > 0)
{
current = plug->GetName();
name = current;
c->BeginSubMenu(current);
AddEffectMenuItemGroup(c, groupNames, groupPlugs, groupFlags);
c->EndSubMenu();
}
else // default to "name"
}
else
{
for (size_t i = 0; i < pluginCnt; i++)
{
current = plug->GetName();
name = current;
}
const PluginDescriptor *plug = plugs[i];
if (current != last || i + 1 == pluginCnt)
{
if (i + 1 == pluginCnt)
wxString name = plug->GetName();
// This goes away once everything has been converted to new format
wxString stripped;
if (name.EndsWith(wxT("..."), &stripped))
{
groupNames.Add(name);
groupPlugs.Add(plug->GetID());
name = stripped;
}
int groupCnt = (int) groupPlugs.GetCount();
if (plug->IsEffectInteractive())
{
name += wxT("...");
}
if (grouped && groupCnt > 0 && i > 0)
wxString group = wxEmptyString;
if (groupBy == wxT("sortby:publisher:name"))
{
group = plug->GetVendor();
}
else if (groupBy == wxT("sortby:type:name"))
{
c->BeginSubMenu(last);
group = plug->GetEffectFamily();
}
if (grouped || i + 1 == pluginCnt)
if (plug->IsEffectDefault())
{
int max = perGroup;
int items = perGroup;
group = wxEmptyString;
}
if (max > groupCnt)
{
max = 0;
}
if (!group.IsEmpty())
{
group += wxT(": ");
}
for (int j = 0; j < groupCnt; j++)
{
if (max > 0 && items == max)
{
int end = j + max;
if (end + 1 > groupCnt)
{
end = groupCnt;
}
c->BeginSubMenu(wxString::Format(_("Plug-ins %d to %d"),
j + 1,
end));
}
groupNames.Add(group + name);
groupPlugs.Add(plug->GetID());
groupFlags.Add(plug->IsEffectRealtime() ? realflags : batchflags);
}
if (groupNames.GetCount() > 0)
{
AddEffectMenuItemGroup(c, groupNames, groupPlugs, groupFlags);
}
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;
}
}
}
}
return;
}
void AudacityProject::AddEffectMenuItemGroup(CommandManager *c,
const wxArrayString & names,
const PluginIDList & plugs,
const wxArrayInt & flags)
{
int groupCnt = (int) names.GetCount();
int perGroup;
#if defined(__WXGTK__)
gPrefs->Read(wxT("/Effects/MaxPerGroup"), &perGroup, 15);
#else
gPrefs->Read(wxT("/Effects/MaxPerGroup"), &perGroup, 0);
#endif
int max = perGroup;
int items = perGroup;
if (max > groupCnt)
{
max = 0;
}
for (int j = 0; j < groupCnt; j++)
{
if (max > 0 && items == max)
{
int end = j + max;
if (end + 1 > groupCnt)
{
end = groupCnt;
}
c->BeginSubMenu(wxString::Format(_("Plug-ins %d to %d"),
j + 1,
end));
}
if (grouped && groupCnt > 0 && i > 0)
c->AddItem(names[j],
names[j],
FNS(OnEffect, plugs[j]),
flags[j],
flags[j]);
if (max > 0)
{
items--;
if (items == 0 || j + 1 == groupCnt)
{
c->EndSubMenu();
groupNames.Clear();
groupPlugs.Clear();
items = max;
}
last = current;
}
groupNames.Add(name);
groupPlugs.Add(plug->GetID());
}
return;

1
src/Menus.h

@ -40,6 +40,7 @@ void AddEffectsToMenu(CommandManager* c, const EffectSet& effects);
void PopulateEffectsMenu(CommandManager *c, EffectType type, int batchflags, int realflags);
void AddEffectMenuItems(CommandManager *c, EffectPlugs & plugs, int batchflags, int realflags);
void AddEffectMenuItemGroup(CommandManager *c, const wxArrayString & names, const PluginIDList & plugs, const wxArrayInt & flags);
void CreateRecentFilesMenu(CommandManager *c);
void ModifyUndoMenuItems();
void ModifyToolbarMenus();

138
src/ModuleManager.cpp

@ -18,6 +18,7 @@ i.e. an alternative to the usual interface, for Audacity.
*//*******************************************************************/
#include <wx/dynarray.h>
#include <wx/dynlib.h>
#include <wx/list.h>
#include <wx/log.h>
@ -44,6 +45,8 @@ i.e. an alternative to the usual interface, for Audacity.
#include "ModuleManager.h"
#include "widgets/MultiDialog.h"
#include <wx/arrimpl.cpp>
#define initFnName "ExtensionModuleInit"
#define versionFnName "GetVersionString"
#define scriptFnName "RegScriptServerFunc"
@ -182,9 +185,12 @@ static wxArrayPtrVoid *pBuiltinModuleList = NULL;
void RegisterBuiltinModule(ModuleMain moduleMain)
{
if (pBuiltinModuleList == NULL)
{
pBuiltinModuleList = new wxArrayPtrVoid;
}
pBuiltinModuleList->Add((void *)moduleMain);
return;
}
@ -205,14 +211,17 @@ ModuleManager::~ModuleManager()
}
mModules.Clear();
for (ModuleMap::iterator iter = mDynModules.begin(); iter != mDynModules.end(); iter++)
ModuleMap::iterator iter = mDynModules.begin();
while (iter != mDynModules.end())
{
ModuleInterface *mod = iter->second;
delete mod;
UnloadModule(iter->second);
iter = mDynModules.begin();
}
mDynModules.clear();
if( pBuiltinModuleList != NULL )
if (pBuiltinModuleList != NULL)
{
delete pBuiltinModuleList;
}
}
// static
@ -352,38 +361,10 @@ ModuleManager & ModuleManager::Get()
return mInstance;
}
void ModuleManager::InitializeBuiltins()
{
PluginManager & pm = PluginManager::Get();
if (pBuiltinModuleList==NULL)
return;
for (size_t i = 0, cnt = pBuiltinModuleList->GetCount(); i < cnt; i++)
{
ModuleMain audacityMain = (ModuleMain) (*pBuiltinModuleList)[i];
ModuleInterface *module = audacityMain(this, NULL);
mDynModules[module->GetID()] = module;
module->Initialize();
// First, we need to remember it
pm.RegisterModulePlugin(module);
// Now, allow the module to auto-register children
module->AutoRegisterPlugins(pm);
}
}
// static
void ModuleManager::EarlyInit()
bool ModuleManager::DiscoverProviders()
{
InitializeBuiltins();
}
bool ModuleManager::DiscoverProviders(wxArrayString & providers)
{
wxArrayString provList;
wxArrayString pathList;
@ -407,31 +388,43 @@ bool ModuleManager::DiscoverProviders(wxArrayString & providers)
wxGetApp().FindFilesInPathList(wxT("*.so"), pathList, provList);
#endif
PluginManager & pm = PluginManager::Get();
for (int i = 0, cnt = provList.GetCount(); i < cnt; i++)
{
providers.push_back(provList[i]);
ModuleInterface *module = LoadModule(provList[i]);
if (module)
{
// First, we need to remember it
pm.RegisterModulePlugin(module);
// Now, allow the module to auto-register children
module->AutoRegisterPlugins(pm);
}
}
return true;
}
bool ModuleManager::DiscoverProvider(const wxString & path)
void ModuleManager::InitializeBuiltins()
{
ModuleInterface *module = LoadModule(path);
if (module)
PluginManager & pm = PluginManager::Get();
for (size_t i = 0, cnt = pBuiltinModuleList->GetCount(); i < cnt; i++)
{
PluginManager & pm = PluginManager::Get();
ModuleInterface *module = ((ModuleMain) (*pBuiltinModuleList)[i])(this, NULL);
// First, we need to remember it
pm.RegisterModulePlugin(module);
if (module->Initialize())
{
mDynModules[module->GetID()] = module;
// Now, allow the module to auto-register children
module->AutoRegisterPlugins(pm);
// First, we need to remember it
pm.RegisterModulePlugin(module);
// UnloadModule(module);
// Now, allow the module to auto-register children
module->AutoRegisterPlugins(pm);
}
}
return true;
}
ModuleInterface *ModuleManager::LoadModule(const wxString & path)
@ -489,19 +482,6 @@ void ModuleManager::UnloadModule(ModuleInterface *module)
}
}
void ModuleManager::InitializePlugins()
{
InitializeBuiltins();
// Look for dynamic modules here
for (ModuleMap::iterator iter = mDynModules.begin(); iter != mDynModules.end(); iter++)
{
ModuleInterface *mod = iter->second;
mod->Initialize();
}
}
void ModuleManager::RegisterModule(ModuleInterface *module)
{
wxString id = module->GetID();
@ -548,7 +528,7 @@ void ModuleManager::FindAllPlugins(PluginIDList & providers, wxArrayString & pat
}
wxArrayString ModuleManager::FindPluginsForProvider(const PluginID & providerID,
const wxString & path)
const wxString & path)
{
// Instantiate if it hasn't already been done
if (mDynModules.find(providerID) == mDynModules.end())
@ -573,15 +553,10 @@ bool ModuleManager::RegisterPlugin(const PluginID & providerID, const wxString &
return mDynModules[providerID]->RegisterPlugin(PluginManager::Get(), path);
}
bool ModuleManager::IsProviderBuiltin(const PluginID & providerID)
{
return mModuleMains.find(providerID) != mModuleMains.end();
}
IdentInterface *ModuleManager::CreateProviderInstance(const PluginID & providerID,
const wxString & path)
{
if (path.empty() && mDynModules.find(providerID) != mDynModules.end())
if (path.IsEmpty() && mDynModules.find(providerID) != mDynModules.end())
{
return mDynModules[providerID];
}
@ -611,3 +586,34 @@ void ModuleManager::DeleteInstance(const PluginID & providerID,
mDynModules[providerID]->DeleteInstance(instance);
}
bool ModuleManager::IsProviderValid(const PluginID & providerID,
const wxString & path)
{
// Builtin modules do not have a path
if (path.IsEmpty())
{
return true;
}
wxFileName lib(path);
if (lib.FileExists() || lib.DirExists())
{
return true;
}
return false;
}
bool ModuleManager::IsPluginValid(const PluginID & providerID,
const PluginID & ID,
const wxString & path)
{
if (mDynModules.find(providerID) == mDynModules.end())
{
return false;
}
return mDynModules[providerID]->IsPluginValid(ID, path);
}

10
src/ModuleManager.h

@ -86,22 +86,20 @@ public:
void Initialize(CommandHandler & cmdHandler);
int Dispatch(ModuleDispatchTypes type);
void EarlyInit();
// PluginManager use
bool DiscoverProviders(wxArrayString & providers);
bool DiscoverProvider(const wxString & path);
bool DiscoverProviders();
void FindAllPlugins(PluginIDList & providers, wxArrayString & paths);
wxArrayString FindPluginsForProvider(const PluginID & provider, const wxString & path);
bool RegisterPlugin(const PluginID & provider, const wxString & path);
void InitializePlugins();
bool IsProviderBuiltin(const PluginID & provider);
IdentInterface *CreateProviderInstance(const PluginID & ID, const wxString & path);
IdentInterface *CreateInstance(const PluginID & provider, const PluginID & ID, const wxString & path);
void DeleteInstance(const PluginID & provider, IdentInterface *instance);
bool IsProviderValid(const PluginID & provider, const wxString & path);
bool IsPluginValid(const PluginID & provider, const PluginID & ID, const wxString & path);
private:
void InitializeBuiltins();
ModuleInterface *LoadModule(const wxString & path);

567
src/PluginManager.cpp

@ -22,6 +22,7 @@
#include <wx/dir.h>
#include <wx/dynarray.h>
#include <wx/dynlib.h>
#include <wx/hashmap.h>
#include <wx/filename.h>
#include <wx/icon.h>
#include <wx/imaglist.h>
@ -48,6 +49,8 @@
#include <wx/arrimpl.cpp>
WX_DECLARE_STRING_HASH_MAP(wxString, ProviderMap);
// ============================================================================
//
//
@ -373,11 +376,19 @@ wxAccStatus CheckListAx::GetValue( int childId, wxString *strValue )
#define EffectClearAllID 7002
#define EffectSelectAllID 7003
int wxCALLBACK SortCompare(long item1, long item2, long WXUNUSED(sortData))
{
wxString *str1 = (wxString *) item1;
wxString *str2 = (wxString *) item2;
return str2->Cmp(*str1);
}
class PluginRegistrationDialog : public wxDialog
{
public:
// constructors and destructors
PluginRegistrationDialog();
PluginRegistrationDialog(ProviderMap & map);
virtual ~PluginRegistrationDialog();
private:
@ -405,10 +416,12 @@ private:
wxListCtrl *mEffects;
PluginIDList mProvs;
wxArrayString mPaths;
std::vector<int> miState;
wxArrayInt miState;
bool mCancelClicked;
ProviderMap & mMap;
DECLARE_EVENT_TABLE()
};
@ -419,12 +432,13 @@ BEGIN_EVENT_TABLE(PluginRegistrationDialog, wxDialog)
EVT_BUTTON(EffectSelectAllID, PluginRegistrationDialog::OnSelectAll)
END_EVENT_TABLE()
PluginRegistrationDialog::PluginRegistrationDialog()
PluginRegistrationDialog::PluginRegistrationDialog(ProviderMap & map)
: wxDialog(wxGetApp().GetTopWindow(),
wxID_ANY,
_("Register Effects"),
wxDefaultPosition, wxDefaultSize,
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
mMap(map)
{
mEffects = NULL;
SetLabel(_("Register Effects")); // Provide visual label
@ -443,6 +457,15 @@ PluginRegistrationDialog::~PluginRegistrationDialog()
wxKeyEventHandler(PluginRegistrationDialog::OnListChar),
NULL,
this);
for (int i = 0, cnt = mEffects->GetItemCount(); i < cnt; i++)
{
wxString *str = (wxString *) mEffects->GetItemData(i);
if (str)
{
delete str;
}
}
}
void PluginRegistrationDialog::Populate()
@ -453,8 +476,6 @@ void PluginRegistrationDialog::Populate()
// ----------------------- End of main section --------------
}
WX_DECLARE_STRING_HASH_MAP(wxString, ProviderMap);
/// Defines the dialog and does data exchange with it.
void PluginRegistrationDialog::PopulateOrExchange(ShuttleGui &S)
{
@ -521,44 +542,6 @@ void PluginRegistrationDialog::PopulateOrExchange(ShuttleGui &S)
}
S.EndVerticalLay();
PluginManager & pm = PluginManager::Get();
ModuleManager & mm = ModuleManager::Get();
// Capture all of the module IDs and paths so the iterate stays valid
ProviderMap provs;
wxArrayString keys;
wxArrayString paths;
wxString padding = wxT("0000000000");
const PluginDescriptor *plug = pm.GetFirstPlugin(PluginTypeModule);
while (plug)
{
wxString key = wxString::Format(wxT("%d"), (int) provs.size());
key.insert(0, padding.substr(0, padding.length() - key.length()));
provs[key] = plug->GetID();
keys.push_back(key);
paths.push_back(plug->GetPath());
plug = pm.GetNextPlugin(PluginTypeModule);
}
wxArrayString sortable;
for (size_t i = 0, icnt = paths.size(); i < icnt; i++)
{
wxString key = keys[i];
PluginID provID = provs[key];
wxString provPath = paths[i];
wxArrayString newPaths = mm.FindPluginsForProvider(provID, provPath);
for (size_t j = 0, jcnt = newPaths.size(); j < jcnt; j++)
{
sortable.push_back(key + wxT(" ") + newPaths[j]);
}
}
// With the index
sortable.Sort();
// The dc is used to compute the text width in pixels.
// FIXME: That works fine for PC, but apparently comes out too small for wxMAC.
// iLen is minimum width in pixels shown for the file names. 200 is reasonable.
@ -566,20 +549,18 @@ void PluginRegistrationDialog::PopulateOrExchange(ShuttleGui &S)
int iPathLen = 0;
int x, y;
wxRect iconrect;
for (int i = 0, cnt = sortable.size(); i < cnt; i++)
int i = 0;
for (ProviderMap::iterator iter = mMap.begin(); iter != mMap.end(); iter++, i++)
{
miState.push_back( SHOW_CHECKED );
miState.Add( SHOW_CHECKED );
wxString item = sortable[i];
int split = item.find(wxT(" "));
mProvs.push_back(provs[item.substr(0, split)]);
mPaths.push_back(item.substr(split + 1, wxString::npos));
wxFileName fn(mPaths.back());
wxString name(fn.GetName());
wxString path(fn.GetFullPath());
wxFileName fname = iter->first;
wxString name = fname.GetName();
wxString path = fname.GetFullPath();
wxString *key = new wxString(iter->second + name);
mEffects->InsertItem(i, name, SHOW_CHECKED);
mEffects->SetItemPtrData(i, (wxUIntPtr) key);
mEffects->SetItem(i, COL_PATH, path);
// Only need to get the icon width once
@ -606,6 +587,8 @@ void PluginRegistrationDialog::PopulateOrExchange(ShuttleGui &S)
iPathLen = wxMax(iPathLen, x + iconrect.width + (iconrect.x * 2));
}
mEffects->SortItems(SortCompare, 0);
mEffects->SetColumnWidth(COL_NAME, iNameLen + /* fudge */ 5);
mEffects->SetColumnWidth(COL_PATH, iPathLen + /* fudge */ 5);
@ -713,18 +696,50 @@ void PluginRegistrationDialog::OnClearAll(wxCommandEvent & WXUNUSED(evt))
void PluginRegistrationDialog::OnOK(wxCommandEvent & WXUNUSED(evt))
{
mCancelClicked = false;
FindWindowById(EffectListID)->Disable();
FindWindowById(wxID_OK)->Disable();
FindWindowById(EffectListID)->Disable();
FindWindowById(EffectClearAllID)->Disable();
FindWindowById(EffectSelectAllID)->Disable();
for (size_t i = 0, cnt = mPaths.size(); i < cnt && !mCancelClicked; i++)
PluginManager & pm = PluginManager::Get();
ModuleManager & mm = ModuleManager::Get();
wxListItem li;
li.Clear();
for (int i = 0, cnt = mEffects->GetItemCount(); i < cnt && !mCancelClicked; i++)
{
mEffects->EnsureVisible(i);
li.SetId(i);
li.SetColumn(COL_PATH);
li.SetMask(wxLIST_MASK_TEXT);
mEffects->GetItem(li);
wxString path = li.GetText();
// Create a placeholder descriptor to show we've seen this plugin before and not
// to show it as new the next time Audacity starts.
//
// If the user chooses not to enable it or the scan of the plugin fails, the dummy
// entry will remain in the plugin list as disabled.
//
// However, if the scan of the of the plugin succeeds, then this dummy entry will be
// replaced during registration.
PluginDescriptor & plug = pm.mPlugins[path];
plug.SetID(path);
plug.SetPath(path);
plug.SetEnabled(false);
if (miState[i] == SHOW_CHECKED)
{
li.SetId(i);
li.SetColumn(COL_PATH);
li.SetMask(wxLIST_MASK_TEXT);
mEffects->GetItem(li);
wxString path = li.GetText();
mEffects->SetItemImage(i, SHOW_ARROW);
ModuleManager::Get().RegisterPlugin(mProvs[i], wxString(mPaths[i]));
mm.RegisterPlugin(mMap[path], path);
mEffects->SetItemImage(i, SHOW_CHECKED);
}
wxYield();
@ -841,11 +856,6 @@ const PluginID & PluginDescriptor::GetProviderID() const
return mProviderID;
}
const wxString & PluginDescriptor::GetDateTime() const
{
return mDateTime;
}
bool PluginDescriptor::IsEnabled() const
{
return mEnabled;
@ -902,11 +912,6 @@ void PluginDescriptor::SetProviderID(const PluginID & providerID)
mProviderID = providerID;
}
void PluginDescriptor::SetDateTime(const wxString & dateTime)
{
mDateTime = dateTime;
}
void PluginDescriptor::SetEnabled(bool enable)
{
mEnabled = enable;
@ -1054,7 +1059,9 @@ void PluginDescriptor::SetImporterExtensions(const wxArrayString & extensions)
void PluginManager::RegisterModulePlugin(IdentInterface *module)
{
CreatePlugin(module, PluginTypeModule);
PluginDescriptor & plug = CreatePlugin(module, PluginTypeModule);
plug.SetEnabled(true);
}
void PluginManager::RegisterEffectPlugin(IdentInterface *provider, EffectIdentInterface *effect)
@ -1332,26 +1339,14 @@ PluginManager & PluginManager::Get()
void PluginManager::Initialize()
{
// Always load the config first
bool loaded = Load();
ModuleManager::Get().EarlyInit();
// Then look for providers (they may autoregister plugins)
ModuleManager::Get().DiscoverProviders();
CheckForUpdates();
bool doRescan;
gPrefs->Read(wxT("/Plugins/Rescan"), &doRescan, true);
if (!loaded || doRescan)
{
gPrefs->Write(wxT("/Plugins/Rescan"), false);
PluginRegistrationDialog dlg;
dlg.ShowModal();
if (mConfig)
{
mConfig->Flush();
}
}
// And finally check for updates
CheckForUpdates(!loaded);
}
void PluginManager::Terminate()
@ -1416,6 +1411,8 @@ bool PluginManager::Load()
LoadGroup(wxT("exporters"), PluginTypeExporter);
LoadGroup(wxT("importers"), PluginTypeImporter);
LoadGroup(wxT("placeholders"), PluginTypeNone);
return true;
}
@ -1494,16 +1491,6 @@ void PluginManager::LoadGroup(const wxChar * group, PluginType type)
}
plug.SetDescription(wxString(strVal));
// Get the last update time and bypass group if not found
if (!plug.GetPath().IsEmpty())
{
if (!mConfig->Read(KEY_LASTUPDATED, &strVal))
{
continue;
}
plug.SetDateTime(wxString(strVal));
}
// Is it enabled...default to no if not found
mConfig->Read(KEY_ENABLED, &boolVal, false);
plug.SetEnabled(boolVal);
@ -1511,9 +1498,13 @@ void PluginManager::LoadGroup(const wxChar * group, PluginType type)
switch (type)
{
case PluginTypeModule:
{
// Nothing to do here yet
}