diff --git a/Makefile.in b/Makefile.in
index 41edc3c418ac7c90e737f1b39a6d239978bc6836..eda9edbcb9b273b50b8180f9d30dcb7972369aab 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -90,6 +90,22 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 subdir = .
+<<<<<<< HEAD
+=======
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+	$(top_srcdir)/configure $(am__configure_deps) $(dist_doc_DATA) \
+	$(dist_pkgdata_DATA) $(nobase_dist_pkgdata_DATA) ABOUT-NLS \
+	autotools/ar-lib autotools/compile autotools/config.guess \
+	autotools/config.rpath autotools/config.sub autotools/depcomp \
+	autotools/install-sh autotools/missing autotools/ltmain.sh \
+	$(top_srcdir)/autotools/ar-lib \
+	$(top_srcdir)/autotools/config.guess \
+	$(top_srcdir)/autotools/config.rpath \
+	$(top_srcdir)/autotools/config.sub \
+	$(top_srcdir)/autotools/install-sh \
+	$(top_srcdir)/autotools/ltmain.sh \
+	$(top_srcdir)/autotools/missing
+>>>>>>> upstream/master
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ac_c99_func_lrint.m4 \
 	$(top_srcdir)/m4/ac_c99_func_lrintf.m4 \
@@ -902,16 +918,22 @@ dist-xz: distdir
 	$(am__post_remove_distdir)
 
 dist-tarZ: distdir
+<<<<<<< HEAD
 	@echo WARNING: "Support for distribution archives compressed with" \
 		       "legacy program 'compress' is deprecated." >&2
 	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+=======
+>>>>>>> upstream/master
 	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
 	$(am__post_remove_distdir)
 
 dist-shar: distdir
+<<<<<<< HEAD
 	@echo WARNING: "Support for shar distribution archives is" \
 	               "deprecated." >&2
 	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+=======
+>>>>>>> upstream/master
 	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
 	$(am__post_remove_distdir)
 
@@ -952,11 +974,18 @@ distcheck: dist
 	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
 	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
 	  && am__cwd=`pwd` \
+<<<<<<< HEAD
 	  && $(am__cd) $(distdir)/_build/sub \
 	  && ../../configure \
 	    $(AM_DISTCHECK_CONFIGURE_FLAGS) \
 	    $(DISTCHECK_CONFIGURE_FLAGS) \
 	    --srcdir=../.. --prefix="$$dc_install_base" \
+=======
+	  && $(am__cd) $(distdir)/_build \
+	  && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+	    $(AM_DISTCHECK_CONFIGURE_FLAGS) \
+	    $(DISTCHECK_CONFIGURE_FLAGS) \
+>>>>>>> upstream/master
 	  && $(MAKE) $(AM_MAKEFLAGS) \
 	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
 	  && $(MAKE) $(AM_MAKEFLAGS) check \
diff --git a/images/Cursors.h b/images/Cursors.h
index 83da26ff38cfd37881ef96cf05793e6bddbb7278..cb7d51f8338ca4eac0616f26dee6aaeb84ed86a9 100644
--- a/images/Cursors.h
+++ b/images/Cursors.h
@@ -56,3 +56,5 @@
 #endif
 
 #endif
+
+wxCursor * MakeCursor(int WXUNUSED(CursorId), const char * pXpm[36], int HotX, int HotY);
diff --git a/mac/Audacity.xcodeproj/project.pbxproj b/mac/Audacity.xcodeproj/project.pbxproj
index e5d651dda01de65816d2eec00c35d84090c6ecca..9957af97d7cc1dac581cb43ff5c01d444f6266d2 100644
--- a/mac/Audacity.xcodeproj/project.pbxproj
+++ b/mac/Audacity.xcodeproj/project.pbxproj
@@ -842,6 +842,7 @@
 		288A544B1346D1BA0050D774 /* chanmap.c in Sources */ = {isa = PBXBuildFile; fileRef = 288A54481346D1BA0050D774 /* chanmap.c */; };
 		288A544C1346D1BA0050D774 /* chanmap.h in Headers */ = {isa = PBXBuildFile; fileRef = 288A54491346D1BA0050D774 /* chanmap.h */; };
 		288A544D1346D1BA0050D774 /* id3.c in Sources */ = {isa = PBXBuildFile; fileRef = 288A544A1346D1BA0050D774 /* id3.c */; };
+		2890498E1B6716B40038A543 /* SpectrogramSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2890498C1B6716B40038A543 /* SpectrogramSettings.cpp */; };
 		2891B2870C531D2C0044FBE3 /* FindClipping.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2891B2850C531D2C0044FBE3 /* FindClipping.cpp */; };
 		2892CE24131AFAE200E1E17D /* LICENSE.txt in Install miscellany */ = {isa = PBXBuildFile; fileRef = 288F0977131A3EE00008E860 /* LICENSE.txt */; };
 		2892CE25131AFAEF00E1E17D /* README.txt in Install miscellany */ = {isa = PBXBuildFile; fileRef = 288F097A131A3F130008E860 /* README.txt */; };
@@ -2072,6 +2073,7 @@
 		280A8B4619F4403B0091DE70 /* ModuleManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModuleManager.h; sourceTree = "<group>"; };
 		280A8B4819F440880091DE70 /* EffectRack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EffectRack.cpp; sourceTree = "<group>"; };
 		280A8B4919F440880091DE70 /* EffectRack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EffectRack.h; sourceTree = "<group>"; };
+		280F5C8B1B676699003022C5 /* NumberScale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NumberScale.h; sourceTree = "<group>"; };
 		28105D9B0AD09FB200BB4269 /* portmixer.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.c.h; path = portmixer.h; sourceTree = "<group>"; tabWidth = 3; };
 		28105DA00AD09FC500BB4269 /* px_mac_coreaudio.c */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.c.c; path = px_mac_coreaudio.c; sourceTree = "<group>"; tabWidth = 3; };
 		28105DA10AD09FC500BB4269 /* px_mixer.c */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.c.c; path = px_mixer.c; sourceTree = "<group>"; tabWidth = 3; };
@@ -2550,6 +2552,8 @@
 		288A544A1346D1BA0050D774 /* id3.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; path = id3.c; sourceTree = "<group>"; };
 		288F0977131A3EE00008E860 /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; name = LICENSE.txt; path = ../LICENSE.txt; sourceTree = "<group>"; };
 		288F097A131A3F130008E860 /* README.txt */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = text; name = README.txt; path = ../README.txt; sourceTree = "<group>"; };
+		2890498C1B6716B40038A543 /* SpectrogramSettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpectrogramSettings.cpp; sourceTree = "<group>"; };
+		2890498D1B6716B40038A543 /* SpectrogramSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpectrogramSettings.h; sourceTree = "<group>"; };
 		2891B2850C531D2C0044FBE3 /* FindClipping.cpp */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.cpp.cpp; path = FindClipping.cpp; sourceTree = "<group>"; tabWidth = 3; };
 		2891B2860C531D2C0044FBE3 /* FindClipping.h */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.c.h; path = FindClipping.h; sourceTree = "<group>"; tabWidth = 3; };
 		28948425101DF8FC005B0713 /* EffectsPrefs.cpp */ = {isa = PBXFileReference; fileEncoding = 5; indentWidth = 3; lastKnownFileType = sourcecode.cpp.cpp; path = EffectsPrefs.cpp; sourceTree = "<group>"; tabWidth = 3; };
@@ -3880,6 +3884,7 @@
 				280A8B4619F4403B0091DE70 /* ModuleManager.h */,
 				1790B0AF09883BFD008A330A /* NoteTrack.cpp */,
 				1790B0B009883BFD008A330A /* NoteTrack.h */,
+				280F5C8B1B676699003022C5 /* NumberScale.h */,
 				EDF3B7AF1588C0D50032D35F /* Paulstretch.cpp */,
 				EDF3B7AE1588C0D50032D35F /* Paulstretch.h */,
 				1790B0B109883BFD008A330A /* PitchName.cpp */,
@@ -4226,6 +4231,8 @@
 				1790B0CA09883BFD008A330A /* SpectrumPrefs.cpp */,
 				1790B0CB09883BFD008A330A /* SpectrumPrefs.h */,
 				28456AC00A2C180E00C23C1E /* ThemePrefs.cpp */,
+				2890498C1B6716B40038A543 /* SpectrogramSettings.cpp */,
+				2890498D1B6716B40038A543 /* SpectrogramSettings.h */,
 				28456AC10A2C180E00C23C1E /* ThemePrefs.h */,
 				284B27E00FC66CCD005EAC96 /* TracksPrefs.cpp */,
 				284B27E10FC66CCD005EAC96 /* TracksPrefs.h */,
@@ -7528,6 +7535,8 @@
 				28D000A51A32920C00367B21 /* DeviceChange.cpp in Sources */,
 				28D8425C1AD8D69D00551353 /* SelectedRegion.cpp in Sources */,
 				2888A1631AE25F9A00E06FDC /* Diags.cpp in Sources */,
+				28DDE3A21AE3771100C784FE /* ViewInfo.cpp in Sources */,
+				2890498E1B6716B40038A543 /* SpectrogramSettings.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/plug-ins/SpectralEditMulti.ny b/plug-ins/SpectralEditMulti.ny
index 57175dcf72bc68a5f09f2eb461ae82c1653b431b..c609fd20d821a9d79191f9723677e13b6bf1c9d8 100644
--- a/plug-ins/SpectralEditMulti.ny
+++ b/plug-ins/SpectralEditMulti.ny
@@ -45,7 +45,5 @@
       (T  (sum (prod env (wet sig f0 f1 fc))
                (prod (diff 1.0 env) sig))))))
 
-(if (string-not-equal (get '*TRACK* 'VIEW) "spectral"  :end1 8 :end2 8)
-    "Use this effect in the 'Spectral Selection'\nor 'Spectral Selection log(f)' view."
-    (catch 'error-message
-      (multichan-expand #'result *track*)))
+(catch 'error-message
+  (multichan-expand #'result *track*))
diff --git a/plug-ins/SpectralEditParametricEQ.ny b/plug-ins/SpectralEditParametricEQ.ny
index 20d7403bd2c0729cd59426d95eebfd73253d5fab..45671cf6d3d543c196cabd73d54c57be2531a6c1 100644
--- a/plug-ins/SpectralEditParametricEQ.ny
+++ b/plug-ins/SpectralEditParametricEQ.ny
@@ -19,20 +19,23 @@
 
 (defmacro validate (hz)
 "Ensure frequency is below Nyquist"
-  `(setf hz (min (/ *sound-srate* 2.0),hz)))
+  `(setf ,hz (max 0 (min (/ *sound-srate* 2.0) ,hz))))
 
 (defun wet (sig gain f0 f1)
   ;; (re)calculate bw and fc to ensure we do not exceed Nyquist frequency
-  (let ((fc (sqrt (* f0 (validate f1))))
-       (bw (/ (log (/ (validate f1) f0))
-              (log 2.0))))
+  (validate f0)
+  (validate f1)
+  (let ((fc (sqrt (* f0 f1)))
+	(bw (/ (log (/ f1 f0))
+	       (log 2.0))))
+    (when (= bw 0)
+      (throw 'error-message (format nil "~aBandwidth is zero.~%Select a frequency range." p-err)))
     (eq-band sig fc gain (/ bw 2))))
 
 (defun result (sig)
   (let*
       ((f0 (get '*selection* 'low-hz))
        (f1 (get '*selection* 'high-hz))
-       (bw (get '*selection* 'bandwidth))
        (tn (truncate len))
        (rate (snd-srate sig))
        (transition (truncate (* 0.01 rate)))  ; 10 ms
@@ -43,26 +46,16 @@
     (cond
       ((not (or f0 f1))
         (throw 'error-message (format nil "~aPlease select frequencies." p-err)))
-      ((not f0)
+      ((or (not f0) (= f0 0))
          (throw 'error-message (format nil "~aLow frequency is undefined." p-err)))
       ((not f1)
          (throw 'error-message (format nil "~aHigh frequency is undefined." p-err)))
-      ((= bw 0)
-         (throw 'error-message (format nil "~aBandwidth is zero.~%Select a frequency range." p-err)))
       ;; If seleted frequency band is above Nyquist, do nothing.
       ((< f0 (/ *sound-srate* 2.0))
           (sum (prod env (wet sig control-gain f0 f1)) (prod (diff 1.0 env) sig))))))
 
-(cond
-  ((not (get '*TRACK* 'VIEW)) ; 'View is NIL during Preview
-      (setf p-err (format nil "This effect requires a frequency selection in the~%~
-                              'Spectrogram' or 'Spectrogram (log f)' track view.~%~%"))
-      (catch 'error-message
-        (multichan-expand #'result *track*)))
-  ((string-not-equal (get '*TRACK* 'VIEW) "spectral"  :end1 8 :end2 8)
-      "Use this effect in the 'Spectral Selection'\nor 'Spectral Selection log(f)' view.")
-  (T  (setf p-err "")
-      (if (= control-gain 0)  ; Allow dry preview
-          "Gain is zero. Nothing to do."
-          (catch 'error-message
-            (multichan-expand #'result *track*)))))
+(catch 'error-message
+  (setf p-err "")
+  (if (= control-gain 0)		; Allow dry preview
+      "Gain is zero. Nothing to do."
+    (multichan-expand #'result *track*)))
diff --git a/plug-ins/SpectralEditShelves.ny b/plug-ins/SpectralEditShelves.ny
index ff6c4060a5e1edc114895a61be49bbaebaa1dd23..6f523023cbf1bb4f2ad693dcfb820da356645567 100644
--- a/plug-ins/SpectralEditShelves.ny
+++ b/plug-ins/SpectralEditShelves.ny
@@ -19,7 +19,7 @@
 
 (defmacro validate (hz)
 "Ensure frequency is below Nyquist"
-  `(setf hz (min (/ *sound-srate* 2.0),hz)))
+  `(setf ,hz (max 0 (min (/ *sound-srate* 2.0) ,hz))))
 
 (defun mid-shelf (sig lf hf gain)
   "Combines high shelf and low shelf filters"
@@ -30,9 +30,14 @@
 
 (defun wet (sig gain f0 f1)
   (cond
-    ((not f0) (eq-lowshelf sig f1 gain))
-    ((not f1) (eq-highshelf sig f0 gain))
-    (t (mid-shelf sig f0 (validate f1) gain))))
+   ((not f0) (eq-lowshelf sig (validate f1) gain))
+   ((not f1) (eq-highshelf sig (validate f0) gain))
+   (t
+    (validate f0)
+    (validate f1)
+    (when (= f0 f1)
+      (throw 'error-message "Please select a frequency range."))
+    (mid-shelf sig f0 f1 gain))))
 
 (defun result (sig)
   (let*
@@ -48,8 +53,6 @@
     (cond
       ((not (or f0 f1))
           (throw 'error-message (format nil "~aPlease select frequencies." p-err)))
-      ((and f0 f1 (= f0 f1)) (throw 'error-message
-                                    "Please select a frequency range."))
       ; shelf is above Nyquist frequency so do nothing
       ((and f0 (>= f0 (/ *sound-srate* 2.0))) nil)
       (T (sum (prod env (wet sig control-gain f0 f1))
@@ -63,18 +66,9 @@
          (>= (get '*selection* 'high-hz)(/ *sound-srate* 2)))
     (remprop '*selection* 'high-hz))
 
-(cond
-  ((not (get '*TRACK* 'VIEW)) ; 'View is NIL during Preview
-      (setf p-err (format nil "This effect requires a frequency selection in the~%~
-                              'Spectral Selection' or 'Spectral Selection log(f)'~%~
-                              track view.~%~%"))
-      (catch 'error-message
-        (multichan-expand #'result *track*)))
-  ((string-not-equal (get '*TRACK* 'VIEW) "spectral"  :end1 8 :end2 8)
-     "Use this effect in the 'Spectral Selection'\nor 'Spectral Selection log(f)' view.")
-  (T  (setf p-err "")
-      (if (= control-gain 0)  ; Allow dry preview
-          "Gain is zero. Nothing to do."
-          (catch 'error-message
-            (multichan-expand #'result *track*)))))
+(catch 'error-message
+  (setf p-err "")
+  (if (= control-gain 0)		; Allow dry preview
+      "Gain is zero. Nothing to do."
+    (multichan-expand #'result *track*)))
 
diff --git a/src/Audacity.h b/src/Audacity.h
index 7b934bca42e4339331488e8a86a66566d937554f..1ad029cbb2da17da7cbd4eead62a35320f840915 100644
--- a/src/Audacity.h
+++ b/src/Audacity.h
@@ -152,8 +152,11 @@ void QuitAudacity();
    #endif
 #endif
 
-// This macro is used widely, so declared here.
-#define QUANTIZED_TIME(time, rate) ((double)((sampleCount)floor(((double)(time) * (rate)) + 0.5))) / (rate)
+// These macros are used widely, so declared here.
+#define QUANTIZED_TIME(time, rate) (((double)((sampleCount)floor(((double)(time) * (rate)) + 0.5))) / (rate))
+// dB - linear amplitude convesions
+#define DB_TO_LINEAR(x) (pow(10.0, (x) / 20.0))
+#define LINEAR_TO_DB(x) (20.0 * log10(x))
 
 // Marks strings for extraction only...must use wxGetTranslation() to translate.
 #define XO(s) wxT(s)
diff --git a/src/AudacityApp.cpp b/src/AudacityApp.cpp
index d4b3ebc1d145f436cba72863d07d7e84634b89d8..97b7ee0c0743b18c840ec477da54bd5df2d99705 100644
--- a/src/AudacityApp.cpp
+++ b/src/AudacityApp.cpp
@@ -92,6 +92,9 @@ It handles initialization and termination by subclassing wxApp.
 #include "ondemand/ODManager.h"
 #include "commands/Keyboard.h"
 #include "widgets/ErrorDialog.h"
+#include "prefs/DirectoriesPrefs.h"
+#include "prefs/SpectrogramSettings.h"
+#include "prefs/WaveformSettings.h"
 
 //temporarilly commented out till it is added to all projects
 //#include "Profiler.h"
@@ -123,9 +126,7 @@ It handles initialization and termination by subclassing wxApp.
 // Windows specific linker control...only needed once so
 // this is a good place (unless we want to add another file).
 #if defined(__WXMSW__)
-//#if wxCHECK_VERSION(3, 0, 2) && !wxCHECK_VERSION(3, 1, 0)
-#include <wx/init.h>
-//#endif
+
 // These lines ensure that Audacity gets WindowsXP themes.
 // Without them we get the old-style Windows98/2000 look under XP.
 #  if !defined(__WXWINCE__)
@@ -209,15 +210,6 @@ It handles initialization and termination by subclassing wxApp.
 #  if defined(EXPERIMENTAL_CRASH_REPORT)
 #     pragma comment(lib, "wxmsw" V "u" D "_qa")
 #  endif
-#  pragma comment(lib, "wxbase" V "u" D)
-#  pragma comment(lib, "wxbase" V "u" D "_net.lib")
-#  pragma comment(lib, "wxmsw"  V "u" D "_adv.lib")
-#  pragma comment(lib, "wxmsw"  V "u" D "_core.lib")
-#  pragma comment(lib, "wxmsw"  V "u" D "_html.lib")
-#  pragma comment(lib, "wxpng"        D)
-#  pragma comment(lib, "wxzlib"       D)
-#  pragma comment(lib, "wxjpeg"       D)
-#  pragma comment(lib, "wxtiff"       D)
 
 #  undef V
 #  undef D
@@ -231,6 +223,9 @@ It handles initialization and termination by subclassing wxApp.
 ////////////////////////////////////////////////////////////
 
 DEFINE_EVENT_TYPE(EVT_OPEN_AUDIO_FILE);
+DEFINE_EVENT_TYPE(EVT_CAPTURE_KEYBOARD);
+DEFINE_EVENT_TYPE(EVT_RELEASE_KEYBOARD);
+DEFINE_EVENT_TYPE(EVT_CAPTURE_KEY);
 
 #ifdef __WXGTK__
 static void wxOnAssert(const wxChar *fileName, int lineNumber, const wxChar *msg)
@@ -249,6 +244,8 @@ static void wxOnAssert(const wxChar *fileName, int lineNumber, const wxChar *msg
 }
 #endif
 
+static wxFrame *gParentFrame = NULL;
+
 static bool gInited = false;
 bool gIsQuitting = false;
 
@@ -259,8 +256,6 @@ void QuitAudacity(bool bForce)
 
    gIsQuitting = true;
 
-   wxTheApp->SetExitOnFrameDelete(true);
-
    // Try to close each open window.  If the user hits Cancel
    // in a Save Changes dialog, don't continue.
    // BG: unless force is true
@@ -295,8 +290,14 @@ void QuitAudacity(bool bForce)
       }
    }
 
+   LWSlider::DeleteSharedTipPanel();
+
    ModuleManager::Get().Dispatch(AppQuiting);
 
+   if (gParentFrame)
+      gParentFrame->Destroy();
+   gParentFrame = NULL;
+
 #ifdef EXPERIMENTAL_SCOREALIGN
    CloseScoreAlignDialog();
 #endif
@@ -648,12 +649,12 @@ public:
    };
 };
 
-#if !defined(__WXMAC__) && !defined(__WXMSW__)
+#ifndef __WXMAC__
 IMPLEMENT_APP(AudacityApp)
 /* make the application class known to wxWidgets for dynamic construction */
 #endif
 
-#if defined(__WXMAC__) || defined(__WXMSW__)
+#ifdef __WXMAC__
 // This should be removed when Lame and FFmpeg support is converted
 // from loadable libraries to commands.
 //
@@ -668,8 +669,6 @@ IMPLEMENT_APP(AudacityApp)
 // one tried.
 IMPLEMENT_APP_NO_MAIN(AudacityApp)
 IMPLEMENT_WX_THEME_SUPPORT
-
-#if defined(__WXMAC__)
 int main(int argc, char *argv[])
 {
    if (getenv("DYLD_LIBRARY_PATH")) {
@@ -678,31 +677,8 @@ int main(int argc, char *argv[])
       unsetenv("DYLD_LIBRARY_PATH");
       execve(argv[0], argv, environ);
    }
-
-   wxDISABLE_DEBUG_SUPPORT();
-
    return wxEntry(argc, argv);
 }
-
-#elif defined(__WXMSW__)
-
-extern "C" int WINAPI WinMain(HINSTANCE hInstance,
-                              HINSTANCE hPrevInstance,
-                              wxCmdLineArgType WXUNUSED(lpCmdLine),
-                              int nCmdShow)
-{
-   wxDISABLE_DEBUG_SUPPORT();
-
-   // Disable setting of HiDPI aware mode
-   wxMSWDisableSettingHighDPIAware();
-
-   /* NB: We pass NULL in place of lpCmdLine to behave the same as  */
-   /*     Borland-specific wWinMain() above. If it becomes needed   */
-   /*     to pass lpCmdLine to wxEntry() here, you'll have to fix   */
-   /*     wWinMain() above too.                                     */
-   return wxEntry(hInstance, hPrevInstance, NULL, nCmdShow);
-}
-#endif
 #endif
 
 #ifdef __WXMAC__
@@ -1012,12 +988,11 @@ void AudacityApp::InitLang( const wxString & lang )
    wxSetEnv(wxT("LANG"), wxT("en_US.UTF-8"));
 #endif
 
-   const wxLanguageInfo *info = wxLocale::FindLanguageInfo(lang);
-   if (!lang)
-   {
-      return;
-   }
-   mLocale = new wxLocale(info->Language);
+#if wxCHECK_VERSION(3,0,0)
+   mLocale = new wxLocale(wxT(""), lang, wxT(""), true);
+#else
+   mLocale = new wxLocale(wxT(""), lang, wxT(""), true, true);
+#endif
 
    for(unsigned int i=0; i<audacityPathList.GetCount(); i++)
       mLocale->AddCatalogLookupPathPrefix(audacityPathList[i]);
@@ -1038,7 +1013,12 @@ void AudacityApp::InitLang( const wxString & lang )
    //
    // This must go _after_ creating the wxLocale instance because
    // creating the wxLocale instance sets the application-wide locale.
+
    Internat::Init();
+
+   // Some static arrays unconnected with any project want to be informed of language changes.
+   SpectrogramSettings::InvalidateNames();
+   WaveformSettings::InvalidateNames();
 }
 
 void AudacityApp::OnFatalException()
@@ -1096,16 +1076,16 @@ void AudacityApp::GenerateCrashReport(wxDebugReport::Context ctx)
 }
 #endif
 
+#if defined(__WXGTK__)
+// On wxGTK, there's a focus issue where dialogs do not automatically pass focus
+// to the first child.  This means that you can use the keyboard to navigate within
+// the dialog.  Watching for the ACTIVATE event allows us to set the focus ourselves
+// when each dialog opens.
+//
+// See bug #57
+//
 int AudacityApp::FilterEvent(wxEvent & event)
 {
-#if !wxCHECK_VERSION(3, 0, 0) && defined(__WXGTK__)
-   // On wxGTK, there's a focus issue where dialogs do not automatically pass focus
-   // to the first child.  This means that you can use the keyboard to navigate within
-   // the dialog.  Watching for the ACTIVATE event allows us to set the focus ourselves
-   // when each dialog opens.
-   //
-   // See bug #57
-   //
    if (event.GetEventType() == wxEVT_ACTIVATE)
    {
       wxActivateEvent & e = (wxActivateEvent &) event;
@@ -1115,11 +1095,10 @@ int AudacityApp::FilterEvent(wxEvent & event)
          ((wxWindow *)e.GetEventObject())->SetFocus();
       }
    }
-   break;
-#endif
 
-   return Event_Skip;
+   return -1;
 }
+#endif
 
 AudacityApp::AudacityApp()
 {
@@ -1137,9 +1116,6 @@ AudacityApp::AudacityApp()
 // main frame
 bool AudacityApp::OnInit()
 {
-   // Ensure we have an event loop during initialization
-   wxEventLoopGuarantor eventLoop;
-
    delete wxLog::SetActiveTarget(new AudacityLogger);
 
    mLocale = NULL;
@@ -1150,6 +1126,11 @@ bool AudacityApp::OnInit()
    mChecker = NULL;
    mIPCServ = NULL;
 
+#if defined(__WXGTK__)
+   // Workaround for bug 154 -- initialize to false
+   inKbdHandler = false;
+#endif
+
 #if defined(__WXMAC__)
    // Disable window animation
    wxSystemOptions::SetOption( wxMAC_WINDOW_PLAIN_TRANSITION, 1 );
@@ -1299,6 +1280,15 @@ bool AudacityApp::OnInit()
 // If we're waiitng in a dialog before then we can very easily
 // start multiple instances, defeating the single instance checker.
 
+
+
+
+   //JKC We'd like to initialise the module manager WHILE showing the splash screen.
+   //Can't in wx3.0.1 as MultiDialog interacts poorly with the splash screen.  So we do it before.
+   //TODO: Find out why opening a multidialog wrecks the splash screen.
+   //best current guess is that it's something to do with doing a DoModal this early
+   //in the program.
+
    // Initialize the CommandHandler
    InitCommandHandler();
 
@@ -1308,6 +1298,64 @@ bool AudacityApp::OnInit()
    // Initialize the ModuleManager, including loading found modules
    ModuleManager::Get().Initialize(*mCmdHandler);
 
+#if !wxCHECK_VERSION(3, 0, 0)
+   FinishInits();
+#endif
+
+   return TRUE;
+}
+
+#if wxCHECK_VERSION(3, 0, 0)
+#include <wx/evtloop.h>
+static bool bInitsDone = false;
+void AudacityApp::OnEventLoopEnter(wxEventLoopBase * pLoop)
+{
+   if( !pLoop->IsMain() )
+      return;
+   if (bInitsDone)
+      return;
+   bInitsDone = true;
+   FinishInits();
+}
+#endif
+
+// JKC: I've split 'FinishInits()' from 'OnInit()', so that 
+// we can have a real event loop running.  We could (I think) 
+// put everything that is in OnInit() in here.
+// This change was to support wxWidgets 3.0.0 and allow us
+// to show a dialog (for module loading) during initialisation.
+// without it messing up the splash screen.
+// Hasn't actually fixed that yet, but is addressing the point
+// they make in their release notes.
+void AudacityApp::FinishInits()
+{
+
+// Until we are ready for wxWidgets 3.x, put a warning dialog up.
+// Our problem is that distros may ship with 3.x builds as default.
+// We are saying, don't.
+//
+// wx3 is Ok for experimental builds.  
+//
+// Deliberately not translated.  People can search for the english error
+// text for more details.  This error will only show in versions
+// of Audacity that were incorrectly built.
+//
+// The intention was to do this, if needed, as part of the splash screen.
+// However the splash screen is one of the things broken by wx3.0
+// changes in OnInit handling.  We also can't put this dialog earlier.
+#if wxCHECK_VERSION(3, 0, 0)
+   ShowErrorDialog( NULL,
+                    wxT("Bad Version"),
+                    wxT(
+"Audacity should be built with wxWidgets 2.8.12.\n\n  This version \
+of Audacity (") AUDACITY_VERSION_STRING wxT(") is using ")  wxVERSION_STRING  \
+wxT( ".\n  We're not ready for that version of wxWidgets yet.\n\n  \
+Click the 'Help' button for known issues."),
+                    wxT("http://wiki.audacityteam.org/wiki/Incorrect_wxWidgets_Version"),
+                     true);
+#endif
+
+
    // Parse command line and handle options that might require
    // immediate exit...no need to initialize all of the audio
    // stuff to display the version string.
@@ -1357,6 +1405,9 @@ bool AudacityApp::OnInit()
       exit(1);
    }
 
+// No Splash screen on wx3 whislt we sort out the problem
+// with showing a dialog AND a splash screen during inits.
+#if !wxCHECK_VERSION(3, 0, 0)
    // BG: Create a temporary window to set as the top window
    wxImage logoimage((const char **) AudacityLogoWithName_xpm);
    logoimage.Rescale(logoimage.GetWidth() / 2, logoimage.GetHeight() / 2);
@@ -1373,7 +1424,7 @@ bool AudacityApp::OnInit()
                          wxSTAY_ON_TOP);
    temporarywindow->SetTitle(_("Audacity is starting up..."));
    SetTopWindow(temporarywindow);
-   wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI);
+#endif
 
    //JKC: Would like to put module loading here.
 
@@ -1403,10 +1454,15 @@ bool AudacityApp::OnInit()
    mRecentFiles->UseMenu(recentMenu);
    mRecentFiles->AddFilesToMenu(recentMenu);
 
-   SetExitOnFrameDelete(false);
+   // This invisibale frame will be the "root" of all other frames and will
+   // become the active frame when no projects are open.
+   gParentFrame = new wxFrame(NULL, -1, wxEmptyString, wxPoint(0, 0), wxSize(0, 0), 0);
 
 #endif //__WXMAC__
 
+   SetExitOnFrameDelete(true);
+
+
    AudacityProject *project = CreateNewAudacityProject();
    mCmdHandler->SetProject(project);
    wxWindow * pWnd = MakeHijackPanel() ;
@@ -1418,8 +1474,11 @@ bool AudacityApp::OnInit()
       pWnd->Show( true );
    }
 
+
+#if !wxCHECK_VERSION(3, 0, 0)
    temporarywindow->Show(false);
    delete temporarywindow;
+#endif
 
    if( project->mShowSplashScreen )
       project->OnHelpWelcome();
@@ -1447,7 +1506,7 @@ bool AudacityApp::OnInit()
       DirManager::SetDontDeleteTempFiles();
       delete parser;
       QuitAudacity(true);
-      return false;
+      return;
    }
 
    //
@@ -1460,7 +1519,7 @@ bool AudacityApp::OnInit()
          delete parser;
    
          RunBenchmark(NULL);
-         return false;
+         return;
       }
 
       for (size_t i = 0, cnt = parser->GetParamCount(); i < cnt; i++)
@@ -1479,8 +1538,6 @@ bool AudacityApp::OnInit()
 
    mTimer.SetOwner(this, kAudacityAppTimerID);
    mTimer.Start(200);
-
-   return TRUE;
 }
 
 void AudacityApp::InitCommandHandler()
@@ -1556,8 +1613,11 @@ bool AudacityApp::InitTempDir()
       // Failed
       wxMessageBox(_("Audacity could not find a place to store temporary files.\nPlease enter an appropriate directory in the preferences dialog."));
 
-      PrefsDialog dialog(NULL);
-      dialog.ShowTempDirPage();
+      // Only want one page of the preferences
+      DirectoriesPrefsFactory directoriesPrefsFactory;
+      PrefsDialog::Factories factories;
+      factories.push_back(&directoriesPrefsFactory);
+      GlobalPrefsDialog dialog(NULL, factories);
       dialog.ShowModal();
 
       wxMessageBox(_("Audacity is now going to exit. Please launch Audacity again to use the new temporary directory."));
@@ -2083,7 +2143,7 @@ void AudacityApp::OnMenuPreferences(wxCommandEvent & event)
    // all platforms.
 
    if(gAudacityProjects.GetCount() == 0) {
-      PrefsDialog dialog(NULL /* parent */ );
+      GlobalPrefsDialog dialog(NULL /* parent */ );
       dialog.ShowModal();
    }
    else
diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp
index b8c6c29069e6093245a76abe97ae4decbe26e12e..cfcaaac07cbd887fdda31a7f85d0e7f4e36812cc 100644
--- a/src/AudioIO.cpp
+++ b/src/AudioIO.cpp
@@ -265,8 +265,9 @@ writing audio.
 *//*******************************************************************/
 
 #include "Audacity.h"
-#include "float_cast.h"
 #include "Experimental.h"
+#include "AudioIO.h"
+#include "float_cast.h"
 
 #include <math.h>
 #include <stdlib.h>
@@ -294,11 +295,11 @@ writing audio.
 #include <wx/txtstrm.h>
 
 #include "AudacityApp.h"
-#include "AudioIO.h"
 #include "Mix.h"
 #include "MixerBoard.h"
 #include "Resample.h"
 #include "RingBuffer.h"
+#include "prefs/GUISettings.h"
 #include "Prefs.h"
 #include "Project.h"
 #include "TimeTrack.h"
@@ -308,8 +309,6 @@ writing audio.
 #include "toolbars/ControlToolBar.h"
 #include "widgets/Meter.h"
 
-#include "Experimental.h"
-
 #ifdef EXPERIMENTAL_MIDI_OUT
    #define MIDI_SLEEP 10 /* milliseconds */
    #define ROUND(x) (int) ((x)+0.5)
@@ -856,6 +855,8 @@ bool AudioIO::ValidateDeviceNames(wxString play, wxString rec)
 
 AudioIO::AudioIO()
 {
+   mCaptureTracks = mPlaybackTracks = NULL;
+
    mAudioThreadShouldCallFillBuffersOnce = false;
    mAudioThreadFillBuffersLoopRunning = false;
    mAudioThreadFillBuffersLoopActive = false;
@@ -992,6 +993,9 @@ AudioIO::~AudioIO()
 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
    delete mScrubQueue;
 #endif
+
+   delete mCaptureTracks;
+   delete mPlaybackTracks;
 }
 
 void AudioIO::SetMixer(int inputSource)
@@ -1525,11 +1529,11 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
    int silenceLevelDB;
    gPrefs->Read(wxT("/AudioIO/SilenceLevel"), &silenceLevelDB, -50);
    int dBRange;
-   dBRange = gPrefs->Read(wxT("/GUI/EnvdBRange"), ENV_DB_RANGE);
+   dBRange = gPrefs->Read(ENV_DB_KEY, ENV_DB_RANGE);
    if(silenceLevelDB < -dBRange)
    {
       silenceLevelDB = -dBRange + 3;   // meter range was made smaller than SilenceLevel
-      gPrefs->Write(wxT("/GUI/EnvdBRange"), dBRange); // so set SilenceLevel reasonable
+      gPrefs->Write(ENV_DB_KEY, dBRange); // so set SilenceLevel reasonable
       gPrefs->Flush();
    }
    mSilenceLevel = (silenceLevelDB + dBRange)/(double)dBRange;  // meter goes -dBRange dB -> 0dB
@@ -1542,8 +1546,8 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
    mTime    = t0;
    mSeek    = 0;
    mLastRecordingOffset = 0;
-   mPlaybackTracks = playbackTracks;
-   mCaptureTracks  = captureTracks;
+   mPlaybackTracks = new WaveTrackArray(playbackTracks);
+   mCaptureTracks  = new WaveTrackArray(captureTracks);
 #ifdef EXPERIMENTAL_MIDI_OUT
    mMidiPlaybackTracks = midiPlaybackTracks;
 #endif
@@ -1563,7 +1567,7 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
    double minScrubStutter = options.minScrubStutter;
    if (scrubbing)
    {
-      if (mCaptureTracks.GetCount() > 0 ||
+      if (mCaptureTracks->GetCount() > 0 ||
           mPlayMode == PLAY_LOOPED ||
           mTimeTrack != NULL ||
           options.maxScrubSpeed < GetMinScrubSpeed())
@@ -1625,8 +1629,8 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
    // Capacity of the playback buffer.
    mPlaybackRingBufferSecs = 10.0;
 
-   mCaptureRingBufferSecs = 4.5 + 0.5 * std::min(size_t(16), mCaptureTracks.GetCount());
-   mMinCaptureSecsToCopy = 0.2 + 0.2 * std::min(size_t(16), mCaptureTracks.GetCount());
+   mCaptureRingBufferSecs = 4.5 + 0.5 * std::min(size_t(16), mCaptureTracks->GetCount());
+   mMinCaptureSecsToCopy = 0.2 + 0.2 * std::min(size_t(16), mCaptureTracks->GetCount());
 
    unsigned int playbackChannels = 0;
    unsigned int captureChannels = 0;
@@ -1641,7 +1645,7 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
    if( captureTracks.GetCount() > 0 )
    {
       // For capture, every input channel gets its own track
-      captureChannels = mCaptureTracks.GetCount();
+      captureChannels = mCaptureTracks->GetCount();
       // I don't deal with the possibility of the capture tracks
       // having different sample formats, since it will never happen
       // with the current code.  This code wouldn't *break* if this
@@ -1650,7 +1654,7 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
       // we would set the sound card to capture in 16 bits and the second
       // track wouldn't get the benefit of all 24 bits the card is capable
       // of.
-      captureFormat = mCaptureTracks[0]->GetSampleFormat();
+      captureFormat = (*mCaptureTracks)[0]->GetSampleFormat();
 
       // Tell project that we are about to start recording
       if (mListener)
@@ -1711,12 +1715,12 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
                return 0;
             }
 
-            mPlaybackBuffers = new RingBuffer* [mPlaybackTracks.GetCount()];
-            mPlaybackMixers  = new Mixer*      [mPlaybackTracks.GetCount()];
+            mPlaybackBuffers = new RingBuffer* [mPlaybackTracks->GetCount()];
+            mPlaybackMixers  = new Mixer*      [mPlaybackTracks->GetCount()];
 
             // Set everything to zero in case we have to delete these due to a memory exception.
-            memset(mPlaybackBuffers, 0, sizeof(RingBuffer*)*mPlaybackTracks.GetCount());
-            memset(mPlaybackMixers, 0, sizeof(Mixer*)*mPlaybackTracks.GetCount());
+            memset(mPlaybackBuffers, 0, sizeof(RingBuffer*)*mPlaybackTracks->GetCount());
+            memset(mPlaybackMixers, 0, sizeof(Mixer*)*mPlaybackTracks->GetCount());
 
             const Mixer::WarpOptions &warpOptions =
 #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
@@ -1724,12 +1728,12 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
 #endif
                Mixer::WarpOptions(mTimeTrack);
 
-            for (unsigned int i = 0; i < mPlaybackTracks.GetCount(); i++)
+            for (unsigned int i = 0; i < mPlaybackTracks->GetCount(); i++)
             {
                mPlaybackBuffers[i] = new RingBuffer(floatSample, playbackBufferSize);
 
                // MB: use normal time for the end time, not warped time!
-               mPlaybackMixers[i]  = new Mixer(1, &mPlaybackTracks[i],
+               mPlaybackMixers[i]  = new Mixer(1, &(*mPlaybackTracks)[i],
                                                warpOptions,
                                                mT0, mT1, 1,
                                                playbackMixBufferSize, false,
@@ -1753,17 +1757,17 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
                return 0;
             }
 
-            mCaptureBuffers = new RingBuffer* [mCaptureTracks.GetCount()];
-            mResample = new Resample* [mCaptureTracks.GetCount()];
+            mCaptureBuffers = new RingBuffer* [mCaptureTracks->GetCount()];
+            mResample = new Resample* [mCaptureTracks->GetCount()];
             mFactor = sampleRate / mRate;
 
             // Set everything to zero in case we have to delete these due to a memory exception.
-            memset(mCaptureBuffers, 0, sizeof(RingBuffer*)*mCaptureTracks.GetCount());
-            memset(mResample, 0, sizeof(Resample*)*mCaptureTracks.GetCount());
+            memset(mCaptureBuffers, 0, sizeof(RingBuffer*)*mCaptureTracks->GetCount());
+            memset(mResample, 0, sizeof(Resample*)*mCaptureTracks->GetCount());
 
-            for( unsigned int i = 0; i < mCaptureTracks.GetCount(); i++ )
+            for( unsigned int i = 0; i < mCaptureTracks->GetCount(); i++ )
             {
-               mCaptureBuffers[i] = new RingBuffer( mCaptureTracks[i]->GetSampleFormat(),
+               mCaptureBuffers[i] = new RingBuffer( (*mCaptureTracks)[i]->GetSampleFormat(),
                                                     captureBufferSize );
                mResample[i] = new Resample(true, mFactor, mFactor); // constant rate resampling
             }
@@ -1791,9 +1795,9 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
       // group determination should mimic what is done in audacityAudioCallback()
       // when calling RealtimeProcess().
       int group = 0;
-      for (size_t i = 0, cnt = mPlaybackTracks.GetCount(); i < cnt; i++)
+      for (size_t i = 0, cnt = mPlaybackTracks->GetCount(); i < cnt; i++)
       {
-         WaveTrack *vt = gAudioIO->mPlaybackTracks[i];
+         WaveTrack *vt = (*gAudioIO->mPlaybackTracks)[i];
 
          int chanCnt = 1;
          if (vt->GetLinked())
@@ -1815,7 +1819,7 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
       // Calculate the new time position
       mTime = std::max(mT0, std::min(mT1, *options.pStartTime));
       // Reset mixer positions for all playback tracks
-      unsigned numMixers = mPlaybackTracks.GetCount();
+      unsigned numMixers = mPlaybackTracks->GetCount();
       for (unsigned ii = 0; ii < numMixers; ++ii)
          mPlaybackMixers[ii]->Reposition(mTime);
       if(mTimeTrack)
@@ -1919,7 +1923,7 @@ void AudioIO::StartStreamCleanup(bool bOnlyBuffers)
 
    if(mPlaybackBuffers)
    {
-      for( unsigned int i = 0; i < mPlaybackTracks.GetCount(); i++ )
+      for( unsigned int i = 0; i < mPlaybackTracks->GetCount(); i++ )
          delete mPlaybackBuffers[i];
       delete [] mPlaybackBuffers;
       mPlaybackBuffers = NULL;
@@ -1927,7 +1931,7 @@ void AudioIO::StartStreamCleanup(bool bOnlyBuffers)
 
    if(mPlaybackMixers)
    {
-      for( unsigned int i = 0; i < mPlaybackTracks.GetCount(); i++ )
+      for( unsigned int i = 0; i < mPlaybackTracks->GetCount(); i++ )
          delete mPlaybackMixers[i];
       delete [] mPlaybackMixers;
       mPlaybackMixers = NULL;
@@ -1935,7 +1939,7 @@ void AudioIO::StartStreamCleanup(bool bOnlyBuffers)
 
    if(mCaptureBuffers)
    {
-      for( unsigned int i = 0; i < mCaptureTracks.GetCount(); i++ )
+      for( unsigned int i = 0; i < mCaptureTracks->GetCount(); i++ )
          delete mCaptureBuffers[i];
       delete [] mCaptureBuffers;
       mCaptureBuffers = NULL;
@@ -1943,7 +1947,7 @@ void AudioIO::StartStreamCleanup(bool bOnlyBuffers)
 
    if(mResample)
    {
-      for( unsigned int i = 0; i < mCaptureTracks.GetCount(); i++ )
+      for( unsigned int i = 0; i < mCaptureTracks->GetCount(); i++ )
          delete mResample[i];
       delete [] mResample;
       mResample = NULL;
@@ -2268,9 +2272,9 @@ void AudioIO::StopStream()
       // we allocated in StartStream()
       //
 
-      if( mPlaybackTracks.GetCount() > 0 )
+      if( mPlaybackTracks->GetCount() > 0 )
       {
-         for( unsigned int i = 0; i < mPlaybackTracks.GetCount(); i++ )
+         for( unsigned int i = 0; i < mPlaybackTracks->GetCount(); i++ )
          {
             delete mPlaybackBuffers[i];
             delete mPlaybackMixers[i];
@@ -2283,7 +2287,7 @@ void AudioIO::StopStream()
       //
       // Offset all recorded tracks to account for latency
       //
-      if( mCaptureTracks.GetCount() > 0 )
+      if( mCaptureTracks->GetCount() > 0 )
       {
          //
          // We only apply latency correction when we actually played back
@@ -2298,15 +2302,15 @@ void AudioIO::StopStream()
          double recordingOffset =
             mLastRecordingOffset + latencyCorrection / 1000.0;
 
-         for( unsigned int i = 0; i < mCaptureTracks.GetCount(); i++ )
+         for( unsigned int i = 0; i < mCaptureTracks->GetCount(); i++ )
             {
                delete mCaptureBuffers[i];
                delete mResample[i];
 
-               WaveTrack* track = mCaptureTracks[i];
+               WaveTrack* track = (*mCaptureTracks)[i];
                track->Flush();
 
-               if (mPlaybackTracks.GetCount() > 0)
+               if (mPlaybackTracks->GetCount() > 0)
                {  // only do latency correction if some tracks are being played back
                   WaveTrackArray playbackTracks;
                   AudacityProject *p = GetActiveProject();
@@ -2873,7 +2877,7 @@ int AudioIO::GetCommonlyAvailPlayback()
    int commonlyAvail = mPlaybackBuffers[0]->AvailForPut();
    unsigned int i;
 
-   for( i = 1; i < mPlaybackTracks.GetCount(); i++ )
+   for( i = 1; i < mPlaybackTracks->GetCount(); i++ )
    {
       int thisBlockAvail = mPlaybackBuffers[i]->AvailForPut();
 
@@ -2889,7 +2893,7 @@ int AudioIO::GetCommonlyAvailCapture()
    int commonlyAvail = mCaptureBuffers[0]->AvailForGet();
    unsigned int i;
 
-   for( i = 1; i < mCaptureTracks.GetCount(); i++ )
+   for( i = 1; i < mCaptureTracks->GetCount(); i++ )
    {
       int avail = mCaptureBuffers[i]->AvailForGet();
       if( avail < commonlyAvail )
@@ -3266,7 +3270,7 @@ void AudioIO::FillBuffers()
 {
    unsigned int i;
 
-   if( mPlaybackTracks.GetCount() > 0 )
+   if( mPlaybackTracks->GetCount() > 0 )
    {
       // Though extremely unlikely, it is possible that some buffers
       // will have more samples available than others.  This could happen
@@ -3323,7 +3327,7 @@ void AudioIO::FillBuffers()
                   mWarpedTime += deltat;
             }
 
-            for( i = 0; i < mPlaybackTracks.GetCount(); i++ )
+            for( i = 0; i < mPlaybackTracks->GetCount(); i++ )
             {
                // The mixer here isn't actually mixing: it's just doing
                // resampling, format conversion, and possibly time track
@@ -3400,7 +3404,7 @@ void AudioIO::FillBuffers()
                         startTime = startSample / mRate;
                         endTime = endSample / mRate;
                         speed = double(abs(endSample - startSample)) / mScrubDuration;
-                        for (i = 0; i < mPlaybackTracks.GetCount(); i++)
+                        for (i = 0; i < mPlaybackTracks->GetCount(); i++)
                            mPlaybackMixers[i]->SetTimesAndSpeed(startTime, endTime, speed);
                      }
                   }
@@ -3415,7 +3419,7 @@ void AudioIO::FillBuffers()
                // and if yes, restart from the beginning.
                if (mWarpedTime >= mWarpedLength)
                {
-                  for (i = 0; i < mPlaybackTracks.GetCount(); i++)
+                  for (i = 0; i < mPlaybackTracks->GetCount(); i++)
                      mPlaybackMixers[i]->Restart();
                   mWarpedTime = 0.0;
                }
@@ -3429,7 +3433,7 @@ void AudioIO::FillBuffers()
       }
    }  // end of playback buffering
 
-   if( mCaptureTracks.GetCount() > 0 ) // start record buffering
+   if( mCaptureTracks->GetCount() > 0 ) // start record buffering
    {
       int commonlyAvail = GetCommonlyAvailCapture();
 
@@ -3444,12 +3448,12 @@ void AudioIO::FillBuffers()
          // Append captured samples to the end of the WaveTracks.
          // The WaveTracks have their own buffering for efficiency.
          AutoSaveFile blockFileLog;
-         int numChannels = mCaptureTracks.GetCount();
+         int numChannels = mCaptureTracks->GetCount();
 
          for( i = 0; (int)i < numChannels; i++ )
          {
             int avail = commonlyAvail;
-            sampleFormat trackFormat = mCaptureTracks[i]->GetSampleFormat();
+            sampleFormat trackFormat = (*mCaptureTracks)[i]->GetSampleFormat();
 
             AutoSaveFile appendLog;
 
@@ -3457,7 +3461,7 @@ void AudioIO::FillBuffers()
             {
                samplePtr temp = NewSamples(avail, trackFormat);
                mCaptureBuffers[i]->Get   (temp, trackFormat, avail);
-               mCaptureTracks[i]-> Append(temp, trackFormat, avail, 1,
+               (*mCaptureTracks)[i]-> Append(temp, trackFormat, avail, 1,
                                           &appendLog);
                DeleteSamples(temp);
             }
@@ -3473,7 +3477,7 @@ void AudioIO::FillBuffers()
                 */
                size = mResample[i]->Process(mFactor, (float *)temp1, avail, !IsStreamActive(),
                                             &size, (float *)temp2, size);
-               mCaptureTracks[i]-> Append(temp2, floatSample, size, 1,
+               (*mCaptureTracks)[i]-> Append(temp2, floatSample, size, 1,
                                           &appendLog);
                DeleteSamples(temp1);
                DeleteSamples(temp2);
@@ -3482,7 +3486,7 @@ void AudioIO::FillBuffers()
             if (!appendLog.IsEmpty())
             {
                blockFileLog.StartTag(wxT("recordingrecovery"));
-               blockFileLog.WriteAttr(wxT("id"), mCaptureTracks[i]->GetAutoSaveIdent());
+               blockFileLog.WriteAttr(wxT("id"), (*mCaptureTracks)[i]->GetAutoSaveIdent());
                blockFileLog.WriteAttr(wxT("channel"), (int)i);
                blockFileLog.WriteAttr(wxT("numchannels"), numChannels);
                blockFileLog.WriteSubTree(appendLog);
@@ -3675,7 +3679,7 @@ bool AudioIO::SetHasSolo(bool hasSolo)
 void AudioIO::FillMidiBuffers()
 {
    bool hasSolo = false;
-   int numPlaybackTracks = gAudioIO->mPlaybackTracks.GetCount();
+   int numPlaybackTracks = gAudioIO->mPlaybackTracks->GetCount();
    int t;
    for(t = 0; t < numPlaybackTracks; t++ )
       if( gAudioIO->mPlaybackTracks[t]->GetSolo() ) {
@@ -3956,7 +3960,7 @@ int audacityAudioCallback(const void *inputBuffer, void *outputBuffer,
                           const PaStreamCallbackFlags WXUNUSED(statusFlags), void * WXUNUSED(userData) )
 {
    int numPlaybackChannels = gAudioIO->mNumPlaybackChannels;
-   int numPlaybackTracks = gAudioIO->mPlaybackTracks.GetCount();
+   int numPlaybackTracks = gAudioIO->mPlaybackTracks->GetCount();
    int numCaptureChannels = gAudioIO->mNumCaptureChannels;
    int callbackReturn = paContinue;
    void *tempBuffer = alloca(framesPerBuffer*sizeof(float)*
@@ -4137,7 +4141,7 @@ int audacityAudioCallback(const void *inputBuffer, void *outputBuffer,
 
          int numSolo = 0;
          for( t = 0; t < numPlaybackTracks; t++ )
-            if( gAudioIO->mPlaybackTracks[t]->GetSolo() )
+            if( (*gAudioIO->mPlaybackTracks)[t]->GetSolo() )
                numSolo++;
 #ifdef EXPERIMENTAL_MIDI_OUT
          int numMidiPlaybackTracks = gAudioIO->mMidiPlaybackTracks.GetCount();
@@ -4162,7 +4166,7 @@ int audacityAudioCallback(const void *inputBuffer, void *outputBuffer,
          int maxLen = 0;
          for (t = 0; t < numPlaybackTracks; t++)
          {
-            WaveTrack *vt = gAudioIO->mPlaybackTracks[t];
+            WaveTrack *vt = (*gAudioIO->mPlaybackTracks)[t];
 
             chans[chanCnt] = vt;
 
@@ -4516,6 +4520,8 @@ int audacityAudioCallback(const void *inputBuffer, void *outputBuffer,
          //    The problem there occurs if Software Playthrough is on.
          //    Could conditionally do the update here if Software Playthrough is off,
          //    and in TrackPanel::OnTimer() if Software Playthrough is on, but not now.
+         // PRL 12 Jul 2015: and what was in TrackPanel::OnTimer is now handled by means of event
+         // type EVT_TRACK_PANEL_TIMER
          //AudacityProject* pProj = GetActiveProject();
          //MixerBoard* pMixerBoard = pProj->GetMixerBoard();
          //if (pMixerBoard)
diff --git a/src/AudioIO.h b/src/AudioIO.h
index ad065548219b4a9bf34c570f9b0332f877fe3ce6..d6fcc32846ae1470466e0509c0b33f0291c177c3 100644
--- a/src/AudioIO.h
+++ b/src/AudioIO.h
@@ -29,10 +29,10 @@
 #include "portmixer.h"
 #endif
 
+#include <wx/event.h>
 #include <wx/string.h>
 #include <wx/thread.h>
 
-#include "WaveTrack.h"
 #include "SampleFormat.h"
 
 class AudioIO;
@@ -46,6 +46,9 @@ class SelectedRegion;
 class TimeTrack;
 class wxDialog;
 
+class AudacityProject;
+class WaveTrackArray;
+
 extern AUDACITY_DLL_API AudioIO *gAudioIO;
 
 void InitAudioIO();
@@ -571,9 +574,9 @@ private:
 #endif
    Resample          **mResample;
    RingBuffer        **mCaptureBuffers;
-   WaveTrackArray      mCaptureTracks;
+   WaveTrackArray     *mCaptureTracks;
    RingBuffer        **mPlaybackBuffers;
-   WaveTrackArray      mPlaybackTracks;
+   WaveTrackArray     *mPlaybackTracks;
 
    Mixer             **mPlaybackMixers;
    volatile int        mStreamToken;
diff --git a/src/AutoRecovery.cpp b/src/AutoRecovery.cpp
index c8f2a15b708aea95388dee0c0702906fb6a05af9..dd97e025264a163a2d1989cf3aa3ca5f3d785359 100644
--- a/src/AutoRecovery.cpp
+++ b/src/AutoRecovery.cpp
@@ -19,6 +19,7 @@ recover previous Audacity projects that were closed incorrectly.
 #include "AudacityApp.h"
 #include "FileNames.h"
 #include "blockfile/SimpleBlockFile.h"
+#include "Sequence.h"
 #include "ShuttleGui.h"
 
 #include <wx/wxprec.h>
@@ -27,6 +28,8 @@ recover previous Audacity projects that were closed incorrectly.
 #include <wx/dialog.h>
 #include <wx/app.h>
 
+#include "WaveTrack.h"
+
 enum {
    ID_RECOVER_ALL = 10000,
    ID_RECOVER_NONE,
diff --git a/src/BatchCommands.cpp b/src/BatchCommands.cpp
index 4023d2bad90a142525168eb3e1e6cf0020002edc..bada3f6a0b92a9d6c820d0c86ed865f099e2607b 100644
--- a/src/BatchCommands.cpp
+++ b/src/BatchCommands.cpp
@@ -17,6 +17,7 @@ See also BatchCommandDialog and BatchProcessDialog.
 
 
 #include "Audacity.h"
+#include "BatchCommands.h"
 
 #include <wx/defs.h>
 #include <wx/dir.h>
@@ -25,7 +26,6 @@ See also BatchCommandDialog and BatchProcessDialog.
 #include <wx/textfile.h>
 
 #include "Project.h"
-#include "BatchCommands.h"
 #include "commands/CommandManager.h"
 #include "effects/EffectManager.h"
 #include "FileNames.h"
@@ -41,6 +41,7 @@ See also BatchCommandDialog and BatchProcessDialog.
 #include "Theme.h"
 #include "AllThemeResources.h"
 
+#include "Track.h"
 
 // KLUDGE: All commands should be on the same footing
 // however, for historical reasons we distinguish between
@@ -682,8 +683,7 @@ bool BatchCommands::ApplyChain(const wxString & filename)
    {
       if(proj) {
          // Chain failed or was cancelled; revert to the previous state
-         UndoManager *um = proj->GetUndoManager();
-         proj->SetStateTo(um->GetCurrentState());
+         proj->RollbackState();
       }
       return false;
    }
diff --git a/src/BlockFile.cpp b/src/BlockFile.cpp
index ed94a1a5847d818759f216b362df9edb680aa4d3..1c434a2df9abfad3d50bfc2ae85467905bbdccd2 100644
--- a/src/BlockFile.cpp
+++ b/src/BlockFile.cpp
@@ -42,6 +42,8 @@ out.
 
 *//*******************************************************************/
 
+#include "BlockFile.h"
+
 #include <float.h>
 #include <math.h>
 
@@ -51,7 +53,6 @@ out.
 #include <wx/log.h>
 #include <wx/math.h>
 
-#include "BlockFile.h"
 #include "Internat.h"
 
 // msmeyer: Define this to add debug output via printf()
diff --git a/src/BlockFile.h b/src/BlockFile.h
index b8254cc43ec5fe829cafd9f9aed60252634c08bb..8f8eb6c1f8578115183f72f51ef7f0934574550e 100644
--- a/src/BlockFile.h
+++ b/src/BlockFile.h
@@ -16,11 +16,11 @@
 #include <wx/ffile.h>
 #include <wx/filename.h>
 
-#include "WaveTrack.h"
-
 #include "xml/XMLTagHandler.h"
 #include "xml/XMLWriter.h"
 
+#include "SampleFormat.h"
+
 
 class SummaryInfo {
  public:
@@ -209,7 +209,7 @@ class AliasBlockFile : public BlockFile
    //
    // These methods are for advanced use only!
    //
-   wxFileName GetAliasedFileName() { return mAliasedFileName; };
+   wxFileName GetAliasedFileName() { return mAliasedFileName; }
    void ChangeAliasedFileName(wxFileName newAliasedFile);
    virtual bool IsAlias() { return true; }
 
diff --git a/src/Dependencies.cpp b/src/Dependencies.cpp
index 8bff3a9cc0926961e3cb33cc6a2fdd6d93ebc32c..3a3df38e1026c6f30506149733254970fb79f791 100644
--- a/src/Dependencies.cpp
+++ b/src/Dependencies.cpp
@@ -21,6 +21,8 @@
 
 **********************************************************************/
 
+#include "Dependencies.h"
+
 #include <wx/button.h>
 #include <wx/defs.h>
 #include <wx/dialog.h>
@@ -30,13 +32,14 @@
 #include <wx/choice.h>
 
 #include "BlockFile.h"
-#include "Dependencies.h"
 #include "DirManager.h"
 #include "Internat.h"
 #include "Prefs.h"
 #include "Project.h"
+#include "Sequence.h"
 #include "ShuttleGui.h"
-#include "Track.h"
+#include "WaveTrack.h"
+#include "WaveClip.h"
 
 // Note, this #include must occur here, not up with the others!
 // It must be between the WX_DECLARE_OBJARRAY and WX_DEFINE_OBJARRAY.
diff --git a/src/Dependencies.h b/src/Dependencies.h
index c4bda4d57278d09bb06483742e950ca76e33d959..70044b23507aa01931c9e8bc064ff672cead1d7a 100644
--- a/src/Dependencies.h
+++ b/src/Dependencies.h
@@ -15,6 +15,7 @@
 #define __AUDACITY_DEPENDENCIES__
 
 #include <wx/dynarray.h>
+#include <wx/filename.h>
 
 class AudacityProject;
 
diff --git a/src/DirManager.cpp b/src/DirManager.cpp
index 8104f56b13b7acc98f724fa5045e5db64f85099a..8d2a570313560d3ffe4a0651be5533cbf8769e56 100644
--- a/src/DirManager.cpp
+++ b/src/DirManager.cpp
@@ -62,6 +62,7 @@
 
 
 #include "Audacity.h"
+#include "DirManager.h"
 
 #include <time.h> // to use time() for srand()
 
@@ -94,16 +95,16 @@
 #include "blockfile/PCMAliasBlockFile.h"
 #include "blockfile/ODPCMAliasBlockFile.h"
 #include "blockfile/ODDecodeBlockFile.h"
-#include "DirManager.h"
 #include "Internat.h"
 #include "Project.h"
 #include "Prefs.h"
 #include "widgets/Warning.h"
 #include "widgets/MultiDialog.h"
 
-#include "prefs/PrefsDialog.h"
 #include "ondemand/ODManager.h"
 
+#include "Track.h"
+
 #if defined(__WXMAC__)
 #include <mach/mach.h>
 #include <mach/vm_statistics.h>
diff --git a/src/DirManager.h b/src/DirManager.h
index bcc10cac7e9ace3000b114836cbe640a57c752b2..dc8af0fc8208c10a43df77f4a142799941f2776e 100644
--- a/src/DirManager.h
+++ b/src/DirManager.h
@@ -15,8 +15,10 @@
 #include <wx/string.h>
 #include <wx/filename.h>
 #include <wx/hashmap.h>
+#include <wx/utils.h>
 
-#include "WaveTrack.h"
+#include "audacity/Types.h"
+#include "xml/XMLTagHandler.h"
 
 class wxHashTable;
 class BlockFile;
@@ -105,7 +107,7 @@ class DirManager: public XMLTagHandler {
    void SetMaxSamples(sampleCount max) { mMaxSamples = max; }
    bool HandleXMLTag(const wxChar *tag, const wxChar **attrs);
    XMLTagHandler *HandleXMLChild(const wxChar * WXUNUSED(tag)) { return NULL; }
-   void WriteXML(XMLWriter & WXUNUSED(xmlFile)) { wxASSERT(false); }; // This class only reads tags.
+   void WriteXML(XMLWriter & WXUNUSED(xmlFile)) { wxASSERT(false); } // This class only reads tags.
    bool AssignFile(wxFileName &filename,wxString value,bool check);
 
    // Clean the temp dir. Note that now where we have auto recovery the temp
diff --git a/src/Envelope.cpp b/src/Envelope.cpp
index e2eec3ffd83c63a0d3571da1e4ce3bdd04608ca4..d12fcb3a7760054867eddb05b3f27a2346ce61ae 100644
--- a/src/Envelope.cpp
+++ b/src/Envelope.cpp
@@ -39,7 +39,6 @@ a draggable point type.
 #include <wx/log.h>
 
 #include "AColor.h"
-#include "Prefs.h"
 #include "DirManager.h"
 #include "TrackArtist.h"
 
@@ -175,23 +174,6 @@ static double Limit( double Lo, double Value, double Hi )
    return Value;
 }
 
-double Envelope::toDB(double value)
-{
-   if (value == 0)
-      return 0;
-
-   // TODO: Cache the gPrefs value.  Reading it every time is inefficient.
-   double dBRange = gPrefs->Read(wxT("/GUI/EnvdBRange"), ENV_DB_RANGE);
-   double sign = (value >= 0 ? 1 : -1);
-
-   wxASSERT( dBRange > 0 );
-   double db = 20 * log10(fabs(value));
-   double val = (db + dBRange) / dBRange;
-
-   val = Limit( 0.0, val, 1.0 );
-   return sign * val;
-}
-
 /// TODO: This should probably move to track artist.
 static void DrawPoint(wxDC & dc, const wxRect & r, int x, int y, bool top)
 {
@@ -205,8 +187,7 @@ static void DrawPoint(wxDC & dc, const wxRect & r, int x, int y, bool top)
 void Envelope::DrawPoints(wxDC & dc, const wxRect & r, const ZoomInfo &zoomInfo, bool dB,
                     float zoomMin, float zoomMax)
 {
-   // TODO: Cache the gPrefs value.  Reading it every time is inefficient.
-   double dBRange = gPrefs->Read(wxT("/GUI/EnvdBRange"), ENV_DB_RANGE);
+   double dBRange = zoomInfo.dBr;
 
    dc.SetPen(AColor::envelopePen);
    dc.SetBrush(*wxWHITE_BRUSH);
@@ -330,13 +311,13 @@ inline int SQR(int x) { return x * x; }
 /// @dB - display mode either linear or log.
 /// @zoomMin - vertical scale, typically -1.0
 /// @zoomMax - vertical scale, typically +1.0
-float Envelope::ValueOfPixel( int y, int height, bool upper, bool dB,
+float Envelope::ValueOfPixel( int y, int height, bool upper,
+                              const ZoomInfo &zoomInfo, bool dB,
                               float zoomMin, float zoomMax)
 {
    double dBRange = 0;
    if (dB)
-      // TODO: Cache the gPrefs value.  Reading it every time is inefficient.
-      dBRange = gPrefs->Read(wxT("/GUI/EnvdBRange"), ENV_DB_RANGE);
+      dBRange = zoomInfo.dBr;
 
    float v = ::ValueOfPixel(y, height, 0 != mContourOffset, dB, dBRange, zoomMin, zoomMax);
 
@@ -368,8 +349,7 @@ bool Envelope::HandleMouseButtonDown(wxMouseEvent & event, wxRect & r,
    int bestNum = -1;
    int bestDistSqr = 100; // Must be within 10 pixel radius.
 
-   // TODO: Cache the gPrefs value.  Reading it every time is inefficient.
-   double dBr = gPrefs->Read(wxT("/GUI/EnvdBRange"), ENV_DB_RANGE);
+   double dBr = zoomInfo.dBr;
 
    // Member variables hold state that will be needed in dragging.
    mButton        = event.GetButton();
@@ -457,7 +437,7 @@ bool Envelope::HandleMouseButtonDown(wxMouseEvent & event, wxRect & r,
             mContourOffset = false;
       }
 
-      double newVal = ValueOfPixel(clip_y, r.height, upper, dB,
+      double newVal = ValueOfPixel(clip_y, r.height, upper, zoomInfo, dB,
                                    zoomMin, zoomMax);
 
       mDragPoint = Insert(when - mOffset, newVal);
@@ -508,7 +488,7 @@ void Envelope::MoveDraggedPoint( wxMouseEvent & event, wxRect & r,
    int clip_y = event.m_y - r.y;
    if(clip_y < 0) clip_y = 0;
    if(clip_y > r.height) clip_y = r.height;
-   double newVal = ValueOfPixel(clip_y, r.height, mUpper, dB,
+   double newVal = ValueOfPixel(clip_y, r.height, mUpper, zoomInfo, dB,
                                 zoomMin, zoomMax);
 
    // We no longer tolerate multiple envelope points at the same t.
diff --git a/src/Envelope.h b/src/Envelope.h
index 508c5c76d07d4ad813fb3b8d760c3ff41de1fcb8..c4c08b3e241ca19cef33b7ee92a7843ca439b60a 100644
--- a/src/Envelope.h
+++ b/src/Envelope.h
@@ -31,8 +31,6 @@ class Envelope;
 
 class ZoomInfo;
 
-#define ENV_DB_RANGE 60
-
 class EnvPoint : public XMLTagHandler {
 
 public:
@@ -197,10 +195,10 @@ class Envelope : public XMLTagHandler {
                   int bufferLen) const;
 
 private:
-   double toDB(double x);
    EnvPoint *  AddPointAtEnd( double t, double val );
    void MarkDragPointForDeletion();
-   float ValueOfPixel( int y, int height, bool upper, bool dB,
+   float ValueOfPixel( int y, int height, bool upper,
+                       const ZoomInfo &zoomInfo, bool dB,
                        float zoomMin, float zoomMax);
    void BinarySearchForTime( int &Lo, int &Hi, double t ) const;
    double GetInterpolationStartValueAtPoint( int iPoint ) const;
diff --git a/src/FFT.cpp b/src/FFT.cpp
index c64535e0f6c74822ecc19504cc1b016dfcc717b9..af1217bf77273a3c871df1dd1be92f4340734dc9 100644
--- a/src/FFT.cpp
+++ b/src/FFT.cpp
@@ -39,13 +39,13 @@
     * 9: Gaussian(a=4.5)
 */
 
+#include "FFT.h"
+
 #include <wx/intl.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <math.h>
 
-#include "FFT.h"
-
 static int **gFFTBitTable = NULL;
 static const int MaxFastBits = 16;
 
diff --git a/src/FFT.h b/src/FFT.h
index 0713441c24086b6a8330158d308de03d6ecb5960..80de2b398d00ff857e55dbd582e3a39fae9976d6 100644
--- a/src/FFT.h
+++ b/src/FFT.h
@@ -32,6 +32,8 @@
 #ifndef __AUDACITY_FFT_H__
 #define __AUDACITY_FFT_H__
 
+#include <wx/defs.h>
+
 /*
   Salvo Ventura - November 2006
   Added more window functions:
diff --git a/src/FFmpeg.h b/src/FFmpeg.h
index 79cd36261b9ee5707417dccc27047d7bae59e527..aef40ae8b10373fe29fbb47ac7d3913af8ca7c33 100644
--- a/src/FFmpeg.h
+++ b/src/FFmpeg.h
@@ -128,6 +128,8 @@ extern "C" {
 #endif
 
 #include "Audacity.h"
+#include "Experimental.h"
+
 /* rather earlier than normal, but pulls in config*.h and other program stuff
  * we need for the next bit */
 #include <wx/string.h>
@@ -141,10 +143,8 @@ extern "C" {
 #include "Prefs.h"
 #include <wx/checkbox.h>
 #include <wx/textctrl.h>
-// needed for sampleCount
-#include "Sequence.h"
 
-#include "Experimental.h"
+#include "audacity/Types.h"
 
 // if you needed them, any other audacity header files would go here
 
diff --git a/src/FreqWindow.cpp b/src/FreqWindow.cpp
index 3b865e36e72d362795a2ab4ff727facae57b92a6..b793b9f34632014b381ddb3035698d2f1d6390cf 100644
--- a/src/FreqWindow.cpp
+++ b/src/FreqWindow.cpp
@@ -43,6 +43,8 @@ and in the spectrogram spectral selection.
 #include "Audacity.h"
 #include "FreqWindow.h"
 
+#include <algorithm>
+
 #include <wx/brush.h>
 #include <wx/button.h>
 #include <wx/choice.h>
@@ -67,6 +69,7 @@ and in the spectrogram spectral selection.
 #include "FFT.h"
 #include "Internat.h"
 #include "PitchName.h"
+#include "prefs/GUISettings.h"
 #include "Prefs.h"
 #include "Project.h"
 #include "WaveClip.h"
@@ -75,10 +78,7 @@ and in the spectrogram spectral selection.
 
 #include "FileDialog.h"
 
-//#if defined(__WXGTK__)
-//#define GSocket GSocketHack
-//#include <gtk/gtk.h>
-//#endif
+#include "WaveTrack.h"
 
 DEFINE_EVENT_TYPE(EVT_FREQWINDOW_RECALC);
 
@@ -253,7 +253,7 @@ FreqWindow::FreqWindow(wxWindow * parent, wxWindowID id,
 
    gPrefs->Read(wxT("/FreqWindow/FuncChoice"), &mFunc, 3);
    gPrefs->Read(wxT("/FreqWindow/AxisChoice"), &mAxis, 0);
-   gPrefs->Read(wxT("/GUI/EnvdBRange"), &dBRange, ENV_DB_RANGE);
+   gPrefs->Read(ENV_DB_KEY, &dBRange, ENV_DB_RANGE);
    if(dBRange < 90.)
       dBRange = 90.;
 
@@ -534,7 +534,7 @@ bool FreqWindow::Show(bool show)
 
    if (show && !shown)
    {
-      gPrefs->Read(wxT("/GUI/EnvdBRange"), &dBRange, ENV_DB_RANGE);
+      gPrefs->Read(ENV_DB_KEY, &dBRange, ENV_DB_RANGE);
       if(dBRange < 90.)
          dBRange = 90.;
       GetAudio();
@@ -1067,7 +1067,7 @@ void FreqWindow::OnExport(wxCommandEvent & WXUNUSED(event))
 
 void FreqWindow::OnReplot(wxCommandEvent & WXUNUSED(event))
 {
-   gPrefs->Read(wxT("/GUI/EnvdBRange"), &dBRange, ENV_DB_RANGE);
+   gPrefs->Read(ENV_DB_KEY, &dBRange, ENV_DB_RANGE);
    if(dBRange < 90.)
       dBRange = 90.;
    GetAudio();
diff --git a/src/LabelDialog.cpp b/src/LabelDialog.cpp
index 5907816930d0bc6e3277c53218ad1134fe36602a..64624127c8f4a47f6bf3508fde5641d01af3926b 100644
--- a/src/LabelDialog.cpp
+++ b/src/LabelDialog.cpp
@@ -35,7 +35,6 @@
 #include "LabelTrack.h"
 #include "Prefs.h"
 #include "Project.h"
-#include "Track.h"
 #include "ViewInfo.h"
 #include "widgets/NumericTextCtrl.h"
 
diff --git a/src/LyricsWindow.cpp b/src/LyricsWindow.cpp
index 1424521e88862dbc3a551456dab120e38b3e35a2..7d2acad4ef210403d793e6770ce445d116c74c9c 100644
--- a/src/LyricsWindow.cpp
+++ b/src/LyricsWindow.cpp
@@ -13,7 +13,9 @@
 
 #include "LyricsWindow.h"
 #include "Lyrics.h"
+#include "AudioIO.h"
 #include "Project.h"
+#include "TrackPanel.h" // for EVT_TRACK_PANEL_TIMER
 
 #include <wx/radiobut.h>
 #include <wx/toolbar.h>
@@ -123,10 +125,21 @@ LyricsWindow::LyricsWindow(AudacityProject *parent):
    //   default:
    //      pRadioButton_Highlight->SetValue(true); break;
    //}
+
+   // Events from the project don't propagate directly to this other frame, so...
+   mProject->Connect(EVT_TRACK_PANEL_TIMER,
+      wxCommandEventHandler(LyricsWindow::OnTimer),
+      NULL,
+      this);
 }
 
 LyricsWindow::~LyricsWindow()
-{}
+{
+   mProject->Disconnect(EVT_TRACK_PANEL_TIMER,
+      wxCommandEventHandler(LyricsWindow::OnTimer),
+      NULL,
+      this);
+}
 
 void LyricsWindow::OnCloseWindow(wxCloseEvent & WXUNUSED(event))
 {
@@ -143,3 +156,18 @@ void LyricsWindow::OnStyle_Highlight(wxCommandEvent & WXUNUSED(event))
    mLyricsPanel->SetLyricsStyle(Lyrics::kHighlightLyrics);
 }
 
+void LyricsWindow::OnTimer(wxCommandEvent &event)
+{
+   if (mProject->IsAudioActive())
+   {
+      GetLyricsPanel()->Update(gAudioIO->GetStreamTime());
+   }
+   else
+   {
+      // Reset lyrics display.
+      GetLyricsPanel()->Update(mProject->GetSel0());
+   }
+
+   // Let other listeners get the notification
+   event.Skip();
+}
diff --git a/src/LyricsWindow.h b/src/LyricsWindow.h
index d0afd19d7635d2050e2235516662fc10be116c02..1334ae33ff36c6fc9ab7dc5cd8d59a9a63b00a60 100644
--- a/src/LyricsWindow.h
+++ b/src/LyricsWindow.h
@@ -32,6 +32,7 @@ class LyricsWindow : public wxFrame {
 
    void OnStyle_BouncingBall(wxCommandEvent &evt);
    void OnStyle_Highlight(wxCommandEvent &evt);
+   void OnTimer(wxCommandEvent &event);
 
    AudacityProject *mProject;
    Lyrics *mLyricsPanel;
diff --git a/src/Makefile.am b/src/Makefile.am
index 3953208c89e8e698f1c33525edaf3042e74bcb3d..c5370f4b2a0ab8e4e26c4b44fd8dd63f36c6f6af 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -169,6 +169,7 @@ audacity_SOURCES = \
 	MixerBoard.h \
 	ModuleManager.cpp \
 	ModuleManager.h \
+        NumberScale.h \
 	PitchName.cpp \
 	PitchName.h \
 	PlatformCompatibility.cpp \
@@ -239,6 +240,7 @@ audacity_SOURCES = \
 	WaveClip.h \
 	WaveTrack.cpp \
 	WaveTrack.h \
+	WaveTrackLocation.h \
 	WrappedType.cpp \
 	WrappedType.h \
 	commands/AppCommandEvent.cpp \
@@ -452,6 +454,7 @@ audacity_SOURCES = \
 	prefs/ExtImportPrefs.h \
 	prefs/GUIPrefs.cpp \
 	prefs/GUIPrefs.h \
+	prefs/GUISettings.h \
 	prefs/ImportExportPrefs.cpp \
 	prefs/ImportExportPrefs.h \
 	prefs/KeyConfigPrefs.cpp \
@@ -475,6 +478,8 @@ audacity_SOURCES = \
 	prefs/QualityPrefs.h \
 	prefs/RecordingPrefs.cpp \
 	prefs/RecordingPrefs.h \
+	prefs/SpectrogramSettings.cpp \
+	prefs/SpectrogramSettings.h \
 	prefs/SpectrumPrefs.cpp \
 	prefs/SpectrumPrefs.h \
 	prefs/ThemePrefs.cpp \
@@ -483,6 +488,10 @@ audacity_SOURCES = \
 	prefs/TracksPrefs.h \
 	prefs/WarningsPrefs.cpp \
 	prefs/WarningsPrefs.h \
+	prefs/WaveformPrefs.cpp \
+	prefs/WaveformPrefs.h \
+	prefs/WaveformSettings.cpp \
+	prefs/WaveformSettings.h \
 	toolbars/ControlToolBar.cpp \
 	toolbars/ControlToolBar.h \
 	toolbars/DeviceToolBar.cpp \
diff --git a/src/Makefile.in b/src/Makefile.in
index d92565e8e970ff79e77499888b5ed9f4a17f0cc9..8f4c37dc254f3f13afe67f78b663ab795a6c02e6 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -301,17 +301,17 @@ am__audacity_SOURCES_DIST = BlockFile.cpp BlockFile.h DirManager.cpp \
 	Lyrics.h LyricsWindow.cpp LyricsWindow.h MacroMagic.h \
 	Matrix.cpp Matrix.h Menus.cpp Menus.h Mix.cpp Mix.h \
 	MixerBoard.cpp MixerBoard.h ModuleManager.cpp ModuleManager.h \
-	PitchName.cpp PitchName.h PlatformCompatibility.cpp \
-	PlatformCompatibility.h PluginManager.cpp PluginManager.h \
-	Printing.cpp Printing.h Profiler.cpp Profiler.h Project.cpp \
-	Project.h RealFFTf.cpp RealFFTf.h RealFFTf48x.cpp \
-	RealFFTf48x.h Resample.cpp Resample.h RevisionIdent.h \
-	RingBuffer.cpp RingBuffer.h Screenshot.cpp Screenshot.h \
-	SelectedRegion.cpp SelectedRegion.h Shuttle.cpp Shuttle.h \
-	ShuttleGui.cpp ShuttleGui.h ShuttlePrefs.cpp ShuttlePrefs.h \
-	Snap.cpp Snap.h SoundActivatedRecord.cpp \
-	SoundActivatedRecord.h Spectrum.cpp Spectrum.h \
-	SplashDialog.cpp SplashDialog.h SseMathFuncs.cpp \
+	NumberScale.h PitchName.cpp PitchName.h \
+	PlatformCompatibility.cpp PlatformCompatibility.h \
+	PluginManager.cpp PluginManager.h Printing.cpp Printing.h \
+	Profiler.cpp Profiler.h Project.cpp Project.h RealFFTf.cpp \
+	RealFFTf.h RealFFTf48x.cpp RealFFTf48x.h Resample.cpp \
+	Resample.h RevisionIdent.h RingBuffer.cpp RingBuffer.h \
+	Screenshot.cpp Screenshot.h SelectedRegion.cpp \
+	SelectedRegion.h Shuttle.cpp Shuttle.h ShuttleGui.cpp \
+	ShuttleGui.h ShuttlePrefs.cpp ShuttlePrefs.h Snap.cpp Snap.h \
+	SoundActivatedRecord.cpp SoundActivatedRecord.h Spectrum.cpp \
+	Spectrum.h SplashDialog.cpp SplashDialog.h SseMathFuncs.cpp \
 	SseMathFuncs.h Tags.cpp Tags.h Theme.cpp Theme.h \
 	ThemeAsCeeCode.h TimeDialog.cpp TimeDialog.h \
 	TimerRecordDialog.cpp TimerRecordDialog.h TimeTrack.cpp \
@@ -319,7 +319,7 @@ am__audacity_SOURCES_DIST = BlockFile.cpp BlockFile.h DirManager.cpp \
 	TrackPanel.cpp TrackPanel.h TrackPanelAx.cpp TrackPanelAx.h \
 	UndoManager.cpp UndoManager.h ViewInfo.cpp ViewInfo.h \
 	VoiceKey.cpp VoiceKey.h WaveClip.cpp WaveClip.h WaveTrack.cpp \
-	WaveTrack.h WrappedType.cpp WrappedType.h \
+	WaveTrack.h WaveTrackLocation.h WrappedType.cpp WrappedType.h \
 	commands/AppCommandEvent.cpp commands/AppCommandEvent.h \
 	commands/BatchEvalCommand.cpp commands/BatchEvalCommand.h \
 	commands/Command.cpp commands/Command.h \
@@ -416,7 +416,7 @@ am__audacity_SOURCES_DIST = BlockFile.cpp BlockFile.h DirManager.cpp \
 	prefs/DirectoriesPrefs.cpp prefs/DirectoriesPrefs.h \
 	prefs/EffectsPrefs.cpp prefs/EffectsPrefs.h \
 	prefs/ExtImportPrefs.cpp prefs/ExtImportPrefs.h \
-	prefs/GUIPrefs.cpp prefs/GUIPrefs.h \
+	prefs/GUIPrefs.cpp prefs/GUIPrefs.h prefs/GUISettings.h \
 	prefs/ImportExportPrefs.cpp prefs/ImportExportPrefs.h \
 	prefs/KeyConfigPrefs.cpp prefs/KeyConfigPrefs.h \
 	prefs/LibraryPrefs.cpp prefs/LibraryPrefs.h \
@@ -427,10 +427,13 @@ am__audacity_SOURCES_DIST = BlockFile.cpp BlockFile.h DirManager.cpp \
 	prefs/PrefsDialog.h prefs/PrefsPanel.h prefs/ProjectsPrefs.cpp \
 	prefs/ProjectsPrefs.h prefs/QualityPrefs.cpp \
 	prefs/QualityPrefs.h prefs/RecordingPrefs.cpp \
-	prefs/RecordingPrefs.h prefs/SpectrumPrefs.cpp \
+	prefs/RecordingPrefs.h prefs/SpectrogramSettings.cpp \
+	prefs/SpectrogramSettings.h prefs/SpectrumPrefs.cpp \
 	prefs/SpectrumPrefs.h prefs/ThemePrefs.cpp prefs/ThemePrefs.h \
 	prefs/TracksPrefs.cpp prefs/TracksPrefs.h \
 	prefs/WarningsPrefs.cpp prefs/WarningsPrefs.h \
+	prefs/WaveformPrefs.cpp prefs/WaveformPrefs.h \
+	prefs/WaveformSettings.cpp prefs/WaveformSettings.h \
 	toolbars/ControlToolBar.cpp toolbars/ControlToolBar.h \
 	toolbars/DeviceToolBar.cpp toolbars/DeviceToolBar.h \
 	toolbars/EditToolBar.cpp toolbars/EditToolBar.h \
@@ -675,10 +678,13 @@ am_audacity_OBJECTS = $(am__objects_1) audacity-AboutDialog.$(OBJEXT) \
 	prefs/audacity-ProjectsPrefs.$(OBJEXT) \
 	prefs/audacity-QualityPrefs.$(OBJEXT) \
 	prefs/audacity-RecordingPrefs.$(OBJEXT) \
+	prefs/audacity-SpectrogramSettings.$(OBJEXT) \
 	prefs/audacity-SpectrumPrefs.$(OBJEXT) \
 	prefs/audacity-ThemePrefs.$(OBJEXT) \
 	prefs/audacity-TracksPrefs.$(OBJEXT) \
 	prefs/audacity-WarningsPrefs.$(OBJEXT) \
+	prefs/audacity-WaveformPrefs.$(OBJEXT) \
+	prefs/audacity-WaveformSettings.$(OBJEXT) \
 	toolbars/audacity-ControlToolBar.$(OBJEXT) \
 	toolbars/audacity-DeviceToolBar.$(OBJEXT) \
 	toolbars/audacity-EditToolBar.$(OBJEXT) \
@@ -1164,17 +1170,17 @@ audacity_SOURCES = $(libaudacity_la_SOURCES) AboutDialog.cpp \
 	Lyrics.h LyricsWindow.cpp LyricsWindow.h MacroMagic.h \
 	Matrix.cpp Matrix.h Menus.cpp Menus.h Mix.cpp Mix.h \
 	MixerBoard.cpp MixerBoard.h ModuleManager.cpp ModuleManager.h \
-	PitchName.cpp PitchName.h PlatformCompatibility.cpp \
-	PlatformCompatibility.h PluginManager.cpp PluginManager.h \
-	Printing.cpp Printing.h Profiler.cpp Profiler.h Project.cpp \
-	Project.h RealFFTf.cpp RealFFTf.h RealFFTf48x.cpp \
-	RealFFTf48x.h Resample.cpp Resample.h RevisionIdent.h \
-	RingBuffer.cpp RingBuffer.h Screenshot.cpp Screenshot.h \
-	SelectedRegion.cpp SelectedRegion.h Shuttle.cpp Shuttle.h \
-	ShuttleGui.cpp ShuttleGui.h ShuttlePrefs.cpp ShuttlePrefs.h \
-	Snap.cpp Snap.h SoundActivatedRecord.cpp \
-	SoundActivatedRecord.h Spectrum.cpp Spectrum.h \
-	SplashDialog.cpp SplashDialog.h SseMathFuncs.cpp \
+	NumberScale.h PitchName.cpp PitchName.h \
+	PlatformCompatibility.cpp PlatformCompatibility.h \
+	PluginManager.cpp PluginManager.h Printing.cpp Printing.h \
+	Profiler.cpp Profiler.h Project.cpp Project.h RealFFTf.cpp \
+	RealFFTf.h RealFFTf48x.cpp RealFFTf48x.h Resample.cpp \
+	Resample.h RevisionIdent.h RingBuffer.cpp RingBuffer.h \
+	Screenshot.cpp Screenshot.h SelectedRegion.cpp \
+	SelectedRegion.h Shuttle.cpp Shuttle.h ShuttleGui.cpp \
+	ShuttleGui.h ShuttlePrefs.cpp ShuttlePrefs.h Snap.cpp Snap.h \
+	SoundActivatedRecord.cpp SoundActivatedRecord.h Spectrum.cpp \
+	Spectrum.h SplashDialog.cpp SplashDialog.h SseMathFuncs.cpp \
 	SseMathFuncs.h Tags.cpp Tags.h Theme.cpp Theme.h \
 	ThemeAsCeeCode.h TimeDialog.cpp TimeDialog.h \
 	TimerRecordDialog.cpp TimerRecordDialog.h TimeTrack.cpp \
@@ -1182,7 +1188,7 @@ audacity_SOURCES = $(libaudacity_la_SOURCES) AboutDialog.cpp \
 	TrackPanel.cpp TrackPanel.h TrackPanelAx.cpp TrackPanelAx.h \
 	UndoManager.cpp UndoManager.h ViewInfo.cpp ViewInfo.h \
 	VoiceKey.cpp VoiceKey.h WaveClip.cpp WaveClip.h WaveTrack.cpp \
-	WaveTrack.h WrappedType.cpp WrappedType.h \
+	WaveTrack.h WaveTrackLocation.h WrappedType.cpp WrappedType.h \
 	commands/AppCommandEvent.cpp commands/AppCommandEvent.h \
 	commands/BatchEvalCommand.cpp commands/BatchEvalCommand.h \
 	commands/Command.cpp commands/Command.h \
@@ -1279,7 +1285,7 @@ audacity_SOURCES = $(libaudacity_la_SOURCES) AboutDialog.cpp \
 	prefs/DirectoriesPrefs.cpp prefs/DirectoriesPrefs.h \
 	prefs/EffectsPrefs.cpp prefs/EffectsPrefs.h \
 	prefs/ExtImportPrefs.cpp prefs/ExtImportPrefs.h \
-	prefs/GUIPrefs.cpp prefs/GUIPrefs.h \
+	prefs/GUIPrefs.cpp prefs/GUIPrefs.h prefs/GUISettings.h \
 	prefs/ImportExportPrefs.cpp prefs/ImportExportPrefs.h \
 	prefs/KeyConfigPrefs.cpp prefs/KeyConfigPrefs.h \
 	prefs/LibraryPrefs.cpp prefs/LibraryPrefs.h \
@@ -1290,10 +1296,13 @@ audacity_SOURCES = $(libaudacity_la_SOURCES) AboutDialog.cpp \
 	prefs/PrefsDialog.h prefs/PrefsPanel.h prefs/ProjectsPrefs.cpp \
 	prefs/ProjectsPrefs.h prefs/QualityPrefs.cpp \
 	prefs/QualityPrefs.h prefs/RecordingPrefs.cpp \
-	prefs/RecordingPrefs.h prefs/SpectrumPrefs.cpp \
+	prefs/RecordingPrefs.h prefs/SpectrogramSettings.cpp \
+	prefs/SpectrogramSettings.h prefs/SpectrumPrefs.cpp \
 	prefs/SpectrumPrefs.h prefs/ThemePrefs.cpp prefs/ThemePrefs.h \
 	prefs/TracksPrefs.cpp prefs/TracksPrefs.h \
 	prefs/WarningsPrefs.cpp prefs/WarningsPrefs.h \
+	prefs/WaveformPrefs.cpp prefs/WaveformPrefs.h \
+	prefs/WaveformSettings.cpp prefs/WaveformSettings.h \
 	toolbars/ControlToolBar.cpp toolbars/ControlToolBar.h \
 	toolbars/DeviceToolBar.cpp toolbars/DeviceToolBar.h \
 	toolbars/EditToolBar.cpp toolbars/EditToolBar.h \
@@ -1377,8 +1386,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
@@ -1389,8 +1398,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
@@ -1771,6 +1780,8 @@ prefs/audacity-QualityPrefs.$(OBJEXT): prefs/$(am__dirstamp) \
 	prefs/$(DEPDIR)/$(am__dirstamp)
 prefs/audacity-RecordingPrefs.$(OBJEXT): prefs/$(am__dirstamp) \
 	prefs/$(DEPDIR)/$(am__dirstamp)
+prefs/audacity-SpectrogramSettings.$(OBJEXT): prefs/$(am__dirstamp) \
+	prefs/$(DEPDIR)/$(am__dirstamp)
 prefs/audacity-SpectrumPrefs.$(OBJEXT): prefs/$(am__dirstamp) \
 	prefs/$(DEPDIR)/$(am__dirstamp)
 prefs/audacity-ThemePrefs.$(OBJEXT): prefs/$(am__dirstamp) \
@@ -1779,6 +1790,10 @@ prefs/audacity-TracksPrefs.$(OBJEXT): prefs/$(am__dirstamp) \
 	prefs/$(DEPDIR)/$(am__dirstamp)
 prefs/audacity-WarningsPrefs.$(OBJEXT): prefs/$(am__dirstamp) \
 	prefs/$(DEPDIR)/$(am__dirstamp)
+prefs/audacity-WaveformPrefs.$(OBJEXT): prefs/$(am__dirstamp) \
+	prefs/$(DEPDIR)/$(am__dirstamp)
+prefs/audacity-WaveformSettings.$(OBJEXT): prefs/$(am__dirstamp) \
+	prefs/$(DEPDIR)/$(am__dirstamp)
 toolbars/$(am__dirstamp):
 	@$(MKDIR_P) toolbars
 	@: > toolbars/$(am__dirstamp)
@@ -2200,10 +2215,13 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@prefs/$(DEPDIR)/audacity-ProjectsPrefs.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@prefs/$(DEPDIR)/audacity-QualityPrefs.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@prefs/$(DEPDIR)/audacity-RecordingPrefs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@prefs/$(DEPDIR)/audacity-SpectrogramSettings.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@prefs/$(DEPDIR)/audacity-SpectrumPrefs.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@prefs/$(DEPDIR)/audacity-ThemePrefs.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@prefs/$(DEPDIR)/audacity-TracksPrefs.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@prefs/$(DEPDIR)/audacity-WarningsPrefs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@prefs/$(DEPDIR)/audacity-WaveformPrefs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@prefs/$(DEPDIR)/audacity-WaveformSettings.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@toolbars/$(DEPDIR)/audacity-ControlToolBar.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@toolbars/$(DEPDIR)/audacity-DeviceToolBar.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@toolbars/$(DEPDIR)/audacity-EditToolBar.Po@am__quote@
@@ -5192,6 +5210,20 @@ prefs/audacity-RecordingPrefs.obj: prefs/RecordingPrefs.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o prefs/audacity-RecordingPrefs.obj `if test -f 'prefs/RecordingPrefs.cpp'; then $(CYGPATH_W) 'prefs/RecordingPrefs.cpp'; else $(CYGPATH_W) '$(srcdir)/prefs/RecordingPrefs.cpp'; fi`
 
+prefs/audacity-SpectrogramSettings.o: prefs/SpectrogramSettings.cpp
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT prefs/audacity-SpectrogramSettings.o -MD -MP -MF prefs/$(DEPDIR)/audacity-SpectrogramSettings.Tpo -c -o prefs/audacity-SpectrogramSettings.o `test -f 'prefs/SpectrogramSettings.cpp' || echo '$(srcdir)/'`prefs/SpectrogramSettings.cpp
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) prefs/$(DEPDIR)/audacity-SpectrogramSettings.Tpo prefs/$(DEPDIR)/audacity-SpectrogramSettings.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='prefs/SpectrogramSettings.cpp' object='prefs/audacity-SpectrogramSettings.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o prefs/audacity-SpectrogramSettings.o `test -f 'prefs/SpectrogramSettings.cpp' || echo '$(srcdir)/'`prefs/SpectrogramSettings.cpp
+
+prefs/audacity-SpectrogramSettings.obj: prefs/SpectrogramSettings.cpp
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT prefs/audacity-SpectrogramSettings.obj -MD -MP -MF prefs/$(DEPDIR)/audacity-SpectrogramSettings.Tpo -c -o prefs/audacity-SpectrogramSettings.obj `if test -f 'prefs/SpectrogramSettings.cpp'; then $(CYGPATH_W) 'prefs/SpectrogramSettings.cpp'; else $(CYGPATH_W) '$(srcdir)/prefs/SpectrogramSettings.cpp'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) prefs/$(DEPDIR)/audacity-SpectrogramSettings.Tpo prefs/$(DEPDIR)/audacity-SpectrogramSettings.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='prefs/SpectrogramSettings.cpp' object='prefs/audacity-SpectrogramSettings.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o prefs/audacity-SpectrogramSettings.obj `if test -f 'prefs/SpectrogramSettings.cpp'; then $(CYGPATH_W) 'prefs/SpectrogramSettings.cpp'; else $(CYGPATH_W) '$(srcdir)/prefs/SpectrogramSettings.cpp'; fi`
+
 prefs/audacity-SpectrumPrefs.o: prefs/SpectrumPrefs.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT prefs/audacity-SpectrumPrefs.o -MD -MP -MF prefs/$(DEPDIR)/audacity-SpectrumPrefs.Tpo -c -o prefs/audacity-SpectrumPrefs.o `test -f 'prefs/SpectrumPrefs.cpp' || echo '$(srcdir)/'`prefs/SpectrumPrefs.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) prefs/$(DEPDIR)/audacity-SpectrumPrefs.Tpo prefs/$(DEPDIR)/audacity-SpectrumPrefs.Po
@@ -5248,6 +5280,34 @@ prefs/audacity-WarningsPrefs.obj: prefs/WarningsPrefs.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o prefs/audacity-WarningsPrefs.obj `if test -f 'prefs/WarningsPrefs.cpp'; then $(CYGPATH_W) 'prefs/WarningsPrefs.cpp'; else $(CYGPATH_W) '$(srcdir)/prefs/WarningsPrefs.cpp'; fi`
 
+prefs/audacity-WaveformPrefs.o: prefs/WaveformPrefs.cpp
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT prefs/audacity-WaveformPrefs.o -MD -MP -MF prefs/$(DEPDIR)/audacity-WaveformPrefs.Tpo -c -o prefs/audacity-WaveformPrefs.o `test -f 'prefs/WaveformPrefs.cpp' || echo '$(srcdir)/'`prefs/WaveformPrefs.cpp
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) prefs/$(DEPDIR)/audacity-WaveformPrefs.Tpo prefs/$(DEPDIR)/audacity-WaveformPrefs.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='prefs/WaveformPrefs.cpp' object='prefs/audacity-WaveformPrefs.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o prefs/audacity-WaveformPrefs.o `test -f 'prefs/WaveformPrefs.cpp' || echo '$(srcdir)/'`prefs/WaveformPrefs.cpp
+
+prefs/audacity-WaveformPrefs.obj: prefs/WaveformPrefs.cpp
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT prefs/audacity-WaveformPrefs.obj -MD -MP -MF prefs/$(DEPDIR)/audacity-WaveformPrefs.Tpo -c -o prefs/audacity-WaveformPrefs.obj `if test -f 'prefs/WaveformPrefs.cpp'; then $(CYGPATH_W) 'prefs/WaveformPrefs.cpp'; else $(CYGPATH_W) '$(srcdir)/prefs/WaveformPrefs.cpp'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) prefs/$(DEPDIR)/audacity-WaveformPrefs.Tpo prefs/$(DEPDIR)/audacity-WaveformPrefs.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='prefs/WaveformPrefs.cpp' object='prefs/audacity-WaveformPrefs.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o prefs/audacity-WaveformPrefs.obj `if test -f 'prefs/WaveformPrefs.cpp'; then $(CYGPATH_W) 'prefs/WaveformPrefs.cpp'; else $(CYGPATH_W) '$(srcdir)/prefs/WaveformPrefs.cpp'; fi`
+
+prefs/audacity-WaveformSettings.o: prefs/WaveformSettings.cpp
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT prefs/audacity-WaveformSettings.o -MD -MP -MF prefs/$(DEPDIR)/audacity-WaveformSettings.Tpo -c -o prefs/audacity-WaveformSettings.o `test -f 'prefs/WaveformSettings.cpp' || echo '$(srcdir)/'`prefs/WaveformSettings.cpp
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) prefs/$(DEPDIR)/audacity-WaveformSettings.Tpo prefs/$(DEPDIR)/audacity-WaveformSettings.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='prefs/WaveformSettings.cpp' object='prefs/audacity-WaveformSettings.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o prefs/audacity-WaveformSettings.o `test -f 'prefs/WaveformSettings.cpp' || echo '$(srcdir)/'`prefs/WaveformSettings.cpp
+
+prefs/audacity-WaveformSettings.obj: prefs/WaveformSettings.cpp
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT prefs/audacity-WaveformSettings.obj -MD -MP -MF prefs/$(DEPDIR)/audacity-WaveformSettings.Tpo -c -o prefs/audacity-WaveformSettings.obj `if test -f 'prefs/WaveformSettings.cpp'; then $(CYGPATH_W) 'prefs/WaveformSettings.cpp'; else $(CYGPATH_W) '$(srcdir)/prefs/WaveformSettings.cpp'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) prefs/$(DEPDIR)/audacity-WaveformSettings.Tpo prefs/$(DEPDIR)/audacity-WaveformSettings.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='prefs/WaveformSettings.cpp' object='prefs/audacity-WaveformSettings.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o prefs/audacity-WaveformSettings.obj `if test -f 'prefs/WaveformSettings.cpp'; then $(CYGPATH_W) 'prefs/WaveformSettings.cpp'; else $(CYGPATH_W) '$(srcdir)/prefs/WaveformSettings.cpp'; fi`
+
 toolbars/audacity-ControlToolBar.o: toolbars/ControlToolBar.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT toolbars/audacity-ControlToolBar.o -MD -MP -MF toolbars/$(DEPDIR)/audacity-ControlToolBar.Tpo -c -o toolbars/audacity-ControlToolBar.o `test -f 'toolbars/ControlToolBar.cpp' || echo '$(srcdir)/'`toolbars/ControlToolBar.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) toolbars/$(DEPDIR)/audacity-ControlToolBar.Tpo toolbars/$(DEPDIR)/audacity-ControlToolBar.Po
diff --git a/src/Menus.cpp b/src/Menus.cpp
index 3e2bc18f62a8d3c55b1dcb01bd1c927e4b8e1b22..b4665ed36026de7061499103471186dbd4adcaec 100644
--- a/src/Menus.cpp
+++ b/src/Menus.cpp
@@ -31,6 +31,7 @@ simplifies construction of menu items.
 *//*******************************************************************/
 
 #include "Audacity.h"
+#include "Project.h"
 
 #include <iterator>
 #include <limits>
@@ -53,7 +54,6 @@ simplifies construction of menu items.
 #include "effects/Contrast.h"
 #include "TrackPanel.h"
 
-#include "Project.h"
 #include "effects/EffectManager.h"
 
 #include "AudacityApp.h"
@@ -119,6 +119,8 @@ simplifies construction of menu items.
 
 #include "Snap.h"
 
+#include "WaveTrack.h"
+
 #if defined(EXPERIMENTAL_CRASH_REPORT)
 #include <wx/debugrpt.h>
 #endif
@@ -3551,7 +3553,7 @@ void AudacityProject::OnExportMultiple()
 
 void AudacityProject::OnPreferences()
 {
-   PrefsDialog dialog(this /* parent */ );
+   GlobalPrefsDialog dialog(this /* parent */ );
 
    if (!dialog.ShowModal()) {
       // Canceled
@@ -4730,12 +4732,7 @@ void AudacityProject::DoNextPeakFrequency(bool up)
    for (Track *t = iter.First(); t; t = iter.Next()) {
       WaveTrack *const wt = static_cast<WaveTrack*>(t);
       const int display = wt->GetDisplay();
-      if (display == WaveTrack::SpectrumDisplay ||
-          display == WaveTrack::SpectrumLogDisplay ||
-          display == WaveTrack::SpectralSelectionDisplay ||
-          display == WaveTrack::SpectralSelectionLogDisplay 
-          
-          ) {
+      if (display == WaveTrack::Spectrum) {
          pTrack = wt;
          break;
       }
diff --git a/src/Mix.cpp b/src/Mix.cpp
index 50fc1561494fc4178802ba4775e84930c3ded036..3ed5e4b7d3e625860fcf89d794f88df3e160cfd9 100644
--- a/src/Mix.cpp
+++ b/src/Mix.cpp
@@ -35,11 +35,11 @@
 
 #include "WaveTrack.h"
 #include "DirManager.h"
-#include "Envelope.h"
 #include "Internat.h"
 #include "Prefs.h"
 #include "Project.h"
 #include "Resample.h"
+#include "TimeTrack.h"
 #include "float_cast.h"
 
 //TODO-MB: wouldn't it make more sense to delete the time track after 'mix and render'?
diff --git a/src/Mix.h b/src/Mix.h
index b4274d5898222a7d430116217802e152766da4b3..475ae6b3176e49da30cc3d4a9abcbc41a13af16a 100644
--- a/src/Mix.h
+++ b/src/Mix.h
@@ -15,11 +15,13 @@
 #include <wx/string.h>
 
 #include "SampleFormat.h"
-#include "WaveTrack.h"
-#include "TimeTrack.h"
 #include "Resample.h"
 
 class DirManager;
+class TimeTrack;
+class TrackFactory;
+class TrackList;
+class WaveTrack;
 
 /** @brief Mixes together all input tracks, applying any envelopes, amplitude
  * gain, panning, and real-time effects in the process.
diff --git a/src/MixerBoard.cpp b/src/MixerBoard.cpp
index c6813ea21d1ee082ade6616e29e78cf8a9478706..b0f9ffaebe8cc694450b6ba3fe8567130002d280 100644
--- a/src/MixerBoard.cpp
+++ b/src/MixerBoard.cpp
@@ -10,8 +10,8 @@
 **********************************************************************/
 
 #include "Audacity.h"
-
 #include "Experimental.h"
+#include "MixerBoard.h"
 
 #include <math.h>
 
@@ -22,12 +22,14 @@
 
 #include "AColor.h"
 #include "AudioIO.h"
-#include "MixerBoard.h"
 #ifdef EXPERIMENTAL_MIDI_OUT
    #include "NoteTrack.h"
 #endif
 #include "Project.h"
-#include "Track.h"
+#include "TrackPanel.h" // for EVT_TRACK_PANEL_TIMER
+#include "WaveTrack.h"
+
+#include "widgets/Meter.h"
 
 
 #include "../images/MusicalInstruments.h"
@@ -1015,6 +1017,12 @@ MixerBoard::MixerBoard(AudacityProject* pProject,
 
    mPrevT1 = 0.0;
    mTracks = mProject->GetTracks();
+
+   // Events from the project don't propagate directly to this other frame, so...
+   mProject->Connect(EVT_TRACK_PANEL_TIMER,
+      wxCommandEventHandler(MixerBoard::OnTimer),
+      NULL,
+      this);
 }
 
 MixerBoard::~MixerBoard()
@@ -1032,6 +1040,11 @@ MixerBoard::~MixerBoard()
 
    // private data members
    mMusicalInstruments.Clear();
+
+   mProject->Disconnect(EVT_TRACK_PANEL_TIMER,
+      wxCommandEventHandler(MixerBoard::OnTimer),
+      NULL,
+      this);
 }
 
 // Reassign mixer input strips (MixerTrackClusters) to Track Clusters
@@ -1691,6 +1704,30 @@ void MixerBoard::OnSize(wxSizeEvent &evt)
    this->RefreshTrackClusters(true);
 }
 
+void MixerBoard::OnTimer(wxCommandEvent &event)
+{
+   // PRL 12 Jul 2015:  Moved the below (with comments) out of TrackPanel::OnTimer.
+
+   // Vaughan, 2011-01-28: No longer doing this on timer.
+   //   Now it's in AudioIO::SetMeters() and AudioIO::StopStream(), as with Meter Toolbar meters.
+   //if (pMixerBoard)
+   //   pMixerBoard->ResetMeters(false);
+
+   //v Vaughan, 2011-02-25: Moved this update back here from audacityAudioCallback.
+   //    See note there.
+   // Vaughan, 2010-01-30:
+   //    Since all we're doing here is updating the meters, I moved it to
+   //    audacityAudioCallback where it calls gAudioIO->mOutputMeter->UpdateDisplay().
+   if (mProject->IsAudioActive())
+   {
+      UpdateMeters(gAudioIO->GetStreamTime(),
+         (mProject->mLastPlayMode == loopedPlay));
+   }
+
+   // Let other listeners get the notification
+   event.Skip();
+}
+
 
 // class MixerBoardFrame
 
@@ -1759,5 +1796,3 @@ void MixerBoardFrame::OnSize(wxSizeEvent & WXUNUSED(event))
 {
    mMixerBoard->SetSize(this->GetClientSize());
 }
-
-
diff --git a/src/MixerBoard.h b/src/MixerBoard.h
index 057420226caf9e017f648404f2dd0c4cb900cb40..0d3ead754bd033df326931925fc2e42eb8823a2a 100644
--- a/src/MixerBoard.h
+++ b/src/MixerBoard.h
@@ -24,7 +24,6 @@
 
 #include "widgets/AButton.h"
 #include "widgets/ASlider.h"
-#include "widgets/Meter.h"
 
 // containment hierarchy:
 //    MixerBoardFrame -> MixerBoard -> MixerBoardScrolledWindow -> MixerTrackCluster(s)
@@ -45,7 +44,7 @@ public:
                      bool canUseShift = true,
                      float stepValue = STEP_CONTINUOUS,
                      int orientation = wxHORIZONTAL);
-   virtual ~MixerTrackSlider() {};
+   virtual ~MixerTrackSlider() {}
 
    void OnMouseEvent(wxMouseEvent & event);
 
@@ -61,6 +60,7 @@ public:
 
 
 class AudacityProject;
+class Meter;
 class MixerBoard;
 #ifdef EXPERIMENTAL_MIDI_OUT
 class Track;
@@ -76,7 +76,7 @@ public:
                      WaveTrack* pLeftTrack, WaveTrack* pRightTrack = NULL,
                      const wxPoint& pos = wxDefaultPosition,
                      const wxSize& size = wxDefaultSize);
-   virtual ~MixerTrackCluster() {};
+   virtual ~MixerTrackCluster() {}
 
    void HandleResize(); // For wxSizeEvents, update gain slider and meter.
 
@@ -265,6 +265,7 @@ private:
 
    // event handlers
    void OnSize(wxSizeEvent &evt);
+   void OnTimer(wxCommandEvent &event);
 
 
 public:
diff --git a/src/NumberScale.h b/src/NumberScale.h
new file mode 100644
index 0000000000000000000000000000000000000000..b68a557f5e62dc7846c44f93c4bc484c5edb8cec
--- /dev/null
+++ b/src/NumberScale.h
@@ -0,0 +1,279 @@
+/**********************************************************************
+
+Audacity: A Digital Audio Editor
+
+NumberScale.h
+
+Paul Licameli
+
+**********************************************************************/
+
+#ifndef __AUDACITY_NUMBER_SCALE__
+#define __AUDACITY_NUMBER_SCALE__
+
+#include <algorithm>
+#include <cmath>
+#include <wx/defs.h>
+#include <wx/debug.h>
+
+enum NumberScaleType {
+   nstLinear,
+   nstLogarithmic,
+   nstMel,
+   nstBark,
+   nstErb,
+   nstUndertone,
+
+   nstNumScaleTypes,
+};
+
+
+class NumberScale
+{
+public:
+   NumberScale(NumberScaleType type,
+      float value0, float value1, float unit)
+      : mType(type)
+   {
+      switch (mType) {
+      case nstLinear:
+      {
+         mValue0 = value0 / unit;
+         mValue1 = value1 / unit;
+         mUnit = 1.0;
+      }
+      break;
+      case nstLogarithmic:
+      {
+         mValue0 = logf(value0 / unit);
+         mValue1 = logf(value1 / unit);
+         mUnit = 1.0;
+      }
+      break;
+      case nstMel:
+      {
+         mValue0 = hzToMel(value0);
+         mValue1 = hzToMel(value1);
+         mUnit = unit;
+      }
+      break;
+      case nstBark:
+      {
+         mValue0 = hzToBark(value0);
+         mValue1 = hzToBark(value1);
+         mUnit = unit;
+      }
+      break;
+      case nstErb:
+      {
+         mValue0 = hzToErb(value0);
+         mValue1 = hzToErb(value1);
+         mUnit = unit;
+      }
+      break;
+      case nstUndertone:
+      {
+         mValue0 = hzToUndertone(value0);
+         mValue1 = hzToUndertone(value1);
+         mUnit = unit;
+      }
+      break;
+      default:
+         wxASSERT(false);
+      }
+   }
+
+   NumberScale Reversal() const
+   {
+      NumberScale result(*this);
+      std::swap(result.mValue0, result.mValue1);
+      return result;
+   }
+
+   bool operator == (const NumberScale& other) const
+   {
+      return mType == other.mType
+         && mValue0 == other.mValue0
+         && mValue1 == other.mValue1
+         && mUnit == other.mUnit;
+   }
+
+   bool operator != (const NumberScale &other) const
+   {
+      return !(*this == other);
+   }
+
+   static inline float hzToMel(float hz)
+   {
+      return 1127 * log(1 + hz / 700);
+   }
+
+   static inline float melToHz(float mel)
+   {
+      return 700 * (exp(mel / 1127) - 1);
+   }
+
+   static inline float hzToBark(float hz)
+   {
+      // Traunmueller's formula
+      const float z1 = 26.81 * hz / (1960 + hz) - 0.53;
+      if (z1 < 2.0)
+         return z1 + 0.15 * (2.0 - z1);
+      else if (z1 > 20.1)
+         return z1 + 0.22 * (z1 - 20.1);
+      else
+         return z1;
+   }
+
+   static inline float barkToHz(float z1)
+   {
+      if (z1 < 2.0)
+         z1 = 2.0 + (z1 - 2.0) / 0.85;
+      else if (z1 > 20.1)
+         z1 = 20.1 + (z1 - 20.1) / 1.22;
+      return 1960 * (z1 + 0.53) / (26.28 - z1);
+   }
+
+   static inline float hzToErb(float hz)
+   {
+      return 11.17268 * log(1 + (46.06538 * hz) / (hz + 14678.49));
+   }
+
+   static inline float erbToHz(float erb)
+   {
+      return 676170.4 / (47.06538 - exp(0.08950404 * erb)) - 14678.49;
+   }
+
+   static inline float hzToUndertone(float hz)
+   {
+      return -1.0 / std::max (1.0f, hz);
+   }
+
+   static inline float undertoneToHz(float u)
+   {
+      return -1.0 / u;
+   }
+
+   // Random access
+   float PositionToValue(float pp) const
+   {
+      switch (mType) {
+      default:
+         wxASSERT(false);
+      case nstLinear:
+         return mValue0 + pp * (mValue1 - mValue0);
+      case nstLogarithmic:
+         return exp(mValue0 + pp * (mValue1 - mValue0));
+      case nstMel:
+         return melToHz(mValue0 + pp * (mValue1 - mValue0)) / mUnit;
+      case nstBark:
+         return barkToHz(mValue0 + pp * (mValue1 - mValue0)) / mUnit;
+      case nstErb:
+         return erbToHz(mValue0 + pp * (mValue1 - mValue0)) / mUnit;
+      case nstUndertone:
+         return undertoneToHz(mValue0 + pp * (mValue1 - mValue0)) / mUnit;
+      }
+   }
+
+   // STL-idiom iteration
+
+   class Iterator
+   {
+   public:
+      Iterator(NumberScaleType type, float step, float value, float unit)
+         : mType(type), mStep(step), mValue(value), mUnit(unit)
+      {
+      }
+
+      float operator * () const
+      {
+         switch (mType) {
+         default:
+            wxASSERT(false);
+         case nstLinear:
+         case nstLogarithmic:
+            return mValue;
+         case nstMel:
+            return melToHz(mValue) / mUnit;
+         case nstBark:
+            return barkToHz(mValue) / mUnit;
+         case nstErb:
+            return erbToHz(mValue) / mUnit;
+         case nstUndertone:
+            return undertoneToHz(mValue) / mUnit;
+         }
+      }
+
+      Iterator &operator ++()
+      {
+         switch (mType) {
+         case nstLinear:
+         case nstMel:
+         case nstBark:
+         case nstErb:
+         case nstUndertone:
+            mValue += mStep;
+            break;
+         case nstLogarithmic:
+            mValue *= mStep;
+            break;
+         default:
+            wxASSERT(false);
+         }
+         return *this;
+      }
+
+   private:
+      const NumberScaleType mType;
+      const float mStep;
+      float mValue;
+      float mUnit;
+   };
+
+   Iterator begin(float nPositions) const
+   {
+      switch (mType) {
+      default:
+         wxASSERT(false);
+      case nstLinear:
+      case nstMel:
+      case nstBark:
+      case nstErb:
+      case nstUndertone:
+         return Iterator
+            (mType, (mValue1 - mValue0) / nPositions, mValue0, mUnit);
+      case nstLogarithmic:
+         return Iterator
+            (mType, exp((mValue1 - mValue0) / nPositions), exp(mValue0), mUnit);
+      }
+   }
+
+   // Inverse
+   float ValueToPosition(float val) const
+   {
+      switch (mType) {
+      default:
+         wxASSERT(false);
+      case nstLinear:
+         return ((val - mValue0) / (mValue1 - mValue0));
+      case nstLogarithmic:
+         return ((log(val) - mValue0) / (mValue1 - mValue0));
+      case nstMel:
+         return ((hzToMel(val * mUnit) - mValue0) / (mValue1 - mValue0));
+      case nstBark:
+         return ((hzToBark(val * mUnit) - mValue0) / (mValue1 - mValue0));
+      case nstErb:
+         return ((hzToErb(val * mUnit) - mValue0) / (mValue1 - mValue0));
+      case nstUndertone:
+         return ((hzToUndertone(val * mUnit) - mValue0) / (mValue1 - mValue0));
+      }
+   }
+
+private:
+   const NumberScaleType mType;
+   float mValue0;
+   float mValue1;
+   float mUnit;
+};
+
+#endif
diff --git a/src/Printing.cpp b/src/Printing.cpp
index 3e9f8974dd3dd7e2b1d0e3873d157bce75802e5d..18362f1e94ea674c55a46177c6f05327a7aa1704 100644
--- a/src/Printing.cpp
+++ b/src/Printing.cpp
@@ -25,7 +25,6 @@
 #include <wx/printdlg.h>
 
 #include "AColor.h"
-#include "Track.h"
 #include "TrackArtist.h"
 #include "ViewInfo.h"
 #include "WaveTrack.h"
diff --git a/src/Project.cpp b/src/Project.cpp
index 3802101139e3d216abbaeb631ca56cb235117f80..297de91d901366ed0b5613cae7bcb7fa46b4aeb8 100644
--- a/src/Project.cpp
+++ b/src/Project.cpp
@@ -110,10 +110,10 @@ scroll information.  It also has some status flags.
 #include "Mix.h"
 #include "NoteTrack.h"
 #include "Prefs.h"
+#include "Sequence.h"
 #include "Snap.h"
 #include "Tags.h"
 #include "TimeTrack.h"
-#include "Track.h"
 #include "TrackPanel.h"
 #include "WaveTrack.h"
 #include "DirManager.h"
@@ -121,7 +121,6 @@ scroll information.  It also has some status flags.
 #include "prefs/PrefsDialog.h"
 #include "widgets/LinkingHtmlWindow.h"
 #include "widgets/ErrorDialog.h"
-#include "widgets/Meter.h"
 #include "widgets/Ruler.h"
 #include "widgets/Warning.h"
 #include "xml/XMLFileReader.h"
@@ -1162,7 +1161,7 @@ AdornedRulerPanel *AudacityProject::GetRulerPanel()
    return mRuler;
 }
 
-int AudacityProject::GetAudioIOToken()
+int AudacityProject::GetAudioIOToken() const
 {
    return mAudioIOToken;
 }
@@ -1172,6 +1171,12 @@ void AudacityProject::SetAudioIOToken(int token)
    mAudioIOToken = token;
 }
 
+bool AudacityProject::IsAudioActive() const
+{
+   return GetAudioIOToken() > 0 &&
+      gAudioIO->IsStreamActive(GetAudioIOToken());
+}
+
 Tags *AudacityProject::GetTags()
 {
    return mTags;
@@ -1208,6 +1213,11 @@ void AudacityProject::SetProjectTitle()
    SetName(name);       // to make the nvda screen reader read the correct title
 }
 
+bool AudacityProject::GetIsEmpty()
+{
+   return mTracks->IsEmpty();
+}
+
 double AudacityProject::AS_GetRate()
 {
    return mRate;
@@ -1250,7 +1260,18 @@ void AudacityProject::AS_SetSelectionFormat(const wxString & format)
 
 double AudacityProject::SSBL_GetRate() const
 {
-   return mRate;
+   // Return maximum of project rate and all track rates.
+   double rate = mRate;
+
+   TrackListOfKindIterator iterWaveTrack(Track::Wave, mTracks);
+   WaveTrack *pWaveTrack = static_cast<WaveTrack*>(iterWaveTrack.First());
+   while (pWaveTrack)
+   {
+      rate = std::max(rate, pWaveTrack->GetRate());
+      pWaveTrack = static_cast<WaveTrack*>(iterWaveTrack.Next());
+   }
+
+   return rate;
 }
 
 const wxString & AudacityProject::SSBL_GetFrequencySelectionFormatName()
@@ -1282,7 +1303,7 @@ void AudacityProject::SSBL_SetBandwidthSelectionFormatName(const wxString & form
 void AudacityProject::SSBL_ModifySpectralSelection(double &bottom, double &top, bool done)
 {
 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
-   double nyq = mRate / 2.0;
+   double nyq = SSBL_GetRate() / 2.0;
    if (bottom >= 0.0)
       bottom = std::min(nyq, bottom);
    if (top >= 0.0)
@@ -2949,6 +2970,8 @@ bool AudacityProject::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
          SetBandwidthSelectionFormatName(value);
    } // while
 
+   mViewInfo.UpdatePrefs();
+
    if (longVpos != 0) {
       // PRL: It seems this must happen after SetSnapTo
        mViewInfo.track = NULL;
@@ -3861,6 +3884,11 @@ void AudacityProject::PushState(wxString desc,
       AutoSave();
 }
 
+void AudacityProject::RollbackState()
+{
+   SetStateTo(GetUndoManager()->GetCurrentState());
+}
+
 void AudacityProject::ModifyState(bool bWantsAutoSave)
 {
    mUndoManager.ModifyState(mTracks, mViewInfo.selectedRegion);
@@ -4353,7 +4381,7 @@ void AudacityProject::GetRegionsByLabel( Regions &regions )
 //If the function replaces the selection with audio of a different length,
 // bSyncLockedTracks should be set true to perform the same action on sync-lock selected
 // tracks.
-void AudacityProject::EditByLabel( WaveTrack::EditFunction action,
+void AudacityProject::EditByLabel( EditFunction action,
                                    bool bSyncLockedTracks )
 {
    Regions regions;
@@ -4402,7 +4430,7 @@ void AudacityProject::EditByLabel( WaveTrack::EditFunction action,
 //Functions copy the edited regions to clipboard, possibly in multiple tracks
 //This probably should not be called if *action() changes the timeline, because
 // the copy needs to happen by track, and the timeline change by group.
-void AudacityProject::EditClipboardByLabel( WaveTrack::EditDestFunction action )
+void AudacityProject::EditClipboardByLabel( EditDestFunction action )
 {
    Regions regions;
 
diff --git a/src/Project.h b/src/Project.h
index 98cc9ffac8d89719d366ff83c16b07039a39d6f5..2c6b034be42fcec888715a732821a652df187240 100644
--- a/src/Project.h
+++ b/src/Project.h
@@ -86,6 +86,9 @@ class MixerBoardFrame;
 
 struct AudioIOStartStreamOptions;
 
+class WaveTrackArray;
+class Regions;
+
 AudacityProject *CreateNewAudacityProject();
 AUDACITY_DLL_API AudacityProject *GetActiveProject();
 void RedrawAllProjects();
@@ -179,7 +182,8 @@ class AUDACITY_DLL_API AudacityProject:  public wxFrame,
    TrackFactory *GetTrackFactory();
    AdornedRulerPanel *GetRulerPanel();
    Tags *GetTags();
-   int GetAudioIOToken();
+   int GetAudioIOToken() const;
+   bool IsAudioActive() const;
    void SetAudioIOToken(int token);
 
    bool IsActive();
@@ -241,7 +245,7 @@ class AUDACITY_DLL_API AudacityProject:  public wxFrame,
 
    TrackPanel * GetTrackPanel(){return mTrackPanel;}
 
-   bool GetIsEmpty() { return mTracks->IsEmpty(); }
+   bool GetIsEmpty();
 
    bool GetTracksFitVerticallyZoomed() { return mTracksFitVerticallyZoomed; } //lda
    void SetTracksFitVerticallyZoomed(bool flag) { mTracksFitVerticallyZoomed = flag; } //lda
@@ -321,8 +325,14 @@ class AUDACITY_DLL_API AudacityProject:  public wxFrame,
    void ZoomBy(double multiplier);
    void Rewind(bool shift);
    void SkipEnd(bool shift);
-   void EditByLabel( WaveTrack::EditFunction action, bool bSyncLockedTracks );
-   void EditClipboardByLabel( WaveTrack::EditDestFunction action );
+
+
+   typedef bool (WaveTrack::* EditFunction)(double, double);
+   typedef bool (WaveTrack::* EditDestFunction)(double, double, Track**);
+
+   void EditByLabel(EditFunction action, bool bSyncLockedTracks);
+   void EditClipboardByLabel(EditDestFunction action );
+
    bool IsSyncLocked();
    void SetSyncLock(bool flag);
 
@@ -468,6 +478,7 @@ class AUDACITY_DLL_API AudacityProject:  public wxFrame,
 
    void PushState(wxString desc, wxString shortDesc,
                   int flags = PUSH_AUTOSAVE);
+   void RollbackState();
 
  private:
 
diff --git a/src/Screenshot.cpp b/src/Screenshot.cpp
index 94fc80c3396a097acb062dc9705f961b6449e1ff..af6513968b21f06fd5ed82b4f201681a052c193e 100644
--- a/src/Screenshot.cpp
+++ b/src/Screenshot.cpp
@@ -34,6 +34,8 @@
 #include "Prefs.h"
 #include "toolbars/ToolManager.h"
 
+#include "Track.h"
+
 class CommandType;
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/Snap.cpp b/src/Snap.cpp
index 951c8119784077cd7ee4d390c47b7f4fa0e6c3f5..f8c7a4dffe676efae1befbdc46e561dd3ed1996d 100644
--- a/src/Snap.cpp
+++ b/src/Snap.cpp
@@ -16,6 +16,7 @@
 #include "LabelTrack.h"
 #include "Project.h"
 #include "TrackPanel.h"
+#include "WaveTrack.h"
 #include "widgets/NumericTextCtrl.h"
 
 // Change this to "true" to snap to nearest and "false" to snap to previous
@@ -81,7 +82,7 @@ SnapManager::SnapManager(TrackList *tracks, TrackClipArray *exclusions,
             WaveClip *clip = it->GetData();
             if (exclusions) {
                bool skip = false;
-               for(int j=0; j<(int)exclusions->GetCount(); j++) {
+               for(int j=0; j<(int)exclusions->size(); j++) {
                   if ((*exclusions)[j].track == waveTrack &&
                       (*exclusions)[j].clip == clip)
                      skip = true;
diff --git a/src/Snap.h b/src/Snap.h
index a3e9fe82c1cbc9bd8431dbb85d7031ce11bb273f..478a49e0e46b03aacd19d07bae53040f849b8983 100644
--- a/src/Snap.h
+++ b/src/Snap.h
@@ -15,15 +15,27 @@
 #ifndef __AUDACITY_SNAP__
 #define __AUDACITY_SNAP__
 
+#include <vector>
+
 #include <wx/defs.h>
-#include <wx/dynarray.h>
 
-#include "Track.h"
 #include "widgets/NumericTextCtrl.h"
 
-class TrackClipArray;
+class Track;
+class WaveClip;
+class TrackList;
 class ZoomInfo;
 
+class TrackClip
+{
+public:
+   TrackClip(Track *t, WaveClip *c) { track = t; clip = c; }
+   Track *track;
+   WaveClip *clip;
+};
+
+typedef std::vector<TrackClip> TrackClipArray;
+
 enum
 {
    SNAP_OFF,
diff --git a/src/SoundActivatedRecord.cpp b/src/SoundActivatedRecord.cpp
index 671380b96efe09d7bd48416d1d2c5e9744104bbc..29f896e1721523941701f8c8c81006d853356576 100644
--- a/src/SoundActivatedRecord.cpp
+++ b/src/SoundActivatedRecord.cpp
@@ -19,14 +19,12 @@
 *//********************************************************************/
 
 #include "Audacity.h"
+#include "SoundActivatedRecord.h"
 
-#include <wx/dialog.h>
-
-#include "Envelope.h"
 #include "ShuttleGui.h"
 #include "ShuttlePrefs.h"
 #include "Prefs.h"
-#include "SoundActivatedRecord.h"
+#include "prefs/GUISettings.h"
 
 BEGIN_EVENT_TABLE(SoundActivatedRecord, wxDialog)
    EVT_BUTTON(wxID_OK, SoundActivatedRecord::OnOK)
@@ -57,7 +55,7 @@ void SoundActivatedRecord::PopulateOrExchange(ShuttleGui & S)
    {
       S.StartMultiColumn(2, wxEXPAND);
          S.SetStretchyCol(1);
-         dBRange = gPrefs->Read(wxT("/GUI/EnvdBRange"), ENV_DB_RANGE);
+         dBRange = gPrefs->Read(ENV_DB_KEY, ENV_DB_RANGE);
          S.TieSlider(_("Activation level (dB):"), wxT("/AudioIO/SilenceLevel"), -50, 0, -dBRange);
       S.EndMultiColumn();
    }
diff --git a/src/SoundActivatedRecord.h b/src/SoundActivatedRecord.h
index 71fef4d7516f621aba1ca864ac420e1bead192f0..a7397f3e0ca81bf3dd5cac8b4ddb051f6144e496 100644
--- a/src/SoundActivatedRecord.h
+++ b/src/SoundActivatedRecord.h
@@ -13,6 +13,13 @@
 
 ********************************************************************/
 
+#ifndef __AUDACITY_SOUND_ACTIVATED_RECORD__
+#define __AUDACITY_SOUND_ACTIVATED_RECORD__
+
+#include <wx/dialog.h>
+
+class ShuttleGui;
+
 class SoundActivatedRecord : public wxDialog
 {
 public:
@@ -27,3 +34,4 @@ private:
    DECLARE_EVENT_TABLE();
 };
 
+#endif
diff --git a/src/Spectrum.h b/src/Spectrum.h
index 64e0e28cb473c7e6b86e174e1dfd2142d4c7fe77..f600a05b8644c0ed47453e0b33f8f885075163dd 100644
--- a/src/Spectrum.h
+++ b/src/Spectrum.h
@@ -11,7 +11,6 @@
 #ifndef __AUDACITY_SPECTRUM__
 #define __AUDACITY_SPECTRUM__
 
-#include "WaveTrack.h"
 #include "FFT.h"
 
 /*
diff --git a/src/Theme.cpp b/src/Theme.cpp
index 386d4b004fd26cff10a012e141b58b8b07665a16..88f2aabfd48a7091dcb0253cdb7c8461904e70d2 100644
--- a/src/Theme.cpp
+++ b/src/Theme.cpp
@@ -60,6 +60,7 @@ and use it for toolbar and window layouts too.
 #include <wx/file.h>
 #include <wx/ffile.h>
 #include <wx/mstream.h>
+#include <wx/msgdlg.h>
 
 #include "Project.h"
 #include "toolbars/ToolBar.h"
diff --git a/src/TimeTrack.cpp b/src/TimeTrack.cpp
index ea121cf4aa1cfe913a9019dbb917f7173d3dc6ed..24464efd7db354d36319b8345c96ca8124410fd1 100644
--- a/src/TimeTrack.cpp
+++ b/src/TimeTrack.cpp
@@ -19,6 +19,7 @@
 #include <wx/intl.h>
 #include "AColor.h"
 #include "widgets/Ruler.h"
+#include "Envelope.h"
 #include "Prefs.h"
 #include "Internat.h"
 #include "Resample.h"
diff --git a/src/TimerRecordDialog.cpp b/src/TimerRecordDialog.cpp
index 1aa1954202cf333aa36f15733a40036fcc0dfa36..5295a861414571473586ea08810b442d55b9fa3c 100644
--- a/src/TimerRecordDialog.cpp
+++ b/src/TimerRecordDialog.cpp
@@ -29,6 +29,7 @@
 #include <wx/string.h>
 #include <wx/timer.h>
 #include <wx/dynlib.h> //<! For windows.h
+#include <wx/msgdlg.h>
 
 #include "ShuttleGui.h"
 #include "Project.h"
diff --git a/src/Track.cpp b/src/Track.cpp
index ae91bd2702b512be36fdae2ba817a01b197d15d0..07fc7a0aacaa1dfbca537c222895f68ebe1745fa 100644
--- a/src/Track.cpp
+++ b/src/Track.cpp
@@ -23,9 +23,7 @@ and TimeTrack.
 #include "Track.h"
 #include "WaveTrack.h"
 #include "NoteTrack.h"
-#include "LabelTrack.h"
 #include "Project.h"
-#include "TimeTrack.h"
 #include "DirManager.h"
 
 #ifdef _MSC_VER
diff --git a/src/TrackArtist.cpp b/src/TrackArtist.cpp
index 3c7624b2fb6cc2f358637661abf5402f2594daf6..c78d210b9d4fa17dd0d03c0ea5ddafff9f36c999 100644
--- a/src/TrackArtist.cpp
+++ b/src/TrackArtist.cpp
@@ -168,13 +168,14 @@ audio tracks.
 #include "AColor.h"
 #include "BlockFile.h"
 #include "Envelope.h"
-#include "Track.h"
+#include "NumberScale.h"
 #include "WaveTrack.h"
 #include "LabelTrack.h"
 #include "TimeTrack.h"
 #include "Prefs.h"
-#include "prefs/SpectrumPrefs.h"
-#include "Sequence.h"
+#include "prefs/GUISettings.h"
+#include "prefs/SpectrogramSettings.h"
+#include "prefs/WaveformSettings.h"
 #include "Spectrum.h"
 #include "ViewInfo.h"
 #include "widgets/Ruler.h"
@@ -459,19 +460,11 @@ void TrackArtist::DrawTrack(const Track * t,
       bool muted = (hasSolo || t->GetMute()) && !t->GetSolo();
 
       switch (wt->GetDisplay()) {
-      case WaveTrack::WaveformDisplay:
+      case WaveTrack::Waveform:
          DrawWaveform(wt, dc, rect, selectedRegion, zoomInfo,
-                      drawEnvelope, bigPoints, drawSliders, false, muted);
+                      drawEnvelope,  bigPoints, drawSliders, muted);
          break;
-      case WaveTrack::WaveformDBDisplay:
-         DrawWaveform(wt, dc, rect, selectedRegion, zoomInfo,
-                      drawEnvelope,  bigPoints, drawSliders, true, muted);
-         break;
-      case WaveTrack::SpectrumDisplay:
-      case WaveTrack::SpectrumLogDisplay:
-      case WaveTrack::SpectralSelectionDisplay:
-      case WaveTrack::SpectralSelectionLogDisplay:
-      case WaveTrack::PitchDisplay:
+      case WaveTrack::Spectrum:
          DrawSpectrum(wt, dc, rect, selectedRegion, zoomInfo);
          break;
       }
@@ -548,11 +541,6 @@ void TrackArtist::DrawVRuler(Track *t, wxDC * dc, wxRect & rect)
       bev.width += 1;
       AColor::BevelTrackInfo(*dc, true, bev);
 
-      // Pitch doesn't have a ruler
-      if (((WaveTrack *)t)->GetDisplay() == WaveTrack::PitchDisplay) {
-         return;
-      }
-
       // Right align the ruler
       wxRect rr = rect;
       rr.width--;
@@ -695,182 +683,187 @@ void TrackArtist::UpdateVRuler(Track *t, wxRect & rect)
    // All waves have a ruler in the info panel
    // The ruler needs a bevelled surround.
    if (t->GetKind() == Track::Wave) {
-      WaveTrack *wt = (WaveTrack *)t;
-      int display = wt->GetDisplay();
+      WaveTrack *wt = static_cast<WaveTrack*>(t);
 
-      if (display == WaveTrack::WaveformDisplay) {
-         // Waveform
+      const int display = wt->GetDisplay();
 
-         float min, max;
-         wt->GetDisplayBounds(&min, &max);
-         if(wt->GetLastDisplay()==WaveTrack::WaveformDBDisplay)
-         {
-            // do a translation into the WaveTrack::WaveformDisplay space
-            wt->SetDisplay(WaveTrack::WaveformDisplay); // this makes the last display not WaveformDBDisplay
-            float sign = (min >= 0 ? 1 : -1);
-            if (min != 0.) {
-               min = pow(10., (fabs(min)*mdBrange - mdBrange)/20.0);
-               if (min < 0.0)
-                  min = 0.0;
-               min *= sign;
-            }
-            sign = (max >= 0 ? 1 : -1);
+      if (display == WaveTrack::Waveform) {
+         WaveformSettings::ScaleType scaleType =
+            wt->GetWaveformSettings().scaleType;
 
-            if (max != 0.) {
-               max = pow(10., (fabs(max)*mdBrange - mdBrange)/20.0);
-               if (max < 0.0)
-                  max = 0.0;
-               max *= sign;
-            }
-            wt->SetDisplayBounds(min, max);
-         }
-
-         vruler->SetBounds(rect.x, rect.y+1, rect.x + rect.width, rect.y + rect.height-1);
-         vruler->SetOrientation(wxVERTICAL);
-         vruler->SetRange(max, min);
-         vruler->SetFormat(Ruler::RealFormat);
-         vruler->SetUnits(wxT(""));
-         vruler->SetLabelEdges(false);
-         vruler->SetLog(false);
-      }
-      else if (display == WaveTrack::WaveformDBDisplay) {
-         // Waveform (db)
+         if (scaleType == WaveformSettings::stLinear) {
+            // Waveform
 
-         vruler->SetUnits(wxT(""));
-
-         float min, max;
-         wt->GetDisplayBounds(&min, &max);
+            float min, max;
+            wt->GetDisplayBounds(&min, &max);
+            if (wt->GetLastScaleType() != scaleType)
+            {
+               // do a translation into the linear space
+               wt->SetLastScaleType(scaleType);
+               float sign = (min >= 0 ? 1 : -1);
+               if (min != 0.) {
+                  min = DB_TO_LINEAR(fabs(min)*mdBrange - mdBrange);
+                  if (min < 0.0)
+                     min = 0.0;
+                  min *= sign;
+               }
+               sign = (max >= 0 ? 1 : -1);
 
-         if(wt->GetLastDisplay()==WaveTrack::WaveformDisplay)
-         {
-            // do a translation into the WaveTrack::WaveformDBDisplay space
-            wt->SetDisplay(WaveTrack::WaveformDBDisplay); // this makes the last display not WaveformDisplay
-            float sign = (min >= 0 ? 1 : -1);
-            if (min != 0.) {
-               min = (20.0 * log10(fabs(min)) + mdBrange) / mdBrange;
-               if (min < 0.0)
-                  min = 0.0;
-               min *= sign;
+               if (max != 0.) {
+                  max = DB_TO_LINEAR(fabs(max)*mdBrange - mdBrange);
+                  if (max < 0.0)
+                     max = 0.0;
+                  max *= sign;
+               }
+               wt->SetDisplayBounds(min, max);
             }
-            sign = (max >= 0 ? 1 : -1);
 
-            if (max != 0.) {
-               max = (20.0 * log10(fabs(max)) + mdBrange) / mdBrange;
-               if (max < 0.0)
-                  max = 0.0;
-               max *= sign;
-            }
-            wt->SetDisplayBounds(min, max);
+            vruler->SetBounds(rect.x, rect.y + 1, rect.x + rect.width, rect.y + rect.height - 1);
+            vruler->SetOrientation(wxVERTICAL);
+            vruler->SetRange(max, min);
+            vruler->SetFormat(Ruler::RealFormat);
+            vruler->SetUnits(wxT(""));
+            vruler->SetLabelEdges(false);
+            vruler->SetLog(false);
          }
+         else {
+            wxASSERT(scaleType == WaveformSettings::stLogarithmic);
+            scaleType = WaveformSettings::stLogarithmic;
+
+            vruler->SetUnits(wxT(""));
 
-         if (max > 0) {
-            int top = 0;
-            float topval = 0;
-            int bot = rect.height;
-            float botval = -mdBrange;
+            float min, max;
+            wt->GetDisplayBounds(&min, &max);
 
-            if (min < 0) {
-               bot = top + (int)((max / (max-min))*(bot-top));
-               min = 0;
-            }
+            if (wt->GetLastScaleType() != scaleType)
+            {
+               // do a translation into the dB space
+               wt->SetLastScaleType(scaleType);
+               float sign = (min >= 0 ? 1 : -1);
+               if (min != 0.) {
+                  min = (LINEAR_TO_DB(fabs(min)) + mdBrange) / mdBrange;
+                  if (min < 0.0)
+                     min = 0.0;
+                  min *= sign;
+               }
+               sign = (max >= 0 ? 1 : -1);
 
-            if (max > 1) {
-               top += (int)((max-1)/(max-min) * (bot-top));
-               max = 1;
+               if (max != 0.) {
+                  max = (LINEAR_TO_DB(fabs(max)) + mdBrange) / mdBrange;
+                  if (max < 0.0)
+                     max = 0.0;
+                  max *= sign;
+               }
+               wt->SetDisplayBounds(min, max);
             }
 
-            if (max < 1 && max > 0)
-               topval = -((1-max)*mdBrange);
+            if (max > 0) {
+               int top = 0;
+               float topval = 0;
+               int bot = rect.height;
+               float botval = -mdBrange;
 
-            if (min > 0) {
-               botval = -((1-min)*mdBrange);
-            }
+               if (min < 0) {
+                  bot = top + (int)((max / (max - min))*(bot - top));
+                  min = 0;
+               }
 
-            vruler->SetBounds(rect.x, rect.y+top+1, rect.x + rect.width, rect.y + bot-1);
-            vruler->SetOrientation(wxVERTICAL);
-            vruler->SetRange(topval, botval);
-          }
-         else
-            vruler->SetBounds(0.0, 0.0, 0.0, 0.0); // A.C.H I couldn't find a way to just disable it?
-         vruler->SetFormat(Ruler::RealLogFormat);
-         vruler->SetLabelEdges(true);
-         vruler->SetLog(false);
-      }
-      else if ( 
-         (display == WaveTrack::SpectrumDisplay) || 
-         (display == WaveTrack::SpectralSelectionDisplay) )
-      {
-         // Spectrum
+               if (max > 1) {
+                  top += (int)((max - 1) / (max - min) * (bot - top));
+                  max = 1;
+               }
 
-         if (rect.height < 60)
-            return;
+               if (max < 1 && max > 0)
+                  topval = -((1 - max)*mdBrange);
 
-         double rate = wt->GetRate();
-         int freq = lrint(rate/2.);
+               if (min > 0) {
+                  botval = -((1 - min)*mdBrange);
+               }
+
+               vruler->SetBounds(rect.x, rect.y + top + 1, rect.x + rect.width, rect.y + bot - 1);
+               vruler->SetOrientation(wxVERTICAL);
+               vruler->SetRange(topval, botval);
+            }
+            else
+               vruler->SetBounds(0.0, 0.0, 0.0, 0.0); // A.C.H I couldn't find a way to just disable it?
+            vruler->SetFormat(Ruler::RealLogFormat);
+            vruler->SetLabelEdges(true);
+            vruler->SetLog(false);
+         }
+      }
+      else {
+         wxASSERT(display == WaveTrack::Spectrum);
+         switch (wt->GetSpectrogramSettings().scaleType) {
+         default:
+            wxASSERT(false);
+         case SpectrogramSettings::stLinear:
+         {
+            // Spectrum
 
-         int maxFreq = GetSpectrumMaxFreq(freq);
-         if(maxFreq > freq)
-            maxFreq = freq;
+            if (rect.height < 60)
+               return;
 
-         int minFreq = GetSpectrumMinFreq(0);
-         if(minFreq < 0)
-            minFreq = 0;
+            const SpectrogramSettings &settings = wt->GetSpectrogramSettings();
+            const double rate = wt->GetRate();
+            const int maxFreq = settings.GetMaxFreq(rate);
+            const int minFreq = settings.GetMinFreq(rate);
 
-         /*
+            /*
             draw the ruler
             we will use Hz if maxFreq is < 2000, otherwise we represent kHz,
             and append to the numbers a "k"
-         */
-         vruler->SetBounds(rect.x, rect.y+1, rect.x + rect.width, rect.y + rect.height-1);
-         vruler->SetOrientation(wxVERTICAL);
-         vruler->SetFormat(Ruler::RealFormat);
-         vruler->SetLabelEdges(true);
-         // use kHz in scale, if appropriate
-         if (maxFreq>=2000) {
-            vruler->SetRange((maxFreq/1000.), (minFreq/1000.));
-            vruler->SetUnits(wxT("k"));
-         } else {
-            // use Hz
-            vruler->SetRange(int(maxFreq), int(minFreq));
-            vruler->SetUnits(wxT(""));
+            */
+            vruler->SetBounds(rect.x, rect.y + 1, rect.x + rect.width, rect.y + rect.height - 1);
+            vruler->SetOrientation(wxVERTICAL);
+            vruler->SetFormat(Ruler::RealFormat);
+            vruler->SetLabelEdges(true);
+            // use kHz in scale, if appropriate
+            if (maxFreq >= 2000) {
+               vruler->SetRange((maxFreq / 1000.), (minFreq / 1000.));
+               vruler->SetUnits(wxT("k"));
+            }
+            else {
+               // use Hz
+               vruler->SetRange(int(maxFreq), int(minFreq));
+               vruler->SetUnits(wxT(""));
+            }
+            vruler->SetLog(false);
          }
-         vruler->SetLog(false);
-      }
-      else if ( 
-         (display == WaveTrack::SpectrumLogDisplay) || 
-         (display == WaveTrack::SpectralSelectionLogDisplay) )
-      {
-         // SpectrumLog
-
-         if (rect.height < 10)
-            return;
-
-         double rate = wt->GetRate();
-         int freq = lrint(rate/2.);
+         break;
+         case SpectrogramSettings::stLogarithmic:
+         case SpectrogramSettings::stMel:
+         case SpectrogramSettings::stBark:
+         case SpectrogramSettings::stErb:
+         case SpectrogramSettings::stUndertone:
+         {
+            // SpectrumLog
 
-         int maxFreq = GetSpectrumLogMaxFreq(freq);
-         if(maxFreq > freq)
-            maxFreq = freq;
+            if (rect.height < 10)
+               return;
 
-         int minFreq = GetSpectrumLogMinFreq(freq/1000.0);
-         if(minFreq < 1)
-            minFreq = 1;
+            const SpectrogramSettings &settings = wt->GetSpectrogramSettings();
+            const double rate = wt->GetRate();
+            const int maxFreq = settings.GetLogMaxFreq(rate);
+            const int minFreq = settings.GetLogMinFreq(rate);
 
-         /*
+            /*
             draw the ruler
             we will use Hz if maxFreq is < 2000, otherwise we represent kHz,
             and append to the numbers a "k"
-         */
-         vruler->SetBounds(rect.x, rect.y+1, rect.x + rect.width, rect.y + rect.height-1);
-         vruler->SetOrientation(wxVERTICAL);
-         vruler->SetFormat(Ruler::IntFormat);
-         vruler->SetLabelEdges(true);
-         vruler->SetRange(maxFreq, minFreq);
-         vruler->SetUnits(wxT(""));
-         vruler->SetLog(true);
-      }
-      else if (display == WaveTrack::PitchDisplay) {
-         // Pitch
+            */
+            vruler->SetBounds(rect.x, rect.y + 1, rect.x + rect.width, rect.y + rect.height - 1);
+            vruler->SetOrientation(wxVERTICAL);
+            vruler->SetFormat(Ruler::IntFormat);
+            vruler->SetLabelEdges(true);
+            vruler->SetRange(maxFreq, minFreq);
+            vruler->SetUnits(wxT(""));
+            vruler->SetLog(true);
+            NumberScale scale
+               (wt->GetSpectrogramSettings().GetScale(wt->GetRate(), false).Reversal());
+            vruler->SetNumberScale(&scale);
+         }
+         break;
+         }
       }
    }
 
@@ -903,7 +896,7 @@ int GetWaveYPos(float value, float min, float max,
       float sign = (value >= 0 ? 1 : -1);
 
       if (value != 0.) {
-         float db = 20.0 * log10(fabs(value));
+         float db = LINEAR_TO_DB(fabs(value));
          value = (db + dBr) / dBr;
          if (!outer) {
             value -= 0.5;
@@ -944,7 +937,7 @@ float FromDB(float value, double dBRange)
       return 0;
 
    double sign = (value >= 0 ? 1 : -1);
-   return pow(10.0, ((fabs(value) * dBRange) - dBRange) / 20.0)*sign;
+   return DB_TO_LINEAR((fabs(value) * dBRange) - dBRange) * sign;
 }
 
 float ValueOfPixel(int yy, int height, bool offset,
@@ -995,11 +988,10 @@ void TrackArtist::DrawNegativeOffsetTrackArrows(wxDC &dc, const wxRect &rect)
 void TrackArtist::DrawWaveformBackground(wxDC &dc, int leftOffset, const wxRect &rect,
                                          const double env[],
                                          float zoomMin, float zoomMax, bool dB,
-                                         const SelectedRegion &selectedRegion,
+                                         double t0, double t1,
                                          const ZoomInfo &zoomInfo,
                                          bool drawEnvelope, bool bIsSyncLockSelected)
 {
-   const double t0 = selectedRegion.t0(), t1 = selectedRegion.t1();
 
    // Visually (one vertical slice of the waveform background, on its side;
    // the "*" is the actual waveform background we're drawing
@@ -1431,9 +1423,10 @@ void TrackArtist::DrawWaveform(WaveTrack *track,
                                bool drawEnvelope,
                                bool bigPoints,
                                bool drawSliders,
-                               bool dB,
                                bool muted)
 {
+   const bool dB = !track->GetWaveformSettings().isLinear();
+
    DrawBackgroundWithSelection(&dc, rect, track, blankSelectedBrush, blankBrush,
          selectedRegion, zoomInfo);
 
@@ -1451,7 +1444,7 @@ void TrackArtist::DrawWaveform(WaveTrack *track,
       if (xx >= 0 && xx < rect.width) {
          dc.SetPen(*wxGREY_PEN);
          AColor::Line(dc, (int) (rect.x + xx - 1), rect.y, (int) (rect.x + xx - 1), rect.y + rect.height);
-         if (loc.typ == WaveTrack::locationCutLine) {
+         if (loc.typ == WaveTrackLocation::locationCutLine) {
             dc.SetPen(*wxRED_PEN);
          }
          else {
@@ -1637,11 +1630,17 @@ struct ClipParameters
 };
 }
 
+#ifdef __GNUC__
+#define CONST
+#else
+#define CONST const
+#endif
+
 namespace {
 struct WavePortion {
    wxRect rect;
-   /*const*/ double averageZoom;
-   /*const*/ bool inFisheye;
+   CONST double averageZoom;
+   CONST bool inFisheye;
    WavePortion(int x, int y, int w, int h, double zoom, bool i)
       : rect(x, y, w, h), averageZoom(zoom), inFisheye(i)
    {}
@@ -1664,9 +1663,9 @@ void FindWavePortions
    for (int left = rect.x; left < rightmost;) {
       while (it != end && it->position <= left)
          prev = it++;
-      const int right = std::max(left, int(
-         it != end ? it->position : rightmost
-      ));
+      if (it == end)
+         break;
+      const int right = std::max(left, int(it->position));
       const int width = right - left;
       if (width > 0)
          portions.push_back(
@@ -1731,11 +1730,20 @@ void TrackArtist::DrawClipWaveform(WaveTrack *track,
    // Draw the background of the track, outlining the shape of
    // the envelope and using a colored pen for the selected
    // part of the waveform
-   DrawWaveformBackground(dc, leftOffset, mid,
-      env,
-      zoomMin, zoomMax, dB,
-      selectedRegion, zoomInfo, drawEnvelope,
-      !track->GetSelected());
+   {
+      double t0, t1;
+      if (track->GetSelected() || track->IsSyncLockSelected()) {
+         t0 = track->LongSamplesToTime(track->TimeToLongSamples(selectedRegion.t0())),
+            t1 = track->LongSamplesToTime(track->TimeToLongSamples(selectedRegion.t1()));
+      }
+      else
+         t0 = t1 = 0.0;
+      DrawWaveformBackground(dc, leftOffset, mid,
+         env,
+         zoomMin, zoomMax, dB,
+         t0, t1, zoomInfo, drawEnvelope,
+         !track->GetSelected());
+   }
 
    WaveDisplay display(hiddenMid.width);
    bool isLoadingOD = false;//true if loading on demand block in sequence.
@@ -1957,6 +1965,8 @@ static inline float findValue
  bool autocorrelation, int gain, int range)
 {
    float value;
+
+
 #if 0
    // Averaging method
    if (int(bin1) == int(bin0)) {
@@ -1982,11 +1992,24 @@ static inline float findValue
    wxUnusedVar(half);
    // Maximum method, and no apportionment of any single bins over multiple pixel rows
    // See Bug971
-   int bin = std::min(half - 1, int(floor(0.5 + bin0)));
-   const int limitBin = std::min(half, int(floor(0.5 + bin1)));
-   value = spectrum[bin];
-   while (++bin < limitBin)
-      value = std::max(value, spectrum[bin]);
+   int index, limitIndex;
+   if (autocorrelation) {
+      // bin = 2 * half / (half - 1 - array_index);
+      // Solve for index
+      index = std::max(0.0f, std::min(float(half - 1),
+         (half - 1) - (2 * half) / (std::max(1.0f, bin0))
+      ));
+      limitIndex = std::max(0.0f, std::min(float(half - 1),
+         (half - 1) - (2 * half) / (std::max(1.0f, bin1))
+      ));
+   }
+   else {
+      index = std::min(half - 1, int(floor(0.5 + bin0)));
+      limitIndex = std::min(half, int(floor(0.5 + bin1)));
+   }
+   value = spectrum[index];
+   while (++index < limitIndex)
+      value = std::max(value, spectrum[index]);
 #endif
    if (!autocorrelation) {
       // Last step converts dB to a 0.0-1.0 range
@@ -2031,10 +2054,10 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
 #endif
 
    const WaveTrack *const track = waveTrackCache.GetTrack();
-   const int display = track->GetDisplay();
-   const bool autocorrelation = (WaveTrack::PitchDisplay == display);
-   const bool logF = (WaveTrack::SpectrumLogDisplay == display
-      || WaveTrack::SpectralSelectionLogDisplay == display);
+   const SpectrogramSettings &settings = track->GetSpectrogramSettings();
+
+   const bool autocorrelation = (settings.algorithm == SpectrogramSettings::algPitchEAC);
+
    enum { DASH_LENGTH = 10 /* pixels */ };
 
    const ClipParameters params(true, track, clip, rect, selectedRegion, zoomInfo);
@@ -2062,13 +2085,10 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
    double freqLo = SelectedRegion::UndefinedFrequency;
    double freqHi = SelectedRegion::UndefinedFrequency;
 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
-   if (!autocorrelation) {
-      freqLo = selectedRegion.f0();
-      freqHi = selectedRegion.f1();
-   }
+   freqLo = selectedRegion.f0();
+   freqHi = selectedRegion.f1();
 #endif
 
-   const SpectrogramSettings &settings = SpectrogramSettings::defaults();
    const bool &isGrayscale = settings.isGrayscale;
    const int &range = settings.range;
    const int &gain = settings.gain;
@@ -2093,7 +2113,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
       return;
    unsigned char *data = image->GetData();
 
-   const int half = GetSpectrumWindowSize(!autocorrelation) / 2;
+   const int half = settings.GetFFTLength() / 2;
    const double binUnit = rate / (2 * half);
    const float *freq = 0;
    const sampleCount *where = 0;
@@ -2104,38 +2124,16 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
          t0, pps, autocorrelation);
    }
 
-   int ifreq = lrint(rate / 2);
-
-   int maxFreq;
-   if (!logF)
-      maxFreq = GetSpectrumMaxFreq(ifreq);
-   else
-      maxFreq = GetSpectrumLogMaxFreq(ifreq);
-   if(maxFreq > ifreq)
-      maxFreq = ifreq;
-
-   int minFreq;
-   if (!logF) {
-      minFreq = GetSpectrumMinFreq(0);
-      if(minFreq < 0)
-         minFreq = 0;
-   }
-   else {
-      minFreq = GetSpectrumLogMinFreq(ifreq/1000.0);
-      if(minFreq < 1)
-         // Paul L:  I suspect this line is now unreachable
-         minFreq = 1.0;
-   }
+   // Legacy special-case treatment of log scale
+   const SpectrogramSettings::ScaleType scaleType = settings.scaleType;
+   const int minFreq =
+      scaleType == SpectrogramSettings::stLinear
+      ? settings.GetMinFreq(rate) : settings.GetLogMinFreq(rate);
+   const int maxFreq =
+      scaleType == SpectrogramSettings::stLinear
+      ? settings.GetMaxFreq(rate) : settings.GetLogMaxFreq(rate);
 
-   float minBin = ((double)minFreq / binUnit);
-   float maxBin = ((double)maxFreq / binUnit);
-   float binPerPx = float(maxBin - minBin) / float(mid.height);
-
-   const float
-      //      e=exp(1.0f),
-      lmin = logf(float(minFreq)),
-      lmax = logf(float(maxFreq)),
-      scale = lmax - lmin;
+   const NumberScale numberScale(settings.GetScale(rate, true));
 
 #ifdef EXPERIMENTAL_FFT_Y_GRID
    const float
@@ -2160,7 +2158,8 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
 #endif //EXPERIMENTAL_FFT_Y_GRID
 
    if (!updated && clip->mSpecPxCache->valid &&
-       (clip->mSpecPxCache->len == hiddenMid.height * hiddenMid.width)
+      (clip->mSpecPxCache->len == hiddenMid.height * hiddenMid.width)
+      && scaleType == clip->mSpecPxCache->scaleType
       && gain == clip->mSpecPxCache->gain
       && range == clip->mSpecPxCache->range
       && minFreq == clip->mSpecPxCache->minFreq
@@ -2183,6 +2182,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
       delete clip->mSpecPxCache;
       clip->mSpecPxCache = new SpecPxCache(hiddenMid.width * hiddenMid.height);
       clip->mSpecPxCache->valid = true;
+      clip->mSpecPxCache->scaleType = scaleType;
       clip->mSpecPxCache->gain = gain;
       clip->mSpecPxCache->range = range;
       clip->mSpecPxCache->minFreq = minFreq;
@@ -2214,135 +2214,124 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
       int *indexes = new int[maxTableSize];
 #endif //EXPERIMENTAL_FIND_NOTES
 
-      for (int xx = 0; xx < hiddenMid.width; ++xx)
-      {
-         if (!logF) {
-            for (int yy = 0; yy < hiddenMid.height; ++yy) {
-               float bin0 = float(yy) * binPerPx + minBin;
-               float bin1 = float(yy + 1) * binPerPx + minBin;
+      for (int xx = 0; xx < hiddenMid.width; ++xx) {
+         NumberScale::Iterator it = numberScale.begin(mid.height);
+         float nextBin = std::max(0.0f, std::min(float(half - 1), *it));
+         for (int yy = 0; yy < hiddenMid.height; ++yy) {
+            const float bin = nextBin;
+            nextBin = std::max(0.0f, std::min(float(half - 1), *++it));
+
+            if (settings.scaleType != SpectrogramSettings::stLogarithmic) {
                const float value = findValue
-                  (freq + half * xx, bin0, bin1, half, autocorrelation, gain, range);
+                  (freq + half * xx, bin, nextBin, half, autocorrelation, gain, range);
                clip->mSpecPxCache->values[xx * hiddenMid.height + yy] = value;
             }
-         }
-         else {
+            else {
+               // Do we need this legacy experiment still?
 #ifdef EXPERIMENTAL_FIND_NOTES
-            int maximas=0;
-            const int x0 = half * xx;
-            if (fftFindNotes) {
-               for (int i = maxTableSize-1; i >= 0; i--)
-                  indexes[i]=-1;
-
-               // Build a table of (most) values, put the index in it.
-               for (int i = int(i0); i < int(i1); i++) {
-                  float freqi=freq[x0 + int(i)];
-                  int value=int((freqi+gain+range)/range*(maxTableSize-1));
-                  if (value < 0)
-                     value=0;
-                  if (value >= maxTableSize)
-                     value=maxTableSize-1;
-                  indexes[value]=i;
-               }
-               // Build from the indices an array of maxima.
-               for (int i = maxTableSize - 1; i >= 0; i--) {
-                  int index = indexes[i];
-                  if (index >= 0) {
-                     float freqi = freq[x0 + index];
-                     if (freqi < findNotesMinA)
-                        break;
-
-                     bool ok = true;
-                     for (int m = 0; m < maximas; m++) {
-                        // Avoid to store very close maxima.
-                        float maxm = maxima[m];
-                        if (maxm / index < minDistance && index / maxm < minDistance) {
-                           ok = false;
+               int maximas = 0;
+               const int x0 = half * x;
+               if (fftFindNotes) {
+                  for (int i = maxTableSize - 1; i >= 0; i--)
+                     indexes[i] = -1;
+
+                  // Build a table of (most) values, put the index in it.
+                  for (int i = int(i0); i < int(i1); i++) {
+                     float freqi = freq[x0 + int(i)];
+                     int value = int((freqi + gain + range) / range*(maxTableSize - 1));
+                     if (value < 0)
+                        value = 0;
+                     if (value >= maxTableSize)
+                        value = maxTableSize - 1;
+                     indexes[value] = i;
+                  }
+                  // Build from the indices an array of maxima.
+                  for (int i = maxTableSize - 1; i >= 0; i--) {
+                     int index = indexes[i];
+                     if (index >= 0) {
+                        float freqi = freq[x0 + index];
+                        if (freqi < findNotesMinA)
                            break;
+
+                        bool ok = true;
+                        for (int m = 0; m < maximas; m++) {
+                           // Avoid to store very close maxima.
+                           float maxm = maxima[m];
+                           if (maxm / index < minDistance && index / maxm < minDistance) {
+                              ok = false;
+                              break;
+                           }
+                        }
+                        if (ok) {
+                           maxima[maximas++] = index;
+                           if (maximas >= numberOfMaxima)
+                              break;
                         }
-                     }
-                     if (ok) {
-                        maxima[maximas++] = index;
-                        if (maximas >= numberOfMaxima)
-                           break;
                      }
                   }
-               }
 
 // The f2pix helper macro converts a frequency into a pixel coordinate.
 #define f2pix(f) (logf(f)-lmins)/(lmaxs-lmins)*hiddenMid.height
 
-               // Possibly quantize the maxima frequencies and create the pixel block limits.
-               for (int i=0; i < maximas; i++) {
-                  int index=maxima[i];
-                  float f = float(index)*bin2f;
-                  if (findNotesQuantize)
-                  {  f = expf(int(log(f/440)/log2*12-0.5)/12.0f*log2)*440;
-                  maxima[i] = f*f2bin;
+                  // Possibly quantize the maxima frequencies and create the pixel block limits.
+                  for (int i = 0; i < maximas; i++) {
+                     int index = maxima[i];
+                     float f = float(index)*bin2f;
+                     if (findNotesQuantize)
+                     {
+                        f = expf(int(log(f / 440) / log2 * 12 - 0.5) / 12.0f*log2) * 440;
+                        maxima[i] = f*f2bin;
+                     }
+                     float f0 = expf((log(f / 440) / log2 * 24 - 1) / 24.0f*log2) * 440;
+                     maxima0[i] = f2pix(f0);
+                     float f1 = expf((log(f / 440) / log2 * 24 + 1) / 24.0f*log2) * 440;
+                     maxima1[i] = f2pix(f1);
                   }
-                  float f0 = expf((log(f/440)/log2*24-1)/24.0f*log2)*440;
-                  maxima0[i] = f2pix(f0);
-                  float f1 = expf((log(f/440)/log2*24+1)/24.0f*log2)*440;
-                  maxima1[i] = f2pix(f1);
                }
-            }
-            int it=0;
-            int oldBin0=-1;
-            bool inMaximum = false;
+               int it = 0;
+               int oldBin0 = -1;
+               bool inMaximum = false;
 #endif //EXPERIMENTAL_FIND_NOTES
 
-            double yy2_base = exp(lmin) / binUnit;
-            float yy2 = yy2_base;
-            double exp_scale_per_height = exp(scale / hiddenMid.height);
-            for (int yy = 0; yy < hiddenMid.height; ++yy) {
-               if (int(yy2) >= half)
-                  yy2=half-1;
-               if (yy2<0)
-                  yy2=0;
-               float bin0 = float(yy2);
-               yy2_base *= exp_scale_per_height;
-               float yy3 = yy2_base;
-               if (int(yy3)>=half)
-                  yy3=half-1;
-               if (yy3<0)
-                  yy3=0;
-               float bin1 = float(yy3);
                float value;
 
 #ifdef EXPERIMENTAL_FIND_NOTES
                if (fftFindNotes) {
                   if (it < maximas) {
-                     float i0=maxima0[it];
+                     float i0 = maxima0[it];
                      if (yy >= i0)
                         inMaximum = true;
 
                      if (inMaximum) {
-                        float i1=maxima1[it];
-                        if (yy+1 <= i1) {
-                           value=findValue(freq + x0, bin0, bin1, half, autocorrelation, gain, range);
+                        float i1 = maxima1[it];
+                        if (yy + 1 <= i1) {
+                           value = findValue(freq + x0, bin, nextBin, half, autocorrelation, gain, range);
                            if (value < findNotesMinA)
                               value = minColor;
-                        } else {
+                        }
+                        else {
                            it++;
                            inMaximum = false;
                            value = minColor;
                         }
-                     } else {
+                     }
+                     else {
                         value = minColor;
                      }
-                  } else
+                  }
+                  else
                      value = minColor;
-               } else
+               }
+               else
 #endif //EXPERIMENTAL_FIND_NOTES
                {
                   value = findValue
-                     (freq + half * xx, bin0, bin1, half, autocorrelation, gain, range);
+                     (freq + half * xx, bin, nextBin, half, autocorrelation, gain, range);
                }
                clip->mSpecPxCache->values[xx * hiddenMid.height + yy] = value;
-               yy2 = yy2_base;
-            } // each yy
-         } // is logF
+            } // logF
+         } // each yy
       } // each xx
-
    } // updating cache
 
    float selBinLo = freqLo / binUnit;
@@ -2354,6 +2343,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
       (zoomInfo.PositionToTime(0, -leftOffset) - tOffset)
    );
 
+   const bool isSpectral = settings.SpectralSelectionEnabled();
    const bool hidden = (ZoomInfo::HIDDEN == zoomInfo.GetFisheyeState());
    const int begin = hidden
       ? 0
@@ -2393,93 +2383,42 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
          (zoomInfo.PositionToTime(xx + 1, -leftOffset) - tOffset)
       );
 
-      // TODO: The logF and non-logF case are very similar.
-      // They should be merged and simplified.
-      if (!logF)
-      {
-         for (int yy = 0; yy < hiddenMid.height; ++yy) {
-            float bin0 = float(yy) * binPerPx + minBin;
-            float bin1 = float(yy + 1) * binPerPx + minBin;
-
-            // For spectral selection, determine what colour
-            // set to use.  We use a darker selection if
-            // in both spectral range and time range.
-
-            AColor::ColorGradientChoice selected =
-               AColor::ColorGradientUnselected;
-            // If we are in the time selected range, then we may use a different color set.
-            if (ssel0 <= w0 && w1 < ssel1)
-            {
-               bool isSpectral = ((track->GetDisplay() == WaveTrack::SpectralSelectionDisplay) ||
-                  (track->GetDisplay() == WaveTrack::SpectralSelectionLogDisplay));
-               selected = ChooseColorSet(bin0, bin1, selBinLo, selBinCenter, selBinHi,
+      NumberScale::Iterator it = numberScale.begin(mid.height);
+      float nextBin = std::max(0.0f, std::min(float(half - 1), *it));
+      for (int yy = 0; yy < hiddenMid.height; ++yy) {
+         const float bin = nextBin;
+         nextBin = std::max(0.0f, std::min(float(half - 1), *++it));
+
+         // For spectral selection, determine what colour
+         // set to use.  We use a darker selection if
+         // in both spectral range and time range.
+
+         AColor::ColorGradientChoice selected = AColor::ColorGradientUnselected;
+         // If we are in the time selected range, then we may use a different color set.
+         if (ssel0 <= w0 && w1 < ssel1)
+            selected =
+               ChooseColorSet(bin, nextBin, selBinLo, selBinCenter, selBinHi,
                   (xx + leftOffset - hiddenLeftOffset) / DASH_LENGTH, isSpectral);
-            }
-
-            unsigned char rv, gv, bv;
-            const float value = uncached
-               ? findValue(uncached, bin0, bin1, half, autocorrelation, gain, range)
-               : clip->mSpecPxCache->values[correctedX * hiddenMid.height + yy];
-            GetColorGradient(value, selected, isGrayscale, &rv, &gv, &bv);
-            int px = ((mid.height - 1 - yy) * mid.width + xx) * 3;
-            data[px++] = rv;
-            data[px++] = gv;
-            data[px] = bv;
-         }
-      }
-      else //logF
-      {
-         double yy2_base=exp(lmin)/binUnit;
-         float yy2 = yy2_base;
-         double exp_scale_per_height = exp(scale / hiddenMid.height);
-         for (int yy = 0; yy < hiddenMid.height; ++yy) {
-            if (int(yy2)>=half)
-               yy2=half-1;
-            if (yy2<0)
-               yy2=0;
-            float bin0 = float(yy2);
-            yy2_base *= exp_scale_per_height;
-            float yy3 = yy2_base;
-            if (int(yy3)>=half)
-               yy3=half-1;
-            if (yy3<0)
-               yy3=0;
-            float bin1 = float(yy3);
-
-            AColor::ColorGradientChoice selected = AColor::ColorGradientUnselected;
-            // If we are in the time selected range, then we may use a different color set.
-            if (ssel0 <= w0 && w1 < ssel1)
-            {
-               bool isSpectral = ((track->GetDisplay() == WaveTrack::SpectralSelectionDisplay) ||
-                  (track->GetDisplay() == WaveTrack::SpectralSelectionLogDisplay));
-               selected = ChooseColorSet(
-                  bin0, bin1, selBinLo, selBinCenter, selBinHi,
-                  (xx + leftOffset - hiddenLeftOffset) / DASH_LENGTH, isSpectral);
-            }
-
-            unsigned char rv, gv, bv;
-            const float value = uncached
-               ? findValue(uncached, bin0, bin1, half, autocorrelation, gain, range)
-               : clip->mSpecPxCache->values[correctedX * hiddenMid.height + yy];
-            GetColorGradient(value, selected, isGrayscale, &rv, &gv, &bv);
+         const float value = uncached
+            ? findValue(uncached, bin, nextBin, half, autocorrelation, gain, range)
+            : clip->mSpecPxCache->values[correctedX * hiddenMid.height + yy];
+         unsigned char rv, gv, bv;
+         GetColorGradient(value, selected, isGrayscale, &rv, &gv, &bv);
 
 #ifdef EXPERIMENTAL_FFT_Y_GRID
-            if (fftYGrid && yGrid[yy]) {
-               rv /= 1.1f;
-               gv /= 1.1f;
-               bv /= 1.1f;
-            }
+         if (fftYGrid && yGrid[yy]) {
+            rv /= 1.1f;
+            gv /= 1.1f;
+            bv /= 1.1f;
+         }
 #endif //EXPERIMENTAL_FFT_Y_GRID
 
-            int px = ((mid.height - 1 - yy) * mid.width + xx) * 3;
-            data[px++] = rv;
-            data[px++] = gv;
-            data[px] = bv;
-
-            yy2 = yy2_base;
-         }
-      }
-   }
+         int px = ((mid.height - 1 - yy) * mid.width + xx) * 3;
+         data[px++] = rv;
+         data[px++] = gv;
+         data[px] = bv;
+      } // each yy
+   } // each xx
 
    wxBitmap converted = wxBitmap(*image);
 
@@ -2495,23 +2434,6 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
 #endif //EXPERIMENTAL_FFT_Y_GRID
 }
 
-void TrackArtist::InvalidateSpectrumCache(TrackList *tracks)
-{
-   TrackListOfKindIterator iter(Track::Wave, tracks);
-   for (Track *t = iter.First(); t; t = iter.Next()) {
-      InvalidateSpectrumCache((WaveTrack *)t);
-   }
-}
-
-void TrackArtist::InvalidateSpectrumCache(WaveTrack *track)
-{
-   WaveClipList::compatibility_iterator it;
-   for (it = track->GetClipIterator(); it; it = it->GetNext()) {
-      it->GetData()->mSpecPxCache->valid = false;
-   }
-}
-
-
 #ifdef USE_MIDI
 /*
 Note: recall that Allegro attributes end in a type identifying letter.
@@ -3186,9 +3108,9 @@ void TrackArtist::DrawTimeTrack(TimeTrack *track,
    double lower = track->GetRangeLower(), upper = track->GetRangeUpper();
    if(track->GetDisplayLog()) {
       // MB: silly way to undo the work of GetWaveYPos while still getting a logarithmic scale
-      double dBRange = gPrefs->Read(wxT("/GUI/EnvdBRange"), ENV_DB_RANGE);
-      lower = 20.0 * log10(std::max(1.0e-7, lower)) / dBRange + 1.0;
-      upper = 20.0 * log10(std::max(1.0e-7, upper)) / dBRange + 1.0;
+      double dBRange = gPrefs->Read(ENV_DB_KEY, ENV_DB_RANGE);
+      lower = LINEAR_TO_DB(std::max(1.0e-7, lower)) / dBRange + 1.0;
+      upper = LINEAR_TO_DB(std::max(1.0e-7, upper)) / dBRange + 1.0;
    }
    track->GetEnvelope()->DrawPoints(dc, envRect, zoomInfo,
                track->GetDisplayLog(), lower, upper);
@@ -3196,72 +3118,12 @@ void TrackArtist::DrawTimeTrack(TimeTrack *track,
 
 void TrackArtist::UpdatePrefs()
 {
-   mdBrange = gPrefs->Read(wxT("/GUI/EnvdBRange"), mdBrange);
+   mdBrange = gPrefs->Read(ENV_DB_KEY, mdBrange);
    mShowClipping = gPrefs->Read(wxT("/GUI/ShowClipping"), mShowClipping);
 
    gPrefs->Flush();
 }
 
-// Get various preference values
-int TrackArtist::GetSpectrumMinFreq(int deffreq)
-{
-   const int &minFreq = SpectrogramSettings::defaults().minFreq;
-   return minFreq < 0 ? deffreq : minFreq;
-}
-
-int TrackArtist::GetSpectrumMaxFreq(int deffreq)
-{
-   const int &maxFreq = SpectrogramSettings::defaults().maxFreq;
-   return maxFreq < 0 ? deffreq : maxFreq;
-}
-
-int TrackArtist::GetSpectrumLogMinFreq(int deffreq)
-{
-   const int &logMinFreq = SpectrogramSettings::defaults().logMinFreq;
-   return logMinFreq < 0 ? deffreq : logMinFreq;
-}
-
-int TrackArtist::GetSpectrumLogMaxFreq(int deffreq)
-{
-   const int &logMaxFreq = SpectrogramSettings::defaults().logMaxFreq;
-   return logMaxFreq < 0 ? deffreq : logMaxFreq;
-}
-
-int TrackArtist::GetSpectrumWindowSize(bool includeZeroPadding)
-{
-   wxUnusedVar(includeZeroPadding);
-   const int &windowSize = SpectrogramSettings::defaults().windowSize;
-#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
-   if (includeZeroPadding) {
-      const int &zeroPaddingFactor = SpectrogramSettings::defaults().zeroPaddingFactor;
-      return windowSize * zeroPaddingFactor;
-   }
-   else
-#endif
-      return windowSize;
-}
-
-// Set various preference values
-void TrackArtist::SetSpectrumMinFreq(int freq)
-{
-   SpectrogramSettings::defaults().minFreq = freq;
-}
-
-void TrackArtist::SetSpectrumMaxFreq(int freq)
-{
-   SpectrogramSettings::defaults().maxFreq = freq;
-}
-
-void TrackArtist::SetSpectrumLogMinFreq(int freq)
-{
-   SpectrogramSettings::defaults().logMinFreq = freq;
-}
-
-void TrackArtist::SetSpectrumLogMaxFreq(int freq)
-{
-   SpectrogramSettings::defaults().logMaxFreq = freq;
-}
-
 // Draws the sync-lock bitmap, tiled; always draws stationary relative to the DC
 //
 // AWD: now that the tiles don't link together, we're drawing a tilted grid, at
diff --git a/src/TrackArtist.h b/src/TrackArtist.h
index 5c96ca38aba45c32662c3431eacd8813067e0ea6..b6876d9f6ddef05f2ed6751afd00dc3ab9d8e8c0 100644
--- a/src/TrackArtist.h
+++ b/src/TrackArtist.h
@@ -71,19 +71,6 @@ class AUDACITY_DLL_API TrackArtist {
 
    void UpdatePrefs();
 
-   void InvalidateSpectrumCache(TrackList *tracks);
-   void InvalidateSpectrumCache(WaveTrack *track);
-   int GetSpectrumMinFreq(int deffreq);
-   int GetSpectrumMaxFreq(int deffreq);
-   int GetSpectrumLogMinFreq(int deffreq);
-   int GetSpectrumLogMaxFreq(int deffreq);
-   int GetSpectrumWindowSize(bool includeZeroPadding);
-
-   void SetSpectrumMinFreq(int freq);
-   void SetSpectrumMaxFreq(int freq);
-   void SetSpectrumLogMinFreq(int freq);
-   void SetSpectrumLogMaxFreq(int freq);
-
    void SetBackgroundBrushes(wxBrush unselectedBrush, wxBrush selectedBrush,
                              wxPen unselectedPen, wxPen selectedPen) {
      this->unselectedBrush = unselectedBrush;
@@ -110,7 +97,7 @@ class AUDACITY_DLL_API TrackArtist {
                      wxDC & dc, const wxRect & rect,
                      const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo,
                      bool drawEnvelope, bool bigPoints, bool drawSliders,
-                     bool dB, bool muted);
+                     bool muted);
 
    void DrawSpectrum(WaveTrack *track,
                      wxDC & dc, const wxRect & rect,
@@ -154,7 +141,7 @@ class AUDACITY_DLL_API TrackArtist {
    void DrawWaveformBackground(wxDC & dc, int leftOffset, const wxRect &rect,
                                const double env[],
                                float zoomMin, float zoomMax, bool dB,
-                               const SelectedRegion &selectedRegion, const ZoomInfo &zoomInfo,
+                               double t0, double t1, const ZoomInfo &zoomInfo,
                                bool drawEnvelope, bool bIsSyncLockSelected);
    void DrawMinMaxRMS(wxDC &dc, const wxRect & rect, const double env[],
                       float zoomMin, float zoomMax, bool dB,
diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp
index 730e4db9ac0d26d5a43d955d223b479104d1b4e3..2c883f9d3a94b87942918a122ede53d132f175d5 100644
--- a/src/TrackPanel.cpp
+++ b/src/TrackPanel.cpp
@@ -196,18 +196,16 @@ is time to refresh some aspect of the screen.
 #include "float_cast.h"
 #include "Internat.h"
 #include "LabelTrack.h"
-#include "Lyrics.h"
-#include "LyricsWindow.h"
 #include "MixerBoard.h"
 
 #include "NoteTrack.h"
+#include "NumberScale.h"
 #include "Prefs.h"
 #include "Project.h"
 #include "Snap.h"
 #include "ShuttleGui.h"
 #include "Theme.h"
 #include "TimeTrack.h"
-#include "Track.h"
 #include "TrackArtist.h"
 #include "TrackPanelAx.h"
 #include "ViewInfo.h"
@@ -217,7 +215,9 @@ is time to refresh some aspect of the screen.
 
 #include "ondemand/ODManager.h"
 
+#include "prefs/PrefsDialog.h"
 #include "prefs/SpectrumPrefs.h"
+#include "prefs/WaveformPrefs.h"
 
 #include "toolbars/ControlToolBar.h"
 #include "toolbars/ToolManager.h"
@@ -228,16 +228,14 @@ is time to refresh some aspect of the screen.
 #include "widgets/Ruler.h"
 #include "widgets/NumericTextCtrl.h"
 
-#include <wx/arrimpl.cpp>
-
-#define ZOOMLIMIT 0.001
-
-WX_DEFINE_OBJARRAY(TrackClipArray);
+#define ZOOMLIMIT 0.001f
 
 //This loads the appropriate set of cursors, depending on platform.
 #include "../images/Cursors.h"
 #include <iostream>
 
+DEFINE_EVENT_TYPE(EVT_TRACK_PANEL_TIMER)
+
 enum {
    kLeftInset = 4,
    kTopInset = 4,
@@ -324,12 +322,8 @@ enum {
    OnFloatID,              // <---
 
    OnWaveformID,
-   OnWaveformDBID,
    OnSpectrumID,
-   OnSpectrumLogID,
-   OnSpectralSelID,
-   OnSpectralSelLogID,
-   OnPitchID,
+   OnViewSettingsID,
 
    OnSplitStereoID,
    OnSplitStereoMonoID,
@@ -345,6 +339,18 @@ enum {
    OnTimeTrackLinID,
    OnTimeTrackLogID,
    OnTimeTrackLogIntID,
+
+   // Reserve an ample block of ids for waveform scale types
+   OnFirstWaveformScaleID,
+   OnLastWaveformScaleID = OnFirstWaveformScaleID + 9,
+
+   // Reserve an ample block of ids for spectrum scale types
+   OnFirstSpectrumScaleID,
+   OnLastSpectrumScaleID = OnFirstSpectrumScaleID + 19,
+
+   OnZoomInVerticalID,
+   OnZoomOutVerticalID,
+   OnZoomFitVerticalID,
 };
 
 BEGIN_EVENT_TABLE(TrackPanel, wxWindow)
@@ -368,7 +374,8 @@ BEGIN_EVENT_TABLE(TrackPanel, wxWindow)
     EVT_MENU_RANGE(OnUpOctaveID, OnDownOctaveID, TrackPanel::OnChangeOctave)
     EVT_MENU_RANGE(OnChannelLeftID, OnChannelMonoID,
                TrackPanel::OnChannelChange)
-    EVT_MENU_RANGE(OnWaveformID, OnPitchID, TrackPanel::OnSetDisplay)
+    EVT_MENU_RANGE(OnWaveformID, OnSpectrumID, TrackPanel::OnSetDisplay)
+    EVT_MENU(OnViewSettingsID, TrackPanel::OnViewSettings)
     EVT_MENU_RANGE(OnRate8ID, OnRate384ID, TrackPanel::OnRateChange)
     EVT_MENU_RANGE(On16BitID, OnFloatID, TrackPanel::OnFormatChange)
     EVT_MENU(OnRateOtherID, TrackPanel::OnRateOther)
@@ -385,10 +392,18 @@ BEGIN_EVENT_TABLE(TrackPanel, wxWindow)
     EVT_MENU(OnTimeTrackLinID, TrackPanel::OnTimeTrackLin)
     EVT_MENU(OnTimeTrackLogID, TrackPanel::OnTimeTrackLog)
     EVT_MENU(OnTimeTrackLogIntID, TrackPanel::OnTimeTrackLogInt)
+
+    EVT_MENU_RANGE(OnFirstWaveformScaleID, OnLastWaveformScaleID, TrackPanel::OnWaveformScaleType)
+    EVT_MENU_RANGE(OnFirstSpectrumScaleID, OnLastSpectrumScaleID, TrackPanel::OnSpectrumScaleType)
+
+    EVT_MENU(OnZoomInVerticalID, TrackPanel::OnZoomInVertical)
+    EVT_MENU(OnZoomOutVerticalID, TrackPanel::OnZoomOutVertical)
+    EVT_MENU(OnZoomFitVerticalID, TrackPanel::OnZoomFitVertical)
 END_EVENT_TABLE()
 
 /// Makes a cursor from an XPM, uses CursorId as a fallback.
-static wxCursor * MakeCursor( int WXUNUSED(CursorId), const char * pXpm[36],  int HotX, int HotY )
+/// TODO:  Move this function to some other source file for reuse elsewhere.
+wxCursor * MakeCursor( int WXUNUSED(CursorId), const char * pXpm[36],  int HotX, int HotY )
 {
    wxCursor * pCursor;
 
@@ -552,6 +567,8 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
    mLabelTrackInfoMenu = NULL;
    mTimeTrackMenu = NULL;
 
+   mRulerWaveformMenu = mRulerSpectrumMenu = NULL;
+
    BuildMenus();
 
    mTrackArtist = new TrackArtist();
@@ -584,8 +601,8 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
    mSnapLeft = -1;
    mSnapRight = -1;
 
-   mLastCursor = -1;
-   mLastIndicator = -1;
+   mLastCursorX = -1;
+   mLastIndicatorX = -1;
    mOldQPIndicatorPos = -1;
 
    // Register for tracklist updates
@@ -722,18 +739,11 @@ void TrackPanel::BuildMenus(void)
    /* build the pop-down menu used on wave (sampled audio) tracks */
    mWaveTrackMenu = new wxMenu();
    BuildCommonDropMenuItems(mWaveTrackMenu);   // does name, up/down etc
-   mWaveTrackMenu->Append(OnWaveformID, _("Wa&veform"));
-   mWaveTrackMenu->Append(OnWaveformDBID, _("&Waveform (dB)"));
-   mWaveTrackMenu->Append(OnSpectrumID, _("&Spectrogram"));
-   /* i18n-hint: short form of 'logarithm'*/
-   mWaveTrackMenu->Append(OnSpectrumLogID, _("Spectrogram l&og(f)"));
-   /* i18n-hint: Spectral Selection is spectrogram with ability to select frequencies too'*/
-   mWaveTrackMenu->Append(OnSpectralSelID, _("S&pectral Selection"));
-   /* i18n-hint: short form of 'logarithm'*/
-   mWaveTrackMenu->Append(OnSpectralSelLogID, _("Spectral Selection lo&g(f)"));
-
-   mWaveTrackMenu->Append(OnPitchID, _("Pitc&h (EAC)"));
+   mWaveTrackMenu->AppendRadioItem(OnWaveformID, _("&Waveform"));
+   mWaveTrackMenu->AppendRadioItem(OnSpectrumID, _("&Spectrum"));
+   mWaveTrackMenu->Append(OnViewSettingsID, _("&View Settings..."));
    mWaveTrackMenu->AppendSeparator();
+
    mWaveTrackMenu->AppendRadioItem(OnChannelMonoID, _("&Mono"));
    mWaveTrackMenu->AppendRadioItem(OnChannelLeftID, _("&Left Channel"));
    mWaveTrackMenu->AppendRadioItem(OnChannelRightID, _("&Right Channel"));
@@ -771,6 +781,16 @@ void TrackPanel::BuildMenus(void)
    mLabelTrackInfoMenu->Append(OnCopySelectedTextID, _("&Copy"));
    mLabelTrackInfoMenu->Append(OnPasteSelectedTextID, _("&Paste"));
    mLabelTrackInfoMenu->Append(OnDeleteSelectedLabelID, _("&Delete Label"));
+
+   mRulerWaveformMenu = new wxMenu();
+   BuildVRulerMenuItems
+      (mRulerWaveformMenu, OnFirstWaveformScaleID,
+       WaveformSettings::GetScaleNames());
+
+   mRulerSpectrumMenu = new wxMenu();
+   BuildVRulerMenuItems
+      (mRulerSpectrumMenu, OnFirstSpectrumScaleID,
+       SpectrogramSettings::GetScaleNames());
 }
 
 void TrackPanel::BuildCommonDropMenuItems(wxMenu * menu)
@@ -785,6 +805,19 @@ void TrackPanel::BuildCommonDropMenuItems(wxMenu * menu)
 
 }
 
+// static
+void TrackPanel::BuildVRulerMenuItems
+(wxMenu * menu, int firstId, const wxArrayString &names)
+{
+   int id = firstId;
+   for (int ii = 0, nn = names.size(); ii < nn; ++ii)
+      menu->AppendRadioItem(id++, names[ii]);
+   menu->AppendSeparator();
+   menu->Append(OnZoomInVerticalID, _("Zoom In\tLeft-Click/Left-Drag"));
+   menu->Append(OnZoomOutVerticalID, _("Zoom Out\tShift-Left-Click"));
+   menu->Append(OnZoomFitVerticalID, _("Zoom to Fit\tShift-Right-Click"));
+}
+
 void TrackPanel::DeleteMenus(void)
 {
    // Note that the submenus (mRateMenu, ...)
@@ -813,6 +846,9 @@ void TrackPanel::DeleteMenus(void)
       delete mTimeTrackMenu;
       mTimeTrackMenu = NULL;
    }
+
+   delete mRulerWaveformMenu;
+   delete mRulerSpectrumMenu;
 }
 
 #ifdef EXPERIMENTAL_OUTPUT_DISPLAY
@@ -847,7 +883,6 @@ void TrackPanel::UpdatePrefs()
 #ifdef EXPERIMENTAL_SCROLLING_LIMITS
    gPrefs->Read(wxT("/GUI/ScrollBeyondZero"), &mScrollBeyondZero, false);
 #endif
-   mdBr = gPrefs->Read(wxT("/GUI/EnvdBRange"), ENV_DB_RANGE);
    gPrefs->Read(wxT("/GUI/AutoScroll"), &mViewInfo->bUpdateTrackIndicator,
       true);
    gPrefs->Read(wxT("/GUI/AdjustSelectionEdges"), &mAdjustSelectionEdges,
@@ -869,6 +904,8 @@ void TrackPanel::UpdatePrefs()
       UpdateVirtualStereoOrder();
 #endif
 
+   mViewInfo->UpdatePrefs();
+
    if (mTrackArtist) {
       mTrackArtist->UpdatePrefs();
    }
@@ -1015,30 +1052,9 @@ void TrackPanel::OnTimer()
    wxCommandEvent dummyEvent;
    AudacityProject *p = GetProject();
 
-   if ((p->GetAudioIOToken() > 0) &&
-      gAudioIO->IsStreamActive(p->GetAudioIOToken()))
    {
-      // Update lyrics display.
-      LyricsWindow* pLyricsWindow = p->GetLyricsWindow();
-      if (pLyricsWindow)
-      {
-         Lyrics* pLyricsPanel = pLyricsWindow->GetLyricsPanel();
-         pLyricsPanel->Update(gAudioIO->GetStreamTime());
-      }
-   }
-
-   //v Vaughan, 2011-02-25: Moved this update back here from audacityAudioCallback.
-   //    See note there.
-   // Vaughan, 2010-01-30:
-   //    Since all we're doing here is updating the meters, I moved it to
-   //    audacityAudioCallback where it calls gAudioIO->mOutputMeter->UpdateDisplay().
-   MixerBoard* pMixerBoard = this->GetMixerBoard();
-   if (pMixerBoard &&
-      (p->GetAudioIOToken() > 0) &&
-      gAudioIO->IsStreamActive(p->GetAudioIOToken()))
-   {
-      pMixerBoard->UpdateMeters(gAudioIO->GetStreamTime(),
-         (p->mLastPlayMode == loopedPlay));
+      wxCommandEvent e(EVT_TRACK_PANEL_TIMER);
+      p->ProcessEvent(e);
    }
 
 #ifdef EXPERIMENTAL_SCRUBBING_BASIC
@@ -1079,25 +1095,11 @@ void TrackPanel::OnTimer()
 #endif
 
    // Check whether we were playing or recording, but the stream has stopped.
-   if (p->GetAudioIOToken()>0 &&
-         !gAudioIO->IsStreamActive(p->GetAudioIOToken()))
+   if (p->GetAudioIOToken()>0 && !IsAudioActive())
    {
       //the stream may have been started up after this one finished (by some other project)
       //in that case reset the buttons don't stop the stream
       p->GetControlToolBar()->StopPlaying(!gAudioIO->IsStreamActive());
-
-      // Reset lyrics display.
-      LyricsWindow* pLyricsWindow = p->GetLyricsWindow();
-      if (pLyricsWindow)
-      {
-         Lyrics* pLyricsPanel = pLyricsWindow->GetLyricsPanel();
-         pLyricsPanel->Update(p->GetSel0());
-      }
-
-      // Vaughan, 2011-01-28: No longer doing this on timer.
-      //   Now it's in AudioIO::SetMeters() and AudioIO::StopStream(), as with Meter Toolbar meters.
-      //if (pMixerBoard)
-      //   pMixerBoard->ResetMeters(false);
    }
 
    // Next, check to see if we were playing or recording
@@ -1119,8 +1121,8 @@ void TrackPanel::OnTimer()
    //  that indicates where the current play/record position is. (This also
    //  draws the moving vertical line.)
 
-   if (!gAudioIO->IsPaused() &&
-       ( mIndicatorShowing || gAudioIO->IsStreamActive(p->GetAudioIOToken()))
+   if (!gAudioIO->IsPaused() && ( mIndicatorShowing || IsAudioActive())
+
 #ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
        && !mSmoothScrollingScrub
 #endif
@@ -1129,8 +1131,7 @@ void TrackPanel::OnTimer()
       DrawIndicator();
    }
 
-   if(gAudioIO->IsStreamActive(p->GetAudioIOToken()) &&
-      gAudioIO->GetNumCaptureChannels()) {
+   if(IsAudioActive() && gAudioIO->GetNumCaptureChannels()) {
 
       // Periodically update the display while recording
 
@@ -1239,40 +1240,36 @@ void TrackPanel::DoDrawIndicator
    (wxDC & dc, bool repairOld /* = false */, double indicator /* = -1 */)
 {
    bool onScreen;
-   int x;
    double pos;
 
    if (!repairOld)
    {
       // Erase the old indicator.
-      if( mLastIndicator != -1 )
+      if (mLastIndicatorX != -1)
       {
-         onScreen = between_inclusive( mViewInfo->h,
-                                      mLastIndicator,
-                                      mViewInfo->h + mViewInfo->screen );
-         if( onScreen )
+         onScreen = between_inclusive(GetLeftOffset(),
+            mLastIndicatorX,
+            GetLeftOffset() + mViewInfo->GetScreenWidth());
+         if (onScreen)
          {
-            x = mViewInfo->TimeToPosition(mLastIndicator, GetLeftOffset());
-
             // LL:  Keep from trying to blit outsize of the source DC.  This results in a crash on
             //      OSX due to allocating memory using negative sizes and can be caused by resizing
             //      the project window while recording or playing.
             int w = dc.GetSize().GetWidth();
-            if (x >= w) {
-               x = w - 1;
+            if (mLastIndicatorX >= w) {
+               mLastIndicatorX = w - 1;
             }
-            dc.Blit( x, 0, 1, mBacking->GetHeight(), &mBackingDC, x, 0 );
+
+            dc.Blit(mLastIndicatorX, 0, 1, mBacking->GetHeight(), &mBackingDC, mLastIndicatorX, 0);
          }
 
          // Nothing's ever perfect...
          //
          // Redraw the cursor since we may have just wiped it out
-         if( mLastCursor == mLastIndicator )
+         if (mLastCursorX == mLastIndicatorX)
          {
             DoDrawCursor( dc );
          }
-
-         mLastIndicator = -1;
       }
 
       pos = indicator;
@@ -1281,7 +1278,7 @@ void TrackPanel::DoDrawIndicator
          pos = gAudioIO->GetStreamTime();
 
       AudacityProject *p = GetProject();
-      bool audioActive = ( gAudioIO->IsStreamActive( p->GetAudioIOToken() ) != 0 );
+      bool audioActive = IsAudioActive();
       onScreen = between_inclusive( mViewInfo->h,
                                    pos,
                                    mViewInfo->h + mViewInfo->screen );
@@ -1309,19 +1306,16 @@ void TrackPanel::DoDrawIndicator
 
       mIndicatorShowing = ( onScreen && audioActive );
 
-      // Remember it
-      mLastIndicator = pos;
-   } else {
-      pos = mLastIndicator;
+      // Calculate the horizontal position of the indicator
+      mLastIndicatorX = mViewInfo->TimeToPosition(pos, GetLeftOffset());
    }
+   else
+      pos = mViewInfo->PositionToTime(mLastIndicatorX, GetLeftOffset());
 
    // Set play/record color
    bool rec = (gAudioIO->GetNumCaptureChannels() > 0);
    AColor::IndicatorColor( &dc, !rec);
 
-   // Calculate the horizontal position of the indicator
-   x = mViewInfo->TimeToPosition(pos, GetLeftOffset());
-
    mRuler->DrawIndicator( pos, rec );
 
    // Ensure that we don't draw through the TrackInfo or vertical ruler.
@@ -1329,7 +1323,7 @@ void TrackPanel::DoDrawIndicator
    int leftCutoff = clip.x + GetLabelWidth();
    int rightInset = kLeftInset + 2; // See the call to SetInset
    int rightCutoff = clip.x + clip.width - rightInset;
-   if (!between_inclusive(leftCutoff, x, rightCutoff))
+   if (!between_inclusive(leftCutoff, mLastIndicatorX, rightCutoff))
    {
       return;
    }
@@ -1349,9 +1343,9 @@ void TrackPanel::DoDrawIndicator
 
       // Draw the new indicator in its new location
       AColor::Line(dc,
-                   x,
+                   mLastIndicatorX,
                    y + kTopInset + 1,
-                   x,
+                   mLastIndicatorX,
                    y + t->GetHeight() - 3 );
    }
 }
@@ -1370,38 +1364,28 @@ void TrackPanel::DrawCursor()
 void TrackPanel::DoDrawCursor(wxDC & dc)
 {
    bool onScreen;
-   int x;
 
-   if( mLastCursor != -1 )
+   if( mLastCursorX != -1 )
    {
-      onScreen = between_inclusive( mViewInfo->h,
-                                    mLastCursor,
-                                    mViewInfo->h + mViewInfo->screen );
+      onScreen = between_inclusive(GetLeftOffset(),
+                                   mLastCursorX,
+                                   GetLeftOffset() + mViewInfo->GetScreenWidth());
       if( onScreen )
-      {
-         x = mViewInfo->TimeToPosition(mLastCursor, GetLeftOffset());
-
-         dc.Blit( x, 0, 1, mBacking->GetHeight(), &mBackingDC, x, 0 );
-      }
-
-      mLastCursor = -1;
+         dc.Blit(mLastCursorX, 0, 1, mBacking->GetHeight(), &mBackingDC, mLastCursorX, 0);
    }
 
-   mLastCursor = mViewInfo->selectedRegion.t0();
+   const double time = mViewInfo->selectedRegion.t0();
+   mLastCursorX = mViewInfo->TimeToPosition(time, GetLeftOffset());
 
    onScreen = between_inclusive( mViewInfo->h,
-                                 mLastCursor,
+                                 time,
                                  mViewInfo->h + mViewInfo->screen );
 
    if( !onScreen )
-   {
       return;
-   }
 
    AColor::CursorColor( &dc );
 
-   x = mViewInfo->TimeToPosition(mLastCursor, GetLeftOffset());
-
    // Draw cursor in all selected tracks
    VisibleTrackIterator iter( GetProject() );
    for( Track *t = iter.First(); t; t = iter.Next() )
@@ -1413,14 +1397,14 @@ void TrackPanel::DoDrawCursor(wxDC & dc)
          wxCoord bottom = y + t->GetHeight() - kTopInset;
 
          // MB: warp() is not needed here as far as I know, in fact it creates a bug. Removing it fixes that.
-         AColor::Line( dc, x, top, x, bottom ); // <-- The whole point of this routine.
+         AColor::Line(dc, mLastCursorX, top, mLastCursorX, bottom); // <-- The whole point of this routine.
 
 #ifdef EXPERIMENTAL_OUTPUT_DISPLAY
          if(MONO_WAVE_PAN(t)){
             y = t->GetY(true) - mViewInfo->vpos + 1;
             top = y + kTopInset;
             bottom = y + t->GetHeight(true) - kTopInset;
-            AColor::Line( dc, x, top, x, bottom );
+            AColor::Line( dc, mLastCursorX, top, mLastCursorX, bottom );
          }
 #endif
 
@@ -1428,7 +1412,7 @@ void TrackPanel::DoDrawCursor(wxDC & dc)
    }
 
    // AS: Ah, no, this is where we draw the blinky thing in the ruler.
-   mRuler->DrawCursor( mLastCursor );
+   mRuler->DrawCursor( time );
 
    DisplaySelection();
 }
@@ -1494,8 +1478,7 @@ void TrackPanel::OnPaint(wxPaintEvent & /* event */)
       mRefreshBacking = false;
 
 #ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
-      if (mSmoothScrollingScrub &&
-         gAudioIO->IsStreamActive(GetProject()->GetAudioIOToken())) {
+      if (mSmoothScrollingScrub && IsAudioActive()) {
          // Pan the view, so that we center the play indicator.
          // By the time DoDrawIndicator() is reached, gAudioIO->GetStreamTime()
          // may be a little different.
@@ -1530,9 +1513,7 @@ void TrackPanel::OnPaint(wxPaintEvent & /* event */)
 
    // Update the indicator in case it was damaged if this project is playing
 
-   AudacityProject* p = GetProject();
-   if (!gAudioIO->IsPaused() &&
-      (mIndicatorShowing || gAudioIO->IsStreamActive(p->GetAudioIOToken())))
+   if (!gAudioIO->IsPaused() && (mIndicatorShowing || IsAudioActive()))
    {
       // If not smooth scrolling, then
       // we just want to repair, not update the old, so set the second param to true.
@@ -1622,7 +1603,6 @@ void TrackPanel::HandleEscapeKey(bool down)
       break;
    default:
       return;
-      ;
    }
 
    // Common part in all cases that do anything
@@ -1678,11 +1658,14 @@ MixerBoard* TrackPanel::GetMixerBoard()
 /// edits at the moment.
 /// @return true if audio is being recorded or is playing.
 bool TrackPanel::IsUnsafe()
+{
+   return IsAudioActive();
+}
+
+bool TrackPanel::IsAudioActive()
 {
    AudacityProject *p = GetProject();
-   bool bUnsafe = (p->GetAudioIOToken()>0 &&
-                  gAudioIO->IsStreamActive(p->GetAudioIOToken()));
-   return bUnsafe;
+   return p->IsAudioActive();
 }
 
 
@@ -1714,43 +1697,48 @@ bool TrackPanel::SetCursorByActivity( )
       SetCursor( unsafe ? *mDisabledCursor : *mStretchCursor);
       return true;
 #endif
-   case IsOverCutLine:
-      SetCursor( unsafe ? *mDisabledCursor : *mArrowCursor);
-      // what, no return true here? -- PRL
    default:
       break;
    }
    return false;
 }
 
+bool TrackPanel::SetCursorForCutline(WaveTrack * track, wxRect &rect, wxMouseEvent &event)
+{
+   if (IsOverCutline(track, rect, event)) {
+      bool unsafe = IsUnsafe();
+      SetCursor(unsafe ? *mDisabledCursor : *mArrowCursor);
+      return true;
+      // No tip string?
+   }
+   return false;
+}
+
 /// When in the "label" (TrackInfo or vertical ruler), we can either vertical zoom or re-order tracks.
 /// Dont't change cursor/tip to zoom if display is not waveform (either linear of dB) or Spectrum
 void TrackPanel::SetCursorAndTipWhenInLabel( Track * t,
-         wxMouseEvent &event, const wxChar ** ppTip )
+         wxMouseEvent &event, wxString &tip )
 {
-   if (event.m_x >= GetVRulerOffset() &&
-         (t->GetKind() == Track::Wave) &&
-         ( ((WaveTrack *) t)->GetDisplay() != WaveTrack::PitchDisplay) )
+   if (event.m_x >= GetVRulerOffset() && (t->GetKind() == Track::Wave) )
    {
-      *ppTip = _("Click to vertically zoom in. Shift-click to zoom out. Drag to specify a zoom region.");
+      tip = _("Click to vertically zoom in. Shift-click to zoom out. Drag to specify a zoom region.");
       SetCursor(event.ShiftDown()? *mZoomOutCursor : *mZoomInCursor);
    }
 #ifdef USE_MIDI
    else if (event.m_x >= GetVRulerOffset() && t->GetKind() == Track::Note) {
-      *ppTip = _("Click to verticaly zoom in, Shift-click to zoom out, Drag to create a particular zoom region.");
+      tip = _("Click to verticaly zoom in, Shift-click to zoom out, Drag to create a particular zoom region.");
       SetCursor(event.ShiftDown() ? *mZoomOutCursor : *mZoomInCursor);
    }
 #endif
    else {
       // Set a status message if over TrackInfo.
-      *ppTip = _("Drag the track vertically to change the order of the tracks.");
+      tip = _("Drag the track vertically to change the order of the tracks.");
       SetCursor(*mArrowCursor);
    }
 }
 
 /// When in the resize area we can adjust size or relative size.
-void TrackPanel::SetCursorAndTipWhenInVResizeArea( Track * label,
-         bool bLinked, const wxChar ** ppTip )
+void TrackPanel::SetCursorAndTipWhenInVResizeArea( bool bLinked, wxString &tip )
 {
    // Check to see whether it is the first channel of a stereo track
    if (bLinked) {
@@ -1758,15 +1746,10 @@ void TrackPanel::SetCursorAndTipWhenInVResizeArea( Track * label,
       // not actually in the resize area at all.  (The resize area
       // is shorter when it is between stereo tracks).
 
-      // IF we are in the label THEN return.
-      // Subsequently called methods can detect that a tip and
-      // cursor are still needed.
-      if (label)
-         return;
-      *ppTip = _("Click and drag to adjust relative size of stereo tracks.");
+      tip = _("Click and drag to adjust relative size of stereo tracks.");
       SetCursor(*mResizeCursor);
    } else {
-      *ppTip = _("Click and drag to resize the track.");
+      tip = _("Click and drag to resize the track.");
       SetCursor(*mResizeCursor);
    }
 }
@@ -1774,7 +1757,7 @@ void TrackPanel::SetCursorAndTipWhenInVResizeArea( Track * label,
 /// When in a label track, find out if we've hit anything that
 /// would cause a cursor change.
 void TrackPanel::SetCursorAndTipWhenInLabelTrack( LabelTrack * pLT,
-       wxMouseEvent & event, const wxChar ** ppTip )
+       wxMouseEvent & event, wxString &tip )
 {
    int edge=pLT->OverGlyph(event.m_x, event.m_y);
    if(edge !=0)
@@ -1795,7 +1778,7 @@ void TrackPanel::SetCursorAndTipWhenInLabelTrack( LabelTrack * pLT,
    // signal this by setting the tip.
    if( edge != 0 )
    {
-      *ppTip =
+      tip =
          (pLT->mbHitCenter ) ?
          _("Drag one or more label boundaries.") :
          _("Drag label boundary.");
@@ -1805,20 +1788,15 @@ void TrackPanel::SetCursorAndTipWhenInLabelTrack( LabelTrack * pLT,
 namespace {
 
 // This returns true if we're a spectral editing track.
-inline bool isSpectrogramTrack(const Track *pTrack, bool *pLogf = NULL) {
+inline bool isSpectralSelectionTrack(const Track *pTrack) {
    if (pTrack &&
        pTrack->GetKind() == Track::Wave) {
-      const int display =
-         static_cast<const WaveTrack*>(pTrack)->GetDisplay();
-      const bool logF = (display == WaveTrack::SpectrumLogDisplay) || 
-         (display == WaveTrack::SpectralSelectionLogDisplay);
-      if (pLogf)
-         *pLogf = logF;
-      return (display == WaveTrack::SpectralSelectionLogDisplay) || (display == WaveTrack::SpectralSelectionDisplay);
+      const WaveTrack *const wt = static_cast<const WaveTrack*>(pTrack);
+      const SpectrogramSettings &settings = wt->GetSpectrogramSettings();
+      const int display = wt->GetDisplay();
+      return (display == WaveTrack::Spectrum) && settings.SpectralSelectionEnabled();
    }
    else {
-      if (pLogf)
-         *pLogf = false;
       return false;
    }
 }
@@ -1826,7 +1804,7 @@ inline bool isSpectrogramTrack(const Track *pTrack, bool *pLogf = NULL) {
 } // namespace
 
 // If we're in OnDemand mode, we may change the tip.
-void TrackPanel::MaySetOnDemandTip( Track * t, const wxChar ** ppTip )
+void TrackPanel::MaySetOnDemandTip( Track * t, wxString &tip )
 {
    wxASSERT( t );
    //For OD regions, we need to override and display the percent complete for this task.
@@ -1836,17 +1814,17 @@ void TrackPanel::MaySetOnDemandTip( Track * t, const wxChar ** ppTip )
    //see if the wavetrack exists in the ODManager (if the ODManager exists)
    if(!ODManager::IsInstanceCreated())
       return;
-   //ask the wavetrack for the corresponding tip - it may not change **pptip, but that's fine.
-   ODManager::Instance()->FillTipForWaveTrack((WaveTrack*)t,ppTip);
+   //ask the wavetrack for the corresponding tip - it may not change tip, but that's fine.
+   ODManager::Instance()->FillTipForWaveTrack(static_cast<WaveTrack*>(t), tip);
    return;
 }
 
 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
 void TrackPanel::HandleCenterFrequencyCursor
-(bool shiftDown, const wxChar ** ppTip, const wxCursor ** ppCursor)
+(bool shiftDown, wxString &tip, const wxCursor ** ppCursor)
 {
 #ifndef SPECTRAL_EDITING_ESC_KEY
-   *ppTip =
+   tip =
       shiftDown ?
       _("Click and drag to move center selection frequency.") :
       _("Click and drag to move center selection frequency to a spectral peak.");
@@ -1854,7 +1832,7 @@ void TrackPanel::HandleCenterFrequencyCursor
 #else
    shiftDown;
 
-   *ppTip =
+   tip =
       _("Click and drag to move center selection frequency.");
 
 #endif
@@ -1891,7 +1869,7 @@ void TrackPanel::HandleCenterFrequencyClick
 // Determine and set the cursor and tip accordingly.
 void TrackPanel::SetCursorAndTipWhenSelectTool( Track * t,
         wxMouseEvent & event, wxRect &r, bool bMultiToolMode,
-        const wxChar ** ppTip, const wxCursor ** ppCursor )
+        wxString &tip, const wxCursor ** ppCursor )
 {
    // Do not set the default cursor here and re-set later, that causes
    // flashing.
@@ -1909,13 +1887,10 @@ void TrackPanel::SetCursorAndTipWhenSelectTool( Track * t,
          keyStr = _("Edit, Preferences...");
       else
          keyStr = KeyStringDisplay(keyStr);
-      // Must compose a string that survives the function call, hence static.
-      static wxString result;
       /* i18n-hint: %s is usually replaced by "Ctrl+P" for Windows/Linux, "Command+," for Mac */
-      result = wxString::Format(
+      tip = wxString::Format(
          _("Multi-Tool Mode: %s for Mouse and Keyboard Preferences."),
          keyStr.c_str());
-      *ppTip = result;
       // Later in this function we may point to some other string instead.
    }
 
@@ -1928,7 +1903,7 @@ void TrackPanel::SetCursorAndTipWhenSelectTool( Track * t,
    // the preferences...
    if ( !t->GetSelected() || !mAdjustSelectionEdges)
    {
-      MaySetOnDemandTip( t, ppTip );
+      MaySetOnDemandTip( t, tip );
       return;
    }
 
@@ -1942,11 +1917,10 @@ void TrackPanel::SetCursorAndTipWhenSelectTool( Track * t,
    const bool bShiftDown = event.ShiftDown();
 
 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
-   bool logF;
    if ( (mFreqSelMode == FREQ_SEL_SNAPPING_CENTER) &&
-         isSpectrogramTrack(t, &logF) ) {
+      isSpectralSelectionTrack(t)) {
       // Not shift-down, but center frequency snapping toggle is on
-      *ppTip = _("Click and drag to set frequency bandwidth.");
+      tip = _("Click and drag to set frequency bandwidth.");
       *ppCursor = mEnvelopeCursor;
       return;
    }
@@ -1972,7 +1946,7 @@ void TrackPanel::SetCursorAndTipWhenSelectTool( Track * t,
       case SBLeft:
       case SBRight:
          if ( HitTestStretch(t, r, event)) {
-            *ppTip = _("Click and drag to stretch within selected region.");
+            tip = _("Click and drag to stretch within selected region.");
             *ppCursor = mStretchCursor;
             return;
          }
@@ -1987,33 +1961,33 @@ void TrackPanel::SetCursorAndTipWhenSelectTool( Track * t,
          if( bShiftDown ){
             // wxASSERT( false );
             // Same message is used for moving left right top or bottom edge.
-            *ppTip = _("Click to move selection boundary to cursor.");
+            tip = _("Click to move selection boundary to cursor.");
             // No cursor change.
             return;
          }
          break;
       case SBLeft:
-         *ppTip = _("Click and drag to move left selection boundary.");
+         tip = _("Click and drag to move left selection boundary.");
          *ppCursor = mAdjustLeftSelectionCursor;
          return;
       case SBRight:
-         *ppTip = _("Click and drag to move right selection boundary.");
+         tip = _("Click and drag to move right selection boundary.");
          *ppCursor = mAdjustRightSelectionCursor;
          return;
 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
       case SBBottom:
-         *ppTip = _("Click and drag to move bottom selection frequency.");
+         tip = _("Click and drag to move bottom selection frequency.");
          *ppCursor = mBottomFrequencyCursor;
          return;
       case SBTop:
-         *ppTip = _("Click and drag to move top selection frequency.");
+         tip = _("Click and drag to move top selection frequency.");
          *ppCursor = mTopFrequencyCursor;
          return;
       case SBCenter:
-         HandleCenterFrequencyCursor(bShiftDown, ppTip, ppCursor);
+         HandleCenterFrequencyCursor(bShiftDown, tip, ppCursor);
          return;
       case SBWidth:
-         *ppTip = _("Click and drag to adjust frequency bandwidth.");
+         tip = _("Click and drag to adjust frequency bandwidth.");
          *ppCursor = mBandWidthCursor;
          return;
 #endif
@@ -2022,13 +1996,13 @@ void TrackPanel::SetCursorAndTipWhenSelectTool( Track * t,
    } // switch
    // Falls through the switch if there was no boundary found.
 
-   MaySetOnDemandTip( t, ppTip );
+   MaySetOnDemandTip( t, tip );
 }
 
 /// In this method we know what tool we are using,
 /// so set the cursor accordingly.
 void TrackPanel::SetCursorAndTipByTool( int tool,
-         wxMouseEvent & event, const wxChar ** /*ppTip*/ )
+         wxMouseEvent & event, wxString& )
 {
    bool unsafe = IsUnsafe();
 
@@ -2071,12 +2045,12 @@ void TrackPanel::HandleCursor(wxMouseEvent & event)
 
    // (2) If we are not over a track at all, set the cursor to Arrow and
    //     clear the StatusBar,
-   wxRect r;
-   Track *label = FindTrack(event.m_x, event.m_y, true, true, &r);
-   Track *nonlabel = FindTrack(event.m_x, event.m_y, false, false, &r);
-   Track *t = label ? label : nonlabel;
+   wxRect labelRect, trackRect;
+   Track *const label = FindTrack(event.m_x, event.m_y, true, true, &labelRect);
+   Track *const nonlabel = FindTrack(event.m_x, event.m_y, false, false, &trackRect);
+   Track *const track = label ? label : nonlabel;
 
-   if (!t) {
+   if (!track) {
       SetCursor(*mArrowCursor);
       mListener->TP_DisplayStatusMessage(wxT(""));
       return;
@@ -2089,30 +2063,39 @@ void TrackPanel::HandleCursor(wxMouseEvent & event)
    // Strategy here is to set the tip when we have determined and
    // set the correct cursor.  We stop doing tests for what we've
    // hit once the tip is not NULL.
-   const wxChar *tip = NULL;
 
-   if (label) {
-      SetCursorAndTipWhenInLabel( label, event, &tip );
-   }
+   wxString tip;
 
    // Are we within the vertical resize area?
-   if ((tip == NULL ) && within(event.m_y, r.y + r.height, TRACK_RESIZE_REGION))
+   if (nonlabel
+      ? within(event.m_y, trackRect.y + trackRect.height, TRACK_RESIZE_REGION)
+      : within(event.m_y, labelRect.y + labelRect.height, TRACK_RESIZE_REGION))
    {
-      SetCursorAndTipWhenInVResizeArea( label, t->GetLinked(), &tip );
+      SetCursorAndTipWhenInVResizeArea(nonlabel && track->GetLinked(), tip);
       // tip may still be NULL at this point, in which case we go on looking.
    }
 
+   if ((tip == wxString()) && label) {
+      SetCursorAndTipWhenInLabel( label, event, tip );
+   }
+
    // Otherwise, we must be over a track of some kind
    // Is it a label track?
-   if ((tip==NULL) && (t->GetKind() == Track::Label))
+   if ((tip == wxString()) && (track->GetKind() == Track::Label))
    {
       // We are over a label track
-      SetCursorAndTipWhenInLabelTrack( (LabelTrack*)t, event, &tip );
+      SetCursorAndTipWhenInLabelTrack( static_cast<LabelTrack*>(track), event, tip );
       // ..and if we haven't yet determined the cursor,
       // we go on to do all the standard track hit tests.
    }
 
-   if( tip==NULL )
+   if ((tip == wxString()) &&
+      nonlabel &&
+      nonlabel->GetKind() == Track::Wave &&
+      SetCursorForCutline(static_cast<WaveTrack*>(nonlabel), trackRect, event))
+      return;
+
+   if( tip == wxString() )
    {
       ToolsToolBar * ttb = mListener->TP_GetToolsToolBar();
       if( ttb == NULL )
@@ -2131,21 +2114,21 @@ void TrackPanel::HandleCursor(wxMouseEvent & event)
       // the other tool cases.
       if( tool != selectTool )
       {
-         SetCursorAndTipByTool( tool, event, &tip);
+         SetCursorAndTipByTool( tool, event, tip);
       }
       else
       {
          bool bMultiToolMode = ttb->IsDown(multiTool);
          const wxCursor *pSelection = 0;
          SetCursorAndTipWhenSelectTool
-            ( t, event, r, bMultiToolMode, &tip, &pSelection );
+            ( track, event, trackRect, bMultiToolMode, tip, &pSelection );
          if (pSelection)
             // Set cursor once only here, to avoid flashing during drags
             SetCursor(*pSelection);
       }
    }
 
-   if (tip)
+   if (tip != wxString())
       mListener->TP_DisplayStatusMessage(tip);
 }
 
@@ -2161,7 +2144,7 @@ void TrackPanel::HandleSelect(wxMouseEvent & event)
    // AS: Ok, did the user just click the mouse, release the mouse,
    //  or drag?
    if (event.LeftDown() ||
-	   (event.LeftDClick() && event.CmdDown())) {
+      (event.LeftDClick() && event.CmdDown())) {
       // AS: Now, did they click in a track somewhere?  If so, we want
       //  to extend the current selection or start a new selection,
       //  depending on the shift key.  If not, cancel all selections.
@@ -2220,7 +2203,7 @@ void TrackPanel::HandleSelect(wxMouseEvent & event)
                selectedClip->GetOffset(), selectedClip->GetEndTime());
          }
          //Also, capture this track for dragging until we up-click.
-         mCapturedClipArray.Add(TrackClip(w, selectedClip));
+         mCapturedClipArray.push_back(TrackClip(w, selectedClip));
 
          mMouseCapture = IsSliding;
 
@@ -2243,15 +2226,6 @@ void TrackPanel::HandleSelect(wxMouseEvent & event)
 #endif
  done:
    SelectionHandleDrag(event, t);
-
-   // Update lyrics display for new selection.
-   AudacityProject* pProj = GetActiveProject();
-   LyricsWindow* pLyricsWindow = pProj->GetLyricsWindow();
-   if (pLyricsWindow && pLyricsWindow->IsShown())
-   {
-      Lyrics* pLyricsPanel = pLyricsWindow->GetLyricsPanel();
-      pLyricsPanel->Update(pProj->GetSel0());
-   }
 }
 
 
@@ -2533,8 +2507,6 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
    mCapturedTrack = pTrack;
    mCapturedRect = r;
 
-   mMouseClickX = event.m_x;
-   mMouseClickY = event.m_y;
    mMouseCapture=IsSelecting;
    mInitialSelection = mViewInfo->selectedRegion;
 
@@ -2680,9 +2652,8 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
       // preferences now
       if (mAdjustSelectionEdges) {
 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
-         bool logF;
          if (mFreqSelMode == FREQ_SEL_SNAPPING_CENTER &&
-             isSpectrogramTrack(pTrack, &logF)) {
+            isSpectralSelectionTrack(pTrack)) {
             // Ignore whether we are inside the time selection.
             // Exit center-snapping, start dragging the width.
             mFreqSelMode = FREQ_SEL_PINNED_CENTER;
@@ -2990,10 +2961,10 @@ inline double findMaxRatio(double center, double rate)
 
 }
 
-void TrackPanel::SnapCenterOnce(WaveTrack *pTrack, bool up)
+void TrackPanel::SnapCenterOnce(const WaveTrack *pTrack, bool up)
 {
-   // Always spectrogram, never pitch view, pass true
-   const int windowSize = mTrackArtist->GetSpectrumWindowSize(true);
+   const SpectrogramSettings &settings = pTrack->GetSpectrogramSettings();
+   const int windowSize = settings.GetFFTLength();
    const double rate = pTrack->GetRate();
    const double nyq = rate / 2.0;
    const double binFrequency = rate / windowSize;
@@ -3030,7 +3001,7 @@ void TrackPanel::SnapCenterOnce(WaveTrack *pTrack, bool up)
       (snappedFrequency / ratio, snappedFrequency * ratio);
 }
 
-void TrackPanel::StartSnappingFreqSelection (WaveTrack *pTrack)
+void TrackPanel::StartSnappingFreqSelection (const WaveTrack *pTrack)
 {
    static const sampleCount minLength = 8;
 
@@ -3055,12 +3026,13 @@ void TrackPanel::StartSnappingFreqSelection (WaveTrack *pTrack)
    // Use same settings as are now used for spectrogram display,
    // except, shrink the window as needed so we get some answers
 
-   // Always spectrogram, never pitch view, pass true
-   int windowSize = mTrackArtist->GetSpectrumWindowSize(true);
+   const SpectrogramSettings &settings = pTrack->GetSpectrogramSettings();
+   int windowSize = settings.GetFFTLength();
 
    while(windowSize > effectiveLength)
       windowSize >>= 1;
-   const int windowType = SpectrogramSettings::defaults().windowType;
+   const int windowType = settings.windowType;
+
    mFrequencySnapper->Calculate(
       SpectrumAnalyst::Spectrum, windowType, windowSize, rate,
       &frequencySnappingData[0], length);
@@ -3072,10 +3044,9 @@ void TrackPanel::MoveSnappingFreqSelection (int mouseYCoordinate,
                                             int trackTopEdge,
                                             int trackHeight, Track *pTrack)
 {
-   bool logF;
    if (pTrack &&
        pTrack->GetSelected() &&
-       isSpectrogramTrack(pTrack, &logF)) {
+       isSpectralSelectionTrack(pTrack)) {
       WaveTrack *const wt = static_cast<WaveTrack*>(pTrack);
       // PRL:
       // What happens if center snapping selection began in one spectrogram track,
@@ -3085,8 +3056,8 @@ void TrackPanel::MoveSnappingFreqSelection (int mouseYCoordinate,
       // I am not worrying about that odd case.
       const double rate = wt->GetRate();
       const double frequency =
-         PositionToFrequency(false, mouseYCoordinate,
-         trackTopEdge, trackHeight, rate, logF);
+         PositionToFrequency(wt, false, mouseYCoordinate,
+         trackTopEdge, trackHeight);
       const double snappedFrequency =
          mFrequencySnapper->FindPeak(frequency, NULL);
       const double maxRatio = findMaxRatio(snappedFrequency, rate);
@@ -3118,17 +3089,14 @@ void TrackPanel::StartFreqSelection (int mouseYCoordinate, int trackTopEdge,
    mFreqSelMode = FREQ_SEL_INVALID;
    mFreqSelPin = SelectedRegion::UndefinedFrequency;
 
-   bool logF;
-   if (isSpectrogramTrack(pTrack, &logF)) {
+   if (isSpectralSelectionTrack(pTrack)) {
       mFreqSelTrack = static_cast<WaveTrack*>(pTrack);
       mFreqSelMode = FREQ_SEL_FREE;
-      const double rate = mFreqSelTrack->GetRate();
       mFreqSelPin =
-         PositionToFrequency(false, mouseYCoordinate,
-            trackTopEdge, trackHeight, rate, logF);
+         PositionToFrequency(mFreqSelTrack, false, mouseYCoordinate,
+                             trackTopEdge, trackHeight);
+      mViewInfo->selectedRegion.setFrequencies(mFreqSelPin, mFreqSelPin);
    }
-
-   mViewInfo->selectedRegion.setFrequencies(mFreqSelPin, mFreqSelPin);
 }
 
 void TrackPanel::ExtendFreqSelection(int mouseYCoordinate, int trackTopEdge,
@@ -3145,14 +3113,10 @@ void TrackPanel::ExtendFreqSelection(int mouseYCoordinate, int trackTopEdge,
    // started, and that is of a spectrogram display type.
 
    const WaveTrack* wt = mFreqSelTrack;
-   const int display = wt->GetDisplay();
-   const bool logF = (display == WaveTrack::SpectrumLogDisplay) ||
-      (display == WaveTrack::SpectralSelectionLogDisplay) 
-      ;
    const double rate =  wt->GetRate();
    const double frequency =
-      PositionToFrequency(true, mouseYCoordinate,
-         trackTopEdge, trackHeight, rate, logF);
+      PositionToFrequency(wt, true, mouseYCoordinate,
+         trackTopEdge, trackHeight);
 
    // Dragging center?
    if (mFreqSelMode == FREQ_SEL_DRAG_CENTER) {
@@ -3415,12 +3379,7 @@ void TrackPanel::Stretch(int mouseXCoordinate, int trackLeftEdge,
 void TrackPanel::SelectionHandleDrag(wxMouseEvent & event, Track *clickedTrack)
 {
 #ifdef EXPERIMENTAL_SCRUBBING_BASIC
-   if (IsScrubbing()) {
-      // May need a screen update.
-      if (mAutoScrolling)
-         UpdateSelectionDisplay();
-   }
-   else if (mScrubStartPosition >= 0) {
+   if (mScrubStartPosition >= 0) {
       MaybeStartScrubbing(event);
       // Do nothing more, don't change selection
       return;
@@ -3527,13 +3486,14 @@ enum { FREQ_SNAP_DISTANCE = 10 };
 
 /// Converts a position (mouse Y coordinate) to
 /// frequency, in Hz.
-double TrackPanel::PositionToFrequency(bool maySnap,
+double TrackPanel::PositionToFrequency(const WaveTrack *wt,
+                                       bool maySnap,
                                        wxInt64 mouseYCoordinate,
                                        wxInt64 trackTopEdge,
-                                       int trackHeight,
-                                       double rate,
-                                       bool logF) const
+                                       int trackHeight) const
 {
+   const double rate = wt->GetRate();
+
    // Handle snapping
    if (maySnap &&
        mouseYCoordinate - trackTopEdge < FREQ_SNAP_DISTANCE)
@@ -3542,62 +3502,23 @@ double TrackPanel::PositionToFrequency(bool maySnap,
        trackTopEdge + trackHeight - mouseYCoordinate < FREQ_SNAP_DISTANCE)
       return -1;
 
+   const SpectrogramSettings &settings = wt->GetSpectrogramSettings();
+   const NumberScale numberScale(settings.GetScale(rate, false));
    const double p = double(mouseYCoordinate - trackTopEdge) / trackHeight;
-   const int freq = lrint(rate/2.);
-
-   if (logF)
-   {
-      const double maxFreq =
-         std::min(freq, mTrackArtist->GetSpectrumLogMaxFreq(freq));
-      const double minFreq =
-         std::max(1, mTrackArtist->GetSpectrumLogMinFreq(1));
-      return exp(p * log(minFreq) + (1.0 - p) * log(maxFreq));
-   } 
-   else
-   {
-      const double maxFreq =
-         std::min(freq, mTrackArtist->GetSpectrumMaxFreq(freq));
-      const double minFreq =
-         std::max(0, mTrackArtist->GetSpectrumMinFreq(0));
-      return p * minFreq + (1.0 - p) * maxFreq;
-   }
+   return numberScale.PositionToValue(1.0 - p);
 }
 
 /// Converts a frequency to screen y position.
-wxInt64 TrackPanel::FrequencyToPosition(double frequency,
+wxInt64 TrackPanel::FrequencyToPosition(const WaveTrack *wt,
+                                        double frequency,
                                         wxInt64 trackTopEdge,
-                                        int trackHeight,
-                                        double rate,
-                                        bool logF) const
+                                        int trackHeight) const
 {
-   const int freq = lrint(rate/2.);
-   double p = 0;
-
-   if (logF)
-   {
-      const double maxFreq =
-         std::min(freq, mTrackArtist->GetSpectrumLogMaxFreq(freq));
-      const double minFreq =
-         std::max(1, mTrackArtist->GetSpectrumLogMinFreq(1));
-      if (maxFreq > minFreq)
-      {
-         const double
-            logFrequency = log(frequency < 1.0 ? 1.0 : frequency),
-            logMinFreq = log(minFreq),
-            logMaxFreq = log(maxFreq);
-          p = (logFrequency - logMinFreq) / (logMaxFreq - logMinFreq);
-      }
-   }
-   else
-   {
-      const double maxFreq =
-         std::min(freq, mTrackArtist->GetSpectrumMaxFreq(freq));
-      const double minFreq =
-         std::max(0, mTrackArtist->GetSpectrumMinFreq(0));
-      if (maxFreq > minFreq)
-         p = (frequency - minFreq) / (maxFreq - minFreq);
-   }
+   const double rate = wt->GetRate();
 
+   const SpectrogramSettings &settings = wt->GetSpectrogramSettings();
+   const NumberScale numberScale(settings.GetScale(rate, false));
+   const float p = numberScale.ValueToPosition(frequency);
    return trackTopEdge + wxInt64((1.0 - p) * trackHeight);
 }
 #endif
@@ -3678,20 +3599,17 @@ bool mayDragWidth, bool onlyWithinSnapDistance,
    bool chooseTime = true;
    bool chooseBottom = true;
    bool chooseCenter = false;
-   bool logF;
    // Consider adjustment of frequencies only if mouse is
    // within the time boundaries
    if (!mViewInfo->selectedRegion.isPoint() &&
        t0 <= selend && selend < t1 &&
-       isSpectrogramTrack(pTrack, &logF)) {
+       isSpectralSelectionTrack(pTrack)) {
       const WaveTrack *const wt = static_cast<const WaveTrack*>(pTrack);
       const wxInt64 bottomSel = (f0 >= 0)
-         ? FrequencyToPosition(f0, rect.y, rect.height,
-                               wt->GetRate(), logF)
+         ? FrequencyToPosition(wt, f0, rect.y, rect.height)
          : rect.y + rect.height;
       const wxInt64 topSel = (f1 >= 0)
-         ? FrequencyToPosition(f1, rect.y, rect.height,
-         wt->GetRate(), logF)
+         ? FrequencyToPosition(wt, f1, rect.y, rect.height)
          : rect.y;
       wxInt64 signedBottomDist = int(event.m_y - bottomSel);
       wxInt64 verticalDist = abs(signedBottomDist);
@@ -3709,8 +3627,7 @@ bool mayDragWidth, bool onlyWithinSnapDistance,
 #endif
          ) {
          const wxInt64 centerSel =
-            FrequencyToPosition(fc, rect.y, rect.height,
-                                 wt->GetRate(), logF);
+            FrequencyToPosition(wt, fc, rect.y, rect.height);
          const wxInt64 centerDist = abs(int(event.m_y - centerSel));
          if (centerDist < verticalDist)
             chooseCenter = true, verticalDist = centerDist,
@@ -3761,11 +3678,13 @@ void TrackPanel::HandleEnvelope(wxMouseEvent & event)
 {
    if (event.LeftDown()) {
       wxRect r;
-      mCapturedTrack = FindTrack(event.m_x, event.m_y, false, false, &r);
+      Track *pTrack = FindTrack(event.m_x, event.m_y, false, false, &r);
 
-      if (!mCapturedTrack)
+      if (!pTrack)
          return;
 
+      SetCapturedTrack(pTrack, IsEnveloping);
+
       if (mCapturedTrack->GetKind() == Track::Wave)
       {
          mCapturedEnvelope =
@@ -3807,9 +3726,9 @@ void TrackPanel::ForwardEventToTimeTrackEnvelope(wxMouseEvent & event)
    double lower = ptimetrack->GetRangeLower(), upper = ptimetrack->GetRangeUpper();
    if(ptimetrack->GetDisplayLog()) {
       // MB: silly way to undo the work of GetWaveYPos while still getting a logarithmic scale
-      double dBRange = gPrefs->Read(wxT("/GUI/EnvdBRange"), ENV_DB_RANGE);
-      lower = 20.0 * log10(std::max(1.0e-7, lower)) / dBRange + 1.0;
-      upper = 20.0 * log10(std::max(1.0e-7, upper)) / dBRange + 1.0;
+      double dBRange = mViewInfo->dBr;
+      lower = LINEAR_TO_DB(std::max(1.0e-7, lower)) / dBRange + 1.0;
+      upper = LINEAR_TO_DB(std::max(1.0e-7, upper)) / dBRange + 1.0;
    }
    bool needUpdate =
       pspeedenvelope->MouseEvent(
@@ -3837,10 +3756,8 @@ void TrackPanel::ForwardEventToWaveTrackEnvelope(wxMouseEvent & event)
    //  This asks which one is in use. (ie, Wave, Spectrum, etc)
    int display = pwavetrack->GetDisplay();
 
-   // AS: If we're using the right type of display for envelope operations
-   //  ie one of the Wave displays
-   const bool dB = (display == WaveTrack::WaveformDBDisplay);
-   if (dB || (display == WaveTrack::WaveformDisplay)) {
+   if (display == WaveTrack::Waveform) {
+      const bool dB = !pwavetrack->GetWaveformSettings().isLinear();
       bool needUpdate;
 
       // AS: Then forward our mouse event to the envelope.
@@ -3931,7 +3848,7 @@ void TrackPanel::HandleSlide(wxMouseEvent & event)
       if (mDidSlideVertically && mCapturedTrack)
          // Now that user has dropped the clip into a different track,
          // make sure the sample rate matches the destination track (mCapturedTrack).
-         for (size_t i = 0; i < mCapturedClipArray.GetCount(); i++)
+         for (size_t i = 0; i < mCapturedClipArray.size(); i++)
             if (mCapturedTrack->GetKind() == Track::Wave) // Should always be true here, but make sure.
             {
                WaveClip* pWaveClip = mCapturedClipArray[i].clip;
@@ -4019,7 +3936,7 @@ void TrackPanel::StartSlide(wxMouseEvent & event)
       // The captured clip is the focus, but we need to create a list
       // of all clips that have to move, also...
 
-      mCapturedClipArray.Clear();
+      mCapturedClipArray.clear();
 
       double clickTime =
          mViewInfo->PositionToTime(event.m_x, GetLeftOffset());
@@ -4042,7 +3959,7 @@ void TrackPanel::StartSlide(wxMouseEvent & event)
       }
       else {
          mCapturedClipIsSelection = false;
-         mCapturedClipArray.Add(TrackClip(vt, mCapturedClip));
+         mCapturedClipArray.push_back(TrackClip(vt, mCapturedClip));
 
          // Check for stereo partner
          Track *partner = mTracks->GetLink(vt);
@@ -4056,7 +3973,7 @@ void TrackPanel::StartSlide(wxMouseEvent & event)
             if (s0 >= 0) {
                WaveClip *clip = ((WaveTrack *)partner)->GetClipAtSample(s0);
                if (clip) {
-                  mCapturedClipArray.Add(TrackClip(partner, clip));
+                  mCapturedClipArray.push_back(TrackClip(partner, clip));
                }
             }
          }
@@ -4069,7 +3986,7 @@ void TrackPanel::StartSlide(wxMouseEvent & event)
          // clips are considered (the effect is like recursion and terminates
          // because AddClipsToCaptured doesn't add duplicate clips); to remove
          // this behavior just store the array size beforehand.
-         for (unsigned int i = 0; i < mCapturedClipArray.GetCount(); ++i) {
+         for (unsigned int i = 0; i < mCapturedClipArray.size(); ++i) {
             // Capture based on tracks that have clips -- that means we
             // don't capture based on links to label tracks for now (until
             // we can treat individual labels as clips)
@@ -4101,7 +4018,7 @@ void TrackPanel::StartSlide(wxMouseEvent & event)
 
    } else {
       mCapturedClip = NULL;
-      mCapturedClipArray.Clear();
+      mCapturedClipArray.clear();
    }
 
    mSlideUpDownOnly = event.CmdDown() && !multiToolModeActive;
@@ -4160,7 +4077,7 @@ void TrackPanel::AddClipsToCaptured(Track *t, double t0, double t1)
          {
             // Avoid getting clips that were already captured
             bool newClip = true;
-            for (unsigned int i = 0; i < mCapturedClipArray.GetCount(); ++i) {
+            for (unsigned int i = 0; i < mCapturedClipArray.size(); ++i) {
                if (mCapturedClipArray[i].clip == clip) {
                   newClip = false;
                   break;
@@ -4168,7 +4085,7 @@ void TrackPanel::AddClipsToCaptured(Track *t, double t0, double t1)
             }
 
             if (newClip)
-               mCapturedClipArray.Add(TrackClip(t, clip));
+               mCapturedClipArray.push_back(TrackClip(t, clip));
          }
          it = it->GetNext();
       }
@@ -4180,7 +4097,7 @@ void TrackPanel::AddClipsToCaptured(Track *t, double t0, double t1)
 
       // Avoid adding a track twice
       bool newClip = true;
-      for (unsigned int i = 0; i < mCapturedClipArray.GetCount(); ++i) {
+      for (unsigned int i = 0; i < mCapturedClipArray.size(); ++i) {
          if (mCapturedClipArray[i].track == t) {
             newClip = false;
             break;
@@ -4195,7 +4112,7 @@ void TrackPanel::AddClipsToCaptured(Track *t, double t0, double t1)
                return;
          }
 #endif
-         mCapturedClipArray.Add(TrackClip(t, NULL));
+         mCapturedClipArray.push_back(TrackClip(t, NULL));
       }
    }
 }
@@ -4227,11 +4144,11 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
    // happens relative to the original horizontal position of
    // each clip...
 #ifdef USE_MIDI
-   if (mCapturedClipArray.GetCount()) {
+   if (mCapturedClipArray.size()) {
 #else
    if (mCapturedClip) {
 #endif
-      for(i=0; i<mCapturedClipArray.GetCount(); i++) {
+      for(i=0; i<mCapturedClipArray.size(); i++) {
          if (mCapturedClipArray[i].clip)
             mCapturedClipArray[i].clip->Offset(-mHSlideAmount);
          else
@@ -4261,7 +4178,7 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
                            mtw->GetRate();  // set it to a sample point
    }
    // Adjust desiredSlideAmount using SnapManager
-   if (mSnapManager && mCapturedClipArray.GetCount()) {
+   if (mSnapManager && mCapturedClipArray.size()) {
       double clipLeft;
       double clipRight;
       if (mCapturedClip) {
@@ -4335,7 +4252,7 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
 
       // Temporary apply the offset because we want to see if the
       // track fits with the desired offset
-      for(i=0; i<mCapturedClipArray.GetCount(); i++)
+      for(i=0; i<mCapturedClipArray.size(); i++)
          if (mCapturedClipArray[i].clip)
             mCapturedClipArray[i].clip->Offset(desiredSlideAmount);
       // See if it can be moved
@@ -4356,7 +4273,7 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
       }
       else {
          // Undo the offset
-         for(i=0; i<mCapturedClipArray.GetCount(); i++)
+         for(i=0; i<mCapturedClipArray.size(); i++)
             if (mCapturedClipArray[i].clip)
                mCapturedClipArray[i].clip->Offset(-desiredSlideAmount);
       }
@@ -4377,7 +4294,7 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
    }
 
 #ifdef USE_MIDI
-   if (mCapturedClipArray.GetCount()) {
+   if (mCapturedClipArray.size()) {
 #else
    if (mCapturedClip) {
 #endif
@@ -4390,7 +4307,7 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
          initialAllowed = mHSlideAmount;
 
          unsigned int i, j;
-         for(i=0; i<mCapturedClipArray.GetCount(); i++) {
+         for(i=0; i<mCapturedClipArray.size(); i++) {
             WaveTrack *track = (WaveTrack *)mCapturedClipArray[i].track;
             WaveClip *clip = mCapturedClipArray[i].clip;
 
@@ -4399,7 +4316,7 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
                // temporarily because they're all moving together and
                // we want to find out if OTHER clips are in the way,
                // not one of the moving ones
-               for(j=0; j<mCapturedClipArray.GetCount(); j++) {
+               for(j=0; j<mCapturedClipArray.size(); j++) {
                   WaveClip *clip2 = mCapturedClipArray[j].clip;
                   if (clip2 && clip2 != clip)
                      clip2->Offset(-safeBigDistance);
@@ -4411,7 +4328,7 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
                else
                   mHSlideAmount = 0.0;
 
-               for(j=0; j<mCapturedClipArray.GetCount(); j++) {
+               for(j=0; j<mCapturedClipArray.size(); j++) {
                   WaveClip *clip2 = mCapturedClipArray[j].clip;
                   if (clip2 && clip2 != clip)
                      clip2->Offset(safeBigDistance);
@@ -4422,7 +4339,7 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
 
       if (mHSlideAmount != 0.0) { // finally, here is where clips are moved
          unsigned int i;
-         for(i=0; i<mCapturedClipArray.GetCount(); i++) {
+         for(i=0; i<mCapturedClipArray.size(); i++) {
             Track *track = mCapturedClipArray[i].track;
             WaveClip *clip = mCapturedClipArray[i].clip;
             if (clip)
@@ -4609,9 +4526,7 @@ void TrackPanel::HandleVZoomClick( wxMouseEvent & event )
    if (!mCapturedTrack)
       return;
 
-   // don't do anything if track is not wave or Spectrum/log Spectrum
-   if (((mCapturedTrack->GetKind() == Track::Wave) &&
-            (((WaveTrack*)mCapturedTrack)->GetDisplay() != WaveTrack::PitchDisplay))
+   if (mCapturedTrack->GetKind() == Track::Wave
 #ifdef USE_MIDI
             || mCapturedTrack->GetKind() == Track::Note
 #endif
@@ -4651,7 +4566,6 @@ void TrackPanel::HandleVZoomDrag( wxMouseEvent & event )
 ///   - Zoom in; ensure we don't go too large.
 void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
 {
-   int minBins = 0;
    if (!mCapturedTrack)
       return;
 
@@ -4678,11 +4592,25 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
    }
 #endif
 
+
    // don't do anything if track is not wave
    if (mCapturedTrack->GetKind() != Track::Wave)
       return;
-   WaveTrack *track = (WaveTrack *)mCapturedTrack;
-   WaveTrack *partner = (WaveTrack *)mTracks->GetLink(track);
+
+   if (event.RightUp() &&
+       !(event.ShiftDown() || event.CmdDown())) {
+      OnVRulerMenu(mCapturedTrack, &event);
+      return;
+   }
+
+   HandleWaveTrackVZoom(static_cast<WaveTrack*>(mCapturedTrack),
+      event.ShiftDown(), event.RightUp());
+   mCapturedTrack = NULL;
+}
+
+void TrackPanel::HandleWaveTrackVZoom(WaveTrack *track, bool shiftDown, bool rightUp)
+{
+   WaveTrack *partner = static_cast<WaveTrack *>(mTracks->GetLink(track));
    int height = track->GetHeight();
    int ypos = mCapturedRect.y;
 
@@ -4693,225 +4621,174 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
       mZoomStart = temp;
    }
 
-   float min, max, c, l, binSize = 0.0;
-   bool spectrum, spectrumLog;
-   int windowSize;
-   double rate = ((WaveTrack *)track)->GetRate();
-   spectrum = (((WaveTrack *) track)->GetDisplay() == WaveTrack::SpectrumDisplay) ||
-      (((WaveTrack *) track)->GetDisplay() == WaveTrack::SpectralSelectionDisplay)  ;
-   spectrumLog=(((WaveTrack *) track)->GetDisplay() == WaveTrack::SpectrumLogDisplay) ||
-      (((WaveTrack *) track)->GetDisplay() == WaveTrack::SpectralSelectionLogDisplay) 
-      ;
-   if(spectrum) {
-      min = mTrackArtist->GetSpectrumMinFreq(0);
-      if(min < 0)
-         min = 0;
-      max = mTrackArtist->GetSpectrumMaxFreq(8000);
-      if(max > rate/2.)
-         max = rate/2.;
-
-      // Always spectrogram, never pitch view, pass true
-      windowSize = mTrackArtist->GetSpectrumWindowSize(true);
-      binSize = rate / windowSize;
-      minBins = wxMin(10, windowSize/2); //minimum 10 freq bins, unless there are less
+   float min, max, c, l, minBand = 0;
+   const double rate = track->GetRate();
+   const float halfrate = rate / 2;
+   const SpectrogramSettings &settings = track->GetSpectrogramSettings();
+   NumberScale scale(track->GetSpectrogramSettings().GetScale(rate, false));
+   const bool spectral = (track->GetDisplay() == WaveTrack::Spectrum);
+   const bool spectrumLinear = spectral &&
+      (track->GetSpectrogramSettings().scaleType == SpectrogramSettings::stLinear);
+
+   if (spectral) {
+      if (spectrumLinear) {
+         min = settings.GetMinFreq(rate);
+         max = settings.GetMaxFreq(rate);
+      }
+      else {
+         min = settings.GetLogMinFreq(rate);
+         max = settings.GetLogMaxFreq(rate);
+      }
+      const int fftLength = settings.GetFFTLength();
+      const float binSize = rate / fftLength;
+      const int minBins =
+         std::min(10, fftLength / 2); //minimum 10 freq bins, unless there are less
+      minBand = minBins * binSize;
    }
    else
-      if(spectrumLog) {
-         min = mTrackArtist->GetSpectrumLogMinFreq(lrint(rate/1000.0));
-         if(min < 1)
-            min = 1;
-         max = mTrackArtist->GetSpectrumLogMaxFreq(lrint(rate/2.));
-         if(max > rate/2.)
-            max = rate/2.;
-
-         // Always spectrogram, never pitch view, pass true
-         windowSize = mTrackArtist->GetSpectrumWindowSize(true);
-         binSize = rate / windowSize;
-         minBins = wxMin(10, windowSize/2); //minimum 10 freq bins, unless there are less
-      }
-      else
-         track->GetDisplayBounds(&min, &max);
+      track->GetDisplayBounds(&min, &max);
+
    if (IsDragZooming()) {
       // Drag Zoom
-      float p1, p2, tmin, tmax;
-      tmin=min;
-      tmax=max;
-
-      if(spectrumLog) {
-         double xmin = 1-(mZoomEnd - ypos) / (float)height;
-         double xmax = 1-(mZoomStart - ypos) / (float)height;
-         double lmin=log10(tmin), lmax=log10(tmax);
-         double d=lmax-lmin;
-         min=wxMax(1.0, pow(10, xmin*d+lmin));
-         max=wxMin(rate/2.0, pow(10, xmax*d+lmin));
-         // Enforce vertical zoom limits
-         // done in the linear freq domain for now, but not too far out
-         if(max < min + minBins * binSize)
-            max = min + minBins * binSize;
-         if(max > rate/2.) {
-            max = rate/2.;
-            min = max - minBins * binSize;
-         }
+      const float tmin = min, tmax = max;
+
+      if (spectral) {
+         double xmin = 1 - (mZoomEnd - ypos) / (float)height;
+         double xmax = 1 - (mZoomStart - ypos) / (float)height;
+         const float middle = (xmin + xmax) / 2;
+         const float middleValue = scale.PositionToValue(middle);
+
+         min = std::max(spectrumLinear ? 0.0f : 1.0f,
+            std::min(middleValue - minBand / 2,
+               scale.PositionToValue(xmin)
+         ));
+         max = std::min(halfrate,
+            std::max(middleValue + minBand / 2,
+               scale.PositionToValue(xmax)
+         ));
       }
       else {
-         p1 = (mZoomStart - ypos) / (float)height;
-         p2 = (mZoomEnd - ypos) / (float)height;
+         const float p1 = (mZoomStart - ypos) / (float)height;
+         const float p2 = (mZoomEnd - ypos) / (float)height;
          max = (tmax * (1.0-p1) + tmin * p1);
          min = (tmax * (1.0-p2) + tmin * p2);
 
-         // Enforce vertical zoom limits
-         if(spectrum) {
-            if(min < 0.)
-               min = 0.;
-            if(max < min + minBins * binSize)
-               max = min + minBins * binSize;
-            if(max > rate/2.) {
-               max = rate/2.;
-               min = max - minBins * binSize;
-            }
-         }
-         else {
-            // Waveform view - allow zooming down to a range of ZOOMLIMIT
-            if (max - min < ZOOMLIMIT) {     // if user attempts to go smaller...
-               c = (min+max)/2;           // ...set centre of view to centre of dragged area and top/bottom to ZOOMLIMIT/2 above/below
-               min = c - ZOOMLIMIT/2.0;
-               max = c + ZOOMLIMIT/2.0;
-            }
+         // Waveform view - allow zooming down to a range of ZOOMLIMIT
+         if (max - min < ZOOMLIMIT) {     // if user attempts to go smaller...
+            c = (min+max)/2;           // ...set centre of view to centre of dragged area and top/bottom to ZOOMLIMIT/2 above/below
+            min = c - ZOOMLIMIT/2.0;
+            max = c + ZOOMLIMIT/2.0;
          }
       }
    }
-   else if (event.ShiftDown() || event.RightUp()) {
+   else if (shiftDown || rightUp) {
       // Zoom OUT
-      // Zoom out to -1.0...1.0 first, then, and only
-      // then, if they click again, allow one more
-      // zoom out.
-      if(spectrum) {
-         if (event.ShiftDown() && event.RightUp()) {
+      if (spectral) {
+         if (shiftDown && rightUp) {
             // Zoom out full
-            min = 0.0;
-            max = rate/2.;
+            min = spectrumLinear ? 0.0f : 1.0f;
+            max = halfrate;
          }
          else {
             // Zoom out
-            c = 0.5*(min+max);
-            l = (c - min);
-            if(c - 2*l <= 0) {
-               min = 0.0;
-               max = wxMin( rate/2., 2. * max);
-            }
-            else {
-               min = wxMax( 0.0, c - 2*l);
-               max = wxMin( rate/2., c + 2*l);
-            }
+
+            // (Used to zoom out centered at midline, ignoring the click, if linear view.
+            //  I think it is better to be consistent.  PRL)
+            // Center zoom-out at the midline
+            const float middle = // spectrumLinear ? 0.5f :
+               1.0f - (mZoomStart - ypos) / (float)height;
+
+            min = std::max(spectrumLinear ? 0.0f : 1.0f, scale.PositionToValue(middle - 1.0f));
+            max = std::min(halfrate, scale.PositionToValue(middle + 1.0f));
          }
       }
       else {
-         if(spectrumLog) {
-            if (event.ShiftDown() && event.RightUp()) {
-                // Zoom out full
-                min = 1.0;
-                max = rate/2.;
-            }
-            else {
-               // Zoom out
-               float p1;
-               p1 = (mZoomStart - ypos) / (float)height;
-               c = 1.0-p1;
-               double xmin = c - 1.;
-               double xmax = c + 1.;
-               double lmin = log10(min), lmax = log10(max);
-               double d = lmax-lmin;
-               min = wxMax(1,pow(10, xmin*d+lmin));
-               max = wxMin(rate/2., pow(10, xmax*d+lmin));
-            }
+         // Zoom out to -1.0...1.0 first, then, and only
+         // then, if they click again, allow one more
+         // zoom out.
+         if (shiftDown && rightUp) {
+            // Zoom out full
+            min = -1.0;
+            max = 1.0;
          }
          else {
-            if (event.ShiftDown() && event.RightUp()) {
-               // Zoom out full
-               min = -1.0;
-               max = 1.0;
+            // Zoom out
+            if (min <= -1.0 && max >= 1.0) {
+               min = -2.0;
+               max = 2.0;
             }
             else {
-               // Zoom out
-               if (min <= -1.0 && max >= 1.0) {
-                  min = -2.0;
-                  max = 2.0;
-               }
-               else {
-                  c = 0.5*(min+max);
-                  l = (c - min);
-                  // limit to +/- 1 range unless already outside that range...
-                  float minRange = (min < -1) ? -2.0 : -1.0;
-                  float maxRange = (max > 1) ? 2.0 : 1.0;
-                  // and enforce vertical zoom limits.
-                  min = wxMin(maxRange - ZOOMLIMIT, wxMax(minRange, c - 2*l));
-                  max = wxMax(minRange + ZOOMLIMIT, wxMin(maxRange, c + 2*l));
-               }
+               c = 0.5*(min + max);
+               l = (c - min);
+               // limit to +/- 1 range unless already outside that range...
+               float minRange = (min < -1) ? -2.0 : -1.0;
+               float maxRange = (max > 1) ? 2.0 : 1.0;
+               // and enforce vertical zoom limits.
+               min = std::min(maxRange - ZOOMLIMIT, std::max(minRange, c - 2 * l));
+               max = std::max(minRange + ZOOMLIMIT, std::min(maxRange, c + 2 * l));
             }
          }
       }
    }
    else {
       // Zoom IN
-      float p1;
-      if(spectrum) {
-         c = 0.5*(min+max);
-         // Enforce maximum vertical zoom
-         l = wxMax( minBins * binSize, (c - min));
-
-         p1 = (mZoomStart - ypos) / (float)height;
-         c = (max * (1.0-p1) + min * p1);
-         min = wxMax( 0.0, c - 0.5*l);
-         max = wxMin( rate/2., min + l);
+      if (spectral) {
+         // Center the zoom-in at the click
+         const float middle = 1.0f - (mZoomStart - ypos) / (float)height;
+         const float middleValue = scale.PositionToValue(middle);
+
+         min = std::max(spectrumLinear ? 0.0f : 1.0f,
+            std::min(middleValue - minBand / 2,
+               scale.PositionToValue(middle - 0.25f)
+         ));
+         max = std::min(halfrate,
+            std::max(middleValue + minBand / 2,
+               scale.PositionToValue(middle + 0.25f)
+         ));
       }
       else {
-         if(spectrumLog) {
-            p1 = (mZoomStart - ypos) / (float)height;
-            c = 1.0-p1;
-            double xmin = c - 0.25;
-            double xmax = c + 0.25;
-            double lmin = log10(min), lmax = log10(max);
-            double d = lmax-lmin;
-            min = wxMax(1,pow(10, xmin*d+lmin));
-            max = wxMin(rate/2., pow(10, xmax*d+lmin));
-            // Enforce vertical zoom limits
-            // done in the linear freq domain for now, but not too far out
-            if(max < min + minBins * binSize)
-               max = min + minBins * binSize;
-            if(max > rate/2.) {
-               max = rate/2.;
-               min = max - minBins * binSize;
-            }
+         // Zoom in centered on cursor
+         float p1;
+         if (min < -1.0 || max > 1.0) {
+            min = -1.0;
+            max = 1.0;
          }
          else {
-            // Zoom in centered on cursor
-            if (min < -1.0 || max > 1.0) {
-               min = -1.0;
-               max = 1.0;
-            }
-            else {
-               c = 0.5*(min+max);
-               // Enforce maximum vertical zoom
-               l = wxMax( ZOOMLIMIT, (c - min));
-
-               p1 = (mZoomStart - ypos) / (float)height;
-               c = (max * (1.0-p1) + min * p1);
-               min = c - 0.5*l;
-               max = c + 0.5*l;
-            }
+            c = 0.5*(min + max);
+            // Enforce maximum vertical zoom
+            l = std::max(ZOOMLIMIT, (c - min));
+
+            p1 = (mZoomStart - ypos) / (float)height;
+            c = (max * (1.0 - p1) + min * p1);
+            min = c - 0.5*l;
+            max = c + 0.5*l;
          }
       }
    }
 
-   if(spectrum) {
-      mTrackArtist->SetSpectrumMaxFreq(max);
-      mTrackArtist->SetSpectrumMinFreq(min);
-      mTrackArtist->InvalidateSpectrumCache(mTracks);
-   }
-   else if(spectrumLog) {
-      mTrackArtist->SetSpectrumLogMaxFreq(max);
-      mTrackArtist->SetSpectrumLogMinFreq(min);
-      mTrackArtist->InvalidateSpectrumCache(mTracks);
+   if (spectral) {
+      if (spectrumLinear) {
+         SpectrogramSettings &settings = track->GetSpectrogramSettings();
+         settings.SetMinFreq(min);
+         settings.SetMaxFreq(max);
+         if (partner) {
+            // To do:  share memory with reference counting?
+            SpectrogramSettings &settings = partner->GetSpectrogramSettings();
+            settings.SetMinFreq(min);
+            settings.SetMaxFreq(max);
+         }
+      }
+      else {
+         SpectrogramSettings &settings = track->GetSpectrogramSettings();
+         settings.SetLogMinFreq(min);
+         settings.SetLogMaxFreq(max);
+         if (partner) {
+            // To do:  share memory with reference counting?
+            SpectrogramSettings &settings = partner->GetSpectrogramSettings();
+            settings.SetLogMinFreq(min);
+            settings.SetLogMaxFreq(max);
+         }
+      }
    }
    else {
       track->SetDisplayBounds(min, max);
@@ -4920,9 +4797,8 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
    }
 
    mZoomEnd = mZoomStart = 0;
-   UpdateVRuler(mCapturedTrack);
+   UpdateVRuler(track);
    Refresh(false);
-   mCapturedTrack = NULL;
    MakeParentModifyState(true);
 }
 
@@ -4964,20 +4840,12 @@ bool TrackPanel::IsSampleEditingPossible( wxMouseEvent &event, Track * t )
    //If we aren't displaying the waveform, Display a message dialog
    WaveTrack *const wt = static_cast<WaveTrack*>(t);
    const int display = wt->GetDisplay();
-#if 1
-   if (!(WaveTrack::WaveformDisplay == display ||
-         WaveTrack::WaveformDBDisplay == display))
-   {
-      wxMessageBox(_("To use Draw, choose 'Waveform' or 'Waveform dB' in the Track Drop-down Menu."), wxT("Draw Tool"));
-      return false;
-   }
-#else
-   if(WaveTrack::WaveformDisplay != display)
+
+   if (WaveTrack::Waveform != display)
    {
       wxMessageBox(_("To use Draw, choose 'Waveform' in the Track Drop-down Menu."), wxT("Draw Tool"));
       return false;
    }
-#endif
 
    bool showPoints;
    {
@@ -4992,16 +4860,7 @@ bool TrackPanel::IsSampleEditingPossible( wxMouseEvent &event, Track * t )
    //If we aren't zoomed in far enough, show a message dialog.
    if(!showPoints)
    {
-      // Release capture so user will be able to click OK on Linux
-      bool hadCapture = HasCapture();
-      if (hadCapture)
-         ReleaseMouse();
-
       wxMessageBox(_("To use Draw, zoom in further until you can see the individual samples."), wxT("Draw Tool"));
-
-      // Re-aquire capture
-      if (hadCapture)
-         CaptureMouse();
       return false;
    }
    return true;
@@ -5015,8 +4874,9 @@ float TrackPanel::FindSampleEditingLevel(wxMouseEvent &event, double t0)
 
    const int y = event.m_y - mDrawingTrackTop;
    const int height = mDrawingTrack->GetHeight();
-   const bool dB = (WaveTrack::WaveformDBDisplay == mDrawingTrack->GetDisplay());
-   float newLevel = ::ValueOfPixel(y, height, false, dB, mdBr, zoomMin, zoomMax);
+   const bool dB = !mDrawingTrack->GetWaveformSettings().isLinear();
+   float newLevel =
+      ::ValueOfPixel(y, height, false, dB, mViewInfo->dBr, zoomMin, zoomMax);
 
    //Take the envelope into account
    Envelope *const env = mDrawingTrack->GetEnvelopeAtX(event.m_x);
@@ -5050,11 +4910,7 @@ void TrackPanel::HandleSampleEditingClick( wxMouseEvent & event )
       return;
 
    if( !IsSampleEditingPossible( event, t ) )
-   {
-      if( HasCapture() )
-         ReleaseMouse();
       return;
-   }
 
    /// \todo Should mCapturedTrack take the place of mDrawingTrack??
    mDrawingTrack = static_cast<WaveTrack*>(t);
@@ -5278,8 +5134,6 @@ void TrackPanel::HandleSampleEditing(wxMouseEvent & event)
 // This is for when a given track gets the x.
 void TrackPanel::HandleClosing(wxMouseEvent & event)
 {
-   AudacityProject *p = GetProject(); //lda
-
    Track *t = mCapturedTrack;
    wxRect r = mCapturedRect;
 
@@ -5293,7 +5147,7 @@ void TrackPanel::HandleClosing(wxMouseEvent & event)
    else if (event.LeftUp()) {
       mTrackInfo.DrawCloseBox(&dc, r, false);
       if (closeRect.Contains(event.m_x, event.m_y)) {
-         if (!gAudioIO->IsStreamActive(p->GetAudioIOToken()))
+         if (!IsUnsafe())
             RemoveTrack(t);
       }
       SetCapturedTrack( NULL );
@@ -5601,9 +5455,7 @@ void TrackPanel::HandleLabelClick(wxMouseEvent & event)
    // if they see anything other than a left click.
    bool isleft = event.Button(wxMOUSE_BTN_LEFT);
 
-   AudacityProject *p = GetProject();
-   bool unsafe = (p->GetAudioIOToken()>0 &&
-                  gAudioIO->IsStreamActive(p->GetAudioIOToken()));
+   bool unsafe = IsUnsafe();
 
    wxRect r;
 
@@ -5734,6 +5586,11 @@ void TrackPanel::HandleRearrange(wxMouseEvent & event)
       return;
    }
 
+   // probably harmless during play?  However, we do disallow the click, so check this too.
+   bool unsafe = IsUnsafe();
+   if (unsafe)
+      return;
+
    MixerBoard* pMixerBoard = this->GetMixerBoard(); // Update mixer board, too.
    wxString dir;
    if (event.m_y < mMoveUpThreshold || event.m_y < 0) {
@@ -5918,26 +5775,25 @@ bool TrackPanel::PopupFunc(Track * t, wxRect r, int x, int y)
 ///  update the track size.
 void TrackPanel::HandleResizeClick( wxMouseEvent & event )
 {
-   wxRect r;
+   wxRect rTrack;
    wxRect rLabel;
 
    // DM: Figure out what track is about to be resized
-   Track *t = FindTrack(event.m_x, event.m_y, false, false, &r);
-   Track *label = FindTrack(event.m_x, event.m_y, true, true, &rLabel);
-
-   // If the click is at the bottom of a non-linked track label, we
-   // treat it as a normal resize.  If the label is of a linked track,
-   // we ignore the click.
+   Track *track = FindTrack(event.m_x, event.m_y, false, false, &rTrack);
 
-   if (label && !label->GetLinked()) {
-      t = label;
+   if (!track) {
+      // This will only return unlinked tracks or left channels of stereo tracks
+      // or NULL:
+      track = FindTrack(event.m_x, event.m_y, true, true, &rLabel);
+      // If stereo, get the right channel.
+      if (track && track->GetLinked())
+         track = track->GetLink();
    }
 
-   if (!t) {
+   if (!track) {
       return;
    }
 
-   mMouseClickX = event.m_x;
    mMouseClickY = event.m_y;
 
 #ifdef EXPERIMENTAL_OUTPUT_DISPLAY
@@ -5983,34 +5839,34 @@ void TrackPanel::HandleResizeClick( wxMouseEvent & event )
       }
    }
 #else // EXPERIMENTAL_OUTPUT_DISPLAY
-   Track *prev = mTracks->GetPrev(t);
-   Track *next = mTracks->GetNext(t);
+   Track *prev = mTracks->GetPrev(track);
+   Track *next = mTracks->GetNext(track);
 
    //STM:  Determine whether we should rescale one or two tracks
-   if (prev && prev->GetLink() == t) {
+   if (prev && prev->GetLink() == track) {
       // mCapturedTrack is the lower track
-      mInitialTrackHeight = t->GetHeight();
-      mInitialActualHeight = t->GetActualHeight();
-      mInitialMinimized = t->GetMinimized();
+      mInitialTrackHeight = track->GetHeight();
+      mInitialActualHeight = track->GetActualHeight();
+      mInitialMinimized = track->GetMinimized();
       mInitialUpperTrackHeight = prev->GetHeight();
       mInitialUpperActualHeight = prev->GetActualHeight();
-      SetCapturedTrack(t, IsResizingBelowLinkedTracks);
+      SetCapturedTrack(track, IsResizingBelowLinkedTracks);
    }
-   else if (next && t->GetLink() == next) {
+   else if (next && track->GetLink() == next) {
       // mCapturedTrack is the upper track
       mInitialTrackHeight = next->GetHeight();
       mInitialActualHeight = next->GetActualHeight();
       mInitialMinimized = next->GetMinimized();
-      mInitialUpperTrackHeight = t->GetHeight();
-      mInitialUpperActualHeight = t->GetActualHeight();
-      SetCapturedTrack(t, IsResizingBetweenLinkedTracks);
+      mInitialUpperTrackHeight = track->GetHeight();
+      mInitialUpperActualHeight = track->GetActualHeight();
+      SetCapturedTrack(track, IsResizingBetweenLinkedTracks);
    }
    else {
       // DM: Save the initial mouse location and the initial height
-      mInitialTrackHeight = t->GetHeight();
-      mInitialActualHeight = t->GetActualHeight();
-      mInitialMinimized = t->GetMinimized();
-      SetCapturedTrack(t, IsResizing);
+      mInitialTrackHeight = track->GetHeight();
+      mInitialActualHeight = track->GetActualHeight();
+      mInitialMinimized = track->GetMinimized();
+      SetCapturedTrack(track, IsResizing);
    }
 #endif // EXPERIMENTAL_OUTPUT_DISPLAY
 }
@@ -6491,10 +6347,8 @@ void TrackPanel::OnMouseEvent(wxMouseEvent & event)
 
    if (event.ButtonDown()) {
       SetFocus();
-      if (!HasCapture())
-         CaptureMouse();
    }
-   else if (event.ButtonUp()) {
+   if (event.ButtonUp()) {
       if (HasCapture())
          ReleaseMouse();
    }
@@ -6555,10 +6409,16 @@ void TrackPanel::OnMouseEvent(wxMouseEvent & event)
       HandleLabelTrackMouseEvent((LabelTrack *)mCapturedTrack, mCapturedRect, event);
       break;
    default: //includes case of IsUncaptured
+      // This is where most button-downs are detected
       HandleTrackSpecificMouseEvent(event);
       break;
    }
 
+   if (event.ButtonDown() && IsMouseCaptured()) {
+      if (!HasCapture())
+         CaptureMouse();
+   }
+
    //EnsureVisible should be called after the up-click.
    if (event.ButtonUp()) {
       wxRect r;
@@ -6569,27 +6429,26 @@ void TrackPanel::OnMouseEvent(wxMouseEvent & event)
    }
 }
 
-bool TrackPanel::HandleTrackLocationMouseEvent(WaveTrack * track, wxRect &r, wxMouseEvent &event)
+bool TrackPanel::HandleTrackLocationMouseEvent(WaveTrack * track, wxRect &rect, wxMouseEvent &event)
 {
    // FIXME: Disable this and return true when CutLines aren't showing?
    // (Don't use gPrefs-> for the fix as registry access is slow).
 
    if (mMouseCapture == WasOverCutLine)
    {
-      // Needed to avoid select events right after IsOverCutLine event on button up
       if (event.ButtonUp()) {
          mMouseCapture = IsUncaptured;
          return false;
       }
-      return true;
+      else
+         // Needed to avoid select events after button down
+         return true;
    }
-
-   if (mMouseCapture == IsOverCutLine)
+   else if (!IsUnsafe() && IsOverCutline(track, rect, event))
    {
       if (!mCapturedTrackLocationRect.Contains(event.m_x, event.m_y))
       {
          SetCapturedTrack( NULL );
-         SetCursorByActivity();
          return false;
       }
 
@@ -6597,15 +6456,11 @@ bool TrackPanel::HandleTrackLocationMouseEvent(WaveTrack * track, wxRect &r, wxM
 
       if (event.LeftDown())
       {
-         if (mCapturedTrackLocation.typ == WaveTrack::locationCutLine)
+         if (mCapturedTrackLocation.typ == WaveTrackLocation::locationCutLine)
          {
             // When user presses left button on cut line, expand the line again
             double cutlineStart = 0, cutlineEnd = 0;
 
-            // Release capture so user will be able to click OK on Linux
-            if (HasCapture())
-               ReleaseMouse();
-
             if (track->ExpandCutLine(mCapturedTrackLocation.pos, &cutlineStart, &cutlineEnd))
             {
                WaveTrack* linked = (WaveTrack*)mTracks->GetLink(track);
@@ -6618,8 +6473,8 @@ bool TrackPanel::HandleTrackLocationMouseEvent(WaveTrack * track, wxRect &r, wxM
                MakeParentPushState(_("Expanded Cut Line"), _("Expand"));
                handled = true;
             }
-         } else if (mCapturedTrackLocation.typ == WaveTrack::locationMergePoint)
-         {
+         }
+         else if (mCapturedTrackLocation.typ == WaveTrackLocation::locationMergePoint) {
             if (!track->MergeClips(mCapturedTrackLocation.clipidx1, mCapturedTrackLocation.clipidx2))
                return false;
 
@@ -6646,6 +6501,8 @@ bool TrackPanel::HandleTrackLocationMouseEvent(WaveTrack * track, wxRect &r, wxM
       if (handled)
       {
          SetCapturedTrack( NULL );
+         // Effect happened at button-down, but treat like a dragging mode until
+         // button-up.
          mMouseCapture = WasOverCutLine;
          RefreshTrack(track);
          return true;
@@ -6654,24 +6511,27 @@ bool TrackPanel::HandleTrackLocationMouseEvent(WaveTrack * track, wxRect &r, wxM
       return true;
    }
 
+   return false;
+}
+
+bool TrackPanel::IsOverCutline(WaveTrack * track, wxRect &rect, wxMouseEvent &event)
+{
    for (int i=0; i<track->GetNumCachedLocations(); i++)
    {
       WaveTrack::Location loc = track->GetCachedLocation(i);
 
       const double x = mViewInfo->TimeToPosition(loc.pos);
-      if (x >= 0 && x < r.width)
+      if (x >= 0 && x < rect.width)
       {
          wxRect locRect;
-         locRect.x = int( r.x + x ) - 5;
+         locRect.x = int(rect.x + x) - 5;
          locRect.width = 11;
-         locRect.y = r.y;
-         locRect.height = r.height;
+         locRect.y = rect.y;
+         locRect.height = rect.height;
          if (locRect.Contains(event.m_x, event.m_y))
          {
-            SetCapturedTrack(track, IsOverCutLine);
             mCapturedTrackLocation = loc;
             mCapturedTrackLocationRect = locRect;
-            SetCursorByActivity();
             return true;
          }
       }
@@ -6808,19 +6668,17 @@ bool TrackPanel::HandleLabelTrackMouseEvent(LabelTrack * lTrack, wxRect &r, wxMo
 void TrackPanel::HandleTrackSpecificMouseEvent(wxMouseEvent & event)
 {
    Track * pTrack;
-   wxRect r;
+   wxRect rTrack;
    wxRect rLabel;
 
-   AudacityProject *p = GetProject();
-   bool unsafe = (p->GetAudioIOToken()>0 &&
-                  gAudioIO->IsStreamActive(p->GetAudioIOToken()));
+   bool unsafe = IsUnsafe();
 
    FindTrack(event.m_x, event.m_y, true, true, &rLabel);
-   pTrack = FindTrack(event.m_x, event.m_y, false, false, &r);
+   pTrack = FindTrack(event.m_x, event.m_y, false, false, &rTrack);
 
    //call HandleResize if I'm over the border area
    if (event.LeftDown() &&
-       (within(event.m_y, r.y + r.height, TRACK_RESIZE_REGION)
+          (within(event.m_y, rTrack.y + rTrack.height, TRACK_RESIZE_REGION)
         || within(event.m_y, rLabel.y + rLabel.height,
                   TRACK_RESIZE_REGION))) {
       HandleResize(event);
@@ -6846,7 +6704,7 @@ void TrackPanel::HandleTrackSpecificMouseEvent(wxMouseEvent & event)
    //If so, use MouseDown handler for the label track.
    if (pTrack && (pTrack->GetKind() == Track::Label))
    {
-      if(HandleLabelTrackMouseEvent( (LabelTrack *) pTrack, r, event ))
+      if (HandleLabelTrackMouseEvent((LabelTrack *)pTrack, rTrack, event))
          return;
    }
 
@@ -6863,18 +6721,14 @@ void TrackPanel::HandleTrackSpecificMouseEvent(wxMouseEvent & event)
    }
 #endif
 
+   bool handled = false;
+
    if (pTrack && (pTrack->GetKind() == Track::Wave) &&
-       (mMouseCapture == IsUncaptured || mMouseCapture == IsOverCutLine ||
-        mMouseCapture == WasOverCutLine))
-   {
-      if (HandleTrackLocationMouseEvent( (WaveTrack *) pTrack, r, event ))
-         return;
-   }
+      (mMouseCapture == IsUncaptured || mMouseCapture == WasOverCutLine))
+      handled = HandleTrackLocationMouseEvent((WaveTrack *)pTrack, rTrack, event);
 
    ToolsToolBar * pTtb = mListener->TP_GetToolsToolBar();
-   if( pTtb == NULL )
-      return;
-
+   if( !handled && pTtb != NULL )
    {
       int toolToUse = DetermineToolToUse(pTtb, event);
 
@@ -6986,7 +6840,7 @@ bool TrackPanel::HitTestStretch(Track *track, wxRect &r, wxMouseEvent & event)
    // selected when the cursor is near the center of the track and
    // within the selection
    if (!track || !track->GetSelected() || track->GetKind() != Track::Note ||
-       gAudioIO->IsStreamActive( GetProject()->GetAudioIOToken())) {
+       IsUnsafe()) {
       return false;
    }
    int center = r.y + r.height / 2;
@@ -7015,16 +6869,14 @@ bool TrackPanel::HitTestEnvelope(Track *track, wxRect &r, wxMouseEvent & event)
    if (!envelope)
       return false;
 
-   int displayType = wavetrack->GetDisplay();
+   const int displayType = wavetrack->GetDisplay();
    // Not an envelope hit, unless we're using a type of wavetrack display
    // suitable for envelopes operations, ie one of the Wave displays.
-   const bool dB = (displayType == WaveTrack::WaveformDBDisplay);
-   if (!
-      (dB || (displayType == WaveTrack::WaveformDisplay))
-   )
+   if ( displayType != WaveTrack::Waveform)
       return false;  // No envelope, not a hit, so return.
 
    // Get envelope point, range 0.0 to 1.0
+   const bool dB = !wavetrack->GetWaveformSettings().isLinear();
    // Convert x to time.
    const double envValue = envelope->GetValue(mViewInfo->PositionToTime(event.m_x, r.x));
 
@@ -7034,12 +6886,12 @@ bool TrackPanel::HitTestEnvelope(Track *track, wxRect &r, wxMouseEvent & event)
    // Get y position of envelope point.
    int yValue = GetWaveYPos( envValue,
       zoomMin, zoomMax,
-      r.height, dB, true, mdBr, false ) + r.y;
+      r.height, dB, true, mViewInfo->dBr, false) + r.y;
 
    // Get y position of center line
    int ctr = GetWaveYPos( 0.0,
       zoomMin, zoomMax,
-      r.height, dB, true, mdBr, false ) + r.y;
+      r.height, dB, true, mViewInfo->dBr, false) + r.y;
 
    // Get y distance of mouse from center line (in pixels).
    int yMouse = abs(ctr - event.m_y);
@@ -7082,10 +6934,10 @@ bool TrackPanel::HitTestSamples(Track *track, wxRect &r, wxMouseEvent & event)
    //Get rate in order to calculate the critical zoom threshold
    double rate = wavetrack->GetRate();
 
-   int displayType = wavetrack->GetDisplay();
-   bool dB = (WaveTrack::WaveformDBDisplay == displayType);
-   if (!(WaveTrack::WaveformDisplay == displayType || dB))
+   const int displayType = wavetrack->GetDisplay();
+   if (WaveTrack::Waveform != displayType)
       return false;  // Not a wave, so return.
+   const bool dB = !wavetrack->GetWaveformSettings().isLinear();
 
    const double tt = mViewInfo->PositionToTime(event.m_x, r.x);
    if (!SampleResolutionTest(*mViewInfo, wavetrack, tt, rate))
@@ -7108,7 +6960,7 @@ bool TrackPanel::HitTestSamples(Track *track, wxRect &r, wxMouseEvent & event)
 
    int yValue = GetWaveYPos( oneSample * envValue,
       zoomMin, zoomMax,
-      r.height, dB, true, mdBr, false) + r.y;
+      r.height, dB, true, mViewInfo->dBr, false) + r.y;
 
    // Get y position of mouse (in pixels)
    int yMouse = event.m_y;
@@ -8067,8 +7919,7 @@ void TrackPanel::SeekLeftOrRight
 {
    if (keyup)
    {
-      int token = GetProject()->GetAudioIOToken();
-      if (token > 0 && gAudioIO->IsStreamActive(token))
+      if (IsAudioActive())
       {
          return;
       }
@@ -8089,8 +7940,6 @@ void TrackPanel::SeekLeftOrRight
    if (leftward)
       multiplier = -multiplier;
 
-   int token = GetProject()->GetAudioIOToken();
-
    if (shift && ctrl)
    {
       mLastSelectionAdjustment = curtime;
@@ -8129,7 +7978,7 @@ void TrackPanel::SeekLeftOrRight
       }
       Refresh(false);
    }
-   else if (token > 0 && gAudioIO->IsStreamActive(token)) {
+   else if (IsAudioActive()) {
 #ifdef EXPERIMENTAL_IMPROVED_SEEKING
       if (gAudioIO->GetLastPlaybackTime() < mLastSelectionAdjustment) {
          // Allow time for the last seek to output a buffer before
@@ -8282,8 +8131,7 @@ void TrackPanel::OnBoundaryMove(bool left, bool boundaryContract)
    }
    mLastSelectionAdjustment = curtime;
 
-   int token = GetProject()->GetAudioIOToken();
-   if( token > 0 && gAudioIO->IsStreamActive( token ) )
+   if (IsAudioActive())
    {
       double indicator = gAudioIO->GetStreamTime();
       if (left) {
@@ -8558,16 +8406,11 @@ void TrackPanel::OnTrackMenu(Track *t)
       theMenu->Enable(OnChannelLeftID, !t->GetLinked());
       theMenu->Enable(OnChannelRightID, !t->GetLinked());
 
-      int display = ((WaveTrack *) t)->GetDisplay();
-
-      theMenu->Enable(OnWaveformID, display != WaveTrack::WaveformDisplay);
-      theMenu->Enable(OnWaveformDBID,
-                        display != WaveTrack::WaveformDBDisplay);
-      theMenu->Enable(OnSpectrumID, display != WaveTrack::SpectrumDisplay);
-      theMenu->Enable(OnSpectrumLogID, display != WaveTrack::SpectrumLogDisplay);
-      theMenu->Enable(OnSpectralSelID, display != WaveTrack::SpectralSelectionDisplay);
-      theMenu->Enable(OnSpectralSelLogID, display != WaveTrack::SpectralSelectionLogDisplay);
-      theMenu->Enable(OnPitchID, display != WaveTrack::PitchDisplay);
+      const int display = static_cast<WaveTrack *>(t)->GetDisplay();
+      theMenu->Check(
+         (display == WaveTrack::Waveform) ? OnWaveformID : OnSpectrumID,
+         true
+      );
 
       WaveTrack * track = (WaveTrack *)t;
       SetMenuCheck(*mRateMenu, IdOfRate((int) track->GetRate()));
@@ -8610,6 +8453,55 @@ void TrackPanel::OnTrackMenu(Track *t)
    Refresh(false);
 }
 
+void TrackPanel::OnVRulerMenu(Track *t, wxMouseEvent *pEvent)
+{
+   if (!t) {
+      t = GetFocusedTrack();
+      if (!t)
+         return;
+   }
+
+   if (t->GetKind() != Track::Wave)
+      return;
+
+   WaveTrack *const wt = static_cast<WaveTrack*>(t);
+
+   const int display = wt->GetDisplay();
+   wxMenu *theMenu;
+   if (display == WaveTrack::Waveform) {
+      theMenu = mRulerWaveformMenu;
+      const int id =
+         OnFirstWaveformScaleID + int(wt->GetWaveformSettings().scaleType);
+      theMenu->Check(id, true);
+   }
+   else {
+      theMenu = mRulerSpectrumMenu;
+      const int id =
+         OnFirstSpectrumScaleID + int(wt->GetSpectrogramSettings().scaleType);
+      theMenu->Check(id, true);
+   }
+
+   int x, y;
+   if (pEvent)
+      x = pEvent->m_x, y = pEvent->m_y;
+   else {
+      // If no event given, pop up the menu at the same height
+      // as for the track control menu
+      const wxRect r = FindTrackRect(wt, true);
+      wxRect titleRect;
+      mTrackInfo.GetTitleBarRect(r, titleRect);
+      x = GetVRulerOffset(), y = titleRect.y + titleRect.height + 1;
+   }
+
+   // So that IsDragZooming() returns false, and if we zoom in, we do so
+   // centered where the mouse is now:
+   mZoomStart = mZoomEnd = pEvent->m_y;
+
+   mPopupMenuTarget = wt;
+   PopupMenu(theMenu, x, y);
+   mPopupMenuTarget = NULL;
+}
+
 void TrackPanel::OnTrackMute(bool shiftDown, Track *t)
 {
    if (!t) {
@@ -8659,7 +8551,7 @@ void TrackPanel::OnTrackClose()
    Track *t = GetFocusedTrack();
    if(!t) return;
 
-   if( gAudioIO->IsStreamActive( GetProject()->GetAudioIOToken() ) )
+   if (IsUnsafe())
    {
       mListener->TP_DisplayStatusMessage( _( "Can't delete track with active audio" ) );
       wxBell();
@@ -9029,6 +8921,51 @@ void TrackPanel::OnMergeStereo(wxCommandEvent & WXUNUSED(event))
    Refresh(false);
 }
 
+class ViewSettingsDialog : public PrefsDialog
+{
+public:
+   ViewSettingsDialog
+      (wxWindow *parent, const wxString &title, PrefsDialog::Factories &factories,
+       int page)
+      : PrefsDialog(parent, title, factories)
+      , mPage(page)
+   {
+   }
+
+   virtual long GetPreferredPage()
+   {
+      return mPage;
+   }
+
+   virtual void SavePreferredPage()
+   {
+   }
+
+private:
+   const int mPage;
+};
+
+void TrackPanel::OnViewSettings(wxCommandEvent &)
+{
+   WaveTrack *const wt = static_cast<WaveTrack*>(mPopupMenuTarget);
+   WaveformPrefsFactory waveformFactory(wt);
+   SpectrumPrefsFactory spectrumFactory(wt);
+
+   // Put Waveform page first
+   PrefsDialog::Factories factories;
+   factories.push_back(&waveformFactory);
+   factories.push_back(&spectrumFactory);
+   const int page = (wt->GetDisplay() == WaveTrack::Spectrum)
+      ? 1 : 0;
+
+   wxString title(wt->GetName() + wxT(": "));
+   ViewSettingsDialog dialog(this, title, factories, page);
+
+   if (0 != dialog.ShowModal())
+      // Redraw
+      Refresh(false);
+}
+
 ///  Set the Display mode based on the menu choice in the Track Menu.
 ///  Note that gModes MUST BE IN THE SAME ORDER AS THE MENU CHOICES!!
 ///  const wxChar *gModes[] = { wxT("waveform"), wxT("waveformDB"),
@@ -9036,7 +8973,7 @@ void TrackPanel::OnMergeStereo(wxCommandEvent & WXUNUSED(event))
 void TrackPanel::OnSetDisplay(wxCommandEvent & event)
 {
    int idInt = event.GetId();
-   wxASSERT(idInt >= OnWaveformID && idInt <= OnPitchID);
+   wxASSERT(idInt >= OnWaveformID && idInt <= OnSpectrumID);
    wxASSERT(mPopupMenuTarget
             && mPopupMenuTarget->GetKind() == Track::Wave);
 
@@ -9044,30 +8981,17 @@ void TrackPanel::OnSetDisplay(wxCommandEvent & event)
    switch (idInt) {
    default:
    case OnWaveformID:
-      id = WaveTrack::WaveformDisplay; break;
-   case OnWaveformDBID:
-      id = WaveTrack::WaveformDBDisplay; break;
+      id = WaveTrack::Waveform; break;
    case OnSpectrumID:
-      id = WaveTrack::SpectralSelectionDisplay; break;
-   case OnSpectrumLogID:
-      id = WaveTrack::SpectralSelectionLogDisplay; break;
-   case OnSpectralSelID:
-      id = WaveTrack::SpectralSelectionDisplay; break;
-   case OnSpectralSelLogID:
-      id = WaveTrack::SpectralSelectionLogDisplay; break;
-   case OnPitchID:
-      id = WaveTrack::PitchDisplay; break;
+      id = WaveTrack::Spectrum; break;
    }
    WaveTrack *wt = (WaveTrack *) mPopupMenuTarget;
    if (wt->GetDisplay() != id) {
       wt->SetDisplay(WaveTrack::WaveTrackDisplay(id));
-      mTrackArtist->InvalidateSpectrumCache(wt);
 
-      WaveTrack *l = (WaveTrack *) wt->GetLink();
-      if (l) {
+      WaveTrack *l = static_cast<WaveTrack *>(wt->GetLink());
+      if (l)
          l->SetDisplay(WaveTrack::WaveTrackDisplay(id));
-         mTrackArtist->InvalidateSpectrumCache(l);
-      }
 #ifdef EXPERIMENTAL_OUTPUT_DISPLAY
       if (wt->GetDisplay() == WaveTrack::WaveformDisplay) {
          wt->SetVirtualState(false);
@@ -9076,9 +9000,10 @@ void TrackPanel::OnSetDisplay(wxCommandEvent & event)
       }
 #endif
       UpdateVRuler(wt);
+
+      MakeParentModifyState(true);
+      Refresh(false);
    }
-   MakeParentModifyState(true);
-   Refresh(false);
 }
 
 /// Sets the sample rate for a track, and if it is linked to
@@ -9361,6 +9286,55 @@ void TrackPanel::OnTimeTrackLogInt(wxCommandEvent & /*event*/)
    Refresh(false);
 }
 
+void TrackPanel::OnWaveformScaleType(wxCommandEvent &evt)
+{
+   WaveTrack *const wt = static_cast<WaveTrack *>(mPopupMenuTarget);
+   const WaveformSettings::ScaleType newScaleType =
+      WaveformSettings::ScaleType(
+         std::max(0,
+            std::min(int(WaveformSettings::stNumScaleTypes) - 1,
+               evt.GetId() - OnFirstWaveformScaleID
+      )));
+   if (wt->GetWaveformSettings().scaleType != newScaleType) {
+      wt->GetIndependentWaveformSettings().scaleType = newScaleType;
+      UpdateVRuler(wt); // Is this really needed?
+      MakeParentModifyState(true);
+      Refresh(false);
+   }
+}
+
+void TrackPanel::OnSpectrumScaleType(wxCommandEvent &evt)
+{
+   WaveTrack *const wt = static_cast<WaveTrack *>(mPopupMenuTarget);
+   const SpectrogramSettings::ScaleType newScaleType =
+      SpectrogramSettings::ScaleType(
+         std::max(0,
+            std::min(int(SpectrogramSettings::stNumScaleTypes) - 1,
+               evt.GetId() - OnFirstSpectrumScaleID
+      )));
+   if (wt->GetSpectrogramSettings().scaleType != newScaleType) {
+      wt->GetIndependentSpectrogramSettings().scaleType = newScaleType;
+      UpdateVRuler(wt); // Is this really needed?
+      MakeParentModifyState(true);
+      Refresh(false);
+   }
+}
+
+void TrackPanel::OnZoomInVertical(wxCommandEvent &)
+{
+   HandleWaveTrackVZoom(static_cast<WaveTrack*>(mPopupMenuTarget), false, false);
+}
+
+void TrackPanel::OnZoomOutVertical(wxCommandEvent &)
+{
+   HandleWaveTrackVZoom(static_cast<WaveTrack*>(mPopupMenuTarget), true, false);
+}
+
+void TrackPanel::OnZoomFitVertical(wxCommandEvent &)
+{
+   HandleWaveTrackVZoom(static_cast<WaveTrack*>(mPopupMenuTarget), true, true);
+}
+
 /// Move a track up, down, to top or to bottom.
 
 void TrackPanel::OnMoveTrack(wxCommandEvent &event)
@@ -9759,7 +9733,7 @@ bool TrackPanel::MoveClipToTrack(WaveClip *clip, WaveTrack* dst)
    if (dst->GetKind() != Track::Wave) return false;
 #endif
 
-   for (i = 0; i < mCapturedClipArray.GetCount(); i++) {
+   for (i = 0; i < mCapturedClipArray.size(); i++) {
       if (clip == mCapturedClipArray[i].clip) {
          src = (WaveTrack*)mCapturedClipArray[i].track;
          break;
@@ -9777,7 +9751,7 @@ bool TrackPanel::MoveClipToTrack(WaveClip *clip, WaveTrack* dst)
 
       // find the first track by getting the linked track from src
       // assumes that mCapturedArray[i].clip and .track is not NULL.
-      for (i = 0; i < mCapturedClipArray.GetCount(); i++) {
+      for (i = 0; i < mCapturedClipArray.size(); i++) {
          if (mTracks->GetLink(src) == mCapturedClipArray[i].track) {
             clip = mCapturedClipArray[i].clip;
             break;
@@ -9793,7 +9767,7 @@ bool TrackPanel::MoveClipToTrack(WaveClip *clip, WaveTrack* dst)
    src2 = (WaveTrack*)mTracks->GetLink(src);
    dst2 = (WaveTrack*)mTracks->GetLink(dst);
 
-   for (i = 0; i < mCapturedClipArray.GetCount(); i++) {
+   for (i = 0; i < mCapturedClipArray.size(); i++) {
       if (mCapturedClipArray[i].track == src2) {
          clip2 = mCapturedClipArray[i].clip;
          break;
@@ -9829,7 +9803,7 @@ bool TrackPanel::MoveClipToTrack(WaveClip *clip, WaveTrack* dst)
       src2->MoveClipToTrack(clip2, dst2);
 
    // update the captured clip array.
-   for (i = 0; i < mCapturedClipArray.GetCount(); i++) {
+   for (i = 0; i < mCapturedClipArray.size(); i++) {
       if (clip && mCapturedClipArray[i].clip == clip) {
          mCapturedClipArray[i].track = dst;
       } else if (clip2 && mCapturedClipArray[i].clip == clip2) {
diff --git a/src/TrackPanel.h b/src/TrackPanel.h
index 6dddc2ce00357750e5709f24dbd027863d91d74a..5cc2950b0b076c9efc768493f8f4c07d9ff6ad3f 100644
--- a/src/TrackPanel.h
+++ b/src/TrackPanel.h
@@ -15,18 +15,19 @@
 #include <vector>
 
 #include <wx/dcmemory.h>
-#include <wx/dynarray.h>
 #include <wx/panel.h>
 #include <wx/timer.h>
 #include <wx/window.h>
 
 #include "Experimental.h"
-#include "Sequence.h"  //Stm: included for the sampleCount declaration
-#include "WaveClip.h"
-#include "WaveTrack.h"
+#include "audacity/Types.h"
 #include "UndoManager.h" //JKC: Included for PUSH_XXX definitions.
 #include "widgets/NumericTextCtrl.h"
 
+#include "WaveTrackLocation.h"
+
+#include "Snap.h"
+
 class wxMenu;
 class wxRect;
 
@@ -47,24 +48,16 @@ class TrackPanelAx;
 
 class ViewInfo;
 
-WX_DEFINE_ARRAY(LWSlider *, LWSliderArray);
-
-class AUDACITY_DLL_API TrackClip
-{
- public:
-   TrackClip(Track *t, WaveClip *c) { track = t; clip = c; }
-   Track *track;
-   WaveClip *clip;
-};
-
-WX_DECLARE_OBJARRAY(TrackClip, TrackClipArray);
+class WaveTrack;
+class WaveClip;
+class Envelope;
 
 // Declared elsewhere, to reduce compilation dependencies
 class TrackPanelListener;
 
 // JKC Nov 2011: Disabled warning C4251 which is to do with DLL linkage
 // and only a worry when there are DLLs using the structures.
-// LWSliderArray and TrackClipArray are private in TrackInfo, so we will not
+// Array classes are private in TrackInfo, so we will not
 // access them directly from the DLL.
 // TrackClipArray in TrackPanel needs to be handled with care in the derived
 // class, but the C4251 warning is no worry in core Audacity.
@@ -75,6 +68,8 @@ class TrackPanelListener;
 #pragma warning( disable: 4251 )
 #endif
 
+DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_TRACK_PANEL_TIMER, -1);
+
 class AUDACITY_DLL_API TrackInfo
 {
 public:
@@ -210,6 +205,7 @@ class AUDACITY_DLL_API TrackPanel:public wxPanel {
    virtual void OnTrackGainDec();
    virtual void OnTrackGainInc();
    virtual void OnTrackMenu(Track *t = NULL);
+   virtual void OnVRulerMenu(Track *t, wxMouseEvent *pEvent = NULL);
    virtual void OnTrackMute(bool shiftdown, Track *t = NULL);
    virtual void OnTrackSolo(bool shiftdown, Track *t = NULL);
    virtual void OnTrackClose();
@@ -244,9 +240,12 @@ class AUDACITY_DLL_API TrackPanel:public wxPanel {
     * @param menu the menu to add the commands to.
     */
    virtual void BuildCommonDropMenuItems(wxMenu * menu);
+   static void BuildVRulerMenuItems(wxMenu * menu, int firstId, const wxArrayString &names);
+   virtual bool IsAudioActive();
    virtual bool IsUnsafe();
    virtual bool HandleLabelTrackMouseEvent(LabelTrack * lTrack, wxRect &r, wxMouseEvent & event);
-   virtual bool HandleTrackLocationMouseEvent(WaveTrack * track, wxRect &r, wxMouseEvent &event);
+   virtual bool HandleTrackLocationMouseEvent(WaveTrack * track, wxRect &rect, wxMouseEvent &event);
+   virtual bool IsOverCutline(WaveTrack * track, wxRect &rect, wxMouseEvent &event);
    virtual void HandleTrackSpecificMouseEvent(wxMouseEvent & event);
    virtual void DrawIndicator();
    /// draws the green line on the tracks to show playback position
@@ -337,9 +336,9 @@ protected:
 
 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
 public:
-   void SnapCenterOnce (WaveTrack *pTrack, bool up);
+   void SnapCenterOnce (const WaveTrack *pTrack, bool up);
 protected:
-   void StartSnappingFreqSelection (WaveTrack *pTrack);
+   void StartSnappingFreqSelection (const WaveTrack *pTrack);
    void MoveSnappingFreqSelection (int mouseYCoordinate,
                                    int trackTopEdge,
                                    int trackHeight, Track *pTrack);
@@ -359,14 +358,15 @@ protected:
 
    // AS: Cursor handling
    virtual bool SetCursorByActivity( );
-   virtual void SetCursorAndTipWhenInLabel( Track * t, wxMouseEvent &event, const wxChar ** ppTip );
-   virtual void SetCursorAndTipWhenInVResizeArea( Track * label, bool blinked, const wxChar ** ppTip );
-   virtual void SetCursorAndTipWhenInLabelTrack( LabelTrack * pLT, wxMouseEvent & event, const wxChar ** ppTip );
+   virtual bool SetCursorForCutline(WaveTrack * track, wxRect &rect, wxMouseEvent &event);
+   virtual void SetCursorAndTipWhenInLabel( Track * t, wxMouseEvent &event, wxString &tip );
+   virtual void SetCursorAndTipWhenInVResizeArea( bool blinked, wxString &tip );
+   virtual void SetCursorAndTipWhenInLabelTrack( LabelTrack * pLT, wxMouseEvent & event, wxString &tip );
    virtual void SetCursorAndTipWhenSelectTool
-      ( Track * t, wxMouseEvent & event, wxRect &r, bool bMultiToolMode, const wxChar ** ppTip, const wxCursor ** ppCursor );
-   virtual void SetCursorAndTipByTool( int tool, wxMouseEvent & event, const wxChar **ppTip );
+      ( Track * t, wxMouseEvent & event, wxRect &r, bool bMultiToolMode, wxString &tip, const wxCursor ** ppCursor );
+   virtual void SetCursorAndTipByTool( int tool, wxMouseEvent & event, wxString &tip );
    virtual void HandleCursor(wxMouseEvent & event);
-   virtual void MaySetOnDemandTip( Track * t, const wxChar ** ppTip );
+   virtual void MaySetOnDemandTip( Track * t, wxString &tip );
 
    // AS: Envelope editing handlers
    virtual void HandleEnvelope(wxMouseEvent & event);
@@ -395,6 +395,7 @@ protected:
    virtual void HandleVZoomClick(wxMouseEvent & event);
    virtual void HandleVZoomDrag(wxMouseEvent & event);
    virtual void HandleVZoomButtonUp(wxMouseEvent & event);
+   virtual void HandleWaveTrackVZoom(WaveTrack *track, bool shiftDown, bool rightUp);
 
    // Handle sample editing using the 'draw' tool.
    virtual bool IsSampleEditingPossible( wxMouseEvent & event, Track * t );
@@ -459,12 +460,20 @@ protected:
    virtual void MoveTrack(Track* target, int eventId);
    virtual void OnChangeOctave (wxCommandEvent &event);
    virtual void OnChannelChange(wxCommandEvent &event);
+   virtual void OnViewSettings(wxCommandEvent &event);
    virtual void OnSetDisplay   (wxCommandEvent &event);
    virtual void OnSetTimeTrackRange (wxCommandEvent &event);
    virtual void OnTimeTrackLin(wxCommandEvent &event);
    virtual void OnTimeTrackLog(wxCommandEvent &event);
    virtual void OnTimeTrackLogInt(wxCommandEvent &event);
 
+   virtual void OnWaveformScaleType(wxCommandEvent &event);
+   virtual void OnSpectrumScaleType(wxCommandEvent &event);
+
+   virtual void OnZoomInVertical(wxCommandEvent &event);
+   virtual void OnZoomOutVertical(wxCommandEvent &event);
+   virtual void OnZoomFitVertical(wxCommandEvent &event);
+
    virtual void SetMenuCheck( wxMenu & menu, int newId );
    virtual void SetRate(Track *pTrack, double rate);
    virtual void OnRateChange(wxCommandEvent &event);
@@ -494,9 +503,9 @@ protected:
    virtual wxRect FindTrackRect(Track * target, bool label);
 
    virtual int GetVRulerWidth() const;
-   virtual int GetVRulerOffset() const { return mTrackInfo.GetTrackInfoWidth(); };
+   virtual int GetVRulerOffset() const { return mTrackInfo.GetTrackInfoWidth(); }
 
-   virtual int GetLabelWidth() const { return mTrackInfo.GetTrackInfoWidth() + GetVRulerWidth(); };
+   virtual int GetLabelWidth() const { return mTrackInfo.GetTrackInfoWidth() + GetVRulerWidth(); }
 
 // JKC Nov-2011: These four functions only used from within a dll such as mod-track-panel
 // They work around some messy problems with constructors.
@@ -572,8 +581,8 @@ protected:
 
    // This stores the parts of the screen that get overwritten by the indicator
    // and cursor
-   double mLastIndicator;
-   double mLastCursor;
+   int mLastIndicatorX;
+   int mLastCursorX;
 
    // Quick-Play indicator postion
    double mOldQPIndicatorPos;
@@ -632,7 +641,7 @@ protected:
    WaveClip *mCapturedClip;
    TrackClipArray mCapturedClipArray;
    bool mCapturedClipIsSelection;
-   WaveTrack::Location mCapturedTrackLocation;
+   WaveTrackLocation mCapturedTrackLocation;
    wxRect mCapturedTrackLocationRect;
    wxRect mCapturedRect;
 
@@ -688,22 +697,20 @@ protected:
 
 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
    void HandleCenterFrequencyCursor
-      (bool shiftDown, const wxChar ** ppTip, const wxCursor ** ppCursor);
+      (bool shiftDown, wxString &tip, const wxCursor ** ppCursor);
 
    void HandleCenterFrequencyClick
       (bool shiftDown, Track *pTrack, double value);
 
-   double PositionToFrequency(bool maySnap,
+   double PositionToFrequency(const WaveTrack *wt,
+                              bool maySnap,
                               wxInt64 mouseYCoordinate,
                               wxInt64 trackTopEdge,
-                              int trackHeight,
-                              double rate,
-                              bool logF) const;
-   wxInt64 FrequencyToPosition(double frequency,
+                              int trackHeight) const;
+   wxInt64 FrequencyToPosition(const WaveTrack *wt,
+                               double frequency,
                                wxInt64 trackTopEdge,
-                               int trackHeight,
-                               double rate,
-                               bool logF) const;
+                               int trackHeight) const;
 #endif
 
    enum SelectionBoundary {
@@ -749,7 +756,6 @@ protected:
       IsGainSliding,
       IsPanSliding,
       IsMinimizing,
-      IsOverCutLine,
       WasOverCutLine,
       IsPopping,
 #ifdef USE_MIDI
@@ -766,7 +772,6 @@ protected:
    bool mAdjustSelectionEdges;
    bool mSlideUpDownOnly;
    bool mCircularTrackNavigation;
-   float mdBr;
 
    // JH: if the user is dragging a track, at what y
    //   coordinate should the dragging track move up or down?
@@ -826,6 +831,9 @@ protected:
    wxMenu *mFormatMenu;
    wxMenu *mLabelTrackInfoMenu;
 
+   wxMenu *mRulerWaveformMenu;
+   wxMenu *mRulerSpectrumMenu;
+
    Track *mPopupMenuTarget;
 
    friend class TrackPanelAx;
diff --git a/src/TrackPanelAx.cpp b/src/TrackPanelAx.cpp
index f87bbb5912c9d8d7a9324cd64184aecbb87ed7d7..1ef9a29f7b38157f0fce59d85d5e2037cf0b0075 100644
--- a/src/TrackPanelAx.cpp
+++ b/src/TrackPanelAx.cpp
@@ -14,6 +14,9 @@
 
 *//*******************************************************************/
 
+#include "Audacity.h"
+#include "TrackPanelAx.h"
+
 // For compilers that support precompilation, includes "wx/wx.h".
 #include <wx/wxprec.h>
 
@@ -23,11 +26,10 @@
 #endif
 
 
-#include "Audacity.h"
-#include "TrackPanelAx.h"
-
 #include <wx/intl.h>
 
+#include "Track.h"
+
 TrackPanelAx::TrackPanelAx( wxWindow *window )
 #if wxUSE_ACCESSIBILITY
    :wxWindowAccessible( window )
diff --git a/src/UndoManager.cpp b/src/UndoManager.cpp
index 0c9ecfd9c89d5eda3ecbde30db127804b2a2cf4e..ba8ecbef92adf63648427001f82a380d35de59a3 100644
--- a/src/UndoManager.cpp
+++ b/src/UndoManager.cpp
@@ -28,7 +28,6 @@ UndoManager
 #include "Diags.h"
 #include "Internat.h"
 #include "Sequence.h"
-#include "Track.h"
 #include "WaveTrack.h"          // temp
 #include "NoteTrack.h"  // for Sonify* function declarations
 #include "Diags.h"
diff --git a/src/ViewInfo.cpp b/src/ViewInfo.cpp
index f0f439a4287f6094c51c765ef08fa26f7c7a9a22..7746b297b59f65ccffa9127e0a52003215273c7e 100644
--- a/src/ViewInfo.cpp
+++ b/src/ViewInfo.cpp
@@ -13,6 +13,8 @@ Paul Licameli
 #include <algorithm>
 
 #include "Internat.h"
+#include "prefs/GUISettings.h"
+#include "Prefs.h"
 #include "xml/XMLWriter.h"
 
 namespace {
@@ -26,12 +28,18 @@ ZoomInfo::ZoomInfo(double start, double screenDuration, double pixelsPerSecond)
    , screen(screenDuration)
    , zoom(pixelsPerSecond)
 {
+   UpdatePrefs();
 }
 
 ZoomInfo::~ZoomInfo()
 {
 }
 
+void ZoomInfo::UpdatePrefs()
+{
+   dBr = gPrefs->Read(ENV_DB_KEY, ENV_DB_RANGE);
+}
+
 /// Converts a position (mouse X coordinate) to
 /// project time, in seconds.  Needs the left edge of
 /// the track as an additional parameter.
diff --git a/src/ViewInfo.h b/src/ViewInfo.h
index 23f3445ab108b03294257d00a18af64753369629..836ef04f9a1f76f0a58e541fd63f355bda034639 100644
--- a/src/ViewInfo.h
+++ b/src/ViewInfo.h
@@ -17,6 +17,11 @@
 
 class Track;
 
+#ifdef __GNUC__
+#define CONST
+#else
+#define CONST const
+#endif
 
 // The subset of ViewInfo information (other than selection)
 // that is sufficient for purposes of TrackArtist,
@@ -27,6 +32,8 @@ public:
    ZoomInfo(double start, double duration, double pixelsPerSecond);
    ~ZoomInfo();
 
+   void UpdatePrefs();
+
    int vpos;                    // vertical scroll pos
 
    double h;                    // h pos in secs
@@ -37,6 +44,7 @@ protected:
    double zoom;                 // pixels per second
 
 public:
+   float dBr;                   // decibel scale range
 
    // do NOT use this once to convert a pixel width to a duration!
    // Instead, call twice to convert start and end times,
@@ -85,7 +93,7 @@ public:
    void ZoomBy(double multiplier);
 
    struct Interval {
-      /* const */ wxInt64 position; /* const */ double averageZoom; /* const */ bool inFisheye;
+      CONST wxInt64 position; CONST double averageZoom; CONST bool inFisheye;
       Interval(wxInt64 p, double z, bool i)
          : position(p), averageZoom(z), inFisheye(i) {}
    };
diff --git a/src/VoiceKey.cpp b/src/VoiceKey.cpp
index e138d013a97752922b6e93e11b4c6c61cfc5eac3..d22cb9768558768970e3821f2b2e70627e9acb09 100644
--- a/src/VoiceKey.cpp
+++ b/src/VoiceKey.cpp
@@ -32,6 +32,8 @@ or "OFF" point
 #include <wx/intl.h>
 #include <iostream>
 
+#include "WaveTrack.h"
+
 using std::cout;
 using std::endl;
 
diff --git a/src/VoiceKey.h b/src/VoiceKey.h
index 3cdb859398c474c403ea55bd1e1d23e72f2bafa4..926548ed9791971e135380e301415ea064e07ea5 100644
--- a/src/VoiceKey.h
+++ b/src/VoiceKey.h
@@ -11,13 +11,15 @@
 #ifndef __AUDACITY_VOICEKEY__
 #define __AUDACITY_VOICEKEY__
 
-#include "WaveTrack.h"
-
 
 #ifndef M_PI
 #define	M_PI		3.14159265358979323846  /* pi */
 #endif
 
+#include "audacity/Types.h"
+
+class WaveTrack;
+
 enum VoiceKeyTypes
   {
     VKT_NONE = 0,
@@ -91,10 +93,10 @@ class VoiceKey {
 };
 
 
-inline int sgn(int  number){ return (number<0) ? -1: 1;};
+inline int sgn(int  number){ return (number<0) ? -1: 1;}
 
 //This returns a logistic density based on a z-score
 // a logistic distn has variance (pi*s)^2/3
 
-//inline float inline float logistic(float z){   return fexp(-1 * z/(pi / sqrt(3)) / (1 + pow(fexp(-1 * z(pi / sqrt(3))),2)));};
+//inline float inline float logistic(float z){   return fexp(-1 * z/(pi / sqrt(3)) / (1 + pow(fexp(-1 * z(pi / sqrt(3))),2)));}
 #endif
diff --git a/src/WaveClip.cpp b/src/WaveClip.cpp
index 762683782058bc4bd07610ba0120df6ed4d256a4..572bf676c50dbb194d785a206e12fc65a273963c 100644
--- a/src/WaveClip.cpp
+++ b/src/WaveClip.cpp
@@ -27,13 +27,15 @@
 #include <vector>
 #include <wx/log.h>
 
+#include "Sequence.h"
 #include "Spectrum.h"
 #include "Prefs.h"
 #include "Envelope.h"
 #include "Resample.h"
 #include "Project.h"
+#include "WaveTrack.h"
 
-#include "prefs/SpectrumPrefs.h"
+#include "prefs/SpectrogramSettings.h"
 
 #include <wx/listimpl.cpp>
 WX_DEFINE_LIST(WaveClipList);
@@ -367,6 +369,11 @@ bool WaveClip::SetSamples(samplePtr buffer, sampleFormat format,
    return bResult;
 }
 
+BlockArray* WaveClip::GetSequenceBlockArray()
+{
+   return mSequence->GetBlockArray();
+}
+
 double WaveClip::GetStartTime() const
 {
    // JS: mOffset is the minimum value and it is returned; no clipping to 0
@@ -394,6 +401,11 @@ sampleCount WaveClip::GetEndSample() const
    return GetStartSample() + mSequence->GetNumSamples();
 }
 
+sampleCount WaveClip::GetNumSamples() const
+{
+   return mSequence->GetNumSamples();
+}
+
 bool WaveClip::WithinClip(double t) const
 {
    sampleCount ts = (sampleCount)floor(t * mRate + 0.5);
@@ -846,7 +858,8 @@ void SpecCache::CalculateOneSpectrum
          rate, results,
          autocorrelation, settings.windowType);
 #endif // EXPERIMENTAL_USE_REALFFTF
-      if (!gainFactors.empty()) {
+      if (!autocorrelation &&
+          !gainFactors.empty()) {
          // Apply a frequency-dependant gain factor
          for (int ii = 0; ii < half; ++ii)
             results[ii] += gainFactors[ii];
@@ -902,8 +915,8 @@ bool WaveClip::GetSpectrogram(WaveTrackCache &waveTrackCache,
                               double t0, double pixelsPerSecond,
                               bool autocorrelation)
 {
-   const SpectrogramSettings &settings = SpectrogramSettings::defaults();
-
+   const WaveTrack *const track = waveTrackCache.GetTrack();
+   const SpectrogramSettings &settings = track->GetSpectrogramSettings();
    const int &frequencyGain = settings.frequencyGain;
    const int &windowSize = settings.windowSize;
    const int &windowType = settings.windowType;
diff --git a/src/WaveClip.h b/src/WaveClip.h
index 07bd5230bdaf123ae0a43501296e9797e4d69b63..0beddc6ddc74757590c851772d6cc51bd4274f73 100644
--- a/src/WaveClip.h
+++ b/src/WaveClip.h
@@ -14,7 +14,6 @@
 
 #include "Audacity.h"
 #include "SampleFormat.h"
-#include "Sequence.h"
 #include "widgets/ProgressDialog.h"
 #include "ondemand/ODTaskThread.h"
 #include "xml/XMLTagHandler.h"
@@ -31,7 +30,10 @@
 
 #include <vector>
 
+class BlockArray;
+class DirManager;
 class Envelope;
+class Sequence;
 class SpectrogramSettings;
 class WaveCache;
 class WaveTrackCache;
@@ -127,6 +129,7 @@ public:
       len = cacheLen;
       values = new float[len];
       valid = false;
+      scaleType = 0;
       range = gain = -1;
       minFreq = maxFreq = -1;
    }
@@ -140,6 +143,7 @@ public:
    float       *values;
    bool         valid;
 
+   int scaleType;
    int range;
    int gain;
    int minFreq;
@@ -247,7 +251,7 @@ public:
    double GetEndTime() const;
    sampleCount GetStartSample() const;
    sampleCount GetEndSample() const;
-   sampleCount GetNumSamples() const { return mSequence->GetNumSamples(); }
+   sampleCount GetNumSamples() const;
 
    // One and only one of the following is true for a given t (unless the clip
    // has zero length -- then BeforeClip() and AfterClip() can both be true).
@@ -262,7 +266,7 @@ public:
                    sampleCount start, sampleCount len);
 
    Envelope* GetEnvelope() { return mEnvelope; }
-   BlockArray* GetSequenceBlockArray() { return mSequence->GetBlockArray(); }
+   BlockArray* GetSequenceBlockArray();
 
    // Get low-level access to the sequence. Whenever possible, don't use this,
    // but use more high-level functions inside WaveClip (or add them if you
diff --git a/src/WaveTrack.cpp b/src/WaveTrack.cpp
index 02f2c183fa22053fb270bf5617c99f97191de1b6..394ed1c5e9a9783c1bfff0966acd16e239c7fcbd 100644
--- a/src/WaveTrack.cpp
+++ b/src/WaveTrack.cpp
@@ -39,8 +39,6 @@ Track classes.
 
 #include "float_cast.h"
 
-#include "LabelTrack.h"
-
 #include "Envelope.h"
 #include "Sequence.h"
 #include "Spectrum.h"
@@ -54,6 +52,8 @@ Track classes.
 #include "ondemand/ODManager.h"
 
 #include "effects/TimeWarper.h"
+#include "prefs/SpectrumPrefs.h"
+#include "prefs/WaveformPrefs.h"
 
 using std::max;
 
@@ -72,8 +72,10 @@ WaveTrack *TrackFactory::NewWaveTrack(sampleFormat format, double rate)
    return new WaveTrack(mDirManager, format, rate);
 }
 
-WaveTrack::WaveTrack(DirManager *projDirManager, sampleFormat format, double rate):
+WaveTrack::WaveTrack(DirManager *projDirManager, sampleFormat format, double rate) :
    Track(projDirManager)
+   , mpSpectrumSettings(0)
+   , mpWaveformSettings(0)
 {
    if (format == (sampleFormat)0)
    {
@@ -99,15 +101,20 @@ WaveTrack::WaveTrack(DirManager *projDirManager, sampleFormat format, double rat
    mDisplayNumLocations = 0;
    mDisplayLocations = NULL;
    mDisplayNumLocationsAllocated = 0;
-   mLastDisplay = -1;
+   mLastScaleType = -1;
    mAutoSaveIdent = 0;
 }
 
 WaveTrack::WaveTrack(WaveTrack &orig):
    Track(orig)
+   , mpSpectrumSettings(orig.mpSpectrumSettings
+        ? new SpectrogramSettings(*orig.mpSpectrumSettings) : 0
+     )
+   , mpWaveformSettings(orig.mpWaveformSettings 
+        ? new WaveformSettings(*orig.mpWaveformSettings) : 0)
 {
    mDisplay = FindDefaultViewMode();
-   mLastDisplay = -1;
+   mLastScaleType = -1;
 
    mLegacyProjectFileOffset = 0;
 
@@ -139,9 +146,14 @@ void WaveTrack::Merge(const Track &orig)
 {
    if (orig.GetKind() == Wave)
    {
-      mDisplay = ((WaveTrack &)orig).mDisplay;
-      mGain    = ((WaveTrack &)orig).mGain;
-      mPan     = ((WaveTrack &)orig).mPan;
+      const WaveTrack &wt = static_cast<const WaveTrack&>(orig);
+      mDisplay = wt.mDisplay;
+      mGain    = wt.mGain;
+      mPan     = wt.mPan;
+      SetSpectrogramSettings(wt.mpSpectrumSettings
+         ? new SpectrogramSettings(*wt.mpSpectrumSettings) : 0);
+      SetWaveformSettings
+         (wt.mpWaveformSettings ? new WaveformSettings(*wt.mpWaveformSettings) : 0);
    }
    Track::Merge(orig);
 }
@@ -159,6 +171,8 @@ WaveTrack::~WaveTrack()
    if (mDisplayLocations)
       delete [] mDisplayLocations;
 
+   delete mpSpectrumSettings;
+   delete mpWaveformSettings;
 }
 
 double WaveTrack::GetOffset() const
@@ -195,7 +209,7 @@ WaveTrack::WaveTrackDisplay WaveTrack::FindDefaultViewMode()
    if (viewMode < 0) {
       int oldMode;
       gPrefs->Read(wxT("/GUI/DefaultViewMode"), &oldMode,
-         int(WaveTrack::WaveformDisplay));
+         int(WaveTrack::Waveform));
       viewMode = WaveTrack::ConvertLegacyDisplayValue(oldMode);
    }
 
@@ -222,15 +236,22 @@ WaveTrack::ConvertLegacyDisplayValue(int oldValue)
    switch (oldValue) {
    default:
    case Waveform:
-      newValue = WaveTrack::WaveformDisplay; break;
+   case WaveformDB:
+      newValue = WaveTrack::Waveform; break;
+      /*
    case WaveformDB:
       newValue = WaveTrack::WaveformDBDisplay; break;
+      */
    case Spectrogram:
-      newValue = WaveTrack::SpectrumDisplay; break;
+   case SpectrogramLogF:
+   case Pitch:
+      newValue = WaveTrack::Spectrum; break;
+      /*
    case SpectrogramLogF:
       newValue = WaveTrack::SpectrumLogDisplay; break;
    case Pitch:
       newValue = WaveTrack::PitchDisplay; break;
+      */
    }
    return newValue;
 }
@@ -239,11 +260,26 @@ WaveTrack::ConvertLegacyDisplayValue(int oldValue)
 WaveTrack::WaveTrackDisplay
 WaveTrack::ValidateWaveTrackDisplay(WaveTrackDisplay display)
 {
-   // To do, in future:  detect obsolete values between min and max
-   if (display >= int(MinDisplay) && display <= int(MaxDisplay))
+   switch (display) {
+      // non-obsolete codes
+   case Waveform:
+   case Spectrum:
       return display;
-   else
+
+      // obsolete codes
+   case obsolete1: // was SpectrumLogDisplay
+   case obsolete2: // was SpectralSelectionDisplay
+   case obsolete3: // was SpectralSelectionLogDisplay
+   case obsolete4: // was PitchDisplay
+      return Spectrum;
+
+   case obsolete5: // was WaveformDBDisplay
+      return Waveform;
+
+      // codes out of bounds (from future prefs files?)
+   default:
       return MinDisplay;
+   }
 }
 
 void WaveTrack::GetDisplayBounds(float *min, float *max)
@@ -624,6 +660,69 @@ bool WaveTrack::ClearAndAddCutLine(double t0, double t1)
    return HandleClear(t0, t1, true, false);
 }
 
+const SpectrogramSettings &WaveTrack::GetSpectrogramSettings() const
+{
+   if (mpSpectrumSettings)
+      return *mpSpectrumSettings;
+   else
+      return SpectrogramSettings::defaults();
+}
+
+SpectrogramSettings &WaveTrack::GetSpectrogramSettings()
+{
+   if (mpSpectrumSettings)
+      return *mpSpectrumSettings;
+   else
+      return SpectrogramSettings::defaults();
+}
+
+SpectrogramSettings &WaveTrack::GetIndependentSpectrogramSettings()
+{
+   if (!mpSpectrumSettings)
+      mpSpectrumSettings =
+      new SpectrogramSettings(SpectrogramSettings::defaults());
+   return *mpSpectrumSettings;
+}
+
+void WaveTrack::SetSpectrogramSettings(SpectrogramSettings *pSettings)
+{
+   if (mpSpectrumSettings != pSettings) {
+      delete mpSpectrumSettings;
+      mpSpectrumSettings = pSettings;
+   }
+}
+
+const WaveformSettings &WaveTrack::GetWaveformSettings() const
+{
+   if (mpWaveformSettings)
+      return *mpWaveformSettings;
+   else
+      return WaveformSettings::defaults();
+}
+
+WaveformSettings &WaveTrack::GetWaveformSettings()
+{
+   if (mpWaveformSettings)
+      return *mpWaveformSettings;
+   else
+      return WaveformSettings::defaults();
+}
+
+WaveformSettings &WaveTrack::GetIndependentWaveformSettings()
+{
+   if (!mpWaveformSettings)
+      mpWaveformSettings = new WaveformSettings(WaveformSettings::defaults());
+   return *mpWaveformSettings;
+}
+
+void WaveTrack::SetWaveformSettings(WaveformSettings *pSettings)
+{
+   if (mpWaveformSettings != pSettings) {
+      delete mpWaveformSettings;
+      mpWaveformSettings = pSettings;
+   }
+}
+
 //
 // ClearAndPaste() is a specialized version of HandleClear()
 // followed by Paste() and is used mostly by effects that
@@ -2306,7 +2405,7 @@ void WaveTrack::UpdateLocationsCache()
            it = it->GetNext())
       {
          // Add cut line expander point
-         mDisplayLocations[curpos].typ = locationCutLine;
+         mDisplayLocations[curpos].typ = WaveTrackLocation::locationCutLine;
          mDisplayLocations[curpos].pos =
             clip->GetOffset() + it->GetData()->GetOffset();
          curpos++;
@@ -2320,7 +2419,7 @@ void WaveTrack::UpdateLocationsCache()
                                           < WAVETRACK_MERGE_POINT_TOLERANCE)
          {
             // Add merge point
-            mDisplayLocations[curpos].typ = locationMergePoint;
+            mDisplayLocations[curpos].typ = WaveTrackLocation::locationMergePoint;
             mDisplayLocations[curpos].pos = clips.Item(i-1)->GetEndTime();
             mDisplayLocations[curpos].clipidx1 = mClips.IndexOf(previousClip);
             mDisplayLocations[curpos].clipidx2 = mClips.IndexOf(clip);
diff --git a/src/WaveTrack.h b/src/WaveTrack.h
index 065f649483b3e80c99bd8c791b19f3becae3b8f5..61c063e36a8bf5be7daf31275a803151b357e8be 100644
--- a/src/WaveTrack.h
+++ b/src/WaveTrack.h
@@ -13,7 +13,6 @@
 
 #include "Track.h"
 #include "SampleFormat.h"
-#include "Sequence.h"
 #include "WaveClip.h"
 #include "Experimental.h"
 #include "widgets/ProgressDialog.h"
@@ -22,6 +21,10 @@
 #include <wx/longlong.h>
 #include <wx/thread.h>
 
+#include "WaveTrackLocation.h"
+
+class SpectrogramSettings;
+class WaveformSettings;
 class TimeWarper;
 
 //
@@ -51,7 +54,7 @@ WX_DEFINE_ARRAY( Region*, Regions );
 
 class Envelope;
 
-class AUDACITY_DLL_API WaveTrack: public Track {
+class AUDACITY_DLL_API WaveTrack : public Track {
 
  private:
 
@@ -77,22 +80,8 @@ class AUDACITY_DLL_API WaveTrack: public Track {
 #ifdef EXPERIMENTAL_OUTPUT_DISPLAY
    static bool mMonoAsVirtualStereo;
 #endif
-   enum LocationType {
-      locationCutLine = 1,
-      locationMergePoint
-   };
 
-   struct Location {
-      // Position of track location
-      double pos;
-
-      // Type of track location
-      LocationType typ;
-
-      // Only for typ==locationMergePoint
-      int clipidx1; // first clip (left one)
-      int clipidx2; // second clip (right one)
-   };
+   typedef WaveTrackLocation Location;
 
    virtual ~WaveTrack();
    virtual double GetOffset() const;
@@ -145,6 +134,16 @@ class AUDACITY_DLL_API WaveTrack: public Track {
    sampleFormat GetSampleFormat() { return mFormat; }
    bool ConvertToSampleFormat(sampleFormat format);
 
+   const SpectrogramSettings &GetSpectrogramSettings() const;
+   SpectrogramSettings &GetSpectrogramSettings();
+   SpectrogramSettings &GetIndependentSpectrogramSettings();
+   void SetSpectrogramSettings(SpectrogramSettings *pSettings);
+
+   const WaveformSettings &GetWaveformSettings() const;
+   WaveformSettings &GetWaveformSettings();
+   WaveformSettings &GetIndependentWaveformSettings();
+   void SetWaveformSettings(WaveformSettings *pSettings);
+
    //
    // High-level editing
    //
@@ -172,9 +171,6 @@ class AUDACITY_DLL_API WaveTrack: public Track {
    virtual bool Join       (double t0, double t1);
    virtual bool Disjoin    (double t0, double t1);
 
-   typedef bool ( WaveTrack::* EditFunction )( double, double );
-   typedef bool ( WaveTrack::* EditDestFunction )( double, double, Track** );
-
    virtual bool Trim (double t0, double t1);
 
    bool HandleClear(double t0, double t1, bool addCutLines, bool split);
@@ -408,19 +404,21 @@ class AUDACITY_DLL_API WaveTrack: public Track {
 
       // DO NOT REORDER OLD VALUES!  Replace obsoletes with placeholders.
 
-      WaveformDisplay = 0,
-      MinDisplay = WaveformDisplay,
+      Waveform = 0,
+      MinDisplay = Waveform,
+
+      obsolete5, // was WaveformDBDisplay
+
+      Spectrum,
 
-      WaveformDBDisplay,
-      SpectrumDisplay,
-      SpectrumLogDisplay,
-      SpectralSelectionDisplay,
-      SpectralSelectionLogDisplay,
-      PitchDisplay,
+      obsolete1, // was SpectrumLogDisplay
+      obsolete2, // was SpectralSelectionDisplay
+      obsolete3, // was SpectralSelectionLogDisplay
+      obsolete4, // was PitchDisplay
 
       // Add values here, and update MaxDisplay.
 
-      MaxDisplay = PitchDisplay,
+      MaxDisplay = Spectrum,
 
       NoDisplay,            // Preview track has no display
    };
@@ -434,18 +432,15 @@ class AUDACITY_DLL_API WaveTrack: public Track {
    // Handle restriction of range of values of the enum from future versions
    static WaveTrackDisplay ValidateWaveTrackDisplay(WaveTrackDisplay display);
 
-   void SetDisplay(WaveTrackDisplay display) {
-      if(mDisplay < 2)
-         // remember last display mode for wave and wavedb so they can remap the vertical ruler
-         mLastDisplay = mDisplay;
-      mDisplay = display;
-      if( mDisplay == SpectralSelectionDisplay ){
-      }
-      if( mDisplay == SpectralSelectionLogDisplay ){
-      }
+   int GetLastScaleType() { return mLastScaleType; }
+   void SetLastScaleType(int scaleType)
+   {
+      // remember last display mode for wave and wavedb so vertical ruler can remap
+      mLastScaleType = scaleType;
    }
+
    WaveTrackDisplay GetDisplay() const { return mDisplay; }
-   int GetLastDisplay() {return mLastDisplay;}
+   void SetDisplay(WaveTrackDisplay display) { mDisplay = display; }
 
    void GetDisplayBounds(float *min, float *max);
    void SetDisplayBounds(float min, float max);
@@ -471,7 +466,7 @@ class AUDACITY_DLL_API WaveTrack: public Track {
    float         mDisplayMin;
    float         mDisplayMax;
    WaveTrackDisplay mDisplay;
-   int           mLastDisplay; // last display mode
+   int           mLastScaleType; // last scale type choice
    int           mDisplayNumLocations;
    int           mDisplayNumLocationsAllocated;
    Location*       mDisplayLocations;
@@ -490,6 +485,9 @@ class AUDACITY_DLL_API WaveTrack: public Track {
    wxCriticalSection mAppendCriticalSection;
    double mLegacyProjectFileOffset;
    int mAutoSaveIdent;
+
+   SpectrogramSettings *mpSpectrumSettings;
+   WaveformSettings *mpWaveformSettings;
 };
 
 // This is meant to be a short-lived object, during whose lifetime,
diff --git a/src/WaveTrackLocation.h b/src/WaveTrackLocation.h
new file mode 100644
index 0000000000000000000000000000000000000000..ddb9b2477f97be71dba037323eee43e40dd574e1
--- /dev/null
+++ b/src/WaveTrackLocation.h
@@ -0,0 +1,32 @@
+/**********************************************************************
+
+Audacity: A Digital Audio Editor
+
+WaveTrackLocation.h
+
+Paul Licameli -- split from WaveTrack.h
+
+**********************************************************************/
+
+#ifndef __AUDACITY_WAVE_TRACK_LOCATION__
+#define __AUDACITY_WAVE_TRACK_LOCATION__
+
+struct WaveTrackLocation {
+
+   enum LocationType {
+      locationCutLine = 1,
+      locationMergePoint
+   };
+
+   // Position of track location
+   double pos;
+
+   // Type of track location
+   LocationType typ;
+
+   // Only for typ==locationMergePoint
+   int clipidx1; // first clip (left one)
+   int clipidx2; // second clip (right one)
+};
+
+#endif
diff --git a/src/commands/CompareAudioCommand.cpp b/src/commands/CompareAudioCommand.cpp
index 6957116b5109b169c953da898b1498eb068b460b..35833b9d5cf6a1bae2f6aeebbf2ac6eaaeb1d091 100644
--- a/src/commands/CompareAudioCommand.cpp
+++ b/src/commands/CompareAudioCommand.cpp
@@ -20,6 +20,7 @@ threshold of difference in two selected tracks
 #include "CompareAudioCommand.h"
 #include "../Project.h"
 #include "Command.h"
+#include "../WaveTrack.h"
 
 wxString CompareAudioCommandType::BuildName()
 {
diff --git a/src/commands/GetProjectInfoCommand.cpp b/src/commands/GetProjectInfoCommand.cpp
index 46fb010afebe8b45da46c3f56bfc3fdb67358f5c..cc43d26cc20f8f3e6134a55a7d7b2a8dd53a41e8 100644
--- a/src/commands/GetProjectInfoCommand.cpp
+++ b/src/commands/GetProjectInfoCommand.cpp
@@ -20,7 +20,6 @@
 #include "../TrackPanel.h"
 #include "../Project.h"
 #include "../Track.h"
-#include "../WaveTrack.h"
 
 wxString GetProjectInfoCommandType::BuildName()
 {
@@ -149,3 +148,23 @@ void GetProjectInfoCommand::SendTracksInfo(TrackList *projTracks,
    }
    Status(boolValueStr);
 }
+
+bool GetProjectInfoCommand::testSelected(Track * track) const
+{
+   return track->GetSelected();
+}
+
+bool GetProjectInfoCommand::testLinked(Track * track) const
+{
+   return track->GetLinked();
+}
+
+bool GetProjectInfoCommand::testSolo(Track * track) const
+{
+   return track->GetSolo();
+}
+
+bool GetProjectInfoCommand::testMute(Track * track) const
+{
+   return track->GetMute();
+}
diff --git a/src/commands/GetProjectInfoCommand.h b/src/commands/GetProjectInfoCommand.h
index 6f9942c159bb3ebbb094a243ea1dc6b793a3c21c..329f619d28b3a01e77612d50a6eecc6898f61067 100644
--- a/src/commands/GetProjectInfoCommand.h
+++ b/src/commands/GetProjectInfoCommand.h
@@ -18,7 +18,6 @@
 
 #include "Command.h"
 #include "CommandType.h"
-#include "../Track.h"
 
 class GetProjectInfoCommandType : public CommandType
 {
@@ -51,10 +50,10 @@ private:
    void SendTracksInfo(TrackList *projTracks, Getter);
 
 // Functions pointed to for getting track parameters
-   bool testSelected(Track * track) const {return track->GetSelected();}
-   bool testLinked( Track * track) const {return track->GetLinked();}
-   bool testSolo( Track * track) const {return track->GetSolo();}
-   bool testMute( Track * track) const {return track->GetMute();}
+   bool testSelected(Track * track) const;
+   bool testLinked(Track * track) const;
+   bool testSolo(Track * track) const;
+   bool testMute(Track * track) const;
 };
 
 
diff --git a/src/commands/GetTrackInfoCommand.cpp b/src/commands/GetTrackInfoCommand.cpp
index 7c3e9f786fe1d608f1d9e30f1bf6750a4963b8f2..daf44c0c47be9b36d7f4594faf510beea1dfa887 100644
--- a/src/commands/GetTrackInfoCommand.cpp
+++ b/src/commands/GetTrackInfoCommand.cpp
@@ -19,7 +19,6 @@
 #include "GetTrackInfoCommand.h"
 #include "../TrackPanel.h"
 #include "../Project.h"
-#include "../Track.h"
 #include "../WaveTrack.h"
 
 wxString GetTrackInfoCommandType::BuildName()
diff --git a/src/commands/ImportExportCommands.cpp b/src/commands/ImportExportCommands.cpp
index 548af3ebee905a17f7da85a015936e8ffe639be3..4a6b6885a7ad7361c288b18c1d2d1bc305456c40 100644
--- a/src/commands/ImportExportCommands.cpp
+++ b/src/commands/ImportExportCommands.cpp
@@ -15,6 +15,7 @@
 
 #include "ImportExportCommands.h"
 #include "../Project.h"
+#include "../Track.h"
 #include "../export/Export.h"
 
 // Import
diff --git a/src/commands/ScreenshotCommand.cpp b/src/commands/ScreenshotCommand.cpp
index 30dd1e43347d6b5840c8cc16d48d881634017ebc..5410c003fbdd1f6ac9f765cbdb42943712d1f5d8 100644
--- a/src/commands/ScreenshotCommand.cpp
+++ b/src/commands/ScreenshotCommand.cpp
@@ -25,6 +25,7 @@ project window.
 #include <wx/settings.h>
 #include <wx/bitmap.h>
 
+#include "../Track.h"
 #include "../TrackPanel.h"
 #include "../toolbars/ToolManager.h"
 #include "../toolbars/ToolBar.h"
diff --git a/src/commands/SelectCommand.cpp b/src/commands/SelectCommand.cpp
index 087ad6cc40b71dfb6b34028d865ef3a19ddeb0dd..f689135e333df9555741940598f335a341f44152 100644
--- a/src/commands/SelectCommand.cpp
+++ b/src/commands/SelectCommand.cpp
@@ -19,6 +19,7 @@
 #include "SelectCommand.h"
 #include <wx/string.h>
 #include "../Project.h"
+#include "../Track.h"
 
 wxString SelectCommandType::BuildName()
 {
diff --git a/src/commands/SetProjectInfoCommand.cpp b/src/commands/SetProjectInfoCommand.cpp
index d96b60fa4240cdc4e974281e1efc726f0a9e6107..1724cacba279b4752d5074aceb6f49d70bf95754 100644
--- a/src/commands/SetProjectInfoCommand.cpp
+++ b/src/commands/SetProjectInfoCommand.cpp
@@ -19,7 +19,6 @@
 #include "SetProjectInfoCommand.h"
 #include "../Project.h"
 #include "../Track.h"
-#include "../WaveTrack.h"
 
 // The following parameters have a boolean string, indicated by the kSetOfTracksStr
 #define kSetOfTracksStr "TrackSet"
diff --git a/src/effects/Amplify.cpp b/src/effects/Amplify.cpp
index ce9dea8801222b07ea92c57b49c1e684878c4d67..dc2e73d73f3ec2ae83d0d2276ea58d8a9a40f9a2 100644
--- a/src/effects/Amplify.cpp
+++ b/src/effects/Amplify.cpp
@@ -65,7 +65,7 @@ END_EVENT_TABLE()
 EffectAmplify::EffectAmplify()
 {
    mAmp = DEF_Amp;
-   mRatio = pow(10.0, mAmp / 20.0);
+   mRatio = DB_TO_LINEAR(mAmp);
    mRatioClip = 0.0;
    mCanClip = false;
    mPeak = 0.0;
@@ -211,10 +211,11 @@ void EffectAmplify::PopulateOrExchange(ShuttleGui & S)
 
    S.StartVerticalLay(0);
    {
+      int precission = 3; // allow (a generous) 3 decimal  places for Amplification (dB)
       // Amplitude
       S.StartMultiColumn(2, wxCENTER);
       {
-         FloatingPointValidator<double> vldAmp(2, &mAmp);
+         FloatingPointValidator<double> vldAmp(precission, &mAmp, NUM_VAL_ONE_TRAILING_ZERO);
          vldAmp.SetRange(MIN_Amp, MAX_Amp);
          mAmpT = S.Id(ID_Amp).AddTextBox(_("Amplification (dB):"), wxT(""), 12);
          mAmpT->SetValidator(vldAmp);
@@ -233,10 +234,10 @@ void EffectAmplify::PopulateOrExchange(ShuttleGui & S)
       // Peak
       S.StartMultiColumn(2, wxCENTER);
       {
-         int precission = 2;
-         FloatingPointValidator<double> vldNewPeak(precission, &mNewPeak);
-         double minAmp = MIN_Amp + (20.0 * log10(mPeak));
-         double maxAmp = MAX_Amp + (20.0 * log10(mPeak));
+         // One extra decimal place so that rounding is visible to user (see: bug 958)
+         FloatingPointValidator<double> vldNewPeak(precission + 1, &mNewPeak, NUM_VAL_ONE_TRAILING_ZERO);
+         double minAmp = MIN_Amp + LINEAR_TO_DB(mPeak);
+         double maxAmp = MAX_Amp + LINEAR_TO_DB(mPeak);
 
          // min and max need same precision as what we're validating (bug 963)
          minAmp = Internat::CompatibleToDouble(Internat::ToString(minAmp, precission));
@@ -268,17 +269,17 @@ void EffectAmplify::PopulateOrExchange(ShuttleGui & S)
 bool EffectAmplify::TransferDataToWindow()
 {
    // limit range of gain
-   double dBInit = 20.0*log10(mRatio);
+   double dBInit = LINEAR_TO_DB(mRatio);
    double dB = TrapDouble(dBInit, MIN_Amp, MAX_Amp);
    if (dB != dBInit)
-      mRatio = pow(10.0, dB / 20.0);
+      mRatio = DB_TO_LINEAR(dB);
 
-   mAmp = 20.0 * log10(mRatio);
+   mAmp = LINEAR_TO_DB(mRatio);
    mAmpT->GetValidator()->TransferToWindow();
 
    mAmpS->SetValue((int) (mAmp * SCL_Amp + 0.5f));
 
-   mNewPeak = 20.0 * log10(mRatio * mPeak);
+   mNewPeak = LINEAR_TO_DB(mRatio * mPeak);
    mNewPeakT->GetValidator()->TransferToWindow();
 
    mClip->SetValue(mCanClip);
@@ -295,7 +296,7 @@ bool EffectAmplify::TransferDataFromWindow()
       return false;
    }
 
-   mRatio = pow(10.0, TrapDouble(mAmp * SCL_Amp, MIN_Amp * SCL_Amp, MAX_Amp * SCL_Amp) / (20.0 * SCL_Amp));
+   mRatio = DB_TO_LINEAR(TrapDouble(mAmp * SCL_Amp, MIN_Amp * SCL_Amp, MAX_Amp * SCL_Amp) / SCL_Amp);
 
    mCanClip = mClip->GetValue();
 
@@ -322,11 +323,11 @@ void EffectAmplify::OnAmpText(wxCommandEvent & WXUNUSED(evt))
       return;
    }
 
-   mRatio = pow(10.0, TrapDouble(mAmp * SCL_Amp, MIN_Amp * SCL_Amp, MAX_Amp * SCL_Amp) / (20.0 * SCL_Amp));
+   mRatio = DB_TO_LINEAR(TrapDouble(mAmp * SCL_Amp, MIN_Amp * SCL_Amp, MAX_Amp * SCL_Amp) / SCL_Amp);
 
-   mAmpS->SetValue((int) (20.0 * log10(mRatio) * SCL_Amp + 0.5));
+   mAmpS->SetValue((int) (LINEAR_TO_DB(mRatio) * SCL_Amp + 0.5));
 
-   mNewPeak = 20.0 * log10(mRatio * mPeak);
+   mNewPeak = LINEAR_TO_DB(mRatio * mPeak);
    mNewPeakT->GetValidator()->TransferToWindow();
 
    CheckClip();
@@ -343,12 +344,12 @@ void EffectAmplify::OnPeakText(wxCommandEvent & WXUNUSED(evt))
    if (mNewPeak == 0.0)
       mRatio = mRatioClip;
    else
-      mRatio = pow(10.0, mNewPeak / 20.0) / mPeak;
+      mRatio = DB_TO_LINEAR(mNewPeak) / mPeak;
 
-   double ampInit = 20.0 * log10(mRatio);
+   double ampInit = LINEAR_TO_DB(mRatio);
    mAmp = TrapDouble(ampInit, MIN_Amp, MAX_Amp);
    if (mAmp != ampInit)
-      mRatio = pow(10.0, mAmp / 20.0);
+      mRatio = DB_TO_LINEAR(mAmp);
 
    mAmpT->GetValidator()->TransferToWindow();
 
@@ -360,20 +361,20 @@ void EffectAmplify::OnPeakText(wxCommandEvent & WXUNUSED(evt))
 void EffectAmplify::OnAmpSlider(wxCommandEvent & evt)
 {
    double dB = evt.GetInt() / SCL_Amp;
-   mRatio = pow(10.0, TrapDouble(dB, MIN_Amp, MAX_Amp) / 20.0);
+   mRatio = DB_TO_LINEAR(TrapDouble(dB, MIN_Amp, MAX_Amp));
 
    double dB2 = (evt.GetInt() - 1) / SCL_Amp;
-   double ratio2 = pow(10.0, TrapDouble(dB2, MIN_Amp, MAX_Amp) / 20.0);
+   double ratio2 = DB_TO_LINEAR(TrapDouble(dB2, MIN_Amp, MAX_Amp));
 
    if (!mClip->GetValue() && mRatio * mPeak > 1.0 && ratio2 * mPeak < 1.0)
    {
       mRatio = 1.0 / mPeak;
    }
 
-   mAmp = 20.0 * log10(mRatio);
+   mAmp = LINEAR_TO_DB(mRatio);
    mAmpT->GetValidator()->TransferToWindow();
 
-   mNewPeak = 20.0 * log10(mRatio * mPeak);
+   mNewPeak = LINEAR_TO_DB(mRatio * mPeak);
    mNewPeakT->GetValidator()->TransferToWindow();
 
    CheckClip();
diff --git a/src/effects/AutoDuck.cpp b/src/effects/AutoDuck.cpp
index a582c38005f17c503454c97c01518d3ae9eb46d7..5f3db54ffd5235862b60b73e2ad24a1680577154 100644
--- a/src/effects/AutoDuck.cpp
+++ b/src/effects/AutoDuck.cpp
@@ -33,6 +33,8 @@
 #include "../Theme.h"
 #include "../widgets/valnum.h"
 
+#include "../WaveTrack.h"
+
 // Define keys, defaults, minimums, and maximums for the effect parameters
 //
 //     Name                Type     Key                     Def      Min      Max      Scale
@@ -278,7 +280,7 @@ bool EffectAutoDuck::Process()
    sampleCount minSamplesPause =
       mControlTrack->TimeToLongSamples(maxPause);
 
-   double threshold = pow(10.0, mThresholdDb/20);
+   double threshold = DB_TO_LINEAR(mThresholdDb);
 
    // adjust the threshold so we can compare it to the rmsSum value
    threshold = threshold * threshold * kRMSWindowSize;
@@ -553,7 +555,7 @@ bool EffectAutoDuck::ApplyDuckFade(int trackNumber, WaveTrack* t,
          if (gain < mDuckAmountDb)
             gain = mDuckAmountDb;
 
-         buf[i - pos] *= pow(10.0, gain / 20.0);
+         buf[i - pos] *= DB_TO_LINEAR(gain);
       }
 
       t->Set((samplePtr)buf, floatSample, pos, len);
diff --git a/src/effects/AutoDuck.h b/src/effects/AutoDuck.h
index 45a8878d177cd6023b3bc9c7929012302b406ef8..ede5f31bc5211672e67e5141d96b9a1271cb6d57 100644
--- a/src/effects/AutoDuck.h
+++ b/src/effects/AutoDuck.h
@@ -19,8 +19,6 @@
 #include <wx/textctrl.h>
 #include <wx/window.h>
 
-#include "../WaveTrack.h"
-
 #include "Effect.h"
 
 class EffectAutoDuckPanel;
diff --git a/src/effects/BassTreble.cpp b/src/effects/BassTreble.cpp
index 131cc153cbcf2d8e48dd89b593a021644c8a1b58..e524e7f9004321549da9514fc9de2a5bc5bee553 100644
--- a/src/effects/BassTreble.cpp
+++ b/src/effects/BassTreble.cpp
@@ -44,8 +44,8 @@ enum
 // Define keys, defaults, minimums, and maximums for the effect parameters
 //
 //     Name       Type     Key               Def      Min      Max      Scale
-Param( Bass,      double,  XO("Bass"),       0.0,     -15.0,   15.0,    1  );
-Param( Treble,    double,  XO("Treble"),     0.0,     -15.0,   15.0,    1  );
+Param( Bass,      double,  XO("Bass"),       0.0,     -30.0,   30.0,    1  );
+Param( Treble,    double,  XO("Treble"),     0.0,     -30.0,   30.0,    1  );
 Param( Level,     double,  XO("Level"),      -1.0,    -30.0,   0.0,     1  );
 Param( Normalize, bool,    XO("Normalize"),  true,    false,   true,    1  );
 
@@ -155,7 +155,7 @@ sampleCount EffectBassTreble::ProcessBlock(float **inBlock, float **outBlock, sa
    }
    else
    {
-      float gain = (pow(10.0, dB_level / 20.0f)) / mMax;
+      float gain = DB_TO_LINEAR(dB_level) / mMax;
       for (sampleCount i = 0; i < blockLen; i++)
       {
          // Normalize to specified level
diff --git a/src/effects/ChangeSpeed.cpp b/src/effects/ChangeSpeed.cpp
index a7245b876341122d78612d800d60c786a8e58c3f..705df25bd9084690fb55b005105011f9aac34436 100644
--- a/src/effects/ChangeSpeed.cpp
+++ b/src/effects/ChangeSpeed.cpp
@@ -14,12 +14,12 @@
 *//*******************************************************************/
 
 #include "../Audacity.h"
+#include "ChangeSpeed.h"
 
 #include <math.h>
 
 #include <wx/intl.h>
 
-#include "../Envelope.h"
 #include "../LabelTrack.h"
 #include "../Prefs.h"
 #include "../Project.h"
@@ -27,9 +27,8 @@
 #include "../ShuttleGui.h"
 #include "../widgets/valnum.h"
 
-#include "ChangeSpeed.h"
-
 #include "TimeWarper.h"
+#include "../WaveTrack.h"
 
 enum
 {
diff --git a/src/effects/ChangeSpeed.h b/src/effects/ChangeSpeed.h
index 67a6c912b6e3367839a51b1ee4d210a33a9d348c..7df4ef8d4c36bb30e0f06a5f747d3585f169a2ba 100644
--- a/src/effects/ChangeSpeed.h
+++ b/src/effects/ChangeSpeed.h
@@ -19,8 +19,6 @@
 #include <wx/string.h>
 #include <wx/textctrl.h>
 
-#include "../Track.h"
-#include "../WaveTrack.h"
 #include "../widgets/NumericTextCtrl.h"
 
 #include "Effect.h"
diff --git a/src/effects/ClickRemoval.cpp b/src/effects/ClickRemoval.cpp
index 81e616f65cb34790854b4619f58d4991785390cc..73943daef0b663fa3174092354792fd3f164cd9b 100644
--- a/src/effects/ClickRemoval.cpp
+++ b/src/effects/ClickRemoval.cpp
@@ -37,6 +37,8 @@
 #include "../ShuttleGui.h"
 #include "../widgets/valnum.h"
 
+#include "../WaveTrack.h"
+
 enum
 {
    ID_Thresh = 10000,
diff --git a/src/effects/ClickRemoval.h b/src/effects/ClickRemoval.h
index 5723f09d5a4a29c62aaaceec376e2944c31ed337..723fd9e59bd5b079a1d8b0bcb23133de343a87c5 100644
--- a/src/effects/ClickRemoval.h
+++ b/src/effects/ClickRemoval.h
@@ -21,11 +21,9 @@
 #include <wx/string.h>
 #include <wx/textctrl.h>
 
-#include "../Envelope.h"
-#include "../WaveTrack.h"
-
 #include "Effect.h"
 
+class Envelope;
 class ShuttleGui;
 
 #define CLICKREMOVAL_PLUGIN_SYMBOL XO("Click Removal")
diff --git a/src/effects/Compressor.cpp b/src/effects/Compressor.cpp
index 0d8e8752e417832dda4a542c1f90de0b8f9b99a3..ca506eb77a7abed3e51145f6d21dcf46f95b0295 100644
--- a/src/effects/Compressor.cpp
+++ b/src/effects/Compressor.cpp
@@ -41,6 +41,8 @@
 #include "../float_cast.h"
 #include "../widgets/Ruler.h"
 
+#include "../WaveTrack.h"
+
 enum
 {
    ID_Threshold = 10000,
@@ -328,8 +330,8 @@ bool EffectCompressor::TransferDataFromWindow()
 
 bool EffectCompressor::NewTrackPass1()
 {
-   mThreshold = pow(10.0, mThresholdDB/20); // factor of 20 because it's power
-   mNoiseFloor = pow(10.0, mNoiseFloorDB/20);
+   mThreshold = DB_TO_LINEAR(mThresholdDB);
+   mNoiseFloor = DB_TO_LINEAR(mNoiseFloorDB);
    mNoiseCounter = 100;
 
    mAttackInverseFactor = exp(log(mThreshold) / (mCurRate * mAttackTime + 0.5));
diff --git a/src/effects/Contrast.cpp b/src/effects/Contrast.cpp
index 0ca8cb3db7447131bd22b39b49cdd710019df815..d5576531cb6a4ef9d9ac99bf4e758553e189ad52 100644
--- a/src/effects/Contrast.cpp
+++ b/src/effects/Contrast.cpp
@@ -14,7 +14,6 @@
 
 #include "../AudacityApp.h"
 
-#include "../Envelope.h"
 #include "../FFT.h"
 #include "../WaveTrack.h"
 #include "../Prefs.h"
@@ -112,7 +111,7 @@ float ContrastDialog::GetDB()
    {
       if( rms < 1.0E-30 )
          return -60.0;
-      return 20.0*log10(rms);
+      return LINEAR_TO_DB(rms);
    }
    else
    {
diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp
index 22cd355e876517464dd1d354c8ec4d1a3d184f9d..57b3bf830d3caa23a12e0986fc90ea4426a47c21 100644
--- a/src/effects/Effect.cpp
+++ b/src/effects/Effect.cpp
@@ -2060,6 +2060,11 @@ TimeWarper *Effect::GetTimeWarper()
 // Use these two methods to copy the input tracks to mOutputTracks, if
 // doing the processing on them, and replacing the originals only on success (and not cancel).
 // Copy the group tracks that have tracks selected
+void Effect::CopyInputTracks()
+{
+   CopyInputTracks(Track::Wave);
+}
+
 void Effect::CopyInputTracks(int trackType)
 {
    // Reset map
diff --git a/src/effects/Effect.h b/src/effects/Effect.h
index 973e3d33efb6d8c98a8e7c20087349d393fb519c..1cf24f6b1003e612f1d37c0d6e285256d4a22bb5 100644
--- a/src/effects/Effect.h
+++ b/src/effects/Effect.h
@@ -30,7 +30,6 @@ class wxWindow;
 #include "audacity/EffectInterface.h"
 
 #include "../Experimental.h"
-#include "../WaveTrack.h"
 #include "../SelectedRegion.h"
 #include "../Shuttle.h"
 #include "../Internat.h"
@@ -40,9 +39,14 @@ class ShuttleGui;
 
 #define BUILTIN_EFFECT_PREFIX wxT("Built-in Effect: ")
 
+class AudacityProject;
 class SelectedRegion;
 class TimeWarper;
 class EffectUIHost;
+class Track;
+class TrackList;
+class TrackFactory;
+class WaveTrack;
 
 // TODO:  Apr-06-2015
 // TODO:  Much more cleanup of old methods and variables is needed, but
@@ -337,7 +341,8 @@ protected:
 
    // Use these two methods to copy the input tracks to mOutputTracks, if
    // doing the processing on them, and replacing the originals only on success (and not cancel).
-   void CopyInputTracks(int trackType = Track::Wave);
+   void CopyInputTracks(); // trackType = Track::Wave
+   void CopyInputTracks(int trackType);
 
    // If bGoodResult, replace mWaveTracks tracks in mTracks with successfully processed
    // mOutputTracks copies, get rid of old mWaveTracks, and set mWaveTracks to mOutputTracks.
diff --git a/src/effects/Equalization.cpp b/src/effects/Equalization.cpp
index ac81f46eaa2a470f1e8248611c55e2b869c7067f..fab552507d342ecd7259844856e20360a86204c7 100644
--- a/src/effects/Equalization.cpp
+++ b/src/effects/Equalization.cpp
@@ -53,6 +53,7 @@
 
 
 #include "../Audacity.h"
+#include "Equalization.h"
 
 #include <math.h>
 #include <vector>
@@ -95,13 +96,10 @@
 #include "../xml/XMLFileReader.h"
 #include "../Theme.h"
 #include "../AllThemeResources.h"
-#include "../WaveTrack.h"
 #include "../float_cast.h"
 
 #include "FileDialog.h"
 
-#include "Equalization.h"
-
 #ifdef EXPERIMENTAL_EQ_SSE_THREADED
 #include "Equalization48x.h"
 #endif
@@ -1182,13 +1180,13 @@ bool EffectEqualization::CalcFilter()
    }
    mFilterFuncR[mWindowSize/2] = val1;
 
-   mFilterFuncR[0] = (float)(pow(10., mFilterFuncR[0]/20.));
+   mFilterFuncR[0] = DB_TO_LINEAR(mFilterFuncR[0]);
    for(i=1;i<mWindowSize/2;i++)
    {
-      mFilterFuncR[i] = (float)(pow(10., mFilterFuncR[i]/20.));
+      mFilterFuncR[i] = DB_TO_LINEAR(mFilterFuncR[i]);
       mFilterFuncR[mWindowSize-i]=mFilterFuncR[i];   //Fill entire array
    }
-   mFilterFuncR[i] = (float)(pow(10., mFilterFuncR[i]/20.));   //do last one
+   mFilterFuncR[i] = DB_TO_LINEAR(mFilterFuncR[i]);   //do last one
 
    //transfer to time domain to do the padding and windowing
    float *outr = new float[mWindowSize];
@@ -2773,7 +2771,7 @@ void EqualizationPanel::OnPaint(wxPaintEvent &  WXUNUSED(event))
          yF += mOutr[halfM];
          yF = fabs(yF);
          if(yF!=0.)
-            yF = 20.0*log10(yF);   //20 here as an amplitude
+            yF = LINEAR_TO_DB(yF);
          else
             yF = mEffect->mdBMin;
       }
diff --git a/src/effects/Equalization.h b/src/effects/Equalization.h
index b07f58f2814ea23534294c42fa9c5d024ae45ab4..a2ec0a9047ade5746728f324834724a352ffb77e 100644
--- a/src/effects/Equalization.h
+++ b/src/effects/Equalization.h
@@ -35,8 +35,6 @@
 #endif
 
 #include "Effect.h"
-#include "../Envelope.h"
-#include "../WaveTrack.h"
 #include "../xml/XMLTagHandler.h"
 #include "../widgets/Grid.h"
 #include "../widgets/Ruler.h"
@@ -45,6 +43,7 @@
 #define EQUALIZATION_PLUGIN_SYMBOL XO("Equalization")
 
 
+class Envelope;
 class EqualizationPanel;
 
 //
diff --git a/src/effects/FindClipping.cpp b/src/effects/FindClipping.cpp
index 864e499b8aa4c5ace0d67fc41ed57496b7dfd752..bccbbec05c30afdbee80506cae5ae350453137d2 100644
--- a/src/effects/FindClipping.cpp
+++ b/src/effects/FindClipping.cpp
@@ -30,6 +30,9 @@
 #include "../ShuttleGui.h"
 #include "../widgets/valnum.h"
 
+#include "../LabelTrack.h"
+#include "../WaveTrack.h"
+
 // Define keys, defaults, minimums, and maximums for the effect parameters
 //
 //     Name    Type  Key               Def   Min   Max      Scale
diff --git a/src/effects/FindClipping.h b/src/effects/FindClipping.h
index d5e2270457e09fd7c33feff4d7b3278baabdeea4..0505c253c3a87320f1c989a4646aa27c21f095f6 100644
--- a/src/effects/FindClipping.h
+++ b/src/effects/FindClipping.h
@@ -14,10 +14,9 @@
 
 class wxString;
 
-#include <wx/string.h>
+class LabelTrack;
 
-#include "../LabelTrack.h"
-#include "../WaveTrack.h"
+#include <wx/string.h>
 
 #include "Effect.h"
 
diff --git a/src/effects/Generator.cpp b/src/effects/Generator.cpp
index b4b741d998ed11d65a8292d9d6d72fca67ffd326..0c82567b1f9cd710bb0ea0ceb5607b6b4ec66d73 100644
--- a/src/effects/Generator.cpp
+++ b/src/effects/Generator.cpp
@@ -14,10 +14,12 @@
 
 **********************************************************************/
 
+#include "Generator.h"
+
 #include "../Project.h"
 #include "../Prefs.h"
+#include "../WaveTrack.h"
 
-#include "Generator.h"
 #include "TimeWarper.h"
 
 #include <memory>
diff --git a/src/effects/NoiseReduction.cpp b/src/effects/NoiseReduction.cpp
index d02985d0b0f8c3c25a845846f4ff51d6c665cbf4..9081132aff2eb0776371b8b0f533c1dd23a2427e 100644
--- a/src/effects/NoiseReduction.cpp
+++ b/src/effects/NoiseReduction.cpp
@@ -43,6 +43,8 @@
 #include "../ShuttleGui.h"
 #include "../Prefs.h"
 
+#include "../WaveTrack.h"
+
 #include <algorithm>
 #include <vector>
 #include <math.h>
@@ -765,10 +767,10 @@ EffectNoiseReduction::Worker::Worker
    const int nAttackBlocks = 1 + (int)(settings.mAttackTime * sampleRate / mStepSize);
    const int nReleaseBlocks = 1 + (int)(settings.mReleaseTime * sampleRate / mStepSize);
    // Applies to amplitudes, divide by 20:
-   mNoiseAttenFactor = pow(10.0, noiseGain / 20.0);
+   mNoiseAttenFactor = DB_TO_LINEAR(noiseGain);
    // Apply to gain factors which apply to amplitudes, divide by 20:
-   mOneBlockAttack = pow(10.0, (noiseGain / (20.0 * nAttackBlocks)));
-   mOneBlockRelease = pow(10.0, (noiseGain / (20.0 * nReleaseBlocks)));
+   mOneBlockAttack = DB_TO_LINEAR(noiseGain / nAttackBlocks);
+   mOneBlockRelease = DB_TO_LINEAR(noiseGain / nReleaseBlocks);
    // Applies to power, divide by 10:
    mOldSensitivityFactor = pow(10.0, settings.mOldSensitivity / 10.0);
 
diff --git a/src/effects/NoiseRemoval.cpp b/src/effects/NoiseRemoval.cpp
index 0ac3f4bc206ed148fcd43f15fb930bcb1b5afc61..a1f39364c241a2f170bbda5280b814615b5093c3 100644
--- a/src/effects/NoiseRemoval.cpp
+++ b/src/effects/NoiseRemoval.cpp
@@ -275,10 +275,8 @@ void EffectNoiseRemoval::Initialize()
    mFreqSmoothingBins = (int)(mFreqSmoothingHz * mWindowSize / mSampleRate);
    mAttackDecayBlocks = 1 +
       (int)(mAttackDecayTime * mSampleRate / (mWindowSize / 2));
-   // Applies to amplitudes, divide by 20:
-   mNoiseAttenFactor = pow(10.0, mNoiseGain/20.0);
-   // Applies to gain factors which apply to amplitudes, divide by 20:
-   mOneBlockAttackDecay = pow(10.0, (mNoiseGain / (20.0 * mAttackDecayBlocks)));
+   mNoiseAttenFactor = DB_TO_LINEAR(mNoiseGain);
+   mOneBlockAttackDecay = DB_TO_LINEAR(mNoiseGain / mAttackDecayBlocks);
    // Applies to power, divide by 10:
    mSensitivityFactor = pow(10.0, mSensitivity/10.0);
    mMinSignalBlocks =
diff --git a/src/effects/Normalize.cpp b/src/effects/Normalize.cpp
index 7b090d95f400849e3c7b08690af192b7201045b2..fe3d8971d92e769de87535f025d4e06ee216c1cb 100644
--- a/src/effects/Normalize.cpp
+++ b/src/effects/Normalize.cpp
@@ -16,6 +16,7 @@
 
 
 #include "../Audacity.h" // for rint from configwin.h
+#include "Normalize.h"
 
 #include <math.h>
 
@@ -28,8 +29,6 @@
 #include "../WaveTrack.h"
 #include "../widgets/valnum.h"
 
-#include "Normalize.h"
-
 // Define keys, defaults, minimums, and maximums for the effect parameters
 //
 //     Name       Type     Key                        Def      Min      Max   Scale
@@ -152,9 +151,8 @@ bool EffectNormalize::Process()
 
    float ratio;
    if( mGain )
-      ratio = pow(10.0,TrapDouble(mLevel, // same value used for all tracks
-                               MIN_Level,
-                               MAX_Level)/20.0);
+      // same value used for all tracks
+      ratio = DB_TO_LINEAR(TrapDouble(mLevel, MIN_Level, MAX_Level));
    else
       ratio = 1.0;
 
@@ -285,7 +283,7 @@ void EffectNormalize::PopulateOrExchange(ShuttleGui & S)
                                              mGain ? wxT("true") : wxT("false"));
                mGainCheckBox->SetValidator(wxGenericValidator(&mGain));
 
-               FloatingPointValidator<double> vldLevel(1, &mLevel);
+               FloatingPointValidator<double> vldLevel(2, &mLevel, NUM_VAL_ONE_TRAILING_ZERO);
                vldLevel.SetRange(MIN_Level, MAX_Level);
                mLevelTextCtrl = S.AddTextBox(wxT(""), wxT(""), 10);
                mLevelTextCtrl->SetName(_("Maximum amplitude dB"));
diff --git a/src/effects/Normalize.h b/src/effects/Normalize.h
index a5ab075c5b9a2ce5150b363b2196e9b217d065f6..84ac09ac0523af9d8d909776babc93585d3ad454 100644
--- a/src/effects/Normalize.h
+++ b/src/effects/Normalize.h
@@ -18,8 +18,6 @@
 #include <wx/string.h>
 #include <wx/textctrl.h>
 
-#include "../WaveTrack.h"
-
 #include "Effect.h"
 
 class ShuttleGui;
diff --git a/src/effects/Paulstretch.cpp b/src/effects/Paulstretch.cpp
index 5b1c98a40c2ee974f3fb74caf0a2f069d6a645a9..76e21a04201a98c69de75bd365155fedf0e1e736 100644
--- a/src/effects/Paulstretch.cpp
+++ b/src/effects/Paulstretch.cpp
@@ -27,11 +27,13 @@
 #include "../FFT.h"
 #include "../widgets/valnum.h"
 
+#include "../WaveTrack.h"
+
 // Define keys, defaults, minimums, and maximums for the effect parameters
 //
 //     Name    Type     Key                     Def      Min      Max      Scale
 Param( Amount, float,   XO("Stretch Factor"),   10.0,    1.0,     FLT_MAX, 1   );
-Param( Time,   float,   XO("Time Resolution"),  0.25f,   0.001f,  FLT_MAX, 1   );
+Param( Time,   float,   XO("Time Resolution"),  0.25f,   0.00099f,  FLT_MAX, 1   );
 
 class PaulStretch
 {
@@ -170,7 +172,7 @@ void EffectPaulstretch::PopulateOrExchange(ShuttleGui & S)
        */
       S.AddTextBox(_("Stretch Factor:"), wxT(""), 10)->SetValidator(vldAmount);
 
-      FloatingPointValidator<float> vldTime(1, &time_resolution);
+      FloatingPointValidator<float> vldTime(3, &time_resolution, NUM_VAL_ONE_TRAILING_ZERO);
       vldTime.SetMin(MIN_Time);
       S.AddTextBox(_("Time Resolution (seconds):"), wxT(""), 10)->SetValidator(vldTime);
    }
diff --git a/src/effects/Paulstretch.h b/src/effects/Paulstretch.h
index 44dbd69fd245d97c22f5d01fc720ab25a3a58903..0741aeb0411d824dc18b85270e772bc8df892809 100644
--- a/src/effects/Paulstretch.h
+++ b/src/effects/Paulstretch.h
@@ -12,8 +12,6 @@
 
 #include <wx/string.h>
 
-#include "../WaveTrack.h"
-
 #include "Effect.h"
 
 class ShuttleGui;
diff --git a/src/effects/Phaser.cpp b/src/effects/Phaser.cpp
index 260a1dec0d38937bf43b7815b7549f682bd9a429..529353a8224571983eba6b1211be26631b229783 100644
--- a/src/effects/Phaser.cpp
+++ b/src/effects/Phaser.cpp
@@ -45,8 +45,8 @@ enum
 //     Name       Type     Key               Def   Min   Max         Scale
 Param( Stages,    int,     XO("Stages"),     2,    2,    NUM_STAGES, 1  );
 Param( DryWet,    int,     XO("DryWet"),     128,  0,    255,        1  );
-Param( Freq,      double,  XO("Freq"),       0.4,  0.1,  4.0,        10 );
-Param( Phase,     double,  XO("Phase"),      0.0,  0.0,  359.0,      1  );
+Param( Freq,      double,  XO("Freq"),       0.4,  0.001,4.0,        10.0 );
+Param( Phase,     double,  XO("Phase"),      0.0,  0.0,  360.0,      1  );
 Param( Depth,     int,     XO("Depth"),      100,  0,    255,        1  );
 Param( Feedback,  int,     XO("Feedback"),   0,    -100, 100,        1  );
 
@@ -152,7 +152,7 @@ sampleCount EffectPhaser::ProcessBlock(float **inBlock, float **outBlock, sample
    {
       double in = ibuf[i];
 
-      double m = in + fbout * mFeedback / 100;
+      double m = in + fbout * mFeedback / 101;  // Feedback must be less than 100% to avoid infinite gain.
 
       if (((skipcount++) % lfoskipsamples) == 0)
       {
@@ -222,6 +222,7 @@ bool EffectPhaser::SetAutomationParameters(EffectAutomationParameters & parms)
 void EffectPhaser::PopulateOrExchange(ShuttleGui & S)
 {
    S.SetBorder(5);
+   S.AddSpace(0, 5);
 
    S.StartMultiColumn(3, wxEXPAND);
    {
@@ -229,7 +230,7 @@ void EffectPhaser::PopulateOrExchange(ShuttleGui & S)
 
       IntegerValidator<int> vldStages(&mStages);
       vldStages.SetRange(MIN_Stages, MAX_Stages);
-      mStagesT = S.Id(ID_Stages).AddTextBox(_("Stages:"), wxT(""), 12);
+      mStagesT = S.Id(ID_Stages).AddTextBox(_("Stages:"), wxT(""), 15);
       mStagesT->SetValidator(vldStages);
 
       S.SetStyle(wxSL_HORIZONTAL);
@@ -240,7 +241,7 @@ void EffectPhaser::PopulateOrExchange(ShuttleGui & S)
 
       IntegerValidator<int> vldDryWet(&mDryWet);
       vldDryWet.SetRange(MIN_DryWet, MAX_DryWet);
-      mDryWetT = S.Id(ID_DryWet).AddTextBox(_("Dry/Wet:"), wxT(""), 12);
+      mDryWetT = S.Id(ID_DryWet).AddTextBox(_("Dry/Wet:"), wxT(""), 15);
       mDryWetT->SetValidator(vldDryWet);
 
       S.SetStyle(wxSL_HORIZONTAL);
@@ -248,19 +249,19 @@ void EffectPhaser::PopulateOrExchange(ShuttleGui & S)
       mDryWetS->SetName(_("Dry Wet"));
       mDryWetS->SetMinSize(wxSize(100, -1));
 
-      FloatingPointValidator<double> vldFreq(1, &mFreq);
+      FloatingPointValidator<double> vldFreq(5, &mFreq, NUM_VAL_ONE_TRAILING_ZERO);
       vldFreq.SetRange(MIN_Freq, MAX_Freq);
-      mFreqT = S.Id(ID_Freq).AddTextBox(_("LFO Frequency (Hz):"), wxT(""), 12);
+      mFreqT = S.Id(ID_Freq).AddTextBox(_("LFO Frequency (Hz):"), wxT(""), 15);
       mFreqT->SetValidator(vldFreq);
 
       S.SetStyle(wxSL_HORIZONTAL);
-      mFreqS = S.Id(ID_Freq).AddSlider(wxT(""), DEF_Freq * SCL_Freq, MAX_Freq * SCL_Freq, MIN_Freq * SCL_Freq);
+      mFreqS = S.Id(ID_Freq).AddSlider(wxT(""), DEF_Freq * SCL_Freq, MAX_Freq * SCL_Freq, 0.0);
       mFreqS ->SetName(_("LFO frequency in hertz"));
       mFreqS ->SetMinSize(wxSize(100, -1));
 
       FloatingPointValidator<double> vldPhase(1, &mPhase);
       vldPhase.SetRange(MIN_Phase, MAX_Phase);
-      mPhaseT = S.Id(ID_Phase).AddTextBox(_("LFO Start Phase (deg.):"), wxT(""), 12);
+      mPhaseT = S.Id(ID_Phase).AddTextBox(_("LFO Start Phase (deg.):"), wxT(""), 15);
       mPhaseT->SetValidator(vldPhase);
 
       S.SetStyle(wxSL_HORIZONTAL);
@@ -271,7 +272,7 @@ void EffectPhaser::PopulateOrExchange(ShuttleGui & S)
 
       IntegerValidator<int> vldDepth(&mDepth);
       vldDepth.SetRange(MIN_Depth, MAX_Depth);
-      mDepthT = S.Id(ID_Depth).AddTextBox(_("Depth:"), wxT(""), 12);
+      mDepthT = S.Id(ID_Depth).AddTextBox(_("Depth:"), wxT(""), 15);
       mDepthT->SetValidator(vldDepth);
 
       S.SetStyle(wxSL_HORIZONTAL);
@@ -281,7 +282,7 @@ void EffectPhaser::PopulateOrExchange(ShuttleGui & S)
 
       IntegerValidator<int> vldFeedback(&mFeedback);
       vldFeedback.SetRange(MIN_Feedback, MAX_Feedback);
-      mFeedbackT = S.Id(ID_Feedback).AddTextBox(_("Feedback (%):"), wxT(""), 12);
+      mFeedbackT = S.Id(ID_Feedback).AddTextBox(_("Feedback (%):"), wxT(""), 15);
       mFeedbackT->SetValidator(vldFeedback);
 
       S.SetStyle(wxSL_HORIZONTAL);
@@ -331,7 +332,6 @@ bool EffectPhaser::TransferDataFromWindow()
 void EffectPhaser::OnStagesSlider(wxCommandEvent & evt)
 {
    mStages = (evt.GetInt() / SCL_Stages) & ~1;  // must be even;
-   mPhaseS->SetValue(mStages * SCL_Stages);
    mStagesT->GetValidator()->TransferToWindow();
    EnableApply(mUIParent->Validate());
 }
@@ -346,6 +346,7 @@ void EffectPhaser::OnDryWetSlider(wxCommandEvent & evt)
 void EffectPhaser::OnFreqSlider(wxCommandEvent & evt)
 {
    mFreq = (double) evt.GetInt() / SCL_Freq;
+   if (mFreq < MIN_Freq) mFreq = MIN_Freq;
    mFreqT->GetValidator()->TransferToWindow();
    EnableApply(mUIParent->Validate());
 }
diff --git a/src/effects/Reverse.cpp b/src/effects/Reverse.cpp
index e55c6e309a0c3fbad844db9f857732b356aad069..8ec87a89a72d38ef4bc850b476d9029be7308182 100644
--- a/src/effects/Reverse.cpp
+++ b/src/effects/Reverse.cpp
@@ -15,14 +15,14 @@
 
 
 #include "../Audacity.h"
+#include "Reverse.h"
 
 #include <math.h>
 
 #include <wx/intl.h>
 
 #include "../LabelTrack.h"
-
-#include "Reverse.h"
+#include "../WaveTrack.h"
 
 //
 // EffectReverse
diff --git a/src/effects/Reverse.h b/src/effects/Reverse.h
index d01816ab77064a289d819855cfb49c857dffe6ba..1080f76c78eec4684b61e55d01ced0ac0340ad7b 100644
--- a/src/effects/Reverse.h
+++ b/src/effects/Reverse.h
@@ -15,8 +15,6 @@
 
 #include <wx/string.h>
 
-#include "../WaveTrack.h"
-
 #include "Effect.h"
 
 #define REVERSE_PLUGIN_SYMBOL XO("Reverse")
diff --git a/src/effects/ScienFilter.cpp b/src/effects/ScienFilter.cpp
index 838e8273e9fe5916dca3d056dbd14fbefcf4c21f..7dee7f0e142f30bf1bcd9ca56bec975aafdfb28b 100644
--- a/src/effects/ScienFilter.cpp
+++ b/src/effects/ScienFilter.cpp
@@ -725,7 +725,7 @@ bool EffectScienFilter::CalcFilter()
       }
       if ((mOrder & 1) == 0)
       {
-         float fTemp = pow (10.0, -wxMax(0.001, mRipple) / 20.0);      // at DC the response is down R dB (for even-order)
+         float fTemp = DB_TO_LINEAR(-wxMax(0.001, mRipple));      // at DC the response is down R dB (for even-order)
          mpBiquad[0].fNumerCoeffs [0] *= fTemp;
          mpBiquad[0].fNumerCoeffs [1] *= fTemp;
          mpBiquad[0].fNumerCoeffs [2] *= fTemp;
@@ -761,7 +761,7 @@ bool EffectScienFilter::CalcFilter()
    case kChebyshevTypeII:     // Chebyshev Type 2
       float fSZeroX, fSZeroY;
       float fSPoleX, fSPoleY;
-      eps = pow (10.0, -wxMax(0.001, mStopbandRipple) / 20.0);
+      eps = DB_TO_LINEAR(-wxMax(0.001, mStopbandRipple));
       a = log (1 / eps + sqrt(1 / square(eps) + 1)) / mOrder;
 
       // Assume even order
@@ -1131,7 +1131,7 @@ void EffectScienFilterPanel::OnPaint(wxPaintEvent & WXUNUSED(evt))
       x = mEnvRect.x + i;
       freq = pow(10.0, loLog + i * step);          //Hz
       yF = mEffect->FilterMagnAtFreq (freq);
-      yF = 20.0 * log10(yF);
+      yF = LINEAR_TO_DB(yF);
 
       if (yF < mDbMin)
       {
diff --git a/src/effects/Silence.cpp b/src/effects/Silence.cpp
index 39b30d0d7b3092b311d39a1fdcb443e7427a5cc7..2894ef1e71ad7db73cde5255d9e4c37936786b36 100644
--- a/src/effects/Silence.cpp
+++ b/src/effects/Silence.cpp
@@ -19,6 +19,7 @@
 #include <wx/intl.h>
 
 #include "../ShuttleGui.h"
+#include "../WaveTrack.h"
 
 EffectSilence::EffectSilence()
 {
diff --git a/src/effects/Silence.h b/src/effects/Silence.h
index 25be9f049174ea7e44f16a316913c01d29ef4158..f956472577c88be438a3f5726efdd9a45d475ea5 100644
--- a/src/effects/Silence.h
+++ b/src/effects/Silence.h
@@ -15,7 +15,6 @@
 
 #include <wx/string.h>
 
-#include "../WaveTrack.h"
 #include "../widgets/NumericTextCtrl.h"
 
 #include "Generator.h"
diff --git a/src/effects/StereoToMono.cpp b/src/effects/StereoToMono.cpp
index d45c85e9a2d1a933f9aabeaefd283edeebd9e880..bfdcf5a654fb6510a1fe048233b6b431c87d1f42 100644
--- a/src/effects/StereoToMono.cpp
+++ b/src/effects/StereoToMono.cpp
@@ -14,12 +14,12 @@
 *//*******************************************************************/
 
 #include "../Audacity.h"
+#include "StereoToMono.h"
 
 #include <wx/intl.h>
 
 #include "../Project.h"
-
-#include "StereoToMono.h"
+#include "../WaveTrack.h"
 
 EffectStereoToMono::EffectStereoToMono()
 {
diff --git a/src/effects/TwoPassSimpleMono.cpp b/src/effects/TwoPassSimpleMono.cpp
index 57fe0bfb83f9ebf5447ce2ad585e1123b1cc119e..d1dbefd6e89e8cbe0958489903708293cbb99a2f 100644
--- a/src/effects/TwoPassSimpleMono.cpp
+++ b/src/effects/TwoPassSimpleMono.cpp
@@ -22,6 +22,8 @@ doing the second pass over all selected tracks.
 
 #include "TwoPassSimpleMono.h"
 
+#include "../WaveTrack.h"
+
 bool EffectTwoPassSimpleMono::Process()
 {
     mPass = 0;
diff --git a/src/effects/Wahwah.cpp b/src/effects/Wahwah.cpp
index a14213c32f712e124ac84937d1e45af46b77a532..7cf5510933c9a1c62ba4a6c1353e9fbcd91dda77 100644
--- a/src/effects/Wahwah.cpp
+++ b/src/effects/Wahwah.cpp
@@ -217,7 +217,7 @@ void EffectWahwah::PopulateOrExchange(ShuttleGui & S)
    {
       S.SetStretchyCol(2);
 
-      FloatingPointValidator<double> vldfreq(1, &mFreq);
+      FloatingPointValidator<double> vldfreq(5, &mFreq, NUM_VAL_ONE_TRAILING_ZERO);
       vldfreq.SetRange(MIN_Freq, MAX_Freq);
       mFreqT = S.Id(ID_Freq).AddTextBox(_("LFO Frequency (Hz):"), wxT(""), 12);
       mFreqT->SetValidator(vldfreq);
diff --git a/src/effects/nyquist/Nyquist.cpp b/src/effects/nyquist/Nyquist.cpp
index 244067e6fb2d631d0661e6c7f95c41a4450c2f83..580d0d1788678befbb2f2cf78c26091567112b33 100644
--- a/src/effects/nyquist/Nyquist.cpp
+++ b/src/effects/nyquist/Nyquist.cpp
@@ -45,6 +45,7 @@ effects from this one class.
 #include "../../FileNames.h"
 #include "../../Internat.h"
 #include "../../LabelTrack.h"
+#include "../../prefs/SpectrogramSettings.h"
 #include "../../Project.h"
 #include "../../ShuttleGui.h"
 #include "../../WaveClip.h"
@@ -539,34 +540,6 @@ bool NyquistEffect::Process()
                                  Internat::ToString(mT1).c_str());
       mProps += wxString::Format(wxT("(putprop '*SELECTION* (list %s) 'TRACKS)\n"), waveTrackList.c_str());
       mProps += wxString::Format(wxT("(putprop '*SELECTION* %d 'CHANNELS)\n"), numChannels);
-
-      wxString lowHz = wxT("nil");
-      wxString highHz = wxT("nil");
-      wxString centerHz = wxT("nil");
-      wxString bandwidth = wxT("nil");
-
-#if defined(EXPERIMENTAL_SPECTRAL_EDITING)
-      if (mF0 >= 0.0) {
-         lowHz.Printf(wxT("(float %s)"), Internat::ToString(mF0).c_str());
-      }
-
-      if (mF1 >= 0.0) {
-         highHz.Printf(wxT("(float %s)"), Internat::ToString(mF1).c_str());
-      }
-
-      if ((mF0 >= 0.0) && (mF1 >= 0.0)) {
-         centerHz.Printf(wxT("(float %s)"), Internat::ToString(sqrt(mF0 * mF1)).c_str());
-      }
-
-      if ((mF0 > 0.0) && (mF1 >= mF0)) {
-         bandwidth.Printf(wxT("(float %s)"), Internat::ToString(log(mF1 / mF0)/log(2.0)).c_str());
-      }
-
-#endif
-      mProps += wxString::Format(wxT("(putprop '*SELECTION* %s 'LOW-HZ)\n"), lowHz.c_str());
-      mProps += wxString::Format(wxT("(putprop '*SELECTION* %s 'CENTER-HZ)\n"), centerHz.c_str());
-      mProps += wxString::Format(wxT("(putprop '*SELECTION* %s 'HIGH-HZ)\n"), highHz.c_str());
-      mProps += wxString::Format(wxT("(putprop '*SELECTION* %s 'BANDWIDTH)\n"), bandwidth.c_str());
    }
 
    // Keep track of whether the current track is first selected in its sync-lock group
@@ -621,6 +594,45 @@ bool NyquistEffect::Process()
          nyx_set_os_callback(StaticOSCallback, (void *)this);
          nyx_capture_output(StaticOutputCallback, (void *)this);
 
+         if (mVersion >= 4)
+         {
+            mPerTrackProps = wxEmptyString;
+            wxString lowHz = wxT("nil");
+            wxString highHz = wxT("nil");
+            wxString centerHz = wxT("nil");
+            wxString bandwidth = wxT("nil");
+
+            const WaveTrack::WaveTrackDisplay display = mCurTrack[0]->GetDisplay();
+            const bool bAllowSpectralEditing =
+               (display == WaveTrack::Spectrum) &&
+               mCurTrack[0]->GetSpectrogramSettings().SpectralSelectionEnabled();
+
+            if (bAllowSpectralEditing) {
+#if defined(EXPERIMENTAL_SPECTRAL_EDITING)
+               if (mF0 >= 0.0) {
+                  lowHz.Printf(wxT("(float %s)"), Internat::ToString(mF0).c_str());
+               }
+
+               if (mF1 >= 0.0) {
+                  highHz.Printf(wxT("(float %s)"), Internat::ToString(mF1).c_str());
+               }
+
+               if ((mF0 >= 0.0) && (mF1 >= 0.0)) {
+                  centerHz.Printf(wxT("(float %s)"), Internat::ToString(sqrt(mF0 * mF1)).c_str());
+               }
+
+               if ((mF0 > 0.0) && (mF1 >= mF0)) {
+                  bandwidth.Printf(wxT("(float %s)"), Internat::ToString(log(mF1 / mF0) / log(2.0)).c_str());
+               }
+            }
+
+#endif
+            mPerTrackProps += wxString::Format(wxT("(putprop '*SELECTION* %s 'LOW-HZ)\n"), lowHz.c_str());
+            mPerTrackProps += wxString::Format(wxT("(putprop '*SELECTION* %s 'CENTER-HZ)\n"), centerHz.c_str());
+            mPerTrackProps += wxString::Format(wxT("(putprop '*SELECTION* %s 'HIGH-HZ)\n"), highHz.c_str());
+            mPerTrackProps += wxString::Format(wxT("(putprop '*SELECTION* %s 'BANDWIDTH)\n"), bandwidth.c_str());
+         }
+
          success = ProcessOne();
 
          nyx_capture_output(NULL, (void *)NULL);
@@ -765,6 +777,7 @@ bool NyquistEffect::ProcessOne()
 
    if (mVersion >= 4) {
       cmd += mProps;
+      cmd += mPerTrackProps;
 
       // Set the track TYPE and VIEW properties
       wxString type;
@@ -776,13 +789,8 @@ bool NyquistEffect::ProcessOne()
             type = wxT("wave");
             switch (((WaveTrack *) mCurTrack[0])->GetDisplay())
             {
-               case WaveTrack::WaveformDisplay: view = wxT("\"Waveform\""); break;
-               case WaveTrack::WaveformDBDisplay: view = wxT("\"Waveform (dB)\""); break;
-               case WaveTrack::SpectrumDisplay: view = wxT("\"Spectrogram\""); break;
-               case WaveTrack::SpectrumLogDisplay: view = wxT("\"Spectrogram log(f)\""); break;
-               case WaveTrack::SpectralSelectionDisplay: view = wxT("\"Spectral Selection\""); break;
-               case WaveTrack::SpectralSelectionLogDisplay: view = wxT("\"Spectral Selection log(f)\""); break;
-               case WaveTrack::PitchDisplay: view = wxT("\"Pitch (EAC)\""); break;
+               case WaveTrack::Waveform: view = wxT("\"Waveform\""); break;
+               case WaveTrack::Spectrum: view = wxT("\"Spectrum\""); break;
                default: view = wxT("NIL"); break;
             }
          break;
diff --git a/src/effects/nyquist/Nyquist.h b/src/effects/nyquist/Nyquist.h
index 47b9e224654e3a3f790762330f6ae13a36a25c72..794275fefca4946ae24b2ecf5bb03d3df4e41339 100644
--- a/src/effects/nyquist/Nyquist.h
+++ b/src/effects/nyquist/Nyquist.h
@@ -223,6 +223,7 @@ private:
    wxArrayString     mCategories;
 
    wxString          mProps;
+   wxString          mPerTrackProps;
 
    bool              mRestoreSplits;
    int               mMergeClips;
diff --git a/src/effects/vamp/VampEffect.cpp b/src/effects/vamp/VampEffect.cpp
index 058b1afcad26f2194ef4015d31bd7f6663d2546b..4f4e00fbccf4034912e0d6c94e25b1efffee5ab6 100644
--- a/src/effects/vamp/VampEffect.cpp
+++ b/src/effects/vamp/VampEffect.cpp
@@ -40,6 +40,9 @@
 #include "../../ShuttleGui.h"
 #include "../../widgets/valnum.h"
 
+#include "../../LabelTrack.h"
+#include "../../WaveTrack.h"
+
 enum
 {
    ID_Program  =  10000,
diff --git a/src/effects/vamp/VampEffect.h b/src/effects/vamp/VampEffect.h
index 7e4d08d59218a8511d9af5f8bdd6e77c706bd4d1..1c660d09d542a0ff648954a7fcf190c33dbfbf11 100644
--- a/src/effects/vamp/VampEffect.h
+++ b/src/effects/vamp/VampEffect.h
@@ -25,10 +25,10 @@
 
 #include <vamp-hostsdk/PluginLoader.h>
 
-#include "../../LabelTrack.h"
-
 #include "../Effect.h"
 
+class LabelTrack;
+
 #define VAMPEFFECTS_VERSION wxT("1.0.0.0")
 #define VAMPEFFECTS_FAMILY wxT("Vamp")
 
diff --git a/src/export/Export.cpp b/src/export/Export.cpp
index 283a084541a91d60ec0752223f68299091b0322a..b505852ffefd8c1a33367117dd181a866ece0afa 100644
--- a/src/export/Export.cpp
+++ b/src/export/Export.cpp
@@ -61,16 +61,13 @@
 #include "../DirManager.h"
 #include "../FileFormats.h"
 #include "../Internat.h"
-#include "../LabelTrack.h"
 #include "../Mix.h"
 #include "../Prefs.h"
 #include "../Project.h"
 #include "../ShuttleGui.h"
-#include "../Track.h"
 #include "../WaveTrack.h"
 #include "../widgets/Warning.h"
 #include "../AColor.h"
-#include "../TimeTrack.h"
 #include "../Dependencies.h"
 
 //----------------------------------------------------------------------------
diff --git a/src/export/ExportCL.cpp b/src/export/ExportCL.cpp
index 2bab9da0d68e9cee599e983812a60886c709e096..1b250e4b61b936a1eb2a3239010ab9e5f2b0b65e 100644
--- a/src/export/ExportCL.cpp
+++ b/src/export/ExportCL.cpp
@@ -18,7 +18,7 @@
 #include <wx/button.h>
 #include <wx/combobox.h>
 #include <wx/log.h>
-#include <wx/panel.h>
+#include <wx/msgdlg.h>
 #include <wx/process.h>
 #include <wx/sizer.h>
 #include <wx/textctrl.h>
@@ -32,6 +32,8 @@
 #include "../float_cast.h"
 #include "../widgets/FileHistory.h"
 
+#include "../Track.h"
+
 
 //----------------------------------------------------------------------------
 // ExportCLOptions
diff --git a/src/export/ExportFFmpeg.cpp b/src/export/ExportFFmpeg.cpp
index 951b57c6d4e83db6514ecb7582a4ca447a6f2424..fb437eafdeb36a4d907de444988c002343fbb6a0 100644
--- a/src/export/ExportFFmpeg.cpp
+++ b/src/export/ExportFFmpeg.cpp
@@ -36,13 +36,11 @@ function.
 
 #include "../FileFormats.h"
 #include "../Internat.h"
-#include "../LabelTrack.h"
 #include "../Mix.h"
 #include "../Prefs.h"
 #include "../Project.h"
 #include "../Tags.h"
 #include "../Track.h"
-#include "../WaveTrack.h"
 
 #include "Export.h"
 #include "ExportFFmpeg.h"
diff --git a/src/export/ExportFFmpegDialogs.cpp b/src/export/ExportFFmpegDialogs.cpp
index e8fce8360202966fb9589f8af8d4983c8b2dc88e..1782c62686c29741f477efed2210abedc93e196d 100644
--- a/src/export/ExportFFmpegDialogs.cpp
+++ b/src/export/ExportFFmpegDialogs.cpp
@@ -56,13 +56,10 @@
 
 #include "../FileFormats.h"
 #include "../Internat.h"
-#include "../LabelTrack.h"
 #include "../Mix.h"
 #include "../Prefs.h"
 #include "../Project.h"
 #include "../Tags.h"
-#include "../Track.h"
-#include "../WaveTrack.h"
 
 #include "Export.h"
 
diff --git a/src/export/ExportFLAC.cpp b/src/export/ExportFLAC.cpp
index a025ba1451c45f046431ecaad358af2da3a1d732..b0972a543bd117113b15fddc8aedbd2534943755 100644
--- a/src/export/ExportFLAC.cpp
+++ b/src/export/ExportFLAC.cpp
@@ -41,6 +41,8 @@ and libvorbis examples, Monty <monty@xiph.org>
 #include "../Internat.h"
 #include "../Tags.h"
 
+#include "../Track.h"
+
 //----------------------------------------------------------------------------
 // ExportFLACOptions Class
 //----------------------------------------------------------------------------
diff --git a/src/export/ExportMP2.cpp b/src/export/ExportMP2.cpp
index cac351702d74c1463ccc27d8117a1525f574e09d..bd1b4f191cd335b1ce9c01066f43786173de8828 100644
--- a/src/export/ExportMP2.cpp
+++ b/src/export/ExportMP2.cpp
@@ -55,7 +55,7 @@
 #include "../Project.h"
 #include "../ShuttleGui.h"
 #include "../Tags.h"
-#include "../WaveTrack.h"
+#include "../Track.h"
 
 #define LIBTWOLAME_STATIC
 #include "twolame.h"
diff --git a/src/export/ExportMP3.cpp b/src/export/ExportMP3.cpp
index 001d78acfac6bd22c97f2eba14e6499ad4af5ad0..d1185e20d84a523e1de5e30f2cfd26efd84a3e35 100644
--- a/src/export/ExportMP3.cpp
+++ b/src/export/ExportMP3.cpp
@@ -86,7 +86,7 @@
 #include "../Project.h"
 #include "../ShuttleGui.h"
 #include "../Tags.h"
-#include "../WaveTrack.h"
+#include "../Track.h"
 #include "../widgets/LinkingHtmlWindow.h"
 
 #include "FileDialog.h"
diff --git a/src/export/ExportMultiple.cpp b/src/export/ExportMultiple.cpp
index deeb7f30c64e60f5c780c2d3666c7fcd10291803..20f938c3b60da41a514b9b45946ea9a3a86ed95d 100644
--- a/src/export/ExportMultiple.cpp
+++ b/src/export/ExportMultiple.cpp
@@ -48,6 +48,7 @@
 #include "../Prefs.h"
 #include "../ShuttleGui.h"
 #include "../Tags.h"
+#include "../WaveTrack.h"
 #include "../widgets/HelpSystem.h"
 
 
@@ -104,6 +105,7 @@ END_EVENT_TABLE()
 
 ExportMultiple::ExportMultiple(AudacityProject *project)
 : wxDialog(project, wxID_ANY, wxString(_("Export Multiple")))
+, mIterator(new TrackListIterator)
 {
    SetName(GetTitle());
 
@@ -137,6 +139,7 @@ ExportMultiple::ExportMultiple(AudacityProject *project)
 
 ExportMultiple::~ExportMultiple()
 {
+   delete mIterator;
 }
 
 void ExportMultiple::CountTracksAndLabels()
@@ -146,7 +149,7 @@ void ExportMultiple::CountTracksAndLabels()
    mNumWaveTracks = 0;
 
    Track* pTrack;
-   for (pTrack = mIterator.First(mTracks); pTrack != NULL; pTrack = mIterator.Next())
+   for (pTrack = mIterator->First(mTracks); pTrack != NULL; pTrack = mIterator->Next())
    {
       switch (pTrack->GetKind())
       {
@@ -731,7 +734,7 @@ int ExportMultiple::ExportMultipleByTrack(bool byName,
    wxString title;   // un-messed-with title of file for tagging with
 
    /* Remember which tracks were selected, and set them to unselected */
-   for (tr = mIterator.First(mTracks); tr != NULL; tr = mIterator.Next()) {
+   for (tr = mIterator->First(mTracks); tr != NULL; tr = mIterator->Next()) {
       if (tr->GetKind() != Track::Wave) {
          continue;
       }
@@ -747,7 +750,7 @@ int ExportMultiple::ExportMultipleByTrack(bool byName,
    }
 
    /* Examine all tracks in turn, collecting export information */
-   for (tr = mIterator.First(mTracks); tr != NULL; tr = mIterator.Next()) {
+   for (tr = mIterator->First(mTracks); tr != NULL; tr = mIterator->Next()) {
 
       // Want only non-muted wave tracks.
       if ((tr->GetKind() != Track::Wave)  || tr->GetMute())
@@ -760,7 +763,7 @@ int ExportMultiple::ExportMultipleByTrack(bool byName,
       // Check for a linked track
       tr2 = NULL;
       if (tr->GetLinked()) {
-         tr2 = mIterator.Next();
+         tr2 = mIterator->Next();
          if (tr2) {
 
             // Make sure it gets included
@@ -830,7 +833,7 @@ int ExportMultiple::ExportMultipleByTrack(bool byName,
    // loop
    int count = 0; // count the number of sucessful runs
    ExportKit activeSetting;  // pointer to the settings in use for this export
-   for (tr = mIterator.First(mTracks); tr != NULL; tr = mIterator.Next()) {
+   for (tr = mIterator->First(mTracks); tr != NULL; tr = mIterator->Next()) {
 
       // Want only non-muted wave tracks.
       if ((tr->GetKind() != Track::Wave) || (tr->GetMute() == true)) {
@@ -843,7 +846,7 @@ int ExportMultiple::ExportMultipleByTrack(bool byName,
       // Check for a linked track
       tr2 = NULL;
       if (tr->GetLinked()) {
-         tr2 = mIterator.Next();
+         tr2 = mIterator->Next();
          if (tr2) {
             // Select it also
             tr2->SetSelected(true);
diff --git a/src/export/ExportMultiple.h b/src/export/ExportMultiple.h
index a1cc8324a8bb0fa20641176bc73facfb930893c6..06304cb86dc22e747035669fe274a75c21261f28 100644
--- a/src/export/ExportMultiple.h
+++ b/src/export/ExportMultiple.h
@@ -17,7 +17,6 @@
 #include <wx/listctrl.h>
 
 #include "Export.h"
-#include "../Track.h"
 #include "../Tags.h"       // we need to know about the Tags class for metadata
 
 class wxButton;
@@ -27,7 +26,9 @@ class wxRadioButton;
 class wxTextCtrl;
 
 class AudacityProject;
+class LabelTrack;
 class ShuttleGui;
+class TrackListIterator;
 
 class ExportMultiple : public wxDialog
 {
@@ -107,7 +108,7 @@ private:
    AudacityProject *mProject;
    TrackList *mTracks;           /**< The list of tracks in the project that is
                                    being exported */
-   TrackListIterator mIterator;  /**< Iterator used to work through all the
+   TrackListIterator *mIterator;  /**< Iterator used to work through all the
                                    tracks in the project */
    LabelTrack *mLabels;
    int mNumLabels;
diff --git a/src/export/ExportOGG.cpp b/src/export/ExportOGG.cpp
index 19f73c8250049713ba83675e8c48fb650acfc060..5fb62c17ef0694063723b0e612372bcd91c5ad1f 100644
--- a/src/export/ExportOGG.cpp
+++ b/src/export/ExportOGG.cpp
@@ -36,6 +36,7 @@
 
 #include "../Internat.h"
 #include "../Tags.h"
+#include "../Track.h"
 
 //----------------------------------------------------------------------------
 // ExportOGGOptions
diff --git a/src/export/ExportPCM.cpp b/src/export/ExportPCM.cpp
index 27c5002f6d441e524b75dce66b0ad1f88794040d..cee02cb22552ec842dcba8b51093f523fd640855 100644
--- a/src/export/ExportPCM.cpp
+++ b/src/export/ExportPCM.cpp
@@ -28,14 +28,12 @@
 
 #include "../FileFormats.h"
 #include "../Internat.h"
-#include "../LabelTrack.h"
 #include "../Mix.h"
 #include "../Prefs.h"
 #include "../Project.h"
 #include "../ShuttleGui.h"
 #include "../Tags.h"
 #include "../Track.h"
-#include "../WaveTrack.h"
 #include "../ondemand/ODManager.h"
 
 #include "Export.h"
diff --git a/src/import/Import.cpp b/src/import/Import.cpp
index eff3e380afe0476c1de8f0418f695581568e95ea..b211bf6f836dd256c47c8fa1d3bac248988753f3 100644
--- a/src/import/Import.cpp
+++ b/src/import/Import.cpp
@@ -58,7 +58,6 @@ and ImportLOF.cpp.
 #include "ImportFLAC.h"
 #include "ImportFFmpeg.h"
 #include "ImportGStreamer.h"
-#include "../Track.h"
 #include "../Prefs.h"
 
 WX_DEFINE_LIST(ImportPluginList);
diff --git a/src/import/ImportLOF.cpp b/src/import/ImportLOF.cpp
index fb1d0ad1cd43fc5688bc30aee087cfae67a99830..31058691fb976a7e6081e4f5dba549c10f32ebc1 100644
--- a/src/import/ImportLOF.cpp
+++ b/src/import/ImportLOF.cpp
@@ -90,7 +90,6 @@
 #include "../Project.h"
 #include "../FileFormats.h"
 #include "../Prefs.h"
-#include "../WaveTrack.h"
 #include "../Internat.h"
 
 #define BINARY_FILE_CHECK_BUFFER_SIZE 1024
diff --git a/src/ondemand/ODComputeSummaryTask.cpp b/src/ondemand/ODComputeSummaryTask.cpp
index 9885d0ec2cce937eea86c9e6cff5f78fe445e512..7bc0ca0c0d87ba971cef2b3436b63ddfdb6c66e5 100644
--- a/src/ondemand/ODComputeSummaryTask.cpp
+++ b/src/ondemand/ODComputeSummaryTask.cpp
@@ -20,6 +20,8 @@ updating the ODPCMAliasBlockFile and the GUI of the newly available data.
 
 #include "ODComputeSummaryTask.h"
 #include "../blockfile/ODPCMAliasBlockFile.h"
+#include "../Sequence.h"
+#include "../WaveTrack.h"
 #include <wx/wx.h>
 
 //36 blockfiles > 3 minutes stereo 44.1kHz per ODTask::DoSome
diff --git a/src/ondemand/ODDecodeTask.cpp b/src/ondemand/ODDecodeTask.cpp
index 3761d4ebfc33b26ec3b1691468a68141499e46d3..bd4f483aeacae29cf1818eb5d55894c8487d8c97 100644
--- a/src/ondemand/ODDecodeTask.cpp
+++ b/src/ondemand/ODDecodeTask.cpp
@@ -18,6 +18,8 @@ updating the ODPCMAliasBlockFile and the GUI of the newly available data.
 
 #include "ODDecodeTask.h"
 #include "../blockfile/ODDecodeBlockFile.h"
+#include "../Sequence.h"
+#include "../WaveTrack.h"
 #include <wx/wx.h>
 
 ///Creates a new task that computes summaries for a wavetrack that needs to be specified through SetWaveTrack()
diff --git a/src/ondemand/ODManager.cpp b/src/ondemand/ODManager.cpp
index c14a293ec31b16d180cd8c05ca0a922ea5733034..8acc72e7f712ca904b3e528b9d75945a3f886b6a 100644
--- a/src/ondemand/ODManager.cpp
+++ b/src/ondemand/ODManager.cpp
@@ -541,12 +541,12 @@ bool ODManager::HasLoadedODFlag()
 }
 
 ///fills in the status bar message for a given track
-void ODManager::FillTipForWaveTrack( WaveTrack * t, const wxChar ** ppTip )
+void ODManager::FillTipForWaveTrack( WaveTrack * t, wxString &tip )
 {
    mQueuesMutex.Lock();
    for(unsigned int i=0;i<mQueues.size();i++)
    {
-      mQueues[i]->FillTipForWaveTrack(t,ppTip);
+      mQueues[i]->FillTipForWaveTrack(t, tip);
    }
    mQueuesMutex.Unlock();
 }
diff --git a/src/ondemand/ODManager.h b/src/ondemand/ODManager.h
index 1b23672a8b221c989f09cc4e8165b58fa9b770e8..2a255298c7dbd2a33515c7273bf544ebc2e10ce3 100644
--- a/src/ondemand/ODManager.h
+++ b/src/ondemand/ODManager.h
@@ -98,7 +98,7 @@ class ODManager
    static bool IsInstanceCreated();
 
    ///fills in the status bar message for a given track
-   void FillTipForWaveTrack( WaveTrack * t, const wxChar ** ppTip );
+   void FillTipForWaveTrack( WaveTrack * t, wxString &tip );
 
    ///Gets the total percent complete for all tasks combined.
    float GetOverallPercentComplete();
diff --git a/src/ondemand/ODWaveTrackTaskQueue.cpp b/src/ondemand/ODWaveTrackTaskQueue.cpp
index e6152cf6c8267461f238a701fd5e34db3c5ffbcb..ee4fe629ee4b82118ee807927d2b94d13e611b24 100644
--- a/src/ondemand/ODWaveTrackTaskQueue.cpp
+++ b/src/ondemand/ODWaveTrackTaskQueue.cpp
@@ -325,7 +325,7 @@ ODTask* ODWaveTrackTaskQueue::GetFrontTask()
 }
 
 ///fills in the status bar message for a given track
-void ODWaveTrackTaskQueue::FillTipForWaveTrack( WaveTrack * t, const wxChar ** ppTip )
+void ODWaveTrackTaskQueue::FillTipForWaveTrack( WaveTrack * t, wxString &tip )
 {
    if(ContainsWaveTrack(t) && GetNumTasks())
    {
@@ -335,7 +335,7 @@ void ODWaveTrackTaskQueue::FillTipForWaveTrack( WaveTrack * t, const wxChar ** p
      // else
        //  msg.Printf(_("%s %d additional tasks remaining."), GetFrontTask()->GetTip().c_str(), GetNumTasks());
 
-      *ppTip = mTipMsg.c_str();
+      tip = mTipMsg.c_str();
 
    }
 }
diff --git a/src/ondemand/ODWaveTrackTaskQueue.h b/src/ondemand/ODWaveTrackTaskQueue.h
index 67821513011b7828c0956209757addbc39c419f7..5b05e5571090252a4f04e89a5831c9f5e24dfa38 100644
--- a/src/ondemand/ODWaveTrackTaskQueue.h
+++ b/src/ondemand/ODWaveTrackTaskQueue.h
@@ -92,7 +92,7 @@ class ODWaveTrackTaskQueue
    ODTask* GetTask(size_t x);
 
    ///fills in the status bar message for a given track
-   void FillTipForWaveTrack( WaveTrack * t, const wxChar ** ppTip );
+   void FillTipForWaveTrack( WaveTrack * t, wxString &tip );
 
  protected:
 
diff --git a/src/prefs/BatchPrefs.cpp b/src/prefs/BatchPrefs.cpp
index 8f7664d2c3d3e7827243703c75f8e754336ebc9a..58454628c32aae20f02da7f152415dee80f39f27 100644
--- a/src/prefs/BatchPrefs.cpp
+++ b/src/prefs/BatchPrefs.cpp
@@ -21,7 +21,6 @@
 #include <wx/textdlg.h>
 
 #include "BatchPrefs.h"
-#include "../Envelope.h"
 #include "../Languages.h"
 #include "../Prefs.h"
 #include "../Project.h"
@@ -82,3 +81,8 @@ bool BatchPrefs::Apply()
 BatchPrefs::~BatchPrefs()
 {
 }
+
+PrefsPanel *BatchPrefsFactory::Create(wxWindow *parent)
+{
+   return new BatchPrefs(parent);
+}
diff --git a/src/prefs/BatchPrefs.h b/src/prefs/BatchPrefs.h
index 427e7233c0cfb36a1ed13c3cc544513af7130844..98210b97373283c7b9ccfa601ced39e4b3940f85 100644
--- a/src/prefs/BatchPrefs.h
+++ b/src/prefs/BatchPrefs.h
@@ -34,4 +34,9 @@ private:
    DECLARE_EVENT_TABLE();
 };
 
+class BatchPrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
 #endif
diff --git a/src/prefs/DevicePrefs.cpp b/src/prefs/DevicePrefs.cpp
index 24e5fa5021eb1c7be35c344165739e86c4772538..c0663c84c4d09c7144038f780c904873fcf7059a 100644
--- a/src/prefs/DevicePrefs.cpp
+++ b/src/prefs/DevicePrefs.cpp
@@ -373,3 +373,8 @@ bool DevicePrefs::Apply()
 
    return true;
 }
+
+PrefsPanel *DevicePrefsFactory::Create(wxWindow *parent)
+{
+   return new DevicePrefs(parent);
+}
diff --git a/src/prefs/DevicePrefs.h b/src/prefs/DevicePrefs.h
index 67d3bef24324e30e8c77b8805ea05b4956c59fcd..bb3bc7b6534f613d8db6c3394f91887ee52b10d2 100644
--- a/src/prefs/DevicePrefs.h
+++ b/src/prefs/DevicePrefs.h
@@ -54,4 +54,10 @@ class DevicePrefs :public PrefsPanel
    DECLARE_EVENT_TABLE();
 };
 
+class DevicePrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
+
 #endif
diff --git a/src/prefs/DirectoriesPrefs.cpp b/src/prefs/DirectoriesPrefs.cpp
index 606e3891b4eddb17ddc5eb29b2e5b3fdb0312e28..1a48313ff1a4e82f30e45fe861bb2d8dbca8ecb3 100644
--- a/src/prefs/DirectoriesPrefs.cpp
+++ b/src/prefs/DirectoriesPrefs.cpp
@@ -242,3 +242,8 @@ bool DirectoriesPrefs::Apply()
 
    return true;
 }
+
+PrefsPanel *DirectoriesPrefsFactory::Create(wxWindow *parent)
+{
+   return new DirectoriesPrefs(parent);
+}
diff --git a/src/prefs/DirectoriesPrefs.h b/src/prefs/DirectoriesPrefs.h
index 40407185764637f8d7c6a16943d9656cd22d21d8..423fd005d657c5ba7f39ae47e27f746cb34b2821 100644
--- a/src/prefs/DirectoriesPrefs.h
+++ b/src/prefs/DirectoriesPrefs.h
@@ -38,4 +38,9 @@ class DirectoriesPrefs :public PrefsPanel
    DECLARE_EVENT_TABLE();
 };
 
+class DirectoriesPrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
 #endif
diff --git a/src/prefs/EffectsPrefs.cpp b/src/prefs/EffectsPrefs.cpp
index cf5ae326ee71d36e448241b8c9f4d69f68d2ec91..e8a36f1f8536cfabcda3a5db9874fb48b9178d03 100644
--- a/src/prefs/EffectsPrefs.cpp
+++ b/src/prefs/EffectsPrefs.cpp
@@ -165,3 +165,8 @@ bool EffectsPrefs::Apply()
 
    return true;
 }
+
+PrefsPanel *EffectsPrefsFactory::Create(wxWindow *parent)
+{
+   return new EffectsPrefs(parent);
+}
diff --git a/src/prefs/EffectsPrefs.h b/src/prefs/EffectsPrefs.h
index 0d096c042747e8ebf6f13dca69e23ebe94ef62ea..484913352b987c3a006d9c3cd595005ca819f906 100644
--- a/src/prefs/EffectsPrefs.h
+++ b/src/prefs/EffectsPrefs.h
@@ -34,4 +34,9 @@ class EffectsPrefs :public PrefsPanel
    void PopulateOrExchange(ShuttleGui & S);
 };
 
+class EffectsPrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
 #endif
diff --git a/src/prefs/ExtImportPrefs.cpp b/src/prefs/ExtImportPrefs.cpp
index 9e6550cb7399d558879ed7a3ef816a0a1dbbf0bf..26c1b6593b529f1114edf9838015f5d3b570ed2b 100644
--- a/src/prefs/ExtImportPrefs.cpp
+++ b/src/prefs/ExtImportPrefs.cpp
@@ -780,3 +780,8 @@ void ExtImportPrefsDropTarget::SetDataObject(wxDataObject* data)
 {
    this->m_dataObject = data;
 }
+
+PrefsPanel *ExtImportPrefsFactory::Create(wxWindow *parent)
+{
+   return new ExtImportPrefs(parent);
+}
diff --git a/src/prefs/ExtImportPrefs.h b/src/prefs/ExtImportPrefs.h
index d97f29b697decc1f7aa0d8d81c8657b7058ecbe2..38670d8e315d1fcce7899efdcc3d7ad97428d331 100644
--- a/src/prefs/ExtImportPrefs.h
+++ b/src/prefs/ExtImportPrefs.h
@@ -107,4 +107,10 @@ class ExtImportPrefs:public PrefsPanel
    DECLARE_EVENT_TABLE()
 };
 
+
+class ExtImportPrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
 #endif
diff --git a/src/prefs/GUIPrefs.cpp b/src/prefs/GUIPrefs.cpp
index c6fc5aa04aeac61fab2b4d3b2cdce690280248c7..8c148a2d058db4872b73e8a327df64158a42069c 100644
--- a/src/prefs/GUIPrefs.cpp
+++ b/src/prefs/GUIPrefs.cpp
@@ -18,6 +18,7 @@
 *//*******************************************************************/
 
 #include "../Audacity.h"
+#include "GUIPrefs.h"
 
 #include <wx/defs.h>
 
@@ -26,7 +27,7 @@
 #include "../Prefs.h"
 #include "../ShuttleGui.h"
 
-#include "GUIPrefs.h"
+#include "GUISettings.h"
 
 GUIPrefs::GUIPrefs(wxWindow * parent)
 :  PrefsPanel(parent, _("Interface"))
@@ -99,9 +100,10 @@ void GUIPrefs::PopulateOrExchange(ShuttleGui & S)
 
       S.StartMultiColumn(2);
       {
+         const wxString defaultRange = wxString::Format(wxT("%d"), ENV_DB_RANGE);
          S.TieChoice(_("Meter/Waveform dB &range:"),
-                     wxT("/GUI/EnvdBRange"),
-                     wxT("60"),
+                     ENV_DB_KEY,
+                     defaultRange,
                      mRangeChoices,
                      mRangeCodes);
          S.SetSizeHints(mRangeChoices);
@@ -158,3 +160,8 @@ bool GUIPrefs::Apply()
 
    return true;
 }
+
+PrefsPanel *GUIPrefsFactory::Create(wxWindow *parent)
+{
+   return new GUIPrefs(parent);
+}
diff --git a/src/prefs/GUIPrefs.h b/src/prefs/GUIPrefs.h
index e3af2b7f31467c70c7aa1fa3038c82e05fd883c1..7f114f53a9310b747b2db66200137d5b3ac66a12 100644
--- a/src/prefs/GUIPrefs.h
+++ b/src/prefs/GUIPrefs.h
@@ -43,4 +43,9 @@ class GUIPrefs :public PrefsPanel
    wxArrayString mRangeChoices;
 };
 
+class GUIPrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
 #endif
diff --git a/src/prefs/GUISettings.h b/src/prefs/GUISettings.h
new file mode 100644
index 0000000000000000000000000000000000000000..df0ad6a5b13132fedf0bacc9b0138b0ff40269a7
--- /dev/null
+++ b/src/prefs/GUISettings.h
@@ -0,0 +1,18 @@
+/**********************************************************************
+
+Audacity: A Digital Audio Editor
+
+GUIPrefs.h
+
+Paul Licameli
+   Moved a constant here from Envelope.h where it did not belong
+   Define the key string in one place here too
+
+**********************************************************************/
+#ifndef __AUDACITY_GUI_SETTINGS__
+#define __AUDACITY_GUI_SETTINGS__
+
+#define ENV_DB_KEY (wxT("/GUI/EnvdBRange"))
+#define ENV_DB_RANGE 60
+
+#endif
diff --git a/src/prefs/ImportExportPrefs.cpp b/src/prefs/ImportExportPrefs.cpp
index f6e9538f269df2bf5e7c2bd91d1f5676bcdb2494..609689cc90c93c8ed3e423efb9863fa147d97731 100644
--- a/src/prefs/ImportExportPrefs.cpp
+++ b/src/prefs/ImportExportPrefs.cpp
@@ -109,3 +109,8 @@ bool ImportExportPrefs::Apply()
 
    return true;
 }
+
+PrefsPanel *ImportExportPrefsFactory::Create(wxWindow *parent)
+{
+   return new ImportExportPrefs(parent);
+}
diff --git a/src/prefs/ImportExportPrefs.h b/src/prefs/ImportExportPrefs.h
index 9ba891ea7df145b5334256d3a6a5d73b0647c4be..9ffe0354190c5309a46f8f0ff00d18ef6de9f56f 100644
--- a/src/prefs/ImportExportPrefs.h
+++ b/src/prefs/ImportExportPrefs.h
@@ -33,4 +33,9 @@ class ImportExportPrefs :public PrefsPanel
    void PopulateOrExchange(ShuttleGui & S);
 };
 
+class ImportExportPrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
 #endif
diff --git a/src/prefs/KeyConfigPrefs.cpp b/src/prefs/KeyConfigPrefs.cpp
index 103795f04140ed01b98dc89e489941fc9e256911..5c1ed5d4e951005313b706409fe1c91155ebe60a 100644
--- a/src/prefs/KeyConfigPrefs.cpp
+++ b/src/prefs/KeyConfigPrefs.cpp
@@ -20,12 +20,15 @@ KeyConfigPrefs and MousePrefs use.
 *//*********************************************************************/
 
 #include "../Audacity.h"
+#include "../Experimental.h"
+#include "KeyConfigPrefs.h"
 
 #include <wx/defs.h>
 #include <wx/ffile.h>
 #include <wx/intl.h>
 #include <wx/filedlg.h>
 #include <wx/button.h>
+#include <wx/msgdlg.h>
 
 #include "../Prefs.h"
 #include "../Project.h"
@@ -35,7 +38,6 @@ KeyConfigPrefs and MousePrefs use.
 
 #include "../Internat.h"
 #include "../ShuttleGui.h"
-#include "KeyConfigPrefs.h"
 
 #include "FileDialog.h"
 
@@ -1211,3 +1213,8 @@ void KeyConfigPrefs::Cancel()
 }
 
 #endif
+
+PrefsPanel *KeyConfigPrefsFactory::Create(wxWindow *parent)
+{
+   return new KeyConfigPrefs(parent);
+}
diff --git a/src/prefs/KeyConfigPrefs.h b/src/prefs/KeyConfigPrefs.h
index 36f869ec46219e0e30ed00f2372c7b8e5ece75bf..07bbd0b1d24c7776dadb0bcd4bbff5e74616ae3d 100644
--- a/src/prefs/KeyConfigPrefs.h
+++ b/src/prefs/KeyConfigPrefs.h
@@ -30,6 +30,8 @@ class ShuttleGui;
 
 #include "PrefsPanel.h"
 
+class wxStaticText;
+
 class KeyConfigPrefs :public PrefsPanel
 {
 public:
@@ -141,6 +143,12 @@ class KeyConfigPrefs:public PrefsPanel
 
    DECLARE_EVENT_TABLE();
 };
+
 #endif
 
+class KeyConfigPrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
 #endif
diff --git a/src/prefs/LibraryPrefs.cpp b/src/prefs/LibraryPrefs.cpp
index 6c019f9afcfc3e7980a859e3bd34540c765110bc..ee3e90126c75612254010863e6a7da53bf405ff8 100644
--- a/src/prefs/LibraryPrefs.cpp
+++ b/src/prefs/LibraryPrefs.cpp
@@ -236,3 +236,8 @@ bool LibraryPrefs::Apply()
 
    return true;
 }
+
+PrefsPanel *LibraryPrefsFactory::Create(wxWindow *parent)
+{
+   return new LibraryPrefs(parent);
+}
diff --git a/src/prefs/LibraryPrefs.h b/src/prefs/LibraryPrefs.h
index 15e54a98fd2e196c497eb2019793f83077dc109f..f3a35417d9032b78d42e3d4de41e140a7b3d618f 100644
--- a/src/prefs/LibraryPrefs.h
+++ b/src/prefs/LibraryPrefs.h
@@ -46,4 +46,9 @@ class LibraryPrefs :public PrefsPanel
    DECLARE_EVENT_TABLE();
 };
 
+class LibraryPrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
 #endif
diff --git a/src/prefs/MidiIOPrefs.cpp b/src/prefs/MidiIOPrefs.cpp
index d541e6ec322f4a286514d5a589a85d9ddad3aba9..382876e1b43827e1821ac3ca7349685e1c27f919 100644
--- a/src/prefs/MidiIOPrefs.cpp
+++ b/src/prefs/MidiIOPrefs.cpp
@@ -284,4 +284,9 @@ bool MidiIOPrefs::Validate()
    return true;
 }
 
+PrefsPanel *MidiIOPrefsFactory::Create(wxWindow *parent)
+{
+   return new MidiIOPrefs(parent);
+}
+
 #endif
diff --git a/src/prefs/MidiIOPrefs.h b/src/prefs/MidiIOPrefs.h
index 81da992c3a8e52c0064ae1c84a0fc99a4db28684..1970b7061a049dac21ff77bd3fa177fda3167246 100644
--- a/src/prefs/MidiIOPrefs.h
+++ b/src/prefs/MidiIOPrefs.h
@@ -62,6 +62,11 @@ class MidiIOPrefs:public PrefsPanel
    DECLARE_EVENT_TABLE();
 };
 
+class MidiIOPrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
 #endif
 
 #endif
diff --git a/src/prefs/ModulePrefs.cpp b/src/prefs/ModulePrefs.cpp
index a9a2d9c30f0cb71337429f65349c7a59a3b6437c..01544b50b03a34c97ef517e013943bfb73890d2a 100644
--- a/src/prefs/ModulePrefs.cpp
+++ b/src/prefs/ModulePrefs.cpp
@@ -161,5 +161,9 @@ void ModulePrefs::SetModuleStatus( wxString fname, int iStatus ){
    gPrefs->Flush();
 }
 
+PrefsPanel *ModulePrefsFactory::Create(wxWindow *parent)
+{
+   return new ModulePrefs(parent);
+}
 
 
diff --git a/src/prefs/ModulePrefs.h b/src/prefs/ModulePrefs.h
index 9014e96a57a6005d8cc02a979bb6ecd91a8853b7..09d80a1d2cb016946db4ceb860cf51640c031797 100644
--- a/src/prefs/ModulePrefs.h
+++ b/src/prefs/ModulePrefs.h
@@ -50,4 +50,9 @@ class ModulePrefs:public PrefsPanel
    wxArrayString mPaths;
 };
 
+class ModulePrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
 #endif
diff --git a/src/prefs/MousePrefs.cpp b/src/prefs/MousePrefs.cpp
index 4618ddf39fa7e2dacbdeb9af37e15f0b5c96c893..42d99f78c6f0f1331fd5113aeea682f282f46ce1 100644
--- a/src/prefs/MousePrefs.cpp
+++ b/src/prefs/MousePrefs.cpp
@@ -196,3 +196,8 @@ bool MousePrefs::Apply()
 //   PopulateOrExchange(S);
    return true;
 }
+
+PrefsPanel *MousePrefsFactory::Create(wxWindow *parent)
+{
+   return new MousePrefs(parent);
+}
diff --git a/src/prefs/MousePrefs.h b/src/prefs/MousePrefs.h
index 33f5254eae34f83933150a8b189e3966985966c6..df880373204307a78d6c6d067d9c19ae7fa11761 100644
--- a/src/prefs/MousePrefs.h
+++ b/src/prefs/MousePrefs.h
@@ -38,4 +38,9 @@ class MousePrefs :public PrefsPanel
    wxListCtrl * mList;
 };
 
+class MousePrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
 #endif
diff --git a/src/prefs/PlaybackPrefs.cpp b/src/prefs/PlaybackPrefs.cpp
index 997d9be135854b0f573f99b165e002331dd0848b..d3c56e5c33b8714a8431bacd524cffe6524771d5 100644
--- a/src/prefs/PlaybackPrefs.cpp
+++ b/src/prefs/PlaybackPrefs.cpp
@@ -122,3 +122,8 @@ bool PlaybackPrefs::Apply()
 
    return true;
 }
+
+PrefsPanel *PlaybackPrefsFactory::Create(wxWindow *parent)
+{
+   return new PlaybackPrefs(parent);
+}
diff --git a/src/prefs/PlaybackPrefs.h b/src/prefs/PlaybackPrefs.h
index 8384fb584ee860962110a4ec868dd237efaab9a7..057b51d840c2de36b2d510efee638e3d580cf4d8 100644
--- a/src/prefs/PlaybackPrefs.h
+++ b/src/prefs/PlaybackPrefs.h
@@ -32,4 +32,10 @@ class PlaybackPrefs :public PrefsPanel
    void PopulateOrExchange(ShuttleGui & S);
 };
 
+class PlaybackPrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
+
 #endif
diff --git a/src/prefs/PrefsDialog.cpp b/src/prefs/PrefsDialog.cpp
index 91f18bc65de7be9e2be3ce9cef1ea3ee144bbd75..39cc0a56c64ecdcbf9bcd6768fed9e526e5d2dcf 100644
--- a/src/prefs/PrefsDialog.cpp
+++ b/src/prefs/PrefsDialog.cpp
@@ -15,6 +15,7 @@
 *//*******************************************************************/
 
 #include "../Audacity.h"
+#include "PrefsDialog.h"
 
 #include <wx/defs.h>
 #include <wx/button.h>
@@ -41,7 +42,6 @@
 #include "../Prefs.h"
 #include "../ShuttleGui.h"
 
-#include "PrefsDialog.h"
 #include "PrefsPanel.h"
 
 #include "BatchPrefs.h"
@@ -64,6 +64,7 @@
 #include "ThemePrefs.h"
 #include "TracksPrefs.h"
 #include "WarningsPrefs.h"
+#include "WaveformPrefs.h"
 #include "ExtImportPrefs.h"
 
 #ifdef EXPERIMENTAL_MIDI_OUT
@@ -81,11 +82,14 @@ class wxTreebookExt : public wxTreebook
 {
 public:
    wxTreebookExt( wxWindow *parent,
-      wxWindowID id) : wxTreebook( parent, id )
+      wxWindowID id, const wxString &titlePrefix)
+      : wxTreebook( parent, id )
+      , mTitlePrefix(titlePrefix)
    {;};
    ~wxTreebookExt(){;};
    virtual int ChangeSelection(size_t n);
    virtual int SetSelection(size_t n);
+   const wxString mTitlePrefix;
 };
 
 
@@ -100,7 +104,7 @@ int wxTreebookExt::ChangeSelection(size_t n) {
 int wxTreebookExt::SetSelection(size_t n)
 {
    int i = wxTreebook::SetSelection(n);
-   wxString Temp = wxString(_("Preferences: ")) + GetPageText( n );
+   wxString Temp = wxString(mTitlePrefix) + GetPageText( n );
    ((wxDialog*)GetParent())->SetTitle( Temp );
    ((wxDialog*)GetParent())->SetName( Temp );
    return i;
@@ -108,11 +112,86 @@ int wxTreebookExt::SetSelection(size_t n)
 
 
 
-PrefsDialog::PrefsDialog(wxWindow * parent)
+PrefsDialog::Factories
+&PrefsDialog::DefaultFactories()
+{
+   // To do, perhaps:  create this table by registration, without including each PrefsPanel
+   // class... and thus allowing a plug-in protocol
+   static DevicePrefsFactory devicePrefsFactory;
+   static PlaybackPrefsFactory playbackPrefsFactory;
+   static RecordingPrefsFactory recordingPrefsFactory;
+#ifdef EXPERIMENTAL_MIDI_OUT
+   static MidiIOPrefsFactory midiIOPrefsFactory;
+#endif
+   static QualityPrefsFactory qualityPrefsFactory;
+   static GUIPrefsFactory guiPrefsFactory;
+   static TracksPrefsFactory tracksPrefsFactory;
+   static ImportExportPrefsFactory importExportPrefsFactory;
+   static ExtImportPrefsFactory extImportPrefsFactory;
+   static ProjectsPrefsFactory projectsPrefsFactory;
+#if !defined(DISABLE_DYNAMIC_LOADING_FFMPEG) || !defined(DISABLE_DYNAMIC_LOADING_LAME)
+   static LibraryPrefsFactory libraryPrefsFactory;
+#endif
+   static WaveformPrefsFactory waveformPrefsFactory;
+   static SpectrumPrefsFactory spectrumPrefsFactory;
+   static DirectoriesPrefsFactory directoriesPrefsFactory;
+   static WarningsPrefsFactory warningsPrefsFactory;
+   static EffectsPrefsFactory effectsPrefsFactory;
+#ifdef EXPERIMENTAL_THEME_PREFS
+   static ThemePrefsFactory themePrefsFactory;
+#endif
+   // static BatchPrefsFactory batchPrefsFactory;
+   static KeyConfigPrefsFactory keyConfigPrefsFactory;
+   static MousePrefsFactory mousePrefsFactory;
+#ifdef EXPERIMENTAL_MODULE_PREFS
+   static ModulePrefsFactory modulePrefsFactory;
+#endif
+
+   static PrefsNode nodes[] = {
+      &devicePrefsFactory,
+      &playbackPrefsFactory,
+      &recordingPrefsFactory,
+#ifdef EXPERIMENTAL_MIDI_OUT
+      &midiIOPrefsFactory,
+#endif
+      &qualityPrefsFactory,
+      &guiPrefsFactory,
+      &tracksPrefsFactory,
+      &importExportPrefsFactory,
+      &extImportPrefsFactory,
+      &projectsPrefsFactory,
+#if !defined(DISABLE_DYNAMIC_LOADING_FFMPEG) || !defined(DISABLE_DYNAMIC_LOADING_LAME)
+      &libraryPrefsFactory,
+#endif
+      &waveformPrefsFactory,
+      &spectrumPrefsFactory,
+      &directoriesPrefsFactory,
+      &warningsPrefsFactory,
+      &effectsPrefsFactory,
+#ifdef EXPERIMENTAL_THEME_PREFS
+      &themePrefsFactory,
+#endif
+      // &batchPrefsFactory,
+      &keyConfigPrefsFactory,
+      &mousePrefsFactory,
+#ifdef EXPERIMENTAL_MODULE_PREFS
+      &modulePrefsFactory,
+#endif
+   };
+
+   static Factories factories(nodes, nodes + sizeof(nodes) / sizeof(nodes[0]));
+   return factories;
+}
+
+
+PrefsDialog::PrefsDialog
+  (wxWindow * parent, const wxString &titlePrefix, Factories &factories)
 :  wxDialog(parent, wxID_ANY, wxString(_("Audacity Preferences")),
             wxDefaultPosition,
             wxDefaultSize,
             wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
+, mFactories(factories)
+, mTitlePrefix(titlePrefix)
 {
    ShuttleGui S(this, eIsCreating);
 
@@ -120,42 +199,36 @@ PrefsDialog::PrefsDialog(wxWindow * parent)
    {
       S.StartHorizontalLay(wxALIGN_LEFT | wxEXPAND, true);
       {
-         mCategories = new wxTreebookExt(this, wxID_ANY);
+         mCategories = new wxTreebookExt(this, wxID_ANY, mTitlePrefix);
          S.Prop(1);
          S.AddWindow(mCategories, wxEXPAND);
 
-         wxWindow *w;
-         // Parameters are: AddPage(page, name, IsSelected, imageId).
-         w = new DevicePrefs(mCategories);      mCategories->AddPage(w, w->GetName(), false, 0);
-         w = new PlaybackPrefs(mCategories);    mCategories->AddPage(w, w->GetName(), false, 0);
-         w = new RecordingPrefs(mCategories);   mCategories->AddPage(w, w->GetName(), false, 0);
-#ifdef EXPERIMENTAL_MIDI_OUT
-         w = new MidiIOPrefs(mCategories);      mCategories->AddPage(w, w->GetName(), false, 0);
-#endif
-         w = new QualityPrefs(mCategories);     mCategories->AddPage(w, w->GetName(), false, 0);
-         w = new GUIPrefs(mCategories);         mCategories->AddPage(w, w->GetName(), false, 0);
-         w = new TracksPrefs(mCategories);      mCategories->AddPage(w, w->GetName(), false, 0);
-         w = new ImportExportPrefs(mCategories);mCategories->AddPage(w, w->GetName(), false, 0);
-         w = new ExtImportPrefs(mCategories);   mCategories->AddPage(w, w->GetName(), false, 0);
-         w = new ProjectsPrefs(mCategories);    mCategories->AddPage(w, w->GetName(), false, 0);
-#if !defined(DISABLE_DYNAMIC_LOADING_FFMPEG) || !defined(DISABLE_DYNAMIC_LOADING_LAME)
-         w = new LibraryPrefs(mCategories);     mCategories->AddPage(w, w->GetName(), false, 0);
-#endif
-         w = new SpectrumPrefs(mCategories);    mCategories->AddPage(w, w->GetName(), false, 0);
-         w = new DirectoriesPrefs(mCategories); mCategories->AddPage(w, w->GetName(), false, 0);
-         w = new WarningsPrefs(mCategories);    mCategories->AddPage(w, w->GetName(), false, 0);
-         w = new EffectsPrefs(mCategories);     mCategories->AddPage(w, w->GetName(), false, 0);
-
-#ifdef EXPERIMENTAL_THEME_PREFS
-         w = new ThemePrefs(mCategories);       mCategories->AddPage(w, w->GetName(), false, 0);
-#endif
-
-//       w = new BatchPrefs(mCategories);       mCategories->AddPage(w, w->GetName(), false, 0);
-         w = new KeyConfigPrefs(mCategories);   mCategories->AddPage(w, w->GetName(), false, 0);
-         w = new MousePrefs(mCategories);       mCategories->AddPage(w, w->GetName(), false, 0);
-#ifdef EXPERIMENTAL_MODULE_PREFS
-         w = new ModulePrefs(mCategories);      mCategories->AddPage(w, w->GetName(), false, 0);
-#endif
+         {
+            typedef std::pair<int, int> IntPair;
+            std::vector<IntPair> stack;
+            int iPage = 0;
+            for (Factories::const_iterator it = factories.begin(), end = factories.end();
+               it != end; ++it, ++iPage)
+            {
+               const PrefsNode &node = *it;
+               PrefsPanelFactory &factory = *node.pFactory;
+               wxWindow *const w = factory.Create(mCategories);
+               if (stack.empty())
+                  // Parameters are: AddPage(page, name, IsSelected, imageId).
+                  mCategories->AddPage(w, w->GetName(), false, 0);
+               else {
+                  IntPair &top = *stack.rbegin();
+                  mCategories->InsertSubPage(top.first, w, w->GetName(), false, 0);
+                  if (--top.second == 0) {
+                     // Expand all nodes before the layout calculation
+                     mCategories->ExpandNode(top.first, true);
+                     stack.pop_back();
+                  }
+               }
+               if (node.nChildren > 0)
+                  stack.push_back(IntPair(iPage, node.nChildren));
+            }
+         }
       }
       S.EndHorizontalLay();
    }
@@ -163,23 +236,6 @@ PrefsDialog::PrefsDialog(wxWindow * parent)
 
    S.AddStandardButtons(eOkButton | eCancelButton);
 
-   /* long is signed, size_t is unsigned. On some platforms they are different
-    * lengths as well. So we must check that the stored category is both > 0
-    * and within the possible range of categories, making the first check on the
-    * _signed_ value to avoid issues when converting an unsigned one.
-    */
-   size_t selected;
-   long prefscat = gPrefs->Read(wxT("/Prefs/PrefsCategory"), 0L);
-   if (prefscat > 0L )
-      selected = prefscat; // only assign if number will fit
-   else
-      selected = 0;  // use 0 if value can't be assigned
-
-   if (selected >= mCategories->GetPageCount())
-      selected = 0;  // clamp to available range of tabs
-
-   mCategories->SetSelection(selected);
-
 #if defined(__WXGTK__)
    mCategories->GetTreeCtrl()->EnsureVisible(mCategories->GetTreeCtrl()->GetRootItem());
 #endif
@@ -189,6 +245,14 @@ PrefsDialog::PrefsDialog(wxWindow * parent)
    Fit();
    wxSize sz = GetSize();
 
+   // Collapse nodes only after layout so the tree is wide enough
+   {
+      int iPage = 0;
+      for (Factories::const_iterator it = factories.begin(), end = factories.end();
+         it != end; ++it, ++iPage)
+         mCategories->ExpandNode(iPage, it->expanded);
+   }
+
    // This ASSERT used to limit us to 800 x 600.
    // However, we think screens have got bigger now, and that was a bit too restrictive.
    // The impetus for increasing the limit (before we ASSERT) was that this ASSERT
@@ -219,8 +283,25 @@ PrefsDialog::~PrefsDialog()
 {
 }
 
+int PrefsDialog::ShowModal()
+{
+   /* long is signed, size_t is unsigned. On some platforms they are different
+    * lengths as well. So we must check that the stored category is both > 0
+    * and within the possible range of categories, making the first check on the
+    * _signed_ value to avoid issues when converting an unsigned one.
+    */
+   long selected = GetPreferredPage();
+   if (selected < 0 || size_t(selected) >= mCategories->GetPageCount())
+      selected = 0;  // clamp to available range of tabs
+   mCategories->SetSelection(selected);
+
+   return wxDialog::ShowModal();
+}
+
 void PrefsDialog::OnCancel(wxCommandEvent & WXUNUSED(event))
 {
+   RecordExpansionState();
+
    for (size_t i = 0; i < mCategories->GetPageCount(); i++) {
       ((PrefsPanel *) mCategories->GetPage(i))->Cancel();
    }
@@ -238,6 +319,8 @@ void PrefsDialog::OnTreeKeyDown(wxTreeEvent & event)
 
 void PrefsDialog::OnOK(wxCommandEvent & WXUNUSED(event))
 {
+   RecordExpansionState();
+
    // Validate all pages first
    for (size_t i = 0; i < mCategories->GetPageCount(); i++) {
       PrefsPanel *panel = (PrefsPanel *) mCategories->GetPage(i);
@@ -256,8 +339,7 @@ void PrefsDialog::OnOK(wxCommandEvent & WXUNUSED(event))
       panel->Apply();
    }
 
-   gPrefs->Write(wxT("/Prefs/PrefsCategory"), (long)mCategories->GetSelection());
-   gPrefs->Flush();
+   SavePreferredPage();
 
 #if USE_PORTMIXER
    if (gAudioIO) {
@@ -307,7 +389,39 @@ void PrefsDialog::SelectPageByName(wxString pageName)
    }
 }
 
-void PrefsDialog::ShowTempDirPage()
+int PrefsDialog::GetSelectedPage() const
+{
+   return mCategories->GetSelection();
+}
+
+GlobalPrefsDialog::GlobalPrefsDialog(wxWindow * parent, Factories &factories)
+   : PrefsDialog(parent, _("Preferences: "), factories)
+{
+}
+
+GlobalPrefsDialog::~GlobalPrefsDialog()
+{
+}
+
+long GlobalPrefsDialog::GetPreferredPage()
 {
-   SelectPageByName(_("Directories"));
+   long prefscat = gPrefs->Read(wxT("/Prefs/PrefsCategory"), 0L);
+   return prefscat;
+}
+
+void GlobalPrefsDialog::SavePreferredPage()
+{
+   gPrefs->Write(wxT("/Prefs/PrefsCategory"), (long)GetSelectedPage());
+   gPrefs->Flush();
+}
+
+void PrefsDialog::RecordExpansionState()
+{
+   // Remember expansion state of the tree control
+   {
+      int iPage = 0;
+      for (Factories::iterator it = mFactories.begin(), end = mFactories.end();
+         it != end; ++it, ++iPage)
+         it->expanded = mCategories->IsNodeExpanded(iPage);
+   }
 }
diff --git a/src/prefs/PrefsDialog.h b/src/prefs/PrefsDialog.h
index 13f3d3e0c03eb5388dd2759ad4f3e4cdf6671cda..a4b4689214a8f975ea5ef111968afab82b811779 100644
--- a/src/prefs/PrefsDialog.h
+++ b/src/prefs/PrefsDialog.h
@@ -12,6 +12,7 @@
 #ifndef __AUDACITY_PREFS_DIALOG__
 #define __AUDACITY_PREFS_DIALOG__
 
+#include <vector>
 #include <wx/button.h>
 #include <wx/event.h>
 #include <wx/dialog.h>
@@ -19,24 +20,74 @@
 #include <wx/treebook.h>
 #include <wx/window.h>
 
+class PrefsPanelFactory;
+
+#ifdef __GNUC__
+#define CONST
+#else
+#define CONST const
+#endif
+
 class PrefsDialog:public wxDialog
 {
  public:
-   PrefsDialog(wxWindow * parent);
+    // An array of PrefsNode specifies the tree of pages in pre-order traversal.
+    struct PrefsNode {
+       PrefsPanelFactory * CONST pFactory;
+       CONST int nChildren;
+       bool expanded;
+
+       PrefsNode(PrefsPanelFactory *pFactory_, int nChildren_ = 0)
+          : pFactory(pFactory_), nChildren(nChildren_), expanded(false)
+       {}
+    };
+   typedef std::vector<PrefsNode> Factories;
+   static Factories &DefaultFactories();
+
+   PrefsDialog(wxWindow * parent,
+      const wxString &titlePrefix = _("Preferences: "),
+      Factories &factories = DefaultFactories());
    virtual ~PrefsDialog();
 
+   // Defined this so a protected virtual can be invoked after the constructor
+   virtual int ShowModal();
+
    void OnCategoryChange(wxCommandEvent & e);
    void OnOK(wxCommandEvent & e);
    void OnCancel(wxCommandEvent & e);
    void OnTreeKeyDown(wxTreeEvent & e); // Used to dismiss the dialog when enter is pressed with focus on tree
 
    void SelectPageByName(wxString pageName);
-   void ShowTempDirPage();
 
- private:
+   // Accessor to help implementations of SavePreferredPage(),
+   // such as by saving a preference after DoModal() returns
+   int GetSelectedPage() const;
+
+ protected:
+    // Decide which page to open first; return -1 for undecided
+    virtual long GetPreferredPage() = 0;
+
+    // Called after OK is clicked and all pages validate
+    virtual void SavePreferredPage() = 0;
+
+private:
+   void RecordExpansionState();
    wxTreebook *mCategories;
+   Factories &mFactories;
+   const wxString mTitlePrefix;
 
    DECLARE_EVENT_TABLE()
 };
 
+// This adds code appropriate only to the original use of PrefsDialog for
+// global settings -- not its reuses elsewhere as in View Settings
+class GlobalPrefsDialog : public PrefsDialog
+{
+public:
+   GlobalPrefsDialog(wxWindow * parent, Factories &factories = DefaultFactories());
+   virtual ~GlobalPrefsDialog();
+   virtual long GetPreferredPage();
+   virtual void SavePreferredPage();
+};
+
 #endif
diff --git a/src/prefs/PrefsPanel.h b/src/prefs/PrefsPanel.h
index e35eacf44612768aaef9783893cfa42c0f44dad9..2af21079a42d20d4eb225b06c1f442a84e89870c 100644
--- a/src/prefs/PrefsPanel.h
+++ b/src/prefs/PrefsPanel.h
@@ -61,4 +61,10 @@ class PrefsPanel:public wxPanel
    }
 };
 
+class PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent) = 0;
+};
+
 #endif
diff --git a/src/prefs/ProjectsPrefs.cpp b/src/prefs/ProjectsPrefs.cpp
index 56f22f8c8a303dc300219f8cafc51c208ac0481d..fc1e076304f710c3ac1b2483589657047ffa3189 100644
--- a/src/prefs/ProjectsPrefs.cpp
+++ b/src/prefs/ProjectsPrefs.cpp
@@ -79,3 +79,8 @@ bool ProjectsPrefs::Apply()
 
    return true;
 }
+
+PrefsPanel *ProjectsPrefsFactory::Create(wxWindow *parent)
+{
+   return new ProjectsPrefs(parent);
+}
diff --git a/src/prefs/ProjectsPrefs.h b/src/prefs/ProjectsPrefs.h
index 3f1a0079139cfea7be26e36cdb3e7f5d273c1d76..480a49f717df08793e9c83452fc1e57438677dda 100644
--- a/src/prefs/ProjectsPrefs.h
+++ b/src/prefs/ProjectsPrefs.h
@@ -33,4 +33,9 @@ class ProjectsPrefs :public PrefsPanel
    void PopulateOrExchange(ShuttleGui & S);
 };
 
+class ProjectsPrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
 #endif
diff --git a/src/prefs/QualityPrefs.cpp b/src/prefs/QualityPrefs.cpp
index 10c5fb1b0173e8e2fbdc360af85fb1039553c31f..1f7e54918533ef80499bb3fc5192c8803be7b92a 100644
--- a/src/prefs/QualityPrefs.cpp
+++ b/src/prefs/QualityPrefs.cpp
@@ -16,6 +16,7 @@
 *//*******************************************************************/
 
 #include "../Audacity.h"
+#include "QualityPrefs.h"
 
 #include <wx/defs.h>
 
@@ -26,8 +27,6 @@
 #include "../SampleFormat.h"
 #include "../ShuttleGui.h"
 
-#include "QualityPrefs.h"
-
 #define ID_SAMPLE_RATE_CHOICE           7001
 
 BEGIN_EVENT_TABLE(QualityPrefs, PrefsPanel)
@@ -228,3 +227,8 @@ bool QualityPrefs::Apply()
 
    return true;
 }
+
+PrefsPanel *QualityPrefsFactory::Create(wxWindow *parent)
+{
+   return new QualityPrefs(parent);
+}
diff --git a/src/prefs/QualityPrefs.h b/src/prefs/QualityPrefs.h
index 726da2490c23e2c843f6e35d2ebbe955c67af46b..778417a2c651faf830f7071b3ca7ea71f20d00fb 100644
--- a/src/prefs/QualityPrefs.h
+++ b/src/prefs/QualityPrefs.h
@@ -53,4 +53,9 @@ class QualityPrefs :public PrefsPanel
    DECLARE_EVENT_TABLE();
 };
 
+class QualityPrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
 #endif
diff --git a/src/prefs/RecordingPrefs.cpp b/src/prefs/RecordingPrefs.cpp
index 01e3db2a496026d022886d67414a8d772a274e1d..fcc054c0c8bf5c5740753e93697791f65401e5cc 100644
--- a/src/prefs/RecordingPrefs.cpp
+++ b/src/prefs/RecordingPrefs.cpp
@@ -19,18 +19,17 @@
 *//********************************************************************/
 
 #include "../Audacity.h"
+#include "RecordingPrefs.h"
 
 #include <wx/defs.h>
 #include <wx/textctrl.h>
 #include <algorithm>
 
 #include "../AudioIO.h"
-#include "../Envelope.h"
+#include "../prefs/GUISettings.h"
 #include "../Prefs.h"
 #include "../ShuttleGui.h"
 
-#include "RecordingPrefs.h"
-
 using std::min;
 
 RecordingPrefs::RecordingPrefs(wxWindow * parent)
@@ -113,7 +112,7 @@ void RecordingPrefs::PopulateOrExchange(ShuttleGui & S)
       {
          S.SetStretchyCol(1);
 
-         int dBRange = gPrefs->Read(wxT("/GUI/EnvdBRange"), ENV_DB_RANGE);
+         int dBRange = gPrefs->Read(ENV_DB_KEY, ENV_DB_RANGE);
          S.TieSlider(_("Sound Activation Le&vel (dB):"),
                      wxT("/AudioIO/SilenceLevel"),
                      -50,
@@ -202,3 +201,8 @@ bool RecordingPrefs::Apply()
    #endif
    return gPrefs->Flush();
 }
+
+PrefsPanel *RecordingPrefsFactory::Create(wxWindow *parent)
+{
+   return new RecordingPrefs(parent);
+}
diff --git a/src/prefs/RecordingPrefs.h b/src/prefs/RecordingPrefs.h
index d4f1dd122225d322f247745a62751010d2946952..f3f8b9ee19ccf56d0fdbaab97575ab51eb751b66 100644
--- a/src/prefs/RecordingPrefs.h
+++ b/src/prefs/RecordingPrefs.h
@@ -32,4 +32,9 @@ class RecordingPrefs :public PrefsPanel
    void PopulateOrExchange(ShuttleGui & S);
 };
 
+class RecordingPrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
 #endif
diff --git a/src/prefs/SpectrogramSettings.cpp b/src/prefs/SpectrogramSettings.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ff2c1649aad52108f18796ec71a9547579f5c6ea
--- /dev/null
+++ b/src/prefs/SpectrogramSettings.cpp
@@ -0,0 +1,621 @@
+/**********************************************************************
+
+Audacity: A Digital Audio Editor
+
+SpectrogramSettings.cpp
+
+Paul Licameli
+
+*******************************************************************//**
+
+\class SpectrogramSettings
+\brief Spectrogram settings, either for one track or as defaults.
+
+*//*******************************************************************/
+
+#include "../Audacity.h"
+#include "SpectrogramSettings.h"
+#include "../NumberScale.h"
+
+#include <algorithm>
+#include <wx/msgdlg.h>
+
+#include "../FFT.h"
+#include "../Prefs.h"
+#include "../RealFFTf.h"
+
+#include <cmath>
+
+SpectrogramSettings::Globals::Globals()
+{
+   LoadPrefs();
+}
+
+void SpectrogramSettings::Globals::SavePrefs()
+{
+#ifdef SPECTRAL_SELECTION_GLOBAL_SWITCH
+   gPrefs->Write(wxT("/Spectrum/EnableSpectralSelection"), spectralSelection);
+#endif
+}
+
+void SpectrogramSettings::Globals::LoadPrefs()
+{
+#ifdef SPECTRAL_SELECTION_GLOBAL_SWITCH
+   spectralSelection
+      = (gPrefs->Read(wxT("/Spectrum/EnableSpectralSelection"), 0L) != 0);
+#endif
+}
+
+SpectrogramSettings::Globals
+&SpectrogramSettings::Globals::Get()
+{
+   static Globals instance;
+   return instance;
+}
+
+SpectrogramSettings::SpectrogramSettings()
+   : hFFT(0)
+   , window(0)
+{
+   LoadPrefs();
+}
+
+SpectrogramSettings::SpectrogramSettings(const SpectrogramSettings &other)
+   : minFreq(other.minFreq)
+   , maxFreq(other.maxFreq)
+   , logMinFreq(other.logMinFreq)
+   , logMaxFreq(other.logMaxFreq)
+   , range(other.range)
+   , gain(other.gain)
+   , frequencyGain(other.frequencyGain)
+   , windowType(other.windowType)
+   , windowSize(other.windowSize)
+#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
+   , zeroPaddingFactor(other.zeroPaddingFactor)
+#endif
+   , isGrayscale(other.isGrayscale)
+   , scaleType(other.scaleType)
+#ifndef SPECTRAL_SELECTION_GLOBAL_SWITCH
+   , spectralSelection(other.spectralSelection)
+#endif
+   , algorithm(other.algorithm)
+#ifdef EXPERIMENTAL_FFT_Y_GRID
+   , fftYGrid(other.fftYGrid)
+#endif
+#ifdef EXPERIMENTAL_FIND_NOTES
+   , fftFindNotes(other.fftFindNotes)
+   , findNotesMinA(other.findNotesMinA)
+   , numberOfMaxima(other.numberOfMaxima)
+   , findNotesQuantize(other.findNotesQuantize)
+#endif
+
+   // Do not copy these!
+   , hFFT(0)
+   , window(0)
+{
+}
+
+SpectrogramSettings &SpectrogramSettings::operator= (const SpectrogramSettings &other)
+{
+   if (this != &other) {
+      minFreq = other.minFreq;
+      maxFreq = other.maxFreq;
+      logMinFreq = other.logMinFreq;
+      logMaxFreq = other.logMaxFreq;
+      range = other.range;
+      gain = other.gain;
+      frequencyGain = other.frequencyGain;
+      windowType = other.windowType;
+      windowSize = other.windowSize;
+#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
+      zeroPaddingFactor = other.zeroPaddingFactor;
+#endif
+      isGrayscale = other.isGrayscale;
+      scaleType = other.scaleType;
+#ifndef SPECTRAL_SELECTION_GLOBAL_SWITCH
+      spectralSelection = other.spectralSelection;
+#endif
+      algorithm = other.algorithm;
+#ifdef EXPERIMENTAL_FFT_Y_GRID
+      fftYGrid = other.fftYGrid;
+#endif
+#ifdef EXPERIMENTAL_FIND_NOTES
+      fftFindNotes = other.fftFindNotes;
+      findNotesMinA = other.findNotesMinA;
+      numberOfMaxima = other.numberOfMaxima;
+      findNotesQuantize = other.findNotesQuantize;
+#endif
+
+      // Do not copy these!
+      hFFT = 0;
+      window = 0;
+   }
+   return *this;
+}
+
+SpectrogramSettings& SpectrogramSettings::defaults()
+{
+   static SpectrogramSettings instance;
+   return instance;
+}
+
+namespace
+{
+   wxArrayString &scaleNamesArray()
+   {
+      static wxArrayString theArray;
+      return theArray;
+   }
+
+   wxArrayString &algorithmNamesArray()
+   {
+      static wxArrayString theArray;
+      return theArray;
+   }
+}
+
+//static
+void SpectrogramSettings::InvalidateNames()
+{
+   scaleNamesArray().Clear();
+   algorithmNamesArray().Clear();
+}
+
+//static
+const wxArrayString &SpectrogramSettings::GetScaleNames()
+{
+   wxArrayString &theArray = scaleNamesArray();
+
+   if (theArray.IsEmpty()) {
+      // Keep in correspondence with enum SpectrogramSettings::ScaleType:
+      theArray.Add(_("Linear"));
+      theArray.Add(_("Logarithmic"));
+      theArray.Add(_("Mel"));
+      theArray.Add(_("Bark"));
+      theArray.Add(_("Erb"));
+      theArray.Add(_("Undertone"));
+   }
+
+   return theArray;
+}
+
+//static
+const wxArrayString &SpectrogramSettings::GetAlgorithmNames()
+{
+   wxArrayString &theArray = algorithmNamesArray();
+
+   if (theArray.IsEmpty()) {
+      // Keep in correspondence with enum SpectrogramSettings::Algorithm:
+      theArray.Add(_("STFT"));
+      theArray.Add(_("Pitch (enhanced autocorrelation)"));
+   }
+
+   return theArray;
+}
+
+bool SpectrogramSettings::Validate(bool quiet)
+{
+   if (!quiet &&
+      maxFreq < 100) {
+      wxMessageBox(_("Maximum frequency must be 100 Hz or above"));
+      return false;
+   }
+   else
+      maxFreq = std::max(100, maxFreq);
+
+   if (!quiet &&
+      minFreq < 0) {
+      wxMessageBox(_("Minimum frequency must be at least 0 Hz"));
+      return false;
+   }
+   else
+      minFreq = std::max(0, minFreq);
+
+   if (!quiet &&
+      maxFreq <= minFreq) {
+      wxMessageBox(_("Minimum frequency must be less than maximum frequency"));
+      return false;
+   }
+   else
+      maxFreq = std::max(1 + minFreq, maxFreq);
+
+   if (!quiet &&
+      range <= 0) {
+      wxMessageBox(_("The range must be at least 1 dB"));
+      return false;
+   }
+   else
+      range = std::max(1, range);
+
+   if (!quiet &&
+      frequencyGain < 0) {
+      wxMessageBox(_("The frequency gain cannot be negative"));
+      return false;
+   }
+   else if (!quiet &&
+      frequencyGain > 60) {
+      wxMessageBox(_("The frequency gain must be no more than 60 dB/dec"));
+      return false;
+   }
+   else
+      frequencyGain =
+         std::max(0, std::min(60, frequencyGain));
+
+   // The rest are controlled by drop-down menus so they can't go wrong
+   // in the Preferences dialog, but we also come here after reading fom saved
+   // preference files, which could be or from future versions.  Validate quietly.
+   windowType =
+      std::max(0, std::min(NumWindowFuncs() - 1, windowType));
+   scaleType =
+      ScaleType(std::max(0,
+         std::min(int(SpectrogramSettings::stNumScaleTypes) - 1,
+            int(scaleType))));
+   algorithm = Algorithm(
+      std::max(0, std::min(int(algNumAlgorithms) - 1, int(algorithm)))
+   );
+   ConvertToEnumeratedWindowSizes();
+   ConvertToActualWindowSizes();
+
+   return true;
+}
+
+void SpectrogramSettings::LoadPrefs()
+{
+   minFreq = gPrefs->Read(wxT("/Spectrum/MinFreq"), 0L);
+
+   maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), 8000L);
+
+   range = gPrefs->Read(wxT("/Spectrum/Range"), 80L);
+   gain = gPrefs->Read(wxT("/Spectrum/Gain"), 20L);
+   frequencyGain = gPrefs->Read(wxT("/Spectrum/FrequencyGain"), 0L);
+
+   windowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256);
+
+#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
+   zeroPaddingFactor = gPrefs->Read(wxT("/Spectrum/ZeroPaddingFactor"), 1);
+#endif
+
+   gPrefs->Read(wxT("/Spectrum/WindowType"), &windowType, eWinFuncHanning);
+
+   isGrayscale = (gPrefs->Read(wxT("/Spectrum/Grayscale"), 0L) != 0);
+
+   scaleType = ScaleType(gPrefs->Read(wxT("/Spectrum/ScaleType"), 0L));
+
+#ifndef SPECTRAL_SELECTION_GLOBAL_SWITCH
+   spectralSelection = (gPrefs->Read(wxT("/Spectrum/EnableSpectralSelection"), 0L) != 0);
+#endif
+
+   algorithm = Algorithm(gPrefs->Read(wxT("/Spectrum/Algorithm"), 0L));
+
+#ifdef EXPERIMENTAL_FFT_Y_GRID
+   fftYGrid = (gPrefs->Read(wxT("/Spectrum/FFTYGrid"), 0L) != 0);
+#endif //EXPERIMENTAL_FFT_Y_GRID
+
+#ifdef EXPERIMENTAL_FIND_NOTES
+   fftFindNotes = (gPrefs->Read(wxT("/Spectrum/FFTFindNotes"), 0L) != 0);
+   findNotesMinA = gPrefs->Read(wxT("/Spectrum/FindNotesMinA"), -30.0);
+   numberOfMaxima = gPrefs->Read(wxT("/Spectrum/FindNotesN"), 5L);
+   findNotesQuantize = (gPrefs->Read(wxT("/Spectrum/FindNotesQuantize"), 0L) != 0);
+#endif //EXPERIMENTAL_FIND_NOTES
+
+   // Enforce legal values
+   Validate(true);
+
+   // These preferences are not written anywhere in the program as of now,
+   // but I keep this legacy here.  Who knows, someone might edit prefs files
+   // directly.  PRL
+   logMinFreq = gPrefs->Read(wxT("/SpectrumLog/MinFreq"), -1);
+   if (logMinFreq < 0)
+      logMinFreq = minFreq;
+   if (logMinFreq < 1)
+      logMinFreq = 1;
+   logMaxFreq = gPrefs->Read(wxT("/SpectrumLog/MaxFreq"), -1);
+   if (logMaxFreq < 0)
+      logMaxFreq = maxFreq;
+   logMaxFreq =
+      std::max(logMinFreq + 1, logMaxFreq);
+
+   InvalidateCaches();
+}
+
+void SpectrogramSettings::SavePrefs()
+{
+   gPrefs->Write(wxT("/Spectrum/MinFreq"), minFreq);
+   gPrefs->Write(wxT("/Spectrum/MaxFreq"), maxFreq);
+
+   // Nothing wrote these.  They only varied from the linear scale bounds in-session. -- PRL
+   // gPrefs->Write(wxT("/SpectrumLog/MaxFreq"), logMinFreq);
+   // gPrefs->Write(wxT("/SpectrumLog/MinFreq"), logMaxFreq);
+
+   gPrefs->Write(wxT("/Spectrum/Range"), range);
+   gPrefs->Write(wxT("/Spectrum/Gain"), gain);
+   gPrefs->Write(wxT("/Spectrum/FrequencyGain"), frequencyGain);
+
+   gPrefs->Write(wxT("/Spectrum/FFTSize"), windowSize);
+
+#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
+   gPrefs->Write(wxT("/Spectrum/ZeroPaddingFactor"), zeroPaddingFactor);
+#endif
+
+   gPrefs->Write(wxT("/Spectrum/WindowType"), windowType);
+
+   gPrefs->Write(wxT("/Spectrum/Grayscale"), isGrayscale);
+
+   gPrefs->Write(wxT("/Spectrum/ScaleType"), scaleType);
+
+#ifndef SPECTRAL_SELECTION_GLOBAL_SWITCH
+   gPrefs->Write(wxT("/Spectrum/EnableSpectralSelection"), spectralSelection);
+#endif
+
+   gPrefs->Write(wxT("/Spectrum/Algorithm"), algorithm);
+
+#ifdef EXPERIMENTAL_FFT_Y_GRID
+   gPrefs->Write(wxT("/Spectrum/FFTYGrid"), fftYGrid);
+#endif //EXPERIMENTAL_FFT_Y_GRID
+
+#ifdef EXPERIMENTAL_FIND_NOTES
+   gPrefs->Write(wxT("/Spectrum/FFTFindNotes"), fftFindNotes);
+   gPrefs->Write(wxT("/Spectrum/FindNotesMinA"), findNotesMinA);
+   gPrefs->Write(wxT("/Spectrum/FindNotesN"), numberOfMaxima);
+   gPrefs->Write(wxT("/Spectrum/FindNotesQuantize"), findNotesQuantize);
+#endif //EXPERIMENTAL_FIND_NOTES
+}
+
+void SpectrogramSettings::InvalidateCaches()
+{
+   DestroyWindows();
+}
+
+SpectrogramSettings::~SpectrogramSettings()
+{
+   DestroyWindows();
+}
+
+void SpectrogramSettings::DestroyWindows()
+{
+#ifdef EXPERIMENTAL_USE_REALFFTF
+   if (hFFT != NULL) {
+      EndFFT(hFFT);
+      hFFT = NULL;
+   }
+   if (window != NULL) {
+      delete[] window;
+      window = NULL;
+   }
+#endif
+}
+
+
+namespace
+{
+   enum { WINDOW, TWINDOW, DWINDOW };
+   void RecreateWindow(
+      float *&window, int which, int fftLen,
+      int padding, int windowType, int windowSize, double &scale)
+   {
+      if (window != NULL)
+         delete[] window;
+      // Create the requested window function
+      window = new float[fftLen];
+      int ii;
+
+      wxASSERT(windowSize % 2 == 0);
+      const int endOfWindow = padding + windowSize;
+      // Left and right padding
+      for (ii = 0; ii < padding; ++ii) {
+         window[ii] = 0.0;
+         window[fftLen - ii - 1] = 0.0;
+      }
+      // Default rectangular window in the middle
+      for (; ii < endOfWindow; ++ii)
+         window[ii] = 1.0;
+      // Overwrite middle as needed
+      switch (which) {
+      case WINDOW:
+         WindowFunc(windowType, windowSize, window + padding);
+         // NewWindowFunc(windowType, windowSize, extra, window + padding);
+         break;
+      case TWINDOW:
+         wxASSERT(false);
+#if 0
+         // Future, reassignment
+         NewWindowFunc(windowType, windowSize, extra, window + padding);
+         for (int ii = padding, multiplier = -windowSize / 2; ii < endOfWindow; ++ii, ++multiplier)
+            window[ii] *= multiplier;
+         break;
+#endif
+      case DWINDOW:
+         wxASSERT(false);
+#if 0
+         // Future, reassignment
+         DerivativeOfWindowFunc(windowType, windowSize, extra, window + padding);
+         break;
+#endif
+      default:
+         wxASSERT(false);
+      }
+      // Scale the window function to give 0dB spectrum for 0dB sine tone
+      if (which == WINDOW) {
+         scale = 0.0;
+         for (ii = padding; ii < endOfWindow; ++ii)
+            scale += window[ii];
+         if (scale > 0)
+            scale = 2.0 / scale;
+      }
+      for (ii = padding; ii < endOfWindow; ++ii)
+         window[ii] *= scale;
+   }
+}
+
+void SpectrogramSettings::CacheWindows() const
+{
+#ifdef EXPERIMENTAL_USE_REALFFTF
+   if (hFFT == NULL || window == NULL) {
+
+      double scale;
+      const int fftLen = windowSize * zeroPaddingFactor;
+      const int padding = (windowSize * (zeroPaddingFactor - 1)) / 2;
+
+      if (hFFT != NULL)
+         EndFFT(hFFT);
+      hFFT = InitializeFFT(fftLen);
+      RecreateWindow(window, WINDOW, fftLen, padding, windowType, windowSize, scale);
+   }
+#endif // EXPERIMENTAL_USE_REALFFTF
+}
+
+void SpectrogramSettings::ConvertToEnumeratedWindowSizes()
+{
+   unsigned size;
+   int logarithm;
+
+   logarithm = -LogMinWindowSize;
+   size = unsigned(windowSize);
+   while (size > 1)
+      size >>= 1, ++logarithm;
+   windowSize = std::max(0, std::min(NumWindowSizes - 1, logarithm));
+
+#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
+   // Choices for zero padding begin at 1
+   logarithm = 0;
+   size = unsigned(zeroPaddingFactor);
+   while (zeroPaddingFactor > 1)
+      zeroPaddingFactor >>= 1, ++logarithm;
+   zeroPaddingFactor = std::max(0,
+      std::min(LogMaxWindowSize - (windowSize + LogMinWindowSize),
+         logarithm
+   ));
+#endif
+}
+
+void SpectrogramSettings::ConvertToActualWindowSizes()
+{
+   windowSize = 1 << (windowSize + LogMinWindowSize);
+#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
+   zeroPaddingFactor = 1 << zeroPaddingFactor;
+#endif
+}
+
+int SpectrogramSettings::GetMinFreq(double rate) const
+{
+   const int top = lrint(rate / 2.);
+   return std::max(0, std::min(top, minFreq));
+}
+
+int SpectrogramSettings::GetMaxFreq(double rate) const
+{
+   const int top = lrint(rate / 2.);
+   if (maxFreq < 0)
+      return top;
+   else
+      return std::max(0, std::min(top, maxFreq));
+}
+
+int SpectrogramSettings::GetLogMinFreq(double rate) const
+{
+   const int top = lrint(rate / 2.);
+   if (logMinFreq < 0)
+      return top / 1000.0;
+   else
+      return std::max(1, std::min(top, logMinFreq));
+}
+
+int SpectrogramSettings::GetLogMaxFreq(double rate) const
+{
+   const int top = lrint(rate / 2.);
+   if (logMaxFreq < 0)
+      return top;
+   else
+      return std::max(1, std::min(top, logMaxFreq));
+}
+
+void SpectrogramSettings::SetMinFreq(int freq)
+{
+   minFreq = freq;
+}
+
+void SpectrogramSettings::SetMaxFreq(int freq)
+{
+   maxFreq = freq;
+}
+
+void SpectrogramSettings::SetLogMinFreq(int freq)
+{
+   logMinFreq = freq;
+}
+
+void SpectrogramSettings::SetLogMaxFreq(int freq)
+{
+   logMaxFreq = freq;
+}
+
+int SpectrogramSettings::GetFFTLength() const
+{
+   return windowSize
+#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
+      * ((algorithm == algSTFT) ? zeroPaddingFactor : 1);
+#endif
+   ;
+}
+
+NumberScale SpectrogramSettings::GetScale
+(double rate, bool bins) const
+{
+   int minFreq, maxFreq;
+   NumberScaleType type = nstLinear;
+   const int half = GetFFTLength() / 2;
+
+   // Don't assume the correspondence of the enums will remain direct in the future.
+   // Do this switch.
+   switch (scaleType) {
+   default:
+      wxASSERT(false);
+   case stLinear:
+      type = nstLinear; break;
+   case stLogarithmic:
+      type = nstLogarithmic; break;
+   case stMel:
+      type = nstMel; break;
+   case stBark:
+      type = nstBark; break;
+   case stErb:
+      type = nstErb; break;
+   case stUndertone:
+      type = nstUndertone; break;
+   }
+
+   switch (scaleType) {
+   default:
+      wxASSERT(false);
+   case stLinear:
+      minFreq = GetMinFreq(rate);
+      maxFreq = GetMaxFreq(rate);
+      break;
+   case stLogarithmic:
+   case stMel:
+   case stBark:
+   case stErb:
+      minFreq = GetLogMinFreq(rate);
+      maxFreq = GetLogMaxFreq(rate);
+      break;
+   case stUndertone:
+   {
+      const float bin2 = rate / half;
+      minFreq = std::max(int(0.5 + bin2), GetLogMinFreq(rate));
+      maxFreq = GetLogMaxFreq(rate);
+   }
+   break;
+   }
+
+   return NumberScale(type, minFreq, maxFreq,
+      bins ? rate / (2 * half) : 1.0f);
+}
+
+bool SpectrogramSettings::SpectralSelectionEnabled() const
+{
+#ifdef SPECTRAL_SELECTION_GLOBAL_SWITCH
+   return Globals::Get().spectralSelection;
+#else
+   return spectralSelection;
+#endif
+}
diff --git a/src/prefs/SpectrogramSettings.h b/src/prefs/SpectrogramSettings.h
new file mode 100644
index 0000000000000000000000000000000000000000..57c1cc58ab5437d58a593755a477d8419b570bd7
--- /dev/null
+++ b/src/prefs/SpectrogramSettings.h
@@ -0,0 +1,158 @@
+/**********************************************************************
+
+Audacity: A Digital Audio Editor
+
+SpectrogramSettings.h
+
+Paul Licameli
+
+**********************************************************************/
+
+#ifndef __AUDACITY_SPECTROGRAM_SETTINGS__
+#define __AUDACITY_SPECTROGRAM_SETTINGS__
+
+#include "../Experimental.h"
+
+#undef SPECTRAL_SELECTION_GLOBAL_SWITCH
+
+struct FFTParam;
+class NumberScale;
+class SpectrumPrefs;
+class wxArrayString;
+
+class SpectrogramSettings
+{
+   friend class SpectrumPrefs;
+public:
+
+   // Singleton for settings that are not per-track
+   class Globals
+   {
+   public:
+      static Globals &Get();
+      void SavePrefs();
+
+#ifdef SPECTRAL_SELECTION_GLOBAL_SWITCH
+      bool spectralSelection;
+#endif
+
+   private:
+      Globals();
+      void LoadPrefs();
+   };
+
+   enum {
+      LogMinWindowSize = 3,
+      LogMaxWindowSize = 15,
+
+      NumWindowSizes = LogMaxWindowSize - LogMinWindowSize + 1,
+   };
+
+   // Do not assume that this enumeration will remain the
+   // same as NumberScaleType in future.  That enum may become
+   // more general purpose.
+   enum ScaleType {
+      stLinear,
+      stLogarithmic,
+      stMel,
+      stBark,
+      stErb,
+      stUndertone,
+
+      stNumScaleTypes,
+   };
+
+   static void InvalidateNames(); // in case of language change
+   static const wxArrayString &GetScaleNames();
+   static const wxArrayString &GetAlgorithmNames();
+
+   static SpectrogramSettings &defaults();
+   SpectrogramSettings();
+   SpectrogramSettings(const SpectrogramSettings &other);
+   SpectrogramSettings& operator= (const SpectrogramSettings &other);
+   ~SpectrogramSettings();
+
+   bool IsDefault() const
+   {
+      return this == &defaults();
+   }
+
+   bool Validate(bool quiet);
+   void LoadPrefs();
+   void SavePrefs();
+   void InvalidateCaches();
+   void DestroyWindows();
+   void CacheWindows() const;
+   void ConvertToEnumeratedWindowSizes();
+   void ConvertToActualWindowSizes();
+
+   // If "bins" is false, units are Hz
+   NumberScale GetScale
+      (double rate, bool bins) const;
+
+private:
+   int minFreq;
+   int maxFreq;
+   int logMinFreq;
+   int logMaxFreq;
+public:
+   int GetMinFreq(double rate) const;
+   int GetMaxFreq(double rate) const;
+   int GetLogMinFreq(double rate) const;
+   int GetLogMaxFreq(double rate) const;
+   bool SpectralSelectionEnabled() const;
+
+   void SetMinFreq(int freq);
+   void SetMaxFreq(int freq);
+   void SetLogMinFreq(int freq);
+   void SetLogMaxFreq(int freq);
+
+public:
+   int range;
+   int gain;
+   int frequencyGain;
+
+   int windowType;
+   int windowSize;
+#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
+   int zeroPaddingFactor;
+#endif
+
+   int GetFFTLength() const; // window size (times zero padding, if STFT)
+
+   bool isGrayscale;
+
+   ScaleType scaleType;
+
+#ifndef SPECTRAL_SELECTION_GLOBAL_SWITCH
+   bool spectralSelection; // But should this vary per track? -- PRL
+#endif
+
+   enum Algorithm {
+      algSTFT = 0,
+      algPitchEAC,
+
+      algNumAlgorithms,
+   };
+   Algorithm algorithm;
+
+#ifdef EXPERIMENTAL_FFT_Y_GRID
+   bool fftYGrid;
+#endif //EXPERIMENTAL_FFT_Y_GRID
+
+#ifdef EXPERIMENTAL_FIND_NOTES
+   bool fftFindNotes;
+   bool findNotesMinA;
+   bool numberOfMaxima;
+   bool findNotesQuantize;
+#endif //EXPERIMENTAL_FIND_NOTES
+
+   // Following fields are derived from preferences.
+
+#ifdef EXPERIMENTAL_USE_REALFFTF
+   // Variables used for computing the spectrum
+   mutable FFTParam      *hFFT;
+   mutable float         *window;
+#endif
+};
+#endif
diff --git a/src/prefs/SpectrumPrefs.cpp b/src/prefs/SpectrumPrefs.cpp
index 118df5a384dc6dc7fb02fb9eae21039cd9106808..80564c71b921a79f279e197b36c7bbab04828427 100644
--- a/src/prefs/SpectrumPrefs.cpp
+++ b/src/prefs/SpectrumPrefs.cpp
@@ -20,18 +20,33 @@
 #include <wx/defs.h>
 #include <wx/intl.h>
 #include <wx/msgdlg.h>
+#include <wx/checkbox.h>
 
-#include "../Prefs.h"
+#include "../FFT.h"
 #include "../Project.h"
 #include "../ShuttleGui.h"
-#include "../FFT.h"
+#include "../WaveTrack.h"
+#include "../TrackPanel.h"
 
 #include <algorithm>
 
-SpectrumPrefs::SpectrumPrefs(wxWindow * parent)
+SpectrumPrefs::SpectrumPrefs(wxWindow * parent, WaveTrack *wt)
 :  PrefsPanel(parent, _("Spectrograms"))
+, mWt(wt)
+, mPopulating(false)
 {
-   int windowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256);
+   if (mWt) {
+      SpectrogramSettings &settings = wt->GetSpectrogramSettings();
+      mDefaulted = (&SpectrogramSettings::defaults() == &settings);
+      mTempSettings = settings;
+   }
+   else  {
+      mTempSettings = SpectrogramSettings::defaults();
+      mDefaulted = false;
+   }
+
+   const int windowSize = mTempSettings.windowSize;
+   mTempSettings.ConvertToEnumeratedWindowSizes();
    Populate(windowSize);
 }
 
@@ -39,13 +54,23 @@ SpectrumPrefs::~SpectrumPrefs()
 {
 }
 
-enum { maxWindowSize = 32768 };
-
 enum {
    ID_WINDOW_SIZE = 10001,
 #ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
-   ID_PADDING_SIZE = 10002,
+   ID_WINDOW_TYPE,
+   ID_PADDING_SIZE,
+   ID_SCALE,
+   ID_ALGORITHM,
+   ID_MINIMUM,
+   ID_MAXIMUM,
+   ID_GAIN,
+   ID_RANGE,
+   ID_FREQUENCY_GAIN,
+   ID_GRAYSCALE,
+   ID_SPECTRAL_SELECTION,
 #endif
+   ID_DEFAULTS,
+   ID_APPLY,
 };
 
 void SpectrumPrefs::Populate(int windowSize)
@@ -63,26 +88,21 @@ void SpectrumPrefs::Populate(int windowSize)
    mSizeChoices.Add(wxT("8192"));
    mSizeChoices.Add(wxT("16384"));
    mSizeChoices.Add(_("32768 - most narrowband"));
-
-   int lastCode = 0;
-   for (size_t i = 0; i < mSizeChoices.GetCount(); i++) {
-      mSizeCodes.Add(lastCode = 1 << (i + 3));
-   }
-   wxASSERT(lastCode == maxWindowSize);
+   wxASSERT(mSizeChoices.size() == SpectrogramSettings::NumWindowSizes);
 
    PopulatePaddingChoices(windowSize);
 
    for (int i = 0; i < NumWindowFuncs(); i++) {
       mTypeChoices.Add(WindowFuncName(i));
-      mTypeCodes.Add(i);
    }
 
+   mScaleChoices = SpectrogramSettings::GetScaleNames();
+
+   mAlgorithmChoices = SpectrogramSettings::GetAlgorithmNames();
 
    //------------------------- Main section --------------------
    // Now construct the GUI itself.
-   // Use 'eIsCreatingFromPrefs' so that the GUI is
-   // initialised with values from gPrefs.
-   ShuttleGui S(this, eIsCreatingFromPrefs);
+   ShuttleGui S(this, eIsCreating);
    PopulateOrExchange(S);
    // ----------------------- End of main section --------------
 }
@@ -107,14 +127,12 @@ void SpectrumPrefs::PopulatePaddingChoices(int windowSize)
       pPaddingSizeControl->Clear();
    }
 
-   mZeroPaddingCodes.Clear();
-
    int padding = 1;
    int numChoices = 0;
+   const int maxWindowSize = 1 << (SpectrogramSettings::LogMaxWindowSize);
    while (windowSize <= maxWindowSize) {
       const wxString numeral = wxString::Format(wxT("%d"), padding);
       mZeroPaddingChoices.Add(numeral);
-      mZeroPaddingCodes.Add(padding);
       if (pPaddingSizeControl)
          pPaddingSizeControl->Append(numeral);
       windowSize <<= 1;
@@ -131,174 +149,182 @@ void SpectrumPrefs::PopulatePaddingChoices(int windowSize)
 
 void SpectrumPrefs::PopulateOrExchange(ShuttleGui & S)
 {
+   mPopulating = true;
+
    S.SetBorder(2);
 
-   S.StartStatic(_("FFT Window"));
+   // S.StartStatic(_("Track Settings"));
    {
-      S.StartMultiColumn(2);
+      mDefaultsCheckbox = 0;
+      if (mWt) {
+         mDefaultsCheckbox = S.Id(ID_DEFAULTS).TieCheckBox(_("Defaults"), mDefaulted);
+      }
+      S.StartStatic(_("FFT Window"));
       {
-         S.Id(ID_WINDOW_SIZE).TieChoice(_("Window &size:"),
-                     wxT("/Spectrum/FFTSize"),
-                     256,
-                     mSizeChoices,
-                     mSizeCodes);
-         S.SetSizeHints(mSizeChoices);
-
-         S.TieChoice(_("Window &type:"),
-                     wxT("/Spectrum/WindowType"),
-                     3,
-                     mTypeChoices,
-                     mTypeCodes);
-         S.SetSizeHints(mTypeChoices);
+         S.StartMultiColumn(2);
+         {
+            S.Id(ID_WINDOW_SIZE).TieChoice(_("Window &size:"),
+               mTempSettings.windowSize,
+               &mSizeChoices);
+            S.SetSizeHints(mSizeChoices);
+
+            S.Id(ID_WINDOW_TYPE).TieChoice(_("Window &type:"),
+               mTempSettings.windowType,
+               &mTypeChoices);
+            S.SetSizeHints(mTypeChoices);
 
 #ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
-         S.Id(ID_PADDING_SIZE).TieChoice(_("&Zero padding factor") + wxString(wxT(":")),
-                     wxT("/Spectrum/ZeroPaddingFactor"),
-                     mZeroPaddingChoice,
-                     mZeroPaddingChoices,
-                     mZeroPaddingCodes);
-         S.SetSizeHints(mZeroPaddingChoices);
+            mZeroPaddingChoiceCtrl =
+            S.Id(ID_PADDING_SIZE).TieChoice(_("&Zero padding factor") + wxString(wxT(":")),
+               mTempSettings.zeroPaddingFactor,
+               &mZeroPaddingChoices);
+            S.SetSizeHints(mZeroPaddingChoices);
 #endif
+         }
+         S.EndMultiColumn();
       }
-      S.EndMultiColumn();
-   }
-   S.EndStatic();
+      S.EndStatic();
 
-   S.StartStatic(_("Display"));
-   {
-      S.StartTwoColumn();
+      S.StartStatic(_("Display"));
       {
-         mMinFreq =
-            S.TieNumericTextBox(_("Mi&nimum Frequency (Hz):"),
-                                wxT("/Spectrum/MinFreq"),
-                                0,
-                                12);
-
-         mMaxFreq =
-            S.TieNumericTextBox(_("Ma&ximum Frequency (Hz):"),
-                                wxT("/Spectrum/MaxFreq"),
-                                8000,
-                                12);
-
-         mGain =
-            S.TieNumericTextBox(_("&Gain (dB):"),
-                                wxT("/Spectrum/Gain"),
-                                20,
-                                8);
-
-         mRange =
-            S.TieNumericTextBox(_("&Range (dB):"),
-                                wxT("/Spectrum/Range"),
-                                80,
-                                8);
-
-         mFrequencyGain =
-            S.TieNumericTextBox(_("Frequency g&ain (dB/dec):"),
-                                wxT("/Spectrum/FrequencyGain"),
-                                0,
-                                4);
-      }
-      S.EndTwoColumn();
-
-      S.TieCheckBox(_("S&how the spectrum using grayscale colors"),
-                    wxT("/Spectrum/Grayscale"),
-                    false);
+         S.StartTwoColumn();
+         {
+            S.Id(ID_SCALE).TieChoice(_("S&cale") + wxString(wxT(":")),
+               *(int*)&mTempSettings.scaleType,
+               &mScaleChoices);
+
+            mAlgorithmChoice =
+            S.Id(ID_ALGORITHM).TieChoice(_("Algorithm") + wxString(wxT(":")),
+               *(int*)&mTempSettings.algorithm,
+               &mAlgorithmChoices);
+
+            mMinFreq =
+               S.Id(ID_MINIMUM).TieNumericTextBox(_("Mi&nimum Frequency (Hz):"),
+               mTempSettings.minFreq,
+               12);
+
+            mMaxFreq =
+               S.Id(ID_MAXIMUM).TieNumericTextBox(_("Ma&ximum Frequency (Hz):"),
+               mTempSettings.maxFreq,
+               12);
+
+            mGain =
+               S.Id(ID_GAIN).TieNumericTextBox(_("&Gain (dB):"),
+               mTempSettings.gain,
+               8);
+
+            mRange =
+               S.Id(ID_RANGE).TieNumericTextBox(_("&Range (dB):"),
+               mTempSettings.range,
+               8);
+
+            mFrequencyGain =
+               S.Id(ID_FREQUENCY_GAIN).TieNumericTextBox(_("Frequency g&ain (dB/dec):"),
+               mTempSettings.frequencyGain,
+               4);
+         }
+         S.EndTwoColumn();
+
+         S.Id(ID_GRAYSCALE).TieCheckBox(_("S&how the spectrum using grayscale colors"),
+            mTempSettings.isGrayscale);
+
+#ifndef SPECTRAL_SELECTION_GLOBAL_SWITCH
+         S.Id(ID_SPECTRAL_SELECTION).TieCheckBox(_("Ena&ble spectral selection"),
+            mTempSettings.spectralSelection);
+#endif
 
 #ifdef EXPERIMENTAL_FFT_Y_GRID
-      S.TieCheckBox(_("Show a grid along the &Y-axis"),
-                    wxT("/Spectrum/FFTYGrid"),
-                    false);
+         S.TieCheckBox(_("Show a grid along the &Y-axis"),
+            mTempSettings.fftYGrid);
 #endif //EXPERIMENTAL_FFT_Y_GRID
-   }
-   S.EndStatic();
+      }
+      S.EndStatic();
 
 #ifdef EXPERIMENTAL_FIND_NOTES
-   /* i18n-hint: FFT stands for Fast Fourier Transform and probably shouldn't be translated*/
-   S.StartStatic(_("FFT Find Notes"));
-   {
-      S.StartTwoColumn();
+      /* i18n-hint: FFT stands for Fast Fourier Transform and probably shouldn't be translated*/
+      S.StartStatic(_("FFT Find Notes"));
       {
-         mFindNotesMinA =
-            S.TieNumericTextBox(_("Minimum Amplitude (dB):"),
-                                wxT("/Spectrum/FindNotesMinA"),
-                                -30L,
-                                8);
-
-         mFindNotesN =
-            S.TieNumericTextBox(_("Max. Number of Notes (1..128):"),
-                                wxT("/Spectrum/FindNotesN"),
-                                5L,
-                                8);
+         S.StartTwoColumn();
+         {
+            mFindNotesMinA =
+               S.TieNumericTextBox(_("Minimum Amplitude (dB):"),
+               mTempSettings.fftFindNotes,
+               8);
+
+            mFindNotesN =
+               S.TieNumericTextBox(_("Max. Number of Notes (1..128):"),
+               mTempSettings.findNotesMinA,
+               8);
+         }
+         S.EndTwoColumn();
+
+         S.TieCheckBox(_("&Find Notes"),
+            mTempSettings.numberOfMaxima);
+
+         S.TieCheckBox(_("&Quantize Notes"),
+            mTempSettings.findNotesQuantize);
       }
-      S.EndTwoColumn();
-
-      S.TieCheckBox(_("&Find Notes"),
-                    wxT("/Spectrum/FFTFindNotes"),
-                    false);
+      S.EndStatic();
+#endif //EXPERIMENTAL_FIND_NOTES
+   }
+   // S.EndStatic();
 
-      S.TieCheckBox(_("&Quantize Notes"),
-                    wxT("/Spectrum/FindNotesQuantize"),
-                    false);
+#ifdef SPECTRAL_SELECTION_GLOBAL_SWITCH
+   S.StartStatic(_("Global settings"));
+   {
+      S.TieCheckBox(_("Ena&ble spectral selection"),
+         SpectrogramSettings::Globals::Get().spectralSelection);
    }
    S.EndStatic();
-#endif //EXPERIMENTAL_FIND_NOTES
+#endif
+
+   S.StartMultiColumn(2, wxALIGN_RIGHT);
+   {
+      S.Id(ID_APPLY).AddButton(_("Appl&y"));
+   }
+   S.EndMultiColumn();
+
+   EnableDisableSTFTOnlyControls();
+
+   mPopulating = false;
 }
 
 bool SpectrumPrefs::Validate()
 {
+   // Do checking for whole numbers
+
+   // ToDo: use wxIntegerValidator<unsigned> when available
+
    long maxFreq;
    if (!mMaxFreq->GetValue().ToLong(&maxFreq)) {
       wxMessageBox(_("The maximum frequency must be an integer"));
       return false;
    }
-   if (maxFreq < 100) {
-      wxMessageBox(_("Maximum frequency must be 100 Hz or above"));
-      return false;
-   }
 
    long minFreq;
    if (!mMinFreq->GetValue().ToLong(&minFreq)) {
       wxMessageBox(_("The minimum frequency must be an integer"));
       return false;
    }
-   if (minFreq < 0) {
-      wxMessageBox(_("Minimum frequency must be at least 0 Hz"));
-      return false;
-   }
-
-   if (maxFreq < minFreq) {
-      wxMessageBox(_("Minimum frequency must be less than maximum frequency"));
-      return false;
-   }
 
    long gain;
    if (!mGain->GetValue().ToLong(&gain)) {
       wxMessageBox(_("The gain must be an integer"));
       return false;
    }
+
    long range;
    if (!mRange->GetValue().ToLong(&range)) {
       wxMessageBox(_("The range must be a positive integer"));
       return false;
    }
-   if (range <= 0) {
-      wxMessageBox(_("The range must be at least 1 dB"));
-      return false;
-   }
 
    long frequencygain;
    if (!mFrequencyGain->GetValue().ToLong(&frequencygain)) {
       wxMessageBox(_("The frequency gain must be an integer"));
       return false;
    }
-   if (frequencygain < 0) {
-      wxMessageBox(_("The frequency gain cannot be negative"));
-      return false;
-   }
-   if (frequencygain > 60) {
-      wxMessageBox(_("The frequency gain must be no more than 60 dB/dec"));
-      return false;
-   }
+
 #ifdef EXPERIMENTAL_FIND_NOTES
    long findNotesMinA;
    if (!mFindNotesMinA->GetValue().ToLong(&findNotesMinA)) {
@@ -317,199 +343,155 @@ bool SpectrumPrefs::Validate()
    }
 #endif //EXPERIMENTAL_FIND_NOTES
 
-   return true;
+   ShuttleGui S(this, eIsGettingFromDialog);
+   PopulateOrExchange(S);
+
+   // Delegate range checking to SpectrogramSettings class
+   mTempSettings.ConvertToActualWindowSizes();
+   const bool result = mTempSettings.Validate(false);
+   mTempSettings.ConvertToEnumeratedWindowSizes();
+   return result;
 }
 
 bool SpectrumPrefs::Apply()
 {
-   ShuttleGui S(this, eIsSavingToPrefs);
+   const bool isOpenPage = this->IsShown();
+
+   WaveTrack *const partner =
+      mWt ? static_cast<WaveTrack*>(mWt->GetLink()) : 0;
+
+   ShuttleGui S(this, eIsGettingFromDialog);
    PopulateOrExchange(S);
 
-   SpectrogramSettings::defaults().UpdatePrefs();
+
+   mTempSettings.ConvertToActualWindowSizes();
+   SpectrogramSettings::Globals::Get().SavePrefs(); // always
+
+   if (mWt) {
+      if (mDefaulted) {
+         mWt->SetSpectrogramSettings(NULL);
+         if (partner)
+            partner->SetSpectrogramSettings(NULL);
+      }
+      else {
+         SpectrogramSettings *pSettings =
+            &mWt->GetIndependentSpectrogramSettings();
+         *pSettings = mTempSettings;
+         if (partner) {
+            pSettings = &partner->GetIndependentSpectrogramSettings();
+            *pSettings = mTempSettings;
+         }
+      }
+   }
+
+   if (!mWt || mDefaulted) {
+      SpectrogramSettings *const pSettings = &SpectrogramSettings::defaults();
+      *pSettings = mTempSettings;
+      pSettings->SavePrefs();
+   }
+   mTempSettings.ConvertToEnumeratedWindowSizes();
+
+   if (mWt && isOpenPage) {
+      // Future: open page will determine the track view type
+      mWt->SetDisplay(WaveTrack::Spectrum);
+      if (partner)
+         partner->SetDisplay(WaveTrack::Spectrum);
+   }
 
    return true;
 }
 
-void SpectrumPrefs::OnWindowSize(wxCommandEvent &)
+void SpectrumPrefs::OnControl(wxCommandEvent&)
 {
+   // Common routine for most controls
+   // If any per-track setting is changed, break the association with defaults
+   // Skip this, and View Settings... will be able to change defaults instead
+   // when the checkbox is on, as in the original design.
+
+   if (mDefaultsCheckbox && !mPopulating) {
+      mDefaulted = false;
+      mDefaultsCheckbox->SetValue(false);
+   }
+}
+
+void SpectrumPrefs::OnWindowSize(wxCommandEvent &evt)
+{
+   // Restrict choice of zero padding, so that product of window
+   // size and padding may not exceed the largest window size.
    wxChoice *const pWindowSizeControl =
       static_cast<wxChoice*>(wxWindow::FindWindowById(ID_WINDOW_SIZE, this));
-   int windowSize = 1 << (pWindowSizeControl->GetSelection() + 3);
+   int windowSize = 1 <<
+      (pWindowSizeControl->GetSelection() + SpectrogramSettings::LogMinWindowSize);
    PopulatePaddingChoices(windowSize);
-}
 
-BEGIN_EVENT_TABLE(SpectrumPrefs, PrefsPanel)
-   EVT_CHOICE(ID_WINDOW_SIZE, SpectrumPrefs::OnWindowSize)
-END_EVENT_TABLE()
+   // Do the common part
+   OnControl(evt);
+}
 
-SpectrogramSettings::SpectrogramSettings()
-: hFFT(0)
-, window(0)
+void SpectrumPrefs::OnDefaults(wxCommandEvent &)
 {
-   UpdatePrefs();
+   if (mDefaultsCheckbox->IsChecked()) {
+      mTempSettings = SpectrogramSettings::defaults();
+      mTempSettings.ConvertToEnumeratedWindowSizes();
+      mDefaulted = true;
+      ShuttleGui S(this, eIsSettingToDialog);
+      PopulateOrExchange(S);
+   }
 }
 
-SpectrogramSettings& SpectrogramSettings::defaults()
+void SpectrumPrefs::OnAlgorithm(wxCommandEvent &evt)
 {
-   static SpectrogramSettings instance;
-   return instance;
+   EnableDisableSTFTOnlyControls();
+   OnControl(evt);
 }
 
-void SpectrogramSettings::UpdatePrefs()
+void SpectrumPrefs::EnableDisableSTFTOnlyControls()
 {
-   bool destroy = false;
-
-   minFreq = gPrefs->Read(wxT("/Spectrum/MinFreq"), -1L);
-   maxFreq = gPrefs->Read(wxT("/Spectrum/MaxFreq"), 8000L);
-
-   // These preferences are not written anywhere in the program as of now,
-   // but I keep this legacy here.  Who knows, someone might edit prefs files
-   // directly.  PRL
-   logMaxFreq = gPrefs->Read(wxT("/SpectrumLog/MaxFreq"), -1);
-   if (logMaxFreq < 0)
-      logMaxFreq = maxFreq;
-   logMinFreq = gPrefs->Read(wxT("/SpectrumLog/MinFreq"), -1);
-   if (logMinFreq < 0)
-      logMinFreq = minFreq;
-   if (logMinFreq < 1)
-      logMinFreq = 1;
-
-   range = gPrefs->Read(wxT("/Spectrum/Range"), 80L);
-   gain = gPrefs->Read(wxT("/Spectrum/Gain"), 20L);
-   frequencyGain = gPrefs->Read(wxT("/Spectrum/FrequencyGain"), 0L);
-
-   const int newWindowSize = gPrefs->Read(wxT("/Spectrum/FFTSize"), 256);
-   if (newWindowSize != windowSize) {
-      destroy = true;
-      windowSize = newWindowSize;
-   }
-
+   // Enable or disable other controls that are applicable only to STFT.
+   const bool STFT = (mAlgorithmChoice->GetSelection() == 0);
+   mGain->Enable(STFT);
+   mRange->Enable(STFT);
+   mFrequencyGain->Enable(STFT);
 #ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
-   const int newZeroPaddingFactor = gPrefs->Read(wxT("/Spectrum/ZeroPaddingFactor"), 1);
-   if (newZeroPaddingFactor != zeroPaddingFactor) {
-      destroy = true;
-      zeroPaddingFactor = newZeroPaddingFactor;
-   }
+   mZeroPaddingChoiceCtrl->Enable(STFT);
 #endif
-
-   int newWindowType;
-   gPrefs->Read(wxT("/Spectrum/WindowType"), &newWindowType, 3);
-   if (newWindowType != windowType) {
-      destroy = true;
-      windowType = newWindowType;
-   }
-
-   isGrayscale = (gPrefs->Read(wxT("/Spectrum/Grayscale"), 0L) != 0);
-
-#ifdef EXPERIMENTAL_FFT_Y_GRID
-   fftYGrid = (gPrefs->Read(wxT("/Spectrum/FFTYGrid"), 0L) != 0);
-#endif //EXPERIMENTAL_FFT_Y_GRID
-
-#ifdef EXPERIMENTAL_FIND_NOTES
-   fftFindNotes = (gPrefs->Read(wxT("/Spectrum/FFTFindNotes"), 0L) != 0);
-   findNotesMinA = gPrefs->Read(wxT("/Spectrum/FindNotesMinA"), -30.0);
-   numberOfMaxima = gPrefs->Read(wxT("/Spectrum/FindNotesN"), 5L);
-   findNotesQuantize = (gPrefs->Read(wxT("/Spectrum/FindNotesQuantize"), 0L) != 0);
-#endif //EXPERIMENTAL_FIND_NOTES
-
-   if (destroy)
-      DestroyWindows();
 }
 
-SpectrogramSettings::~SpectrogramSettings()
+void SpectrumPrefs::OnApply(wxCommandEvent &)
 {
-   DestroyWindows();
-}
-
-void SpectrogramSettings::DestroyWindows()
-{
-#ifdef EXPERIMENTAL_USE_REALFFTF
-   if (hFFT != NULL) {
-      EndFFT(hFFT);
-      hFFT = NULL;
+   if (Validate()) {
+      Apply();
+      ::GetActiveProject()->GetTrackPanel()->Refresh(false);
    }
-   if (window != NULL) {
-      delete[] window;
-      window = NULL;
-   }
-#endif
 }
 
+BEGIN_EVENT_TABLE(SpectrumPrefs, PrefsPanel)
+   EVT_CHOICE(ID_WINDOW_SIZE, SpectrumPrefs::OnWindowSize)
+   EVT_CHECKBOX(ID_DEFAULTS, SpectrumPrefs::OnDefaults)
+   EVT_CHOICE(ID_ALGORITHM, SpectrumPrefs::OnAlgorithm)
+
+   // Several controls with common routine that unchecks the default box
+   EVT_CHOICE(ID_WINDOW_TYPE, SpectrumPrefs::OnControl)
+   EVT_CHOICE(ID_PADDING_SIZE, SpectrumPrefs::OnControl)
+   EVT_CHOICE(ID_SCALE, SpectrumPrefs::OnControl)
+   EVT_TEXT(ID_MINIMUM, SpectrumPrefs::OnControl)
+   EVT_TEXT(ID_MAXIMUM, SpectrumPrefs::OnControl)
+   EVT_TEXT(ID_GAIN, SpectrumPrefs::OnControl)
+   EVT_TEXT(ID_RANGE, SpectrumPrefs::OnControl)
+   EVT_TEXT(ID_FREQUENCY_GAIN, SpectrumPrefs::OnControl)
+   EVT_CHECKBOX(ID_GRAYSCALE, SpectrumPrefs::OnControl)
+   EVT_CHECKBOX(ID_SPECTRAL_SELECTION, SpectrumPrefs::OnControl)
+
+   EVT_BUTTON(ID_APPLY, SpectrumPrefs::OnApply)
+
+END_EVENT_TABLE()
 
-namespace
+SpectrumPrefsFactory::SpectrumPrefsFactory(WaveTrack *wt)
+: mWt(wt)
 {
-   enum { WINDOW, TWINDOW, DWINDOW };
-   void RecreateWindow(
-      float *&window, int which, int fftLen,
-      int padding, int windowType, int windowSize, double &scale)
-   {
-      if (window != NULL)
-         delete[] window;
-      // Create the requested window function
-      window = new float[fftLen];
-      int ii;
-
-      wxASSERT(windowSize % 2 == 0);
-      const int endOfWindow = padding + windowSize;
-      // Left and right padding
-      for (ii = 0; ii < padding; ++ii) {
-         window[ii] = 0.0;
-         window[fftLen - ii - 1] = 0.0;
-      }
-      // Default rectangular window in the middle
-      for (; ii < endOfWindow; ++ii)
-         window[ii] = 1.0;
-      // Overwrite middle as needed
-      switch (which) {
-      case WINDOW:
-         WindowFunc(windowType, windowSize, window + padding);
-         // NewWindowFunc(windowType, windowSize, extra, window + padding);
-         break;
-      case TWINDOW:
-         wxASSERT(false);
-#if 0
-         // Future, reassignment
-         NewWindowFunc(windowType, windowSize, extra, window + padding);
-         for (int ii = padding, multiplier = -windowSize / 2; ii < endOfWindow; ++ii, ++multiplier)
-            window[ii] *= multiplier;
-         break;
-#endif
-      case DWINDOW:
-         wxASSERT(false);
-#if 0
-         // Future, reassignment
-         DerivativeOfWindowFunc(windowType, windowSize, extra, window + padding);
-         break;
-#endif
-      default:
-         wxASSERT(false);
-      }
-      // Scale the window function to give 0dB spectrum for 0dB sine tone
-      if (which == WINDOW) {
-         scale = 0.0;
-         for (ii = padding; ii < endOfWindow; ++ii)
-            scale += window[ii];
-         if (scale > 0)
-            scale = 2.0 / scale;
-      }
-      for (ii = padding; ii < endOfWindow; ++ii)
-         window[ii] *= scale;
-   }
 }
 
-void SpectrogramSettings::CacheWindows() const
+PrefsPanel *SpectrumPrefsFactory::Create(wxWindow *parent)
 {
-#ifdef EXPERIMENTAL_USE_REALFFTF
-   if (hFFT == NULL || window == NULL) {
-
-      double scale;
-      const int fftLen = windowSize * zeroPaddingFactor;
-      const int padding = (windowSize * (zeroPaddingFactor - 1)) / 2;
-
-      if (hFFT != NULL)
-         EndFFT(hFFT);
-      hFFT = InitializeFFT(fftLen);
-      RecreateWindow(window, WINDOW, fftLen, padding, windowType, windowSize, scale);
-   }
-#endif // EXPERIMENTAL_USE_REALFFTF
+   return new SpectrumPrefs(parent, mWt);
 }
diff --git a/src/prefs/SpectrumPrefs.h b/src/prefs/SpectrumPrefs.h
index 20a1e7385d0fe7453c235fa1f251638d21195da9..84feb2869e95b87f5e0137522b8c368f72e51718 100644
--- a/src/prefs/SpectrumPrefs.h
+++ b/src/prefs/SpectrumPrefs.h
@@ -28,15 +28,20 @@
 #include "../Experimental.h"
 
 #include "PrefsPanel.h"
+#include "SpectrogramSettings.h"
 
+class wxChoice;
+class wxCheckBox;
 class wxTextCtrl;
 struct FFTParam;
 class ShuttleGui;
+class SpectrogramSettings;
+class WaveTrack;
 
 class SpectrumPrefs:public PrefsPanel
 {
  public:
-   SpectrumPrefs(wxWindow * parent);
+   SpectrumPrefs(wxWindow * parent, WaveTrack *wt);
    virtual ~SpectrumPrefs();
    virtual bool Apply();
    virtual bool Validate();
@@ -46,9 +51,18 @@ class SpectrumPrefs:public PrefsPanel
    void PopulatePaddingChoices(int windowSize);
    void PopulateOrExchange(ShuttleGui & S);
 
+   void OnControl(wxCommandEvent &event);
    void OnWindowSize(wxCommandEvent &event);
+   void OnDefaults(wxCommandEvent&);
+   void OnAlgorithm(wxCommandEvent &);
+   void OnApply(wxCommandEvent &);
    DECLARE_EVENT_TABLE()
 
+   void EnableDisableSTFTOnlyControls();
+
+   WaveTrack *const mWt;
+   bool mDefaulted;
+
    wxTextCtrl *mMinFreq;
    wxTextCtrl *mMaxFreq;
    wxTextCtrl *mGain;
@@ -56,72 +70,39 @@ class SpectrumPrefs:public PrefsPanel
    wxTextCtrl *mFrequencyGain;
 
    wxArrayString mSizeChoices;
-   wxArrayInt mSizeCodes;
 
 #ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
    int mZeroPaddingChoice;
+   wxChoice *mZeroPaddingChoiceCtrl;
    wxArrayString mZeroPaddingChoices;
-   wxArrayInt mZeroPaddingCodes;
 #endif
 
    wxArrayString mTypeChoices;
-   wxArrayInt mTypeCodes;
+   wxArrayString mScaleChoices;
+
+   wxChoice *mAlgorithmChoice;
+   wxArrayString mAlgorithmChoices;
 
 
 #ifdef EXPERIMENTAL_FIND_NOTES
    wxTextCtrl *mFindNotesMinA;
    wxTextCtrl *mFindNotesN;
 #endif
-};
-
-
-class SpectrogramSettings
-{
-public:
-   static SpectrogramSettings &defaults();
-   SpectrogramSettings();
-   ~SpectrogramSettings();
-
-   void UpdatePrefs();
-   void DestroyWindows();
-   void CacheWindows() const;
-
-   int minFreq;
-   int maxFreq;
 
-   int logMinFreq;
-   int logMaxFreq;
+   wxCheckBox *mDefaultsCheckbox;
 
-   int range;
-   int gain;
-   int frequencyGain;
+   SpectrogramSettings mTempSettings;
 
-   int windowType;
-   int windowSize;
-#ifdef EXPERIMENTAL_ZERO_PADDED_SPECTROGRAMS
-   int zeroPaddingFactor;
-#endif
-
-   bool isGrayscale;
+   bool mPopulating;
+};
 
-#ifdef EXPERIMENTAL_FFT_Y_GRID
-   bool fftYGrid;
-#endif //EXPERIMENTAL_FFT_Y_GRID
+class SpectrumPrefsFactory : public PrefsPanelFactory
+{
+public:
+   explicit SpectrumPrefsFactory(WaveTrack *wt = 0);
+   virtual PrefsPanel *Create(wxWindow *parent);
 
-#ifdef EXPERIMENTAL_FIND_NOTES
-   bool fftFindNotes;
-   bool findNotesMinA;
-   bool numberOfMaxima;
-   bool findNotesQuantize;
-#endif //EXPERIMENTAL_FIND_NOTES
-
-   // Following fields are derived from preferences.
-
-#ifdef EXPERIMENTAL_USE_REALFFTF
-   // Variables used for computing the spectrum
-   mutable FFTParam      *hFFT;
-   mutable float         *window;
-#endif
+private:
+   WaveTrack *const mWt;
 };
-
 #endif
diff --git a/src/prefs/ThemePrefs.cpp b/src/prefs/ThemePrefs.cpp
index 2cbfd7ba3c109ce741d15049add6bd1b2e9af69a..f6d947b3ed493b3dcf9b508eb950c37b3f7c393f 100644
--- a/src/prefs/ThemePrefs.cpp
+++ b/src/prefs/ThemePrefs.cpp
@@ -205,3 +205,8 @@ bool ThemePrefs::Apply()
 
    return true;
 }
+
+PrefsPanel *ThemePrefsFactory::Create(wxWindow *parent)
+{
+   return new ThemePrefs(parent);
+}
diff --git a/src/prefs/ThemePrefs.h b/src/prefs/ThemePrefs.h
index 40d080c8cf43cb18ce2c5215aa1ca21254e82db0..7668289d0d92af39b2bf1e2ffce3d46c40d092ea 100644
--- a/src/prefs/ThemePrefs.h
+++ b/src/prefs/ThemePrefs.h
@@ -41,4 +41,9 @@ class ThemePrefs :public PrefsPanel
    DECLARE_EVENT_TABLE();
 };
 
+class ThemePrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
 #endif
diff --git a/src/prefs/TracksPrefs.cpp b/src/prefs/TracksPrefs.cpp
index f94a322225a8c5e8772da6f63c29b26785714f20..495fc7ad40efa5c06b5b6c01c8c547b91e2e78e6 100644
--- a/src/prefs/TracksPrefs.cpp
+++ b/src/prefs/TracksPrefs.cpp
@@ -60,25 +60,10 @@ void TracksPrefs::Populate()
    // we don't display them by increasing integer values.
 
    mViewChoices.Add(_("Waveform"));
-   mViewCodes.Add(int(WaveTrack::WaveformDisplay));
+   mViewCodes.Add(int(WaveTrack::Waveform));
 
-   mViewChoices.Add(_("Waveform (dB)"));
-   mViewCodes.Add(int(WaveTrack::WaveformDBDisplay));
-
-   mViewChoices.Add(_("Spectrogram"));
-   mViewCodes.Add(int(WaveTrack::SpectrumDisplay));
-
-   mViewChoices.Add(_("Spectrogram log(f)"));
-   mViewCodes.Add(int(WaveTrack::SpectrumLogDisplay));
-
-   mViewChoices.Add(_("Spectral Selection"));
-   mViewCodes.Add(int(WaveTrack::SpectralSelectionDisplay));
-
-   mViewChoices.Add(_("Spectral Selection log(f)"));
-   mViewCodes.Add(int(WaveTrack::SpectralSelectionLogDisplay));
-
-   mViewChoices.Add(_("Pitch (EAC)"));
-   mViewCodes.Add(int(WaveTrack::PitchDisplay));
+   mViewChoices.Add(_("Spectrum"));
+   mViewCodes.Add(WaveTrack::Spectrum);
 
    //------------------------- Main section --------------------
    // Now construct the GUI itself.
@@ -165,3 +150,8 @@ bool TracksPrefs::Apply()
 
    return true;
 }
+
+PrefsPanel *TracksPrefsFactory::Create(wxWindow *parent)
+{
+   return new TracksPrefs(parent);
+}
diff --git a/src/prefs/TracksPrefs.h b/src/prefs/TracksPrefs.h
index aa0f54272e68a975812813f0f50a7a2d1a9bec58..be1baeaa0f56e13592c4690a0c9b3ef609540580 100644
--- a/src/prefs/TracksPrefs.h
+++ b/src/prefs/TracksPrefs.h
@@ -39,4 +39,9 @@ class TracksPrefs :public PrefsPanel
    wxArrayString mViewChoices;
 };
 
+class TracksPrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
 #endif
diff --git a/src/prefs/WarningsPrefs.cpp b/src/prefs/WarningsPrefs.cpp
index 68d344593b32de661b55f275b76d2624b72ae413..c0cb5b47b5d4b9e1dc129f25314e52aa95b739f6 100644
--- a/src/prefs/WarningsPrefs.cpp
+++ b/src/prefs/WarningsPrefs.cpp
@@ -83,3 +83,8 @@ bool WarningsPrefs::Apply()
 
    return true;
 }
+
+PrefsPanel *WarningsPrefsFactory::Create(wxWindow *parent)
+{
+   return new WarningsPrefs(parent);
+}
diff --git a/src/prefs/WarningsPrefs.h b/src/prefs/WarningsPrefs.h
index 8f789e163507fa37c7025aaefdde3fc56b4a670d..97e9605b6a65e53480917b37d457a37846267115 100644
--- a/src/prefs/WarningsPrefs.h
+++ b/src/prefs/WarningsPrefs.h
@@ -33,4 +33,9 @@ class WarningsPrefs :public PrefsPanel
    void PopulateOrExchange(ShuttleGui & S);
 };
 
+class WarningsPrefsFactory : public PrefsPanelFactory
+{
+public:
+   virtual PrefsPanel *Create(wxWindow *parent);
+};
 #endif
diff --git a/src/prefs/WaveformPrefs.cpp b/src/prefs/WaveformPrefs.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b29468947f5189e8b269bb21abbb6dd6a84d38c0
--- /dev/null
+++ b/src/prefs/WaveformPrefs.cpp
@@ -0,0 +1,215 @@
+/**********************************************************************
+
+Audacity: A Digital Audio Editor
+
+WaveformPrefs.cpp
+
+Paul Licameli
+
+*******************************************************************//**
+
+\class WaveformPrefs
+\brief A PrefsPanel for spectrum settings.
+
+*//*******************************************************************/
+
+#include "../Audacity.h"
+#include "WaveformPrefs.h"
+
+#include <wx/checkbox.h>
+
+#include "../Project.h"
+#include "../TrackPanel.h"
+#include "../ShuttleGui.h"
+#include "../WaveTrack.h"
+
+WaveformPrefs::WaveformPrefs(wxWindow * parent, WaveTrack *wt)
+: PrefsPanel(parent, _("Waveforms"))
+, mWt(wt)
+, mPopulating(false)
+{
+   if (mWt) {
+      WaveformSettings &settings = wt->GetWaveformSettings();
+      mDefaulted = (&WaveformSettings::defaults() == &settings);
+      mTempSettings = settings;
+   }
+   else  {
+      mTempSettings = WaveformSettings::defaults();
+      mDefaulted = false;
+   }
+
+   Populate();
+}
+
+WaveformPrefs::~WaveformPrefs()
+{
+}
+
+enum {
+   ID_DEFAULTS = 10001,
+   ID_APPLY,
+
+   ID_SCALE,
+};
+
+void WaveformPrefs::Populate()
+{
+   mScaleChoices = WaveformSettings::GetScaleNames();
+
+   //------------------------- Main section --------------------
+   // Now construct the GUI itself.
+   ShuttleGui S(this, eIsCreating);
+   PopulateOrExchange(S);
+   // ----------------------- End of main section --------------
+}
+
+void WaveformPrefs::PopulateOrExchange(ShuttleGui & S)
+{
+   mPopulating = true;
+
+   S.SetBorder(2);
+
+   // S.StartStatic(_("Track Settings"));
+   {
+      mDefaultsCheckbox = 0;
+      if (mWt) {
+         mDefaultsCheckbox = S.Id(ID_DEFAULTS).TieCheckBox(_("Defaults"), mDefaulted);
+      }
+
+      S.StartStatic(_("Display"));
+      {
+         S.StartTwoColumn();
+         {
+            S.Id(ID_SCALE).TieChoice(_("S&cale") + wxString(wxT(":")),
+               *(int*)&mTempSettings.scaleType,
+               &mScaleChoices);
+         }
+         S.EndTwoColumn();
+      }
+      S.EndStatic();
+   }
+   // S.EndStatic();
+
+   /*
+   S.StartStatic(_("Global settings"));
+   {
+   }
+   S.EndStatic();
+   */
+
+   S.StartMultiColumn(2, wxALIGN_RIGHT);
+   {
+      S.Id(ID_APPLY).AddButton(_("Appl&y"));
+   }
+   S.EndMultiColumn();
+
+   mPopulating = false;
+}
+
+bool WaveformPrefs::Validate()
+{
+   // Do checking for whole numbers
+
+   // ToDo: use wxIntegerValidator<unsigned> when available
+
+   ShuttleGui S(this, eIsGettingFromDialog);
+   PopulateOrExchange(S);
+
+   // Delegate range checking to WaveformSettings class
+   const bool result = mTempSettings.Validate(false);
+   return result;
+}
+
+bool WaveformPrefs::Apply()
+{
+   const bool isOpenPage = this->IsShown();
+
+   WaveTrack *const partner =
+      mWt ? static_cast<WaveTrack*>(mWt->GetLink()) : 0;
+
+   ShuttleGui S(this, eIsGettingFromDialog);
+   PopulateOrExchange(S);
+
+   WaveformSettings::Globals::Get().SavePrefs();
+
+   if (mWt) {
+      if (mDefaulted) {
+         mWt->SetWaveformSettings(NULL);
+         if (partner)
+            partner->SetWaveformSettings(NULL);
+      }
+      else {
+         WaveformSettings *pSettings =
+            &mWt->GetIndependentWaveformSettings();
+         *pSettings = mTempSettings;
+         if (partner) {
+            pSettings = &partner->GetIndependentWaveformSettings();
+            *pSettings = mTempSettings;
+         }
+      }
+   }
+
+   if (!mWt || mDefaulted) {
+      WaveformSettings *const pSettings =
+         &WaveformSettings::defaults();
+      *pSettings = mTempSettings;
+      pSettings->SavePrefs();
+   }
+
+   if (mWt && isOpenPage) {
+      mWt->SetDisplay(WaveTrack::Waveform);
+      if (partner)
+         partner->SetDisplay(WaveTrack::Waveform);
+   }
+
+   return true;
+}
+
+void WaveformPrefs::OnControl(wxCommandEvent&)
+{
+   // Common routine for most controls
+   // If any per-track setting is changed, break the association with defaults
+   // Skip this, and View Settings... will be able to change defaults instead
+   // when the checkbox is on, as in the original design.
+
+   if (mDefaultsCheckbox && !mPopulating) {
+      mDefaulted = false;
+      mDefaultsCheckbox->SetValue(false);
+   }
+}
+
+void WaveformPrefs::OnDefaults(wxCommandEvent &)
+{
+   if (mDefaultsCheckbox->IsChecked()) {
+      mTempSettings = WaveformSettings::defaults();
+      mDefaulted = true;
+      ShuttleGui S(this, eIsSettingToDialog);
+      PopulateOrExchange(S);
+   }
+}
+
+void WaveformPrefs::OnApply(wxCommandEvent &)
+{
+   if (Validate()) {
+      Apply();
+      ::GetActiveProject()->GetTrackPanel()->Refresh(false);
+   }
+}
+
+BEGIN_EVENT_TABLE(WaveformPrefs, PrefsPanel)
+
+EVT_CHOICE(ID_SCALE, WaveformPrefs::OnControl)
+
+EVT_CHECKBOX(ID_DEFAULTS, WaveformPrefs::OnDefaults)
+EVT_BUTTON(ID_APPLY, WaveformPrefs::OnApply)
+END_EVENT_TABLE()
+
+WaveformPrefsFactory::WaveformPrefsFactory(WaveTrack *wt)
+: mWt(wt)
+{
+}
+
+PrefsPanel *WaveformPrefsFactory::Create(wxWindow *parent)
+{
+   return new WaveformPrefs(parent, mWt);
+}
diff --git a/src/prefs/WaveformPrefs.h b/src/prefs/WaveformPrefs.h
new file mode 100644
index 0000000000000000000000000000000000000000..9d119c1c63ef54d9beeaf79987390064efd2cfbc
--- /dev/null
+++ b/src/prefs/WaveformPrefs.h
@@ -0,0 +1,60 @@
+/**********************************************************************
+
+Audacity: A Digital Audio Editor
+
+WaveformPrefs.h
+
+Paul Licameli
+
+**********************************************************************/
+
+
+#ifndef __AUDACITY_WAVEFORM_PREFS__
+#define __AUDACITY_WAVEFORM_PREFS__
+
+#include "PrefsPanel.h"
+#include "WaveformSettings.h"
+
+class ShuttleGui;
+class WaveTrack;
+class wxCheckBox;
+
+class WaveformPrefs :public PrefsPanel
+{
+public:
+   WaveformPrefs(wxWindow * parent, WaveTrack *wt);
+   virtual ~WaveformPrefs();
+   virtual bool Apply();
+   virtual bool Validate();
+
+private:
+   void Populate();
+   void PopulateOrExchange(ShuttleGui & S);
+
+   void OnControl(wxCommandEvent&);
+   void OnDefaults(wxCommandEvent&);
+   void OnApply(wxCommandEvent &);
+   DECLARE_EVENT_TABLE()
+
+   WaveTrack *const mWt;
+   bool mDefaulted;
+
+   wxCheckBox *mDefaultsCheckbox;
+
+   wxArrayString mScaleChoices;
+
+   WaveformSettings mTempSettings;
+
+   bool mPopulating;
+};
+
+class WaveformPrefsFactory : public PrefsPanelFactory
+{
+public:
+   explicit WaveformPrefsFactory(WaveTrack *wt = 0);
+   virtual PrefsPanel *Create(wxWindow *parent);
+
+private:
+   WaveTrack *const mWt;
+};
+#endif
diff --git a/src/prefs/WaveformSettings.cpp b/src/prefs/WaveformSettings.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3aa15f4bfde032534a0f136d0f10723855efc335
--- /dev/null
+++ b/src/prefs/WaveformSettings.cpp
@@ -0,0 +1,129 @@
+/**********************************************************************
+
+Audacity: A Digital Audio Editor
+
+WaveformSettings.cpp
+
+Paul Licameli
+
+*******************************************************************//**
+
+\class WaveformSettings
+\brief Waveform settings, either for one track or as defaults.
+
+*//*******************************************************************/
+
+#include "../Audacity.h"
+#include "WaveformSettings.h"
+
+#include <algorithm>
+#include <wx/intl.h>
+
+#include "../Prefs.h"
+
+WaveformSettings::Globals::Globals()
+{
+   LoadPrefs();
+}
+
+void WaveformSettings::Globals::SavePrefs()
+{
+}
+
+void WaveformSettings::Globals::LoadPrefs()
+{
+}
+
+WaveformSettings::Globals
+&WaveformSettings::Globals::Get()
+{
+   static Globals instance;
+   return instance;
+}
+
+WaveformSettings::WaveformSettings()
+{
+   LoadPrefs();
+}
+
+WaveformSettings::WaveformSettings(const WaveformSettings &other)
+   : scaleType(other.scaleType)
+{
+}
+
+WaveformSettings &WaveformSettings::operator= (const WaveformSettings &other)
+{
+   if (this != &other) {
+      scaleType = other.scaleType;
+   }
+   return *this;
+}
+
+WaveformSettings& WaveformSettings::defaults()
+{
+   static WaveformSettings instance;
+   return instance;
+}
+
+bool WaveformSettings::Validate(bool quiet)
+{
+   quiet;
+
+   scaleType = ScaleType(
+      std::max(0, std::min(int(stNumScaleTypes) - 1, int(scaleType)))
+   );
+
+   return true;
+}
+
+void WaveformSettings::LoadPrefs()
+{
+   scaleType = ScaleType(gPrefs->Read(wxT("/Waveform/ScaleType"), 0L));
+
+   // Enforce legal values
+   Validate(true);
+
+   Update();
+}
+
+void WaveformSettings::SavePrefs()
+{
+   gPrefs->Write(wxT("/Waveform/ScaleType"), long(scaleType));
+}
+
+void WaveformSettings::Update()
+{
+}
+
+namespace
+{
+   wxArrayString &scaleNamesArray()
+   {
+      static wxArrayString theArray;
+      return theArray;
+   }
+}
+
+//static
+void WaveformSettings::InvalidateNames()
+{
+   scaleNamesArray().Clear();
+}
+
+//static
+const wxArrayString &WaveformSettings::GetScaleNames()
+{
+   wxArrayString &theArray = scaleNamesArray();
+
+   if (theArray.IsEmpty()) {
+      // Keep in correspondence with enum WaveTrack::WaveTrackDisplay:
+      theArray.Add(_("Linear"));
+      theArray.Add(_("Logarithmic"));
+   }
+
+   return theArray;
+}
+
+WaveformSettings::~WaveformSettings()
+{
+}
diff --git a/src/prefs/WaveformSettings.h b/src/prefs/WaveformSettings.h
new file mode 100644
index 0000000000000000000000000000000000000000..a62243aa3a358ec6af69733cba2241978826474e
--- /dev/null
+++ b/src/prefs/WaveformSettings.h
@@ -0,0 +1,63 @@
+/**********************************************************************
+
+Audacity: A Digital Audio Editor
+
+WaveformSettings.h
+
+Paul Licameli
+
+**********************************************************************/
+
+#ifndef __AUDACITY_WAVEFORM_SETTINGS__
+#define __AUDACITY_WAVEFORM_SETTINGS__
+
+class wxArrayString;
+
+class WaveformSettings
+{
+public:
+
+   // Singleton for settings that are not per-track
+   class Globals
+   {
+   public:
+      static Globals &Get();
+      void SavePrefs();
+
+   private:
+      Globals();
+      void LoadPrefs();
+   };
+
+   static WaveformSettings &defaults();
+   WaveformSettings();
+   WaveformSettings(const WaveformSettings &other);
+   WaveformSettings& operator= (const WaveformSettings &other);
+   ~WaveformSettings();
+
+   bool IsDefault() const
+   {
+      return this == &defaults();
+   }
+
+   bool Validate(bool quiet);
+   void LoadPrefs();
+   void SavePrefs();
+   void Update();
+
+   enum ScaleType {
+      stLinear,
+      stLogarithmic,
+
+      stNumScaleTypes,
+   };
+
+   static void InvalidateNames(); // in case of language change
+   static const wxArrayString &GetScaleNames();
+
+   ScaleType scaleType;
+
+   // Convenience
+   bool isLinear() const { return stLinear == scaleType; }
+};
+#endif
diff --git a/src/toolbars/ControlToolBar.cpp b/src/toolbars/ControlToolBar.cpp
index c3abd8646a9dec98f1bfd0b3bd67c5de03cc9bf3..8a856a3c9e64d5caa1cee3c89d701d4bfac416ec 100644
--- a/src/toolbars/ControlToolBar.cpp
+++ b/src/toolbars/ControlToolBar.cpp
@@ -36,6 +36,7 @@
 
 #include "../Audacity.h"
 #include "../Experimental.h"
+#include "ControlToolBar.h"
 
 // For compilers that support precompilation, includes "wx/wx.h".
 #include <wx/wxprec.h>
@@ -51,7 +52,6 @@
 #endif
 #include <wx/tooltip.h>
 
-#include "ControlToolBar.h"
 #include "TranscriptionToolBar.h"
 #include "MeterToolBar.h"
 
@@ -62,7 +62,7 @@
 #include "../Prefs.h"
 #include "../Project.h"
 #include "../Theme.h"
-#include "../Track.h"
+#include "../WaveTrack.h"
 #include "../widgets/AButton.h"
 #include "../widgets/Meter.h"
 
diff --git a/src/toolbars/EditToolBar.cpp b/src/toolbars/EditToolBar.cpp
index 16237ed01948d59891b88e198205854c9488b0e3..9a77732b5edb134025228cadec0e179858508f21 100644
--- a/src/toolbars/EditToolBar.cpp
+++ b/src/toolbars/EditToolBar.cpp
@@ -52,6 +52,7 @@
 #include "../Prefs.h"
 #include "../Project.h"
 #include "../Theme.h"
+#include "../Track.h"
 #include "../UndoManager.h"
 #include "../widgets/AButton.h"
 
diff --git a/src/toolbars/SpectralSelectionBar.cpp b/src/toolbars/SpectralSelectionBar.cpp
index ae6167e44342542389ee5bf4e2f8fe8b2899ae17..fb443452c71a54e3ea6a97ec8f9ecee4059940d6 100644
--- a/src/toolbars/SpectralSelectionBar.cpp
+++ b/src/toolbars/SpectralSelectionBar.cpp
@@ -158,12 +158,14 @@ void SpectralSelectionBar::Populate()
 
    mLowCtrl = new NumericTextCtrl(
       NumericConverter::FREQUENCY, this, OnLowID, frequencyFormatName, 0.0);
+   mLowCtrl->SetInvalidValue(SelectedRegion::UndefinedFrequency);
    mLowCtrl->SetName(_("Low Frequency:"));
    mLowCtrl->EnableMenu();
    subSizer->Add(mLowCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
 
    mHighCtrl = new NumericTextCtrl(
       NumericConverter::FREQUENCY, this, OnHighID, frequencyFormatName, 0.0);
+   mHighCtrl->SetInvalidValue(SelectedRegion::UndefinedFrequency);
    mHighCtrl->SetName(wxString(_("High Frequency:")));
    mHighCtrl->EnableMenu();
    subSizer->Add(mHighCtrl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 0);
@@ -265,6 +267,10 @@ void SpectralSelectionBar::ModifySpectralSelection(bool done)
          top = SelectedRegion::UndefinedFrequency;
    }
 
+   mLow = bottom;
+   mHigh = top;
+   SetBounds();
+
    // Notify project and track panel, which may change
    // the values again, and call back to us in SetFrequencies()
    mListener->SSBL_ModifySpectralSelection(bottom, top, done);
@@ -349,11 +355,25 @@ void SpectralSelectionBar::ValuesToControls()
       mWidthCtrl->SetValue(mWidth);
    }
    else {
+      SetBounds();
       mLowCtrl->SetValue(mLow);
       mHighCtrl->SetValue(mHigh);
    }
 }
 
+void SpectralSelectionBar::SetBounds()
+{
+   if (mHigh >= 0)
+      mLowCtrl->SetMaxValue(mHigh);
+   else
+      mLowCtrl->ResetMaxValue();
+
+   if (mLow >= 0)
+      mHighCtrl->SetMinValue(mLow);
+   else
+      mHighCtrl->ResetMinValue();
+}
+
 void SpectralSelectionBar::SetFrequencies(double bottom, double top)
 {
    mLow = bottom;
diff --git a/src/toolbars/SpectralSelectionBar.h b/src/toolbars/SpectralSelectionBar.h
index 953d13045ead20a97a3308e327b5267481e1d211..4bdd0fbf11ef5723aae81ca4596d9c276368c610 100644
--- a/src/toolbars/SpectralSelectionBar.h
+++ b/src/toolbars/SpectralSelectionBar.h
@@ -49,6 +49,7 @@ public:
 private:
 
    void ValuesToControls();
+   void SetBounds();
    void OnUpdate(wxCommandEvent &evt);
    void OnCtrl(wxCommandEvent &evt);
    void OnChoice(wxCommandEvent &evt);
diff --git a/src/toolbars/TranscriptionToolBar.cpp b/src/toolbars/TranscriptionToolBar.cpp
index 31c7ab0f3620bce31a99c4714d5fb6522a9a95b5..b520b14ffaed4d075c4ade8ab27114a027d418ce 100644
--- a/src/toolbars/TranscriptionToolBar.cpp
+++ b/src/toolbars/TranscriptionToolBar.cpp
@@ -15,6 +15,7 @@
 *//*******************************************************************/
 
 #include "../Audacity.h"
+#include "TranscriptionToolBar.h"
 
 // For compilers that support precompilation, includes "wx/wx.h".
 #include <wx/wxprec.h>
@@ -28,7 +29,6 @@
 #endif // WX_PRECOMP
 
 #include "../Envelope.h"
-#include "TranscriptionToolBar.h"
 
 #include "ControlToolBar.h"
 #include "../AudacityApp.h"
diff --git a/src/toolbars/TranscriptionToolBar.h b/src/toolbars/TranscriptionToolBar.h
index 2ca08bf76b4aa758d6c0213608d3fb77a45ae0aa..8ae652694284dca40ee8f1638627ae2bf9b633c6 100644
--- a/src/toolbars/TranscriptionToolBar.h
+++ b/src/toolbars/TranscriptionToolBar.h
@@ -18,7 +18,7 @@
 #include <wx/brush.h>
 #include <wx/pen.h>
 
-#include "../Sequence.h"
+#include "audacity/Types.h"
 #include "../Theme.h"
 
 class wxBitmap;
@@ -95,6 +95,15 @@ class TranscriptionToolBar:public ToolBar {
    virtual void OnMakeLabel(wxCommandEvent & event);
    virtual void OnAutomateSelection(wxCommandEvent & event);
    virtual void OnSensitivitySlider(wxCommandEvent & event);
+
+   virtual void Populate();
+   virtual void Repaint(wxDC * WXUNUSED(dc)) {}
+   virtual void EnableDisableButtons();
+   virtual void UpdatePrefs();
+
+   void OnFocus(wxFocusEvent &event);
+   void OnCaptureKey(wxCommandEvent &event);
+
    virtual double GetSensitivity();
    virtual void SetKeyType(wxCommandEvent & event);
 #endif
diff --git a/src/widgets/ASlider.cpp b/src/widgets/ASlider.cpp
index 10caa3d0201163070a54bf01a8ffe4ae977cf4e9..fb107a69ba39e9dfd304f603df8d5761e3164a00 100644
--- a/src/widgets/ASlider.cpp
+++ b/src/widgets/ASlider.cpp
@@ -217,7 +217,7 @@ bool SliderDialog::TransferDataFromWindow()
 
    mTextCtrl->GetValue().ToDouble(&value);
    if (mStyle == DB_SLIDER)
-      value = pow(10.0, value / 20.0);
+      value = DB_TO_LINEAR(value);
    mSlider->Set(value);
 
    return true;
@@ -1231,7 +1231,7 @@ float LWSlider::DragPositionToValue(int fromPos, bool shiftDown)
 float LWSlider::Get( bool convert )
 {
    if (mStyle == DB_SLIDER)
-      return ( convert ? pow(10.0f, mCurrentValue / 20.0f) : mCurrentValue );
+      return (convert ? DB_TO_LINEAR(mCurrentValue) : mCurrentValue);
    else
       return mCurrentValue;
 }
@@ -1241,7 +1241,7 @@ void LWSlider::Set(float value)
    if (mIsDragging)
       return;
    if (mStyle == DB_SLIDER)
-      mCurrentValue = 20.0f*log10(value);
+      mCurrentValue = LINEAR_TO_DB(value);
    else
       mCurrentValue = value;
 
diff --git a/src/widgets/Meter.cpp b/src/widgets/Meter.cpp
index fabc0cba82b965fc79570097b56b52288b1b2d8f..18aee1f51c21b20134dbe059805f932e877fd934 100644
--- a/src/widgets/Meter.cpp
+++ b/src/widgets/Meter.cpp
@@ -61,6 +61,7 @@
 #include "../AudioIO.h"
 #include "../AColor.h"
 #include "../ImageManipulation.h"
+#include "../prefs/GUISettings.h"
 #include "../Project.h"
 #include "../toolbars/MeterToolBar.h"
 #include "../toolbars/ControlToolBar.h"
@@ -366,7 +367,7 @@ Meter::~Meter()
 
 void Meter::UpdatePrefs()
 {
-   mDBRange = gPrefs->Read(wxT("/GUI/EnvdBRange"), ENV_DB_RANGE);
+   mDBRange = gPrefs->Read(ENV_DB_KEY, ENV_DB_RANGE);
 
    mMeterRefreshRate = gPrefs->Read(Key(wxT("RefreshRate")), 30);
    mGradient = gPrefs->Read(Key(wxT("Bars")), wxT("Gradient")) == wxT("Gradient");
@@ -864,7 +865,7 @@ static float ToDB(float v, float range)
 {
    double db;
    if (v > 0)
-      db = 20 * log10(fabs(v));
+      db = LINEAR_TO_DB(fabs(v));
    else
       db = -999;
    return ClipZeroToOne((db + range) / range);
@@ -995,7 +996,7 @@ void Meter::OnMeterUpdate(wxTimerEvent & WXUNUSED(event))
             }
             else {
                double decayAmount = mDecayRate * deltaT;
-               double decayFactor = pow(10.0, -decayAmount/20);
+               double decayFactor = DB_TO_LINEAR(-decayAmount);
                mBar[j].peak = floatMax(msg.peak[j],
                                        mBar[j].peak * decayFactor);
             }
diff --git a/src/widgets/Meter.h b/src/widgets/Meter.h
index c97e0a0116411150fab0773e1310dfa4a5fd5f89..55bfd7fa2b8737383a94ed0dc78b0d0fe6389574 100644
--- a/src/widgets/Meter.h
+++ b/src/widgets/Meter.h
@@ -21,7 +21,6 @@
 #include <wx/timer.h>
 
 #include "../SampleFormat.h"
-#include "../Sequence.h"
 #include "Ruler.h"
 
 // Event used to notify all meters of preference changes
@@ -57,8 +56,8 @@ class MeterUpdateMsg
    int tailPeakCount[kMaxMeterBars];
 
    /* neither constructor nor destructor do anything */
-   MeterUpdateMsg() { };
-   ~MeterUpdateMsg() { };
+   MeterUpdateMsg() { }
+   ~MeterUpdateMsg() { }
    /* for debugging purposes, printing the values out is really handy */
    /** \brief Print out all the values in the meter update message */
    wxString toString();
diff --git a/src/widgets/NumericTextCtrl.cpp b/src/widgets/NumericTextCtrl.cpp
index 73bab1830bed1e0c5688a91c0039db4d5a62514b..181528e7a49c2f85d8843f7e066f4047c49f2e4f 100644
--- a/src/widgets/NumericTextCtrl.cpp
+++ b/src/widgets/NumericTextCtrl.cpp
@@ -167,7 +167,8 @@ different formats.
 
 #include "../Audacity.h"
 #include "NumericTextCtrl.h"
-#include "../Sequence.h"   // for sampleCount
+#include "audacity/Types.h"
+#include "../AudacityApp.h"
 #include "../Theme.h"
 #include "../AllThemeResources.h"
 #include "../AColor.h"
@@ -175,6 +176,7 @@ different formats.
 
 #include <algorithm>
 #include <math.h>
+#include <limits>
 
 #include <wx/wx.h>
 #include <wx/dcmemory.h>
@@ -531,6 +533,10 @@ NumericConverter::NumericConverter(Type type,
                                    double value,
                                    double sampleRate)
 {
+   ResetMinValue();
+   ResetMaxValue();
+   mInvalidValue = -1.0;
+
    mDefaultNdx = 0;
 
    mType = type;
@@ -863,7 +869,7 @@ void NumericConverter::ControlsToValue()
 
    if (mFields.GetCount() > 0 &&
       mValueString.Mid(mFields[0].pos, 1) == wxChar('-')) {
-      mValue = -1;
+      mValue = mInvalidValue;
       return;
    }
 
@@ -904,7 +910,7 @@ void NumericConverter::ControlsToValue()
       t = frames * 1.001 / 30.;
    }
 
-   mValue = t;
+   mValue = std::max(mMinValue, std::min(mMaxValue, t));
 }
 
 void NumericConverter::SetFormatName(const wxString & formatName)
@@ -935,6 +941,35 @@ void NumericConverter::SetValue(double newValue)
    ControlsToValue();
 }
 
+void NumericConverter::SetMinValue(double minValue)
+{
+   mMinValue = minValue;
+   if (mMaxValue < minValue)
+      mMaxValue = minValue;
+   if (mValue < minValue)
+      SetValue(minValue);
+}
+
+void NumericConverter::ResetMinValue()
+{
+   mMinValue = std::numeric_limits<double>::min();
+}
+
+void NumericConverter::SetMaxValue(double maxValue)
+{
+   mMaxValue = maxValue;
+   if (mMinValue > maxValue) {
+      mMinValue = maxValue;
+   }
+   if (mValue > maxValue)
+      SetValue(maxValue);
+}
+
+void NumericConverter::ResetMaxValue()
+{
+   mMaxValue = std::numeric_limits<double>::max();
+}
+
 double NumericConverter::GetValue()
 {
    ControlsToValue();
@@ -1079,6 +1114,8 @@ void NumericConverter::Adjust(int steps, int dir)
                mValue = 0.;
             }
 
+            mValue = std::max(mMinValue, std::min(mMaxValue, mValue));
+
             mValue /= mScalingFactor;
 
             if (!mNtscDrop)
@@ -1141,6 +1178,7 @@ NumericTextCtrl::NumericTextCtrl(NumericConverter::Type type,
    mAutoPos(autoPos)
    , mType(type)
 {
+   mAllowInvalidValue = false;
 
    mDigitBoxW = 10;
    mDigitBoxH = 16;
@@ -1179,6 +1217,7 @@ NumericTextCtrl::~NumericTextCtrl()
 
 // Set the focus to the first (left-most) non-zero digit
 // If all digits are zero, the right-most position is focused
+// If all digits are hyphens (invalid), the left-most position is focused
 void NumericTextCtrl::UpdateAutoFocus()
 {
    if (!mAutoPos)
@@ -1248,6 +1287,15 @@ void NumericTextCtrl::EnableMenu(bool enable)
    Fit();
 }
 
+void NumericTextCtrl::SetInvalidValue(double invalidValue)
+{
+   const bool wasInvalid = mAllowInvalidValue && (mValue == mInvalidValue);
+   mAllowInvalidValue = true;
+   mInvalidValue = invalidValue;
+   if (wasInvalid)
+      SetValue(invalidValue);
+}
+
 bool NumericTextCtrl::Layout()
 {
    unsigned int i, j;
@@ -1564,6 +1612,7 @@ void NumericTextCtrl::OnCaptureKey(wxCommandEvent &event)
       case WXK_TAB:
       case WXK_RETURN:
       case WXK_NUMPAD_ENTER:
+      case '-':
          return;
 
       default:
@@ -1586,6 +1635,7 @@ void NumericTextCtrl::OnKeyUp(wxKeyEvent &event)
       keyCode -= WXK_NUMPAD0 - '0';
 
    if ((keyCode >= '0' && keyCode <= '9') ||
+       (keyCode == '-') ||
        (keyCode == WXK_BACK) ||
        (keyCode == WXK_UP) ||
        (keyCode == WXK_DOWN)) {
@@ -1618,7 +1668,7 @@ void NumericTextCtrl::OnKeyDown(wxKeyEvent &event)
    if (!mReadOnly && (keyCode >= '0' && keyCode <= '9')) {
       int digitPosition = mDigits[mFocusedDigit].pos;
       if (mValueString[digitPosition] == wxChar('-')) {
-         mValue = 0;
+         mValue = std::max(mMinValue, std::min(mMaxValue, 0.0));
          ValueToControls();
          // Beware relocation of the string
          digitPosition = mDigits[mFocusedDigit].pos;
@@ -1630,6 +1680,11 @@ void NumericTextCtrl::OnKeyDown(wxKeyEvent &event)
       Updated();
    }
 
+   else if (!mReadOnly && keyCode == '-') {
+      if (mAllowInvalidValue)
+         SetValue(mInvalidValue);
+   }
+
    else if (!mReadOnly && keyCode == WXK_BACK) {
       // Moves left, replaces that char with '0', stays there...
       mFocusedDigit--;
diff --git a/src/widgets/NumericTextCtrl.h b/src/widgets/NumericTextCtrl.h
index 631042e01c43b8ecaa532dd2cc0aaeaa957da7fd..be5c8d495775ffbbc5e1f80ff292cd071094ab47 100644
--- a/src/widgets/NumericTextCtrl.h
+++ b/src/widgets/NumericTextCtrl.h
@@ -23,6 +23,8 @@
 #include <wx/string.h>
 #include <wx/textctrl.h>
 
+#include "../Audacity.h"
+
 #if wxUSE_ACCESSIBILITY
 #include <wx/access.h>
 #endif
@@ -71,6 +73,11 @@ public:
    void SetFormatString(const wxString & formatString);
    void SetSampleRate(double sampleRate);
    void SetValue(double newValue);
+   void SetMinValue(double minValue);
+   void ResetMinValue();
+   void SetMaxValue(double maxValue);
+   void ResetMaxValue();
+
    double GetValue();
 
    wxString GetString();
@@ -95,6 +102,10 @@ protected:
 
    double         mValue;
 
+   double         mMinValue;
+   double         mMaxValue;
+   double         mInvalidValue;
+
    wxString       mFormatString;
 
    NumericFieldArray mFields;
@@ -147,6 +158,12 @@ class NumericTextCtrl: public wxControl, public NumericConverter
    void SetReadOnly(bool readOnly = true);
    void EnableMenu(bool enable = true);
 
+   // The text control permits typing '-' to make the value invalid only if this
+   // function has previously been called.
+   // Maybe you want something other than the default of -1 to indicate the invalid value
+   // this control returns to the program, so you can specify.
+   void SetInvalidValue(double invalidValue);
+
    int GetFocusedField() { return mLastField; }
    int GetFocusedDigit() { return mFocusedDigit; }
 
@@ -200,6 +217,8 @@ private:
 
    NumericConverter::Type mType;
 
+   bool           mAllowInvalidValue;
+
    DECLARE_EVENT_TABLE()
 };
 
diff --git a/src/widgets/Ruler.cpp b/src/widgets/Ruler.cpp
index 5ff2ce5d709ac1b4badc63d2f6adcf38d9b96007..11d4842107196f8deafff8ad2523fed7f2b79300 100644
--- a/src/widgets/Ruler.cpp
+++ b/src/widgets/Ruler.cpp
@@ -76,6 +76,7 @@ array of Ruler::Label.
 #include "../TimeTrack.h"
 #include "../TrackPanel.h"
 #include "../Menus.h"
+#include "../NumberScale.h"
 #include "../Prefs.h"
 #include "../Snap.h"
 
@@ -97,6 +98,7 @@ using std::max;
 //
 
 Ruler::Ruler()
+   : mpNumberScale(0)
 {
    mMin = mHiddenMin = 0.0;
    mMax = mHiddenMax = 100.0;
@@ -180,6 +182,8 @@ Ruler::~Ruler()
       delete[] mMinorLabels;
    if (mMinorMinorLabels)
       delete[] mMinorMinorLabels;
+
+   delete mpNumberScale;
 }
 
 void Ruler::SetTwoTone(bool twoTone)
@@ -324,6 +328,23 @@ void Ruler::SetFonts(const wxFont &minorFont, const wxFont &majorFont, const wxF
    Invalidate();
 }
 
+void Ruler::SetNumberScale(const NumberScale *pScale)
+{
+   if (!pScale) {
+      if (mpNumberScale) {
+         delete mpNumberScale;
+         Invalidate();
+      }
+   }
+   else {
+      if (!mpNumberScale || *mpNumberScale != *pScale) {
+         delete mpNumberScale;
+         mpNumberScale = new NumberScale(*pScale);
+         Invalidate();
+      }
+   }
+}
+
 void Ruler::OfflimitsPixels(int start, int end)
 {
    int i;
@@ -1170,13 +1191,17 @@ void Ruler::Update(TimeTrack* timetrack)// Envelope *speedEnv, long minSpeed, lo
    }
    else {
       // log case
-      mDigits=2;  //TODO: implement dynamic digit computation
+
+      NumberScale numberScale(mpNumberScale
+         ? *mpNumberScale
+         : NumberScale(nstLogarithmic, mMin, mMax, 1.0f)
+      );
+
+      mDigits=2; //TODO: implement dynamic digit computation
       double loLog = log10(mMin);
       double hiLog = log10(mMax);
-      double scale = mLength/(hiLog - loLog);
       int loDecade = (int) floor(loLog);
 
-      int pos;
       double val;
       double startDecade = pow(10., (double)loDecade);
 
@@ -1184,12 +1209,12 @@ void Ruler::Update(TimeTrack* timetrack)// Envelope *speedEnv, long minSpeed, lo
       double decade = startDecade;
       double delta=hiLog-loLog, steps=fabs(delta);
       double step = delta>=0 ? 10 : 0.1;
-      double rMin=wxMin(mMin, mMax), rMax=wxMax(mMin, mMax);
+      double rMin=std::min(mMin, mMax), rMax=std::max(mMin, mMax);
       for(i=0; i<=steps; i++)
       {  // if(i!=0)
          {  val = decade;
-            if(val > rMin && val < rMax) {
-               pos = (int)(((log10(val) - loLog)*scale)+0.5);
+            if(val >= rMin && val < rMax) {
+               const int pos(0.5 + mLength * numberScale.ValueToPosition(val));
                Tick(pos, val, true, false);
             }
          }
@@ -1209,7 +1234,7 @@ void Ruler::Update(TimeTrack* timetrack)// Envelope *speedEnv, long minSpeed, lo
          for(j=start; j!=end; j+=mstep) {
             val = decade * j;
             if(val >= rMin && val < rMax) {
-               pos = (int)(((log10(val) - loLog)*scale)+0.5);
+               const int pos(0.5 + mLength * numberScale.ValueToPosition(val));
                Tick(pos, val, false, true);
             }
          }
@@ -1224,13 +1249,16 @@ void Ruler::Update(TimeTrack* timetrack)// Envelope *speedEnv, long minSpeed, lo
       {  start=100; end= 10; mstep=-1;
       }
       steps++;
-      for(i=0; i<=steps; i++) {
-         for(int f=start; f!=int(end); f+=mstep) {
-            if (int(f/10)!=f/10.0f) {
-               val = decade * f/10;
-               if(val >= rMin && val < rMax) {
-                  pos = (int)(((log10(val) - loLog)*scale)+0.5);
-               Tick(pos, val, false, false);
+      for (i = 0; i <= steps; i++) {
+         // PRL:  Bug1038.  Don't label 1.6, rounded, as a duplicate tick for "2"
+         if (!(mFormat == IntFormat && decade < 10.0)) {
+            for (int f = start; f != int(end); f += mstep) {
+               if (int(f / 10) != f / 10.0f) {
+                  val = decade * f / 10;
+                  if (val >= rMin && val < rMax) {
+                     const int pos(0.5 + mLength * numberScale.ValueToPosition(val));
+                     Tick(pos, val, false, false);
+                  }
                }
             }
          }
@@ -1909,8 +1937,8 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
    TrackPanel *tp = mProject->GetTrackPanel();
    int mousePosX, width, height;
    tp->GetTracksUsableArea(&width, &height);
-   mousePosX = wxMax(evt.GetX(), tp->GetLeftOffset());
-   mousePosX = wxMin(mousePosX, tp->GetLeftOffset() + width - 1);
+   mousePosX = std::max(evt.GetX(), tp->GetLeftOffset());
+   mousePosX = std::min(mousePosX, tp->GetLeftOffset() + width - 1);
 
    bool isWithinStart = IsWithinMarker(mousePosX, mOldPlayRegionStart);
    bool isWithinEnd = IsWithinMarker(mousePosX, mOldPlayRegionEnd);
@@ -1925,7 +1953,7 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
    mLastMouseX = mousePosX;
    mQuickPlayPos = Pos2Time(mousePosX);
    // If not looping, restrict selection to end of project
-   if (!evt.ShiftDown()) mQuickPlayPos = wxMin(t1, mQuickPlayPos);
+   if (!evt.ShiftDown()) mQuickPlayPos = std::min(t1, mQuickPlayPos);
 
 
    if (evt.Leaving()) {
@@ -2492,7 +2520,7 @@ void AdornedRulerPanel::DrawQuickPlayIndicator(wxDC * dc, bool clear)
    TrackPanel *tp = mProject->GetTrackPanel();
    wxClientDC cdc(tp);
 
-   double latestEnd = wxMax(mProject->GetTracks()->GetEndTime(), mProject->GetSel1());
+   double latestEnd = std::max(mProject->GetTracks()->GetEndTime(), mProject->GetSel1());
    if (clear || (mQuickPlayPos >= latestEnd)) {
       tp->TrackPanel::DrawQuickPlayIndicator(cdc, -1);
       return;
diff --git a/src/widgets/Ruler.h b/src/widgets/Ruler.h
index 935659e8132d38ec50475c06233a92a571657362..f33ad2e33c9ed436330903bbd07b5ba0c90da68a 100644
--- a/src/widgets/Ruler.h
+++ b/src/widgets/Ruler.h
@@ -16,13 +16,13 @@
 #include <wx/font.h>
 #include <wx/panel.h>
 #include <wx/window.h>
-#include "../Envelope.h"
 #include "../Experimental.h"
 
 class ViewInfo;
 class AudacityProject;
 class TimeTrack;
 class SnapManager;
+class NumberScale;
 
 class AUDACITY_DLL_API Ruler {
  public:
@@ -98,6 +98,9 @@ class AUDACITY_DLL_API Ruler {
    // Good defaults are provided, but you can override here
    void SetFonts(const wxFont &minorFont, const wxFont &majorFont, const wxFont &minorMinorFont);
 
+   // Copies *pScale if it is not NULL
+   void SetNumberScale(const NumberScale *pScale);
+
    // The ruler will not draw text within this (pixel) range.
    // Use this if you have another graphic object obscuring part
    // of the ruler's area.  The values start and end are interpreted
@@ -227,6 +230,8 @@ private:
    bool         mTwoTone;
    bool         mUseZoomInfo;
    int          mLeftOffset;
+
+   NumberScale *mpNumberScale;
 };
 
 class AUDACITY_DLL_API RulerPanel : public wxPanel {
diff --git a/win/Projects/Audacity/Audacity.vcxproj b/win/Projects/Audacity/Audacity.vcxproj
index 413659967222e237897a034d5d44b28aa1033405..c4bf71f31361bcff43c6512b2d865d1752a0d853 100755
--- a/win/Projects/Audacity/Audacity.vcxproj
+++ b/win/Projects/Audacity/Audacity.vcxproj
@@ -179,6 +179,9 @@
     <ClCompile Include="..\..\..\src\PlatformCompatibility.cpp" />
     <ClCompile Include="..\..\..\src\PluginManager.cpp" />
     <ClCompile Include="..\..\..\src\Prefs.cpp" />
+    <ClCompile Include="..\..\..\src\prefs\SpectrogramSettings.cpp" />
+    <ClCompile Include="..\..\..\src\prefs\WaveformPrefs.cpp" />
+    <ClCompile Include="..\..\..\src\prefs\WaveformSettings.cpp" />
     <ClCompile Include="..\..\..\src\Printing.cpp" />
     <ClCompile Include="..\..\..\src\Profiler.cpp" />
     <ClCompile Include="..\..\..\src\Project.cpp" />
@@ -421,11 +424,17 @@
     <ClInclude Include="..\..\..\src\import\MultiFormatReader.h" />
     <ClInclude Include="..\..\..\src\import\SpecPowerMeter.h" />
     <ClInclude Include="..\..\..\src\ModuleManager.h" />
+    <ClInclude Include="..\..\..\src\NumberScale.h" />
+    <ClInclude Include="..\..\..\src\prefs\GUISettings.h" />
+    <ClInclude Include="..\..\..\src\prefs\SpectrogramSettings.h" />
+    <ClInclude Include="..\..\..\src\prefs\WaveformPrefs.h" />
+    <ClInclude Include="..\..\..\src\prefs\WaveformSettings.h" />
     <ClInclude Include="..\..\..\src\RevisionIdent.h" />
     <ClInclude Include="..\..\..\src\SelectedRegion.h" />
     <ClInclude Include="..\..\..\src\SseMathFuncs.h" />
     <ClInclude Include="..\..\..\src\toolbars\SpectralSelectionBar.h" />
     <ClInclude Include="..\..\..\src\toolbars\SpectralSelectionBarListener.h" />
+    <ClInclude Include="..\..\..\src\WaveTrackLocation.h" />
     <ClInclude Include="..\..\..\src\widgets\HelpSystem.h" />
     <ClInclude Include="..\..\..\src\widgets\NumericTextCtrl.h" />
     <ClInclude Include="..\..\configwin.h" />
diff --git a/win/Projects/Audacity/Audacity.vcxproj.filters b/win/Projects/Audacity/Audacity.vcxproj.filters
index 6754ad973693aa39fd5e6ac167668840313d4478..abab8c6ac3ba340f3b2ff119e9078250ca8dcc57 100755
--- a/win/Projects/Audacity/Audacity.vcxproj.filters
+++ b/win/Projects/Audacity/Audacity.vcxproj.filters
@@ -3,69 +3,71 @@
   <ItemGroup>
     <Filter Include="src">
       <UniqueIdentifier>{348bf572-4c97-4a76-89f3-117a94118ff5}</UniqueIdentifier>
+      <Extensions>
+      </Extensions>
     </Filter>
-    <Filter Include="src/effects">
-      <UniqueIdentifier>{eaa919b2-fa74-43bf-882e-d62b1365d884}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src/effects/VST">
-      <UniqueIdentifier>{99325e00-3930-4e03-a599-999f275db78e}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src/export">
-      <UniqueIdentifier>{45fbd203-4e13-441d-a7a2-e4614d6a67f7}</UniqueIdentifier>
+    <Filter Include="Resources">
+      <UniqueIdentifier>{67e0ccd0-e2da-46a1-80b9-b27e85475080}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src/import">
-      <UniqueIdentifier>{fcf0dda3-8121-4954-94ef-7cec6d1a163d}</UniqueIdentifier>
+    <Filter Include="plug-ins">
+      <UniqueIdentifier>{cfc19d3c-fac3-4724-b677-d446d9dd10a5}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src/prefs">
-      <UniqueIdentifier>{aa973747-536e-4acd-a418-f1aacd9698ed}</UniqueIdentifier>
+    <Filter Include="nyquist">
+      <UniqueIdentifier>{df132fc5-4e81-4e57-a754-f9d639179bca}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src/widgets">
-      <UniqueIdentifier>{daec450f-84fa-4e72-ba52-e0733f2c5acf}</UniqueIdentifier>
+    <Filter Include="nyquist\rawwaves">
+      <UniqueIdentifier>{5e31814b-dcd1-4c9a-977b-88b4a51e8226}</UniqueIdentifier>
     </Filter>
-    <Filter Include="Resources">
-      <UniqueIdentifier>{67e0ccd0-e2da-46a1-80b9-b27e85475080}</UniqueIdentifier>
+    <Filter Include="includes">
+      <UniqueIdentifier>{ce332b42-4385-473c-ad9c-f385ea2e6c73}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src/xml">
-      <UniqueIdentifier>{b2dffd13-d86c-4502-833b-3fa052e447a5}</UniqueIdentifier>
+    <Filter Include="includes\audacity">
+      <UniqueIdentifier>{2bfa6793-371a-4d2e-b3f4-fb033a0c5729}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src/effects/nyquist">
-      <UniqueIdentifier>{bcfcf79a-6a8d-4768-8ee1-cf503eaecbf9}</UniqueIdentifier>
+    <Filter Include="src\blockfile">
+      <UniqueIdentifier>{884d4cdc-e8f1-45f3-b5a6-5b8ac56b7d91}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src/commands">
+    <Filter Include="src\commands">
       <UniqueIdentifier>{045249ee-cc52-4743-a1b9-e0532f4488d5}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src/blockfile">
-      <UniqueIdentifier>{884d4cdc-e8f1-45f3-b5a6-5b8ac56b7d91}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src/effects/ladspa">
-      <UniqueIdentifier>{ab8cc474-825f-462e-a5da-d2055f6235ed}</UniqueIdentifier>
+    <Filter Include="src\effects">
+      <UniqueIdentifier>{eaa919b2-fa74-43bf-882e-d62b1365d884}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src/toolbars">
-      <UniqueIdentifier>{03d93315-5b4c-4f40-aded-9b496497657d}</UniqueIdentifier>
+    <Filter Include="src\export">
+      <UniqueIdentifier>{45fbd203-4e13-441d-a7a2-e4614d6a67f7}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src/effects/vamp">
-      <UniqueIdentifier>{1cd73294-06e2-42be-b7c0-2d620f621ec2}</UniqueIdentifier>
+    <Filter Include="src\import">
+      <UniqueIdentifier>{fcf0dda3-8121-4954-94ef-7cec6d1a163d}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src/ondemand">
+    <Filter Include="src\ondemand">
       <UniqueIdentifier>{4180976f-8b29-41b8-af53-86d2aed120ec}</UniqueIdentifier>
     </Filter>
-    <Filter Include="plug-ins">
-      <UniqueIdentifier>{cfc19d3c-fac3-4724-b677-d446d9dd10a5}</UniqueIdentifier>
+    <Filter Include="src\prefs">
+      <UniqueIdentifier>{aa973747-536e-4acd-a418-f1aacd9698ed}</UniqueIdentifier>
     </Filter>
-    <Filter Include="nyquist">
-      <UniqueIdentifier>{df132fc5-4e81-4e57-a754-f9d639179bca}</UniqueIdentifier>
+    <Filter Include="src\toolbars">
+      <UniqueIdentifier>{03d93315-5b4c-4f40-aded-9b496497657d}</UniqueIdentifier>
     </Filter>
-    <Filter Include="nyquist\rawwaves">
-      <UniqueIdentifier>{5e31814b-dcd1-4c9a-977b-88b4a51e8226}</UniqueIdentifier>
+    <Filter Include="src\widgets">
+      <UniqueIdentifier>{daec450f-84fa-4e72-ba52-e0733f2c5acf}</UniqueIdentifier>
     </Filter>
-    <Filter Include="src/effects/lv2">
+    <Filter Include="src\xml">
+      <UniqueIdentifier>{b2dffd13-d86c-4502-833b-3fa052e447a5}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\effects\ladspa">
+      <UniqueIdentifier>{ab8cc474-825f-462e-a5da-d2055f6235ed}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\effects\lv2">
       <UniqueIdentifier>{cfbc5496-9828-4c04-8e02-35a5e81cf092}</UniqueIdentifier>
     </Filter>
-    <Filter Include="includes">
-      <UniqueIdentifier>{ce332b42-4385-473c-ad9c-f385ea2e6c73}</UniqueIdentifier>
+    <Filter Include="src\effects\nyquist">
+      <UniqueIdentifier>{bcfcf79a-6a8d-4768-8ee1-cf503eaecbf9}</UniqueIdentifier>
     </Filter>
-    <Filter Include="includes\audacity">
-      <UniqueIdentifier>{2bfa6793-371a-4d2e-b3f4-fb033a0c5729}</UniqueIdentifier>
+    <Filter Include="src\effects\vamp">
+      <UniqueIdentifier>{1cd73294-06e2-42be-b7c0-2d620f621ec2}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\effects\VST">
+      <UniqueIdentifier>{99325e00-3930-4e03-a599-999f275db78e}</UniqueIdentifier>
     </Filter>
   </ItemGroup>
   <ItemGroup>
@@ -295,535 +297,535 @@
       <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Amplify.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\AutoDuck.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\BassTreble.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Biquad.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\ChangePitch.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\ChangeSpeed.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\ChangeTempo.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\ClickRemoval.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Compressor.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Contrast.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\DtmfGen.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Echo.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Effect.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\EffectManager.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Equalization.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Fade.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\FindClipping.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Generator.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Invert.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Leveller.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\LoadEffects.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Noise.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\NoiseRemoval.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Normalize.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Paulstretch.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Repair.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Repeat.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Reverb.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Reverse.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\SBSMSEffect.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\ScienFilter.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\ScoreAlignDialog.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Silence.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\SimpleMono.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\SoundTouchEffect.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\StereoToMono.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\TimeScale.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\TimeWarper.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\ToneGen.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\TruncSilence.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\TwoPassSimpleMono.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Wahwah.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\VST\VSTEffect.cpp">
-      <Filter>src/effects/VST</Filter>
+      <Filter>src\effects\VST</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\export\Export.cpp">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\export\ExportCL.cpp">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\export\ExportFFmpeg.cpp">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\export\ExportFFmpegDialogs.cpp">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\export\ExportFLAC.cpp">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\export\ExportMP2.cpp">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\export\ExportMP3.cpp">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\export\ExportMultiple.cpp">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\export\ExportOGG.cpp">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\export\ExportPCM.cpp">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\import\Import.cpp">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\import\ImportFFmpeg.cpp">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\import\ImportFLAC.cpp">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\import\ImportLOF.cpp">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\import\ImportMIDI.cpp">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\import\ImportMP3.cpp">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\import\ImportOGG.cpp">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\import\ImportPCM.cpp">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\import\ImportRaw.cpp">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\import\RawAudioGuess.cpp">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\BatchPrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\DevicePrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\DirectoriesPrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\EffectsPrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\ExtImportPrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\GUIPrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\ImportExportPrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\KeyConfigPrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\LibraryPrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\MidiIOPrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\ModulePrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\MousePrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\PlaybackPrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\PrefsDialog.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\ProjectsPrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\QualityPrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\RecordingPrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\SpectrumPrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\ThemePrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\TracksPrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\prefs\WarningsPrefs.cpp">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\AButton.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\ASlider.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\AttachableScrollBar.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\ErrorDialog.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\ExpandingToolBar.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\FileHistory.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\Grabber.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\Grid.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\HtmlWindow.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\ImageRoll.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\KeyView.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\LinkingHtmlWindow.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\Meter.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\MultiDialog.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\numformatter.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\ProgressDialog.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\Ruler.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\valnum.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\Warning.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\xml\XMLFileReader.cpp">
-      <Filter>src/xml</Filter>
+      <Filter>src\xml</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\xml\XMLTagHandler.cpp">
-      <Filter>src/xml</Filter>
+      <Filter>src\xml</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\xml\XMLWriter.cpp">
-      <Filter>src/xml</Filter>
+      <Filter>src\xml</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\nyquist\LoadNyquist.cpp">
-      <Filter>src/effects/nyquist</Filter>
+      <Filter>src\effects\nyquist</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\nyquist\Nyquist.cpp">
-      <Filter>src/effects/nyquist</Filter>
+      <Filter>src\effects\nyquist</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\AppCommandEvent.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\BatchEvalCommand.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\Command.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\CommandBuilder.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\CommandDirectory.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\CommandHandler.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\CommandManager.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\CommandSignature.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\CommandType.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\CompareAudioCommand.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\ExecMenuCommand.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\GetAllMenuCommands.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\GetProjectInfoCommand.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\GetTrackInfoCommand.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\HelpCommand.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\ImportExportCommands.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\Keyboard.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\MessageCommand.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\PreferenceCommands.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\ResponseQueue.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\ScreenshotCommand.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\ScriptCommandRelay.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\SelectCommand.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\SetProjectInfoCommand.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\SetTrackInfoCommand.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\blockfile\LegacyAliasBlockFile.cpp">
-      <Filter>src/blockfile</Filter>
+      <Filter>src\blockfile</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\blockfile\LegacyBlockFile.cpp">
-      <Filter>src/blockfile</Filter>
+      <Filter>src\blockfile</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\blockfile\ODDecodeBlockFile.cpp">
-      <Filter>src/blockfile</Filter>
+      <Filter>src\blockfile</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\blockfile\ODPCMAliasBlockFile.cpp">
-      <Filter>src/blockfile</Filter>
+      <Filter>src\blockfile</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\blockfile\PCMAliasBlockFile.cpp">
-      <Filter>src/blockfile</Filter>
+      <Filter>src\blockfile</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\blockfile\SilentBlockFile.cpp">
-      <Filter>src/blockfile</Filter>
+      <Filter>src\blockfile</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\blockfile\SimpleBlockFile.cpp">
-      <Filter>src/blockfile</Filter>
+      <Filter>src\blockfile</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\ladspa\LadspaEffect.cpp">
-      <Filter>src/effects/ladspa</Filter>
+      <Filter>src\effects\ladspa</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\toolbars\ControlToolBar.cpp">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\toolbars\DeviceToolBar.cpp">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\toolbars\EditToolBar.cpp">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\toolbars\MeterToolBar.cpp">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\toolbars\MixerToolBar.cpp">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\toolbars\SelectionBar.cpp">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\toolbars\ToolBar.cpp">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\toolbars\ToolDock.cpp">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\toolbars\ToolManager.cpp">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\toolbars\ToolsToolBar.cpp">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\toolbars\TranscriptionToolBar.cpp">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\vamp\LoadVamp.cpp">
-      <Filter>src/effects/vamp</Filter>
+      <Filter>src\effects\vamp</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\vamp\VampEffect.cpp">
-      <Filter>src/effects/vamp</Filter>
+      <Filter>src\effects\vamp</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\ondemand\ODComputeSummaryTask.cpp">
-      <Filter>src/ondemand</Filter>
+      <Filter>src\ondemand</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\ondemand\ODDecodeFFmpegTask.cpp">
-      <Filter>src/ondemand</Filter>
+      <Filter>src\ondemand</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\ondemand\ODDecodeFlacTask.cpp">
-      <Filter>src/ondemand</Filter>
+      <Filter>src\ondemand</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\ondemand\ODDecodeTask.cpp">
-      <Filter>src/ondemand</Filter>
+      <Filter>src\ondemand</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\ondemand\ODManager.cpp">
-      <Filter>src/ondemand</Filter>
+      <Filter>src\ondemand</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\ondemand\ODTask.cpp">
-      <Filter>src/ondemand</Filter>
+      <Filter>src\ondemand</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\ondemand\ODTaskThread.cpp">
-      <Filter>src/ondemand</Filter>
+      <Filter>src\ondemand</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\ondemand\ODWaveTrackTaskQueue.cpp">
-      <Filter>src/ondemand</Filter>
+      <Filter>src\ondemand</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\lv2\LoadLV2.cpp">
-      <Filter>src/effects/lv2</Filter>
+      <Filter>src\effects\lv2</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\lv2\LV2Effect.cpp">
-      <Filter>src/effects/lv2</Filter>
+      <Filter>src\effects\lv2</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\SseMathFuncs.cpp">
       <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\commands\OpenSaveCommands.cpp">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\import\ImportGStreamer.cpp">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\HelpSystem.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\import\FormatClassifier.cpp">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\import\SpecPowerMeter.cpp">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\import\MultiFormatReader.cpp">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\ModuleManager.cpp">
       <Filter>src</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\EffectRack.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\toolbars\SpectralSelectionBar.cpp">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\widgets\NumericTextCtrl.cpp">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\Phaser.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\effects\NoiseReduction.cpp">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClCompile>
     <ClCompile Include="..\..\..\src\DeviceChange.cpp">
       <Filter>src</Filter>
@@ -840,6 +842,15 @@
     <ClCompile Include="..\..\..\src\effects\VST\VSTControlMSW.cpp">
       <Filter>src/effects/VST</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\..\src\prefs\SpectrogramSettings.cpp">
+      <Filter>src\prefs</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\src\prefs\WaveformPrefs.cpp">
+      <Filter>src\prefs</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\src\prefs\WaveformSettings.cpp">
+      <Filter>src\prefs</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\..\src\AboutDialog.h">
@@ -1083,535 +1094,535 @@
       <Filter>src</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Amplify.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\AutoDuck.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\BassTreble.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Biquad.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\ChangePitch.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\ChangeSpeed.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\ChangeTempo.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\ClickRemoval.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Compressor.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Contrast.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\DtmfGen.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Echo.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Effect.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\EffectManager.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Equalization.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Fade.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\FindClipping.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Generator.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Invert.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Leveller.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\LoadEffects.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Noise.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\NoiseRemoval.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Normalize.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Paulstretch.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Repair.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Repeat.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Reverb.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Reverb_libSoX.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Reverse.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\SBSMSEffect.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\ScienFilter.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Silence.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\SimpleMono.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\SoundTouchEffect.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\StereoToMono.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\TimeScale.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\TimeWarper.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\ToneGen.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\TruncSilence.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\TwoPassSimpleMono.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Wahwah.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\VST\VSTEffect.h">
-      <Filter>src/effects/VST</Filter>
+      <Filter>src\effects\VST</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\export\Export.h">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\export\ExportCL.h">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\export\ExportFFmpeg.h">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\export\ExportFFmpegDialogs.h">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\export\ExportFLAC.h">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\export\ExportMP2.h">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\export\ExportMP3.h">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\export\ExportMultiple.h">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\export\ExportOGG.h">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\export\ExportPCM.h">
-      <Filter>src/export</Filter>
+      <Filter>src\export</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\import\Import.h">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\import\ImportFFmpeg.h">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\import\ImportFLAC.h">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\import\ImportLOF.h">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\import\ImportMIDI.h">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\import\ImportMP3.h">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\import\ImportOGG.h">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\import\ImportPCM.h">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\import\ImportPlugin.h">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\import\ImportRaw.h">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\import\RawAudioGuess.h">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\BatchPrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\DevicePrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\DirectoriesPrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\EffectsPrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\ExtImportPrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\GUIPrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\ImportExportPrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\KeyConfigPrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\LibraryPrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\MidiIOPrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\ModulePrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\MousePrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\PlaybackPrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\PrefsDialog.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\PrefsPanel.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\ProjectsPrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\QualityPrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\RecordingPrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\SpectrumPrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\ThemePrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\TracksPrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\prefs\WarningsPrefs.h">
-      <Filter>src/prefs</Filter>
+      <Filter>src\prefs</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\AButton.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\ASlider.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\AttachableScrollBar.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\ErrorDialog.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\ExpandingToolBar.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\FileHistory.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\Grabber.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\Grid.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\HtmlWindow.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\ImageRoll.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\KeyView.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\LinkingHtmlWindow.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\Meter.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\MultiDialog.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\numformatter.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\ProgressDialog.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\Ruler.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\valnum.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\Warning.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\xml\XMLFileReader.h">
-      <Filter>src/xml</Filter>
+      <Filter>src\xml</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\xml\XMLTagHandler.h">
-      <Filter>src/xml</Filter>
+      <Filter>src\xml</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\xml\XMLWriter.h">
-      <Filter>src/xml</Filter>
+      <Filter>src\xml</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\nyquist\LoadNyquist.h">
-      <Filter>src/effects/nyquist</Filter>
+      <Filter>src\effects\nyquist</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\nyquist\Nyquist.h">
-      <Filter>src/effects/nyquist</Filter>
+      <Filter>src\effects\nyquist</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\AppCommandEvent.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\BatchEvalCommand.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\Command.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\CommandBuilder.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\CommandDirectory.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\CommandHandler.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\CommandManager.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\CommandMisc.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\CommandSignature.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\CommandTargets.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\CommandType.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\CompareAudioCommand.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\ExecMenuCommand.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\GetAllMenuCommands.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\GetProjectInfoCommand.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\GetTrackInfoCommand.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\HelpCommand.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\ImportExportCommands.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\Keyboard.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\MessageCommand.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\PreferenceCommands.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\ResponseQueue.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\ScreenshotCommand.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\ScriptCommandRelay.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\SelectCommand.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\SetProjectInfoCommand.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\SetTrackInfoCommand.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\Validators.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\blockfile\LegacyAliasBlockFile.h">
-      <Filter>src/blockfile</Filter>
+      <Filter>src\blockfile</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\blockfile\LegacyBlockFile.h">
-      <Filter>src/blockfile</Filter>
+      <Filter>src\blockfile</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\blockfile\ODDecodeBlockFile.h">
-      <Filter>src/blockfile</Filter>
+      <Filter>src\blockfile</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\blockfile\ODPCMAliasBlockFile.h">
-      <Filter>src/blockfile</Filter>
+      <Filter>src\blockfile</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\blockfile\PCMAliasBlockFile.h">
-      <Filter>src/blockfile</Filter>
+      <Filter>src\blockfile</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\blockfile\SilentBlockFile.h">
-      <Filter>src/blockfile</Filter>
+      <Filter>src\blockfile</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\blockfile\SimpleBlockFile.h">
-      <Filter>src/blockfile</Filter>
+      <Filter>src\blockfile</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\ladspa\ladspa.h">
-      <Filter>src/effects/ladspa</Filter>
+      <Filter>src\effects\ladspa</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\ladspa\LadspaEffect.h">
-      <Filter>src/effects/ladspa</Filter>
+      <Filter>src\effects\ladspa</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\toolbars\ControlToolBar.h">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\toolbars\DeviceToolBar.h">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\toolbars\EditToolBar.h">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\toolbars\MeterToolBar.h">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\toolbars\MixerToolBar.h">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\toolbars\SelectionBar.h">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\toolbars\ToolBar.h">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\toolbars\ToolDock.h">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\toolbars\ToolManager.h">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\toolbars\ToolsToolBar.h">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\toolbars\TranscriptionToolBar.h">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\vamp\LoadVamp.h">
-      <Filter>src/effects/vamp</Filter>
+      <Filter>src\effects\vamp</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\vamp\VampEffect.h">
-      <Filter>src/effects/vamp</Filter>
+      <Filter>src\effects\vamp</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\ondemand\ODComputeSummaryTask.h">
-      <Filter>src/ondemand</Filter>
+      <Filter>src\ondemand</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\ondemand\ODDecodeFFmpegTask.h">
-      <Filter>src/ondemand</Filter>
+      <Filter>src\ondemand</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\ondemand\ODDecodeFlacTask.h">
-      <Filter>src/ondemand</Filter>
+      <Filter>src\ondemand</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\ondemand\ODDecodeTask.h">
-      <Filter>src/ondemand</Filter>
+      <Filter>src\ondemand</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\ondemand\ODManager.h">
-      <Filter>src/ondemand</Filter>
+      <Filter>src\ondemand</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\ondemand\ODTask.h">
-      <Filter>src/ondemand</Filter>
+      <Filter>src\ondemand</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\ondemand\ODTaskThread.h">
-      <Filter>src/ondemand</Filter>
+      <Filter>src\ondemand</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\ondemand\ODWaveTrackTaskQueue.h">
-      <Filter>src/ondemand</Filter>
+      <Filter>src\ondemand</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\lv2\LoadLV2.h">
-      <Filter>src/effects/lv2</Filter>
+      <Filter>src\effects\lv2</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\lv2\LV2Effect.h">
-      <Filter>src/effects/lv2</Filter>
+      <Filter>src\effects\lv2</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\SseMathFuncs.h">
       <Filter>src</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\commands\OpenSaveCommands.h">
-      <Filter>src/commands</Filter>
+      <Filter>src\commands</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\import\ImportGStreamer.h">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\HelpSystem.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\import\FormatClassifier.h">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\import\SpecPowerMeter.h">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\import\MultiFormatReader.h">
-      <Filter>src/import</Filter>
+      <Filter>src\import</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\include\audacity\ConfigInterface.h">
       <Filter>includes\audacity</Filter>
@@ -1638,25 +1649,25 @@
       <Filter>src</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\EffectRack.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\toolbars\SpectralSelectionBar.h">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\toolbars\SpectralSelectionBarListener.h">
-      <Filter>src/toolbars</Filter>
+      <Filter>src\toolbars</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\widgets\NumericTextCtrl.h">
-      <Filter>src/widgets</Filter>
+      <Filter>src\widgets</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\include\audacity\EffectAutomationParameters.h">
       <Filter>includes\audacity</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\Phaser.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\effects\NoiseReduction.h">
-      <Filter>src/effects</Filter>
+      <Filter>src\effects</Filter>
     </ClInclude>
     <ClInclude Include="..\..\..\src\DeviceChange.h">
       <Filter>src</Filter>
@@ -1679,6 +1690,24 @@
     <ClInclude Include="..\..\..\src\effects\VST\VSTControlMSW.h">
       <Filter>src/effects/VST</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\..\src\prefs\SpectrogramSettings.h">
+      <Filter>src\prefs</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\src\NumberScale.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\src\prefs\WaveformPrefs.h">
+      <Filter>src\prefs</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\src\prefs\WaveformSettings.h">
+      <Filter>src\prefs</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\src\WaveTrackLocation.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\..\src\prefs\GUISettings.h">
+      <Filter>src\prefs</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <Image Include="..\..\audacity.ico">