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