From ad92e8c4bf685f5ba317b23c2c8e2865f43c96f2 Mon Sep 17 00:00:00 2001 From: lllucius Date: Fri, 14 Nov 2014 03:03:17 +0000 Subject: [PATCH] One more round of effects changes. The big thing is the common efffects UI. Right now Ladspa and VST have been converted to use it and Audiounits will be next. It makes everything nice and consistent while reducing the clutter in the dialog. Other goodies are: Ladspa effects now show output controls when supplied by the effect Ladspa effects now work fine as Analyze type effects Ladspa now has user presets VST effects dialog is now less cluttered...leaving more room for the effect Ladspa and VST effects now share a common UI Ladspa and VST effects are now usable in chains Ladspa and VST effects now handle user presets the same way Currently active effects settings automatically saved and reloaded Can now do numeric range checking on input fields. And, as always, plenty of critter squashing. --- Makefile.am | 8 + Makefile.in | 8 + include/audacity/ConfigInterface.h | 10 + include/audacity/EffectAutomationParameters.h | 178 + include/audacity/EffectInterface.h | 75 +- include/audacity/ModuleInterface.h | 7 +- include/audacity/PluginInterface.h | 12 +- locale/Makefile.in | 40 +- mac/Audacity.xcodeproj/project.pbxproj | 2 + src/AudacityApp.cpp | 3 +- src/BatchCommands.cpp | 9 +- src/Makefile.in | 10 +- src/Menus.cpp | 77 +- src/ModuleManager.cpp | 21 +- src/ModuleManager.h | 5 +- src/PluginManager.cpp | 225 +- src/PluginManager.h | 35 +- src/ShuttleGui.cpp | 4 +- src/ShuttleGui.h | 4 +- src/TrackPanel.cpp | 4 +- src/effects/Effect.cpp | 527 ++- src/effects/Effect.h | 66 +- src/effects/EffectManager.cpp | 51 +- src/effects/EffectManager.h | 4 +- src/effects/VST/VSTEffect.cpp | 3620 ++++++++--------- src/effects/VST/VSTEffect.h | 183 +- src/effects/ladspa/LadspaEffect.cpp | 1297 +++--- src/effects/ladspa/LadspaEffect.h | 155 +- src/prefs/EffectsPrefs.cpp | 6 +- src/widgets/valnum.cpp | 223 +- src/widgets/valnum.h | 20 +- win/Projects/Audacity/Audacity.vcxproj | 2647 ++++++------ .../Audacity/Audacity.vcxproj.filters | 9 +- 33 files changed, 5381 insertions(+), 4164 deletions(-) create mode 100644 include/audacity/EffectAutomationParameters.h diff --git a/Makefile.am b/Makefile.am index 5442bfc36..2671a0d0f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,6 +8,14 @@ dist_doc_DATA = LICENSE.txt README.txt dist_pkgdata_DATA = presets/EQDefaultCurves.xml nobase_dist_pkgdata_DATA = \ + include/audacity/ConfigInterface.h \ + include/audacity/EffectAutomationParameters.h \ + include/audacity/EffectInterface.h \ + include/audacity/IdentInterface.h \ + include/audacity/ImporterInterface.h \ + include/audacity/ModuleInterface.h \ + include/audacity/PluginInterface.h \ + include/audacity/Types.h \ nyquist/bug.lsp \ nyquist/dspprims.lsp \ nyquist/envelopes.lsp \ diff --git a/Makefile.in b/Makefile.in index 22d0dfae4..b02da105c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -488,6 +488,14 @@ bin_SCRIPTS = audacity$(EXEEXT) dist_doc_DATA = LICENSE.txt README.txt dist_pkgdata_DATA = presets/EQDefaultCurves.xml nobase_dist_pkgdata_DATA = \ + include/audacity/ConfigInterface.h \ + include/audacity/EffectAutomationParameters.h \ + include/audacity/EffectInterface.h \ + include/audacity/IdentInterface.h \ + include/audacity/ImporterInterface.h \ + include/audacity/ModuleInterface.h \ + include/audacity/PluginInterface.h \ + include/audacity/Types.h \ nyquist/bug.lsp \ nyquist/dspprims.lsp \ nyquist/envelopes.lsp \ diff --git a/include/audacity/ConfigInterface.h b/include/audacity/ConfigInterface.h index 8eb7b37a6..4bd255f9f 100644 --- a/include/audacity/ConfigInterface.h +++ b/include/audacity/ConfigInterface.h @@ -49,6 +49,8 @@ class AUDACITY_DLL_API ConfigClientInterface public: virtual ~ConfigClientInterface() {}; + virtual bool GetSharedConfigSubgroups(const wxString & group, wxArrayString & subgroups) = 0; + virtual bool GetSharedConfig(const wxString & group, const wxString & key, wxString & value, const wxString & defval) = 0; virtual bool GetSharedConfig(const wxString & group, const wxString & key, int & value, int defval) = 0; virtual bool GetSharedConfig(const wxString & group, const wxString & key, bool & value, bool defval) = 0; @@ -63,6 +65,11 @@ public: virtual bool SetSharedConfig(const wxString & group, const wxString & key, const double & value) = 0; virtual bool SetSharedConfig(const wxString & group, const wxString & key, const sampleCount & value) = 0; + virtual bool RemoveSharedConfigSubgroup(const wxString & group) = 0; + virtual bool RemoveSharedConfig(const wxString & group, const wxString & key) = 0; + + virtual bool GetPrivateConfigSubgroups(const wxString & group, wxArrayString & subgroups) = 0; + virtual bool GetPrivateConfig(const wxString & group, const wxString & key, wxString & value, const wxString & defval) = 0; virtual bool GetPrivateConfig(const wxString & group, const wxString & key, int & value, int defval) = 0; virtual bool GetPrivateConfig(const wxString & group, const wxString & key, bool & value, bool defval) = 0; @@ -76,6 +83,9 @@ public: virtual bool SetPrivateConfig(const wxString & group, const wxString & key, const float & value) = 0; virtual bool SetPrivateConfig(const wxString & group, const wxString & key, const double & value) = 0; virtual bool SetPrivateConfig(const wxString & group, const wxString & key, const sampleCount & value) = 0; + + virtual bool RemovePrivateConfigSubgroup(const wxString & group) = 0; + virtual bool RemovePrivateConfig(const wxString & group, const wxString & key) = 0; }; class ConfigHostInterface diff --git a/include/audacity/EffectAutomationParameters.h b/include/audacity/EffectAutomationParameters.h new file mode 100644 index 000000000..59b42924e --- /dev/null +++ b/include/audacity/EffectAutomationParameters.h @@ -0,0 +1,178 @@ +/********************************************************************** + + Audacity: A Digital Audio Editor + + EffectAutomationParameters.h + + Leland Lucius + + Copyright (c) 2014, Audacity Team + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +**********************************************************************/ + +#ifndef __AUDACITY_EFFECTAUTOMATIONPARAMETERS_H__ +#define __AUDACITY_EFFECTAUTOMATIONPARAMETERS_H__ + +#include +#include + +class EffectAutomationParameters : public wxFileConfig +{ +public: + EffectAutomationParameters() + : wxFileConfig(wxEmptyString, + wxEmptyString, + wxEmptyString, + wxEmptyString, + 0) + { + } + + virtual ~EffectAutomationParameters() + { + } + + virtual bool DoReadString(const wxString & key, wxString *pStr) const + { + return wxFileConfig::DoReadString(NormalizeName(key), pStr); + } + + virtual bool DoReadLong(const wxString & key, long *pl) const + { + return wxFileConfig::DoReadLong(NormalizeName(key), pl); + } + + virtual bool DoWriteString(const wxString & key, const wxString & szValue) + { + return wxFileConfig::DoWriteString(NormalizeName(key), szValue); + } + + virtual bool DoWriteLong(const wxString & key, long lValue) + { + return wxFileConfig::DoWriteLong(NormalizeName(key), lValue); + } + + bool ReadEnum(const wxString & key, int *pi, const wxArrayString & choices) const + { + wxString s; + if (wxFileConfig::Read(key, &s)) + { + int i = choices.Index(s); + if (i != wxNOT_FOUND) + { + *pi = i; + return true; + } + } + return false; + } + + bool ReadEnum(const wxString & key, int *pi, int defVal, const wxArrayString & choices) const + { + if (!ReadEnum(key, pi, choices)) + { + *pi = defVal; + } + return true; + } + + bool WriteEnum(const wxString & key, int value, const wxArrayString & choices) + { + if (value < 0 || value >= (int) choices.GetCount()) + { + return false; + } + + return wxFileConfig::Write(key, choices[value]); + } + + wxString NormalizeName(const wxString & name) const + { + wxString cleaned = name; + + cleaned.Trim(true).Trim(false); + cleaned.Replace(wxT(" "), wxT("_")); + cleaned.Replace(wxT("/"), wxT("_")); + cleaned.Replace(wxT("\\"), wxT("_")); + cleaned.Replace(wxT(":"), wxT("_")); + + return cleaned; + } + + bool GetParameters(wxString & parms) + { + wxFileConfig::SetPath(wxT("/")); + + wxString str; + wxString key; + + long ndx = 0; + bool res = wxFileConfig::GetFirstEntry(key, ndx); + while (res) + { + wxString val; + if (!wxFileConfig::Read(key, &val)) + { + return false; + } + + str += key + wxT("=\"") + val + wxT("\" "); + + res = wxFileConfig::GetNextEntry(key, ndx); + } + str.Trim(); + + parms = str; + + return true; + } + + bool SetParameters(const wxString & parms) + { + wxFileConfig::SetPath(wxT("/")); + + wxArrayString parsed = wxCmdLineParser::ConvertStringToArgs(parms); + + for (size_t i = 0, cnt = parsed.GetCount(); i < cnt; i++) + { + wxString key = parsed[i].BeforeFirst(wxT('=')).Trim(false).Trim(true); + wxString val = parsed[i].AfterFirst(wxT('=')).Trim(false).Trim(true); + + if (!wxFileConfig::Write(key, val)) + { + return false; + } + } + } +}; + +#endif diff --git a/include/audacity/EffectInterface.h b/include/audacity/EffectInterface.h index 239f91f4d..b8765019b 100644 --- a/include/audacity/EffectInterface.h +++ b/include/audacity/EffectInterface.h @@ -42,11 +42,12 @@ #ifndef __AUDACITY_EFFECTINTERFACE_H__ #define __AUDACITY_EFFECTINTERFACE_H__ -#include - #include "audacity/Types.h" #include "audacity/IdentInterface.h" #include "audacity/ConfigInterface.h" +#include "audacity/EffectAutomationParameters.h" + +#include typedef enum EffectType { @@ -65,7 +66,7 @@ public: virtual wxString GetFamily() = 0; // These should move to the "EffectClientInterface" class once all - // effects have bee converted. + // effects have been converted. virtual bool IsInteractive() = 0; // I don't really like this, but couldn't think of a better way to force the @@ -76,13 +77,18 @@ public: // interface. virtual bool IsLegacy() = 0; - // Whether the effect supports realtime processing (while audio is playing). - virtual bool IsRealtimeCapable() = 0; + // Whether the effect supports realtime previewing (while audio is playing). + virtual bool SupportsRealtime() = 0; + + // Can the effect be used without the UI. + virtual bool SupportsAutomation() = 0; }; -class AUDACITY_DLL_API EffectHostInterface : - public EffectIdentInterface, - public ConfigClientInterface +class EffectUIHostInterface; +class EffectUIClientInterface; + +class AUDACITY_DLL_API EffectHostInterface : public EffectIdentInterface, + public ConfigClientInterface { public: virtual ~EffectHostInterface() {}; @@ -92,19 +98,22 @@ public: virtual bool Apply() = 0; virtual void Preview() = 0; -}; -typedef float * pfloat; -typedef std::vector pvec; + // + virtual wxDialog *CreateUI(wxWindow *parent, EffectUIClientInterface *client) = 0; + + // Preset handling + virtual wxString GetUserPresetsGroup(const wxString & name) = 0; + virtual wxString GetCurrentSettingsGroup() = 0; + virtual wxString GetFactoryDefaultsGroup() = 0; +}; class EffectClientInterface : public EffectIdentInterface { public: virtual ~EffectClientInterface() {}; - virtual void SetHost(EffectHostInterface *host) = 0; - virtual bool Startup() = 0; - virtual bool Shutdown() = 0; + virtual bool SetHost(EffectHostInterface *host) = 0; virtual int GetAudioInCount() = 0; virtual int GetAudioOutCount() = 0; @@ -130,7 +139,43 @@ public: virtual bool RealtimeResume() = 0; virtual sampleCount RealtimeProcess(int group, float **inbuf, float **outbuf, sampleCount size) = 0; - virtual bool ShowInterface(void *parent) = 0; + virtual bool ShowInterface(wxWindow *parent, bool forceModal = false) = 0; + + virtual bool GetAutomationParameters(EffectAutomationParameters & parms) = 0; + virtual bool SetAutomationParameters(EffectAutomationParameters & parms) = 0; +}; + +class EffectUIHostInterface +{ +public: + virtual ~EffectUIHostInterface() {}; + +// virtual wxScrolledWindow *GetScrollableClientArea(); +// virtual wxScrolledWindow *GetStaticClientArea(); +}; + +class EffectUIClientInterface +{ +public: + virtual ~EffectUIClientInterface() {}; + + virtual void SetUIHost(EffectUIHostInterface *host) = 0; + virtual bool PopulateUI(wxWindow *parent) = 0; + virtual bool ValidateUI() = 0; + virtual bool HideUI() = 0; + virtual bool CloseUI() = 0; + + virtual void LoadUserPreset(const wxString & name) = 0; + virtual void SaveUserPreset(const wxString & name) = 0; + + virtual void LoadFactoryPreset(int id) = 0; + virtual void LoadFactoryDefaults() = 0; + + virtual wxArrayString GetFactoryPresets() = 0; + + virtual void ExportPresets() = 0; + virtual void ImportPresets() = 0; + virtual void ShowOptions() = 0; }; class EffectManagerInterface diff --git a/include/audacity/ModuleInterface.h b/include/audacity/ModuleInterface.h index dd0ebaf80..93eea9c4e 100644 --- a/include/audacity/ModuleInterface.h +++ b/include/audacity/ModuleInterface.h @@ -89,8 +89,11 @@ public: virtual bool RegisterPlugin(PluginManagerInterface & pluginManager, const wxString & path) = 0; - // When appropriate, CreateInstance() will be called to instantiate the plugins. - virtual void *CreateInstance(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; + + // When appropriate, DeleteInstance() will be called to delete the plugin. + virtual void DeleteInstance(IdentInterface *instance) = 0; }; // ============================================================================ diff --git a/include/audacity/PluginInterface.h b/include/audacity/PluginInterface.h index d9275ff7d..80670bac0 100644 --- a/include/audacity/PluginInterface.h +++ b/include/audacity/PluginInterface.h @@ -48,8 +48,6 @@ #include "audacity/IdentInterface.h" #include "audacity/ImporterInterface.h" -class AUDACITY_DLL_API IdentInterface; -class AUDACITY_DLL_API EffectIdentInterface; class PluginManagerInterface { public: @@ -64,6 +62,8 @@ public: wxArrayString & files, bool directories = false) = 0; + virtual bool GetSharedConfigSubgroups(const PluginID & ID, const wxString & group, wxArrayString & subgroups) = 0; + virtual bool GetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, wxString & value, const wxString & defval = wxString()) = 0; virtual bool GetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, int & value, int defval = 0) = 0; virtual bool GetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, bool & value, bool defval = false) = 0; @@ -78,6 +78,11 @@ public: virtual bool SetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, const double & value) = 0; virtual bool SetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, const sampleCount & value) = 0; + virtual bool RemoveSharedConfigSubgroup(const PluginID & ID, const wxString & group) = 0; + virtual bool RemoveSharedConfig(const PluginID & ID, const wxString & group, const wxString & key) = 0; + + virtual bool GetPrivateConfigSubgroups(const PluginID & ID, const wxString & group, wxArrayString & subgroups) = 0; + virtual bool GetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, wxString & value, const wxString & defval = wxString()) = 0; virtual bool GetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, int & value, int defval = 0) = 0; virtual bool GetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, bool & value, bool defval = false) = 0; @@ -91,6 +96,9 @@ public: virtual bool SetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, const float & value) = 0; virtual bool SetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, const double & value) = 0; virtual bool SetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, const sampleCount & value) = 0; + + virtual bool RemovePrivateConfigSubgroup(const PluginID & ID, const wxString & group) = 0; + virtual bool RemovePrivateConfig(const PluginID & ID, const wxString & group, const wxString & key) = 0; }; #endif // __AUDACITY_PLUGININTERFACE_H__ diff --git a/locale/Makefile.in b/locale/Makefile.in index 932373604..ca3ef1282 100644 --- a/locale/Makefile.in +++ b/locale/Makefile.in @@ -35,29 +35,29 @@ INSTALL_DATA = ${INSTALL} -m 644 # We use $(mkdir_p). # In automake <= 1.9.x, $(mkdir_p) is defined either as "mkdir -p --" or as # "$(mkinstalldirs)" or as "$(install_sh) -d". For these automake versions, -# ${SHELL} /home/yam/a/audacity/autotools/install-sh does not start with $(SHELL), so we add it. -# In automake >= 1.10, /usr/bin/mkdir -p is derived from ${MKDIR_P}, which is defined +# ${SHELL} /Users/yam/a/audacity/autotools/install-sh does not start with $(SHELL), so we add it. +# In automake >= 1.10, $(top_builddir)/autotools/install-sh -c -d is derived from ${MKDIR_P}, which is defined # either as "/path/to/mkdir -p" or ".../install-sh -c -d". For these automake # versions, $(mkinstalldirs) and $(install_sh) are unused. -mkinstalldirs = $(SHELL) ${SHELL} /home/yam/a/audacity/autotools/install-sh -d -install_sh = $(SHELL) ${SHELL} /home/yam/a/audacity/autotools/install-sh -MKDIR_P = /usr/bin/mkdir -p -mkdir_p = /usr/bin/mkdir -p +mkinstalldirs = $(SHELL) ${SHELL} /Users/yam/a/audacity/autotools/install-sh -d +install_sh = $(SHELL) ${SHELL} /Users/yam/a/audacity/autotools/install-sh +MKDIR_P = ../autotools/install-sh -c -d +mkdir_p = $(top_builddir)/autotools/install-sh -c -d -GMSGFMT_ = /usr/bin/msgfmt -GMSGFMT_no = /usr/bin/msgfmt -GMSGFMT_yes = /usr/bin/msgfmt +GMSGFMT_ = /opt/local/bin/msgfmt +GMSGFMT_no = /opt/local/bin/msgfmt +GMSGFMT_yes = /opt/local/bin/msgfmt GMSGFMT = $(GMSGFMT_$(USE_MSGCTXT)) -MSGFMT_ = /usr/bin/msgfmt -MSGFMT_no = /usr/bin/msgfmt -MSGFMT_yes = /usr/bin/msgfmt +MSGFMT_ = /opt/local/bin/msgfmt +MSGFMT_no = /opt/local/bin/msgfmt +MSGFMT_yes = /opt/local/bin/msgfmt MSGFMT = $(MSGFMT_$(USE_MSGCTXT)) -XGETTEXT_ = /usr/bin/xgettext -XGETTEXT_no = /usr/bin/xgettext -XGETTEXT_yes = /usr/bin/xgettext +XGETTEXT_ = /opt/local/bin/xgettext +XGETTEXT_no = /opt/local/bin/xgettext +XGETTEXT_yes = /opt/local/bin/xgettext XGETTEXT = $(XGETTEXT_$(USE_MSGCTXT)) MSGMERGE = msgmerge -MSGMERGE_UPDATE = /usr/bin/msgmerge --update +MSGMERGE_UPDATE = /opt/local/bin/msgmerge --update MSGINIT = msginit MSGCONV = msgconv MSGFILTER = msgfilter @@ -98,7 +98,7 @@ CATALOGS = @CATALOGS@ mv t-$@ $@ -all: check-macro-version all-yes +all: check-macro-version all-no all-yes: stamp-po all-no: @@ -211,7 +211,7 @@ $(POFILES): $(srcdir)/$(DOMAIN).pot install: install-exec install-data install-exec: -install-data: install-data-yes +install-data: install-data-no if test "$(PACKAGE)" = "gettext-tools"; then \ $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ for file in $(DISTFILES.common) Makevars.template; do \ @@ -269,7 +269,7 @@ install-strip: install installdirs: installdirs-exec installdirs-data installdirs-exec: -installdirs-data: installdirs-data-yes +installdirs-data: installdirs-data-no if test "$(PACKAGE)" = "gettext-tools"; then \ $(mkdir_p) $(DESTDIR)$(gettextsrcdir); \ else \ @@ -313,7 +313,7 @@ installcheck: uninstall: uninstall-exec uninstall-data uninstall-exec: -uninstall-data: uninstall-data-yes +uninstall-data: uninstall-data-no if test "$(PACKAGE)" = "gettext-tools"; then \ for file in $(DISTFILES.common) Makevars.template; do \ rm -f $(DESTDIR)$(gettextsrcdir)/$$file; \ diff --git a/mac/Audacity.xcodeproj/project.pbxproj b/mac/Audacity.xcodeproj/project.pbxproj index 80483c4c4..0b2fb248f 100644 --- a/mac/Audacity.xcodeproj/project.pbxproj +++ b/mac/Audacity.xcodeproj/project.pbxproj @@ -4001,6 +4001,7 @@ 28FE4A060ABF4E960056F5C4 /* mmx_optimized.cpp */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.cpp.cpp; path = mmx_optimized.cpp; sourceTree = ""; tabWidth = 3; }; 28FE4A070ABF4E960056F5C4 /* sse_optimized.cpp */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.cpp.cpp; path = sse_optimized.cpp; sourceTree = ""; tabWidth = 3; }; 28FE4A390ABF58360056F5C4 /* soundtouch_config.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = soundtouch_config.h; path = "../lib-src/soundtouch/include/soundtouch_config.h"; sourceTree = SOURCE_ROOT; tabWidth = 3; }; + 28FEC1B21A12B6FB00FACE48 /* EffectAutomationParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EffectAutomationParameters.h; path = ../include/audacity/EffectAutomationParameters.h; sourceTree = SOURCE_ROOT; }; 82FF184D13CF01A600C1B664 /* dBTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dBTable.cpp; path = sbsms/src/dBTable.cpp; sourceTree = ""; }; 82FF184E13CF01A600C1B664 /* dBTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dBTable.h; path = sbsms/src/dBTable.h; sourceTree = ""; }; 82FF184F13CF01A600C1B664 /* slide.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = slide.cpp; path = sbsms/src/slide.cpp; sourceTree = ""; }; @@ -5588,6 +5589,7 @@ 280A8B3D19F440010091DE70 /* audacity */ = { isa = PBXGroup; children = ( + 28FEC1B21A12B6FB00FACE48 /* EffectAutomationParameters.h */, 280A8B3E19F440160091DE70 /* ConfigInterface.h */, 280A8B3F19F440160091DE70 /* EffectInterface.h */, 280A8B4019F440160091DE70 /* IdentInterface.h */, diff --git a/src/AudacityApp.cpp b/src/AudacityApp.cpp index 7c12dca00..b819ca253 100644 --- a/src/AudacityApp.cpp +++ b/src/AudacityApp.cpp @@ -645,7 +645,7 @@ IMPLEMENT_APP(AudacityApp) #ifdef __WXMAC__ // This should be removed when Lame and FFmpeg support is converted -// from loadable libraries to commands.mLogger +// from loadable libraries to commands. // // The purpose of this is to give the user more control over where libraries // such as Lame and FFmpeg get loaded from. @@ -1008,7 +1008,6 @@ int AudacityApp::FilterEvent(wxEvent & event) return -1; } #endif -#include "effects/VST/VSTEffect.h" // The `main program' equivalent, creating the windows and returning the // main frame diff --git a/src/BatchCommands.cpp b/src/BatchCommands.cpp index 13538530c..744a686bf 100644 --- a/src/BatchCommands.cpp +++ b/src/BatchCommands.cpp @@ -283,10 +283,13 @@ wxArrayString BatchCommands::GetAllCommands() const PluginDescriptor *plug = pm.GetFirstPlugin(PluginTypeEffect); while (plug) { - command = em.GetEffectIdentifier(plug->GetID()); - if (!command.IsEmpty()) + if (plug->IsEffectAutomatable()) { - commands.Add( command); + command = em.GetEffectIdentifier(plug->GetID()); + if (!command.IsEmpty()) + { + commands.Add( command); + } } plug = pm.GetNextPlugin(PluginTypeEffect); } diff --git a/src/Makefile.in b/src/Makefile.in index 64c89c6d0..261a53734 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. +# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -1384,8 +1384,8 @@ $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) $(am__aclocal_m4_deps): configwin.h: stamp-h1 - @test -f $@ || rm -f stamp-h1 - @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 + @if test ! -f $@; then rm -f stamp-h1; else :; fi + @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi stamp-h1: $(srcdir)/configtemplate.h $(top_builddir)/config.status @rm -f stamp-h1 @@ -1396,8 +1396,8 @@ $(srcdir)/configtemplate.h: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) touch $@ configunix.h: stamp-h2 - @test -f $@ || rm -f stamp-h2 - @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h2 + @if test ! -f $@; then rm -f stamp-h2; else :; fi + @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h2; else :; fi stamp-h2: $(srcdir)/configtemplate.h $(top_builddir)/config.status @rm -f stamp-h2 diff --git a/src/Menus.cpp b/src/Menus.cpp index 595c917d4..93c630a0a 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -216,26 +216,6 @@ void AudacityProjectCommandFunctor::operator()(int index, const wxEvent * evt) // Effects menu arrays // WX_DEFINE_ARRAY_PTR(const PluginDescriptor *, EffectPlugs); -static int SortPlugsByDefault(const PluginDescriptor **a, const PluginDescriptor **b) -{ - wxString akey = (*a)->GetVendor(); - wxString bkey = (*b)->GetVendor(); - - if ((*a)->IsEffectDefault()) - { - akey = wxEmptyString; - } - if ((*b)->IsEffectDefault()) - { - bkey = wxEmptyString; - } - - akey += (*a)->GetName(); - bkey += (*b)->GetName(); - - return akey.CmpNoCase(bkey); -} - static int SortPlugsByName(const PluginDescriptor **a, const PluginDescriptor **b) { wxString akey = (*a)->GetName(); @@ -264,6 +244,26 @@ static int SortPlugsByPublisher(const PluginDescriptor **a, const PluginDescript return akey.CmpNoCase(bkey); } +static int SortPlugsByPublisherAndName(const PluginDescriptor **a, const PluginDescriptor **b) +{ + wxString akey = (*a)->GetVendor(); + wxString bkey = (*b)->GetVendor(); + + if ((*a)->IsEffectDefault()) + { + akey = wxEmptyString; + } + if ((*b)->IsEffectDefault()) + { + bkey = wxEmptyString; + } + + akey += (*a)->GetName(); + bkey += (*b)->GetName(); + + return akey.CmpNoCase(bkey); +} + static int SortPlugsByFamily(const PluginDescriptor **a, const PluginDescriptor **b) { wxString akey = (*a)->GetEffectFamily(); @@ -291,8 +291,6 @@ static int SortPlugsByFamily(const PluginDescriptor **a, const PluginDescriptor void AudacityProject::CreateMenusAndCommands() { CommandManager *c = &mCommandManager; - EffectManager& em = EffectManager::Get(); - EffectArray *effects; wxArrayString names; wxArrayInt indices; @@ -934,8 +932,6 @@ void AudacityProject::CreateMenusAndCommands() // the plugin manager...sorry! :-( wxArrayString defaults; - PluginManager & pm = PluginManager::Get(); - const PluginDescriptor *plug; ////////////////////////////////////////////////////////////////////////// // Generate Menu @@ -1005,8 +1001,6 @@ void AudacityProject::CreateMenusAndCommands() c->AddSeparator(); - int additionalEffects = ADVANCED_EFFECT; - // this is really ugly but we need to keep all the old code to get any // effects at all in the menu when EFFECT_CATEGORIES is undefined @@ -1290,14 +1284,19 @@ void AudacityProject::PopulateEffectsMenu(CommandManager* c, if (groupby == wxT("default")) { - defplugs.Sort(SortPlugsByDefault); - optplugs.Sort(SortPlugsByDefault); + defplugs.Sort(SortPlugsByName); + optplugs.Sort(SortPlugsByName); } else if (groupby == wxT("publisher")) { defplugs.Sort(SortPlugsByPublisher); optplugs.Sort(SortPlugsByPublisher); } + else if (groupby == wxT("publisher:name")) + { + defplugs.Sort(SortPlugsByPublisherAndName); + optplugs.Sort(SortPlugsByPublisherAndName); + } else if (groupby == wxT("family")) { defplugs.Sort(SortPlugsByFamily); @@ -1351,11 +1350,7 @@ void AudacityProject::AddEffectMenuItems(CommandManager *c, const PluginDescriptor *plug = plugs[i]; #if defined(EXPERIMENTAL_REALTIME_EFFECTS) - if (plug->GetName() == wxT("Cross Fade In")) - { - int f = 1; - } - int flags = plug->IsEffectRealtimeCapable() ? realflags : batchflags; + int flags = plug->IsEffectRealtime() ? realflags : batchflags; #else int flags = batchflags; #endif @@ -1420,7 +1415,7 @@ void AudacityProject::AddEffectMenuItems(CommandManager *c, groupPlugs.Add(plug->GetID()); } - size_t groupCnt = groupPlugs.GetCount(); + int groupCnt = (int) groupPlugs.GetCount(); if (grouped && groupCnt > 0 && i > 0) { @@ -1437,7 +1432,7 @@ void AudacityProject::AddEffectMenuItems(CommandManager *c, max = 0; } - for (size_t j = 0; j < groupCnt; j++) + for (int j = 0; j < groupCnt; j++) { if (max > 0 && items == max) { @@ -1447,8 +1442,8 @@ void AudacityProject::AddEffectMenuItems(CommandManager *c, end = groupCnt; } c->BeginSubMenu(wxString::Format(_("Plug-ins %d to %d"), - (int) j + 1, - (int) end)); + j + 1, + end)); } c->AddItem(groupNames[j], @@ -3042,6 +3037,10 @@ void AudacityProject::OnEffect(const PluginID & pluginID) case EffectTypeAnalyze: type = ANALYZE_EFFECT; break; + + case EffectTypeNone: + type = 0; + break; } type |= plug->IsEffectDefault() ? BUILTIN_EFFECT : PLUGIN_EFFECT; @@ -3069,6 +3068,10 @@ void AudacityProject::OnEffect(const PluginID & pluginID, bool configured) case EffectTypeAnalyze: type = ANALYZE_EFFECT; break; + + case EffectTypeNone: + type = 0; + break; } type |= plug->IsEffectDefault() ? BUILTIN_EFFECT : PLUGIN_EFFECT; diff --git a/src/ModuleManager.cpp b/src/ModuleManager.cpp index 4578ea8f2..c74d639ee 100644 --- a/src/ModuleManager.cpp +++ b/src/ModuleManager.cpp @@ -578,8 +578,8 @@ bool ModuleManager::IsProviderBuiltin(const PluginID & providerID) return mModuleMains.find(providerID) != mModuleMains.end(); } -void *ModuleManager::CreateProviderInstance(const PluginID & providerID, - const wxString & path) +IdentInterface *ModuleManager::CreateProviderInstance(const PluginID & providerID, + const wxString & path) { if (path.empty() && mDynModules.find(providerID) != mDynModules.end()) { @@ -589,9 +589,9 @@ void *ModuleManager::CreateProviderInstance(const PluginID & providerID, return LoadModule(path); } -void *ModuleManager::CreateInstance(const PluginID & providerID, - const PluginID & ID, - const wxString & path) +IdentInterface *ModuleManager::CreateInstance(const PluginID & providerID, + const PluginID & ID, + const wxString & path) { if (mDynModules.find(providerID) == mDynModules.end()) { @@ -600,3 +600,14 @@ void *ModuleManager::CreateInstance(const PluginID & providerID, return mDynModules[providerID]->CreateInstance(ID, path); } + +void ModuleManager::DeleteInstance(const PluginID & providerID, + IdentInterface *instance) +{ + if (mDynModules.find(providerID) == mDynModules.end()) + { + return; + } + + mDynModules[providerID]->DeleteInstance(instance); +} diff --git a/src/ModuleManager.h b/src/ModuleManager.h index 932316da6..2b58b7808 100644 --- a/src/ModuleManager.h +++ b/src/ModuleManager.h @@ -98,8 +98,9 @@ public: void InitializePlugins(); bool IsProviderBuiltin(const PluginID & provider); - void *CreateProviderInstance(const PluginID & ID, const wxString & path); - void *CreateInstance(const PluginID & provider, const PluginID & ID, const wxString & path); + 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); private: void InitializeBuiltins(); diff --git a/src/PluginManager.cpp b/src/PluginManager.cpp index aa4dbeea6..983f7292b 100644 --- a/src/PluginManager.cpp +++ b/src/PluginManager.cpp @@ -528,7 +528,7 @@ void PluginRegistrationDialog::PopulateOrExchange(ShuttleGui &S) ProviderMap provs; wxArrayString keys; wxArrayString paths; - wxString padding = L"0000000000"; + wxString padding = wxT("0000000000"); const PluginDescriptor *plug = pm.GetFirstPlugin(PluginTypeModule); while (plug) { @@ -552,7 +552,7 @@ void PluginRegistrationDialog::PopulateOrExchange(ShuttleGui &S) for (size_t j = 0, jcnt = newPaths.size(); j < jcnt; j++) { - sortable.push_back(key + L" " + newPaths[j]); + sortable.push_back(key + wxT(" ") + newPaths[j]); } } @@ -571,7 +571,7 @@ void PluginRegistrationDialog::PopulateOrExchange(ShuttleGui &S) miState.push_back( SHOW_CHECKED ); wxString item = sortable[i]; - int split = item.find(L" "); + int split = item.find(wxT(" ")); mProvs.push_back(provs[item.substr(0, split)]); mPaths.push_back(item.substr(split + 1, wxString::npos)); @@ -758,23 +758,26 @@ PluginDescriptor::PluginDescriptor() mEffectInteractive = false; mEffectDefault = false; mEffectLegacy = false; + mEffectRealtime = false; + mEffectAutomatable = false; } PluginDescriptor::~PluginDescriptor() { if (mInstance) { - switch (mPluginType) - { - case PluginTypeEffect: - EffectHostInterface *e = reinterpret_cast(mInstance); - delete e; - break; - } + ModuleManager::Get().DeleteInstance(GetProviderID(), mInstance); } + + return; } -void *PluginDescriptor::GetInstance() +bool PluginDescriptor::IsInstantiated() +{ + return mInstance != NULL; +} + +IdentInterface *PluginDescriptor::GetInstance() { if (!mInstance) { @@ -791,7 +794,7 @@ void *PluginDescriptor::GetInstance() return mInstance; } -void PluginDescriptor::SetInstance(void *instance) +void PluginDescriptor::SetInstance(IdentInterface *instance) { mInstance = instance; @@ -936,9 +939,14 @@ bool PluginDescriptor::IsEffectLegacy() const return mEffectLegacy; } -bool PluginDescriptor::IsEffectRealtimeCapable() const +bool PluginDescriptor::IsEffectRealtime() const { - return mEffectRealtimeCapable; + return mEffectRealtime; +} + +bool PluginDescriptor::IsEffectAutomatable() const +{ + return mEffectAutomatable; } void PluginDescriptor::SetEffectFamily(const wxString & family) @@ -966,9 +974,14 @@ void PluginDescriptor::SetEffectLegacy(bool legacy) mEffectLegacy = legacy; } -void PluginDescriptor::SetEffectRealtimeCapable(bool realtime) +void PluginDescriptor::SetEffectRealtime(bool realtime) { - mEffectRealtimeCapable = realtime; + mEffectRealtime = realtime; +} + +void PluginDescriptor::SetEffectAutomatable(bool automatable) +{ + mEffectAutomatable = automatable; } // Importer @@ -1024,7 +1037,8 @@ void PluginDescriptor::SetImporterExtensions(const wxArrayString & extensions) #define KEY_EFFECTFAMILY wxT("EffectFamily") #define KEY_EFFECTDEFAULT wxT("EffectDefault") #define KEY_EFFECTINTERACTIVE wxT("EffectInteractive") -#define KEY_EFFECTREALTIMECAPABLE wxT("EffectRealtimeCapable") +#define KEY_EFFECTREALTIME wxT("EffectRealtime") +#define KEY_EFFECTAUTOMATABLE wxT("EffectAutomatable") #define KEY_EFFECTTYPE_ANALYZE wxT("Analyze") #define KEY_EFFECTTYPE_GENERATE wxT("Generate") #define KEY_EFFECTTYPE_PROCESS wxT("Process") @@ -1053,7 +1067,8 @@ void PluginManager::RegisterEffectPlugin(IdentInterface *provider, EffectIdentIn plug.SetEffectFamily(effect->GetFamily()); plug.SetEffectInteractive(effect->IsInteractive()); plug.SetEffectDefault(effect->IsDefault()); - plug.SetEffectRealtimeCapable(effect->IsRealtimeCapable()); + plug.SetEffectRealtime(effect->SupportsRealtime()); + plug.SetEffectAutomatable(effect->SupportsAutomation()); plug.SetEnabled(true); } @@ -1078,7 +1093,7 @@ void PluginManager::FindFilesInPathList(const wxString & pattern, wxLogNull nolog; // Why bother... - if (pattern.empty()) + if (pattern.IsEmpty()) { return; } @@ -1117,13 +1132,17 @@ void PluginManager::FindFilesInPathList(const wxString & pattern, for (size_t i = 0, cnt = paths.GetCount(); i < cnt; i++) { f = paths[i] + wxFILE_SEP_PATH + pattern; - wxString a = f.GetFullPath(); wxDir::GetAllFiles(f.GetPath(), &files, f.GetFullName(), directories ? wxDIR_DEFAULT : wxDIR_FILES); } return; } +bool PluginManager::GetSharedConfigSubgroups(const PluginID & ID, const wxString & group, wxArrayString & subgroups) +{ + return GetSubgroups(SharedGroup(ID, group), subgroups); +} + bool PluginManager::GetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, wxString & value, const wxString & defval) { return GetConfig(SharedKey(ID, group, key), value, defval); @@ -1184,6 +1203,21 @@ bool PluginManager::SetSharedConfig(const PluginID & ID, const wxString & group, return SetConfig(SharedKey(ID, group, key), value); } +bool PluginManager::RemoveSharedConfigSubgroup(const PluginID & ID, const wxString & group) +{ + return mConfig->DeleteGroup(SharedGroup(ID, group)); +} + +bool PluginManager::RemoveSharedConfig(const PluginID & ID, const wxString & group, const wxString & key) +{ + return mConfig->DeleteEntry(SharedKey(ID, group, key)); +} + +bool PluginManager::GetPrivateConfigSubgroups(const PluginID & ID, const wxString & group, wxArrayString & subgroups) +{ + return GetSubgroups(PrivateGroup(ID, group), subgroups); +} + bool PluginManager::GetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, wxString & value, const wxString & defval) { return GetConfig(PrivateKey(ID, group, key), value, defval); @@ -1244,6 +1278,16 @@ bool PluginManager::SetPrivateConfig(const PluginID & ID, const wxString & group return SetConfig(PrivateKey(ID, group, key), value); } +bool PluginManager::RemovePrivateConfigSubgroup(const PluginID & ID, const wxString & group) +{ + return mConfig->DeleteGroup(PrivateGroup(ID, group)); +} + +bool PluginManager::RemovePrivateConfig(const PluginID & ID, const wxString & group, const wxString & key) +{ + return mConfig->DeleteEntry(PrivateKey(ID, group, key)); +} + // ============================================================================ // // PluginManager @@ -1302,6 +1346,11 @@ void PluginManager::Initialize() gPrefs->Write(wxT("/Plugins/Rescan"), false); PluginRegistrationDialog dlg; dlg.ShowModal(); + + if (mConfig) + { + mConfig->Flush(); + } } } @@ -1446,7 +1495,7 @@ 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().empty()) + if (!plug.GetPath().IsEmpty()) { if (!mConfig->Read(KEY_LASTUPDATED, &strVal)) { @@ -1509,12 +1558,19 @@ void PluginManager::LoadGroup(const wxChar * group, PluginType type) } plug.SetEffectInteractive(boolVal); - // Is it an realtime capable effect and bypass group if not found - if (!mConfig->Read(KEY_EFFECTREALTIMECAPABLE, &boolVal)) + // Is it a realtime capable effect and bypass group if not found + if (!mConfig->Read(KEY_EFFECTREALTIME, &boolVal)) { continue; } - plug.SetEffectRealtimeCapable(boolVal); + plug.SetEffectRealtime(boolVal); + + // Does the effect support automation...bypass group if not found + if (!mConfig->Read(KEY_EFFECTAUTOMATABLE, &boolVal)) + { + continue; + } + plug.SetEffectAutomatable(boolVal); break; @@ -1628,7 +1684,8 @@ void PluginManager::SaveGroup(const wxChar *group, PluginType type) mConfig->Write(KEY_EFFECTFAMILY, plug.GetEffectFamily()); mConfig->Write(KEY_EFFECTDEFAULT, plug.IsEffectDefault()); mConfig->Write(KEY_EFFECTINTERACTIVE, plug.IsEffectInteractive()); - mConfig->Write(KEY_EFFECTREALTIMECAPABLE, plug.IsEffectRealtimeCapable()); + mConfig->Write(KEY_EFFECTREALTIME, plug.IsEffectRealtime()); + mConfig->Write(KEY_EFFECTAUTOMATABLE, plug.IsEffectAutomatable()); } break; @@ -1695,7 +1752,7 @@ void PluginManager::RemoveMissing() { PluginDescriptor & plug = iter->second; - if (!plug.GetPath().empty()) + if (!plug.GetPath().IsEmpty()) { wxFileName plugPath = plug.GetPath(); @@ -1919,7 +1976,8 @@ const PluginID & PluginManager::RegisterLegacyEffectPlugin(EffectIdentInterface plug.SetEffectFamily(effect->GetFamily()); plug.SetEffectInteractive(effect->IsInteractive()); plug.SetEffectDefault(effect->IsDefault()); - plug.SetEffectRealtimeCapable(effect->IsRealtimeCapable()); + plug.SetEffectRealtime(effect->SupportsRealtime()); + plug.SetEffectAutomatable(effect->SupportsAutomation()); plug.SetInstance(effect); plug.SetEffectLegacy(true); @@ -1959,7 +2017,7 @@ const wxString & PluginManager::GetName(const PluginID & ID) return mPlugins[ID].GetName(); } -void *PluginManager::GetInstance(const PluginID & ID) +IdentInterface *PluginManager::GetInstance(const PluginID & ID) { if (mPlugins.find(ID) == mPlugins.end()) { @@ -1983,7 +2041,7 @@ void *PluginManager::GetInstance(const PluginID & ID) } // TODO: This goes away when all effects have been converted -void PluginManager::SetInstance(const PluginID & ID, void *instance) +void PluginManager::SetInstance(const PluginID & ID, IdentInterface *instance) { if (mPlugins.find(ID) == mPlugins.end()) { @@ -2022,14 +2080,51 @@ wxString PluginManager::GetDateTime(const wxString & path) return wxString(mod.FormatISODate() + wxT(' ') + mod.FormatISOTime()); } - return L""; + return wxEmptyString; +} + +bool PluginManager::GetSubgroups(const wxString & group, wxArrayString & subgroups) +{ + bool result = false; + + if (mConfig && !group.IsEmpty()) + { + wxString name = wxEmptyString; + long index = 0; + wxString path = mConfig->GetPath(); + mConfig->SetPath(group); + + if (mConfig->GetFirstGroup(name, index)) + { + do + { + subgroups.Add(name); + } while (mConfig->GetNextGroup(name, index)); + } + + mConfig->SetPath(path); + } + + return result; +} + +bool PluginManager::GetConfig(const wxString & key, int & value, int defval) +{ + bool result = false; + + if (mConfig && !key.IsEmpty()) + { + result = mConfig->Read(key, &value, defval); + } + + return result; } bool PluginManager::GetConfig(const wxString & key, wxString & value, const wxString & defval) { bool result = false; - if (mConfig && !key.empty()) + if (mConfig && !key.IsEmpty()) { wxString wxval = wxEmptyString; @@ -2041,23 +2136,11 @@ bool PluginManager::GetConfig(const wxString & key, wxString & value, const wxSt return result; } -bool PluginManager::GetConfig(const wxString & key, int & value, int defval) -{ - bool result = false; - - if (mConfig && !key.empty()) - { - result = mConfig->Read(key, &value, defval); - } - - return result; -} - bool PluginManager::GetConfig(const wxString & key, bool & value, bool defval) { bool result = false; - if (mConfig && !key.empty()) + if (mConfig && !key.IsEmpty()) { result = mConfig->Read(key, &value, defval); } @@ -2069,7 +2152,7 @@ bool PluginManager::GetConfig(const wxString & key, float & value, float defval) { bool result = false; - if (mConfig && !key.empty()) + if (mConfig && !key.IsEmpty()) { double dval = 0.0; @@ -2085,7 +2168,7 @@ bool PluginManager::GetConfig(const wxString & key, double & value, double defva { bool result = false; - if (mConfig && !key.empty()) + if (mConfig && !key.IsEmpty()) { result = mConfig->Read(key, &value, defval); } @@ -2097,7 +2180,7 @@ bool PluginManager::GetConfig(const wxString & key, sampleCount & value, sampleC { bool result = false; - if (mConfig && !key.empty()) + if (mConfig && !key.IsEmpty()) { wxString wxval = wxEmptyString; wxString wxdef; @@ -2115,7 +2198,7 @@ bool PluginManager::SetConfig(const wxString & key, const wxString & value) { bool result = false; - if (mConfig && !key.empty()) + if (mConfig && !key.IsEmpty()) { wxString wxval = value.c_str(); result = mConfig->Write(key, wxval); @@ -2132,7 +2215,7 @@ bool PluginManager::SetConfig(const wxString & key, const int & value) { bool result = false; - if (mConfig && !key.empty()) + if (mConfig && !key.IsEmpty()) { result = mConfig->Write(key, value); if (result) @@ -2148,7 +2231,7 @@ bool PluginManager::SetConfig(const wxString & key, const bool & value) { bool result = false; - if (mConfig && !key.empty()) + if (mConfig && !key.IsEmpty()) { result = mConfig->Write(key, value); if (result) @@ -2164,7 +2247,7 @@ bool PluginManager::SetConfig(const wxString & key, const float & value) { bool result = false; - if (mConfig && !key.empty()) + if (mConfig && !key.IsEmpty()) { result = mConfig->Write(key, value); if (result) @@ -2180,7 +2263,7 @@ bool PluginManager::SetConfig(const wxString & key, const double & value) { bool result = false; - if (mConfig && !key.empty()) + if (mConfig && !key.IsEmpty()) { result = mConfig->Write(key, value); if (result) @@ -2196,7 +2279,7 @@ bool PluginManager::SetConfig(const wxString & key, const sampleCount & value) { bool result = false; - if (mConfig && !key.empty()) + if (mConfig && !key.IsEmpty()) { result = mConfig->Write(key, wxString::Format(wxT("%d"), (int) value)); if (result) @@ -2208,33 +2291,44 @@ bool PluginManager::SetConfig(const wxString & key, const sampleCount & value) return result; } -wxString PluginManager::SharedKey(const PluginID & ID, const wxString & group, const wxString & key) +wxString PluginManager::SharedGroup(const PluginID & ID, const wxString & group) { if (mPlugins.find(ID) == mPlugins.end()) { - L""; + return wxEmptyString; } wxString path = CACHEROOT + ConvertID(mPlugins[ID].GetProviderID()) + wxCONFIG_PATH_SEPARATOR + - wxT("private") + + wxT("shared") + wxCONFIG_PATH_SEPARATOR; wxFileName f(group); if (!f.GetName().IsEmpty()) { - path += f.GetName() + wxCONFIG_PATH_SEPARATOR; + path += f.GetFullPath(wxPATH_UNIX) + wxCONFIG_PATH_SEPARATOR; + } + + return path; +} + +wxString PluginManager::SharedKey(const PluginID & ID, const wxString & group, const wxString & key) +{ + wxString path = SharedGroup(ID, group); + if (path.IsEmpty()) + { + return path; } return path + key; } -wxString PluginManager::PrivateKey(const PluginID & ID, const wxString & group, const wxString & key) +wxString PluginManager::PrivateGroup(const PluginID & ID, const wxString & group) { if (mPlugins.find(ID) == mPlugins.end()) { - L""; + return wxEmptyString; } wxString path = CACHEROOT + @@ -2246,7 +2340,18 @@ wxString PluginManager::PrivateKey(const PluginID & ID, const wxString & group, wxFileName f(group); if (!f.GetName().IsEmpty()) { - path += f.GetName() + wxCONFIG_PATH_SEPARATOR; + path += f.GetFullPath(wxPATH_UNIX) + wxCONFIG_PATH_SEPARATOR; + } + + return path; +} + +wxString PluginManager::PrivateKey(const PluginID & ID, const wxString & group, const wxString & key) +{ + wxString path = PrivateGroup(ID, group); + if (path.IsEmpty()) + { + return path; } return path + key; diff --git a/src/PluginManager.h b/src/PluginManager.h index 49927274f..56a67cb5e 100644 --- a/src/PluginManager.h +++ b/src/PluginManager.h @@ -45,8 +45,9 @@ public: PluginDescriptor(); virtual ~PluginDescriptor(); - void *GetInstance(); - void SetInstance(void *instance); + bool IsInstantiated(); + IdentInterface *GetInstance(); + void SetInstance(IdentInterface *instance); PluginType GetPluginType() const; void SetPluginType(PluginType type); @@ -81,14 +82,16 @@ public: bool IsEffectDefault() const; bool IsEffectInteractive() const; bool IsEffectLegacy() const; - bool IsEffectRealtimeCapable() const; + bool IsEffectRealtime() const; + bool IsEffectAutomatable() const; void SetEffectType(EffectType type); void SetEffectFamily(const wxString & family); void SetEffectDefault(bool dflt); void SetEffectInteractive(bool interactive); void SetEffectLegacy(bool legacy); - void SetEffectRealtimeCapable(bool realtime); + void SetEffectRealtime(bool realtime); + void SetEffectAutomatable(bool automatable); // Importer plugins only @@ -104,7 +107,7 @@ private: // Common - void *mInstance; + IdentInterface *mInstance; PluginType mPluginType; @@ -125,9 +128,11 @@ private: bool mEffectInteractive; bool mEffectDefault; bool mEffectLegacy; - bool mEffectRealtimeCapable; + bool mEffectRealtime; + bool mEffectAutomatable; // Importers + wxString mImporterIdentifier; wxString mImporterFilterDesc; wxArrayString mImporterExtensions; @@ -154,6 +159,8 @@ public: wxArrayString & files, bool directories = false); + virtual bool GetSharedConfigSubgroups(const PluginID & ID, const wxString & group, wxArrayString & subgroups); + virtual bool GetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, wxString & value, const wxString & defval = _T("")); virtual bool GetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, int & value, int defval = 0); virtual bool GetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, bool & value, bool defval = false); @@ -168,6 +175,11 @@ public: virtual bool SetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, const double & value); virtual bool SetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, const sampleCount & value); + virtual bool RemoveSharedConfigSubgroup(const PluginID & ID, const wxString & group); + virtual bool RemoveSharedConfig(const PluginID & ID, const wxString & group, const wxString & key); + + virtual bool GetPrivateConfigSubgroups(const PluginID & ID, const wxString & group, wxArrayString & subgroups); + virtual bool GetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, wxString & value, const wxString & defval = _T("")); virtual bool GetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, int & value, int defval = 0); virtual bool GetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, bool & value, bool defval = false); @@ -182,6 +194,9 @@ public: virtual bool SetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, const double & value); virtual bool SetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, const sampleCount & value); + virtual bool RemovePrivateConfigSubgroup(const PluginID & ID, const wxString & group); + virtual bool RemovePrivateConfig(const PluginID & ID, const wxString & group, const wxString & key); + // PluginManager implementation void Initialize(); @@ -214,8 +229,8 @@ public: void EnablePlugin(const PluginID & ID, bool enable); const wxString & GetName(const PluginID & ID); - void *GetInstance(const PluginID & ID); - void SetInstance(const PluginID & ID, void *instance); // TODO: Remove after conversion + IdentInterface *GetInstance(const PluginID & ID); + void SetInstance(const PluginID & ID, IdentInterface *instance); // TODO: Remove after conversion // const PluginID & RegisterLegacyEffectPlugin(EffectIdentInterface *effect); @@ -234,6 +249,8 @@ private: PluginDescriptor & CreatePlugin(IdentInterface *ident, PluginType type); wxString GetDateTime(const wxString & path); + bool GetSubgroups(const wxString & group, wxArrayString & subgroups); + bool GetConfig(const wxString & key, wxString & value, const wxString & defval = L""); bool GetConfig(const wxString & key, int & value, int defval = 0); bool GetConfig(const wxString & key, bool & value, bool defval = false); @@ -248,7 +265,9 @@ private: bool SetConfig(const wxString & key, const double & value); bool SetConfig(const wxString & key, const sampleCount & value); + wxString SharedGroup(const PluginID & ID, const wxString & group); 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); wxString ConvertID(const PluginID & ID); diff --git a/src/ShuttleGui.cpp b/src/ShuttleGui.cpp index 8a91863fb..f4a7f3ac1 100644 --- a/src/ShuttleGui.cpp +++ b/src/ShuttleGui.cpp @@ -2191,9 +2191,9 @@ wxSizer *CreateStdButtonSizer(wxWindow *parent, long buttons, wxButton *extra) bs->Add( 20, 0 ); } - if( buttons & eDefaultsButton ) + if( buttons & eSettingsButton ) { - bs->Add(new wxButton( parent, eDefaultsID, _("&Defaults") ), 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, margin ); + bs->Add(new wxButton( parent, eSettingsID, _("&Settings") ), 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, margin ); bs->Add( 20, 0 ); } diff --git a/src/ShuttleGui.h b/src/ShuttleGui.h index 5bad91907..2093a1360 100644 --- a/src/ShuttleGui.h +++ b/src/ShuttleGui.h @@ -334,7 +334,7 @@ enum eHelpButton = 0x0010, ePreviewButton = 0x0020, eDebugButton = 0x0040, - eDefaultsButton= 0x0080, + eSettingsButton= 0x0080, ePreviewDryButton = 0x0100, eApplyButton = 0x0200, }; @@ -343,7 +343,7 @@ enum { ePreviewID = wxID_LOWEST - 1, eDebugID = wxID_LOWEST - 2, - eDefaultsID = wxID_LOWEST - 3, + eSettingsID = wxID_LOWEST - 3, ePreviewDryID = wxID_LOWEST - 4 }; diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index e1995b2ec..cce8897ff 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -129,7 +129,7 @@ is time to refresh some aspect of the screen. +----------------------------------------------------+ |+------------+ +-----------------------------------+| || | | (L) GuiWaveTrack || - || TrackInfo | +-----------------------------------+| + || TrackInfo | +-----------------------------------+| || | +-----------------------------------+| || | | (R) GuiWaveTrack || |+------------+ +-----------------------------------+| @@ -137,7 +137,7 @@ is time to refresh some aspect of the screen. +----------------------------------------------------+ |+------------+ +-----------------------------------+| || | | (L) GuiWaveTrack || - || TrackInfo | +-----------------------------------+| + || TrackInfo | +-----------------------------------+| || | +-----------------------------------+| || | | (R) GuiWaveTrack || |+------------+ +-----------------------------------+| diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index 3e69d7609..f674e87d9 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -68,6 +68,8 @@ wxString Effect::StripAmpersand(const wxString& str) // Legacy (or full blown effect) Effect::Effect() { + mParent = NULL; + mClient = NULL; mWarper = NULL; @@ -99,11 +101,6 @@ Effect::Effect() Effect::~Effect() { - if (mClient) - { - mClient->Shutdown(); - } - if (mWarper != NULL) { delete mWarper; @@ -214,6 +211,16 @@ wxString Effect::GetFamily() return _("Audacity"); } +bool Effect::IsInteractive() +{ + if (mClient) + { + return mClient->IsInteractive(); + } + + return GetEffectName().EndsWith(wxT("...")); +} + bool Effect::IsDefault() { if (mClient) @@ -234,14 +241,14 @@ bool Effect::IsLegacy() return true; } -bool Effect::IsInteractive() +bool Effect::SupportsAutomation() { if (mClient) { - return mClient->IsInteractive(); + return mClient->SupportsAutomation(); } - return GetEffectName().EndsWith(wxT("...")); + return SupportsChains(); } // EffectHostInterface implementation @@ -283,8 +290,48 @@ void Effect::Preview() Preview(false); } +wxDialog *Effect::CreateUI(wxWindow *parent, EffectUIClientInterface *client) +{ + EffectUIHost *dlg = new EffectUIHost(parent, this, client); + + if (dlg->Initialize()) + { + return dlg; + } + + delete dlg; + + return NULL; +} + +wxString Effect::GetUserPresetsGroup(const wxString & name) +{ + wxString group = wxT("UserPresets"); + if (!name.IsEmpty()) + { + group += wxCONFIG_PATH_SEPARATOR + name; + } + + return group; +} + +wxString Effect::GetCurrentSettingsGroup() +{ + return wxT("CurrentSettings"); +} + +wxString Effect::GetFactoryDefaultsGroup() +{ + return wxT("FactoryDefaults"); +} + // ConfigClientInterface implementation +bool Effect::GetSharedConfigSubgroups(const wxString & group, wxArrayString & subgroups) +{ + return PluginManager::Get().GetSharedConfigSubgroups(GetID(), group, subgroups); +} + bool Effect::GetSharedConfig(const wxString & group, const wxString & key, wxString & value, const wxString & defval) { return PluginManager::Get().GetSharedConfig(GetID(), group, key, value, defval); @@ -345,6 +392,21 @@ bool Effect::SetSharedConfig(const wxString & group, const wxString & key, const return PluginManager::Get().SetSharedConfig(GetID(), group, key, value); } +bool Effect::RemoveSharedConfigSubgroup(const wxString & group) +{ + return PluginManager::Get().RemoveSharedConfigSubgroup(GetID(), group); +} + +bool Effect::RemoveSharedConfig(const wxString & group, const wxString & key) +{ + return PluginManager::Get().RemoveSharedConfig(GetID(), group, key); +} + +bool Effect::GetPrivateConfigSubgroups(const wxString & group, wxArrayString & subgroups) +{ + return PluginManager::Get().GetPrivateConfigSubgroups(GetID(), group, subgroups); +} + bool Effect::GetPrivateConfig(const wxString & group, const wxString & key, wxString & value, const wxString & defval) { return PluginManager::Get().GetPrivateConfig(GetID(), group, key, value, defval); @@ -405,6 +467,16 @@ bool Effect::SetPrivateConfig(const wxString & group, const wxString & key, cons return PluginManager::Get().SetPrivateConfig(GetID(), group, key, value); } +bool Effect::RemovePrivateConfigSubgroup(const wxString & group) +{ + return PluginManager::Get().RemovePrivateConfigSubgroup(GetID(), group); +} + +bool Effect::RemovePrivateConfig(const wxString & group, const wxString & key) +{ + return PluginManager::Get().RemovePrivateConfig(GetID(), group, key); +} + // Effect implementation bool Effect::Startup(EffectClientInterface *client) @@ -412,14 +484,11 @@ bool Effect::Startup(EffectClientInterface *client) // Let destructor know we need to be shutdown mClient = client; - // Need to set host now so client startup can use our services - mClient->SetHost(this); - - // Bail if the client startup fails - if (!mClient->Startup()) + // Set host so client startup can use our services + if (!mClient->SetHost(this)) { + // Bail if the client startup fails mClient = NULL; - return false; } @@ -447,6 +516,46 @@ bool Effect::Startup(EffectClientInterface *client) return true; } +bool Effect::GetAutomationParameters(wxString & parms) +{ + if (mClient) + { + EffectAutomationParameters eap; + if (!mClient->GetAutomationParameters(eap)) + { + return false; + } + + return eap.GetParameters(parms); + } + + ShuttleCli shuttle; + shuttle.mbStoreInClient = false; + if (!TransferParameters(shuttle)) + { + return false; + } + + parms = shuttle.mParams; + + return true; +} + +bool Effect::SetAutomationParameters(const wxString & parms) +{ + if (mClient) + { + EffectAutomationParameters eap; + eap.SetParameters(parms); + return mClient->SetAutomationParameters(eap); + } + + ShuttleCli shuttle; + shuttle.mParams = parms; + shuttle.mbStoreInClient = true; + return TransferParameters(shuttle); +} + // All legacy effects should have this overridden wxString Effect::GetEffectName() { @@ -591,19 +700,20 @@ bool Effect::PromptUser() return PromptUser(mParent); } -bool Effect::PromptUser(wxWindow *parent) +bool Effect::PromptUser(wxWindow *parent, bool forceModal) { if (mClient) { -#if defined(EXPERIMENTAL_REALTIME_EFFECTS) - if (IsRealtimeCapable()) + bool res = mClient->ShowInterface(parent, forceModal); + + // Really need to clean this up...should get easier when + // all effects get converted. + if (!res || SupportsRealtime()) { - mClient->ShowInterface(parent); + // Return false to force DoEffect() to skip processing since + // this UI has either been shown modeless or there was an error. return false; } -#endif - - return mClient->ShowInterface(parent); } return true; @@ -853,6 +963,7 @@ bool Effect::ProcessTrack(int count, WaveTrack *genRight = NULL; sampleCount genLength = 0; bool isGenerator = mClient->GetType() == EffectTypeGenerate; + bool isProcessor = mClient->GetType() == EffectTypeProcess; if (isGenerator) { genLength = left->GetRate() * mDuration; @@ -980,7 +1091,7 @@ bool Effect::ProcessTrack(int count, } // Get the current number of delayed samples and accumulate - if (!isGenerator) + if (isProcessor) { sampleCount delay = mClient->GetLatency(); curDelay += delay; @@ -999,7 +1110,7 @@ bool Effect::ProcessTrack(int count, else if (curDelay > 0) { curBlockSize -= curDelay; - for (int i = 0; i < mNumChannels; i++) + for (int i = 0; i < wxMin(mNumAudioOut, mNumChannels); i++) { memmove(mOutBufPos[i], mOutBufPos[i] + curDelay, SAMPLE_SIZE(floatSample) * curBlockSize); } @@ -1014,7 +1125,7 @@ bool Effect::ProcessTrack(int count, if (outputBufferCnt < mBufferSize) { // Bump to next output buffer position - for (int i = 0; i < mNumChannels; i++) + for (int i = 0; i < wxMin(mNumAudioOut, mNumChannels); i++) { mOutBufPos[i] += curBlockSize; } @@ -1022,7 +1133,7 @@ bool Effect::ProcessTrack(int count, // Output buffers have filled else { - if (!isGenerator) + if (isProcessor) { // Write them out left->Set((samplePtr) mOutBuffer[0], floatSample, outLeftPos, outputBufferCnt); @@ -1031,7 +1142,7 @@ bool Effect::ProcessTrack(int count, right->Set((samplePtr) mOutBuffer[1], floatSample, outRightPos, outputBufferCnt); } } - else + else if (isGenerator) { genLeft->Append((samplePtr) mOutBuffer[0], floatSample, outputBufferCnt); if (genRight) @@ -1041,7 +1152,7 @@ bool Effect::ProcessTrack(int count, } // Reset the output buffer positions - for (int i = 0; i < mNumChannels; i++) + for (int i = 0; i < wxMin(mNumAudioOut, mNumChannels); i++) { mOutBufPos[i] = mOutBuffer[i]; } @@ -1080,7 +1191,7 @@ bool Effect::ProcessTrack(int count, // Put any remaining output if (outputBufferCnt) { - if (!isGenerator) + if (isProcessor) { left->Set((samplePtr) mOutBuffer[0], floatSample, outLeftPos, outputBufferCnt); if (right) @@ -1088,7 +1199,7 @@ bool Effect::ProcessTrack(int count, right->Set((samplePtr) mOutBuffer[1], floatSample, outRightPos, outputBufferCnt); } } - else + else if (isGenerator) { genLeft->Append((samplePtr) mOutBuffer[0], floatSample, outputBufferCnt); if (genRight) @@ -1385,12 +1496,12 @@ wxString Effect::GetPreviewName() return _("Pre&view"); } -bool Effect::IsRealtimeCapable() +bool Effect::SupportsRealtime() { #if defined(EXPERIMENTAL_REALTIME_EFFECTS) if (mClient) { - return mClient->IsRealtimeCapable(); + return mClient->SupportsRealtime(); } #endif @@ -1793,3 +1904,357 @@ void EffectDialog::OnPreview(wxCommandEvent & WXUNUSED(event)) { return; } + +enum +{ + kSaveAsID = 30001, + kImportID = 30002, + kExportID = 30003, + kDefaultsID = 30004, + kOptionsID = 30005, + kDeleteAllID = 30006, + kUserPresetsID = 31000, + kDeletePresetID = 32000, + kFactoryPresetsID = 33000, +}; + +BEGIN_EVENT_TABLE(EffectUIHost, wxDialog) +// EVT_WINDOW_DESTROY(EffectUIHost::OnDestroy) + EVT_CLOSE(EffectUIHost::OnClose) + EVT_BUTTON(wxID_OK, EffectUIHost::OnOk) + EVT_BUTTON(wxID_CANCEL, EffectUIHost::OnCancel) + EVT_BUTTON(ePreviewID, EffectUIHost::OnPreview) + EVT_BUTTON(eSettingsID, EffectUIHost::OnSettings) + EVT_MENU(kSaveAsID, EffectUIHost::OnSaveAs) + EVT_MENU(kImportID, EffectUIHost::OnImport) + EVT_MENU(kExportID, EffectUIHost::OnExport) + EVT_MENU(kOptionsID, EffectUIHost::OnOptions) + EVT_MENU(kDefaultsID, EffectUIHost::OnDefaults) + EVT_MENU(kDeleteAllID, EffectUIHost::OnDeleteAllPresets) + EVT_MENU_RANGE(kUserPresetsID, kUserPresetsID + 999, EffectUIHost::OnUserPreset) + EVT_MENU_RANGE(kDeletePresetID, kDeletePresetID + 999, EffectUIHost::OnDeletePreset) + EVT_MENU_RANGE(kFactoryPresetsID, kFactoryPresetsID + 999, EffectUIHost::OnFactoryPreset) +END_EVENT_TABLE() + +EffectUIHost::EffectUIHost(wxWindow *parent, + EffectHostInterface *host, + EffectUIClientInterface *client) +: wxDialog(parent, wxID_ANY, host->GetName()) +{ + SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY); + + mParent = parent; + mHost = host; + mClient = client; + mClient->SetUIHost(this); +} + +EffectUIHost::~EffectUIHost() +{ + if (mClient) + { + mClient->CloseUI(); + mClient = NULL; + } +} + +bool EffectUIHost::Initialize() +{ + wxBoxSizer *vs = new wxBoxSizer(wxVERTICAL); + + wxScrolledWindow *w = new wxScrolledWindow(this, + wxID_ANY, + wxDefaultPosition, + wxDefaultSize, + wxVSCROLL | wxTAB_TRAVERSAL); + + // Try to give the window a sensible default/minimum size + w->SetMinSize(wxSize(wxMax(600, mParent->GetSize().GetWidth() * 2/3), + mParent->GetSize().GetHeight() / 2)); + + w->SetScrollRate(0, 20); + + wxSizer *s = CreateStdButtonSizer(this, eSettingsButton | eOkButton | eCancelButton); + + vs->Add(w, 1, wxEXPAND); + vs->Add(s, 0, wxEXPAND | wxALIGN_CENTER_VERTICAL); + SetSizer(vs); + + if (!mClient->PopulateUI(w)) + { + return false; + } + + Layout(); + Fit(); + Center(); + + LoadUserPresets(); + + mClient->LoadUserPreset(mHost->GetCurrentSettingsGroup()); + + return true; +} + +void EffectUIHost::OnDestroy(wxWindowDestroyEvent & WXUNUSED(evt)) +{ + mClient->CloseUI(); +} + +void EffectUIHost::OnClose(wxCloseEvent & WXUNUSED(evt)) +{ + mClient->CloseUI(); + mClient = NULL; + + Destroy(); +} + +void EffectUIHost::OnOk(wxCommandEvent & WXUNUSED(evt)) +{ + if (!mClient->ValidateUI()) + { + return; + } + + mClient->SaveUserPreset(mHost->GetCurrentSettingsGroup()); + + if (IsModal()) + { + SetReturnCode(true); + + Close(); + +#if !defined(__WXGTK__) + EndModal(true); +#endif + return; + } + + mHost->Apply(); + + if (!mClient->HideUI()) + { + return; + } + + Close(); + + return; +} + +void EffectUIHost::OnCancel(wxCommandEvent & WXUNUSED(evt)) +{ + if (IsModal()) + { + EndModal(false); + return; + } + + Close(); + + return; +} + +void EffectUIHost::OnPreview(wxCommandEvent & WXUNUSED(evt)) +{ + mHost->Preview(); +} + +void EffectUIHost::OnSettings(wxCommandEvent & evt) +{ + wxButton *b = (wxButton *)evt.GetEventObject(); + + wxMenu *menu = new wxMenu(); + wxMenu *sub; + + LoadUserPresets(); + + sub = new wxMenu(); + for (size_t i = 0, cnt = mUserPresets.GetCount(); i < cnt; i++) + { + sub->Append(kUserPresetsID + i, mUserPresets[i]); + } + menu->Append(0, _("User Presets"), sub); + + wxArrayString factory = mClient->GetFactoryPresets(); + + sub = new wxMenu(); + sub->Append(kDefaultsID, _("Defaults")); + if (factory.GetCount() > 0) + { + sub->AppendSeparator(); + for (size_t i = 0, cnt = factory.GetCount(); i < cnt; i++) + { + wxString label = factory[i]; + if (label.IsEmpty()) + { + label = _("None"); + } + + sub->Append(kFactoryPresetsID + i, label); + } + } + menu->Append(0, _("Factory Presets"), sub); + + sub = new wxMenu(); + for (size_t i = 0, cnt = mUserPresets.GetCount(); i < cnt; i++) + { + sub->Append(kDeletePresetID + i, mUserPresets[i]); + } + menu->Append(0, _("Delete Preset"), sub); + + menu->AppendSeparator(); + menu->Append(kSaveAsID, _("Save As...")); + menu->AppendSeparator(); + menu->Append(kImportID, _("Import...")); + menu->Append(kExportID, _("Export...")); + menu->AppendSeparator(); + menu->Append(kOptionsID, _("Options...")); + menu->AppendSeparator(); + + sub = new wxMenu(); + + sub->Append(0, wxString::Format(_("Type: %s"), mHost->GetFamily().c_str())); + sub->Append(0, wxString::Format(_("Name: %s"), mHost->GetName().c_str())); + sub->Append(0, wxString::Format(_("Version: %s"), mHost->GetVersion().c_str())); + sub->Append(0, wxString::Format(_("Vendor: %s"), mHost->GetVendor().c_str())); + sub->Append(0, wxString::Format(_("Description: %s"), mHost->GetDescription().c_str())); +// sub->Append(0, wxString::Format(_("Audio In: %d"), mHost->GetAudioInCount())); +// sub->Append(0, wxString::Format(_("Audio Out: %d"), mHost->GetAudioOutCount())); + + menu->Append(0, _("About"), sub); + + wxRect r = b->GetRect(); + PopupMenu(menu, wxPoint(r.GetLeft(), r.GetBottom())); + + delete menu; +} + +void EffectUIHost::OnSaveAs(wxCommandEvent & WXUNUSED(evt)) +{ + wxTextCtrl *text; + wxString name; + wxDialog dlg(this, wxID_ANY, wxString(_("Save Preset"))); + ShuttleGui S(&dlg, eIsCreating); + + S.StartPanel(); + { + S.StartVerticalLay(0); + { + S.StartHorizontalLay(wxALIGN_LEFT, 0); + { + text = S.AddTextBox(_("Preset name:"), name, 30); + } + S.EndHorizontalLay(); + S.AddStandardButtons(); + } + S.EndVerticalLay(); + } + S.EndPanel(); + dlg.SetSize(dlg.GetSizer()->GetMinSize()); + dlg.Center(); + + while (true) + { + int rc = dlg.ShowModal(); + + if (rc != wxID_OK) + { + break; + } + + name = text->GetValue(); + if (mUserPresets.Index(name) == wxNOT_FOUND) + { + mClient->SaveUserPreset(mHost->GetUserPresetsGroup(name)); + LoadUserPresets(); + break; + } + + wxMessageBox(_("Preset already exists"), + _("Save Preset"), + wxICON_EXCLAMATION); + } + + return; +} + +void EffectUIHost::OnImport(wxCommandEvent & WXUNUSED(evt)) +{ + mClient->ImportPresets(); + + LoadUserPresets(); + + return; +} + +void EffectUIHost::OnExport(wxCommandEvent & WXUNUSED(evt)) +{ + mClient->ExportPresets(); + + return; +} + +void EffectUIHost::OnDefaults(wxCommandEvent & WXUNUSED(evt)) +{ + mClient->LoadFactoryDefaults(); + + return; +} + +void EffectUIHost::OnOptions(wxCommandEvent & WXUNUSED(evt)) +{ + mClient->ShowOptions(); + + return; +} + +void EffectUIHost::OnUserPreset(wxCommandEvent & evt) +{ + int preset = evt.GetId() - kUserPresetsID; + + mClient->LoadUserPreset(mHost->GetUserPresetsGroup(mUserPresets[preset])); + + return; +} + +void EffectUIHost::OnFactoryPreset(wxCommandEvent & evt) +{ + mClient->LoadFactoryPreset(evt.GetId() - kFactoryPresetsID); + + return; +} + +void EffectUIHost::OnDeletePreset(wxCommandEvent & evt) +{ + mHost->RemovePrivateConfigSubgroup(mHost->GetUserPresetsGroup(mUserPresets[evt.GetId() - kDeletePresetID])); + + LoadUserPresets(); + + return; +} + +void EffectUIHost::OnDeleteAllPresets(wxCommandEvent & WXUNUSED(evt)) +{ + int res = wxMessageBox(_("This will delete all of your user presets. Are you sure?"), + _("Delete All Presets"), + wxICON_QUESTION | wxYES_NO); + if (res == wxID_YES) + { + mHost->RemovePrivateConfigSubgroup(mHost->GetUserPresetsGroup(wxEmptyString)); + mUserPresets.Clear(); + } + + return; +} + +void EffectUIHost::LoadUserPresets() +{ + mUserPresets.Clear(); + + mHost->GetPrivateConfigSubgroups(mHost->GetUserPresetsGroup(wxEmptyString), mUserPresets); + + mUserPresets.Sort(); + + return; +} diff --git a/src/effects/Effect.h b/src/effects/Effect.h index 9936d5515..3e833b2d9 100644 --- a/src/effects/Effect.h +++ b/src/effects/Effect.h @@ -92,7 +92,8 @@ class AUDACITY_DLL_API Effect : public EffectHostInterface virtual bool IsInteractive(); virtual bool IsDefault(); virtual bool IsLegacy(); - virtual bool IsRealtimeCapable(); + virtual bool SupportsRealtime(); + virtual bool SupportsAutomation(); // EffectHostInterface implementation @@ -102,8 +103,16 @@ class AUDACITY_DLL_API Effect : public EffectHostInterface virtual bool Apply(); virtual void Preview(); + virtual wxDialog *CreateUI(wxWindow *parent, EffectUIClientInterface *client); + + virtual wxString GetUserPresetsGroup(const wxString & name); + virtual wxString GetCurrentSettingsGroup(); + virtual wxString GetFactoryDefaultsGroup(); + // ConfigClientInterface implementation + virtual bool GetSharedConfigSubgroups(const wxString & group, wxArrayString & subgroups); + virtual bool GetSharedConfig(const wxString & group, const wxString & key, wxString & value, const wxString & defval = wxEmptyString); virtual bool GetSharedConfig(const wxString & group, const wxString & key, int & value, int defval = 0); virtual bool GetSharedConfig(const wxString & group, const wxString & key, bool & value, bool defval = false); @@ -118,6 +127,11 @@ class AUDACITY_DLL_API Effect : public EffectHostInterface virtual bool SetSharedConfig(const wxString & group, const wxString & key, const double & value); virtual bool SetSharedConfig(const wxString & group, const wxString & key, const sampleCount & value); + virtual bool RemoveSharedConfigSubgroup(const wxString & group); + virtual bool RemoveSharedConfig(const wxString & group, const wxString & key); + + virtual bool GetPrivateConfigSubgroups(const wxString & group, wxArrayString & subgroups); + virtual bool GetPrivateConfig(const wxString & group, const wxString & key, wxString & value, const wxString & defval = wxEmptyString); virtual bool GetPrivateConfig(const wxString & group, const wxString & key, int & value, int defval = 0); virtual bool GetPrivateConfig(const wxString & group, const wxString & key, bool & value, bool defval = false); @@ -132,8 +146,14 @@ class AUDACITY_DLL_API Effect : public EffectHostInterface virtual bool SetPrivateConfig(const wxString & group, const wxString & key, const double & value); virtual bool SetPrivateConfig(const wxString & group, const wxString & key, const sampleCount & value); + virtual bool RemovePrivateConfigSubgroup(const wxString & group); + virtual bool RemovePrivateConfig(const wxString & group, const wxString & key); + // Effect implementation + virtual bool Startup(EffectClientInterface *client); + virtual bool GetAutomationParameters(wxString & parms); + virtual bool SetAutomationParameters(const wxString & parms); // Each subclass of Effect should override this method. // This name will go in the menu bar; @@ -274,7 +294,7 @@ class AUDACITY_DLL_API Effect : public EffectHostInterface // repeats an effect) but if it is called, it will be called // after Init. virtual bool PromptUser(); - virtual bool PromptUser(wxWindow *parent); + virtual bool PromptUser(wxWindow *parent, bool forceModal = false); // Check whether effect should be skipped // Typically this is only useful in automation, for example @@ -451,6 +471,48 @@ private: int mAdditionalButtons; }; +// +class EffectUIHost : public wxDialog, + public EffectUIHostInterface +{ +public: + // constructors and destructors + EffectUIHost(wxWindow *parent, + EffectHostInterface *host, + EffectUIClientInterface *client); + virtual ~EffectUIHost(); + + bool Initialize(); + +private: + void OnDestroy(wxWindowDestroyEvent & evt); + void OnClose(wxCloseEvent & evt); + void OnOk(wxCommandEvent & evt); + void OnCancel(wxCommandEvent & evt); + void OnPreview(wxCommandEvent & evt); + void OnSettings(wxCommandEvent & evt); + void OnSaveAs(wxCommandEvent & evt); + void OnImport(wxCommandEvent & evt); + void OnExport(wxCommandEvent & evt); + void OnOptions(wxCommandEvent & evt); + void OnUserPreset(wxCommandEvent & evt); + void OnDeletePreset(wxCommandEvent & evt); + void OnFactoryPreset(wxCommandEvent & evt); + void OnDefaults(wxCommandEvent & evt); + void OnDeleteAllPresets(wxCommandEvent & evt); + + void LoadUserPresets(); + +private: + wxWindow *mParent; + EffectHostInterface *mHost; + EffectUIClientInterface *mClient; + + wxArrayString mUserPresets; + + DECLARE_EVENT_TABLE(); +}; + // Utility functions float TrapFloat(float x, float min, float max); diff --git a/src/effects/EffectManager.cpp b/src/effects/EffectManager.cpp index 8600abdf5..530446eb2 100644 --- a/src/effects/EffectManager.cpp +++ b/src/effects/EffectManager.cpp @@ -215,6 +215,13 @@ EffectManager::~EffectManager() // wxWidgets has already destroyed the rack since it was derived from wxFrame. So // no need to delete it here. #endif + + EffectMap::iterator iter = mEffects.begin(); + while (iter != mEffects.end()) + { + delete iter->second; + iter++; + } } void EffectManager::RegisterEffect(Effect *f, int NewFlags) @@ -227,7 +234,7 @@ void EffectManager::RegisterEffect(Effect *f, int NewFlags) } // This will go away after all effects have been converted - mEffectPlugins.Add(PluginManager::Get().RegisterLegacyEffectPlugin(f)); + mEffects[PluginManager::Get().RegisterLegacyEffectPlugin(f)] = f; #ifdef EFFECT_CATEGORIES // Add the effect in the right categories @@ -275,7 +282,7 @@ bool EffectManager::DoEffect(const PluginID & ID, } #if defined(EXPERIMENTAL_REALTIME_EFFECTS) && defined(EXPERIMENTAL_EFFECTS_RACK) - if (effect->IsRealtimeCapable()) + if (effect->SupportsRealtime()) { GetRack()->Add(effect); } @@ -333,16 +340,28 @@ wxString EffectManager::GetEffectDescription(const PluginID & ID) return wxEmptyString; } +bool EffectManager::SupportsAutomation(const PluginID & ID) +{ + const PluginDescriptor *plug = PluginManager::Get().GetPlugin(ID); + if (plug) + { + return plug->IsEffectAutomatable(); + } + + return false; +} + wxString EffectManager::GetEffectParameters(const PluginID & ID) { Effect *effect = GetEffect(ID); if (effect) { - ShuttleCli shuttle; - shuttle.mbStoreInClient = false; - effect->TransferParameters(shuttle); - return shuttle.mParams; + wxString parms; + + effect->GetAutomationParameters(parms); + + return parms; } return wxEmptyString; @@ -354,10 +373,7 @@ bool EffectManager::SetEffectParameters(const PluginID & ID, const wxString & pa if (effect) { - ShuttleCli shuttle; - shuttle.mParams = params; - shuttle.mbStoreInClient=true; - return effect->TransferParameters(shuttle); + return effect->SetAutomationParameters(params); } return false; @@ -370,7 +386,7 @@ bool EffectManager::PromptUser(const PluginID & ID, wxWindow *parent) if (effect) { - result = effect->PromptUser(parent); + result = effect->PromptUser(parent, true); } return result; @@ -634,18 +650,17 @@ Effect *EffectManager::GetEffect(const PluginID & ID) Effect *effect; // TODO: This is temporary and should be redone when all effects are converted - if (mEffectPlugins.Index(wxString(ID)) == wxNOT_FOUND) + if (mEffects.find(ID) == mEffects.end()) { effect = new Effect(); if (effect) { // This will instantiate the effect client if it hasn't already been done - EffectClientInterface *client = static_cast(PluginManager::Get().GetInstance(ID)); + EffectClientInterface *client = dynamic_cast(PluginManager::Get().GetInstance(ID)); if (client && effect->Startup(client)) { effect->SetEffectID(mNumEffects++); - PluginManager::Get().SetInstance(ID, effect); - mEffectPlugins.Add(ID); + mEffects[ID] = effect; return effect; } @@ -659,14 +674,14 @@ Effect *EffectManager::GetEffect(const PluginID & ID) return NULL; } - return static_cast(PluginManager::Get().GetInstance(ID)); + return mEffects[ID]; } const PluginID & EffectManager::GetEffectByIdentifier(const wxString & strTarget) { if (strTarget == wxEmptyString) // set GetEffectIdentifier to wxT("") to not show an effect in Batch mode { - return PluginID(wxString(wxEmptyString)); + return PluginID(wxEmptyString); } PluginManager & pm = PluginManager::Get(); @@ -680,7 +695,7 @@ const PluginID & EffectManager::GetEffectByIdentifier(const wxString & strTarget plug = pm.GetNextPlugin(PluginTypeEffect); } - return PluginID(wxString(wxEmptyString)); + return PluginID(wxEmptyString); } #ifdef EFFECT_CATEGORIES diff --git a/src/effects/EffectManager.h b/src/effects/EffectManager.h index d5b407e43..dafbc5bf1 100644 --- a/src/effects/EffectManager.h +++ b/src/effects/EffectManager.h @@ -34,6 +34,7 @@ effects. #endif WX_DEFINE_USER_EXPORTED_ARRAY(Effect *, EffectArray, class AUDACITY_DLL_API); +WX_DECLARE_STRING_HASH_MAP_WITH_DECL(Effect *, EffectMap, class AUDACITY_DLL_API); #if defined(EXPERIMENTAL_EFFECTS_RACK) class EffectRack; @@ -88,6 +89,7 @@ class AUDACITY_DLL_API EffectManager wxString GetEffectDescription(const PluginID & ID); /** Support for batch commands */ + bool SupportsAutomation(const PluginID & ID); wxString GetEffectParameters(const PluginID & ID); bool SetEffectParameters(const PluginID & ID, const wxString & params); bool PromptUser(const PluginID & ID, wxWindow *parent); @@ -148,7 +150,7 @@ class AUDACITY_DLL_API EffectManager #endif private: - wxArrayString mEffectPlugins; + EffectMap mEffects; int mNumEffects; diff --git a/src/effects/VST/VSTEffect.cpp b/src/effects/VST/VSTEffect.cpp index 4a4f94971..ec71c6190 100644 --- a/src/effects/VST/VSTEffect.cpp +++ b/src/effects/VST/VSTEffect.cpp @@ -29,6 +29,8 @@ #if USE_VST +#include + #include #include #include @@ -77,6 +79,7 @@ #include "../../Prefs.h" #include "../../ShuttleGui.h" #include "../../effects/Effect.h" +#include "../../widgets/NumericTextCtrl.h" #include "../../widgets/valnum.h" #include "../../xml/XMLFileReader.h" #include "../../xml/XMLWriter.h" @@ -139,12 +142,13 @@ public: // VSTs that are bad or that our support isn't currect. But, it can also // hide Audacity failures in the subprocess, so if you're having an unruley // VST or odd Audacity failures, comment it out and you might get more info. - wxHandleFatalExceptions(); + //wxHandleFatalExceptions(); VSTEffectsModule::Check(wxTheApp->argv[2]); // Returning false causes default processing to display a message box, but we don't // want that so disable logging. wxLog::EnableLogging(false); + return false; } @@ -162,15 +166,16 @@ IMPLEMENT_DYNAMIC_CLASS(VSTSubEntry, wxModule); //---------------------------------------------------------------------------- // VSTSubProcess //---------------------------------------------------------------------------- -#define OUTPUTKEY L"-" -#define KEY_ID L"ID" -#define KEY_NAME L"Name" -#define KEY_PATH L"Path" -#define KEY_VENDOR L"Vendor" -#define KEY_VERSION L"Version" -#define KEY_DESCRIPTION L"Description" -#define KEY_EFFECTTYPE L"EffectType" -#define KEY_INTERACTIVE L"Interactive" +#define OUTPUTKEY wxT("-") +#define KEY_ID wxT("ID") +#define KEY_NAME wxT("Name") +#define KEY_PATH wxT("Path") +#define KEY_VENDOR wxT("Vendor") +#define KEY_VERSION wxT("Version") +#define KEY_DESCRIPTION wxT("Description") +#define KEY_EFFECTTYPE wxT("EffectType") +#define KEY_INTERACTIVE wxT("Interactive") +#define KEY_AUTOMATABLE wxT("Automatable") class VSTSubProcess : public wxProcess, public EffectIdentInterface @@ -238,13 +243,15 @@ public: return false; } - bool IsRealtimeCapable() + bool SupportsRealtime() { - // TODO: This should check to see if setting parameters can be - // automated. If so, then realtime is supported. return mType == EffectTypeProcess; } + bool SupportsAutomation() + { + return mAutomatable; + } public: PluginID mID; @@ -255,6 +262,7 @@ public: wxString mDescription; EffectType mType; bool mInteractive; + bool mAutomatable; }; // ============================================================================ @@ -274,6 +282,7 @@ VSTEffectsModule::VSTEffectsModule(ModuleManagerInterface *moduleManager, VSTEffectsModule::~VSTEffectsModule() { + mPath = wxEmptyString; } // ============================================================================ @@ -353,9 +362,9 @@ wxArrayString VSTEffectsModule::FindPlugins(PluginManagerInterface & pm) #if defined(__WXMAC__) #define VSTPATH wxT("/Library/Audio/Plug-Ins/VST") - // Look in /Library/Audio/Plug-Ins/VST and $HOME/Library/Audio/Plug-Ins/VST + // Look in ~/Library/Audio/Plug-Ins/VST and /Library/Audio/Plug-Ins/VST + pathList.Add(wxGetHomeDir() + wxFILE_SEP_PATH + VSTPATH); pathList.Add(VSTPATH); - pathList.Add(wxString::FromUTF8(getenv("HOME")) + VSTPATH); // Recursively search all paths for Info.plist files. This will identify all // bundles. @@ -432,7 +441,7 @@ wxArrayString VSTEffectsModule::FindPlugins(PluginManagerInterface & pm) // These are the defaults used by other hosts pathList.Add(wxT("/usr/lib/vst")); pathList.Add(wxT("/usr/local/lib/vst")); - pathList.Add(wxString(wxGetHomeDir()) + wxFILE_SEP_PATH + wxT(".vst")); + pathList.Add(wxGetHomeDir() + wxFILE_SEP_PATH + wxT(".vst")); } // Recursively scan for all shared objects @@ -523,9 +532,14 @@ bool VSTEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxStrin proc->mInteractive = val.IsSameAs(wxT("1")); keycount++; } + else if (key.IsSameAs(KEY_AUTOMATABLE)) + { + proc->mAutomatable = val.IsSameAs(wxT("1")); + keycount++; + } } - bool valid = keycount == 8; + bool valid = keycount == 9; if (valid) { @@ -537,13 +551,22 @@ bool VSTEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxStrin return valid; } -void *VSTEffectsModule::CreateInstance(const PluginID & WXUNUSED(ID), - const wxString & path) +IdentInterface *VSTEffectsModule::CreateInstance(const PluginID & WXUNUSED(ID), + const wxString & path) { // For us, the ID is simply the path to the effect return new VSTEffect(path); } +void VSTEffectsModule::DeleteInstance(IdentInterface *instance) +{ + VSTEffect *effect = dynamic_cast(instance); + if (effect) + { + delete effect; + } +} + // ============================================================================ // ModuleEffectInterface implementation // ============================================================================ @@ -560,7 +583,7 @@ void VSTEffectsModule::Check(const wxChar *path) VSTEffect *effect = new VSTEffect(path); if (effect) { - if (effect->Startup()) + if (effect->SetHost(NULL)) { wxPrintf(OUTPUTKEY KEY_ID wxT("=%s\n"), effect->GetID().c_str()); wxPrintf(OUTPUTKEY KEY_PATH wxT("=%s\n"), effect->GetPath().c_str()); @@ -570,6 +593,7 @@ void VSTEffectsModule::Check(const wxChar *path) wxPrintf(OUTPUTKEY KEY_DESCRIPTION wxT("=%s\n"), effect->GetDescription().c_str()); wxPrintf(OUTPUTKEY KEY_EFFECTTYPE wxT("=%d\n"), effect->GetType()); wxPrintf(OUTPUTKEY KEY_INTERACTIVE wxT("=%d\n"), effect->IsInteractive()); + wxPrintf(OUTPUTKEY KEY_AUTOMATABLE wxT("=%d\n"), effect->SupportsAutomation()); } delete effect; @@ -732,147 +756,88 @@ void VSTEffectSettingsDialog::OnOk(wxCommandEvent & WXUNUSED(evt)) /////////////////////////////////////////////////////////////////////////////// // -// VSTEffectDialog +// VSTEffectTimer // /////////////////////////////////////////////////////////////////////////////// -DECLARE_LOCAL_EVENT_TYPE(EVT_SIZEWINDOW, -1); -DEFINE_LOCAL_EVENT_TYPE(EVT_SIZEWINDOW); -DECLARE_LOCAL_EVENT_TYPE(EVT_UPDATEDISPLAY, -1); -DEFINE_LOCAL_EVENT_TYPE(EVT_UPDATEDISPLAY); - -class VSTEffectDialog:public wxDialog, XMLTagHandler +class VSTEffectTimer : public wxTimer { public: - VSTEffectDialog(wxWindow * parent, - const wxString & title, - VSTEffect *effect, - AEffect *aeffect); - virtual ~VSTEffectDialog(); + VSTEffectTimer(VSTEffect *effect) + : wxTimer(), + mEffect(effect) + { + } - void EnableApply(bool enable); + ~VSTEffectTimer() + { + } + + void Notify() + { + mEffect->OnTimer(); + } private: - - void RemoveHandler(); - - void OnProgram(wxCommandEvent & evt); - void OnProgramText(wxCommandEvent & evt); - void OnLoad(wxCommandEvent & evt); - void OnSave(wxCommandEvent & evt); - void OnSettings(wxCommandEvent & evt); - - void OnSlider(wxCommandEvent & evt); - - void OnApply(wxCommandEvent & evt); - void OnOk(wxCommandEvent & evt); - void OnCancel(wxCommandEvent & evt); - void OnPreview(wxCommandEvent & evt); - void OnDefaults(wxCommandEvent & evt); - void OnClose(wxCloseEvent & evt); - - void OnSizeWindow(wxCommandEvent & evt); - void OnUpdateDisplay(wxCommandEvent & evt); - - void BuildPlain(); - void BuildFancy(); - wxSizer *BuildProgramBar(); - void RefreshParameters(int skip = -1); - - // Program/Bank loading/saving - bool LoadFXB(const wxFileName & fn); - bool LoadFXP(const wxFileName & fn); - bool LoadXML(const wxFileName & fn); - bool LoadFXProgram(unsigned char **bptr, ssize_t & len, int index, bool dryrun); - void SaveFXB(const wxFileName & fn); - void SaveFXP(const wxFileName & fn); - void SaveXML(const wxFileName & fn); - void SaveFXProgram(wxMemoryBuffer & buf, int index); - - virtual bool HandleXMLTag(const wxChar *tag, const wxChar **attrs); - virtual void HandleXMLEndTag(const wxChar *tag); - virtual void HandleXMLContent(const wxString & content); - virtual XMLTagHandler *HandleXMLChild(const wxChar *tag); - -private: - VSTEffect *mEffect; - AEffect *mAEffect; - - bool mGui; - - wxSizerItem *mContainer; - - wxComboBox *mProgram; - wxStaticText **mNames; - wxSlider **mSliders; - wxStaticText **mDisplays; - wxStaticText **mLabels; - - bool mInChunk; - wxString mChunk; - -#if defined(__WXMAC__) - static pascal OSStatus OverlayEventHandler(EventHandlerCallRef handler, EventRef event, void *data); - OSStatus OnOverlayEvent(EventHandlerCallRef handler, EventRef event); - static pascal OSStatus WindowEventHandler(EventHandlerCallRef handler, EventRef event, void *data); - OSStatus OnWindowEvent(EventHandlerCallRef handler, EventRef event); - - WindowRef mOverlayRef; - EventHandlerUPP mOverlayEventHandlerUPP; - EventHandlerRef mOverlayEventHandlerRef; - - WindowRef mWindowRef; - WindowRef mPreviousRef; - EventHandlerUPP mWindowEventHandlerUPP; - EventHandlerRef mWindowEventHandlerRef; - -#elif defined(__WXMSW__) - - HANDLE mHwnd; - -#else - - Display *mXdisp; - Window mXwin; - -#endif - - DECLARE_EVENT_TABLE() }; +/////////////////////////////////////////////////////////////////////////////// +// +// LadspaEffectEventHelper +// +/////////////////////////////////////////////////////////////////////////////// + enum { - ID_VST_PROGRAM = 11000, - ID_VST_PROGRAMTEXT, - ID_VST_LOAD, - ID_VST_SAVE, - ID_VST_SLIDERS, - ID_VST_SETTINGS + ID_DURATION = 20000, + ID_SLIDERS = 21000, }; -BEGIN_EVENT_TABLE(VSTEffectDialog, wxDialog) - EVT_CLOSE(VSTEffectDialog::OnClose) - - EVT_BUTTON(wxID_APPLY, VSTEffectDialog::OnApply) - EVT_BUTTON(wxID_OK, VSTEffectDialog::OnOk) - EVT_BUTTON(wxID_CANCEL, VSTEffectDialog::OnCancel) - EVT_BUTTON(ePreviewID, VSTEffectDialog::OnPreview) - EVT_BUTTON(eDefaultsID, VSTEffectDialog::OnDefaults) - - EVT_COMBOBOX(ID_VST_PROGRAM, VSTEffectDialog::OnProgram) - EVT_TEXT(ID_VST_PROGRAM, VSTEffectDialog::OnProgramText) - EVT_BUTTON(ID_VST_LOAD, VSTEffectDialog::OnLoad) - EVT_BUTTON(ID_VST_SAVE, VSTEffectDialog::OnSave) - EVT_BUTTON(ID_VST_SETTINGS, VSTEffectDialog::OnSettings) - - EVT_SLIDER(wxID_ANY, VSTEffectDialog::OnSlider) +BEGIN_EVENT_TABLE(VSTEffectEventHelper, wxEvtHandler) + EVT_COMMAND_RANGE(ID_SLIDERS, ID_SLIDERS + 999, wxEVT_COMMAND_SLIDER_UPDATED, VSTEffectEventHelper::OnSlider) // Events from the audioMaster callback - EVT_COMMAND(wxID_ANY, EVT_SIZEWINDOW, VSTEffectDialog::OnSizeWindow) - EVT_COMMAND(wxID_ANY, EVT_UPDATEDISPLAY, VSTEffectDialog::OnUpdateDisplay) + EVT_COMMAND(wxID_ANY, EVT_SIZEWINDOW, VSTEffectEventHelper::OnSizeWindow) END_EVENT_TABLE() +VSTEffectEventHelper::VSTEffectEventHelper(VSTEffect *effect) +{ + mEffect = effect; +} + +VSTEffectEventHelper::~VSTEffectEventHelper() +{ +} + +// ============================================================================ +// VSTEffectEventHelper implementation +// ============================================================================ + +void VSTEffectEventHelper::OnSlider(wxCommandEvent & evt) +{ + mEffect->OnSlider(evt); +} + +void VSTEffectEventHelper::ControlSetFocus(wxFocusEvent & evt) +{ + mEffect->ControlSetFocus(evt); +} + +void VSTEffectEventHelper::OnSizeWindow(wxCommandEvent & evt) +{ + mEffect->OnSizeWindow(evt); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// VSTEffect +// +/////////////////////////////////////////////////////////////////////////////// + +DEFINE_LOCAL_EVENT_TYPE(EVT_SIZEWINDOW); +DEFINE_LOCAL_EVENT_TYPE(EVT_UPDATEDISPLAY); + #if defined(__WXMAC__) // To use, change the SDK in the project to at least 10.5 @@ -921,13 +886,13 @@ static const EventTypeSpec OverlayEventList[] = }; // Overlay window event handler callback thunk -pascal OSStatus VSTEffectDialog::OverlayEventHandler(EventHandlerCallRef handler, EventRef event, void *data) +pascal OSStatus VSTEffect::OverlayEventHandler(EventHandlerCallRef handler, EventRef event, void *data) { - return ((VSTEffectDialog *)data)->OnOverlayEvent(handler, event); + return ((VSTEffect *)data)->OnOverlayEvent(handler, event); } // Overlay window event handler -OSStatus VSTEffectDialog::OnOverlayEvent(EventHandlerCallRef handler, EventRef event) +OSStatus VSTEffect::OnOverlayEvent(EventHandlerCallRef handler, EventRef event) { // Get the current window in front of all the rest of the non-floaters. WindowRef frontwin = FrontNonFloatingWindow(); @@ -1067,13 +1032,13 @@ static const EventTypeSpec WindowEventList[] = }; // Our window event handler callback thunk -pascal OSStatus VSTEffectDialog::WindowEventHandler(EventHandlerCallRef handler, EventRef event, void *data) +pascal OSStatus VSTEffect::WindowEventHandler(EventHandlerCallRef handler, EventRef event, void *data) { - return ((VSTEffectDialog *)data)->OnWindowEvent(handler, event); + return ((VSTEffect *)data)->OnWindowEvent(handler, event); } // Our window event handler -OSStatus VSTEffectDialog::OnWindowEvent(EventHandlerCallRef handler, EventRef event) +OSStatus VSTEffect::OnWindowEvent(EventHandlerCallRef handler, EventRef event) { // Get the current window in from of all the rest non-floaters. WindowRef frontwin = FrontNonFloatingWindow(); @@ -1155,7 +1120,7 @@ OSStatus VSTEffectDialog::OnWindowEvent(EventHandlerCallRef handler, EventRef ev case kEventWindowClose: { RemoveHandler(); - Close(); + mDialog->Close(); return noErr; } break; @@ -1257,1690 +1222,6 @@ static int X11TrapHandler(Display *, XErrorEvent *err) } #endif -VSTEffectDialog::VSTEffectDialog(wxWindow *parent, - const wxString & title, - VSTEffect *effect, - AEffect *aeffect) -: wxDialog(parent, wxID_ANY, title), - mEffect(effect), - mAEffect(aeffect) -{ - mNames = NULL; - mSliders = NULL; - mDisplays = NULL; - mLabels = NULL; - mContainer = NULL; - -#if defined(__WXMAC__) - -#if defined(EXPERIMENTAL_REALTIME_EFFECTS) - HIWindowChangeClass((WindowRef) MacGetWindowRef(), kFloatingWindowClass); -#endif - - mOverlayRef = 0; - mOverlayEventHandlerUPP = 0; - mOverlayEventHandlerRef = 0; - - mWindowRef = 0; - mWindowEventHandlerUPP = 0; - mWindowEventHandlerRef = 0; -#elif defined(__WXMSW__) - mHwnd = 0; -#else - mXdisp = NULL; - mXwin = NULL; -#endif - - // Determine if the VST editor is supposed to be used or not - mEffect->mHost->GetSharedConfig(wxT("Settings"), - wxT("UseGUI"), - mGui, - true); - mGui = mAEffect->flags & effFlagsHasEditor ? mGui : false; - - // Must use the GUI editor if parameters aren't provided - if (mAEffect->numParams == 0) - { - mGui = true; - } - - // Build the appropriate dialog type - if (mGui) - { - BuildFancy(); - } - else - { - BuildPlain(); - } -} - -VSTEffectDialog::~VSTEffectDialog() -{ - mEffect->InterfaceClosed(); - - mEffect->PowerOff(); - mEffect->NeedEditIdle(false); - - RemoveHandler(); - - if (mNames) - { - delete [] mNames; - } - - if (mSliders) - { - delete [] mSliders; - } - - if (mDisplays) - { - delete [] mDisplays; - } - - if (mLabels) - { - delete [] mLabels; - } -} - -void VSTEffectDialog::RemoveHandler() -{ -#if defined(__WXMAC__) - if (mWindowRef) - { - mEffect->callDispatcher(effEditClose, 0, 0, mWindowRef, 0.0); - mWindowRef = 0; - } - - if (mOverlayEventHandlerRef) - { - ::RemoveEventHandler(mOverlayEventHandlerRef); - mOverlayEventHandlerRef = 0; - } - - if (mOverlayEventHandlerUPP) - { - DisposeEventHandlerUPP(mOverlayEventHandlerUPP); - mOverlayEventHandlerUPP = 0; - } - - if (mWindowEventHandlerRef) - { - ::RemoveEventHandler(mWindowEventHandlerRef); - mWindowEventHandlerRef = 0; - MacInstallTopLevelWindowEventHandler(); - } - - if (mWindowEventHandlerUPP) - { - DisposeEventHandlerUPP(mWindowEventHandlerUPP); - mWindowEventHandlerUPP = 0; - } -#elif defined(__WXMSW__) - if (mHwnd) - { - mEffect->callDispatcher(effEditClose, 0, 0, mHwnd, 0.0); - mHwnd = 0; - } -#else - if (mXwin) - { - mEffect->callDispatcher(effEditClose, 0, (intptr_t)mXdisp, (void *)mXwin, 0.0); - mXdisp = NULL; - mXwin = NULL; - } -#endif -} - -void VSTEffectDialog::BuildFancy() -{ - struct - { - short top, left, bottom, right; - } *rect; - - // Turn the power on...some effects need this when the editor is open - mEffect->PowerOn(); - - // Some effects like to have us get their rect before opening them. - mEffect->callDispatcher(effEditGetRect, 0, 0, &rect, 0.0); - -#if defined(__WXMAC__) - // Retrieve the current window and the one above it. The window list - // is kept in top-most to bottom-most order, so we'll use that to - // determine if another window was opened above ours. - mWindowRef = (WindowRef) MacGetWindowRef(); - mPreviousRef = GetPreviousWindow(mWindowRef); - - // Install the event handler on our window - mWindowEventHandlerUPP = NewEventHandlerUPP(WindowEventHandler); - InstallWindowEventHandler(mWindowRef, - mWindowEventHandlerUPP, - GetEventTypeCount(WindowEventList), - WindowEventList, - this, - &mWindowEventHandlerRef); - - // Find the content view within our window - HIViewRef view; - HIViewFindByID(HIViewGetRoot(mWindowRef), kHIViewWindowContentID, &view); - - // And ask the effect to add it's GUI - mEffect->callDispatcher(effEditOpen, 0, 0, mWindowRef, 0.0); - - // Get the subview it created - HIViewRef subview = HIViewGetFirstSubview(view); - if (subview == NULL) - { - // Doesn't seem the effect created the subview, so switch - // to the plain dialog. This can happen when an effect - // uses the content view directly. As of this time, we - // will not try to support those and fall back to the - // textual interface. - mGui = false; - RemoveHandler(); - BuildPlain(); - return; - } - -#elif defined(__WXMSW__) - - wxPanel *w = new wxPanel(this, wxID_ANY); - mHwnd = w->GetHWND(); - mEffect->callDispatcher(effEditOpen, 0, 0, mHwnd, 0.0); - -#else - - // Use a panel to host the plugins GUI - wxPanel *w = new wxPanel(this); - - // Make sure is has a window - if (!GTK_WIDGET(w->m_wxwindow)->window) - { - gtk_widget_realize(GTK_WIDGET(w->m_wxwindow)); - } - - GdkWindow *gwin = GTK_WIDGET(w->m_wxwindow)->window; - mXdisp = GDK_WINDOW_XDISPLAY(gwin); - mXwin = GDK_WINDOW_XWINDOW(gwin); - - mEffect->callDispatcher(effEditOpen, 0, (intptr_t)mXdisp, (void *)mXwin, 0.0); - -#endif - - // Get the final bounds of the effect GUI - mEffect->callDispatcher(effEditGetRect, 0, 0, &rect, 0.0); - - // Build our display now - wxBoxSizer *vs = new wxBoxSizer(wxVERTICAL); - wxBoxSizer *hs = new wxBoxSizer(wxHORIZONTAL); - - // Add the program bar at the top - vs->Add(BuildProgramBar(), 0, wxCENTER | wxEXPAND); - -#if defined(__WXMAC__) - - // Reserve space for the effect GUI - mContainer = hs->Add(rect->right - rect->left, rect->bottom - rect->top); - -#elif defined(__WXMSW__) - - // Add the effect host window to the layout - mContainer = hs->Add(w, 1, wxCENTER | wxEXPAND); - mContainer->SetMinSize(rect->right - rect->left, rect->bottom - rect->top); - -#else - - // Add the effect host window to the layout - mContainer = hs->Add(w, 1, wxCENTER | wxEXPAND); - mContainer->SetMinSize(rect->right - rect->left, rect->bottom - rect->top); - -#endif - - vs->Add(hs, 0, wxCENTER); - - // Add the standard button bar at the bottom -#if defined(EXPERIMENTAL_REALTIME_EFFECTS) - vs->Add(CreateStdButtonSizer(this, eApplyButton | eCancelButton | eDefaultsButton), 0, wxEXPAND); -#else - vs->Add(CreateStdButtonSizer(this, ePreviewButton | eDefaultsButton |eCancelButton | eOkButton), 0, wxEXPAND); -#endif - SetSizerAndFit(vs); - -#if defined(__WXMAC__) - - // Found out where the reserved space wound up - wxPoint pos = mContainer->GetPosition(); - - // Reposition the subview into the reserved space - HIViewPlaceInSuperviewAt(subview, pos.x, pos.y); - - // Some VST effects do not work unless the default handler is removed since - // it captures many of the events that the plugins need. But, it must be - // done last since proper window sizing will not occur otherwise. - ::RemoveEventHandler((EventHandlerRef)MacGetEventHandler()); - -#elif defined(__WXMSW__) -#else -#endif - - mEffect->NeedEditIdle(true); -} - -void VSTEffectDialog::BuildPlain() -{ - mNames = new wxStaticText *[mAEffect->numParams]; - mSliders = new wxSlider *[mAEffect->numParams]; - mDisplays = new wxStaticText *[mAEffect->numParams]; - mLabels = new wxStaticText *[mAEffect->numParams]; - - wxBoxSizer *vSizer = new wxBoxSizer(wxVERTICAL); - vSizer->Add(BuildProgramBar(), 0, wxALIGN_CENTER | wxEXPAND); - - wxScrolledWindow *sw = new wxScrolledWindow(this, - wxID_ANY, - wxDefaultPosition, - wxDefaultSize, - wxVSCROLL | wxTAB_TRAVERSAL); - - // Try to give the window a sensible default/minimum size - wxSize sz = GetParent()->GetSize(); - sw->SetMinSize(wxSize(wxMax(600, sz.GetWidth() * 2 / 3), sz.GetHeight() / 2)); - - sw->SetScrollRate(0, 20); - vSizer->Add(sw, 1, wxEXPAND | wxALL, 5); - - // Add the standard button bar at the bottom - if (mEffect->IsRealtimeCapable()) - { - vSizer->Add(CreateStdButtonSizer(this, eDefaultsButton | eCancelButton | eApplyButton), 0, wxEXPAND); - } - else - { - vSizer->Add(CreateStdButtonSizer(this, ePreviewButton | eDefaultsButton | eCancelButton | eOkButton), 0, wxEXPAND); - } - - SetSizer(vSizer); - - wxSizer *paramSizer = new wxStaticBoxSizer(wxVERTICAL, sw, _("Effect Settings")); - - wxFlexGridSizer *gridSizer = new wxFlexGridSizer(4, 0, 0); - gridSizer->AddGrowableCol(1); - - // Find the longest parameter name. - int namew = 0; - int w; - int h; - for (int i = 0; i < mAEffect->numParams; i++) - { - wxString text = mEffect->GetString(effGetParamName, i); - if (text.Right(1) != wxT(':')) - { - text += wxT(':'); - } - GetTextExtent(text, &w, &h); - if (w > namew) - { - namew = w; - } - } - - GetTextExtent(wxT("HHHHHHHH"), &w, &h); - - for (int i = 0; i < mAEffect->numParams; i++) - { - mNames[i] = new wxStaticText(sw, - wxID_ANY, - wxEmptyString, - wxDefaultPosition, - wxSize(namew, -1), - wxALIGN_RIGHT | wxST_NO_AUTORESIZE); - gridSizer->Add(mNames[i], 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5); - - mSliders[i] = new wxSlider(sw, - ID_VST_SLIDERS + i, - 0, - 0, - 1000, - wxDefaultPosition, - wxSize(200, -1)); - gridSizer->Add(mSliders[i], 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxALL, 5); - - mDisplays[i] = new wxStaticText(sw, - wxID_ANY, - wxEmptyString, - wxDefaultPosition, - wxSize(w, -1), - wxALIGN_RIGHT | wxST_NO_AUTORESIZE); - gridSizer->Add(mDisplays[i], 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5); - - mLabels[i] = new wxStaticText(sw, - wxID_ANY, - wxEmptyString, - wxDefaultPosition, - wxSize(w, -1), - wxALIGN_LEFT | wxST_NO_AUTORESIZE); - gridSizer->Add(mLabels[i], 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, 5); - } - - paramSizer->Add(gridSizer, 1, wxEXPAND | wxALL, 5); - sw->SetSizer(paramSizer); - - Layout(); - Fit(); - SetSizeHints(GetSize()); - RefreshParameters(); - - mSliders[0]->SetFocus(); -} - -wxSizer *VSTEffectDialog::BuildProgramBar() -{ - wxArrayString progs; - - // Some plugins, like Guitar Rig 5, only report 128 programs while they have hundreds. While - // I was able to come up with a hack in the Guitar Rig case to gather all of the program names, - // it would not let me set a program outside of the first 128. - for (int i = 0; i < mAEffect->numPrograms; i++) - { - progs.Add(mEffect->GetString(effGetProgramNameIndexed, i)); - } - - if (progs.GetCount() == 0) - { - progs.Add(_("None")); - } - - wxString val; - int progn = mEffect->callDispatcher(effGetProgram, 0, 0, NULL, 0.0); - - // An unset program is perfectly valid, do not force a default. - if (progn >= 0 && progn < (int) progs.GetCount()) - { - val = progs[progn]; - } - - wxBoxSizer *hs = new wxBoxSizer(wxHORIZONTAL); - - wxStaticText *st = new wxStaticText(this, wxID_ANY, _("Presets:")); - hs->Add(st, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - - mProgram = new wxComboBox(this, - ID_VST_PROGRAM, - val, - wxDefaultPosition, - wxSize(200, -1), - progs); - mProgram->SetName(_("Presets")); - hs->Add(mProgram, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - - wxButton *bt = new wxButton(this, ID_VST_LOAD, _("&Load")); - hs->Add(bt, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - - bt = new wxButton(this, ID_VST_SAVE, _("&Save")); - hs->Add(bt, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - - hs->AddStretchSpacer(); - - bt = new wxButton(this, ID_VST_SETTINGS, _("S&ettings...")); - hs->Add(bt, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, 5); - - return hs; -} - -void VSTEffectDialog::RefreshParameters(int skip) -{ - if (!mGui) - { - for (int i = 0; i < mAEffect->numParams; i++) - { - wxString text = mEffect->GetString(effGetParamName, i); - text = text.Trim(true).Trim(false); - - wxString name = text; - - if (text.Right(1) != wxT(':')) - { - text += wxT(':'); - } - mNames[i]->SetLabel(text); - - // For some parameters types like on/off, setting the slider value has - // a side effect that causes it to only move when the parameter changes - // from off to on. However, this prevents changing the value using the - // keyboard, so we skip the active slider if any. - if (i != skip) - { - mSliders[i]->SetValue(mEffect->callGetParameter(i) * 1000); - } - name = text; - - text = mEffect->GetString(effGetParamDisplay, i); - if (text.IsEmpty()) - { - text.Printf(wxT("%.5g"),mEffect->callGetParameter(i)); - } - mDisplays[i]->SetLabel(wxString::Format(wxT("%8s"), text.c_str())); - name += wxT(' ') + text; - - text = mEffect->GetString(effGetParamDisplay, i); - if (!text.IsEmpty()) - { - text.Printf(wxT("%-8s"), mEffect->GetString(effGetParamLabel, i).c_str()); - mLabels[i]->SetLabel(wxString::Format(wxT("%8s"), text.c_str())); - name += wxT(' ') + text; - } - - mSliders[i]->SetName(name); - } - } -} - -void VSTEffectDialog::OnUpdateDisplay(wxCommandEvent & WXUNUSED(evt)) -{ - int i; - - Freeze(); - - // Refresh the program list since some effects change the available programs based - // on the users activity. - mProgram->Clear(); - for (i = 0; i < mAEffect->numPrograms; i++) - { - mProgram->Append(mEffect->GetString(effGetProgramNameIndexed, i)); - } - - // The new list may not have the previously selected program or the user may have - // changed it - i = mEffect->callDispatcher(effGetProgram, 0, 0, NULL, 0.0); - if (i >= 0) - { - mProgram->SetSelection(i); - } - - Thaw(); -} - -void VSTEffectDialog::OnSizeWindow(wxCommandEvent & evt) -{ - if (!mContainer) - { - return; - } - - mContainer->SetMinSize(evt.GetInt(), (int) evt.GetExtraLong()); - Fit(); - Layout(); -} - -void VSTEffectDialog::OnSlider(wxCommandEvent & evt) -{ - wxSlider *s = (wxSlider *) evt.GetEventObject(); - int i = s->GetId() - ID_VST_SLIDERS; - - mEffect->callSetParameter(i, s->GetValue() / 1000.0); - - RefreshParameters(i); -} - -void VSTEffectDialog::OnProgram(wxCommandEvent & evt) -{ - mEffect->callDispatcher(effSetProgram, 0, evt.GetInt(), NULL, 0.0); - - RefreshParameters(); -} - -void VSTEffectDialog::OnProgramText(wxCommandEvent & WXUNUSED(evt)) -{ - int i = mEffect->callDispatcher(effGetProgram, 0, 0, NULL, 0.0); - - // Bail if nothing is selected - if (i < 0) - { - return; - } - - wxString name = mProgram->GetValue(); - int ip = mProgram->GetInsertionPoint(); - - // Limit the length of the string, max 24 + 1 for null terminator - if (name.length() > 24) - { - name = name.substr(0, 24); - } - - mEffect->SetString(effSetProgramName, name, i); - - // Some effects do not allow you to change the name and you can't always trust the - // return value, so just ask for the name again. - name = mEffect->GetString(effGetProgramNameIndexed, i); - - mProgram->SetString(i, name); - - // On Windows, you must reselect after doing a SetString()...at least that's - // what seems to be required. -#if defined(__WXMSW__) - mProgram->SetStringSelection(name); -#endif - - // Which also means we have to reposition the caret. - if (ip >= 0) - { - mProgram->SetInsertionPoint(ip); - } - - RefreshParameters(); -} - -// -// Load an "fxb", "fxp" or Audacuty "xml" file -// -// Based on work by Sven Giermann -// -void VSTEffectDialog::OnLoad(wxCommandEvent & WXUNUSED(evt)) -{ - wxString path; - - // Ask the user for the real name - path = FileSelector(_("Load VST Preset:"), - FileNames::DataDir(), - wxEmptyString, - wxT("xml"), - wxT("VST preset files (*.fxb; *.fxp; *.xml)|*.fxb;*.fxp;*.xml"), - wxFD_OPEN | wxRESIZE_BORDER, - this); - - // User canceled... - if (path.IsEmpty()) - { - return; - } - - wxFileName fn(path); - wxString ext = fn.GetExt(); - bool success = false; - if (ext.CmpNoCase(wxT("fxb")) == 0) - { - success = LoadFXB(fn); - } - else if (ext.CmpNoCase(wxT("fxp")) == 0) - { - success = LoadFXP(fn); - } - else if (ext.CmpNoCase(wxT("xml")) == 0) - { - success = LoadXML(fn); - } - else - { - // This shouldn't happen, but complain anyway - wxMessageBox(_("Unrecognized file extension."), - _("Error Loading VST Presets"), - wxOK | wxCENTRE, - this); - - return; - } - - if (!success) - { - wxMessageBox(_("Unable to load presets file."), - _("Error Loading VST Presets"), - wxOK | wxCENTRE, - this); - - return; - } - - RefreshParameters(); - - return; -} - -bool VSTEffectDialog::LoadFXB(const wxFileName & fn) -{ - bool ret = false; - - // Try to open the file...will be closed automatically when method returns - wxFFile f(fn.GetFullPath(), wxT("rb")); - if (!f.IsOpened()) - { - return false; - } - - // Allocate memory for the contents - unsigned char *data = new unsigned char[f.Length()]; - if (!data) - { - wxMessageBox(_("Unable to allocate memory when loading presets file."), - _("Error Loading VST Presets"), - wxOK | wxCENTRE, - this); - return false; - } - unsigned char *bptr = data; - - do - { - // Read in the whole file - ssize_t len = f.Read((void *) bptr, f.Length()); - if (f.Error()) - { - wxMessageBox(_("Unable to read presets file."), - _("Error Loading VST Presets"), - wxOK | wxCENTRE, - this); - break; - } - - // Most references to the data are via an "int" array - int32_t *iptr = (int32_t *) bptr; - - // Verify that we have at least enough the header - if (len < 156) - { - break; - } - - // Verify that we probably have a FX file - if (wxINT32_SWAP_ON_LE(iptr[0]) != CCONST('C', 'c', 'n', 'K')) - { - break; - } - - // Ignore the size...sometimes it's there, other times it's zero - - // Get the version and verify - int version = wxINT32_SWAP_ON_LE(iptr[3]); - if (version != 1 && version != 2) - { - break; - } - - // Ensure this program looks to belong to the current plugin - if (wxINT32_SWAP_ON_LE(iptr[4]) != mAEffect->uniqueID) - { - break; - } - - // Get the number of programs - int numProgs = wxINT32_SWAP_ON_LE(iptr[6]); - if (numProgs != mAEffect->numPrograms) - { - break; - } - - // Get the current program index - int curProg = 0; - if (version == 2) - { - curProg = wxINT32_SWAP_ON_LE(iptr[7]); - if (curProg < 0 || curProg >= numProgs) - { - break; - } - } - - // Is it a bank of programs? - if (wxINT32_SWAP_ON_LE(iptr[2]) == CCONST('F', 'x', 'B', 'k')) - { - // Drop the header - bptr += 156; - len -= 156; - - unsigned char *tempPtr = bptr; - ssize_t tempLen = len; - - // Validate all of the programs - for (int i = 0; i < numProgs; i++) - { - if (!LoadFXProgram(&tempPtr, tempLen, i, true)) - { - break; - } - } - - // They look okay, time to start changing things - for (int i = 0; i < numProgs; i++) - { - ret = LoadFXProgram(&bptr, len, i, false); - } - } - // Or maybe a bank chunk? - else if (wxINT32_SWAP_ON_LE(iptr[2]) == CCONST('F', 'B', 'C', 'h')) - { - // Can't load programs chunks if the plugin doesn't support it - if (!(mAEffect->flags & effFlagsProgramChunks)) - { - break; - } - - // Verify that we have enough to grab the chunk size - if (len < 160) - { - break; - } - - // Get the chunk size - int size = wxINT32_SWAP_ON_LE(iptr[39]); - - // We finally know the full length of the program - int proglen = 160 + size; - - // Verify that we have enough for the entire program - if (len < proglen) - { - break; - } - - // Set the entire bank in one shot - mEffect->callDispatcher(effSetChunk, 0, size, &iptr[40], 0.0); - - // Success - ret = true; - } - // Unrecognizable type - else - { - break; - } - - // Set the active program - if (ret && version == 2) - { - mEffect->callDispatcher(effSetProgram, 0, curProg, NULL, 0.0); - mProgram->SetSelection(curProg); - } - } while (false); - - // Get rid of the data - delete [] data; - - return ret; -} - -bool VSTEffectDialog::LoadFXP(const wxFileName & fn) -{ - bool ret = false; - - // Try to open the file...will be closed automatically when method returns - wxFFile f(fn.GetFullPath(), wxT("rb")); - if (!f.IsOpened()) - { - return false; - } - - // Allocate memory for the contents - unsigned char *data = new unsigned char[f.Length()]; - if (!data) - { - wxMessageBox(_("Unable to allocate memory when loading presets file."), - _("Error Loading VST Presets"), - wxOK | wxCENTRE, - this); - return false; - } - unsigned char *bptr = data; - - do - { - // Read in the whole file - ssize_t len = f.Read((void *) bptr, f.Length()); - if (f.Error()) - { - wxMessageBox(_("Unable to read presets file."), - _("Error Loading VST Presets"), - wxOK | wxCENTRE, - this); - break; - } - - // Get (or default) currently selected program - int i = mProgram->GetCurrentSelection(); - if (i < 0) - { - i = 0; // default to first program - } - - // Go verify and set the program - ret = LoadFXProgram(&bptr, len, i, false); - } while (false); - - // Get rid of the data - delete [] data; - - return ret; -} - -bool VSTEffectDialog::LoadFXProgram(unsigned char **bptr, ssize_t & len, int index, bool dryrun) -{ - // Most references to the data are via an "int" array - int32_t *iptr = (int32_t *) *bptr; - - // Verify that we have at least enough for a program without parameters - if (len < 28) - { - return false; - } - - // Verify that we probably have an FX file - if (wxINT32_SWAP_ON_LE(iptr[0]) != CCONST('C', 'c', 'n', 'K')) - { - return false; - } - - // Ignore the size...sometimes it's there, other times it's zero - - // Get the version and verify -#if defined(IS_THIS_AND_FXP_ARTIFICAL_LIMITATION) - int version = wxINT32_SWAP_ON_LE(iptr[3]); - if (version != 1) - { - return false; - } -#endif - - // Ensure this program looks to belong to the current plugin - if (wxINT32_SWAP_ON_LE(iptr[4]) != mAEffect->uniqueID) - { - return false; - } - - // Get the number of parameters - int numParams = wxINT32_SWAP_ON_LE(iptr[6]); - if (numParams != mAEffect->numParams) - { - return false; - } - - // At this point, we have to have enough to include the program name as well - if (len < 56) - { - return false; - } - - // Get the program name - wxString progName(wxString::From8BitData((char *)&iptr[7])); - - // Might be a regular program - if (wxINT32_SWAP_ON_LE(iptr[2]) == CCONST('F', 'x', 'C', 'k')) - { - // We finally know the full length of the program - int proglen = 56 + (numParams * sizeof(float)); - - // Verify that we have enough for all of the parameter values - if (len < proglen) - { - return false; - } - - // Validate all of the parameter values - for (int i = 0; i < numParams; i++) - { - uint32_t ival = wxUINT32_SWAP_ON_LE(iptr[14 + i]); - float val = *((float *) &ival); - if (val < 0.0 || val > 1.0) - { - return false; - } - } - - // They look okay...time to start changing things - if (!dryrun) - { - for (int i = 0; i < numParams; i++) - { - wxUint32 val = wxUINT32_SWAP_ON_LE(iptr[14 + i]); - mEffect->callSetParameter(i, *((float *) &val)); - } - } - - // Update in case we're loading an "FxBk" format bank file - *bptr += proglen; - len -= proglen; - } - // Maybe we have a program chunk - else if (wxINT32_SWAP_ON_LE(iptr[2]) == CCONST('F', 'P', 'C', 'h')) - { - // Can't load programs chunks if the plugin doesn't support it - if (!(mAEffect->flags & effFlagsProgramChunks)) - { - return false; - } - - // Verify that we have enough to grab the chunk size - if (len < 60) - { - return false; - } - - // Get the chunk size - int size = wxINT32_SWAP_ON_LE(iptr[14]); - - // We finally know the full length of the program - int proglen = 60 + size; - - // Verify that we have enough for the entire program - if (len < proglen) - { - return false; - } - - // Set the entire program in one shot - if (!dryrun) - { - mEffect->callDispatcher(effSetChunk, 1, size, &iptr[15], 0.0); - } - - // Update in case we're loading an "FxBk" format bank file - *bptr += proglen; - len -= proglen; - } - else - { - // Unknown type - return false; - } - - if (!dryrun) - { - mProgram->SetString(index, progName); - mProgram->SetValue(progName); - mEffect->SetString(effSetProgramName, wxString(progName), index); - } - - return true; -} - -bool VSTEffectDialog::LoadXML(const wxFileName & fn) -{ - // default to read as XML file - // Load the program - XMLFileReader reader; - if (!reader.Parse(this, fn.GetFullPath())) - { - // Inform user of load failure - wxMessageBox(reader.GetErrorStr(), - _("Error Loading VST Presets"), - wxOK | wxCENTRE, - this); - return false; - } - - return true; -} - -void VSTEffectDialog::OnSave(wxCommandEvent & WXUNUSED(evt)) -{ - wxString path; - - // Ask the user for the real name - // - // Passing a valid parent will cause some effects dialogs to malfunction - // upon returning from the FileSelector(). - path = FileSelector(_("Save VST Preset As:"), - FileNames::DataDir(), - mProgram->GetValue(), - wxT("xml"), - wxT("Standard VST bank file (*.fxb)|*.fxb|Standard VST program file (*.fxp)|*.fxp|Audacity VST preset file (*.xml)|*.xml"), - wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER, - NULL); - - // User canceled... - if (path.IsEmpty()) - { - return; - } - - wxFileName fn(path); - wxString ext = fn.GetExt(); - if (ext.CmpNoCase(wxT("fxb")) == 0) - { - SaveFXB(fn); - } - else if (ext.CmpNoCase(wxT("fxp")) == 0) - { - SaveFXP(fn); - } - else if (ext.CmpNoCase(wxT("xml")) == 0) - { - SaveXML(fn); - } - else - { - // This shouldn't happen, but complain anyway - wxMessageBox(_("Unrecognized file extension."), - _("Error Saving VST Presets"), - wxOK | wxCENTRE, - this); - - return; - } -} - -void VSTEffectDialog::SaveFXB(const wxFileName & fn) -{ - // Create/Open the file - wxFFile f(fn.GetFullPath(), wxT("wb")); - if (!f.IsOpened()) - { - wxMessageBox(wxString::Format(_("Could not open file: \"%s\""), fn.GetFullPath().c_str()), - _("Error Saving VST Presets"), - wxOK | wxCENTRE, - this); - return; - } - - wxMemoryBuffer buf; - wxInt32 subType; - void *chunkPtr; - int chunkSize; - int dataSize = 148; - wxInt32 tab[8]; - int curProg = mProgram->GetCurrentSelection(); - - if (mAEffect->flags & effFlagsProgramChunks) - { - subType = CCONST('F', 'B', 'C', 'h'); - - chunkSize = mEffect->callDispatcher(effGetChunk, 0, 0, &chunkPtr, 0.0); - dataSize += 4 + chunkSize; - } - else - { - subType = CCONST('F', 'x', 'B', 'k'); - - for (int i = 0; i < mAEffect->numPrograms; i++) - { - SaveFXProgram(buf, i); - } - - dataSize += buf.GetDataLen(); - } - - tab[0] = wxINT32_SWAP_ON_LE(CCONST('C', 'c', 'n', 'K')); - tab[1] = wxINT32_SWAP_ON_LE(dataSize); - tab[2] = wxINT32_SWAP_ON_LE(subType); - tab[3] = wxINT32_SWAP_ON_LE(curProg >= 0 ? 2 : 1); - tab[4] = wxINT32_SWAP_ON_LE(mAEffect->uniqueID); - tab[5] = wxINT32_SWAP_ON_LE(mAEffect->version); - tab[6] = wxINT32_SWAP_ON_LE(mAEffect->numPrograms); - tab[7] = wxINT32_SWAP_ON_LE(curProg >= 0 ? curProg : 0); - - f.Write(tab, sizeof(tab)); - if (!f.Error()) - { - char padding[124]; - memset(padding, 0, sizeof(padding)); - f.Write(padding, sizeof(padding)); - - if (!f.Error()) - { - if (mAEffect->flags & effFlagsProgramChunks) - { - wxInt32 size = wxINT32_SWAP_ON_LE(chunkSize); - f.Write(&size, sizeof(size)); - f.Write(chunkPtr, chunkSize); - } - else - { - f.Write(buf.GetData(), buf.GetDataLen()); - } - } - } - - if (f.Error()) - { - wxMessageBox(wxString::Format(_("Error writing to file: \"%s\""), fn.GetFullPath().c_str()), - _("Error Saving VST Presets"), - wxOK | wxCENTRE, - this); - } - - f.Close(); - - return; -} - -void VSTEffectDialog::SaveFXP(const wxFileName & fn) -{ - // Create/Open the file - wxFFile f(fn.GetFullPath(), wxT("wb")); - if (!f.IsOpened()) - { - wxMessageBox(wxString::Format(_("Could not open file: \"%s\""), fn.GetFullPath().c_str()), - _("Error Saving VST Presets"), - wxOK | wxCENTRE, - this); - return; - } - - wxMemoryBuffer buf; - - int ndx = mEffect->callDispatcher(effGetProgram, 0, 0, NULL, 0.0); - SaveFXProgram(buf, ndx); - - f.Write(buf.GetData(), buf.GetDataLen()); - if (f.Error()) - { - wxMessageBox(wxString::Format(_("Error writing to file: \"%s\""), fn.GetFullPath().c_str()), - _("Error Saving VST Presets"), - wxOK | wxCENTRE, - this); - } - - f.Close(); - - return; -} - -void VSTEffectDialog::SaveFXProgram(wxMemoryBuffer & buf, int index) -{ - wxInt32 subType; - void *chunkPtr; - int chunkSize; - int dataSize = 48; - char progName[28]; - wxInt32 tab[7]; - - mEffect->callDispatcher(effGetProgramNameIndexed, index, 0, &progName, 0.0); - progName[27] = '\0'; - chunkSize = strlen(progName); - memset(&progName[chunkSize], 0, sizeof(progName) - chunkSize); - - if (mAEffect->flags & effFlagsProgramChunks) - { - subType = CCONST('F', 'P', 'C', 'h'); - - chunkSize = mEffect->callDispatcher(effGetChunk, 1, 0, &chunkPtr, 0.0); - dataSize += 4 + chunkSize; - } - else - { - subType = CCONST('F', 'x', 'C', 'k'); - - dataSize += (mAEffect->numParams << 2); - } - - tab[0] = wxINT32_SWAP_ON_LE(CCONST('C', 'c', 'n', 'K')); - tab[1] = wxINT32_SWAP_ON_LE(dataSize); - tab[2] = wxINT32_SWAP_ON_LE(subType); - tab[3] = wxINT32_SWAP_ON_LE(1); - tab[4] = wxINT32_SWAP_ON_LE(mAEffect->uniqueID); - tab[5] = wxINT32_SWAP_ON_LE(mAEffect->version); - tab[6] = wxINT32_SWAP_ON_LE(mAEffect->numParams); - - buf.AppendData(tab, sizeof(tab)); - buf.AppendData(progName, sizeof(progName)); - - if (mAEffect->flags & effFlagsProgramChunks) - { - wxInt32 size = wxINT32_SWAP_ON_LE(chunkSize); - buf.AppendData(&size, sizeof(size)); - buf.AppendData(chunkPtr, chunkSize); - } - else - { - for (int i = 0; i < mAEffect->numParams; i++) - { - float val = mEffect->callGetParameter(i); - wxUint32 ival = wxUINT16_SWAP_ON_LE(*((wxUint32 *) &val)); - buf.AppendData(&ival, sizeof(ival)); - } - } - - return; -} - -void VSTEffectDialog::SaveXML(const wxFileName & fn) -{ - XMLFileWriter xmlFile; - - // Create/Open the file - xmlFile.Open(fn.GetFullPath(), wxT("wb")); - - xmlFile.StartTag(wxT("vstprogrampersistence")); - xmlFile.WriteAttr(wxT("version"), wxT("1")); - - xmlFile.StartTag(wxT("effect")); - xmlFile.WriteAttr(wxT("name"), mEffect->GetName()); - xmlFile.WriteAttr(wxT("version"), mEffect->callDispatcher(effGetVendorVersion, 0, 0, NULL, 0.0)); - - xmlFile.StartTag(wxT("program")); - xmlFile.WriteAttr(wxT("name"), mProgram->GetValue()); - - int clen = 0; - if (mAEffect->flags & effFlagsProgramChunks) - { - void *chunk = NULL; - - clen = (int) mEffect->callDispatcher(effGetChunk, 1, 0, &chunk, 0.0); - if (clen != 0) - { - xmlFile.StartTag(wxT("chunk")); - xmlFile.WriteSubTree(VSTEffect::b64encode(chunk, clen) + wxT('\n')); - xmlFile.EndTag(wxT("chunk")); - } - } - - if (clen == 0) - { - for (int i = 0; i < mAEffect->numParams; i++) - { - xmlFile.StartTag(wxT("param")); - - xmlFile.WriteAttr(wxT("index"), i); - xmlFile.WriteAttr(wxT("name"), - mEffect->GetString(effGetParamName, i)); - xmlFile.WriteAttr(wxT("value"), - wxString::Format(wxT("%f"), - mEffect->callGetParameter(i))); - - xmlFile.EndTag(wxT("param")); - } - } - - xmlFile.EndTag(wxT("program")); - - xmlFile.EndTag(wxT("effect")); - - xmlFile.EndTag(wxT("vstprogrampersistence")); - - // Close the file - xmlFile.Close(); - - return; -} - - -void VSTEffectDialog::OnSettings(wxCommandEvent & WXUNUSED(evt)) -{ - VSTEffectSettingsDialog dlg(this, mEffect->mHost); - if (dlg.ShowModal()) - { - // Call Startup() to reinitialize configuration settings - mEffect->Startup(); - } -} - -void VSTEffectDialog::OnClose(wxCloseEvent & evt) -{ -#if defined(EXPERIMENTAL_REALTIME_EFFECTS) - -#if defined(__WXMAC__) - Destroy(); -#else - Show(false); - evt.Veto(); -#endif - -#else - EndModal(false); -#endif -} - -void VSTEffectDialog::OnApply(wxCommandEvent & WXUNUSED(evt)) -{ -#if defined(__WXMAC__) - Close(); -#else - Show(false); -#endif - - mEffect->SaveParameters(wxT("Current")); - - mEffect->mHost->Apply(); -} - -void VSTEffectDialog::OnPreview(wxCommandEvent & WXUNUSED(evt)) -{ - mEffect->mHost->Preview(); -} - -void VSTEffectDialog::OnOk(wxCommandEvent & WXUNUSED(evt)) -{ -// In wxGTK, Show(false) calls EndModal, which produces an assertion in debug builds -#if !defined(__WXGTK__) - // Hide the dialog before closing the effect to prevent a brief empty dialog - Show(false); -#endif - - mEffect->SaveParameters(wxT("Current")); - - if (mGui) - { -// mEffect->PowerOff(); -// mEffect->NeedEditIdle(false); -// mEffect->callDispatcher(effEditClose, 0, 0, NULL, 0.0); - } - - EndModal(true); -} - -void VSTEffectDialog::OnCancel(wxCommandEvent & WXUNUSED(evt)) -{ -// In wxGTK, Show(false) calls EndModal, which produces an assertion in debug builds -#if !defined(__WXGTK__) - // Hide the dialog before closing the effect to prevent a brief empty dialog - Show(false); -#endif - - if (mGui) - { -// mEffect->PowerOff(); -// mEffect->NeedEditIdle(false); -// mEffect->callDispatcher(effEditClose, 0, 0, NULL, 0.0); - } - - if (IsModal()) - { - EndModal(false); - } -} - -void VSTEffectDialog::OnDefaults(wxCommandEvent & WXUNUSED(evt)) -{ - mEffect->LoadParameters(wxT("Default")); - RefreshParameters(); -} - -bool VSTEffectDialog::HandleXMLTag(const wxChar *tag, const wxChar **attrs) -{ - if (wxStrcmp(tag, wxT("vstprogrampersistence")) == 0) - { - while (*attrs) - { - const wxChar *attr = *attrs++; - const wxChar *value = *attrs++; - - if (!value) - { - break; - } - - const wxString strValue = value; - - if (wxStrcmp(attr, wxT("version")) == 0) - { - if (!XMLValueChecker::IsGoodInt(strValue)) - { - return false; - } - // Nothing to do with it for now - } - else - { - return false; - } - } - - return true; - } - - if (wxStrcmp(tag, wxT("effect")) == 0) - { - while (*attrs) - { - const wxChar *attr = *attrs++; - const wxChar *value = *attrs++; - - if (!value) - { - break; - } - - const wxString strValue = value; - - if (wxStrcmp(attr, wxT("name")) == 0) - { - if (!XMLValueChecker::IsGoodString(strValue)) - { - return false; - } - - if (value != mEffect->GetName()) - { - wxString msg; - msg.Printf(_("This parameter file was saved from %s. Continue?"), value); - int result = wxMessageBox(msg, wxT("Confirm"), wxYES_NO, this); - if (result == wxNO) - { - return false; - } - } - } - else if (wxStrcmp(attr, wxT("version")) == 0) - { - if (!XMLValueChecker::IsGoodInt(strValue)) - { - return false; - } - // Nothing to do with it for now - } - else - { - return false; - } - } - - return true; - } - - if (wxStrcmp(tag, wxT("program")) == 0) - { - while (*attrs) - { - const wxChar *attr = *attrs++; - const wxChar *value = *attrs++; - - if (!value) - { - break; - } - - const wxString strValue = value; - - if (wxStrcmp(attr, wxT("name")) == 0) - { - if (!XMLValueChecker::IsGoodString(strValue)) - { - return false; - } - - if (strValue.length() > 24) - { - return false; - } - - int ndx = mProgram->GetCurrentSelection(); - if (ndx == wxNOT_FOUND) - { - ndx = 0; - } - - mProgram->SetString(ndx, strValue); - mProgram->SetValue(strValue); - - mEffect->SetString(effSetProgramName, strValue, ndx); - } - else - { - return false; - } - } - - mInChunk = false; - - return true; - } - - if (wxStrcmp(tag, wxT("param")) == 0) - { - long ndx = -1; - double val = -1.0; - while (*attrs) - { - const wxChar *attr = *attrs++; - const wxChar *value = *attrs++; - - if (!value) - { - break; - } - - const wxString strValue = value; - - if (wxStrcmp(attr, wxT("index")) == 0) - { - if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&ndx)) - { - return false; - } - - if (ndx < 0 || ndx >= mAEffect->numParams) - { - // Could be a different version of the effect...probably should - // tell the user - return false; - } - } - else if (wxStrcmp(attr, wxT("name")) == 0) - { - if (!XMLValueChecker::IsGoodString(strValue)) - { - return false; - } - // Nothing to do with it for now - } - else if (wxStrcmp(attr, wxT("value")) == 0) - { - if (!XMLValueChecker::IsGoodInt(strValue) || - !Internat::CompatibleToDouble(strValue, &val)) - { - return false; - } - - if (val < 0.0 || val > 1.0) - { - return false; - } - } - } - - if (ndx == -1 || val == -1.0) - { - return false; - } - - mEffect->callSetParameter(ndx, val); - - return true; - } - - if (wxStrcmp(tag, wxT("chunk")) == 0) - { - mInChunk = true; - return true; - } - - return false; -} - -void VSTEffectDialog::HandleXMLEndTag(const wxChar *tag) -{ - if (wxStrcmp(tag, wxT("chunk")) == 0) - { - if (mChunk.length()) - { - char *buf = new char[mChunk.length() / 4 * 3]; - - int len = VSTEffect::b64decode(mChunk, buf); - if (len) - { - mEffect->callDispatcher(effSetChunk, 1, len, buf, 0.0); - } - - delete [] buf; - mChunk.clear(); - } - mInChunk = false; - } -} - -void VSTEffectDialog::HandleXMLContent(const wxString & content) -{ - if (mInChunk) - { - mChunk += wxString(content).Trim(true).Trim(false); - } -} - -XMLTagHandler *VSTEffectDialog::HandleXMLChild(const wxChar *tag) -{ - if (wxStrcmp(tag, wxT("vstprogrampersistence")) == 0) - { - return this; - } - - if (wxStrcmp(tag, wxT("effect")) == 0) - { - return this; - } - - if (wxStrcmp(tag, wxT("program")) == 0) - { - return this; - } - - if (wxStrcmp(tag, wxT("param")) == 0) - { - return this; - } - - if (wxStrcmp(tag, wxT("chunk")) == 0) - { - return this; - } - - return NULL; -} - -/////////////////////////////////////////////////////////////////////////////// -// -// VSTEffectTimer -// -/////////////////////////////////////////////////////////////////////////////// - -class VSTEffectTimer : public wxTimer -{ -public: - VSTEffectTimer(VSTEffect *effect) - : wxTimer(), - mEffect(effect) - { - } - - ~VSTEffectTimer() - { - } - - void Notify() - { - mEffect->OnTimer(); - } - -private: - VSTEffect *mEffect; -}; - -/////////////////////////////////////////////////////////////////////////////// -// -// VSTEffect -// -/////////////////////////////////////////////////////////////////////////////// - typedef AEffect *(*vstPluginMain)(audioMasterCallback audioMaster); intptr_t VSTEffect::AudioMaster(AEffect * effect, @@ -3121,7 +1402,9 @@ VSTEffect::VSTEffect(const wxString & path, VSTEffect *master) mHost = NULL; mModule = NULL; mAEffect = NULL; - mDlg = NULL; + mDialog = NULL; + mEventHelper = NULL; + mTimer = new VSTEffectTimer(this); mTimerGuard = 0; @@ -3155,6 +1438,29 @@ VSTEffect::VSTEffect(const wxString & path, VSTEffect *master) mTimeInfo.timeSigDenominator = 4; mTimeInfo.flags = kVstTempoValid | kVstNanosValid; + // UI + + mNames = NULL; + mSliders = NULL; + mDisplays = NULL; + mLabels = NULL; + mContainer = NULL; + +#if defined(__WXMAC__) + mOverlayRef = 0; + mOverlayEventHandlerUPP = 0; + mOverlayEventHandlerRef = 0; + + mWindowRef = 0; + mWindowEventHandlerUPP = 0; + mWindowEventHandlerRef = 0; +#elif defined(__WXMSW__) + mHwnd = 0; +#else + mXdisp = 0; + mXwin = 0; +#endif + // If we're a slave then go ahead a load immediately if (mMaster) { @@ -3164,6 +1470,31 @@ VSTEffect::VSTEffect(const wxString & path, VSTEffect *master) VSTEffect::~VSTEffect() { + if (mDialog) + { + mDialog->Close(); + } + + if (mNames) + { + delete [] mNames; + } + + if (mSliders) + { + delete [] mSliders; + } + + if (mDisplays) + { + delete [] mDisplays; + } + + if (mLabels) + { + delete [] mLabels; + } + Unload(); } @@ -3268,23 +1599,24 @@ bool VSTEffect::IsLegacy() return false; } -bool VSTEffect::IsRealtimeCapable() +bool VSTEffect::SupportsRealtime() { - return true; + return GetType() == EffectTypeProcess; +} + +bool VSTEffect::SupportsAutomation() +{ + return mAutomatable; } // ============================================================================ // EffectClientInterface Implementation // ============================================================================ -void VSTEffect::SetHost(EffectHostInterface *host) +bool VSTEffect::SetHost(EffectHostInterface *host) { mHost = host; - Startup(); -} - -bool VSTEffect::Startup() -{ + if (!mAEffect) { Load(); @@ -3323,19 +1655,6 @@ bool VSTEffect::Startup() return true; } -bool VSTEffect::Shutdown() -{ - // The master will save the settings. - if (mMaster) - { - return true; - } - - SaveParameters(wxT("Current")); - - return true; -} - int VSTEffect::GetAudioInCount() { return mAudioIns; @@ -3641,9 +1960,15 @@ bool VSTEffect::RealtimeAddProcessor(int numChannels, float sampleRate) // provided by the effect, so it will not work with all effects since they don't // all provide the information (kn0ck0ut is one). // -bool VSTEffect::ShowInterface(void *parent) +bool VSTEffect::ShowInterface(wxWindow *parent, bool forceModal) { -// mProcessLevel = 1; // in GUI thread + if (mDialog) + { + mDialog->Close(true); + return false; + } + + // mProcessLevel = 1; // in GUI thread // Set some defaults since some VSTs need them...these will be reset when // normal or realtime processing begins @@ -3670,35 +1995,300 @@ bool VSTEffect::ShowInterface(void *parent) #endif } - if (!mDlg) + mDialog = mHost->CreateUI(parent, this); + if (!mDialog) { - mDlg = new VSTEffectDialog((wxWindow *) parent, mName, this, mAEffect); - mDlg->CentreOnParent(); + return false; + } + mDialog->CentreOnParent(); + + if (SupportsRealtime() && !forceModal) + { + mDialog->Show(); + + return false; } -#if defined(EXPERIMENTAL_REALTIME_EFFECTS) - mDlg->Show(!mDlg->IsShown()); + bool res = mDialog->ShowModal(); + mDialog = NULL; + + return res; +} + +bool VSTEffect::GetAutomationParameters(EffectAutomationParameters & parms) +{ + for (int i = 0; i < mAEffect->numParams; i++) + { + wxString name = GetString(effGetParamName, i); + float value = callGetParameter(i); + if (!parms.Write(name, value)) + { + return false; + } + } return true; -#else - mDlg->ShowModal(); - bool ret = mDlg->GetReturnCode() != 0; - mDlg->Destroy(); - mDlg = NULL; +} - return ret; +bool VSTEffect::SetAutomationParameters(EffectAutomationParameters & parms) +{ + for (int i = 0; i < mAEffect->numParams; i++) + { + wxString name = GetString(effGetParamName, i); + double d = 0.0; + if (!parms.Read(name, &d)) + { + return false; + } + + callSetParameter(i, d); + } + + return true; +} + +// ============================================================================ +// EffectUIClientInterface implementation +// ============================================================================ + +void VSTEffect::SetUIHost(EffectUIHostInterface *host) +{ + mUIHost = host; +} + +bool VSTEffect::PopulateUI(wxWindow *parent) +{ + mDialog = (wxDialog *) wxGetTopLevelParent(parent); + mParent = parent; + + mEventHelper = new VSTEffectEventHelper(this); + mParent->PushEventHandler(mEventHelper); + +#if defined(__WXMAC__) +#if defined(EXPERIMENTAL_REALTIME_EFFECTS) + HIWindowChangeClass((WindowRef) mDialog->MacGetWindowRef(), kFloatingWindowClass); #endif +#endif + + + // Determine if the VST editor is supposed to be used or not + mHost->GetSharedConfig(wxT("Settings"), + wxT("UseGUI"), + mGui, + true); + mGui = mAEffect->flags & effFlagsHasEditor ? mGui : false; + + // Must use the GUI editor if parameters aren't provided + if (mAEffect->numParams == 0) + { + mGui = true; + } + + // Build the appropriate dialog type + if (mGui) + { + BuildFancy(); + } + else + { + BuildPlain(); + } + + return true; +} + +bool VSTEffect::ValidateUI() +{ + return true; +} + +bool VSTEffect::HideUI() +{ + return true; +} + +bool VSTEffect::CloseUI() +{ + mParent->RemoveEventHandler(mEventHelper); + delete mEventHelper; + + PowerOff(); + + NeedEditIdle(false); + + RemoveHandler(); + + mUIHost = NULL; + mParent = NULL; + mDialog = NULL; + + return true; +} + +void VSTEffect::LoadUserPreset(const wxString & name) +{ + LoadParameters(name); +} + +void VSTEffect::SaveUserPreset(const wxString & name) +{ + SaveParameters(name); +} + +void VSTEffect::LoadFactoryPreset(int id) +{ + callDispatcher(effSetProgram, 0, id, NULL, 0.0); + + RefreshParameters(); +} + +void VSTEffect::LoadFactoryDefaults() +{ + LoadParameters(mHost->GetFactoryDefaultsGroup()); +} + +wxArrayString VSTEffect::GetFactoryPresets() +{ + wxArrayString progs; + + // Some plugins, like Guitar Rig 5, only report 128 programs while they have hundreds. While + // I was able to come up with a hack in the Guitar Rig case to gather all of the program names + // it would not let me set a program outside of the first 128. + for (int i = 0; i < mAEffect->numPrograms; i++) + { + progs.Add(GetString(effGetProgramNameIndexed, i)); + } + + return progs; +} + +void VSTEffect::ExportPresets() +{ + wxString path; + + // Ask the user for the real name + // + // Passing a valid parent will cause some effects dialogs to malfunction + // upon returning from the FileSelector(). + path = FileSelector(_("Save VST Preset As:"), + FileNames::DataDir(), + wxEmptyString, + wxT("xml"), + wxT("Standard VST bank file (*.fxb)|*.fxb|Standard VST program file (*.fxp)|*.fxp|Audacity VST preset file (*.xml)|*.xml"), + wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER, + NULL); + + // User canceled... + if (path.IsEmpty()) + { + return; + } + + wxFileName fn(path); + wxString ext = fn.GetExt(); + if (ext.CmpNoCase(wxT("fxb")) == 0) + { + SaveFXB(fn); + } + else if (ext.CmpNoCase(wxT("fxp")) == 0) + { + SaveFXP(fn); + } + else if (ext.CmpNoCase(wxT("xml")) == 0) + { + SaveXML(fn); + } + else + { + // This shouldn't happen, but complain anyway + wxMessageBox(_("Unrecognized file extension."), + _("Error Saving VST Presets"), + wxOK | wxCENTRE, + mParent); + + return; + } +} + +// +// Load an "fxb", "fxp" or Audacuty "xml" file +// +// Based on work by Sven Giermann +// +void VSTEffect::ImportPresets() +{ + wxString path; + + // Ask the user for the real name + path = FileSelector(_("Load VST Preset:"), + FileNames::DataDir(), + wxEmptyString, + wxT("xml"), + wxT("VST preset files (*.fxb; *.fxp; *.xml)|*.fxb;*.fxp;*.xml"), + wxFD_OPEN | wxRESIZE_BORDER, + mParent); + + // User canceled... + if (path.IsEmpty()) + { + return; + } + + wxFileName fn(path); + wxString ext = fn.GetExt(); + bool success = false; + if (ext.CmpNoCase(wxT("fxb")) == 0) + { + success = LoadFXB(fn); + } + else if (ext.CmpNoCase(wxT("fxp")) == 0) + { + success = LoadFXP(fn); + } + else if (ext.CmpNoCase(wxT("xml")) == 0) + { + success = LoadXML(fn); + } + else + { + // This shouldn't happen, but complain anyway + wxMessageBox(_("Unrecognized file extension."), + _("Error Loading VST Presets"), + wxOK | wxCENTRE, + mParent); + + return; + } + + if (!success) + { + wxMessageBox(_("Unable to load presets file."), + _("Error Loading VST Presets"), + wxOK | wxCENTRE, + mParent); + + return; + } + + RefreshParameters(); + + return; +} + +void VSTEffect::ShowOptions() +{ + VSTEffectSettingsDialog dlg(mParent, mHost); + if (dlg.ShowModal()) + { + // Reinitialize configuration settings + SetHost(mHost); + } } // ============================================================================ // VSTEffect implementation // ============================================================================ -void VSTEffect::InterfaceClosed() -{ - mDlg = NULL; -} - bool VSTEffect::Load() { vstPluginMain pluginMain; @@ -3829,7 +2419,7 @@ bool VSTEffect::Load() // Save the library reference mModule = lib; } -wxLogDebug(wxT("Loaded")); + #else // Attempt to load it @@ -3940,6 +2530,18 @@ wxLogDebug(wxT("Loaded")); mMidiIns = 0; mMidiOuts = 0; + // Check to see if parameters can be automated. This isn't a gaurantee + // since it could be that the effect simply doesn't support the "Can + mAutomatable = false; + for (int i = 0; i < mAEffect->numParams; i++) + { + if (callDispatcher(effCanBeAutomated, 0, i, NULL, 0.0)) + { + mAutomatable = true; + break; + } + } + // Pretty confident that we're good to go success = true; } @@ -3955,6 +2557,11 @@ wxLogDebug(wxT("Loaded")); void VSTEffect::Unload() { + if (mDialog) + { + CloseUI(); + } + if (mTimer) { mTimer->Stop(); @@ -4148,12 +2755,12 @@ void VSTEffect::PowerOff() void VSTEffect::SizeWindow(int w, int h) { // Queue the event to make the resizes smoother - if (mDlg) + if (mParent) { wxCommandEvent sw(EVT_SIZEWINDOW); sw.SetInt(w); sw.SetExtraLong(h); - mDlg->GetEventHandler()->AddPendingEvent(sw); + mParent->GetEventHandler()->AddPendingEvent(sw); } return; @@ -4161,13 +2768,14 @@ void VSTEffect::SizeWindow(int w, int h) void VSTEffect::UpdateDisplay() { +#if 0 // Tell the dialog to refresh effect information - if (mDlg) + if (mParent) { wxCommandEvent ud(EVT_UPDATEDISPLAY); - mDlg->GetEventHandler()->AddPendingEvent(ud); + mParent->GetEventHandler()->AddPendingEvent(ud); } - +#endif return; } @@ -4404,4 +3012,1258 @@ int VSTEffect::b64decode(wxString in, void *out) return p - (unsigned char *) out; } +void VSTEffect::RemoveHandler() +{ +#if defined(__WXMAC__) + if (mWindowRef) + { + callDispatcher(effEditClose, 0, 0, mWindowRef, 0.0); + mWindowRef = 0; + } + + if (mOverlayEventHandlerRef) + { + ::RemoveEventHandler(mOverlayEventHandlerRef); + mOverlayEventHandlerRef = 0; + } + + if (mOverlayEventHandlerUPP) + { + DisposeEventHandlerUPP(mOverlayEventHandlerUPP); + mOverlayEventHandlerUPP = 0; + } + + if (mWindowEventHandlerRef) + { + ::RemoveEventHandler(mWindowEventHandlerRef); + mWindowEventHandlerRef = 0; + mDialog->MacInstallTopLevelWindowEventHandler(); + } + + if (mWindowEventHandlerUPP) + { + DisposeEventHandlerUPP(mWindowEventHandlerUPP); + mWindowEventHandlerUPP = 0; + } +#elif defined(__WXMSW__) + if (mHwnd) + { + callDispatcher(effEditClose, 0, 0, mHwnd, 0.0); + mHwnd = 0; + } +#else + if (mXwin) + { + callDispatcher(effEditClose, 0, (intptr_t)mXdisp, (void *)mXwin, 0.0); + mXdisp = 0; + mXwin = 0; + } +#endif +} + +void VSTEffect::BuildFancy() +{ + struct + { + short top, left, bottom, right; + } *rect; + + // Turn the power on...some effects need this when the editor is open + PowerOn(); + + // Some effects like to have us get their rect before opening them. + callDispatcher(effEditGetRect, 0, 0, &rect, 0.0); + +#if defined(__WXMAC__) + // Retrieve the current window and the one above it. The window list + // is kept in top-most to bottom-most order, so we'll use that to + // determine if another window was opened above ours. + mWindowRef = (WindowRef) mDialog->MacGetWindowRef(); + mPreviousRef = GetPreviousWindow(mWindowRef); + + // Install the event handler on our window + mWindowEventHandlerUPP = NewEventHandlerUPP(WindowEventHandler); + InstallWindowEventHandler(mWindowRef, + mWindowEventHandlerUPP, + GetEventTypeCount(WindowEventList), + WindowEventList, + this, + &mWindowEventHandlerRef); + + // Find the content view within our window + HIViewRef view; + HIViewFindByID(HIViewGetRoot(mWindowRef), kHIViewWindowContentID, &view); + + // And ask the effect to add it's GUI + callDispatcher(effEditOpen, 0, 0, mWindowRef, 0.0); + + // Get the subview it created + HIViewRef subview = HIViewGetFirstSubview(view); + if (subview == NULL) + { + // Doesn't seem the effect created the subview, so switch + // to the plain dialog. This can happen when an effect + // uses the content view directly. As of this time, we + // will not try to support those and fall back to the + // textual interface. + mGui = false; + RemoveHandler(); + BuildPlain(); + return; + } + +#elif defined(__WXMSW__) + + wxPanel *w = new wxPanel(mParent, wxID_ANY); + mHwnd = w->GetHWND(); + callDispatcher(effEditOpen, 0, 0, mHwnd, 0.0); + +#else + + // Use a panel to host the plugins GUI + wxPanel *w = new wxPanel(mParent); + + // Make sure is has a window + if (!GTK_WIDGET(w->m_wxwindow)->window) + { + gtk_widget_realize(GTK_WIDGET(w->m_wxwindow)); + } + + GdkWindow *gwin = GTK_WIDGET(w->m_wxwindow)->window; + mXdisp = GDK_WINDOW_XDISPLAY(gwin); + mXwin = GDK_WINDOW_XWINDOW(gwin); + + callDispatcher(effEditOpen, 0, (intptr_t)mXdisp, (void *)mXwin, 0.0); + +#endif + + // Get the final bounds of the effect GUI + callDispatcher(effEditGetRect, 0, 0, &rect, 0.0); + + // Build our display now + wxBoxSizer *vs = new wxBoxSizer(wxVERTICAL); + wxBoxSizer *hs = new wxBoxSizer(wxHORIZONTAL); + +#if defined(__WXMAC__) + + // Reserve space for the effect GUI + mContainer = hs->Add(rect->right - rect->left, rect->bottom - rect->top); + +#elif defined(__WXMSW__) + + // Add the effect host window to the layout + mContainer = hs->Add(w, 1, wxCENTER | wxEXPAND); + mContainer->SetMinSize(rect->right - rect->left, rect->bottom - rect->top); + +#else + + // Add the effect host window to the layout + mContainer = hs->Add(w, 1, wxCENTER | wxEXPAND); + mContainer->SetMinSize(rect->right - rect->left, rect->bottom - rect->top); + +#endif + + vs->Add(hs, 0, wxCENTER); + + mParent->SetSizerAndFit(vs); + +#if defined(__WXMAC__) + + // Found out where the reserved space wound up + wxPoint pos = mContainer->GetPosition(); + + // Reposition the subview into the reserved space + HIViewPlaceInSuperviewAt(subview, pos.x, pos.y); + + // Some VST effects do not work unless the default handler is removed since + // it captures many of the events that the plugins need. But, it must be + // done last since proper window sizing will not occur otherwise. + ::RemoveEventHandler((EventHandlerRef) mDialog->MacGetEventHandler()); + +#elif defined(__WXMSW__) +#else +#endif + + NeedEditIdle(true); +} + +void VSTEffect::BuildPlain() +{ + mNames = new wxStaticText *[mAEffect->numParams]; + mSliders = new wxSlider *[mAEffect->numParams]; + mDisplays = new wxStaticText *[mAEffect->numParams]; + mLabels = new wxStaticText *[mAEffect->numParams]; + + wxSizer *paramSizer = new wxStaticBoxSizer(wxVERTICAL, mParent, _("Effect Settings")); + + wxFlexGridSizer *gridSizer = new wxFlexGridSizer(4, 0, 0); + gridSizer->AddGrowableCol(1); + + // Add the duration control for generators + if (GetType() == EffectTypeGenerate) + { + wxControl *item = new wxStaticText(mParent, 0, _("Duration:")); + gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5); + mDuration = new NumericTextCtrl(NumericConverter::TIME, + mParent, + ID_DURATION, + _("hh:mm:ss + milliseconds"), + mHost->GetDuration(), + mSampleRate, + wxDefaultPosition, + wxDefaultSize, + true); + mDuration->SetName(_("Duration")); + mDuration->EnableMenu(); + gridSizer->Add(mDuration, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); + gridSizer->Add(1, 1, 0); + gridSizer->Add(1, 1, 0); + ConnectFocus(mDuration); + } + + // Find the longest parameter name. + int namew = 0; + int w; + int h; + for (int i = 0; i < mAEffect->numParams; i++) + { + wxString text = GetString(effGetParamName, i); + + if (text.Right(1) != wxT(':')) + { + text += wxT(':'); + } + + mParent->GetTextExtent(text, &w, &h); + if (w > namew) + { + namew = w; + } + } + + mParent->GetTextExtent(wxT("HHHHHHHH"), &w, &h); + + for (int i = 0; i < mAEffect->numParams; i++) + { + mNames[i] = new wxStaticText(mParent, + wxID_ANY, + wxEmptyString, + wxDefaultPosition, + wxSize(namew, -1), + wxALIGN_RIGHT | wxST_NO_AUTORESIZE); + gridSizer->Add(mNames[i], 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5); + + mSliders[i] = new wxSlider(mParent, + ID_SLIDERS + i, + 0, + 0, + 1000, + wxDefaultPosition, + wxSize(200, -1)); + gridSizer->Add(mSliders[i], 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxALL, 5); + + mDisplays[i] = new wxStaticText(mParent, + wxID_ANY, + wxEmptyString, + wxDefaultPosition, + wxSize(w, -1), + wxALIGN_RIGHT | wxST_NO_AUTORESIZE); + gridSizer->Add(mDisplays[i], 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5); + + mLabels[i] = new wxStaticText(mParent, + wxID_ANY, + wxEmptyString, + wxDefaultPosition, + wxSize(w, -1), + wxALIGN_LEFT | wxST_NO_AUTORESIZE); + gridSizer->Add(mLabels[i], 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, 5); + } + + paramSizer->Add(gridSizer, 1, wxEXPAND | wxALL, 5); + mParent->SetSizer(paramSizer); + + RefreshParameters(); + + mSliders[0]->SetFocus(); +} + +void VSTEffect::RefreshParameters(int skip) +{ + if (mGui) + { + return; + } + + for (int i = 0; i < mAEffect->numParams; i++) + { + wxString text = GetString(effGetParamName, i); + + text = text.Trim(true).Trim(false); + + wxString name = text; + + if (text.Right(1) != wxT(':')) + { + text += wxT(':'); + } + mNames[i]->SetLabel(text); + + // For some parameters types like on/off, setting the slider value has + // a side effect that causes it to only move when the parameter changes + // from off to on. However, this prevents changing the value using the + // keyboard, so we skip the active slider if any. + if (i != skip) + { + mSliders[i]->SetValue(callGetParameter(i) * 1000); + } + name = text; + + text = GetString(effGetParamDisplay, i); + if (text.IsEmpty()) + { + text.Printf(wxT("%.5g"),callGetParameter(i)); + } + mDisplays[i]->SetLabel(wxString::Format(wxT("%8s"), text.c_str())); + name += wxT(' ') + text; + + text = GetString(effGetParamDisplay, i); + if (!text.IsEmpty()) + { + text.Printf(wxT("%-8s"), GetString(effGetParamLabel, i).c_str()); + mLabels[i]->SetLabel(wxString::Format(wxT("%8s"), text.c_str())); + name += wxT(' ') + text; + } + + mSliders[i]->SetName(name); + } +} + +void VSTEffect::OnSizeWindow(wxCommandEvent & evt) +{ + if (!mContainer) + { + return; + } + + // This really needs some work. We should know anything about the parent... + mContainer->SetMinSize(evt.GetInt(), (int) evt.GetExtraLong()); + mParent->SetMinSize(mContainer->GetMinSize()); + mDialog->Layout(); + mDialog->Fit(); +} + +void VSTEffect::OnSlider(wxCommandEvent & evt) +{ + wxSlider *s = (wxSlider *) evt.GetEventObject(); + int i = s->GetId() - ID_SLIDERS; + + callSetParameter(i, s->GetValue() / 1000.0); + + RefreshParameters(i); +} + +void VSTEffect::ConnectFocus(wxControl *c) +{ + c->GetEventHandler()->Connect(wxEVT_SET_FOCUS, + wxFocusEventHandler(VSTEffectEventHelper::ControlSetFocus)); +} + +void VSTEffect::DisconnectFocus(wxControl *c) +{ + c->GetEventHandler()->Disconnect(wxEVT_SET_FOCUS, + wxFocusEventHandler(VSTEffectEventHelper::ControlSetFocus)); +} + +void VSTEffect::ControlSetFocus(wxFocusEvent & evt) +{ + wxControl *c = (wxControl *) evt.GetEventObject(); + wxScrolledWindow *p = (wxScrolledWindow *) c->GetParent(); + wxRect r = c->GetRect(); + wxRect rv = p->GetRect(); + rv.y = 0; + + evt.Skip(); + + int y; + int yppu; + p->GetScrollPixelsPerUnit(NULL, &yppu); + + if (r.y >= rv.y && r.GetBottom() <= rv.GetBottom()) { + return; + } + + if (r.y < rv.y) { + p->CalcUnscrolledPosition(0, r.y, NULL, &r.y); + y = r.y / yppu; + } + else { + p->CalcUnscrolledPosition(0, r.y, NULL, &r.y); + y = (r.GetBottom() - rv.GetBottom() + yppu) / yppu; + } + + p->Scroll(-1, y); +}; + +bool VSTEffect::LoadFXB(const wxFileName & fn) +{ + bool ret = false; + + // Try to open the file...will be closed automatically when method returns + wxFFile f(fn.GetFullPath(), wxT("rb")); + if (!f.IsOpened()) + { + return false; + } + + // Allocate memory for the contents + unsigned char *data = new unsigned char[f.Length()]; + if (!data) + { + wxMessageBox(_("Unable to allocate memory when loading presets file."), + _("Error Loading VST Presets"), + wxOK | wxCENTRE, + mParent); + return false; + } + unsigned char *bptr = data; + + do + { + // Read in the whole file + ssize_t len = f.Read((void *) bptr, f.Length()); + if (f.Error()) + { + wxMessageBox(_("Unable to read presets file."), + _("Error Loading VST Presets"), + wxOK | wxCENTRE, + mParent); + break; + } + + // Most references to the data are via an "int" array + int32_t *iptr = (int32_t *) bptr; + + // Verify that we have at least enough the header + if (len < 156) + { + break; + } + + // Verify that we probably have a FX file + if (wxINT32_SWAP_ON_LE(iptr[0]) != CCONST('C', 'c', 'n', 'K')) + { + break; + } + + // Ignore the size...sometimes it's there, other times it's zero + + // Get the version and verify + int version = wxINT32_SWAP_ON_LE(iptr[3]); + if (version != 1 && version != 2) + { + break; + } + + // Ensure this program looks to belong to the current plugin + if (wxINT32_SWAP_ON_LE(iptr[4]) != mAEffect->uniqueID) + { + break; + } + + // Get the number of programs + int numProgs = wxINT32_SWAP_ON_LE(iptr[6]); + if (numProgs != mAEffect->numPrograms) + { + break; + } + + // Get the current program index + int curProg = 0; + if (version == 2) + { + curProg = wxINT32_SWAP_ON_LE(iptr[7]); + if (curProg < 0 || curProg >= numProgs) + { + break; + } + } + + // Is it a bank of programs? + if (wxINT32_SWAP_ON_LE(iptr[2]) == CCONST('F', 'x', 'B', 'k')) + { + // Drop the header + bptr += 156; + len -= 156; + + unsigned char *tempPtr = bptr; + ssize_t tempLen = len; + + // Validate all of the programs + for (int i = 0; i < numProgs; i++) + { + if (!LoadFXProgram(&tempPtr, tempLen, i, true)) + { + break; + } + } + + // They look okay, time to start changing things + for (int i = 0; i < numProgs; i++) + { + ret = LoadFXProgram(&bptr, len, i, false); + } + } + // Or maybe a bank chunk? + else if (wxINT32_SWAP_ON_LE(iptr[2]) == CCONST('F', 'B', 'C', 'h')) + { + // Can't load programs chunks if the plugin doesn't support it + if (!(mAEffect->flags & effFlagsProgramChunks)) + { + break; + } + + // Verify that we have enough to grab the chunk size + if (len < 160) + { + break; + } + + // Get the chunk size + int size = wxINT32_SWAP_ON_LE(iptr[39]); + + // We finally know the full length of the program + int proglen = 160 + size; + + // Verify that we have enough for the entire program + if (len < proglen) + { + break; + } + + // Set the entire bank in one shot + callDispatcher(effSetChunk, 0, size, &iptr[40], 0.0); + + // Success + ret = true; + } + // Unrecognizable type + else + { + break; + } + + // Set the active program + if (ret && version == 2) + { + callDispatcher(effSetProgram, 0, curProg, NULL, 0.0); + } + } while (false); + + // Get rid of the data + delete [] data; + + return ret; +} + +bool VSTEffect::LoadFXP(const wxFileName & fn) +{ + bool ret = false; + + // Try to open the file...will be closed automatically when method returns + wxFFile f(fn.GetFullPath(), wxT("rb")); + if (!f.IsOpened()) + { + return false; + } + + // Allocate memory for the contents + unsigned char *data = new unsigned char[f.Length()]; + if (!data) + { + wxMessageBox(_("Unable to allocate memory when loading presets file."), + _("Error Loading VST Presets"), + wxOK | wxCENTRE, + mParent); + return false; + } + unsigned char *bptr = data; + + do + { + // Read in the whole file + ssize_t len = f.Read((void *) bptr, f.Length()); + if (f.Error()) + { + wxMessageBox(_("Unable to read presets file."), + _("Error Loading VST Presets"), + wxOK | wxCENTRE, + mParent); + break; + } + + // Get (or default) currently selected program + int i = 0; //mProgram->GetCurrentSelection(); + if (i < 0) + { + i = 0; // default to first program + } + + // Go verify and set the program + ret = LoadFXProgram(&bptr, len, i, false); + } while (false); + + // Get rid of the data + delete [] data; + + return ret; +} + +bool VSTEffect::LoadFXProgram(unsigned char **bptr, ssize_t & len, int index, bool dryrun) +{ + // Most references to the data are via an "int" array + int32_t *iptr = (int32_t *) *bptr; + + // Verify that we have at least enough for a program without parameters + if (len < 28) + { + return false; + } + + // Verify that we probably have an FX file + if (wxINT32_SWAP_ON_LE(iptr[0]) != CCONST('C', 'c', 'n', 'K')) + { + return false; + } + + // Ignore the size...sometimes it's there, other times it's zero + + // Get the version and verify +#if defined(IS_THIS_AND_FXP_ARTIFICAL_LIMITATION) + int version = wxINT32_SWAP_ON_LE(iptr[3]); + if (version != 1) + { + return false; + } +#endif + + // Ensure this program looks to belong to the current plugin + if (wxINT32_SWAP_ON_LE(iptr[4]) != mAEffect->uniqueID) + { + return false; + } + + // Get the number of parameters + int numParams = wxINT32_SWAP_ON_LE(iptr[6]); + if (numParams != mAEffect->numParams) + { + return false; + } + + // At this point, we have to have enough to include the program name as well + if (len < 56) + { + return false; + } + + // Get the program name + wxString progName(wxString::From8BitData((char *)&iptr[7])); + + // Might be a regular program + if (wxINT32_SWAP_ON_LE(iptr[2]) == CCONST('F', 'x', 'C', 'k')) + { + // We finally know the full length of the program + int proglen = 56 + (numParams * sizeof(float)); + + // Verify that we have enough for all of the parameter values + if (len < proglen) + { + return false; + } + + // Validate all of the parameter values + for (int i = 0; i < numParams; i++) + { + uint32_t ival = wxUINT32_SWAP_ON_LE(iptr[14 + i]); + float val = *((float *) &ival); + if (val < 0.0 || val > 1.0) + { + return false; + } + } + + // They look okay...time to start changing things + if (!dryrun) + { + for (int i = 0; i < numParams; i++) + { + wxUint32 val = wxUINT32_SWAP_ON_LE(iptr[14 + i]); + callSetParameter(i, *((float *) &val)); + } + } + + // Update in case we're loading an "FxBk" format bank file + *bptr += proglen; + len -= proglen; + } + // Maybe we have a program chunk + else if (wxINT32_SWAP_ON_LE(iptr[2]) == CCONST('F', 'P', 'C', 'h')) + { + // Can't load programs chunks if the plugin doesn't support it + if (!(mAEffect->flags & effFlagsProgramChunks)) + { + return false; + } + + // Verify that we have enough to grab the chunk size + if (len < 60) + { + return false; + } + + // Get the chunk size + int size = wxINT32_SWAP_ON_LE(iptr[14]); + + // We finally know the full length of the program + int proglen = 60 + size; + + // Verify that we have enough for the entire program + if (len < proglen) + { + return false; + } + + // Set the entire program in one shot + if (!dryrun) + { + callDispatcher(effSetChunk, 1, size, &iptr[15], 0.0); + } + + // Update in case we're loading an "FxBk" format bank file + *bptr += proglen; + len -= proglen; + } + else + { + // Unknown type + return false; + } + + if (!dryrun) + { + SetString(effSetProgramName, wxString(progName), index); + } + + return true; +} + +bool VSTEffect::LoadXML(const wxFileName & fn) +{ + // default to read as XML file + // Load the program + XMLFileReader reader; + if (!reader.Parse(this, fn.GetFullPath())) + { + // Inform user of load failure + wxMessageBox(reader.GetErrorStr(), + _("Error Loading VST Presets"), + wxOK | wxCENTRE, + mParent); + return false; + } + + return true; +} + +void VSTEffect::SaveFXB(const wxFileName & fn) +{ + // Create/Open the file + wxFFile f(fn.GetFullPath(), wxT("wb")); + if (!f.IsOpened()) + { + wxMessageBox(wxString::Format(_("Could not open file: \"%s\""), fn.GetFullPath().c_str()), + _("Error Saving VST Presets"), + wxOK | wxCENTRE, + mParent); + return; + } + + wxMemoryBuffer buf; + wxInt32 subType; + void *chunkPtr; + int chunkSize; + int dataSize = 148; + wxInt32 tab[8]; + int curProg = 0 ; //mProgram->GetCurrentSelection(); + + if (mAEffect->flags & effFlagsProgramChunks) + { + subType = CCONST('F', 'B', 'C', 'h'); + + chunkSize = callDispatcher(effGetChunk, 0, 0, &chunkPtr, 0.0); + dataSize += 4 + chunkSize; + } + else + { + subType = CCONST('F', 'x', 'B', 'k'); + + for (int i = 0; i < mAEffect->numPrograms; i++) + { + SaveFXProgram(buf, i); + } + + dataSize += buf.GetDataLen(); + } + + tab[0] = wxINT32_SWAP_ON_LE(CCONST('C', 'c', 'n', 'K')); + tab[1] = wxINT32_SWAP_ON_LE(dataSize); + tab[2] = wxINT32_SWAP_ON_LE(subType); + tab[3] = wxINT32_SWAP_ON_LE(curProg >= 0 ? 2 : 1); + tab[4] = wxINT32_SWAP_ON_LE(mAEffect->uniqueID); + tab[5] = wxINT32_SWAP_ON_LE(mAEffect->version); + tab[6] = wxINT32_SWAP_ON_LE(mAEffect->numPrograms); + tab[7] = wxINT32_SWAP_ON_LE(curProg >= 0 ? curProg : 0); + + f.Write(tab, sizeof(tab)); + if (!f.Error()) + { + char padding[124]; + memset(padding, 0, sizeof(padding)); + f.Write(padding, sizeof(padding)); + + if (!f.Error()) + { + if (mAEffect->flags & effFlagsProgramChunks) + { + wxInt32 size = wxINT32_SWAP_ON_LE(chunkSize); + f.Write(&size, sizeof(size)); + f.Write(chunkPtr, chunkSize); + } + else + { + f.Write(buf.GetData(), buf.GetDataLen()); + } + } + } + + if (f.Error()) + { + wxMessageBox(wxString::Format(_("Error writing to file: \"%s\""), fn.GetFullPath().c_str()), + _("Error Saving VST Presets"), + wxOK | wxCENTRE, + mParent); + } + + f.Close(); + + return; +} + +void VSTEffect::SaveFXP(const wxFileName & fn) +{ + // Create/Open the file + wxFFile f(fn.GetFullPath(), wxT("wb")); + if (!f.IsOpened()) + { + wxMessageBox(wxString::Format(_("Could not open file: \"%s\""), fn.GetFullPath().c_str()), + _("Error Saving VST Presets"), + wxOK | wxCENTRE, + mParent); + return; + } + + wxMemoryBuffer buf; + + int ndx = callDispatcher(effGetProgram, 0, 0, NULL, 0.0); + SaveFXProgram(buf, ndx); + + f.Write(buf.GetData(), buf.GetDataLen()); + if (f.Error()) + { + wxMessageBox(wxString::Format(_("Error writing to file: \"%s\""), fn.GetFullPath().c_str()), + _("Error Saving VST Presets"), + wxOK | wxCENTRE, + mParent); + } + + f.Close(); + + return; +} + +void VSTEffect::SaveFXProgram(wxMemoryBuffer & buf, int index) +{ + wxInt32 subType; + void *chunkPtr; + int chunkSize; + int dataSize = 48; + char progName[28]; + wxInt32 tab[7]; + + callDispatcher(effGetProgramNameIndexed, index, 0, &progName, 0.0); + progName[27] = '\0'; + chunkSize = strlen(progName); + memset(&progName[chunkSize], 0, sizeof(progName) - chunkSize); + + if (mAEffect->flags & effFlagsProgramChunks) + { + subType = CCONST('F', 'P', 'C', 'h'); + + chunkSize = callDispatcher(effGetChunk, 1, 0, &chunkPtr, 0.0); + dataSize += 4 + chunkSize; + } + else + { + subType = CCONST('F', 'x', 'C', 'k'); + + dataSize += (mAEffect->numParams << 2); + } + + tab[0] = wxINT32_SWAP_ON_LE(CCONST('C', 'c', 'n', 'K')); + tab[1] = wxINT32_SWAP_ON_LE(dataSize); + tab[2] = wxINT32_SWAP_ON_LE(subType); + tab[3] = wxINT32_SWAP_ON_LE(1); + tab[4] = wxINT32_SWAP_ON_LE(mAEffect->uniqueID); + tab[5] = wxINT32_SWAP_ON_LE(mAEffect->version); + tab[6] = wxINT32_SWAP_ON_LE(mAEffect->numParams); + + buf.AppendData(tab, sizeof(tab)); + buf.AppendData(progName, sizeof(progName)); + + if (mAEffect->flags & effFlagsProgramChunks) + { + wxInt32 size = wxINT32_SWAP_ON_LE(chunkSize); + buf.AppendData(&size, sizeof(size)); + buf.AppendData(chunkPtr, chunkSize); + } + else + { + for (int i = 0; i < mAEffect->numParams; i++) + { + float val = callGetParameter(i); + wxUint32 ival = wxUINT16_SWAP_ON_LE(*((wxUint32 *) &val)); + buf.AppendData(&ival, sizeof(ival)); + } + } + + return; +} + +void VSTEffect::SaveXML(const wxFileName & fn) +{ + XMLFileWriter xmlFile; + + // Create/Open the file + xmlFile.Open(fn.GetFullPath(), wxT("wb")); + + xmlFile.StartTag(wxT("vstprogrampersistence")); + xmlFile.WriteAttr(wxT("version"), wxT("1")); + + xmlFile.StartTag(wxT("effect")); + xmlFile.WriteAttr(wxT("name"), GetName()); + xmlFile.WriteAttr(wxT("version"), callDispatcher(effGetVendorVersion, 0, 0, NULL, 0.0)); + + xmlFile.StartTag(wxT("program")); + xmlFile.WriteAttr(wxT("name"), wxEmptyString); //mProgram->GetValue()); + + int clen = 0; + if (mAEffect->flags & effFlagsProgramChunks) + { + void *chunk = NULL; + + clen = (int) callDispatcher(effGetChunk, 1, 0, &chunk, 0.0); + if (clen != 0) + { + xmlFile.StartTag(wxT("chunk")); + xmlFile.WriteSubTree(VSTEffect::b64encode(chunk, clen) + wxT('\n')); + xmlFile.EndTag(wxT("chunk")); + } + } + + if (clen == 0) + { + for (int i = 0; i < mAEffect->numParams; i++) + { + xmlFile.StartTag(wxT("param")); + + xmlFile.WriteAttr(wxT("index"), i); + xmlFile.WriteAttr(wxT("name"), + GetString(effGetParamName, i)); + xmlFile.WriteAttr(wxT("value"), + wxString::Format(wxT("%f"), + callGetParameter(i))); + + xmlFile.EndTag(wxT("param")); + } + } + + xmlFile.EndTag(wxT("program")); + + xmlFile.EndTag(wxT("effect")); + + xmlFile.EndTag(wxT("vstprogrampersistence")); + + // Close the file + xmlFile.Close(); + + return; +} + +bool VSTEffect::HandleXMLTag(const wxChar *tag, const wxChar **attrs) +{ + if (wxStrcmp(tag, wxT("vstprogrampersistence")) == 0) + { + while (*attrs) + { + const wxChar *attr = *attrs++; + const wxChar *value = *attrs++; + + if (!value) + { + break; + } + + const wxString strValue = value; + + if (wxStrcmp(attr, wxT("version")) == 0) + { + if (!XMLValueChecker::IsGoodInt(strValue)) + { + return false; + } + // Nothing to do with it for now + } + else + { + return false; + } + } + + return true; + } + + if (wxStrcmp(tag, wxT("effect")) == 0) + { + while (*attrs) + { + const wxChar *attr = *attrs++; + const wxChar *value = *attrs++; + + if (!value) + { + break; + } + + const wxString strValue = value; + + if (wxStrcmp(attr, wxT("name")) == 0) + { + if (!XMLValueChecker::IsGoodString(strValue)) + { + return false; + } + + if (value != GetName()) + { + wxString msg; + msg.Printf(_("This parameter file was saved from %s. Continue?"), value); + int result = wxMessageBox(msg, wxT("Confirm"), wxYES_NO, mParent); + if (result == wxNO) + { + return false; + } + } + } + else if (wxStrcmp(attr, wxT("version")) == 0) + { + if (!XMLValueChecker::IsGoodInt(strValue)) + { + return false; + } + // Nothing to do with it for now + } + else + { + return false; + } + } + + return true; + } + + if (wxStrcmp(tag, wxT("program")) == 0) + { + while (*attrs) + { + const wxChar *attr = *attrs++; + const wxChar *value = *attrs++; + + if (!value) + { + break; + } + + const wxString strValue = value; + + if (wxStrcmp(attr, wxT("name")) == 0) + { + if (!XMLValueChecker::IsGoodString(strValue)) + { + return false; + } + + if (strValue.length() > 24) + { + return false; + } + + int ndx = 0; //mProgram->GetCurrentSelection(); + if (ndx == wxNOT_FOUND) + { + ndx = 0; + } + + SetString(effSetProgramName, strValue, ndx); + } + else + { + return false; + } + } + + mInChunk = false; + + return true; + } + + if (wxStrcmp(tag, wxT("param")) == 0) + { + long ndx = -1; + double val = -1.0; + while (*attrs) + { + const wxChar *attr = *attrs++; + const wxChar *value = *attrs++; + + if (!value) + { + break; + } + + const wxString strValue = value; + + if (wxStrcmp(attr, wxT("index")) == 0) + { + if (!XMLValueChecker::IsGoodInt(strValue) || !strValue.ToLong(&ndx)) + { + return false; + } + + if (ndx < 0 || ndx >= mAEffect->numParams) + { + // Could be a different version of the effect...probably should + // tell the user + return false; + } + } + else if (wxStrcmp(attr, wxT("name")) == 0) + { + if (!XMLValueChecker::IsGoodString(strValue)) + { + return false; + } + // Nothing to do with it for now + } + else if (wxStrcmp(attr, wxT("value")) == 0) + { + if (!XMLValueChecker::IsGoodInt(strValue) || + !Internat::CompatibleToDouble(strValue, &val)) + { + return false; + } + + if (val < 0.0 || val > 1.0) + { + return false; + } + } + } + + if (ndx == -1 || val == -1.0) + { + return false; + } + + callSetParameter(ndx, val); + + return true; + } + + if (wxStrcmp(tag, wxT("chunk")) == 0) + { + mInChunk = true; + return true; + } + + return false; +} + +void VSTEffect::HandleXMLEndTag(const wxChar *tag) +{ + if (wxStrcmp(tag, wxT("chunk")) == 0) + { + if (mChunk.length()) + { + char *buf = new char[mChunk.length() / 4 * 3]; + + int len = VSTEffect::b64decode(mChunk, buf); + if (len) + { + callDispatcher(effSetChunk, 1, len, buf, 0.0); + } + + delete [] buf; + mChunk.clear(); + } + mInChunk = false; + } +} + +void VSTEffect::HandleXMLContent(const wxString & content) +{ + if (mInChunk) + { + mChunk += wxString(content).Trim(true).Trim(false); + } +} + +XMLTagHandler *VSTEffect::HandleXMLChild(const wxChar *tag) +{ + if (wxStrcmp(tag, wxT("vstprogrampersistence")) == 0) + { + return this; + } + + if (wxStrcmp(tag, wxT("effect")) == 0) + { + return this; + } + + if (wxStrcmp(tag, wxT("program")) == 0) + { + return this; + } + + if (wxStrcmp(tag, wxT("param")) == 0) + { + return this; + } + + if (wxStrcmp(tag, wxT("chunk")) == 0) + { + return this; + } + + return NULL; +} + #endif // USE_VST diff --git a/src/effects/VST/VSTEffect.h b/src/effects/VST/VSTEffect.h index 769b84be4..ebd4c4482 100644 --- a/src/effects/VST/VSTEffect.h +++ b/src/effects/VST/VSTEffect.h @@ -10,11 +10,13 @@ #if USE_VST +#include + #include "audacity/EffectInterface.h" #include "audacity/ModuleInterface.h" #include "audacity/PluginInterface.h" -#include +#include "../../widgets/NumericTextCtrl.h" #include "aeffectx.h" @@ -48,15 +50,30 @@ class VSTEffectTimer; class VSTEffectDialog; class VSTEffect; +/////////////////////////////////////////////////////////////////////////////// +// +// VSTEffect +// +/////////////////////////////////////////////////////////////////////////////// + WX_DEFINE_ARRAY_PTR(VSTEffect *, VSTEffectArray); -class VSTEffect : public EffectClientInterface +DECLARE_LOCAL_EVENT_TYPE(EVT_SIZEWINDOW, -1); +DECLARE_LOCAL_EVENT_TYPE(EVT_UPDATEDISPLAY, -1); + +class VSTEffectEventHelper; + +class VSTEffect : public EffectClientInterface, + public EffectUIClientInterface, + public XMLTagHandler + { public: VSTEffect(const wxString & path, VSTEffect *master = NULL); virtual ~VSTEffect(); // IdentInterface implementation + virtual PluginID GetID(); virtual wxString GetPath(); virtual wxString GetName(); @@ -65,17 +82,18 @@ class VSTEffect : public EffectClientInterface virtual wxString GetDescription(); // EffectIdentInterface implementation + virtual EffectType GetType(); virtual wxString GetFamily(); virtual bool IsInteractive(); virtual bool IsDefault(); virtual bool IsLegacy(); - virtual bool IsRealtimeCapable(); + virtual bool SupportsRealtime(); + virtual bool SupportsAutomation(); // EffectClientInterface implementation - virtual void SetHost(EffectHostInterface *host); - virtual bool Startup(); - virtual bool Shutdown(); + + virtual bool SetHost(EffectHostInterface *host); virtual int GetAudioInCount(); virtual int GetAudioOutCount(); @@ -104,7 +122,30 @@ class VSTEffect : public EffectClientInterface float **outbuf, sampleCount numSamples); - virtual bool ShowInterface(void *parent); + virtual bool ShowInterface(wxWindow *parent, bool forceModal = false); + + virtual bool GetAutomationParameters(EffectAutomationParameters & parms); + virtual bool SetAutomationParameters(EffectAutomationParameters & parms); + + // EffectUIClientInterface implementation + + virtual void SetUIHost(EffectUIHostInterface *host); + virtual bool PopulateUI(wxWindow *parent); + virtual bool ValidateUI(); + virtual bool HideUI(); + virtual bool CloseUI(); + + virtual void LoadUserPreset(const wxString & name); + virtual void SaveUserPreset(const wxString & name); + + virtual void LoadFactoryPreset(int id); + virtual void LoadFactoryDefaults(); + + virtual wxArrayString GetFactoryPresets(); + + virtual void ExportPresets(); + virtual void ImportPresets(); + virtual void ShowOptions(); // VSTEffect implementation @@ -135,6 +176,52 @@ private: int GetChannelCount(); void SetChannelCount(int numChannels); + // UI + void OnSlider(wxCommandEvent & evt); + void ConnectFocus(wxControl *c); + void DisconnectFocus(wxControl *c); + void ControlSetFocus(wxFocusEvent & evt); + + void OnSizeWindow(wxCommandEvent & evt); + void OnUpdateDisplay(wxCommandEvent & evt); + + void RemoveHandler(); + + void OnProgram(wxCommandEvent & evt); + void OnProgramText(wxCommandEvent & evt); + void OnLoad(wxCommandEvent & evt); + void OnSave(wxCommandEvent & evt); + void OnSettings(wxCommandEvent & evt); + + + void OnApply(wxCommandEvent & evt); + void OnOk(wxCommandEvent & evt); + void OnCancel(wxCommandEvent & evt); + void OnPreview(wxCommandEvent & evt); + void OnDefaults(wxCommandEvent & evt); + void OnClose(wxCloseEvent & evt); + + + void BuildPlain(); + void BuildFancy(); + wxSizer *BuildProgramBar(); + void RefreshParameters(int skip = -1); + + // Program/Bank loading/saving + bool LoadFXB(const wxFileName & fn); + bool LoadFXP(const wxFileName & fn); + bool LoadXML(const wxFileName & fn); + bool LoadFXProgram(unsigned char **bptr, ssize_t & len, int index, bool dryrun); + void SaveFXB(const wxFileName & fn); + void SaveFXP(const wxFileName & fn); + void SaveXML(const wxFileName & fn); + void SaveFXProgram(wxMemoryBuffer & buf, int index); + + virtual bool HandleXMLTag(const wxChar *tag, const wxChar **attrs); + virtual void HandleXMLEndTag(const wxChar *tag); + virtual void HandleXMLContent(const wxString & content); + virtual XMLTagHandler *HandleXMLChild(const wxChar *tag); + // Utility methods VstTimeInfo *GetTimeInfo(); @@ -148,7 +235,6 @@ private: void Automate(int index, float value); void PowerOn(); void PowerOff(); - void InterfaceClosed(); int GetString(wxString & outstr, int opcode, int index = 0); wxString GetString(int opcode, int index = 0); @@ -170,6 +256,7 @@ private: int mAudioOuts; int mMidiIns; int mMidiOuts; + bool mAutomatable; float mSampleRate; sampleCount mUserBlockSize; wxString mName; @@ -187,8 +274,6 @@ private: void *mModule; AEffect *mAEffect; - VSTEffectDialog *mDlg; - VstTimeInfo mTimeInfo; bool mUseBufferDelay; @@ -215,11 +300,82 @@ private: float **mMasterOut; int mMasterOutLen; - friend class VSTEffectDialog; + // UI + wxDialog *mDialog; + wxWindow *mParent; + EffectUIHostInterface *mUIHost; + VSTEffectEventHelper *mEventHelper; + wxSizerItem *mContainer; + bool mGui; + + NumericTextCtrl *mDuration; + wxStaticText **mNames; + wxSlider **mSliders; + wxStaticText **mDisplays; + wxStaticText **mLabels; + + bool mInChunk; + wxString mChunk; + +#if defined(__WXMAC__) + static pascal OSStatus OverlayEventHandler(EventHandlerCallRef handler, EventRef event, void *data); + OSStatus OnOverlayEvent(EventHandlerCallRef handler, EventRef event); + static pascal OSStatus WindowEventHandler(EventHandlerCallRef handler, EventRef event, void *data); + OSStatus OnWindowEvent(EventHandlerCallRef handler, EventRef event); + + WindowRef mOverlayRef; + EventHandlerUPP mOverlayEventHandlerUPP; + EventHandlerRef mOverlayEventHandlerRef; + + WindowRef mWindowRef; + WindowRef mPreviousRef; + EventHandlerUPP mWindowEventHandlerUPP; + EventHandlerRef mWindowEventHandlerRef; + +#elif defined(__WXMSW__) + + HANDLE mHwnd; + +#else + + Display *mXdisp; + Window mXwin; + +#endif + + friend class VSTEffectEventHelper; friend class VSTEffectsModule; }; -void RegisterVSTEffects(); +/////////////////////////////////////////////////////////////////////////////// +// +// VSTEffectEventHelper +// +/////////////////////////////////////////////////////////////////////////////// + +class VSTEffectEventHelper : public wxEvtHandler +{ +public: + VSTEffectEventHelper(VSTEffect *effect); + virtual ~VSTEffectEventHelper(); + + // VSTEffectEventHelper implementation + + void OnSlider(wxCommandEvent & evt); + void ControlSetFocus(wxFocusEvent & evt); + void OnSizeWindow(wxCommandEvent & evt); + +private: + VSTEffect *mEffect; + + DECLARE_EVENT_TABLE(); +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// VSTEffectsModule +// +/////////////////////////////////////////////////////////////////////////////// class VSTEffectsModule : public ModuleInterface { @@ -245,7 +401,8 @@ public: virtual wxArrayString FindPlugins(PluginManagerInterface & pm); virtual bool RegisterPlugin(PluginManagerInterface & pm, const wxString & path); - virtual void *CreateInstance(const PluginID & ID, const wxString & path); + virtual IdentInterface *CreateInstance(const PluginID & ID, const wxString & path); + virtual void DeleteInstance(IdentInterface *instance); // VSTEffectModule implementation diff --git a/src/effects/ladspa/LadspaEffect.cpp b/src/effects/ladspa/LadspaEffect.cpp index ee5da5413..66e385add 100644 --- a/src/effects/ladspa/LadspaEffect.cpp +++ b/src/effects/ladspa/LadspaEffect.cpp @@ -26,12 +26,15 @@ effects from this one class. #include "ladspa.h" +#include + #include #include #include #include #include #include +#include #include #include #include @@ -43,12 +46,11 @@ effects from this one class. #include #include -#include "../Effect.h" // Audacity Effect base class #include "LadspaEffect.h" // This class's header file #include "../../Internat.h" +#include "../../widgets/valnum.h" // ============================================================================ -// // Module registration entry point // // This is the symbol that Audacity looks for when the module is built as a @@ -56,7 +58,6 @@ effects from this one class. // // 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) { @@ -65,17 +66,16 @@ DECLARE_MODULE_ENTRY(AudacityModule) } // ============================================================================ -// // Register this as a builtin module -// // ============================================================================ DECLARE_BUILTIN_MODULE(LadspaBuiltin); -// ============================================================================ +/////////////////////////////////////////////////////////////////////////////// // // LadspaEffectsModule // -// ============================================================================ +/////////////////////////////////////////////////////////////////////////////// + LadspaEffectsModule::LadspaEffectsModule(ModuleManagerInterface *moduleManager, const wxString *path) { @@ -264,27 +264,29 @@ wxArrayString LadspaEffectsModule::FindPlugins(PluginManagerInterface & pm) } #if defined(__WXMAC__) +#define LADSPAPATH wxT("/Library/Audio/Plug-Ins/LADSPA") - pathList.Add(wxT("~/Library/Audio/Plug-Ins/LADSPA")); - pathList.Add(wxT("/Library/Audio/Plug-Ins/LADSPA")); + // Look in ~/Library/Audio/Plug-Ins/LADSPA and /Library/Audio/Plug-Ins/LADSPA + pathList.Add(wxGetHomeDir() + wxFILE_SEP_PATH + LADSPAPATH); + pathList.Add(LADSPAPATH); // Recursively scan for all shared objects - pm.FindFilesInPathList(wxT("*.so"), pathList, files); + pm.FindFilesInPathList(wxT("*.so"), pathList, files, true); #elif defined(__WXMSW__) // Recursively scan for all DLLs - pm.FindFilesInPathList(wxT("*.dll"), pathList, files); + pm.FindFilesInPathList(wxT("*.dll"), pathList, files, true); #else - pathList.Add(wxT("~/.ladspa")); + pathList.Add(wxGetHomeDir() + wxFILE_SEP_PATH + wxT(".ladspa")); pathList.Add(wxT("/usr/local/lib/ladspa")); pathList.Add(wxT("/usr/lib/ladspa")); pathList.Add(wxT(LIBDIR) wxT("/ladspa")); // Recursively scan for all shared objects - pm.FindFilesInPathList(wxT("*.so"), pathList, files); + pm.FindFilesInPathList(wxT("*.so"), pathList, files, true); #endif @@ -315,7 +317,6 @@ bool LadspaEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxSt wxLogNull logNo; mainFn = (LADSPA_Descriptor_Function) lib.GetSymbol(wxT("ladspa_descriptor")); - if (mainFn) { const LADSPA_Descriptor *data; @@ -329,9 +330,8 @@ bool LadspaEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxSt categories.insert(iter->second); #endif LadspaEffect effect(path, index); - if (effect.Startup()) { + if (effect.SetHost(NULL)) { pm.RegisterEffectPlugin(this, &effect); - effect.Shutdown(); } } } @@ -346,7 +346,8 @@ bool LadspaEffectsModule::RegisterPlugin(PluginManagerInterface & pm, const wxSt return index > 0; } -void *LadspaEffectsModule::CreateInstance(const PluginID & ID, const wxString & path) +IdentInterface *LadspaEffectsModule::CreateInstance(const PluginID & ID, + const wxString & path) { // For us, the ID is two words. // 1) The Ladspa descriptor index @@ -357,6 +358,74 @@ void *LadspaEffectsModule::CreateInstance(const PluginID & ID, const wxString & return new LadspaEffect(path, (int) index); } +void LadspaEffectsModule::DeleteInstance(IdentInterface *instance) +{ + LadspaEffect *effect = dynamic_cast(instance); + if (effect) + { + delete effect; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// +// LadspaEffectEventHelper +// +/////////////////////////////////////////////////////////////////////////////// + +enum +{ + ID_DURATION = 20000, + ID_TOGGLES = 21000, + ID_SLIDERS = 22000, + ID_TEXTS = 23000, +}; + +BEGIN_EVENT_TABLE(LadspaEffectEventHelper, wxEvtHandler) + EVT_COMMAND_RANGE(ID_TOGGLES, ID_TOGGLES + 999, wxEVT_COMMAND_CHECKBOX_CLICKED, LadspaEffectEventHelper::OnCheckBox) + EVT_COMMAND_RANGE(ID_SLIDERS, ID_SLIDERS + 999, wxEVT_COMMAND_SLIDER_UPDATED, LadspaEffectEventHelper::OnSlider) + EVT_COMMAND_RANGE(ID_TEXTS, ID_TEXTS + 999, wxEVT_COMMAND_TEXT_UPDATED, LadspaEffectEventHelper::OnTextCtrl) +END_EVENT_TABLE() + +LadspaEffectEventHelper::LadspaEffectEventHelper(LadspaEffect *effect) +{ + mEffect = effect; +} + +LadspaEffectEventHelper::~LadspaEffectEventHelper() +{ +} + +// ============================================================================ +// LadspaEffectEventHelper implementation +// ============================================================================ + +void LadspaEffectEventHelper::OnCheckBox(wxCommandEvent & evt) +{ + mEffect->OnCheckBox(evt); +} + +void LadspaEffectEventHelper::OnSlider(wxCommandEvent & evt) +{ + mEffect->OnSlider(evt); +} + +void LadspaEffectEventHelper::OnTextCtrl(wxCommandEvent & evt) +{ + mEffect->OnTextCtrl(evt); +} + +void LadspaEffectEventHelper::ControlSetFocus(wxFocusEvent & evt) +{ + mEffect->ControlSetFocus(evt); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// LadspaEffect +// +/////////////////////////////////////////////////////////////////////////////// + LadspaEffect::LadspaEffect(const wxString & path, int index) { mPath = path; @@ -367,9 +436,12 @@ LadspaEffect::LadspaEffect(const wxString & path, int index) mMaster = NULL; mReady = false; + mInteractive = false; + mAudioIns = 0; mAudioOuts = 0; mNumInputControls = 0; + mNumOutputControls = 0; mSampleRate = 44100; mInputPorts = NULL; @@ -379,7 +451,12 @@ LadspaEffect::LadspaEffect(const wxString & path, int index) mLatencyPort = -1; - mDlg = NULL; + mEventHelper = NULL; + mDialog = NULL; + mSliders = NULL; + mFields = NULL; + mLabels = NULL; + mToggles = NULL; } LadspaEffect::~LadspaEffect() @@ -403,11 +480,32 @@ LadspaEffect::~LadspaEffect() { delete [] mOutputControls; } + + if (mToggles) + { + delete [] mToggles; + } + + if (mSliders) + { + delete [] mSliders; + } + + if (mFields) + { + delete [] mFields; + } + + if (mLabels) + { + delete [] mLabels; + } } -// +// ============================================================================ // IdentInterface implementation -// +// ============================================================================ + wxString LadspaEffect::GetID() { return wxString::Format(wxT("%d %s"), mIndex, mPath.c_str()); @@ -435,15 +533,13 @@ wxString LadspaEffect::GetVersion() wxString LadspaEffect::GetDescription() { - return _("Audio In: ") + - wxString::Format(wxT("%d"), mAudioIns) + - _(", Audio Out: ") + - wxString::Format(wxT("%d"), mAudioOuts); + return LAT1CTOWX(mData->Copyright); } -// +// ============================================================================ // EffectIdentInterface implementation -// +// ============================================================================ + EffectType LadspaEffect::GetType() { if (mAudioIns == 0 && mAudioOuts == 0) @@ -484,21 +580,24 @@ bool LadspaEffect::IsLegacy() return false; } -bool LadspaEffect::IsRealtimeCapable() +bool LadspaEffect::SupportsRealtime() { return GetType() == EffectTypeProcess; } -// -// EffectClientInterface Implementation -// -void LadspaEffect::SetHost(EffectHostInterface *host) +bool LadspaEffect::SupportsAutomation() { - mHost = host; + return mNumInputControls > 0; } -bool LadspaEffect::Startup() +// ============================================================================ +// EffectClientInterface Implementation +// ============================================================================ + +bool LadspaEffect::SetHost(EffectHostInterface *host) { + mHost = host; + if (!Load()) { return false; @@ -512,6 +611,7 @@ bool LadspaEffect::Startup() for (unsigned long p = 0; p < mData->PortCount; p++) { LADSPA_PortDescriptor d = mData->PortDescriptors[p]; + // Collect the audio ports if (LADSPA_IS_PORT_AUDIO(d)) { @@ -529,47 +629,71 @@ bool LadspaEffect::Startup() { mInteractive = true; - float val = float(1.0); LADSPA_PortRangeHint hint = mData->PortRangeHints[p]; + float val = float(1.0); + float lower = hint.LowerBound; + float upper = hint.UpperBound; - if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor) && val < hint.LowerBound) + if (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor)) { - val = hint.LowerBound; + lower *= mSampleRate; + upper *= mSampleRate; } - if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor) && val > hint.UpperBound) + if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor) && val < lower) { - val = hint.UpperBound; + val = lower; + } + + if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor) && val > upper) + { + val = upper; } if (LADSPA_IS_HINT_DEFAULT_MINIMUM(hint.HintDescriptor)) { - val = hint.LowerBound; - } - - if (LADSPA_IS_HINT_DEFAULT_LOW(hint.HintDescriptor)) - { - val = hint.LowerBound * 0.75f + hint.UpperBound * 0.25f; - } - - if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hint.HintDescriptor)) - { - val = hint.LowerBound * 0.5f + hint.UpperBound * 0.5f; - } - - if (LADSPA_IS_HINT_DEFAULT_HIGH(hint.HintDescriptor)) - { - val = hint.LowerBound * 0.25f + hint.UpperBound * 0.75f; + val = lower; } if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hint.HintDescriptor)) { - val = hint.UpperBound; + val = upper; } - if (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor)) + if (LADSPA_IS_HINT_DEFAULT_LOW(hint.HintDescriptor)) { - val *= mSampleRate; + if (LADSPA_IS_HINT_LOGARITHMIC(hint.HintDescriptor)) + { + val = exp(log(lower)) * 0.75f + log(upper) * 0.25f; + } + else + { + val = lower * 0.75f + upper * 0.25f; + } + } + + if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hint.HintDescriptor)) + { + if (LADSPA_IS_HINT_LOGARITHMIC(hint.HintDescriptor)) + { + val = exp(log(lower)) * 0.5f + log(upper) * 0.5f; + } + else + { + val = lower * 0.5f + upper * 0.5f; + } + } + + if (LADSPA_IS_HINT_DEFAULT_HIGH(hint.HintDescriptor)) + { + if (LADSPA_IS_HINT_LOGARITHMIC(hint.HintDescriptor)) + { + val = exp(log(lower)) * 0.25f + log(upper) * 0.75f; + } + else + { + val = lower * 0.25f + upper * 0.75f; + } } if (LADSPA_IS_HINT_DEFAULT_0(hint.HintDescriptor)) @@ -595,14 +719,18 @@ bool LadspaEffect::Startup() mNumInputControls++; mInputControls[p] = val; } - // Ladspa effects have a convention of providing latency on an output - // control port whose name is "latency". else if (LADSPA_IS_PORT_CONTROL(d) && LADSPA_IS_PORT_OUTPUT(d)) { + mInteractive = true; + + mNumOutputControls++; + mOutputControls[p] = 0.0; + + // Ladspa effects have a convention of providing latency on an output + // control port whose name is "latency". if (strcmp(mData->PortNames[p], "latency") == 0) { mLatencyPort = p; - mOutputControls[p] = 0; } } } @@ -627,35 +755,6 @@ bool LadspaEffect::Startup() return true; } -bool LadspaEffect::Shutdown() -{ - if (mInputPorts) - { - delete [] mInputPorts; - mInputPorts = NULL; - } - - if (mOutputPorts) - { - delete [] mOutputPorts; - mOutputPorts = NULL; - } - - if (mInputControls) - { - delete [] mInputControls; - mInputControls = NULL; - } - - if (mOutputControls) - { - delete [] mOutputControls; - mOutputControls = NULL; - } - - return true; -} - int LadspaEffect::GetAudioInCount() { return mAudioIns; @@ -764,6 +863,8 @@ sampleCount LadspaEffect::ProcessBlock(float **inbuf, float **outbuf, sampleCoun mData->run(mMaster, size); + RefreshControls(true); + return size; } @@ -832,47 +933,405 @@ bool LadspaEffect::RealtimeAddProcessor(int numChannels, float sampleRate) return true; } -bool LadspaEffect::ShowInterface(void *parent) +bool LadspaEffect::ShowInterface(wxWindow *parent, bool forceModal) { - if (mNumInputControls == 0) { + if (mDialog) + { + mDialog->Close(true); return false; } - double length = 0; - - if (!IsRealtimeCapable()) + mDialog = mHost->CreateUI(parent, this); + if (!mDialog) { - length = mHost->GetDuration(); + return false; } - if (!mDlg) + if ((SupportsRealtime() || GetType() == EffectTypeAnalyze) && !forceModal) { - mDlg = new LadspaEffectDialog(this, (wxWindow *) parent, mData, mInputControls, mSampleRate, length); - mDlg->CentreOnParent(); + mDialog->Show(); + + return false; } - if (IsRealtimeCapable()) - { - mDlg->Show(!mDlg->IsShown()); - return true; - } + bool res = mDialog->ShowModal() != 0; + mDialog = NULL; - mDlg->ShowModal(); - bool ret = mDlg->GetReturnCode() != 0; - if (ret) - { - mHost->SetDuration(mDlg->GetLength()); - } - mDlg->Destroy(); - mDlg = NULL; - - - return ret; + return res; } -// +bool LadspaEffect::GetAutomationParameters(EffectAutomationParameters & parms) +{ + for (unsigned long p = 0; p < mData->PortCount; p++) + { + LADSPA_PortDescriptor d = mData->PortDescriptors[p]; + + if (LADSPA_IS_PORT_CONTROL(d) && LADSPA_IS_PORT_INPUT(d)) + { + if (!parms.Write(LAT1CTOWX(mData->PortNames[p]), mInputControls[p])) + { + return false; + } + } + } + + return true; +} + +bool LadspaEffect::SetAutomationParameters(EffectAutomationParameters & parms) +{ + for (unsigned long p = 0; p < mData->PortCount; p++) + { + LADSPA_PortDescriptor d = mData->PortDescriptors[p]; + + if (LADSPA_IS_PORT_CONTROL(d) && LADSPA_IS_PORT_INPUT(d)) + { + wxString labelText = LAT1CTOWX(mData->PortNames[p]); + double d = 0.0; + if (!parms.Read(labelText, &d)) + { + return false; + } + + mInputControls[p] = d; + } + } + + return true; +} + +// ============================================================================ +// EffectUIClientInterface Implementation +// ============================================================================ + +void LadspaEffect::SetUIHost(EffectUIHostInterface *host) +{ + mUIHost = host; +} + +bool LadspaEffect::PopulateUI(wxWindow *parent) +{ + mParent = parent; + + mEventHelper = new LadspaEffectEventHelper(this); + mParent->PushEventHandler(mEventHelper); + + mToggles = new wxCheckBox*[mData->PortCount]; + mSliders = new wxSlider*[mData->PortCount]; + mFields = new wxTextCtrl*[mData->PortCount]; + mLabels = new wxStaticText*[mData->PortCount]; + + memset(mFields, 0, mData->PortCount * sizeof(wxTextCtrl *)); + + wxSizer *marginSizer = new wxBoxSizer(wxVERTICAL); + + if (mNumInputControls) + { + wxSizer *paramSizer = new wxStaticBoxSizer(wxVERTICAL, mParent, _("Effect Settings")); + + wxFlexGridSizer *gridSizer = new wxFlexGridSizer(5, 0, 0); + gridSizer->AddGrowableCol(3); + + wxControl *item; + + // Add the duration control for generators + if (GetType() == EffectTypeGenerate) + { + item = new wxStaticText(mParent, 0, _("Duration:")); + gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5); + mDuration = new NumericTextCtrl(NumericConverter::TIME, + mParent, + ID_DURATION, + _("hh:mm:ss + milliseconds"), + mHost->GetDuration(), + mSampleRate, + wxDefaultPosition, + wxDefaultSize, + true); + mDuration->SetName(_("Duration")); + mDuration->EnableMenu(); + gridSizer->Add(mDuration, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); + gridSizer->Add(1, 1, 0); + gridSizer->Add(1, 1, 0); + gridSizer->Add(1, 1, 0); + ConnectFocus(mDuration); + } + + for (unsigned long p = 0; p < mData->PortCount; p++) + { + LADSPA_PortDescriptor d = mData->PortDescriptors[p]; + if (LADSPA_IS_PORT_AUDIO(d) || LADSPA_IS_PORT_OUTPUT(d)) + { + continue; + } + + wxString labelText = LAT1CTOWX(mData->PortNames[p]); + item = new wxStaticText(mParent, 0, labelText + wxT(":")); + gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5); + + wxString fieldText; + LADSPA_PortRangeHint hint = mData->PortRangeHints[p]; + + if (LADSPA_IS_HINT_TOGGLED(hint.HintDescriptor)) + { + mToggles[p] = new wxCheckBox(mParent, ID_TOGGLES + p, wxT("")); + mToggles[p]->SetName(labelText); + mToggles[p]->SetValue(mInputControls[p] > 0); + gridSizer->Add(mToggles[p], 0, wxALL, 5); + ConnectFocus(mToggles[p]); + + gridSizer->Add(1, 1, 0); + gridSizer->Add(1, 1, 0); + gridSizer->Add(1, 1, 0); + continue; + } + + wxString bound; + double lower = -FLT_MAX; + double upper = FLT_MAX; + bool haslo = false; + bool hashi = false; + bool forceint = 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_SAMPLE_RATE(hint.HintDescriptor)) + { + lower *= mSampleRate; + upper *= mSampleRate; + forceint = true; + } + + // Don't specify a value at creation time. This prevents unwanted events + // being sent to the OnTextCtrl() handler before the associated slider + // has been created. + mFields[p] = new wxTextCtrl(mParent, ID_TEXTS + p); + mFields[p]->SetName(labelText); + gridSizer->Add(mFields[p], 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); + ConnectFocus(mFields[p]); + + wxString str; + if (haslo) + { + if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint) + { + str.Printf(wxT("%d"), (int)(lower + 0.5)); + } + else + { + str = Internat::ToDisplayString(lower); + } + item = new wxStaticText(mParent, 0, str); + gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5); + } + else + { + gridSizer->Add(1, 1, 0); + } + + mSliders[p] = new wxSlider(mParent, ID_SLIDERS + p, + 0, 0, 1000, + wxDefaultPosition, + wxSize(200, -1)); + mSliders[p]->SetName(labelText); + gridSizer->Add(mSliders[p], 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxALL, 5); + ConnectFocus(mSliders[p]); + + if (hashi) + { + if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint) + { + str.Printf(wxT("%d"), (int)(upper + 0.5)); + } + else + { + str = Internat::ToDisplayString(upper); + } + item = new wxStaticText(mParent, 0, str); + gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, 5); + } + else + { + gridSizer->Add(1, 1, 0); + } + + if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint) + { + fieldText.Printf(wxT("%d"), (int)(mInputControls[p] + 0.5)); + + wxIntegerValidator vld(&mInputControls[p]); + vld.SetRange(haslo ? lower : INT_MIN, + hashi ? upper : INT_MAX); + mFields[p]->SetValidator(vld); + } + else + { + fieldText = Internat::ToDisplayString(mInputControls[p]); + + // > 12 decimal places can cause rounding errors in display. + wxFloatingPointValidator vld(12, &mInputControls[p]); + vld.SetRange(haslo ? lower : -FLT_MAX, + hashi ? upper : FLT_MAX); + + // Set number of decimal places + if (upper - lower < 10.0) + { + vld.SetStyle(wxNUM_VAL_THREE_TRAILING_ZEROES); + } + else if (upper - lower < 100.0) + { + vld.SetStyle(wxNUM_VAL_TWO_TRAILING_ZEROES); + } + else + { + vld.SetStyle(wxNUM_VAL_ONE_TRAILING_ZERO); + } + + mFields[p]->SetValidator(vld); + } + + // Set the textctrl value. This will trigger an event so OnTextCtrl() + // can update the slider. + mFields[p]->SetValue(fieldText); + } + + paramSizer->Add(gridSizer, 1, wxEXPAND | wxALL, 5); + marginSizer->Add(paramSizer, 1, wxEXPAND | wxALL, 5); + } + + if (mNumOutputControls > 0 ) + { + wxSizer *paramSizer = new wxStaticBoxSizer(wxVERTICAL, mParent, _("Effect Output")); + + wxFlexGridSizer *gridSizer = new wxFlexGridSizer(2, 0, 0); + gridSizer->AddGrowableCol(3); + + wxControl *item; + + for (unsigned long p = 0; p < mData->PortCount; p++) + { + LADSPA_PortDescriptor d = mData->PortDescriptors[p]; + if (LADSPA_IS_PORT_AUDIO(d) || LADSPA_IS_PORT_INPUT(d)) + { + continue; + } + + wxString labelText = LAT1CTOWX(mData->PortNames[p]); + item = new wxStaticText(mParent, 0, labelText + wxT(":")); + 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, + wxDefaultPosition, + wxDefaultSize, + wxTE_READONLY); + mFields[p]->SetName(labelText); + gridSizer->Add(mFields[p], 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); + ConnectFocus(mFields[p]); + } + + paramSizer->Add(gridSizer, 1, wxEXPAND | wxALL, 5); + marginSizer->Add(paramSizer, 1, wxEXPAND | wxALL, 5); + + RefreshControls(true); + } + + mParent->SetSizer(marginSizer); + + return true; +} + +bool LadspaEffect::ValidateUI() +{ + if (!mParent->Validate()) + { + return false; + } + + if (GetType() == EffectTypeGenerate) + { + mHost->SetDuration(mDuration->GetValue()); + } + + return true; +} + +bool LadspaEffect::HideUI() +{ + if (GetType() == EffectTypeAnalyze || mNumOutputControls > 0) + { + return false; + } + + return true; +} + +bool LadspaEffect::CloseUI() +{ + mParent->RemoveEventHandler(mEventHelper); + delete mEventHelper; + + mUIHost = NULL; + mParent = NULL; + mDialog = NULL; + + return true; +} + +void LadspaEffect::LoadUserPreset(const wxString & name) +{ + LoadParameters(name); +} + +void LadspaEffect::SaveUserPreset(const wxString & name) +{ + SaveParameters(name); +} + +void LadspaEffect::LoadFactoryPreset(int WXUNUSED(id)) +{ + return; +} + +void LadspaEffect::LoadFactoryDefaults() +{ + LoadParameters(mHost->GetFactoryDefaultsGroup()); +} + +wxArrayString LadspaEffect::GetFactoryPresets() +{ + return wxArrayString(); +} + +void LadspaEffect::ExportPresets() +{ +} + +void LadspaEffect::ImportPresets() +{ +} + +void LadspaEffect::ShowOptions() +{ +} + +// ============================================================================ // LadspaEffect Implementation -// +// ============================================================================ + bool LadspaEffect::Load() { if (mLib.IsLoaded()) @@ -922,11 +1381,7 @@ void LadspaEffect::LoadParameters(const wxString & group) { double val = 0.0; st.GetNextToken().ToDouble(&val); - - if (val >= -1.0 && val <= 1.0) - { - mInputControls[p] = val; - } + mInputControls[p] = val; } } } @@ -986,366 +1441,16 @@ void LadspaEffect::FreeInstance(LADSPA_Handle handle) mData->cleanup(handle); } -class Slider:public wxSlider +void LadspaEffect::OnCheckBox(wxCommandEvent & evt) { - public: - Slider(wxWindow *parent, wxWindowID id, - int value, int minValue, int maxValue, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxSL_HORIZONTAL, - const wxValidator& validator = wxDefaultValidator, - const wxString& name = wxSliderNameStr) - : wxSlider(parent, id, value, minValue, maxValue, - pos, size, style, validator, name) - { - }; + int p = evt.GetId() - ID_TOGGLES; - void OnSetFocus(wxFocusEvent & evt) - { - wxScrolledWindow *p = (wxScrolledWindow *) GetParent(); - wxRect r = GetRect(); - wxRect rv = p->GetRect(); - rv.y = 0; - - evt.Skip(); - - int y; - int yppu; - p->GetScrollPixelsPerUnit(NULL, &yppu); - - if (r.y >= rv.y && r.GetBottom() <= rv.GetBottom()) { - return; - } - - if (r.y < rv.y) { - p->CalcUnscrolledPosition(0, r.y, NULL, &r.y); - y = r.y / yppu; - } - else { - p->CalcUnscrolledPosition(0, r.y, NULL, &r.y); - y = (r.GetBottom() - rv.GetBottom() + yppu) / yppu; - } - - p->Scroll(-1, y); - }; - - DECLARE_EVENT_TABLE(); -}; - -BEGIN_EVENT_TABLE(Slider, wxSlider) - EVT_SET_FOCUS(Slider::OnSetFocus) -END_EVENT_TABLE() - -class TextCtrl:public wxTextCtrl -{ - public: - TextCtrl(wxWindow *parent, wxWindowID id, - const wxString& value = wxEmptyString, - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, long style = 0, - const wxValidator& validator = wxDefaultValidator, - const wxString& name = wxTextCtrlNameStr) - : wxTextCtrl(parent, id, value, - pos, size, style, validator, name) - { - }; - - void OnSetFocus(wxFocusEvent & evt) - { - wxScrolledWindow *p = (wxScrolledWindow *) GetParent(); - wxRect r = GetRect(); - wxRect rv = p->GetRect(); - rv.y = 0; - - evt.Skip(); - - int y; - int yppu; - p->GetScrollPixelsPerUnit(NULL, &yppu); - - if (r.y >= rv.y && r.GetBottom() <= rv.GetBottom()) { - return; - } - - if (r.y < rv.y) { - p->CalcUnscrolledPosition(0, r.y, NULL, &r.y); - y = r.y / yppu; - } - else { - p->CalcUnscrolledPosition(0, r.y, NULL, &r.y); - y = (r.GetBottom() - rv.GetBottom() + yppu) / yppu; - } - - p->Scroll(-1, y); - }; - - DECLARE_EVENT_TABLE(); -}; - -BEGIN_EVENT_TABLE(TextCtrl, wxTextCtrl) - EVT_SET_FOCUS(TextCtrl::OnSetFocus) -END_EVENT_TABLE() - -const int LADSPA_SECONDS_ID = 13101; - -BEGIN_EVENT_TABLE(LadspaEffectDialog, wxDialog) - EVT_BUTTON(wxID_APPLY, LadspaEffectDialog::OnApply) - EVT_BUTTON(wxID_OK, LadspaEffectDialog::OnOK) - EVT_BUTTON(wxID_CANCEL, LadspaEffectDialog::OnCancel) - EVT_BUTTON(ePreviewID, LadspaEffectDialog::OnPreview) - EVT_BUTTON(eDefaultsID, LadspaEffectDialog::OnDefaults) - EVT_SLIDER(wxID_ANY, LadspaEffectDialog::OnSlider) - EVT_TEXT(wxID_ANY, LadspaEffectDialog::OnTextCtrl) - EVT_CHECKBOX(wxID_ANY, LadspaEffectDialog::OnCheckBox) -END_EVENT_TABLE() - -IMPLEMENT_CLASS(LadspaEffectDialog, wxDialog) - -LadspaEffectDialog::LadspaEffectDialog(LadspaEffect *eff, - wxWindow * parent, - const LADSPA_Descriptor *data, - float *inputControls, - sampleCount sampleRate, - double length) - :wxDialog(parent, -1, LAT1CTOWX(data->Name), - wxDefaultPosition, wxDefaultSize, - wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), - mEffect(eff) -{ - mNumParams = 0; - mData = data; - mInputControls = inputControls; - mSampleRate = sampleRate; - #if defined(__WXMSW__) || (defined(__WXGTK__) && wxCHECK_VERSION(3, 0, 0)) - // In some environments wxWidgets calls OnTextCtrl during creation - // of the text control, and LadspaEffectDialog::OnTextCtrl calls HandleText, - // which assumes all the fields have been initialized. - // This can give us a bad pointer crash, so manipulate inSlider to - // no-op HandleText during creation. - inSlider = true; - #else - inSlider = false; - #endif - inText = false; - - mToggles = new wxCheckBox*[mData->PortCount]; - mSliders = new wxSlider*[mData->PortCount]; - mFields = new wxTextCtrl*[mData->PortCount]; - mLabels = new wxStaticText*[mData->PortCount]; - mPorts = new unsigned long [mData->PortCount]; - - unsigned long p; - for(p=0; pPortCount; p++) { - LADSPA_PortDescriptor d = mData->PortDescriptors[p]; - if (LADSPA_IS_PORT_CONTROL(d) && - LADSPA_IS_PORT_INPUT(d)) { - mPorts[mNumParams] = p; - mNumParams++; - } - } - - wxControl *item; - - wxBoxSizer *vSizer = new wxBoxSizer(wxVERTICAL); - - if (mData->Maker && - mData->Maker[0] && - LAT1CTOWX(mData->Maker) != wxString(_("None"))) { - item = new wxStaticText(this, 0, - wxString(_("Author: "))+LAT1CTOWX(mData->Maker)); - vSizer->Add(item, 0, wxALL, 5); - } - - if (mData->Copyright && - mData->Copyright[0] && - LAT1CTOWX(mData->Copyright) != wxString(_("None"))) { - - item = new wxStaticText(this, 0, - LAT1CTOWX(mData->Copyright)); - vSizer->Add(item, 0, wxALL, 5); - } - - wxScrolledWindow *w = new wxScrolledWindow(this, - wxID_ANY, - wxDefaultPosition, - wxDefaultSize, - wxVSCROLL | wxTAB_TRAVERSAL); - - // Try to give the window a sensible default/minimum size - w->SetMinSize(wxSize( - wxMax(600, parent->GetSize().GetWidth() * 2/3), - parent->GetSize().GetHeight() / 2)); - - w->SetScrollRate(0, 20); - vSizer->Add(w, 1, wxEXPAND|wxALL, 5); - - // Preview, OK, & Cancel buttons - if (mEffect->IsRealtimeCapable()) { - vSizer->Add(CreateStdButtonSizer(this, eApplyButton | eCancelButton | eDefaultsButton), 0, wxEXPAND); - } - else { - vSizer->Add(CreateStdButtonSizer(this, ePreviewButton | eDefaultsButton | eCancelButton | eOkButton), 0, wxEXPAND); - } - - SetSizer(vSizer); - - wxSizer *paramSizer = - new wxStaticBoxSizer(wxVERTICAL, w, _("Effect Settings")); - - wxFlexGridSizer *gridSizer = - new wxFlexGridSizer(5, 0, 0); - gridSizer->AddGrowableCol(3); - - for (p = 0; p < mNumParams; p++) { - wxString labelText = LAT1CTOWX(mData->PortNames[mPorts[p]]); - item = new wxStaticText(w, 0, labelText + wxT(":")); - gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5); - - wxString fieldText; - LADSPA_PortRangeHint hint = mData->PortRangeHints[mPorts[p]]; - - if (LADSPA_IS_HINT_TOGGLED(hint.HintDescriptor)) { - mToggles[p] = new wxCheckBox(w, p, wxT("")); - mToggles[p]->SetName(labelText); - mToggles[p]->SetValue(mInputControls[mPorts[p]] > 0); - gridSizer->Add(mToggles[p], 0, wxALL, 5); - ConnectFocus(mToggles[p]); - - gridSizer->Add(1, 1, 0); - gridSizer->Add(1, 1, 0); - gridSizer->Add(1, 1, 0); - } - else { - wxString bound; - double lower = 0.0; - double upper = 0.0; - bool haslo = false; - bool hashi = false; - bool forceint = 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_SAMPLE_RATE(hint.HintDescriptor)) { - lower *= mSampleRate; - upper *= mSampleRate; - forceint = true; - } - - if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint) - fieldText.Printf(wxT("%d"), (int)(mInputControls[mPorts[p]] + 0.5)); - else - fieldText = Internat::ToDisplayString(mInputControls[mPorts[p]]); - - mFields[p] = new wxTextCtrl(w, p, fieldText); - mFields[p]->SetName(labelText); - gridSizer->Add(mFields[p], 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - ConnectFocus(mFields[p]); - - wxString str; - if (haslo) { - if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint) - str.Printf(wxT("%d"), (int)(lower + 0.5)); - else - str = Internat::ToDisplayString(lower); - item = new wxStaticText(w, 0, str); - gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5); - } - else { - gridSizer->Add(1, 1, 0); - } - - mSliders[p] = - new wxSlider(w, p, - 0, 0, 1000, - wxDefaultPosition, - wxSize(200, -1)); - mSliders[p]->SetName(labelText); - gridSizer->Add(mSliders[p], 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxALL, 5); - ConnectFocus(mSliders[p]); - - if (hashi) { - if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint) - str.Printf(wxT("%d"), (int)(upper + 0.5)); - else - str = Internat::ToDisplayString(upper); - item = new wxStaticText(w, 0, str); - gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, 5); - } - else { - gridSizer->Add(1, 1, 0); - } - } - } - - // Now add the length control - if (mEffect->GetType() == EffectTypeGenerate) { - item = new wxStaticText(w, 0, _("Length (seconds):")); - gridSizer->Add(item, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, 5); - mSeconds = new NumericTextCtrl(NumericConverter::TIME, w, - wxID_ANY, - _("hh:mm:ss + milliseconds"), - length, - mSampleRate, - wxDefaultPosition, - wxDefaultSize, - true); - mSeconds->SetName(_("Duration")); - mSeconds->EnableMenu(); - gridSizer->Add(mSeconds, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - gridSizer->Add(1, 1, 0); - gridSizer->Add(1, 1, 0); - gridSizer->Add(1, 1, 0); - ConnectFocus(mSeconds); - } - - // Set all of the mSliders based on the value in the - // text mFields - inSlider = false; // Now we're ready for HandleText to actually do something. - mEffect->LoadParameters(wxT("Current")); -// HandleText(); - - paramSizer->Add(gridSizer, 1, wxEXPAND | wxALL, 5); - w->SetSizer(paramSizer); - - Layout(); - Fit(); - SetSizeHints(GetSize()); + mInputControls[p] = mToggles[p]->GetValue(); } -LadspaEffectDialog::~LadspaEffectDialog() +void LadspaEffect::OnSlider(wxCommandEvent & evt) { - delete[]mToggles; - delete[]mSliders; - delete[]mFields; - delete[]mLabels; - delete[]mPorts; -} - -void LadspaEffectDialog::OnCheckBox(wxCommandEvent & evt) -{ - int p = evt.GetId(); - - mInputControls[mPorts[p]] = mToggles[p]->GetValue(); -} - -void LadspaEffectDialog::OnSlider(wxCommandEvent & evt) -{ - int p = evt.GetId(); - - // if we don't add the following three lines, changing - // the value of the slider will change the text, which - // will change the slider, and so on. This gets rid of - // the implicit loop. - if (inText) - return; - inSlider = true; + int p = evt.GetId() - ID_SLIDERS; float val; float lower = float(0.0); @@ -1353,7 +1458,7 @@ void LadspaEffectDialog::OnSlider(wxCommandEvent & evt) float range; bool forceint = false; - LADSPA_PortRangeHint hint = mData->PortRangeHints[mPorts[p]]; + LADSPA_PortRangeHint hint = mData->PortRangeHints[p]; if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)) lower = hint.LowerBound; if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)) @@ -1376,164 +1481,139 @@ void LadspaEffectDialog::OnSlider(wxCommandEvent & evt) mFields[p]->SetValue(str); - mInputControls[mPorts[p]] = val; - - inSlider = false; + mInputControls[p] = val; } -void LadspaEffectDialog::OnTextCtrl(wxCommandEvent & WXUNUSED(evt)) +void LadspaEffect::OnTextCtrl(wxCommandEvent & evt) { - HandleText(); + LadspaEffect *that = reinterpret_cast(this); + int p = evt.GetId() - ID_TEXTS; + + float val; + float lower = float(0.0); + float upper = float(10.0); + float range; + + val = Internat::CompatibleToDouble(that->mFields[p]->GetValue()); + + LADSPA_PortRangeHint hint = that->mData->PortRangeHints[p]; + if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)) + lower = hint.LowerBound; + if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)) + upper = hint.UpperBound; + if (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor)) { + lower *= mSampleRate; + upper *= mSampleRate; + } + range = upper - lower; + + if (val < lower) + val = lower; + if (val > upper) + val = upper; + + mInputControls[p] = val; + + that->mSliders[p]->SetValue((int)(((val-lower)/range) * 1000.0 + 0.5)); } -void LadspaEffectDialog::HandleText() +void LadspaEffect::RefreshControls(bool outputOnly) { - // if we don't add the following three lines, changing - // the value of the slider will change the text, which - // will change the slider, and so on. This gets rid of - // the implicit loop. - - if (inSlider) + if (!mParent) + { return; - inText = true; - for (unsigned long p = 0; p < mNumParams; p++) { - double dval; - float val; - float lower = float(0.0); - float upper = float(10.0); - float range; + } - LADSPA_PortRangeHint hint = mData->PortRangeHints[mPorts[p]]; - if (LADSPA_IS_HINT_TOGGLED(hint.HintDescriptor)) { + for (unsigned long p = 0; p < mData->PortCount; p++) + { + LADSPA_PortDescriptor d = mData->PortDescriptors[p]; + if (!(LADSPA_IS_PORT_CONTROL(d))) + { continue; } - dval = Internat::CompatibleToDouble(mFields[p]->GetValue()); - val = dval; + wxString fieldText; + LADSPA_PortRangeHint hint = mData->PortRangeHints[p]; + + bool forceint = false; + if (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor)) + { + forceint = true; + } + + if (LADSPA_IS_PORT_OUTPUT(d)) + { + if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint) + { + fieldText.Printf(wxT("%d"), (int)(mOutputControls[p] + 0.5)); + } + else + { + fieldText = Internat::ToDisplayString(mOutputControls[p]); + } + + mFields[p]->SetValue(fieldText); + + continue; + } + + if (outputOnly) + { + continue; + } + + if (LADSPA_IS_HINT_TOGGLED(hint.HintDescriptor)) + { + mToggles[p]->SetValue(mInputControls[p] > 0); + 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; - if (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor)) { - lower *= mSampleRate; - upper *= mSampleRate; + hashi = true; } - range = upper - lower; - if (val < lower) - val = lower; - if (val > upper) - val = upper; - - mInputControls[mPorts[p]] = val; - - mSliders[p]->SetValue((int)(((val-lower)/range) * 1000.0 + 0.5)); - } - - inText = false; -} - -void LadspaEffectDialog::OnApply(wxCommandEvent & WXUNUSED(evt)) -{ -#if defined(__WXMAC__) - Close(); -#else - Show(false); -#endif - mEffect->SaveParameters(wxT("Current")); - - mEffect->mHost->Apply(); -} - -void LadspaEffectDialog::OnOK(wxCommandEvent & WXUNUSED(evt)) -{ - mEffect->SaveParameters(wxT("Current")); - - EndModal(TRUE); -} - -void LadspaEffectDialog::OnCancel(wxCommandEvent & WXUNUSED(evt)) -{ - if (IsModal()) - { - EndModal(FALSE); - } - else - { -#if defined(__WXMAC__) - Close(); -#else - Show(false); -#endif - } -} - -void LadspaEffectDialog::OnPreview(wxCommandEvent & WXUNUSED(evt)) -{ - mEffect->mHost->Preview(); -} - -void LadspaEffectDialog::OnDefaults(wxCommandEvent & WXUNUSED(evt)) -{ - mEffect->LoadParameters(wxT("Default")); - RefreshParaemters(); -} - -void LadspaEffectDialog::RefreshParaemters() -{ - for (unsigned long p = 0; p < mNumParams; p++) { - LADSPA_PortRangeHint hint = mData->PortRangeHints[mPorts[p]]; - - if (LADSPA_IS_HINT_TOGGLED(hint.HintDescriptor)) { - mToggles[p]->SetValue(mInputControls[mPorts[p]] > 0); + if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint) + { + fieldText.Printf(wxT("%d"), (int)(mInputControls[p] + 0.5)); } - else { - wxString bound; - double lower = 0.0; - double upper = 0.0; - bool haslo = false; - bool hashi = false; - bool forceint = 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_SAMPLE_RATE(hint.HintDescriptor)) { - lower *= mSampleRate; - upper *= mSampleRate; - forceint = true; - } - - wxString fieldText; - if (LADSPA_IS_HINT_INTEGER(hint.HintDescriptor) || forceint) - fieldText.Printf(wxT("%d"), (int)(mInputControls[mPorts[p]] + 0.5)); - else - fieldText = Internat::ToDisplayString(mInputControls[mPorts[p]]); - mFields[p]->ChangeValue(fieldText); + else + { + fieldText = Internat::ToDisplayString(mInputControls[p]); } + + // Set the textctrl value. This will trigger an event so OnTextCtrl() + // can update the slider. + mFields[p]->SetValue(fieldText); } - HandleText(); } -void LadspaEffectDialog::ConnectFocus(wxControl *c) +void LadspaEffect::ConnectFocus(wxControl *c) { c->GetEventHandler()->Connect(wxEVT_SET_FOCUS, - wxFocusEventHandler(LadspaEffectDialog::ControlSetFocus)); + wxFocusEventHandler(LadspaEffectEventHelper::ControlSetFocus)); } -void LadspaEffectDialog::DisconnectFocus(wxControl *c) +void LadspaEffect::DisconnectFocus(wxControl *c) { c->GetEventHandler()->Disconnect(wxEVT_SET_FOCUS, - wxFocusEventHandler(LadspaEffectDialog::ControlSetFocus)); + wxFocusEventHandler(LadspaEffectEventHelper::ControlSetFocus)); } -void LadspaEffectDialog::ControlSetFocus(wxFocusEvent & evt) +void LadspaEffect::ControlSetFocus(wxFocusEvent & evt) { wxControl *c = (wxControl *) evt.GetEventObject(); wxScrolledWindow *p = (wxScrolledWindow *) c->GetParent(); @@ -1562,12 +1642,3 @@ void LadspaEffectDialog::ControlSetFocus(wxFocusEvent & evt) p->Scroll(-1, y); }; - -double LadspaEffectDialog::GetLength() -{ - if (mEffect->GetType() == EffectTypeGenerate) { - return mSeconds->GetValue(); - } - - return 0; -} diff --git a/src/effects/ladspa/LadspaEffect.h b/src/effects/ladspa/LadspaEffect.h index daa91e1a9..a3098e30e 100644 --- a/src/effects/ladspa/LadspaEffect.h +++ b/src/effects/ladspa/LadspaEffect.h @@ -26,17 +26,25 @@ class wxCheckBox; #define LADSPAEFFECTS_VERSION wxT("1.0.0.0"); #define LADSPAEFFECTS_FAMILY L"Ladspa" +/////////////////////////////////////////////////////////////////////////////// +// +// LadspaEffect +// +/////////////////////////////////////////////////////////////////////////////// + WX_DEFINE_ARRAY_PTR(LADSPA_Handle, LadspaSlaveArray); -class LadspaEffectDialog; +class LadspaEffectEventHelper; -class LadspaEffect : public EffectClientInterface +class LadspaEffect : public EffectClientInterface, + public EffectUIClientInterface { public: LadspaEffect(const wxString & path, int index); virtual ~LadspaEffect(); // IdentInterface implementation + virtual PluginID GetID(); virtual wxString GetPath(); virtual wxString GetName(); @@ -45,17 +53,18 @@ public: virtual wxString GetDescription(); // EffectIdentInterface implementation + virtual EffectType GetType(); virtual wxString GetFamily(); virtual bool IsInteractive(); virtual bool IsDefault(); virtual bool IsLegacy(); - virtual bool IsRealtimeCapable(); + virtual bool SupportsRealtime(); + virtual bool SupportsAutomation(); // EffectClientInterface implementation - virtual void SetHost(EffectHostInterface *host); - virtual bool Startup(); - virtual bool Shutdown(); + + virtual bool SetHost(EffectHostInterface *host); virtual int GetAudioInCount(); virtual int GetAudioOutCount(); @@ -84,10 +93,34 @@ public: float **outbuf, sampleCount numSamples); - virtual bool ShowInterface(void *parent); + virtual bool ShowInterface(wxWindow *parent, bool forceModal = false); + + virtual bool GetAutomationParameters(EffectAutomationParameters & parms); + virtual bool SetAutomationParameters(EffectAutomationParameters & parms); + + // EffectUIClientInterface implementation + + virtual void SetUIHost(EffectUIHostInterface *host); + virtual bool PopulateUI(wxWindow *parent); + virtual bool ValidateUI(); + virtual bool HideUI(); + virtual bool CloseUI(); + + virtual void LoadUserPreset(const wxString & name); + virtual void SaveUserPreset(const wxString & name); + + virtual void LoadFactoryPreset(int id); + virtual void LoadFactoryDefaults(); + + virtual wxArrayString GetFactoryPresets(); + + virtual void ExportPresets(); + virtual void ImportPresets(); + virtual void ShowOptions(); + + // LadspaEffect implementation private: - // LadspaEffect implementation bool Load(); void Unload(); @@ -97,6 +130,14 @@ private: LADSPA_Handle InitInstance(float sampleRate); void FreeInstance(LADSPA_Handle handle); + void OnCheckBox(wxCommandEvent & evt); + void OnSlider(wxCommandEvent & evt); + void OnTextCtrl(wxCommandEvent & evt); + void RefreshControls(bool outputOnly = false); + void ConnectFocus(wxControl *c); + void DisconnectFocus(wxControl *c); + void ControlSetFocus(wxFocusEvent & evt); + private: wxString mPath; @@ -126,6 +167,7 @@ private: int mNumInputControls; float *mInputControls; + int mNumOutputControls; float *mOutputControls; int mLatencyPort; @@ -135,12 +177,52 @@ private: LadspaSlaveArray mSlaves; wxArrayInt mSlaveChannels; - LadspaEffectDialog *mDlg; + EffectUIHostInterface *mUIHost; + LadspaEffectEventHelper *mEventHelper; - friend class LadspaEffectDialog; + NumericTextCtrl *mDuration; + wxDialog *mDialog; + wxWindow *mParent; + wxSlider **mSliders; + wxTextCtrl **mFields; + wxStaticText **mLabels; + wxCheckBox **mToggles; + + friend class LadspaEffectEventHelper; friend class LadspaEffectsModule; }; +/////////////////////////////////////////////////////////////////////////////// +// +// LadspaEffectEventHelper +// +/////////////////////////////////////////////////////////////////////////////// + +class LadspaEffectEventHelper : public wxEvtHandler +{ +public: + LadspaEffectEventHelper(LadspaEffect *effect); + virtual ~LadspaEffectEventHelper(); + + // LadspaEffectEventHelper implementatino + + void OnCheckBox(wxCommandEvent & evt); + void OnSlider(wxCommandEvent & evt); + void OnTextCtrl(wxCommandEvent & evt); + void ControlSetFocus(wxFocusEvent & evt); + +private: + LadspaEffect *mEffect; + + DECLARE_EVENT_TABLE(); +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// LadspaEffectsModule +// +/////////////////////////////////////////////////////////////////////////////// + class LadspaEffectsModule : public ModuleInterface { public: @@ -165,7 +247,8 @@ public: virtual wxArrayString FindPlugins(PluginManagerInterface & pm); virtual bool RegisterPlugin(PluginManagerInterface & pm, const wxString & path); - virtual void *CreateInstance(const PluginID & ID, const wxString & path); + virtual IdentInterface *CreateInstance(const PluginID & ID, const wxString & path); + virtual void DeleteInstance(IdentInterface *instance); // LadspaEffectModule implementation @@ -176,53 +259,3 @@ private: wxString mPath; }; -class LadspaEffectDialog : public wxDialog -{ - DECLARE_DYNAMIC_CLASS(LadspaEffectDialog) - - public: - LadspaEffectDialog(LadspaEffect *effect, - wxWindow * parent, - const LADSPA_Descriptor *data, - float *inputControls, - sampleCount sampleRate, - double length); - - ~LadspaEffectDialog(); - - double GetLength(); - - DECLARE_EVENT_TABLE() - -private: - void OnCheckBox(wxCommandEvent & evt); - void OnSlider(wxCommandEvent & evt); - void OnTextCtrl(wxCommandEvent & evt); - void OnApply(wxCommandEvent & evt); - void OnOK(wxCommandEvent & evt); - void OnCancel(wxCommandEvent & evt); - void OnPreview(wxCommandEvent & evt); - void OnDefaults(wxCommandEvent & evt); - - void HandleText(); - void RefreshParaemters(); - void ConnectFocus(wxControl *c); - void DisconnectFocus(wxControl *c); - void ControlSetFocus(wxFocusEvent & evt); - -private: - bool inSlider; - bool inText; - - int mSampleRate; - const LADSPA_Descriptor *mData; - wxSlider **mSliders; - wxTextCtrl **mFields; - wxStaticText **mLabels; - wxCheckBox **mToggles; - unsigned long *mPorts; - unsigned long mNumParams; - float *mInputControls; - LadspaEffect *mEffect; - NumericTextCtrl *mSeconds; -}; diff --git a/src/prefs/EffectsPrefs.cpp b/src/prefs/EffectsPrefs.cpp index ecf04e812..87383f084 100644 --- a/src/prefs/EffectsPrefs.cpp +++ b/src/prefs/EffectsPrefs.cpp @@ -104,14 +104,14 @@ void EffectsPrefs::PopulateOrExchange(ShuttleGui & S) wxArrayString visualgroups; wxArrayString prefsgroups; - visualgroups.Add(_("Publisher: Effect Name")); - visualgroups.Add(_("Name")); + visualgroups.Add(_("Effect Name")); visualgroups.Add(_("Publisher")); + visualgroups.Add(_("Publisher: Effect Name")); visualgroups.Add(_("Type (Internal, Ladspa, VST, etc.)")); prefsgroups.Add(wxT("default")); - prefsgroups.Add(wxT("name")); prefsgroups.Add(wxT("publisher")); + prefsgroups.Add(wxT("publisher:name")); prefsgroups.Add(wxT("family")); S.TieChoice(_("Group effects in menus by:"), diff --git a/src/widgets/valnum.cpp b/src/widgets/valnum.cpp index 2bde5ff2c..26048d060 100644 --- a/src/widgets/valnum.cpp +++ b/src/widgets/valnum.cpp @@ -29,8 +29,8 @@ #if wxUSE_VALIDATORS && wxUSE_TEXTCTRL #ifndef WX_PRECOMP + #include "wx/msgdlg.h" #include "wx/textctrl.h" - #include "wx/combobox.h" #endif #include "valnum.h" @@ -39,7 +39,7 @@ // ============================================================================ // wxNumValidatorBase implementation // ============================================================================ - + BEGIN_EVENT_TABLE(wxNumValidatorBase, wxValidator) EVT_CHAR(wxNumValidatorBase::OnChar) EVT_KILL_FOCUS(wxNumValidatorBase::OnKillFocus) @@ -74,6 +74,26 @@ wxTextEntry *wxNumValidatorBase::GetTextEntry() const return NULL; } +bool wxNumValidatorBase::Validate(wxWindow *parent) +{ + // If window is disabled, simply return + if ( !m_validatorWindow->IsEnabled() ) + return true; + + wxString errmsg; + bool res = DoValidateNumber(&errmsg); + + if ( !res ) + { + wxMessageBox(errmsg, _("Validation error"), + wxOK | wxICON_ERROR, parent); + m_validatorWindow->SetFocus(); + return false; + } + + return true; +} + void wxNumValidatorBase::GetCurrentValueAndInsertionPoint(wxString& val, int& pos) const @@ -145,7 +165,9 @@ void wxNumValidatorBase::OnChar(wxKeyEvent& event) return; } #endif // wxUSE_UNICODE/!wxUSE_UNICODE - + + // Space is an allowed thousands separator. But we don't allow user to type + // it. We will add it at formatting time in OnKillFocus(). if ( c < WXK_SPACE || c == WXK_DELETE ) { // Allow ASCII control characters and Delete. @@ -188,6 +210,8 @@ void wxNumValidatorBase::OnKillFocus(wxFocusEvent& event) text->MarkDirty(); event.Skip(); + +// Validate(text); } // ============================================================================ @@ -223,26 +247,65 @@ wxIntegerValidatorBase::IsCharOk(const wxString& val, int pos, wxChar ch) const return m_min < 0 && IsMinusOk(val, pos); } - // We only accept digits here (remember that '-' is taken care of by the - // base class already). + // A separator is accepted if the locale allow it, the other chars must be digits if ( ch < '0' || ch > '9' ) - return false; + { + wxChar thousands; + if ( wxNumberFormatter::GetThousandsSeparatorIfUsed(&thousands) ) + { + if (ch != thousands) + return false; + } + else + { + return false; + } + } - // And the value after insertion needs to be in the defined range. - LongestValueType value; - if ( !FromString(GetValueAfterInsertingChar(val, pos, ch), &value) ) - return false; - - wxString smin = ToString(m_min); - wxString smax = ToString(m_max); - if ( pos < (int) smin.Length() ) - return true; - if ( pos < (int) smax.Length() - 1 ) - return true; - - return IsInRange(value); + return true; } +bool wxIntegerValidatorBase::DoValidateNumber(wxString * errMsg) const +{ + wxTextEntry * const control = GetTextEntry(); + if ( !control ) + return false; + + wxString s(control->GetValue()); + wxChar thousandsSep; + if ( wxNumberFormatter::GetThousandsSeparatorIfUsed(&thousandsSep) ) + s.Replace(wxString(thousandsSep), wxString()); + + if ( s.empty() ) + { + // Is blank, but allowed. Stop here + if ( HasFlag(wxNUM_VAL_ZERO_AS_BLANK) ) + { + return true; + } + // We can't do any check with an empty string + else + { + *errMsg = _("Empty value"); + return false; + } + } + + // Can it be converted to a value? + LongestValueType value; + bool res = FromString(s, &value); + if ( !res ) + *errMsg = _("Malformed number"); + else + { + res = IsInRange(value); + if ( !res ) + *errMsg = _("Not in range"); + } + + return res; +} + // ============================================================================ // wxFloatingPointValidatorBase implementation // ============================================================================ @@ -264,10 +327,27 @@ wxFloatingPointValidatorBase::IsCharOk(const wxString& val, int pos, wxChar ch) const { - // We may accept minus sign if we can represent negative numbers at all. if ( ch == '-' ) - return m_min < 0 && IsMinusOk(val, pos); - + { + // We may accept minus sign if we can represent negative numbers at all. + if ( pos == 0 ) + return m_min < 0 && IsMinusOk(val, pos); + // or for the exponent definition + else if ( val[pos-1] != 'e' && val[pos-1] != 'E' ) + return false; + + return true; + } + else if ( ch == '+' ) + { + if ( pos == 0 ) + return m_max >= 0; + else if ( val[pos-1] != 'e' && val[pos-1] != 'E' ) + return false; + + return true; + } + const wxChar separator = wxNumberFormatter::GetDecimalSeparator(); if ( ch == separator ) { @@ -277,8 +357,8 @@ wxFloatingPointValidatorBase::IsCharOk(const wxString& val, return false; } - // Prepending a separator before the minus sign isn't allowed. - if ( pos == 0 && !val.empty() && val[0] == '-' ) + // Prepending a separator before the sign isn't allowed. + if ( pos == 0 && !val.empty() && ( val[0] == '-' || val[0] == '+' ) ) return false; // Otherwise always accept it, adding a decimal separator doesn't @@ -289,24 +369,83 @@ wxFloatingPointValidatorBase::IsCharOk(const wxString& val, return true; } - // Must be a digit then. - if ( ch < '0' || ch > '9' ) - return false; + // Must be a digit, an exponent or a thousands separator. + if( ( ch < '0' || ch > '9' ) && ch != 'E' && ch != 'e' ) + { + wxChar thousands; + if ( wxNumberFormatter::GetThousandsSeparatorIfUsed(&thousands) ) + { + if (ch != thousands) + return false; + } + else + { + return false; + } + } + + // Check the number of decimal digits in the final string + wxString str(val); + str.insert(pos, ch); + return ValidatePrecision(str); +} - // Check whether the value we'd obtain if we accepted this key is correct. - const wxString newval(GetValueAfterInsertingChar(val, pos, ch)); - - LongestValueType value; - if ( !FromString(newval, &value) ) - return false; - - // Also check that it doesn't have too many decimal digits. - const size_t posSep = newval.find(separator); - if ( posSep != wxString::npos && newval.length() - posSep - 1 > m_precision ) - return false; - - // Finally check whether it is in the range. - return IsInRange(value); -} +bool wxFloatingPointValidatorBase::DoValidateNumber(wxString * errMsg) const +{ + wxTextEntry * const control = GetTextEntry(); + if ( !control ) + return false; + + wxString s(control->GetValue()); + wxChar thousandsSep; + if ( wxNumberFormatter::GetThousandsSeparatorIfUsed(&thousandsSep) ) + s.Replace(wxString(thousandsSep), wxString()); + + if ( s.empty() ) + { + if ( HasFlag(wxNUM_VAL_ZERO_AS_BLANK) ) + return true; //Is blank, but allowed. Stop here + else + { + *errMsg = _("Empty value"); + return false; //We can't do any checks with an empty string + } + } + + LongestValueType value; + bool res = FromString(s, &value); // Can it be converted to a value? + if ( !res ) + *errMsg = _("Value overflow"); + else + { + res = ValidatePrecision(s); + if ( !res ) + *errMsg = _("Too meany decimal digits"); + else + { + res = IsInRange(value); + if ( !res ) + *errMsg = _("Not in range"); + } + } + + return res; +} + +bool wxFloatingPointValidatorBase::ValidatePrecision(const wxString& s) const +{ + size_t posSep = s.find(wxNumberFormatter::GetDecimalSeparator()); + if ( posSep == wxString::npos ) + posSep = s.length(); + + // If user typed exponent 'e' the number of decimal digits is not + // important at all. But we must know that 'e' position. + size_t posExp = s.Lower().Find(_("e")); + if ( posExp == wxString::npos ) + posExp = s.length(); + + // Return true if number has no more decimal digits than allowed + return ( (int)(posExp - posSep) - 1 <= (int)m_precision ); +} #endif // wxUSE_VALIDATORS && wxUSE_TEXTCTRL diff --git a/src/widgets/valnum.h b/src/widgets/valnum.h index a049eb3a9..038965688 100644 --- a/src/widgets/valnum.h +++ b/src/widgets/valnum.h @@ -43,10 +43,9 @@ public: // Change the validator style. Usually it's specified during construction. void SetStyle(int style) { m_style = style; } - - // Override base class method to not do anything but always return success: - // we don't need this as we do our validation on the fly here. - virtual bool Validate(wxWindow * WXUNUSED(parent)) { return true; } + // Called when the value in the window must be validated. + // This function can pop up an error message. + virtual bool Validate(wxWindow * parent); protected: wxNumValidatorBase(int style) @@ -98,12 +97,16 @@ private: // NormalizeString the contents of the string if it's a valid number, return // empty string otherwise. virtual wxString NormalizeString(const wxString& s) const = 0; - + + // Do all checks to ensure this is a valid value. + // Returns 'true' if the control has valid value. + // Otherwise the cause is indicated in 'errMsg'. + virtual bool DoValidateNumber(wxString * errMsg) const = 0; // Event handlers. void OnChar(wxKeyEvent& event); void OnKillFocus(wxFocusEvent& event); - + // Determine the current insertion point and text in the associated control. void GetCurrentValueAndInsertionPoint(wxString& val, int& pos) const; @@ -297,6 +300,7 @@ protected: // Implement wxNumValidatorBase pure virtual method. virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const; + virtual bool DoValidateNumber(wxString * errMsg) const; private: // Minimal and maximal values accepted (inclusive). @@ -392,6 +396,10 @@ protected: // Implement wxNumValidatorBase pure virtual method. virtual bool IsCharOk(const wxString& val, int pos, wxChar ch) const; + virtual bool DoValidateNumber(wxString * errMsg) const; + + //Checks that it doesn't have too many decimal digits. + bool ValidatePrecision(const wxString& s) const; private: // Maximum number of decimals digits after the decimal separator. diff --git a/win/Projects/Audacity/Audacity.vcxproj b/win/Projects/Audacity/Audacity.vcxproj index 81fd87a59..d0ba31a3c 100755 --- a/win/Projects/Audacity/Audacity.vcxproj +++ b/win/Projects/Audacity/Audacity.vcxproj @@ -1,1324 +1,1325 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - wx3-Debug - Win32 - - - wx3-Release - Win32 - - - - {1D64095C-F936-4FCF-B609-56E9DDF941FA} - Audacity - - - - Application - v120 - Unicode - false - PATH=%WXWIN%\lib\vc_dll;%PATH% - - - Application - v120 - Unicode - false - PATH=%WXWIN3%\lib\vc_dll;%PATH% - - - Application - v120_xp - Unicode - true - PATH=%WXWIN%\lib\vc_dll;%PATH% - - - Application - v120_xp - Unicode - true - PATH=%WXWIN3%\lib\vc_dll;%PATH% - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>11.0.60610.1 - - - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - - - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - - - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - true - - - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - true - - - - MaxSpeed - $(WXWIN)\lib\vc_dll\mswu;$(WXWIN)\include;..\..;..\..\..\include;..\..\..\lib-src\expat\lib;..\..\..\lib-src\FileDialog;..\..\..\lib-src\FileDialog\win;..\..\..\lib-src\ffmpeg\win32;..\..\..\lib-src\ffmpeg;..\..\..\lib-src\lib-widget-extra;..\..\..\lib-src\libflac\include;..\..\..\lib-src\libid3tag;..\..\..\lib-src\libmad\msvc++;..\..\..\lib-src\libmad;..\..\..\lib-src\libnyquist;..\..\..\lib-src\libogg\include;..\..\..\lib-src\libresample\include;..\..\..\lib-src\libsamplerate\src;..\..\..\lib-src\libscorealign;..\libsndfile;..\..\..\lib-src\libsoxr\src;..\..\..\lib-src\libvamp;..\..\..\lib-src\libvorbis\include;..\..\..\lib-src\portaudio-v19\include;..\..\..\lib-src\portmixer\include;..\..\..\lib-src\portsmf;..\..\..\lib-src\sbsms\include;..\..\..\lib-src\soundtouch\include;..\..\..\lib-src\twolame\libtwolame;..\..\..\lib-src\portmidi\pm_common;..\..\..\lib-src\portmidi\pm_win;..\..\..\lib-src\portmidi\porttime;..\..\..\lib-src\lv2\lilv;..\..\..\lib-src\lv2\lv2;..\..\..\lib-src\lame;$(GSTREAMER_SDK)\include\gstreamer-1.0;$(GSTREAMER_SDK)\include\glib-2.0;$(GSTREAMER_SDK)\lib\glib-2.0\include;%(AdditionalIncludeDirectories) - BUILDING_AUDACITY;FLAC__NO_DLL;XML_STATIC;__STDC_CONSTANT_MACROS;WXUSINGDLL;__WXMSW__;NDEBUG;WIN32;STRICT;%(PreprocessorDefinitions) - true - MultiThreadedDLL - true - .\$(Configuration)/audacity.pch - Level3 - Default - 4996;%(DisableSpecificWarnings) - - - NDEBUG;%(PreprocessorDefinitions) - 0x0809 - $(WXWIN)\include;..\..\..\src;%(AdditionalIncludeDirectories) - - - false - - - expat.lib;filedialog.lib;libsndfile.lib;portaudio-v19.lib;wxbase28u.lib;wxbase28u_net.lib;wxmsw28u_adv.lib;wxmsw28u_core.lib;wxmsw28u_html.lib;wxpng.lib;wxzlib.lib;wxjpeg.lib;wxtiff.lib;comctl32.lib;rpcrt4.lib;wsock32.lib;winmm.lib;oleacc.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;%(AdditionalDependencies) - $(OutDir);$(WXWIN)\lib\vc_dll;$(GSTREAMER_SDK)\lib;%(AdditionalLibraryDirectories) - Windows - 8388608 - false - - MachineX86 - - - - - MaxSpeed - $(WXWIN3)\lib\vc_dll\mswu;$(WXWIN3)\include;..\..;..\..\..\include;..\..\..\lib-src\expat\lib;..\..\..\lib-src\FileDialog;..\..\..\lib-src\FileDialog\win;..\..\..\lib-src\ffmpeg\win32;..\..\..\lib-src\ffmpeg;..\..\..\lib-src\lib-widget-extra;..\..\..\lib-src\libflac\include;..\..\..\lib-src\libid3tag;..\..\..\lib-src\libmad\msvc++;..\..\..\lib-src\libmad;..\..\..\lib-src\libnyquist;..\..\..\lib-src\libogg\include;..\..\..\lib-src\libresample\include;..\..\..\lib-src\libsamplerate\src;..\..\..\lib-src\libscorealign;..\libsndfile;..\..\..\lib-src\libsoxr\src;..\..\..\lib-src\libvamp;..\..\..\lib-src\libvorbis\include;..\..\..\lib-src\portaudio-v19\include;..\..\..\lib-src\portmixer\include;..\..\..\lib-src\portsmf;..\..\..\lib-src\sbsms\include;..\..\..\lib-src\soundtouch\include;..\..\..\lib-src\twolame\libtwolame;..\..\..\lib-src\portmidi\pm_common;..\..\..\lib-src\portmidi\pm_win;..\..\..\lib-src\portmidi\porttime;..\..\..\lib-src\lv2\lilv;..\..\..\lib-src\lv2\lv2;..\..\..\lib-src\lame;$(GSTREAMER_SDK)\include\gstreamer-1.0;$(GSTREAMER_SDK)\include\glib-2.0;$(GSTREAMER_SDK)\lib\glib-2.0\include;%(AdditionalIncludeDirectories) - BUILDING_AUDACITY;FLAC__NO_DLL;XML_STATIC;__STDC_CONSTANT_MACROS;WXUSINGDLL;__WXMSW__;NDEBUG;WIN32;STRICT;%(PreprocessorDefinitions) - true - MultiThreadedDLL - true - .\$(Configuration)/audacity.pch - Level3 - Default - 4996;%(DisableSpecificWarnings) - - - NDEBUG;%(PreprocessorDefinitions) - 0x0809 - $(WXWIN3)\include;..\..\..\src;%(AdditionalIncludeDirectories) - - - false - - - expat.lib;filedialog.lib;libsndfile.lib;portaudio-v19.lib;wxbase30u.lib;wxbase30u_net.lib;wxmsw30u_adv.lib;wxmsw30u_core.lib;wxmsw30u_html.lib;wxpng.lib;wxzlib.lib;wxjpeg.lib;wxtiff.lib;comctl32.lib;rpcrt4.lib;wsock32.lib;winmm.lib;oleacc.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;%(AdditionalDependencies) - $(OutDir);$(WXWIN3)\lib\vc_dll;$(GSTREAMER_SDK)\lib;%(AdditionalLibraryDirectories) - Windows - 8388608 - false - - - MachineX86 - - - - - Disabled - $(WXWIN)\lib\vc_dll\mswud;$(WXWIN)\include;..\..;..\..\..\include;..\..\..\lib-src\expat\lib;..\..\..\lib-src\FileDialog;..\..\..\lib-src\FileDialog\win;..\..\..\lib-src\lib-widget-extra;..\..\..\lib-src\libflac\include;..\..\..\lib-src\libid3tag;..\..\..\lib-src\libmad\msvc++;..\..\..\lib-src\libmad;..\..\..\lib-src\libnyquist;..\..\..\lib-src\libogg\include;..\..\..\lib-src\libresample\include;..\..\..\lib-src\libsamplerate\src;..\..\..\lib-src\libscorealign;..\libsndfile;..\..\..\lib-src\libsoxr\src;..\..\..\lib-src\libvamp;..\..\..\lib-src\libvorbis\include;..\..\..\lib-src\portaudio-v19\include;..\..\..\lib-src\portmixer\include;..\..\..\lib-src\portsmf;..\..\..\lib-src\sbsms\include;..\..\..\lib-src\soundtouch\include;..\..\..\lib-src\twolame\libtwolame;..\..\..\lib-src\portmidi\pm_common;..\..\..\lib-src\portmidi\pm_win;..\..\..\lib-src\portmidi\porttime;..\..\..\lib-src\ffmpeg\win32;..\..\..\lib-src\ffmpeg;..\..\..\lib-src\lv2\lilv;..\..\..\lib-src\lv2\lv2;..\..\..\lib-src\lame;&quot;$(GSTREAMER_SDK)\include\gstreamer-1.0;$(GSTREAMER_SDK)\include\glib-2.0;$(GSTREAMER_SDK)\lib\glib-2.0\include;%(AdditionalIncludeDirectories) - BUILDING_AUDACITY;FLAC__NO_DLL;XML_STATIC;__STDC_CONSTANT_MACROS;WXUSINGDLL;__WXMSW__;__WXDEBUG__;_DEBUG;WIN32;STRICT;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - true - Use - AudacityHeaders.h - Level4 - EditAndContinue - Default - 4996;%(DisableSpecificWarnings) - AudacityHeaders.h;%(ForcedIncludeFiles) - - - _DEBUG;%(PreprocessorDefinitions) - 0x0809 - $(WXWIN)\include;..\..\..\src;%(AdditionalIncludeDirectories) - - - false - - - expat.lib;filedialog.lib;libsndfile.lib;portaudio-v19.lib;wxbase28ud.lib;wxbase28ud_net.lib;wxmsw28ud_adv.lib;wxmsw28ud_core.lib;wxmsw28ud_html.lib;wxpngd.lib;wxzlibd.lib;wxjpegd.lib;wxtiffd.lib;comctl32.lib;rpcrt4.lib;wsock32.lib;winmm.lib;oleacc.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;%(AdditionalDependencies) - $(OutDir);$(WXWIN)\lib\vc_dll;$(GSTREAMER_SDK)\lib;%(AdditionalLibraryDirectories) - true - Windows - 8388608 - false - - MachineX86 - - - - - Disabled - $(WXWIN3)\lib\vc_dll\mswud;$(WXWIN3)\include;..\..;..\..\..\include;..\..\..\lib-src\expat\lib;..\..\..\lib-src\FileDialog;..\..\..\lib-src\FileDialog\win;..\..\..\lib-src\lib-widget-extra;..\..\..\lib-src\libflac\include;..\..\..\lib-src\libid3tag;..\..\..\lib-src\libmad\msvc++;..\..\..\lib-src\libmad;..\..\..\lib-src\libnyquist;..\..\..\lib-src\libogg\include;..\..\..\lib-src\libresample\include;..\..\..\lib-src\libsamplerate\src;..\..\..\lib-src\libscorealign;..\libsndfile;..\..\..\lib-src\libsoxr\src;..\..\..\lib-src\libvamp;..\..\..\lib-src\libvorbis\include;..\..\..\lib-src\portaudio-v19\include;..\..\..\lib-src\portmixer\include;..\..\..\lib-src\portsmf;..\..\..\lib-src\sbsms\include;..\..\..\lib-src\soundtouch\include;..\..\..\lib-src\twolame\libtwolame;..\..\..\lib-src\portmidi\pm_common;..\..\..\lib-src\portmidi\pm_win;..\..\..\lib-src\portmidi\porttime;..\..\..\lib-src\ffmpeg\win32;..\..\..\lib-src\ffmpeg;..\..\..\lib-src\lv2\lilv;..\..\..\lib-src\lv2\lv2;..\..\..\lib-src\lame;&quot;$(GSTREAMER_SDK)\include\gstreamer-1.0;$(GSTREAMER_SDK)\include\glib-2.0;$(GSTREAMER_SDK)\lib\glib-2.0\include;%(AdditionalIncludeDirectories) - BUILDING_AUDACITY;FLAC__NO_DLL;XML_STATIC;__STDC_CONSTANT_MACROS;WXUSINGDLL;__WXMSW__;__WXDEBUG__;_DEBUG;WIN32;STRICT;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - true - Use - AudacityHeaders.h - Level4 - EditAndContinue - Default - 4996;%(DisableSpecificWarnings) - AudacityHeaders.h;%(ForcedIncludeFiles) - - - _DEBUG;%(PreprocessorDefinitions) - 0x0809 - $(WXWIN3)\include;..\..\..\src;%(AdditionalIncludeDirectories) - - - false - - - expat.lib;filedialog.lib;libsndfile.lib;portaudio-v19.lib;wxbase30ud.lib;wxbase30ud_net.lib;wxmsw30ud_adv.lib;wxmsw30ud_core.lib;wxmsw30ud_html.lib;wxpngd.lib;wxzlibd.lib;wxjpegd.lib;wxtiffd.lib;comctl32.lib;rpcrt4.lib;wsock32.lib;winmm.lib;oleacc.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;%(AdditionalDependencies) - $(OutDir);$(WXWIN3)\lib\vc_dll;$(GSTREAMER_SDK)\lib;%(AdditionalLibraryDirectories) - true - Windows - 8388608 - false - - - MachineX86 - - - - - - - - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.obj - $(IntDir)%(Filename)1.xdc - $(IntDir)%(Filename)1.xdc - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - Document - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - - - - - {5284d863-3813-479f-bbf0-ac234e216bc6} - false - - - {b28c9f3f-ff0e-4fec-844c-685390b8ac06} - false - - - {6c7dc635-26fb-419a-b69a-7ecbbb068245} - false - - - {d96c7be1-e3f1-4767-bbbb-320e082ce425} - false - - - {a52bbea5-8b02-4147-8734-5d9bbf4d1177} - false - - - {7aa41bed-41b0-427a-9148-dea40549d158} - false - - - {a939aaf8-44f1-4ce7-9dd0-7a6e99814857} - false - - - {f00717f2-67c8-44e1-af00-541dfa9cb7f2} - false - - - {c0fe933b-4af7-4acd-95e8-acd3a73f1400} - false - - - {f4b4a272-4ed3-4951-a6ee-b7baac1c4952} - false - - - {af9ad75c-4785-4432-bac3-adab1e7f1192} - false - - - {a61e2bf1-21aa-4118-b0d8-fd3d53db892e} - false - - - {727d6675-67ee-4d0b-9dc1-177a0af741f0} - false - - - {0fec8848-e24e-4fa5-9acd-e4582dc4cbbe} - false - - - {7aba0f80-94ae-4e82-ab89-2e1258212d59} - false - - - {d5ab2d87-51dc-4277-a9ab-2a6018d0e947} - false - - - {3a76129b-55ab-4d54-baa7-08f63ed52569} - false - - - {8a1c2514-85dd-4ae2-9cf3-3183b66c537d} - false - - - {a64ffb5d-0cf0-43ee-9de3-c72260864bff} - false - - - {ec3f5835-c486-4970-8a6b-a0700f4b3637} - false - - - {8c69f7b6-684f-48d9-9057-8912ca3daa8b} - false - - - - - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + wx3-Debug + Win32 + + + wx3-Release + Win32 + + + + {1D64095C-F936-4FCF-B609-56E9DDF941FA} + Audacity + + + + Application + v120 + Unicode + false + PATH=%WXWIN%\lib\vc_dll;%PATH% + + + Application + v120 + Unicode + false + PATH=%WXWIN3%\lib\vc_dll;%PATH% + + + Application + v120_xp + Unicode + true + PATH=%WXWIN%\lib\vc_dll;%PATH% + + + Application + v120_xp + Unicode + true + PATH=%WXWIN3%\lib\vc_dll;%PATH% + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + + MaxSpeed + $(WXWIN)\lib\vc_dll\mswu;$(WXWIN)\include;..\..;..\..\..\include;..\..\..\lib-src\expat\lib;..\..\..\lib-src\FileDialog;..\..\..\lib-src\FileDialog\win;..\..\..\lib-src\ffmpeg\win32;..\..\..\lib-src\ffmpeg;..\..\..\lib-src\lib-widget-extra;..\..\..\lib-src\libflac\include;..\..\..\lib-src\libid3tag;..\..\..\lib-src\libmad\msvc++;..\..\..\lib-src\libmad;..\..\..\lib-src\libnyquist;..\..\..\lib-src\libogg\include;..\..\..\lib-src\libresample\include;..\..\..\lib-src\libsamplerate\src;..\..\..\lib-src\libscorealign;..\libsndfile;..\..\..\lib-src\libsoxr\src;..\..\..\lib-src\libvamp;..\..\..\lib-src\libvorbis\include;..\..\..\lib-src\portaudio-v19\include;..\..\..\lib-src\portmixer\include;..\..\..\lib-src\portsmf;..\..\..\lib-src\sbsms\include;..\..\..\lib-src\soundtouch\include;..\..\..\lib-src\twolame\libtwolame;..\..\..\lib-src\portmidi\pm_common;..\..\..\lib-src\portmidi\pm_win;..\..\..\lib-src\portmidi\porttime;..\..\..\lib-src\lv2\lilv;..\..\..\lib-src\lv2\lv2;..\..\..\lib-src\lame;$(GSTREAMER_SDK)\include\gstreamer-1.0;$(GSTREAMER_SDK)\include\glib-2.0;$(GSTREAMER_SDK)\lib\glib-2.0\include;%(AdditionalIncludeDirectories) + BUILDING_AUDACITY;FLAC__NO_DLL;XML_STATIC;__STDC_CONSTANT_MACROS;WXUSINGDLL;__WXMSW__;NDEBUG;WIN32;STRICT;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + .\$(Configuration)/audacity.pch + Level3 + Default + 4996;%(DisableSpecificWarnings) + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + $(WXWIN)\include;..\..\..\src;%(AdditionalIncludeDirectories) + + + false + + + expat.lib;filedialog.lib;libsndfile.lib;portaudio-v19.lib;wxbase28u.lib;wxbase28u_net.lib;wxmsw28u_adv.lib;wxmsw28u_core.lib;wxmsw28u_html.lib;wxpng.lib;wxzlib.lib;wxjpeg.lib;wxtiff.lib;comctl32.lib;rpcrt4.lib;wsock32.lib;winmm.lib;oleacc.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;%(AdditionalDependencies) + $(OutDir);$(WXWIN)\lib\vc_dll;$(GSTREAMER_SDK)\lib;%(AdditionalLibraryDirectories) + Windows + 8388608 + false + + MachineX86 + + + + + MaxSpeed + $(WXWIN3)\lib\vc_dll\mswu;$(WXWIN3)\include;..\..;..\..\..\include;..\..\..\lib-src\expat\lib;..\..\..\lib-src\FileDialog;..\..\..\lib-src\FileDialog\win;..\..\..\lib-src\ffmpeg\win32;..\..\..\lib-src\ffmpeg;..\..\..\lib-src\lib-widget-extra;..\..\..\lib-src\libflac\include;..\..\..\lib-src\libid3tag;..\..\..\lib-src\libmad\msvc++;..\..\..\lib-src\libmad;..\..\..\lib-src\libnyquist;..\..\..\lib-src\libogg\include;..\..\..\lib-src\libresample\include;..\..\..\lib-src\libsamplerate\src;..\..\..\lib-src\libscorealign;..\libsndfile;..\..\..\lib-src\libsoxr\src;..\..\..\lib-src\libvamp;..\..\..\lib-src\libvorbis\include;..\..\..\lib-src\portaudio-v19\include;..\..\..\lib-src\portmixer\include;..\..\..\lib-src\portsmf;..\..\..\lib-src\sbsms\include;..\..\..\lib-src\soundtouch\include;..\..\..\lib-src\twolame\libtwolame;..\..\..\lib-src\portmidi\pm_common;..\..\..\lib-src\portmidi\pm_win;..\..\..\lib-src\portmidi\porttime;..\..\..\lib-src\lv2\lilv;..\..\..\lib-src\lv2\lv2;..\..\..\lib-src\lame;$(GSTREAMER_SDK)\include\gstreamer-1.0;$(GSTREAMER_SDK)\include\glib-2.0;$(GSTREAMER_SDK)\lib\glib-2.0\include;%(AdditionalIncludeDirectories) + BUILDING_AUDACITY;FLAC__NO_DLL;XML_STATIC;__STDC_CONSTANT_MACROS;WXUSINGDLL;__WXMSW__;NDEBUG;WIN32;STRICT;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + .\$(Configuration)/audacity.pch + Level3 + Default + 4996;%(DisableSpecificWarnings) + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + $(WXWIN3)\include;..\..\..\src;%(AdditionalIncludeDirectories) + + + false + + + expat.lib;filedialog.lib;libsndfile.lib;portaudio-v19.lib;wxbase30u.lib;wxbase30u_net.lib;wxmsw30u_adv.lib;wxmsw30u_core.lib;wxmsw30u_html.lib;wxpng.lib;wxzlib.lib;wxjpeg.lib;wxtiff.lib;comctl32.lib;rpcrt4.lib;wsock32.lib;winmm.lib;oleacc.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;%(AdditionalDependencies) + $(OutDir);$(WXWIN3)\lib\vc_dll;$(GSTREAMER_SDK)\lib;%(AdditionalLibraryDirectories) + Windows + 8388608 + false + + + MachineX86 + + + + + Disabled + $(WXWIN)\lib\vc_dll\mswud;$(WXWIN)\include;..\..;..\..\..\include;..\..\..\lib-src\expat\lib;..\..\..\lib-src\FileDialog;..\..\..\lib-src\FileDialog\win;..\..\..\lib-src\lib-widget-extra;..\..\..\lib-src\libflac\include;..\..\..\lib-src\libid3tag;..\..\..\lib-src\libmad\msvc++;..\..\..\lib-src\libmad;..\..\..\lib-src\libnyquist;..\..\..\lib-src\libogg\include;..\..\..\lib-src\libresample\include;..\..\..\lib-src\libsamplerate\src;..\..\..\lib-src\libscorealign;..\libsndfile;..\..\..\lib-src\libsoxr\src;..\..\..\lib-src\libvamp;..\..\..\lib-src\libvorbis\include;..\..\..\lib-src\portaudio-v19\include;..\..\..\lib-src\portmixer\include;..\..\..\lib-src\portsmf;..\..\..\lib-src\sbsms\include;..\..\..\lib-src\soundtouch\include;..\..\..\lib-src\twolame\libtwolame;..\..\..\lib-src\portmidi\pm_common;..\..\..\lib-src\portmidi\pm_win;..\..\..\lib-src\portmidi\porttime;..\..\..\lib-src\ffmpeg\win32;..\..\..\lib-src\ffmpeg;..\..\..\lib-src\lv2\lilv;..\..\..\lib-src\lv2\lv2;..\..\..\lib-src\lame;&quot;$(GSTREAMER_SDK)\include\gstreamer-1.0;$(GSTREAMER_SDK)\include\glib-2.0;$(GSTREAMER_SDK)\lib\glib-2.0\include;%(AdditionalIncludeDirectories) + BUILDING_AUDACITY;FLAC__NO_DLL;XML_STATIC;__STDC_CONSTANT_MACROS;WXUSINGDLL;__WXMSW__;__WXDEBUG__;_DEBUG;WIN32;STRICT;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + Use + AudacityHeaders.h + Level4 + EditAndContinue + Default + 4996;%(DisableSpecificWarnings) + AudacityHeaders.h;%(ForcedIncludeFiles) + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + $(WXWIN)\include;..\..\..\src;%(AdditionalIncludeDirectories) + + + false + + + expat.lib;filedialog.lib;libsndfile.lib;portaudio-v19.lib;wxbase28ud.lib;wxbase28ud_net.lib;wxmsw28ud_adv.lib;wxmsw28ud_core.lib;wxmsw28ud_html.lib;wxpngd.lib;wxzlibd.lib;wxjpegd.lib;wxtiffd.lib;comctl32.lib;rpcrt4.lib;wsock32.lib;winmm.lib;oleacc.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;%(AdditionalDependencies) + $(OutDir);$(WXWIN)\lib\vc_dll;$(GSTREAMER_SDK)\lib;%(AdditionalLibraryDirectories) + true + Windows + 8388608 + false + + MachineX86 + + + + + Disabled + $(WXWIN3)\lib\vc_dll\mswud;$(WXWIN3)\include;..\..;..\..\..\include;..\..\..\lib-src\expat\lib;..\..\..\lib-src\FileDialog;..\..\..\lib-src\FileDialog\win;..\..\..\lib-src\lib-widget-extra;..\..\..\lib-src\libflac\include;..\..\..\lib-src\libid3tag;..\..\..\lib-src\libmad\msvc++;..\..\..\lib-src\libmad;..\..\..\lib-src\libnyquist;..\..\..\lib-src\libogg\include;..\..\..\lib-src\libresample\include;..\..\..\lib-src\libsamplerate\src;..\..\..\lib-src\libscorealign;..\libsndfile;..\..\..\lib-src\libsoxr\src;..\..\..\lib-src\libvamp;..\..\..\lib-src\libvorbis\include;..\..\..\lib-src\portaudio-v19\include;..\..\..\lib-src\portmixer\include;..\..\..\lib-src\portsmf;..\..\..\lib-src\sbsms\include;..\..\..\lib-src\soundtouch\include;..\..\..\lib-src\twolame\libtwolame;..\..\..\lib-src\portmidi\pm_common;..\..\..\lib-src\portmidi\pm_win;..\..\..\lib-src\portmidi\porttime;..\..\..\lib-src\ffmpeg\win32;..\..\..\lib-src\ffmpeg;..\..\..\lib-src\lv2\lilv;..\..\..\lib-src\lv2\lv2;..\..\..\lib-src\lame;&quot;$(GSTREAMER_SDK)\include\gstreamer-1.0;$(GSTREAMER_SDK)\include\glib-2.0;$(GSTREAMER_SDK)\lib\glib-2.0\include;%(AdditionalIncludeDirectories) + BUILDING_AUDACITY;FLAC__NO_DLL;XML_STATIC;__STDC_CONSTANT_MACROS;WXUSINGDLL;__WXMSW__;__WXDEBUG__;_DEBUG;WIN32;STRICT;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + true + Use + AudacityHeaders.h + Level4 + EditAndContinue + Default + 4996;%(DisableSpecificWarnings) + AudacityHeaders.h;%(ForcedIncludeFiles) + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + $(WXWIN3)\include;..\..\..\src;%(AdditionalIncludeDirectories) + + + false + + + expat.lib;filedialog.lib;libsndfile.lib;portaudio-v19.lib;wxbase30ud.lib;wxbase30ud_net.lib;wxmsw30ud_adv.lib;wxmsw30ud_core.lib;wxmsw30ud_html.lib;wxpngd.lib;wxzlibd.lib;wxjpegd.lib;wxtiffd.lib;comctl32.lib;rpcrt4.lib;wsock32.lib;winmm.lib;oleacc.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;%(AdditionalDependencies) + $(OutDir);$(WXWIN3)\lib\vc_dll;$(GSTREAMER_SDK)\lib;%(AdditionalLibraryDirectories) + true + Windows + 8388608 + false + + + MachineX86 + + + + + + + + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(IntDir)%(Filename)1.obj + $(IntDir)%(Filename)1.obj + $(IntDir)%(Filename)1.xdc + $(IntDir)%(Filename)1.xdc + $(IntDir)%(Filename)1.obj + $(IntDir)%(Filename)1.obj + $(IntDir)%(Filename)1.xdc + $(IntDir)%(Filename)1.xdc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\rawwaves\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + Document + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + + + + + {5284d863-3813-479f-bbf0-ac234e216bc6} + false + + + {b28c9f3f-ff0e-4fec-844c-685390b8ac06} + false + + + {6c7dc635-26fb-419a-b69a-7ecbbb068245} + false + + + {d96c7be1-e3f1-4767-bbbb-320e082ce425} + false + + + {a52bbea5-8b02-4147-8734-5d9bbf4d1177} + false + + + {7aa41bed-41b0-427a-9148-dea40549d158} + false + + + {a939aaf8-44f1-4ce7-9dd0-7a6e99814857} + false + + + {f00717f2-67c8-44e1-af00-541dfa9cb7f2} + false + + + {c0fe933b-4af7-4acd-95e8-acd3a73f1400} + false + + + {f4b4a272-4ed3-4951-a6ee-b7baac1c4952} + false + + + {af9ad75c-4785-4432-bac3-adab1e7f1192} + false + + + {a61e2bf1-21aa-4118-b0d8-fd3d53db892e} + false + + + {727d6675-67ee-4d0b-9dc1-177a0af741f0} + false + + + {0fec8848-e24e-4fa5-9acd-e4582dc4cbbe} + false + + + {7aba0f80-94ae-4e82-ab89-2e1258212d59} + false + + + {d5ab2d87-51dc-4277-a9ab-2a6018d0e947} + false + + + {3a76129b-55ab-4d54-baa7-08f63ed52569} + false + + + {8a1c2514-85dd-4ae2-9cf3-3183b66c537d} + false + + + {a64ffb5d-0cf0-43ee-9de3-c72260864bff} + false + + + {ec3f5835-c486-4970-8a6b-a0700f4b3637} + false + + + {8c69f7b6-684f-48d9-9057-8912ca3daa8b} + false + + + + + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + copy /Y %(Identity) ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + ..\..\$(IntDir)\Nyquist\%(Filename)%(Extension) + + + + + + \ No newline at end of file diff --git a/win/Projects/Audacity/Audacity.vcxproj.filters b/win/Projects/Audacity/Audacity.vcxproj.filters index 83e03fe21..05e1e3dae 100755 --- a/win/Projects/Audacity/Audacity.vcxproj.filters +++ b/win/Projects/Audacity/Audacity.vcxproj.filters @@ -831,9 +831,7 @@ src/widgets - - src/effects - + @@ -1655,8 +1653,9 @@ src/widgets - - src/effects + + + includes\audacity