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.
This commit is contained in:
lllucius 2014-11-19 06:58:44 +00:00
parent 393109afa3
commit 41083f74cc
60 changed files with 2163 additions and 1011 deletions

View File

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

View File

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

View File

@ -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__

View File

@ -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:

View File

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

View File

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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

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

View File

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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 .

View File

@ -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.

View File

@ -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.

View File

@ -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."

View File

@ -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.
;;

View File

@ -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

View File

@ -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

View File

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

View File

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

View File

@ -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(SortEffectsByName);
optplugs.Sort(SortEffectsByPublisherAndName);
}
else if (groupby == wxT("sortby:type:name"))
{
defplugs.Sort(SortEffectsByName);
optplugs.Sort(SortEffectsByTypeAndName);
}
else if (groupby == wxT("groupby:publisher"))
{
defplugs.Sort(SortEffectsByPublisher);
optplugs.Sort(SortEffectsByPublisher);
}
else if (groupby == wxT("publisher:name"))
else if (groupby == wxT("groupby:type"))
{
defplugs.Sort(SortEffectsByPublisherAndName);
optplugs.Sort(SortEffectsByPublisherAndName);
}
else if (groupby == wxT("family"))
{
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 stripped;
if (name.EndsWith(wxT("..."), &stripped))
{
name = stripped;
}
if (plug->IsEffectInteractive())
{
name += wxT("...");
}
wxString last;
wxString current;
if (groupBy == wxT("publisher:name"))
for (size_t i = 0; i < pluginCnt; i++)
{
current = plug->GetVendor();
if (plug->IsEffectDefault())
const PluginDescriptor *plug = plugs[i];
wxString name = plug->GetName();
// 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");
}
}
else if (groupBy == wxT("family"))
{
current = plug->GetEffectFamily();
if (current.IsEmpty())
{
current = _("Unknown");
}
}
else if (groupBy == wxT("name"))
{
current = plug->GetName();
name = current;
}
else // default to "name"
{
current = plug->GetName();
name = current;
}
if (current != last || i + 1 == pluginCnt)
{
if (i + 1 == pluginCnt)
{
groupNames.Add(name);
groupPlugs.Add(plug->GetID());
}
int groupCnt = (int) 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)
current = plug->GetVendor();
if (current.IsEmpty())
{
max = 0;
current = _("Unknown");
}
for (int j = 0; j < groupCnt; j++)
}
else if (groupBy == wxT("groupby:type"))
{
current = plug->GetEffectFamily();
if (current.IsEmpty())
{
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));
}
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;
}
}
current = _("Unknown");
}
}
if (grouped && groupCnt > 0 && i > 0)
if (current != last)
{
c->EndSubMenu();
if (!last.IsEmpty())
{
c->BeginSubMenu(last);
}
AddEffectMenuItemGroup(c, groupNames, groupPlugs, groupFlags);
if (!last.IsEmpty())
{
c->EndSubMenu();
}
groupNames.Clear();
groupPlugs.Clear();
groupFlags.Clear();
last = current;
}
last = current;
groupNames.Add(name);
groupPlugs.Add(plug->GetID());
groupFlags.Add(plug->IsEffectRealtime() ? realflags : batchflags);
}
groupNames.Add(name);
groupPlugs.Add(plug->GetID());
if (groupNames.GetCount() > 0)
{
c->BeginSubMenu(current);
AddEffectMenuItemGroup(c, groupNames, groupPlugs, groupFlags);
c->EndSubMenu();
}
}
else
{
for (size_t i = 0; i < pluginCnt; i++)
{
const PluginDescriptor *plug = plugs[i];
wxString name = plug->GetName();
// This goes away once everything has been converted to new format
wxString stripped;
if (name.EndsWith(wxT("..."), &stripped))
{
name = stripped;
}
if (plug->IsEffectInteractive())
{
name += wxT("...");
}
wxString group = wxEmptyString;
if (groupBy == wxT("sortby:publisher:name"))
{
group = plug->GetVendor();
}
else if (groupBy == wxT("sortby:type:name"))
{
group = plug->GetEffectFamily();
}
if (plug->IsEffectDefault())
{
group = wxEmptyString;
}
if (!group.IsEmpty())
{
group += wxT(": ");
}
groupNames.Add(group + name);
groupPlugs.Add(plug->GetID());
groupFlags.Add(plug->IsEffectRealtime() ? realflags : batchflags);
}
if (groupNames.GetCount() > 0)
{
AddEffectMenuItemGroup(c, groupNames, groupPlugs, groupFlags);
}
}
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));
}
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();
items = max;
}
}
}
return;

View File

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

View File

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

View File

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

View File

@ -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
}
break;
case PluginTypeEffect:
{
// Get the effect type and bypass group if not found
if (!mConfig->Read(KEY_EFFECTTYPE, &strVal))
{
@ -1571,7 +1562,7 @@ void PluginManager::LoadGroup(const wxChar * group, PluginType type)
continue;
}
plug.SetEffectAutomatable(boolVal);
}
break;
case PluginTypeImporter:
@ -1605,8 +1596,16 @@ void PluginManager::LoadGroup(const wxChar * group, PluginType type)
}
break;
case PluginTypeNone:
{
// Used for placeholder groups
}
break;
default:
{
continue;
}
}
// Everything checked out...accept the plugin
@ -1624,12 +1623,13 @@ void PluginManager::Save()
return;
}
// TODO: This is a bit drastic...only save groups when new plugins are registerd
// TODO: This is a bit drastic...only save groups when new plugins are registered
// Save the individual groups
SaveGroup(wxT("effects"), PluginTypeEffect);
SaveGroup(wxT("exporters"), PluginTypeExporter);
SaveGroup(wxT("importers"), PluginTypeImporter);
SaveGroup(wxT("placeholders"), PluginTypeNone);
// And now the providers
SaveGroup(wxT("modules"), PluginTypeModule);
@ -1656,7 +1656,6 @@ void PluginManager::SaveGroup(const wxChar *group, PluginType type)
mConfig->Write(KEY_VENDOR, plug.GetVendor());
mConfig->Write(KEY_DESCRIPTION, plug.GetDescription());
mConfig->Write(KEY_PROVIDERID, plug.GetProviderID());
mConfig->Write(KEY_LASTUPDATED, plug.GetDateTime());
mConfig->Write(KEY_ENABLED, plug.IsEnabled());
switch (type)
@ -1712,118 +1711,93 @@ void PluginManager::SaveGroup(const wxChar *group, PluginType type)
return;
}
void PluginManager::CheckForUpdates()
void PluginManager::CheckForUpdates(bool forceRescan)
{
// Always check for and remove missing plugins
RemoveMissing();
// Get ModuleManager reference
ModuleManager & mm = ModuleManager::Get();
wxArrayString providers;
wxArrayString paths;
// Always check for new or updated modules
if (mm.DiscoverProviders(paths))
{
paths = IsNewOrUpdated(paths);
for (size_t i = 0, cnt = paths.size(); i < cnt; i++)
{
mm.DiscoverProvider(paths[i]);
}
}
bool doRescan;
gPrefs->Read(wxT("/Plugins/Rescan"), &doRescan, true);
bool doCheck;
gPrefs->Read(wxT("/Plugins/CheckForUpdates"), &doCheck, true);
if (doCheck && paths.size() > 0)
{
PluginRegistrationDialog dlg;
dlg.ShowModal();
}
return;
}
ProviderMap map;
void PluginManager::RemoveMissing()
{
// Check for plugins that no longer exist
// Always check for and disable missing plugins
//
// Since the user's saved presets are in the registery, never delete them. That is
// a job for the plugin manager UI (once it is written)
// Check for plugins that are no longer valid
PluginMap::iterator iter = mPlugins.begin();
while (iter != mPlugins.end())
{
PluginDescriptor & plug = iter->second;
const PluginID & plugID = plug.GetID();
const wxString & plugPath = plug.GetPath();
if (!plug.GetPath().IsEmpty())
if (plug.GetPluginType() == PluginTypeModule)
{
wxFileName plugPath = plug.GetPath();
if (!(plugPath.FileExists() || plugPath.DirExists()))
if (!mm.IsProviderValid(plugID, plugPath))
{
mPlugins.erase(iter++);
continue;
plug.SetEnabled(false);
}
else
{
// Only collect plugin paths if we're doing a full scan or checking for updates
if (doRescan || doCheck)
{
wxArrayString paths = mm.FindPluginsForProvider(plugID, plugPath);
for (size_t i = 0, cnt = paths.GetCount(); i < cnt; i++)
{
map[paths[i]] = plugID;
}
}
}
}
else
{
if (!mm.IsPluginValid(plug.GetProviderID(), plugID, plugPath))
{
plug.SetEnabled(false);
}
}
++iter;
}
}
wxArrayString PluginManager::IsNewOrUpdated(const wxArrayString & paths)
{
wxArrayString plugsToAddOrUpdate;
// Create a map of plugins indexed by their path
std::map<wxString, PluginDescriptor *> pathPlugs;
for (PluginMap::iterator iter = mPlugins.begin(); iter != mPlugins.end(); iter++)
{
PluginDescriptor & plug = iter->second;
pathPlugs[plug.GetPath()] = &plug;
iter++;
}
// Now check for new or updated paths
for (size_t i = 0, cnt = paths.size(); i < cnt; i++)
// If we're only checking for new plugins, then remove all of the known ones
if (doCheck && !doRescan)
{
wxFileName scanPath = paths[i];
wxString scanFull = scanPath.GetFullPath();
if (pathPlugs.find(scanFull) != pathPlugs.end())
for (PluginMap::iterator iter = mPlugins.begin(); iter != mPlugins.end(); iter++)
{
if (GetDateTime(scanFull) <= pathPlugs[scanFull]->GetDateTime())
PluginDescriptor & plug = iter->second;
const wxString & plugPath = plug.GetPath();
ProviderMap::iterator mapiter = map.find(plugPath);
if (map.find(plugPath) != map.end())
{
continue;
map.erase(mapiter);
}
}
plugsToAddOrUpdate.push_back(scanFull);
}
return plugsToAddOrUpdate;
}
bool PluginManager::HasType(PluginType type)
{
for (PluginMap::iterator iter = mPlugins.begin(); iter != mPlugins.end(); iter++)
// Allow the user to choose which ones to enable
if (map.size() != 0)
{
if (iter->second.GetPluginType() == type)
PluginRegistrationDialog dlg(map);
if (dlg.ShowModal() == wxID_OK)
{
return true;
gPrefs->Write(wxT("/Plugins/Rescan"), false);
}
}
return false;
}
void PluginManager::PurgeType(PluginType type)
{
#if 0
for (PluginMap::iterator iter = mPlugins.begin(); iter != mPlugins.end(); iter++)
if (mConfig)
{
if (iter->second.GetPluginType() == type)
{
mPlugins.erase(iter->first);
mConfig->DeleteGroup(CACHEROOT + iter->second.GetID()
}
Save();
}
#endif
return;
}
int PluginManager::GetPluginCount(PluginType type)
@ -1855,7 +1829,13 @@ const PluginDescriptor *PluginManager::GetFirstPlugin(PluginType type)
{
for (mPluginsIter = mPlugins.begin(); mPluginsIter != mPlugins.end(); mPluginsIter++)
{
if (mPluginsIter->second.GetPluginType() == type)
PluginDescriptor & plug = mPluginsIter->second;
bool familyEnabled = true;
if (type == PluginTypeEffect)
{
gPrefs->Read(plug.GetEffectFamily() + wxT("/Enable"), &familyEnabled, true);
}
if (plug.IsEnabled() && plug.GetPluginType() == type && familyEnabled)
{
return &mPluginsIter->second;
}
@ -1868,33 +1848,13 @@ const PluginDescriptor *PluginManager::GetNextPlugin(PluginType type)
{
while (++mPluginsIter != mPlugins.end())
{
if (mPluginsIter->second.GetPluginType() == type)
PluginDescriptor & plug = mPluginsIter->second;
bool familyEnabled = true;
if (type == PluginTypeEffect)
{
return &mPluginsIter->second;
gPrefs->Read(plug.GetEffectFamily() + wxT("/Enable"), &familyEnabled, true);
}
}
return NULL;
}
const PluginDescriptor *PluginManager::GetFirstPluginForProvider(const PluginID & ID)
{
for (mPluginsIter = mPlugins.begin(); mPluginsIter != mPlugins.end(); mPluginsIter++)
{
if (mPluginsIter->second.GetProviderID() == ID)
{
return &mPluginsIter->second;
}
}
return NULL;
}
const PluginDescriptor *PluginManager::GetNextPluginForProvider(const PluginID & ID)
{
while (++mPluginsIter != mPlugins.end())
{
if (mPluginsIter->second.GetProviderID() == ID)
if (plug.IsEnabled() && plug.GetPluginType() == type && familyEnabled)
{
return &mPluginsIter->second;
}
@ -1908,7 +1868,9 @@ const PluginDescriptor *PluginManager::GetFirstPluginForEffectType(EffectType ty
for (mPluginsIter = mPlugins.begin(); mPluginsIter != mPlugins.end(); mPluginsIter++)
{
PluginDescriptor & plug = mPluginsIter->second;
if (plug.IsEnabled() && plug.GetEffectType() == type)
bool familyEnabled;
gPrefs->Read(plug.GetEffectFamily() + wxT("/Enable"), &familyEnabled, true);
if (plug.IsEnabled() && plug.GetEffectType() == type && familyEnabled)
{
return &plug;
}
@ -1922,7 +1884,9 @@ const PluginDescriptor *PluginManager::GetNextPluginForEffectType(EffectType typ
while (++mPluginsIter != mPlugins.end())
{
PluginDescriptor & plug = mPluginsIter->second;
if (plug.IsEnabled() && plug.GetEffectType() == type)
bool familyEnabled;
gPrefs->Read(plug.GetEffectFamily() + wxT("/Enable"), &familyEnabled, true);
if (plug.IsEnabled() && plug.GetEffectType() == type && familyEnabled)
{
return &plug;
}
@ -1931,33 +1895,6 @@ const PluginDescriptor *PluginManager::GetNextPluginForEffectType(EffectType typ
return NULL;
}
const PluginDescriptor *PluginManager::GetFirstPluginForEffectFamily(const wxString & family)
{
for (mPluginsIter = mPlugins.begin(); mPluginsIter != mPlugins.end(); mPluginsIter++)
{
if (mPluginsIter->second.GetEffectFamily() == family)
{
return &mPluginsIter->second;
}
}
return NULL;
}
const PluginDescriptor *PluginManager::GetNextPluginForEffectFamily(const wxString & family)
{
while (++mPluginsIter != mPlugins.end())
{
if (mPluginsIter->second.GetEffectFamily() == family)
{
return &mPluginsIter->second;
}
}
return NULL;
}
bool PluginManager::IsRegistered(const PluginID & ID)
{
if (mPlugins.find(ID) == mPlugins.end())
@ -2053,7 +1990,8 @@ void PluginManager::SetInstance(const PluginID & ID, IdentInterface *instance)
PluginDescriptor & PluginManager::CreatePlugin(IdentInterface *ident, PluginType type)
{
PluginDescriptor plug;
// This will either create a new entry or replace an existing entry
PluginDescriptor & plug = mPlugins[ident->GetID()];
plug.SetPluginType(type);
@ -2063,24 +2001,8 @@ PluginDescriptor & PluginManager::CreatePlugin(IdentInterface *ident, PluginType
plug.SetVendor(ident->GetVendor());
plug.SetVersion(ident->GetVersion());
plug.SetDescription(ident->GetDescription());
plug.SetEnabled(false);
plug.SetDateTime(GetDateTime(ident->GetPath()));
// This will either create a new entry or replace an existing entry
mPlugins[plug.GetID()] = plug;
return mPlugins[plug.GetID()];
}
wxString PluginManager::GetDateTime(const wxString & path)
{
wxFileName fn(path);
if (fn.FileExists())
{
wxDateTime mod = fn.GetModificationTime();
return wxString(mod.FormatISODate() + wxT(' ') + mod.FormatISOTime());
}
return wxEmptyString;
return plug;
}
bool PluginManager::GetSubgroups(const wxString & group, wxArrayString & subgroups)
@ -2358,24 +2280,149 @@ wxString PluginManager::PrivateKey(const PluginID & ID, const wxString & group,
}
// Sanitize the ID...not the best solution, but will suffice until this
// is converted to XML
// is converted to XML. We use base64 encoding to preserve case.
wxString PluginManager::ConvertID(const PluginID & ID)
{
wxString id = ID;
size_t cnt = 0;
cnt += id.Replace(wxT("\x01"), wxT(":"));
cnt += id.Replace(wxT("\x02"), wxT("/"));
cnt += id.Replace(wxT("\x03"), wxT("\\"));
if (cnt > 0)
if (ID.StartsWith(wxT("base64:")))
{
wxString id = ID.Mid(7);
char *buf = new char[id.Length() / 4 * 3];
id = wxString::FromUTF8(buf, b64decode(id, buf));
delete [] buf;
return id;
}
id.Replace(wxT(":"), wxT("\x01"));
id.Replace(wxT("/"), wxT("\x02"));
id.Replace(wxT("\\"), wxT("\x03"));
return id;
const wxCharBuffer & buf = ID.ToUTF8();
return wxT("base64:") + b64encode(buf, strlen(buf));
}
////////////////////////////////////////////////////////////////////////////////
// Base64 en/decoding
//
// Original routines marked as public domain and found at:
//
// http://en.wikibooks.org/wiki/Algorithm_implementation/Miscellaneous/Base64
//
////////////////////////////////////////////////////////////////////////////////
// Lookup table for encoding
const static wxChar cset[] = wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
const static char padc = wxT('=');
wxString PluginManager::b64encode(const void *in, int len)
{
unsigned char *p = (unsigned char *) in;
wxString out;
unsigned long temp;
for (int i = 0; i < len / 3; i++)
{
temp = (*p++) << 16; //Convert to big endian
temp += (*p++) << 8;
temp += (*p++);
out += cset[(temp & 0x00FC0000) >> 18];
out += cset[(temp & 0x0003F000) >> 12];
out += cset[(temp & 0x00000FC0) >> 6];
out += cset[(temp & 0x0000003F)];
}
switch (len % 3)
{
case 1:
temp = (*p++) << 16; //Convert to big endian
out += cset[(temp & 0x00FC0000) >> 18];
out += cset[(temp & 0x0003F000) >> 12];
out += padc;
out += padc;
break;
case 2:
temp = (*p++) << 16; //Convert to big endian
temp += (*p++) << 8;
out += cset[(temp & 0x00FC0000) >> 18];
out += cset[(temp & 0x0003F000) >> 12];
out += cset[(temp & 0x00000FC0) >> 6];
out += padc;
break;
}
return out;
}
int PluginManager::b64decode(wxString in, void *out)
{
int len = in.length();
unsigned char *p = (unsigned char *) out;
if (len % 4) //Sanity check
{
return 0;
}
int padding = 0;
if (len)
{
if (in[len - 1] == padc)
{
padding++;
}
if (in[len - 2] == padc)
{
padding++;
}
}
//const char *a = in.mb_str();
//Setup a vector to hold the result
unsigned long temp = 0; //Holds decoded quanta
int i = 0;
while (i < len)
{
for (int quantumPosition = 0; quantumPosition < 4; quantumPosition++)
{
unsigned char c = in[i];
temp <<= 6;
if (c >= 0x41 && c <= 0x5A)
{
temp |= c - 0x41;
}
else if (c >= 0x61 && c <= 0x7A)
{
temp |= c - 0x47;
}
else if (c >= 0x30 && c <= 0x39)
{
temp |= c + 0x04;
}
else if (c == 0x2B)
{
temp |= 0x3E;
}
else if (c == 0x2F)
{
temp |= 0x3F;
}
else if (c == padc)
{
switch (len - i)
{
case 1: //One pad character
*p++ = (temp >> 16) & 0x000000FF;
*p++ = (temp >> 8) & 0x000000FF;
return p - (unsigned char *) out;
case 2: //Two pad characters
*p++ = (temp >> 10) & 0x000000FF;
return p - (unsigned char *) out;
}
}
i++;
}
*p++ = (temp >> 16) & 0x000000FF;
*p++ = (temp >> 8) & 0x000000FF;
*p++ = temp & 0x000000FF;
}
return p - (unsigned char *) out;
}

View File

@ -25,7 +25,7 @@
///////////////////////////////////////////////////////////////////////////////
//
// PluginManager
// PluginDescriptor
//
///////////////////////////////////////////////////////////////////////////////
@ -53,6 +53,7 @@ public:
void SetPluginType(PluginType type);
// All plugins
const wxString & GetID() const;
const wxString & GetPath() const;
const wxString & GetName() const;
@ -60,7 +61,6 @@ public:
const wxString & GetVendor() const;
const wxString & GetDescription() const;
const wxString & GetProviderID() const;
const wxString & GetDateTime() const;
bool IsEnabled() const;
void SetID(const PluginID & ID);
@ -70,7 +70,6 @@ public:
void SetVendor(const wxString & vendor);
void SetDescription(const wxString & description);
void SetProviderID(const PluginID & providerID);
void SetDateTime(const wxString & dateTime);
void SetEnabled(bool enable);
wxString GetMenuName() const;
@ -118,7 +117,6 @@ private:
wxString mVendor;
wxString mDescription;
wxString mProviderID;
wxString mDateTime;
bool mEnabled;
// Effects
@ -138,10 +136,21 @@ private:
wxArrayString mImporterExtensions;
};
///////////////////////////////////////////////////////////////////////////////
//
// PluginManager
//
///////////////////////////////////////////////////////////////////////////////
WX_DECLARE_STRING_HASH_MAP(wxArrayString, ArrayStringMap);
//WX_DECLARE_STRING_HASH_MAP(PluginDescriptor, PluginMap);
typedef std::map<PluginID, PluginDescriptor> PluginMap;
typedef wxArrayString PluginIDList;
class PluginRegistrationDialog;
class PluginManager : public PluginManagerInterface
{
public:
@ -213,15 +222,9 @@ public:
const PluginDescriptor *GetFirstPlugin(PluginType type);
const PluginDescriptor *GetNextPlugin(PluginType type);
const PluginDescriptor *GetFirstPluginForProvider(const PluginID & ID);
const PluginDescriptor *GetNextPluginForProvider(const PluginID & ID);
const PluginDescriptor *GetFirstPluginForEffectType(EffectType type);
const PluginDescriptor *GetNextPluginForEffectType(EffectType type);
const PluginDescriptor *GetFirstPluginForEffectFamily(const PluginID & ID);
const PluginDescriptor *GetNextPluginForEffectFamily(const PluginID & ID);
bool IsRegistered(const PluginID & ID);
void RegisterPlugin(const wxString & type, const wxString & path);
@ -235,19 +238,17 @@ public:
//
const PluginID & RegisterLegacyEffectPlugin(EffectIdentInterface *effect);
void CheckForUpdates();
private:
bool Load();
void LoadGroup(const wxChar *group, PluginType type);
void Save();
void SaveGroup(const wxChar *group, PluginType type);
void RemoveMissing();
void CheckForUpdates(bool forceRescan);
void DisableMissing();
wxArrayString IsNewOrUpdated(const wxArrayString & paths);
PluginDescriptor & CreatePlugin(IdentInterface *ident, PluginType type);
wxString GetDateTime(const wxString & path);
bool GetSubgroups(const wxString & group, wxArrayString & subgroups);
@ -269,7 +270,12 @@ private:
wxString SharedKey(const PluginID & ID, const wxString & group, const wxString & key);
wxString PrivateGroup(const PluginID & ID, const wxString & group);
wxString PrivateKey(const PluginID & ID, const wxString & group, const wxString & key);
// The PluginID must be kept unique. Since the wxFileConfig class does not preserve
// case, we use base64 encoding.
wxString ConvertID(const PluginID & ID);
wxString b64encode(const void *in, int len);
int b64decode(wxString in, void *out);
private:
static PluginManager mInstance;
@ -283,6 +289,8 @@ private:
PluginMap mPlugins;
PluginMap::iterator mPluginsIter;
friend class PluginRegistrationDialog;
};
#endif /* __AUDACITY_PLUGINMANAGER_H__ */

View File

@ -168,7 +168,7 @@ wxString Effect::GetName()
return mClient->GetName();
}
return GetEffectName();
return GetEffectIdentifier();
}
wxString Effect::GetVendor()
@ -509,6 +509,10 @@ bool Effect::Startup(EffectClientInterface *client)
case EffectTypeAnalyze:
flags |= INSERT_EFFECT;
break;
case EffectTypeNone:
// Nothing to set
break;
}
SetEffectFlags(flags);
@ -708,13 +712,17 @@ bool Effect::PromptUser(wxWindow *parent, bool forceModal)
// Really need to clean this up...should get easier when
// all effects get converted.
if (!res || SupportsRealtime())
if (!res || (SupportsRealtime() && !forceModal))
{
// Return false to force DoEffect() to skip processing since
// this UI has either been shown modeless or there was an error.
return false;
}
}
else
{
PromptUser();
}
return true;
}
@ -1998,8 +2006,8 @@ EffectUIHost::~EffectUIHost()
{
if (mClient)
{
mClient->CloseUI();
mClient = NULL;
mClient->CloseUI();
mClient = NULL;
}
}
@ -2096,7 +2104,14 @@ void EffectUIHost::OnCancel(wxCommandEvent & WXUNUSED(evt))
{
if (IsModal())
{
SetReturnCode(false);
Close();
#if !defined(__WXGTK__)
EndModal(false);
#endif
return;
}

View File

@ -224,6 +224,20 @@ EffectManager::~EffectManager()
}
}
void EffectManager::RegisterEffect(IdentInterface *p, Effect *f, int NewFlags)
{
f->SetEffectID(mNumEffects++);
if( NewFlags != 0)
{
f->SetEffectFlags( NewFlags );
}
PluginManager::Get().RegisterEffectPlugin(p, f);
mEffects[f->GetID()] = f;
}
void EffectManager::RegisterEffect(Effect *f, int NewFlags)
{
f->SetEffectID(mNumEffects++);
@ -679,9 +693,10 @@ Effect *EffectManager::GetEffect(const PluginID & ID)
const PluginID & EffectManager::GetEffectByIdentifier(const wxString & strTarget)
{
static PluginID empty;
if (strTarget == wxEmptyString) // set GetEffectIdentifier to wxT("") to not show an effect in Batch mode
{
return PluginID(wxEmptyString);
return empty;
}
PluginManager & pm = PluginManager::Get();
@ -695,7 +710,7 @@ const PluginID & EffectManager::GetEffectByIdentifier(const wxString & strTarget
plug = pm.GetNextPlugin(PluginTypeEffect);
}
return PluginID(wxEmptyString);
return empty;;
}
#ifdef EFFECT_CATEGORIES

View File

@ -67,6 +67,7 @@ class AUDACITY_DLL_API EffectManager
/** Register an effect so it will appear in the menu. */
void RegisterEffect(Effect *f, int AdditionalFlags=0);
void RegisterEffect(IdentInterface *p, Effect *f, int AdditionalFlags=0);
/** Unregister all effects. */
void UnregisterEffects();

View File

@ -265,7 +265,7 @@ void EffectRack::OnClose(wxCloseEvent & evt)
evt.Veto();
}
void EffectRack::OnTimer(wxTimerEvent & AUNUSED(evt))
void EffectRack::OnTimer(wxTimerEvent & WXUNUSED(evt))
{
int latency = EffectManager::Get().GetRealtimeLatency();
if (latency != mLastLatency)
@ -276,7 +276,7 @@ void EffectRack::OnTimer(wxTimerEvent & AUNUSED(evt))
}
}
void EffectRack::OnApply(wxCommandEvent & AUNUSED(evt))
void EffectRack::OnApply(wxCommandEvent & WXUNUSED(evt))
{
AudacityProject *project = GetActiveProject();

View File

@ -57,18 +57,10 @@
#include "ChangeTempo.h"
#endif
#ifdef USE_NYQUIST
#include "nyquist/LoadNyquist.h"
#endif
#ifdef USE_AUDIO_UNITS
#include "audiounits/LoadAudioUnits.h"
#endif
#ifdef USE_LV2
#include "lv2/LoadLV2.h"
#endif
#ifdef USE_VAMP
#include "vamp/LoadVamp.h"
#endif
@ -279,42 +271,15 @@ void LoadEffects()
// Analyze menu
em.RegisterEffect(new EffectFindClipping());
#ifdef USE_NYQUIST
if (gPrefs->Read(wxT("/Nyquist/Enable"), true)) {
LoadNyquistPlugins();
}
#endif
#ifdef USE_LV2
if (gPrefs->Read(wxT("/LV2/Enable"), true)) {
LoadLV2Plugins();
}
#endif
#ifdef USE_AUDIO_UNITS
if (gPrefs->Read(wxT("/AudioUnits/Enable"), true)) {
LoadAudioUnits();
}
#endif
#ifdef USE_VAMP
if (gPrefs->Read(wxT("/VAMP/Enable"), true)) {
LoadVampPlugins();
}
#endif
}
void UnloadEffects()
{
EffectManager::Get().UnregisterEffects();
#ifdef USE_LV2
UnloadLV2Plugins();
#endif
#ifdef USE_VAMP
UnloadVampPlugins();
#endif
}

View File

@ -551,6 +551,12 @@ bool VSTEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxStrin
return valid;
}
bool VSTEffectsModule::IsPluginValid(const PluginID & ID,
const wxString & path)
{
return wxFileName::FileExists(path);
}
IdentInterface *VSTEffectsModule::CreateInstance(const PluginID & WXUNUSED(ID),
const wxString & path)
{

View File

@ -397,6 +397,8 @@ public:
virtual wxArrayString FindPlugins(PluginManagerInterface & pm);
virtual bool RegisterPlugin(PluginManagerInterface & pm, const wxString & path);
virtual bool IsPluginValid(const PluginID & ID, const wxString & path);
virtual IdentInterface *CreateInstance(const PluginID & ID, const wxString & path);
virtual void DeleteInstance(IdentInterface *instance);

View File

@ -346,6 +346,12 @@ bool LadspaEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxSt
return index > 0;
}
bool LadspaEffectsModule::IsPluginValid(const PluginID & ID,
const wxString & path)
{
return wxFileName::FileExists(path);
}
IdentInterface *LadspaEffectsModule::CreateInstance(const PluginID & ID,
const wxString & path)
{
@ -1222,7 +1228,6 @@ bool LadspaEffect::PopulateUI(wxWindow *parent)
gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5);
wxString fieldText;
LADSPA_PortRangeHint hint = mData->PortRangeHints[p];
mFields[p] = new wxTextCtrl(mParent, wxID_ANY,
fieldText,
@ -1558,24 +1563,6 @@ void LadspaEffect::RefreshControls(bool outputOnly)
continue;
}
wxString bound;
double lower = -FLT_MAX;
double upper = FLT_MAX;
bool haslo = false;
bool hashi = false;
if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor))
{
lower = hint.LowerBound;
haslo = true;
}
if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor))
{
upper = hint.UpperBound;
hashi = true;
}
if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint)
{
fieldText.Printf(wxT("%d"), (int)(mInputControls[p] + 0.5));

View File

@ -244,6 +244,8 @@ public:
virtual wxArrayString FindPlugins(PluginManagerInterface & pm);
virtual bool RegisterPlugin(PluginManagerInterface & pm, const wxString & path);
virtual bool IsPluginValid(const PluginID & ID, const wxString & path);
virtual IdentInterface *CreateInstance(const PluginID & ID, const wxString & path);
virtual void DeleteInstance(IdentInterface *instance);

View File

@ -53,6 +53,12 @@
#include <wx/arrimpl.cpp>
///////////////////////////////////////////////////////////////////////////////
//
// LV2Effect
//
///////////////////////////////////////////////////////////////////////////////
WX_DEFINE_OBJARRAY(LV2PortArray);
LV2Effect::LV2Effect(const LilvPlugin *data,
@ -292,6 +298,92 @@ LV2Effect::~LV2Effect()
}
}
// ============================================================================
// IdentInterface implementation
// ============================================================================
wxString LV2Effect::GetID()
{
return GetString(lilv_plugin_get_uri(mData));
}
wxString LV2Effect::GetPath()
{
return GetString(lilv_plugin_get_bundle_uri(mData));
}
wxString LV2Effect::GetName()
{
return pluginName;
}
wxString LV2Effect::GetVendor()
{
wxString vendor = GetString(lilv_plugin_get_author_name(mData), true);
if (vendor.IsEmpty())
{
vendor = wxT("N/A");
}
return vendor;
}
wxString LV2Effect::GetVersion()
{
return wxT("N/A");
}
wxString LV2Effect::GetDescription()
{
return wxT("N/A");
}
// ============================================================================
// EffectIdentInterface implementation
// ============================================================================
EffectType LV2Effect::GetType()
{
// For now, relegate to Effect()
return Effect::GetType();
}
wxString LV2Effect::GetFamily()
{
return LV2EFFECTS_FAMILY;
}
bool LV2Effect::IsInteractive()
{
// For now, relegate to Effect()
return Effect::IsInteractive();
}
bool LV2Effect::IsDefault()
{
return false;
}
bool LV2Effect::IsLegacy()
{
return true;
}
bool LV2Effect::SupportsRealtime()
{
return false;
}
bool LV2Effect::SupportsAutomation()
{
return true;
}
// ============================================================================
// Effect Implementation
// ============================================================================
wxString LV2Effect::GetEffectName()
{
if (mControlInputs.GetCount() > 0)
@ -714,6 +806,9 @@ void LV2Effect::End()
}
}
// ============================================================================
// LV2Effect Implementation
// ============================================================================
bool LV2Effect::IsValid()
{
@ -1246,9 +1341,11 @@ LV2EffectDialog::LV2EffectDialog(LV2Effect *effect,
LV2EffectDialog::~LV2EffectDialog()
{
delete [] mToggles;
delete [] mSliders;
delete [] mFields;
delete [] mLabels;
delete [] mEnums;
}
void LV2EffectDialog::OnCheckBox(wxCommandEvent &event)

View File

@ -24,6 +24,8 @@ class wxCheckBox;
#include "../Effect.h"
#include "LV2PortGroup.h"
#define LV2EFFECTS_VERSION wxT("1.0.0.0");
#define LV2EFFECTS_FAMILY L"LV2"
/** A structure that contains information about a single LV2 plugin port. */
struct LV2Port
@ -66,6 +68,27 @@ public:
const std::set<wxString> & categories = std::set<wxString>());
virtual ~LV2Effect();
// IdentInterface implementation
virtual PluginID GetID();
virtual wxString GetPath();
virtual wxString GetName();
virtual wxString GetVendor();
virtual wxString GetVersion();
virtual wxString GetDescription();
// EffectIdentInterface implementation
virtual EffectType GetType();
virtual wxString GetFamily();
virtual bool IsInteractive();
virtual bool IsDefault();
virtual bool IsLegacy();
virtual bool SupportsRealtime();
virtual bool SupportsAutomation();
// Effect implementation
/** Get the name of the effect. */
virtual wxString GetEffectName();

View File

@ -41,6 +41,32 @@ Functions that find and load all LV2 plugins on the system.
#include "LoadLV2.h"
// ============================================================================
// Module registration entry point
//
// This is the symbol that Audacity looks for when the module is built as a
// dynamic library.
//
// When the module is builtin to Audacity, we use the same function, but it is
// declared static so as not to clash with other builtin modules.
// ============================================================================
DECLARE_MODULE_ENTRY(AudacityModule)
{
// Create and register the importer
return new LV2EffectsModule(moduleManager, path);
}
// ============================================================================
// Register this as a builtin module
// ============================================================================
DECLARE_BUILTIN_MODULE(LV2sEffectBuiltin);
///////////////////////////////////////////////////////////////////////////////
//
// LV2EffectsModule
//
///////////////////////////////////////////////////////////////////////////////
LilvWorld *gWorld = NULL;
// This is the URI Map Feature object. It is required for loading synth
@ -96,24 +122,67 @@ LilvNode *gName;
LilvNode *gPortGroup;
LilvNode *gSubGroupOf;
void LoadLV2Plugins()
LV2EffectsModule::LV2EffectsModule(ModuleManagerInterface *moduleManager,
const wxString *path)
{
EffectManager& em = EffectManager::Get();
// If gWorld isn't 0 we have already initialised Lilv - unload all plugins
// and initialise again.
if (gWorld)
mModMan = moduleManager;
if (path)
{
UnloadLV2Plugins();
mPath = *path;
}
}
LV2EffectsModule::~LV2EffectsModule()
{
}
// ============================================================================
// IdentInterface implementation
// ============================================================================
wxString LV2EffectsModule::GetID()
{
// Can be anything, but this is a v4 UUID
return wxT("5d03b6ad-ca64-41b2-a3f2-785ff5b279d9");
}
wxString LV2EffectsModule::GetPath()
{
return mPath;
}
wxString LV2EffectsModule::GetName()
{
return _("LV2 Effects Module");
}
wxString LV2EffectsModule::GetVendor()
{
return _("The Audacity Team");
}
wxString LV2EffectsModule::GetVersion()
{
// This "may" be different if this were to be maintained as a separate DLL
return LV2EFFECTS_VERSION;
}
wxString LV2EffectsModule::GetDescription()
{
return _("Provides LV2 Effects support to Audacity");
}
// ============================================================================
// ModuleInterface implementation
// ============================================================================
bool LV2EffectsModule::Initialize()
{
// Try to initialise Lilv, or return.
gWorld = lilv_world_new();
if (!gWorld)
{
wxLogMessage(wxT("Could not initialise lilv!"));
return;
return false;
}
gAudioPortClass = lilv_new_uri(gWorld, LV2_CORE__AudioPort);
@ -133,49 +202,10 @@ void LoadLV2Plugins()
lilv_world_load_all(gWorld);
#ifdef EFFECT_CATEGORIES
// Add all LV2 categories and their relationships
LilvPluginClasses classes = Lilv_world_get_plugin_classes(gWorld);
for (unsigned index = 0; index < Lilv_plugin_classes_size(classes);++index){
LilvPluginClass c = Lilv_plugin_classes_get_at(classes, index);
em.AddCategory(wxString::FromUTF8(lilv_node_as_uri(Lilv_plugin_class_get_uri(c))),
wxString::FromUTF8(lilv_node_as_string(Lilv_plugin_class_get_label(c))));
}
for (unsigned index = 0; index < Lilv_plugin_classes_size(classes);++index){
LilvPluginClass c = Lilv_plugin_classes_get_at(classes, index);
LilvPluginClasses ch = Lilv_plugin_class_get_children(c);
EffectCategory* pCat = em.LookupCategory(wxString::FromUTF8(lilv_node_as_uri(Lilv_plugin_class_get_uri(c))));
for (unsigned j = 0; j < Lilv_plugin_classes_size(ch); ++j) {
EffectCategory* chCat = em.LookupCategory(wxString::FromUTF8(lilv_node_as_uri(Lilv_plugin_class_get_uri(Lilv_plugin_classes_get_at(ch, j)))));
if (chCat && pCat) {
em.AddCategoryParent(chCat, pCat);
}
}
}
#endif
// Retrieve data about all plugins
const LilvPlugins *plugs = lilv_world_get_all_plugins(gWorld);
// Iterate over all plugins and register them with the EffectManager
LILV_FOREACH(plugins, i, plugs)
{
const LilvPlugin *plug = lilv_plugins_get(plugs, i);
std::set<wxString> cats;
cats.insert(wxString::FromUTF8(lilv_node_as_uri(lilv_plugin_class_get_uri(lilv_plugin_get_class(plug)))));
LV2Effect *effect = new LV2Effect(plug, cats);
if (effect->IsValid())
em.RegisterEffect(effect);
else
delete effect;
//std::cerr<<"Loaded LV2 \""<<lilv_node_as_string(Lilv_plugin_get_name(plug))<<"\""<<std::endl;
}
return true;
}
void UnloadLV2Plugins()
void LV2EffectsModule::Terminate()
{
lilv_node_free(gAudioPortClass);
gAudioPortClass = NULL;
@ -221,6 +251,97 @@ void UnloadLV2Plugins()
lilv_world_free(gWorld);
gWorld = NULL;
return;
}
bool LV2EffectsModule::AutoRegisterPlugins(PluginManagerInterface & pm)
{
EffectManager& em = EffectManager::Get();
#ifdef EFFECT_CATEGORIES
// Add all LV2 categories and their relationships
LilvPluginClasses classes = Lilv_world_get_plugin_classes(gWorld);
for (unsigned index = 0; index < Lilv_plugin_classes_size(classes);++index){
LilvPluginClass c = Lilv_plugin_classes_get_at(classes, index);
em.AddCategory(wxString::FromUTF8(lilv_node_as_uri(Lilv_plugin_class_get_uri(c))),
wxString::FromUTF8(lilv_node_as_string(Lilv_plugin_class_get_label(c))));
}
for (unsigned index = 0; index < Lilv_plugin_classes_size(classes);++index){
LilvPluginClass c = Lilv_plugin_classes_get_at(classes, index);
LilvPluginClasses ch = Lilv_plugin_class_get_children(c);
EffectCategory* pCat = em.LookupCategory(wxString::FromUTF8(lilv_node_as_uri(Lilv_plugin_class_get_uri(c))));
for (unsigned j = 0; j < Lilv_plugin_classes_size(ch); ++j) {
EffectCategory* chCat = em.LookupCategory(wxString::FromUTF8(lilv_node_as_uri(Lilv_plugin_class_get_uri(Lilv_plugin_classes_get_at(ch, j)))));
if (chCat && pCat) {
em.AddCategoryParent(chCat, pCat);
}
}
}
#endif
// Retrieve data about all plugins
const LilvPlugins *plugs = lilv_world_get_all_plugins(gWorld);
// Iterate over all plugins and register them with the EffectManager
LILV_FOREACH(plugins, i, plugs)
{
const LilvPlugin *plug = lilv_plugins_get(plugs, i);
std::set<wxString> cats;
cats.insert(wxString::FromUTF8(lilv_node_as_uri(lilv_plugin_class_get_uri(lilv_plugin_get_class(plug)))));
LV2Effect *effect = new LV2Effect(plug, cats);
if (effect->IsValid())
{
em.RegisterEffect(this, effect);
}
else
{
delete effect;
}
}
return true;
}
wxArrayString LV2EffectsModule::FindPlugins(PluginManagerInterface & pm)
{
// Nothing to do here yet
return false;
}
bool LV2EffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxString & path)
{
// Nothing to do here yet
return false;
}
bool LV2EffectsModule::IsPluginValid(const PluginID & ID,
const wxString & path)
{
LilvNode *uri = lilv_new_uri(gWorld, path.ToUTF8());
const LilvPlugin *plugin = lilv_plugins_get_by_uri(lilv_world_get_all_plugins(gWorld), uri);
lilv_node_free(uri);
return plugin != NULL;
}
IdentInterface *LV2EffectsModule::CreateInstance(const PluginID & ID,
const wxString & path)
{
// Nothing to do here yet since we are autoregistering (and creating legacy
// effects anyway).
return NULL;
}
void LV2EffectsModule::DeleteInstance(IdentInterface *instance)
{
// Nothing to do here yet
}
// ============================================================================
// LV2EffectsModule implementation
// ============================================================================
#endif

View File

@ -11,6 +11,52 @@
#include <lilv/lilv.h>
#include "audacity/ModuleInterface.h"
#include "audacity/EffectInterface.h"
#include "audacity/PluginInterface.h"
///////////////////////////////////////////////////////////////////////////////
//
// LV2EffectsModule
//
///////////////////////////////////////////////////////////////////////////////
class LV2EffectsModule : public ModuleInterface
{
public:
LV2EffectsModule(ModuleManagerInterface *moduleManager, const wxString *path);
virtual ~LV2EffectsModule();
// IdentInterface implementatino
virtual wxString GetID();
virtual wxString GetPath();
virtual wxString GetName();
virtual wxString GetVendor();
virtual wxString GetVersion();
virtual wxString GetDescription();
// ModuleInterface implementation
virtual bool Initialize();
virtual void Terminate();
virtual bool AutoRegisterPlugins(PluginManagerInterface & pm);
virtual wxArrayString FindPlugins(PluginManagerInterface & pm);
virtual bool RegisterPlugin(PluginManagerInterface & pm, const wxString & path);
virtual bool IsPluginValid(const PluginID & ID, const wxString & path);
virtual IdentInterface *CreateInstance(const PluginID & ID, const wxString & path);
virtual void DeleteInstance(IdentInterface *instance);
// LV2EffectModule implementation
private:
ModuleManagerInterface *mModMan;
wxString mPath;
};
extern LilvWorld *gWorld;
// This is the LV2 Feature array. It is passed to every LV2 plugin on

View File

@ -8,43 +8,174 @@
**********************************************************************/
#include <wx/defs.h>
#include <wx/filefn.h>
#include <wx/list.h>
#include <wx/log.h>
#include <wx/string.h>
#include "../../Audacity.h"
#include "../../AudacityApp.h"
#include "../EffectManager.h"
#include "Nyquist.h"
#include "LoadNyquist.h"
void LoadNyquistEffect(wxString fname)
// ============================================================================
// Module registration entry point
//
// This is the symbol that Audacity looks for when the module is built as a
// dynamic library.
//
// When the module is builtin to Audacity, we use the same function, but it is
// declared static so as not to clash with other builtin modules.
// ============================================================================
DECLARE_MODULE_ENTRY(AudacityModule)
{
EffectNyquist *effect = new EffectNyquist(fname);
if (effect->LoadedNyFile())
EffectManager::Get().RegisterEffect(effect);
else
delete effect;
// Create and register the importer
return new NyquistEffectsModule(moduleManager, path);
}
void LoadNyquistPlugins()
// ============================================================================
// Register this as a builtin module
// ============================================================================
DECLARE_BUILTIN_MODULE(NyquistsEffectBuiltin);
///////////////////////////////////////////////////////////////////////////////
//
// NyquistEffectsModule
//
///////////////////////////////////////////////////////////////////////////////
NyquistEffectsModule::NyquistEffectsModule(ModuleManagerInterface *moduleManager,
const wxString *path)
{
mModMan = moduleManager;
if (path)
{
mPath = *path;
}
}
NyquistEffectsModule::~NyquistEffectsModule()
{
mPath.Clear();
}
// ============================================================================
// IdentInterface implementation
// ============================================================================
wxString NyquistEffectsModule::GetID()
{
// Can be anything, but this is a v4 UUID
return wxT("42a58b1e-cc24-4b55-861a-4b2008a7cf7b");
}
wxString NyquistEffectsModule::GetPath()
{
return mPath;
}
wxString NyquistEffectsModule::GetName()
{
return _("Nyquist Effects Module");
}
wxString NyquistEffectsModule::GetVendor()
{
return _("The Audacity Team");
}
wxString NyquistEffectsModule::GetVersion()
{
// This "may" be different if this were to be maintained as a separate DLL
return NYQUISTEFFECTS_VERSION;
}
wxString NyquistEffectsModule::GetDescription()
{
return _("Provides Nyquist Effects support to Audacity");
}
// ============================================================================
// ModuleInterface implementation
// ============================================================================
bool NyquistEffectsModule::Initialize()
{
// Nothing to do here
return true;
}
void NyquistEffectsModule::Terminate()
{
// Nothing to do here
return;
}
bool NyquistEffectsModule::AutoRegisterPlugins(PluginManagerInterface & pm)
{
// For Nyquist, we autoregister plugins at this time using the legacy
// interface. This will change eventually.
wxArrayString pathList = EffectNyquist::GetNyquistSearchPath();
wxArrayString files;
unsigned int i;
// Create one "interactive Nyquist"
// Create one "interactive Nyquist" effect
EffectNyquist *effect = new EffectNyquist(wxT(""));
EffectManager::Get().RegisterEffect(effect);
EffectManager::Get().RegisterEffect(this, effect);
// Load .ny plug-ins
wxGetApp().FindFilesInPathList(wxT("*.ny"), pathList, files);
pm.FindFilesInPathList(wxT("*.ny"), pathList, files);
#ifdef __WXGTK__
wxGetApp().FindFilesInPathList(wxT("*.NY"), pathList, files); // Ed's fix for bug 179
pm.FindFilesInPathList(wxT("*.NY"), pathList, files); // Ed's fix for bug 179
#endif
for(i=0; i<files.GetCount(); i++)
LoadNyquistEffect(files[i]);
for (size_t i = 0; i < files.GetCount(); i++)
{
EffectNyquist *effect = new EffectNyquist(files[i]);
if (effect->LoadedNyFile())
{
EffectManager::Get().RegisterEffect(this, effect);
}
else
{
delete effect;
}
}
return true;
}
wxArrayString NyquistEffectsModule::FindPlugins(PluginManagerInterface & pm)
{
// Nothing to do here yet
return wxArrayString();
}
bool NyquistEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxString & path)
{
// Nothing to do here yet
return false;
}
bool NyquistEffectsModule::IsPluginValid(const PluginID & ID,
const wxString & path)
{
if (ID == wxT("nyquist prompt"))
{
return true;
}
return wxFileName::FileExists(path);
}
IdentInterface *NyquistEffectsModule::CreateInstance(const PluginID & ID,
const wxString & path)
{
// Nothing to do here yet since we are autoregistering (and creating legacy
// effects anyway).
return NULL;
}
void NyquistEffectsModule::DeleteInstance(IdentInterface *instance)
{
// Nothing to do here yet
}
// ============================================================================
// NyquistEffectsModule implementation
// ============================================================================

View File

@ -8,5 +8,48 @@
**********************************************************************/
void LoadNyquistPlugins();
#include "audacity/ModuleInterface.h"
#include "audacity/EffectInterface.h"
#include "audacity/PluginInterface.h"
///////////////////////////////////////////////////////////////////////////////
//
// NyquistEffectsModule
//
///////////////////////////////////////////////////////////////////////////////
class NyquistEffectsModule : public ModuleInterface
{
public:
NyquistEffectsModule(ModuleManagerInterface *moduleManager, const wxString *path);
virtual ~NyquistEffectsModule();
// IdentInterface implementatino
virtual wxString GetID();
virtual wxString GetPath();
virtual wxString GetName();
virtual wxString GetVendor();
virtual wxString GetVersion();
virtual wxString GetDescription();
// ModuleInterface implementation
virtual bool Initialize();
virtual void Terminate();
virtual bool AutoRegisterPlugins(PluginManagerInterface & pm);
virtual wxArrayString FindPlugins(PluginManagerInterface & pm);
virtual bool RegisterPlugin(PluginManagerInterface & pm, const wxString & path);
virtual bool IsPluginValid(const PluginID & ID, const wxString & path);
virtual IdentInterface *CreateInstance(const PluginID & ID, const wxString & path);
virtual void DeleteInstance(IdentInterface *instance);
// NyquistEffectModule implementation
private:
ModuleManagerInterface *mModMan;
wxString mPath;
};

View File

@ -74,6 +74,15 @@ effects from this one class.
#include <float.h>
#include <wx/arrimpl.cpp>
///////////////////////////////////////////////////////////////////////////////
//
// NyquistEffect
//
///////////////////////////////////////////////////////////////////////////////
#define UNINITIALIZED_CONTROL ((double)99999999.99)
WX_DEFINE_OBJARRAY(NyqControlArray);
EffectNyquist::EffectNyquist(wxString fName)
@ -88,6 +97,8 @@ EffectNyquist::EffectNyquist(wxString fName)
mDebug = false;
mIsSal = false;
mOK = false;
mAuthor = wxT("N/A");
mCopyright = wxT("N/A");
mVersion = 4;
@ -120,331 +131,103 @@ EffectNyquist::EffectNyquist(wxString fName)
EffectNyquist::~EffectNyquist()
{
nyx_set_xlisp_path(NULL);
}
wxString EffectNyquist::NyquistToWxString(const char *nyqString)
// ============================================================================
// IdentInterface implementation
// ============================================================================
wxString EffectNyquist::GetID()
{
wxString str(nyqString, wxConvUTF8);
if (nyqString != NULL && nyqString[0] && str.IsEmpty()) {
// invalid UTF-8 string, convert as Latin-1
str = _("[Warning: Nyquist returned invalid UTF-8 string, converted here as Latin-1]");
str += LAT1CTOWX(nyqString);
}
return str;
return GetPath();
}
void EffectNyquist::Break()
wxString EffectNyquist::GetPath()
{
mBreak = true;
if (mFileName.GetFullPath().IsEmpty())
{
return wxT("nyquist prompt");
}
return mFileName.GetFullPath();
}
void EffectNyquist::Continue()
wxString EffectNyquist::GetName()
{
mCont = true;
return mName;
}
void EffectNyquist::Stop()
wxString EffectNyquist::GetVendor()
{
mStop = true;
if (GetID() == wxT("nyquist prompt"))
{
return wxT("Audacity");
}
return mAuthor;
}
#define UNINITIALIZED_CONTROL ((double)99999999.99)
wxString EffectNyquist::UnQuote(wxString s)
wxString EffectNyquist::GetVersion()
{
wxString out;
int len = s.Length();
if (len >= 2 && s[0] == wxT('\"') && s[len - 1] == wxT('\"')) {
return s.Mid(1, len - 2);
}
return s;
return wxT("N/A");
}
double EffectNyquist::GetCtrlValue(wxString s)
wxString EffectNyquist::GetDescription()
{
if (s == wxT("rate")) {
TrackListOfKindIterator iter(Track::Wave, mTracks);
return ((WaveTrack *)iter.First())->GetRate();
}
return Internat::CompatibleToDouble(s);
return mCopyright;
}
void EffectNyquist::Parse(wxString line)
// ============================================================================
// EffectIdentInterface implementation
// ============================================================================
EffectType EffectNyquist::GetType()
{
wxArrayString tokens;
int i;
int len = line.Length();
bool sl = false;
bool q = false;
wxString tok = wxT("");
for (i = 1; i < len; i++) {
wxChar c = line[i];
if (c == wxT('\\')) {
sl = true;
}
else if (c == wxT('"')) {
q = !q;
}
else {
if ((!q && !sl && c == wxT(' ')) || c == wxT('\t')) {
tokens.Add(tok);
tok = wxT("");
}
else if (sl && c == wxT('n')) {
tok += wxT('\n');
}
else {
tok += c;
}
sl = false;
}
}
if (tok != wxT("")) {
tokens.Add(tok);
}
len = tokens.GetCount();
if (len < 1) {
return;
}
if (len == 2 && tokens[0] == wxT("nyquist") && tokens[1] == wxT("plug-in")) {
mOK = true;
return;
}
if (len >= 2 && tokens[0] == wxT("type")) {
if (tokens[1] == wxT("process")) {
SetEffectFlags(PROCESS_EFFECT | PLUGIN_EFFECT);
}
else if (tokens[1] == wxT("generate")) {
SetEffectFlags(INSERT_EFFECT | PLUGIN_EFFECT);
}
else if (tokens[1] == wxT("analyze")) {
SetEffectFlags(ANALYZE_EFFECT | PLUGIN_EFFECT);
}
return;
}
if (len == 2 && tokens[0] == wxT("codetype")) {
if (tokens[1] == wxT("lisp")) {
mIsSal = false;
}
else if (tokens[1] == wxT("sal")) {
mIsSal = true;
}
return;
}
if (len >= 2 && tokens[0] == wxT("debugflags")) {
for (int i = 1; i < len; i++) {
// Note: "trace" and "notrace" are overridden by "Debug" and "OK"
// buttons if the plug-in generates a dialog box by using controls
if (tokens[i] == wxT("trace")) {
mDebug = true;
}
else if (tokens[i] == wxT("notrace")) {
mDebug = false;
}
else if (tokens[i] == wxT("compiler")) {
mCompiler = true;
}
else if (tokens[i] == wxT("nocompiler")) {
mCompiler = false;
}
}
return;
}
// We support versions 1, 2 and 3
// (Version 2 added support for string parameters.)
// (Version 3 added support for choice parameters.)
// (Version 4 added support for project/track/selection information.)
if (len >= 2 && tokens[0] == wxT("version")) {
long v;
tokens[1].ToLong(&v);
if (v < 1 && v > 4) {
// This is an unsupported plug-in version
mOK = false;
return;
}
mVersion = (int) v;
}
if (len >= 2 && tokens[0] == wxT("name")) {
mName = UnQuote(tokens[1]);
return;
}
if (len >= 2 && tokens[0] == wxT("action")) {
mAction = UnQuote(tokens[1]);
return;
}
if (len >= 2 && tokens[0] == wxT("info")) {
mInfo = UnQuote(tokens[1]);
return;
}
if (len >= 2 && tokens[0] == wxT("preview")) {
if (tokens[1] == wxT("enabled") || tokens[1] == wxT("true")) {
mEnablePreview = true;
}
return;
}
if (len >= 6 && tokens[0] == wxT("control")) {
NyqControl ctrl;
ctrl.var = tokens[1];
ctrl.name = tokens[2];
ctrl.label = tokens[4];
ctrl.valStr = tokens[5];
if (tokens[3] == wxT("string")) {
ctrl.type = NYQ_CTRL_STRING;
}
else if (tokens[ 3 ] == wxT("choice")) {
ctrl.type = NYQ_CTRL_CHOICE;
}
else {
if (len < 8) {
return;
}
if ((tokens[3] == wxT("real")) ||
(tokens[3] == wxT("float"))) // undocumented, but useful, alternative
ctrl.type = NYQ_CTRL_REAL;
else if (tokens[3] == wxT("int"))
ctrl.type = NYQ_CTRL_INT;
else
{
wxString str;
str.Printf(_("Bad Nyquist 'control' type specification: '%s' in plugin file '%s'.\nControl not created."),
tokens[3].c_str(), mFileName.GetFullPath().c_str());
// Too disturbing to show alert before Audacity frame is up.
// wxMessageBox(str, wxT("Nyquist Warning"), wxOK | wxICON_EXCLAMATION);
// Note that the AudacityApp's mLogger has not yet been created,
// so this brings up an alert box, but after the Audacity frame is up.
wxLogWarning(str);
return;
}
ctrl.lowStr = tokens[6];
ctrl.highStr = tokens[7];
}
ctrl.val = UNINITIALIZED_CONTROL;
if( mPresetNames.Index( ctrl.var ) == wxNOT_FOUND )
{
mControls.Add(ctrl);
}
}
if (len >= 2 && tokens[0] == wxT("categories")) {
for (size_t i = 1; i < tokens.GetCount(); ++i) {
mCategories.Add(tokens[i]);
}
}
// For now, relegate to Effect()
return Effect::GetType();
}
void EffectNyquist::ParseFile()
wxString EffectNyquist::GetFamily()
{
wxTextFile f(mFileName.GetFullPath());
if (!f.Open())
return;
mCmd = wxT("");
SetEffectFlags(PROCESS_EFFECT | PLUGIN_EFFECT);
mOK = false;
mEnablePreview = false;
mIsSal = false;
mControls.Clear();
mDebug = false;
int i;
int len = f.GetLineCount();
wxString line;
for (i = 0; i < len; i++) {
line = f[i];
if (line.Length() > 1 && line[0] == wxT(';')) {
Parse(line);
}
// preserve comments so that SAL effects compile with proper line numbers
mCmd += line + wxT("\n");
}
return NYQUISTEFFECTS_FAMILY;
}
void EffectNyquist::SetCommand(wxString cmd)
bool EffectNyquist::IsInteractive()
{
mExternal = true;
mInteractive = false;
mCmd = wxT("");
SetEffectFlags(INSERT_EFFECT | HIDDEN_EFFECT);
mOK = false;
mIsSal = false;
mControls.Clear();
wxStringTokenizer lines(cmd, wxT("\n"));
while (lines.HasMoreTokens()) {
wxString line = lines.GetNextToken();
if (line.Length() > 1 && line[0] == wxT(';')) {
Parse(line);
}
else {
mCmd += line + wxT("\n");
}
}
// For now, relegate to Effect()
return Effect::IsInteractive();
}
bool EffectNyquist::SetXlispPath()
bool EffectNyquist::IsDefault()
{
wxString fname;
fname = mXlispPath + wxFILE_SEP_PATH + wxT("nyinit.lsp");
if (!(::wxFileExists(fname))) {
mXlispPath = wxT("");
if (GetID() == wxT("nyquist prompt"))
{
return true;
}
if (mXlispPath == wxT("")) {
wxArrayString audacityPathList = wxGetApp().audacityPathList;
wxArrayString pathList;
wxArrayString files;
unsigned int i;
for (i = 0; i < audacityPathList.GetCount(); i++) {
wxString prefix = audacityPathList[i] + wxFILE_SEP_PATH;
wxGetApp().AddUniquePathToPathList(prefix + wxT("nyquist"),
pathList);
}
wxGetApp().FindFilesInPathList(wxT("nyquist.lsp"), pathList, files);
if (files.GetCount() > 0) {
mXlispPath = ::wxPathOnly(files[0]);
}
}
/* set_xlisp_path doesn't handle fn_Str() in Unicode build. May or may not actually work. */
nyx_set_xlisp_path(mXlispPath.mb_str());
fname = mXlispPath + wxFILE_SEP_PATH + wxT("nyinit.lsp");
return ::wxFileExists(fname);
return false;
}
bool EffectNyquist::IsLegacy()
{
return true;
}
bool EffectNyquist::SupportsRealtime()
{
return false;
}
bool EffectNyquist::SupportsAutomation()
{
return true;
}
// ============================================================================
// Effect Implementation
// ============================================================================
bool EffectNyquist::SupportsChains()
{
return (GetEffectFlags() & PROCESS_EFFECT) != 0;
@ -1270,6 +1053,341 @@ bool EffectNyquist::ProcessOne()
return true;
}
// ============================================================================
// EffectNyquist Implementation
// ============================================================================
wxString EffectNyquist::NyquistToWxString(const char *nyqString)
{
wxString str(nyqString, wxConvUTF8);
if (nyqString != NULL && nyqString[0] && str.IsEmpty()) {
// invalid UTF-8 string, convert as Latin-1
str = _("[Warning: Nyquist returned invalid UTF-8 string, converted here as Latin-1]");
str += LAT1CTOWX(nyqString);
}
return str;
}
void EffectNyquist::Break()
{
mBreak = true;
}
void EffectNyquist::Continue()
{
mCont = true;
}
void EffectNyquist::Stop()
{
mStop = true;
}
wxString EffectNyquist::UnQuote(wxString s)
{
wxString out;
int len = s.Length();
if (len >= 2 && s[0] == wxT('\"') && s[len - 1] == wxT('\"')) {
return s.Mid(1, len - 2);
}
return s;
}
double EffectNyquist::GetCtrlValue(wxString s)
{
if (s == wxT("rate")) {
TrackListOfKindIterator iter(Track::Wave, mTracks);
return ((WaveTrack *)iter.First())->GetRate();
}
return Internat::CompatibleToDouble(s);
}
void EffectNyquist::Parse(wxString line)
{
wxArrayString tokens;
int i;
int len = line.Length();
bool sl = false;
bool q = false;
wxString tok = wxT("");
for (i = 1; i < len; i++) {
wxChar c = line[i];
if (c == wxT('\\')) {
sl = true;
}
else if (c == wxT('"')) {
q = !q;
}
else {
if ((!q && !sl && c == wxT(' ')) || c == wxT('\t')) {
tokens.Add(tok);
tok = wxT("");
}
else if (sl && c == wxT('n')) {
tok += wxT('\n');
}
else {
tok += c;
}
sl = false;
}
}
if (tok != wxT("")) {
tokens.Add(tok);
}
len = tokens.GetCount();
if (len < 1) {
return;
}
if (len == 2 && tokens[0] == wxT("nyquist") && tokens[1] == wxT("plug-in")) {
mOK = true;
return;
}
if (len >= 2 && tokens[0] == wxT("type")) {
if (tokens[1] == wxT("process")) {
SetEffectFlags(PROCESS_EFFECT | PLUGIN_EFFECT);
}
else if (tokens[1] == wxT("generate")) {
SetEffectFlags(INSERT_EFFECT | PLUGIN_EFFECT);
}
else if (tokens[1] == wxT("analyze")) {
SetEffectFlags(ANALYZE_EFFECT | PLUGIN_EFFECT);
}
return;
}
if (len == 2 && tokens[0] == wxT("codetype")) {
if (tokens[1] == wxT("lisp")) {
mIsSal = false;
}
else if (tokens[1] == wxT("sal")) {
mIsSal = true;
}
return;
}
if (len >= 2 && tokens[0] == wxT("debugflags")) {
for (int i = 1; i < len; i++) {
// Note: "trace" and "notrace" are overridden by "Debug" and "OK"
// buttons if the plug-in generates a dialog box by using controls
if (tokens[i] == wxT("trace")) {
mDebug = true;
}
else if (tokens[i] == wxT("notrace")) {
mDebug = false;
}
else if (tokens[i] == wxT("compiler")) {
mCompiler = true;
}
else if (tokens[i] == wxT("nocompiler")) {
mCompiler = false;
}
}
return;
}
// We support versions 1, 2 and 3
// (Version 2 added support for string parameters.)
// (Version 3 added support for choice parameters.)
// (Version 4 added support for project/track/selection information.)
if (len >= 2 && tokens[0] == wxT("version")) {
long v;
tokens[1].ToLong(&v);
if (v < 1 && v > 4) {
// This is an unsupported plug-in version
mOK = false;
return;
}
mVersion = (int) v;
}
if (len >= 2 && tokens[0] == wxT("name")) {
mName = UnQuote(tokens[1]);
return;
}
if (len >= 2 && tokens[0] == wxT("action")) {
mAction = UnQuote(tokens[1]);
return;
}
if (len >= 2 && tokens[0] == wxT("info")) {
mInfo = UnQuote(tokens[1]);
return;
}
if (len >= 2 && tokens[0] == wxT("preview")) {
if (tokens[1] == wxT("enabled") || tokens[1] == wxT("true")) {
mEnablePreview = true;
}
return;
}
if (len >= 2 && tokens[0] == wxT("author")) {
mAuthor = UnQuote(tokens[1]);
return;
}
if (len >= 2 && tokens[0] == wxT("copyright")) {
mCopyright = UnQuote(tokens[1]);
return;
}
if (len >= 6 && tokens[0] == wxT("control")) {
NyqControl ctrl;
ctrl.var = tokens[1];
ctrl.name = tokens[2];
ctrl.label = tokens[4];
ctrl.valStr = tokens[5];
if (tokens[3] == wxT("string")) {
ctrl.type = NYQ_CTRL_STRING;
}
else if (tokens[ 3 ] == wxT("choice")) {
ctrl.type = NYQ_CTRL_CHOICE;
}
else {
if (len < 8) {
return;
}
if ((tokens[3] == wxT("real")) ||
(tokens[3] == wxT("float"))) // undocumented, but useful, alternative
ctrl.type = NYQ_CTRL_REAL;
else if (tokens[3] == wxT("int"))
ctrl.type = NYQ_CTRL_INT;
else
{
wxString str;
str.Printf(_("Bad Nyquist 'control' type specification: '%s' in plugin file '%s'.\nControl not created."),
tokens[3].c_str(), mFileName.GetFullPath().c_str());
// Too disturbing to show alert before Audacity frame is up.
// wxMessageBox(str, wxT("Nyquist Warning"), wxOK | wxICON_EXCLAMATION);
// Note that the AudacityApp's mLogger has not yet been created,
// so this brings up an alert box, but after the Audacity frame is up.
wxLogWarning(str);
return;
}
ctrl.lowStr = tokens[6];
ctrl.highStr = tokens[7];
}
ctrl.val = UNINITIALIZED_CONTROL;
if( mPresetNames.Index( ctrl.var ) == wxNOT_FOUND )
{
mControls.Add(ctrl);
}
}
if (len >= 2 && tokens[0] == wxT("categories")) {
for (size_t i = 1; i < tokens.GetCount(); ++i) {
mCategories.Add(tokens[i]);
}
}
}
void EffectNyquist::ParseFile()
{
wxTextFile f(mFileName.GetFullPath());
if (!f.Open())
return;
mCmd = wxT("");
SetEffectFlags(PROCESS_EFFECT | PLUGIN_EFFECT);
mOK = false;
mEnablePreview = false;
mIsSal = false;
mControls.Clear();
mDebug = false;
int i;
int len = f.GetLineCount();
wxString line;
for (i = 0; i < len; i++) {
line = f[i];
if (line.Length() > 1 && line[0] == wxT(';')) {
Parse(line);
}
// preserve comments so that SAL effects compile with proper line numbers
mCmd += line + wxT("\n");
}
}
void EffectNyquist::SetCommand(wxString cmd)
{
mExternal = true;
mInteractive = false;
mCmd = wxT("");
SetEffectFlags(INSERT_EFFECT | HIDDEN_EFFECT);
mOK = false;
mIsSal = false;
mControls.Clear();
wxStringTokenizer lines(cmd, wxT("\n"));
while (lines.HasMoreTokens()) {
wxString line = lines.GetNextToken();
if (line.Length() > 1 && line[0] == wxT(';')) {
Parse(line);
}
else {
mCmd += line + wxT("\n");
}
}
}
bool EffectNyquist::SetXlispPath()
{
wxString fname;
fname = mXlispPath + wxFILE_SEP_PATH + wxT("nyinit.lsp");
if (!(::wxFileExists(fname))) {
mXlispPath = wxT("");
}
if (mXlispPath == wxT("")) {
wxArrayString audacityPathList = wxGetApp().audacityPathList;
wxArrayString pathList;
wxArrayString files;
unsigned int i;
for (i = 0; i < audacityPathList.GetCount(); i++) {
wxString prefix = audacityPathList[i] + wxFILE_SEP_PATH;
wxGetApp().AddUniquePathToPathList(prefix + wxT("nyquist"),
pathList);
}
wxGetApp().FindFilesInPathList(wxT("nyquist.lsp"), pathList, files);
if (files.GetCount() > 0) {
mXlispPath = ::wxPathOnly(files[0]);
}
}
/* set_xlisp_path doesn't handle fn_Str() in Unicode build. May or may not actually work. */
nyx_set_xlisp_path(mXlispPath.mb_str());
fname = mXlispPath + wxFILE_SEP_PATH + wxT("nyinit.lsp");
return ::wxFileExists(fname);
}
int EffectNyquist::StaticGetCallback(float *buffer, int channel,
long start, long len, long totlen,
void *userdata)
@ -1427,7 +1545,11 @@ wxArrayString EffectNyquist::GetNyquistSearchPath()
return pathList;
}
/**********************************************************/
///////////////////////////////////////////////////////////////////////////////
//
// NyquistDialog
//
///////////////////////////////////////////////////////////////////////////////
#define ID_NYQ_SLIDER 2000
#define ID_NYQ_TEXT 3000
@ -1584,6 +1706,10 @@ NyquistDialog::NyquistDialog(wxWindow * parent, wxWindowID id,
mainSizer->SetSizeHints(this);
}
// ============================================================================
// NyquistDialog implementation
// ============================================================================
void NyquistDialog::OnSlider(wxCommandEvent & /* event */)
{
if (mInHandler) {
@ -1715,7 +1841,12 @@ void NyquistDialog::OnPreview(wxCommandEvent & /* event */)
mEffect->Preview();
}
/**********************************************************/
///////////////////////////////////////////////////////////////////////////////
//
// NyquistInputDialog
//
///////////////////////////////////////////////////////////////////////////////
#define ID_VERSION 1001
BEGIN_EVENT_TABLE(NyquistInputDialog, wxDialog)
@ -1770,6 +1901,10 @@ NyquistInputDialog::NyquistInputDialog(wxWindow * parent, wxWindowID id,
mCommandText->SetFocus();
}
// ============================================================================
// NyquistInputDialog implementation
// ============================================================================
wxString NyquistInputDialog::GetCommand()
{
return mCommandText->GetValue();
@ -1805,7 +1940,11 @@ void NyquistInputDialog::OnPreview(wxCommandEvent & /* event */)
}
/**********************************************************/
///////////////////////////////////////////////////////////////////////////////
//
// NyquistOutputDialog
//
///////////////////////////////////////////////////////////////////////////////
BEGIN_EVENT_TABLE(NyquistOutputDialog, wxDialog)
@ -1849,6 +1988,10 @@ NyquistOutputDialog::NyquistOutputDialog(wxWindow * parent, wxWindowID id,
mainSizer->SetSizeHints(this);
}
// ============================================================================
// NyquistOutputDialog implementation
// ============================================================================
void NyquistOutputDialog::OnOk(wxCommandEvent & /* event */)
{
EndModal(wxID_OK);

View File

@ -28,6 +28,9 @@
#include <string>
#define NYQUISTEFFECTS_VERSION wxT("1.0.0.0");
#define NYQUISTEFFECTS_FAMILY L"Nyquist"
class NyqControl
{
public:
@ -60,18 +63,26 @@ class AUDACITY_DLL_API EffectNyquist:public Effect
EffectNyquist(wxString fName);
virtual ~EffectNyquist();
bool SetXlispPath();
// IdentInterface implementation
bool LoadedNyFile() {
return mOK;
}
virtual PluginID GetID();
virtual wxString GetPath();
virtual wxString GetName();
virtual wxString GetVendor();
virtual wxString GetVersion();
virtual wxString GetDescription();
void Continue();
void Break();
void Stop();
// EffectIdentInterface implementation
void SetCommand(wxString cmd);
wxString GetOutput();
virtual EffectType GetType();
virtual wxString GetFamily();
virtual bool IsInteractive();
virtual bool IsDefault();
virtual bool IsLegacy();
virtual bool SupportsRealtime();
virtual bool SupportsAutomation();
// Effect implementation
/** Get the name of the effect (taken from the script that is loaded). Note
* that this name is currently not translated because the translations system
@ -121,6 +132,22 @@ class AUDACITY_DLL_API EffectNyquist:public Effect
virtual bool SupportsChains();
virtual bool TransferParameters( Shuttle & shuttle );
// EffectNyquist implementation
bool SetXlispPath();
bool LoadedNyFile() {
return mOK;
}
void Continue();
void Break();
void Stop();
void SetCommand(wxString cmd);
wxString GetOutput();
static wxArrayString GetNyquistSearchPath();
private:
@ -175,6 +202,8 @@ class AUDACITY_DLL_API EffectNyquist:public Effect
wxString mName; ///< Name of the Effect
wxString mAction;
wxString mInfo;
wxString mAuthor;
wxString mCopyright;
bool mEnablePreview;
bool mDebug;
std::string mDebugOutput;

View File

@ -19,60 +19,100 @@
using namespace Vamp;
using namespace Vamp::HostExt;
#ifdef EFFECT_CATEGORIES
static std::map<wxString, wxString> gCategoryMap;
#define VAMP(S) wxT("http://audacityteam.org/namespace#VampCategories") wxT(S)
#define ATEAM(S) wxT("http://audacityteam.org/namespace#") wxT(S)
/** Initialise the data structure that maps locally generated URI strings to
internal ones. */
static void InitCategoryMap()
// ============================================================================
// Module registration entry point
//
// This is the symbol that Audacity looks for when the module is built as a
// dynamic library.
//
// When the module is builtin to Audacity, we use the same function, but it is
// declared static so as not to clash with other builtin modules.
// ============================================================================
DECLARE_MODULE_ENTRY(AudacityModule)
{
gCategoryMap[VAMP("/Time")] = ATEAM("TimeAnalyser");
gCategoryMap[VAMP("/Time/Onsets")] = ATEAM("OnsetDetector");
// Create and register the importer
return new VampEffectsModule(moduleManager, path);
}
/** Map the generated VAMP category URI to the internal ones. */
static wxString MapCategoryUri(const wxString& uri)
{
std::map<wxString, wxString>::const_iterator iter;
iter = gCategoryMap.find(uri);
if (iter != gCategoryMap.end())
return iter->second;
return uri;
}
// ============================================================================
// Register this as a builtin module
// ============================================================================
DECLARE_BUILTIN_MODULE(VampsEffectBuiltin);
/** Generate category URIs for all levels in a VAMP category hierarchy,
add them to the EffectManager and return the most detailed one. */
static wxString VampHierarchyToUri(const PluginLoader::PluginCategoryHierarchy& h)
///////////////////////////////////////////////////////////////////////////////
//
// VampEffectsModule
//
///////////////////////////////////////////////////////////////////////////////
VampEffectsModule::VampEffectsModule(ModuleManagerInterface *moduleManager,
const wxString *path)
{
// Else, generate URIs and add them to the EffectManager
EffectManager& em = EffectManager::Get();
wxString vampCategory =
wxString::FromAscii("http://audacityteam.org/namespace#VampCategories");
EffectCategory* parent =
em.LookupCategory(wxT("http://lv2plug.in/ns/lv2core#AnalyserPlugin"));
if (parent) {
for (size_t c = 0; c < h.size(); ++c) {
vampCategory += wxT("/");
wxString catName = wxString::FromAscii(h[c].c_str());
vampCategory += catName;
EffectCategory* ec = em.AddCategory(MapCategoryUri(vampCategory),
catName);
em.AddCategoryParent(ec, parent);
parent = ec;
}
mModMan = moduleManager;
if (path)
{
mPath = *path;
}
return MapCategoryUri(vampCategory);
}
#endif
void LoadVampPlugins()
VampEffectsModule::~VampEffectsModule()
{
}
// ============================================================================
// IdentInterface implementation
// ============================================================================
wxString VampEffectsModule::GetID()
{
// Can be anything, but this is a v4 UUID
return wxT("33a86140-7310-4bdf-ad8e-a4af29079f61");
}
wxString VampEffectsModule::GetPath()
{
return mPath;
}
wxString VampEffectsModule::GetName()
{
return _("Vamp Effects Module");
}
wxString VampEffectsModule::GetVendor()
{
return _("The Audacity Team");
}
wxString VampEffectsModule::GetVersion()
{
// This "may" be different if this were to be maintained as a separate DLL
return VAMPEFFECTS_VERSION;
}
wxString VampEffectsModule::GetDescription()
{
return _("Provides Vamp Effects support to Audacity");
}
// ============================================================================
// ModuleInterface implementation
// ============================================================================
bool VampEffectsModule::Initialize()
{
// Nothing to do here
return true;
}
void VampEffectsModule::Terminate()
{
// Nothing to do here
return;
}
bool VampEffectsModule::AutoRegisterPlugins(PluginManagerInterface & pm)
{
#ifdef EFFECT_CATEGORIES
InitCategoryMap();
#endif
@ -155,13 +195,115 @@ void LoadVampPlugins()
#else
VampEffect *effect = new VampEffect(*i, n, hasParameters, name);
#endif
em.RegisterEffect(effect);
em.RegisterEffect(this, effect);
++n;
}
delete vp;
}
return true;
}
wxArrayString VampEffectsModule::FindPlugins(PluginManagerInterface & pm)
{
// Nothing to do here yet
return wxArrayString();
}
bool VampEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxString & path)
{
// Nothing to do here yet
return false;
}
bool VampEffectsModule::IsPluginValid(const PluginID & ID,
const wxString & path)
{
Vamp::HostExt::PluginLoader *loader = Vamp::HostExt::PluginLoader::getInstance();
Vamp::Plugin *plug = loader->loadPlugin(ID.ToUTF8().data(), 48000); // rate doesn't matter here
if (plug)
{
delete plug;
return true;
}
return false;
}
IdentInterface *VampEffectsModule::CreateInstance(const PluginID & ID,
const wxString & path)
{
// Nothing to do here yet since we are autoregistering (and creating legacy
// effects anyway).
return NULL;
}
void VampEffectsModule::DeleteInstance(IdentInterface *instance)
{
// Nothing to do here yet
}
// ============================================================================
// VampEffectsModule implementation
// ============================================================================
#ifdef EFFECT_CATEGORIES
static std::map<wxString, wxString> gCategoryMap;
#define VAMP(S) wxT("http://audacityteam.org/namespace#VampCategories") wxT(S)
#define ATEAM(S) wxT("http://audacityteam.org/namespace#") wxT(S)
/** Initialise the data structure that maps locally generated URI strings to
internal ones. */
static void InitCategoryMap()
{
gCategoryMap[VAMP("/Time")] = ATEAM("TimeAnalyser");
gCategoryMap[VAMP("/Time/Onsets")] = ATEAM("OnsetDetector");
}
/** Map the generated VAMP category URI to the internal ones. */
static wxString MapCategoryUri(const wxString& uri)
{
std::map<wxString, wxString>::const_iterator iter;
iter = gCategoryMap.find(uri);
if (iter != gCategoryMap.end())
return iter->second;
return uri;
}
/** Generate category URIs for all levels in a VAMP category hierarchy,
add them to the EffectManager and return the most detailed one. */
static wxString VampHierarchyToUri(const PluginLoader::PluginCategoryHierarchy& h)
{
// Else, generate URIs and add them to the EffectManager
EffectManager& em = EffectManager::Get();
wxString vampCategory =
wxString::FromAscii("http://audacityteam.org/namespace#VampCategories");
EffectCategory* parent =
em.LookupCategory(wxT("http://lv2plug.in/ns/lv2core#AnalyserPlugin"));
if (parent) {
for (size_t c = 0; c < h.size(); ++c) {
vampCategory += wxT("/");
wxString catName = wxString::FromAscii(h[c].c_str());
vampCategory += catName;
EffectCategory* ec = em.AddCategory(MapCategoryUri(vampCategory),
catName);
em.AddCategoryParent(ec, parent);
parent = ec;
}
}
return MapCategoryUri(vampCategory);
}
#endif
void LoadVampPlugins()
{
}
void UnloadVampPlugins()

View File

@ -8,5 +8,48 @@
**********************************************************************/
void LoadVampPlugins();
void UnloadVampPlugins();
#include "audacity/ModuleInterface.h"
#include "audacity/EffectInterface.h"
#include "audacity/PluginInterface.h"
///////////////////////////////////////////////////////////////////////////////
//
// VampEffectsModule
//
///////////////////////////////////////////////////////////////////////////////
class VampEffectsModule : public ModuleInterface
{
public:
VampEffectsModule(ModuleManagerInterface *moduleManager, const wxString *path);
virtual ~VampEffectsModule();
// IdentInterface implementatino
virtual wxString GetID();
virtual wxString GetPath();
virtual wxString GetName();
virtual wxString GetVendor();
virtual wxString GetVersion();
virtual wxString GetDescription();
// ModuleInterface implementation
virtual bool Initialize();
virtual void Terminate();
virtual bool AutoRegisterPlugins(PluginManagerInterface & pm);
virtual wxArrayString FindPlugins(PluginManagerInterface & pm);
virtual bool RegisterPlugin(PluginManagerInterface & pm, const wxString & path);
virtual bool IsPluginValid(const PluginID & ID, const wxString & path);
virtual IdentInterface *CreateInstance(const PluginID & ID, const wxString & path);
virtual void DeleteInstance(IdentInterface *instance);
// VampEffectModule implementation
private:
ModuleManagerInterface *mModMan;
wxString mPath;
};

View File

@ -33,6 +33,12 @@
#include <wx/scrolwin.h>
#include <wx/version.h>
///////////////////////////////////////////////////////////////////////////////
//
// VampEffect
//
///////////////////////////////////////////////////////////////////////////////
VampEffect::VampEffect(Vamp::HostExt::PluginLoader::PluginKey key,
int output,
bool hasParameters,
@ -46,6 +52,9 @@ VampEffect::VampEffect(Vamp::HostExt::PluginLoader::PluginKey key,
mCategory(category),
mPlugin(NULL)
{
Vamp::HostExt::PluginLoader *loader = Vamp::HostExt::PluginLoader::getInstance();
mPlugin = loader->loadPlugin(mKey, 48000); // rate doesn't matter here
SetEffectFlags(PLUGIN_EFFECT | ANALYZE_EFFECT);
}
@ -55,6 +64,82 @@ VampEffect::~VampEffect()
mPlugin = NULL;
}
// ============================================================================
// IdentInterface implementation
// ============================================================================
wxString VampEffect::GetID()
{
return mName;
}
wxString VampEffect::GetPath()
{
Vamp::HostExt::PluginLoader *loader = Vamp::HostExt::PluginLoader::getInstance();
return LAT1CTOWX(loader->getLibraryPathForPlugin(mKey).c_str());
}
wxString VampEffect::GetName()
{
return mName;
}
wxString VampEffect::GetVendor()
{
return LAT1CTOWX(mPlugin->getMaker().c_str());
}
wxString VampEffect::GetVersion()
{
return wxString::Format(wxT("%d"), mPlugin->getPluginVersion());
}
wxString VampEffect::GetDescription()
{
return LAT1CTOWX(mPlugin->getCopyright().c_str());
}
// ============================================================================
// EffectIdentInterface implementation
// ============================================================================
EffectType VampEffect::GetType()
{
// For now, relegate to Effect()
return Effect::GetType();
}
wxString VampEffect::GetFamily()
{
return VAMPEFFECTS_FAMILY;
}
bool VampEffect::IsInteractive()
{
// For now, relegate to Effect()
return Effect::IsInteractive();
}
bool VampEffect::IsDefault()
{
return false;
}
bool VampEffect::IsLegacy()
{
return true;
}
bool VampEffect::SupportsRealtime()
{
return false;
}
bool VampEffect::SupportsAutomation()
{
return true;
}
wxString VampEffect::GetEffectName()
{
if (mHasParameters) {

View File

@ -24,7 +24,8 @@ class wxComboBox;
#include <vamp-hostsdk/PluginLoader.h>
void LoadVampPlugins();
#define VAMPEFFECTS_VERSION wxT("1.0.0.0");
#define VAMPEFFECTS_FAMILY L"Vamp"
class VampEffect : public Effect {
@ -37,6 +38,27 @@ class VampEffect : public Effect {
wxString category = wxString());
virtual ~VampEffect();
// IdentInterface implementation
virtual PluginID GetID();
virtual wxString GetPath();
virtual wxString GetName();
virtual wxString GetVendor();
virtual wxString GetVersion();
virtual wxString GetDescription();
// EffectIdentInterface implementation
virtual EffectType GetType();
virtual wxString GetFamily();
virtual bool IsInteractive();
virtual bool IsDefault();
virtual bool IsLegacy();
virtual bool SupportsRealtime();
virtual bool SupportsAutomation();
// Effect implementation
virtual wxString GetEffectName();
virtual std::set<wxString> GetEffectCategories();

View File

@ -92,8 +92,6 @@ void EffectsPrefs::PopulateOrExchange(ShuttleGui & S)
wxT("/VST/Enable"),
true);
#endif
S.AddFixedText(_("Restart Audacity to apply changes."));
}
S.EndStatic();
@ -106,13 +104,15 @@ void EffectsPrefs::PopulateOrExchange(ShuttleGui & S)
visualgroups.Add(_("Sorted by Effect Name"));
visualgroups.Add(_("Sorted by Publisher and Effect Name"));
visualgroups.Add(_("Sorted by Type and Effect Name"));
visualgroups.Add(_("Grouped by Publisher"));
visualgroups.Add(_("Grouped by Type (Ladspa, VST, etc.)"));
visualgroups.Add(_("Grouped by Type"));
prefsgroups.Add(wxT("name"));
prefsgroups.Add(wxT("publisher:name"));
prefsgroups.Add(wxT("publisher"));
prefsgroups.Add(wxT("family"));
prefsgroups.Add(wxT("sortby:name"));
prefsgroups.Add(wxT("sortby:publisher:name"));
prefsgroups.Add(wxT("sortby:type:name"));
prefsgroups.Add(wxT("groupby:publisher"));
prefsgroups.Add(wxT("groupby:type"));
wxChoice *c = S.TieChoice(_("Effects in menus are:"),
wxT("/Effects/GroupBy"),
@ -158,43 +158,10 @@ void EffectsPrefs::PopulateOrExchange(ShuttleGui & S)
#endif
}
void EffectsPrefs::SetState(const wxString & family, const wxString & key)
{
PluginManager & pm = PluginManager::Get();
bool state = gPrefs->Read(wxT("/Nyquist/Enable"), true);
const PluginDescriptor *plug = pm.GetFirstPluginForEffectFamily(family);
while (plug)
{
pm.EnablePlugin(plug->GetID(), state);
plug = pm.GetNextPluginForEffectFamily(family);
}
}
bool EffectsPrefs::Apply()
{
ShuttleGui S(this, eIsSavingToPrefs);
PopulateOrExchange(S);
#ifdef USE_NYQUIST
SetState(wxT("Nyquist"), wxT("/Nyquist/Enable"));
#endif
#ifdef USE_LADSPA
SetState(wxT("Ladspa"), wxT("/Ladspa/Enable"));
#endif
#ifdef USE_LV2
SetState(wxT("LV2"), wxT("/LV2/Enable"));
#endif
#ifdef USE_AUDIO_UNITS
SetState(wxT("AudioUnit"), wxT("/AudioUnits/Enable"));
#endif
#ifdef USE_VAMP
SetState(wxT("VAMP"), wxT("/VAMP/Enable"));
#endif
return true;
}

View File

@ -32,7 +32,6 @@ class EffectsPrefs:public PrefsPanel
private:
void Populate();
void PopulateOrExchange(ShuttleGui & S);
void SetState(const wxString & family, const wxString & key);
};
#endif

View File

@ -784,6 +784,7 @@
<copy Include="..\..\..\plug-ins\clipfix.ny" />
<copy Include="..\..\..\plug-ins\crossfadein.ny" />
<copy Include="..\..\..\plug-ins\crossfadeout.ny" />
<copy Include="..\..\..\plug-ins\crossfadetracks.ny" />
<copy Include="..\..\..\plug-ins\delay.ny" />
<copy Include="..\..\..\plug-ins\equalabel.ny" />
<copy Include="..\..\..\plug-ins\highpass.ny" />
@ -794,6 +795,9 @@
<copy Include="..\..\..\plug-ins\sample-data-export.ny" />
<copy Include="..\..\..\plug-ins\SilenceMarker.ny" />
<copy Include="..\..\..\plug-ins\SoundFinder.ny" />
<copy Include="..\..\..\plug-ins\SpectralEditMulti.ny" />
<copy Include="..\..\..\plug-ins\SpectralEditParametricEQ.ny" />
<copy Include="..\..\..\plug-ins\SpectralEditShelves.ny" />
<copy Include="..\..\..\plug-ins\StudioFadeOut.ny" />
<copy Include="..\..\..\plug-ins\tremolo.ny" />
<copy Include="..\..\..\plug-ins\vocalremover.ny" />

View File

@ -1852,5 +1852,17 @@
<copy Include="..\..\..\plug-ins\vocoder.ny">
<Filter>plug-ins</Filter>
</copy>
<copy Include="..\..\..\plug-ins\crossfadetracks.ny">
<Filter>plug-ins</Filter>
</copy>
<copy Include="..\..\..\plug-ins\SpectralEditMulti.ny">
<Filter>plug-ins</Filter>
</copy>
<copy Include="..\..\..\plug-ins\SpectralEditParametricEQ.ny">
<Filter>plug-ins</Filter>
</copy>
<copy Include="..\..\..\plug-ins\SpectralEditShelves.ny">
<Filter>plug-ins</Filter>
</copy>
</ItemGroup>
</Project>