changeset 434:db0c86c4e5e9 templating

Merge from the default branch
author Chris Cannam
date Tue, 17 May 2011 13:33:15 +0100
parents ee927c1b7941 (diff) 5f22e0bbe4ba (current diff)
children 586eb6764a2b
files main/MainWindow.cpp
diffstat 9 files changed, 321 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/main/MainWindow.cpp	Wed May 11 11:05:10 2011 +0100
+++ b/main/MainWindow.cpp	Tue May 17 13:33:15 2011 +0100
@@ -30,6 +30,7 @@
 #include "framework/TransformUserConfigurator.h"
 #include "view/ViewManager.h"
 #include "base/Preferences.h"
+#include "base/ResourceFinder.h"
 #include "layer/WaveformLayer.h"
 #include "layer/TimeRulerLayer.h"
 #include "layer/TimeInstantLayer.h"
@@ -112,6 +113,8 @@
 #include <QCheckBox>
 #include <QRegExp>
 #include <QScrollArea>
+#include <QDesktopServices>
+#include <QFileSystemWatcher>
 
 #include <iostream>
 #include <cstdio>
@@ -137,6 +140,7 @@
     m_sliceMenu(0),
     m_recentFilesMenu(0),
     m_recentTransformsMenu(0),
+    m_templatesMenu(0),
     m_rightButtonMenu(0),
     m_rightButtonLayerMenu(0),
     m_rightButtonTransformsMenu(0),
@@ -158,7 +162,8 @@
     m_preferencesDialog(0),
     m_layerTreeDialog(0),
     m_activityLog(new ActivityLog()),
-    m_keyReference(new KeyReference())
+    m_keyReference(new KeyReference()),
+    m_templateWatcher(0)
 {
     Profiler profiler("MainWindow::MainWindow");
 
@@ -388,7 +393,7 @@
     m_keyReference->registerShortcut(action);
     menu->addAction(action);
     toolbar->addAction(action);
-
+/*
     icon = il.load("fileopensession");
     action = new QAction(icon, tr("&Open Session..."), this);
     action->setShortcut(tr("Ctrl+O"));
@@ -396,14 +401,51 @@
     connect(action, SIGNAL(triggered()), this, SLOT(openSession()));
     m_keyReference->registerShortcut(action);
     menu->addAction(action);
-
+*/
     icon = il.load("fileopen");
     icon.addPixmap(il.loadPixmap("fileopen-22"));
-
     action = new QAction(icon, tr("&Open..."), this);
+    action->setShortcut(tr("Ctrl+O"));
     action->setStatusTip(tr("Open a session file, audio file, or layer"));
     connect(action, SIGNAL(triggered()), this, SLOT(openSomething()));
     toolbar->addAction(action);
+    menu->addAction(action);
+
+    // We want this one to go on the toolbar now, if we add it at all,
+    // but on the menu later
+    QAction *iaction = new QAction(tr("&Import More Audio..."), this);
+    iaction->setShortcut(tr("Ctrl+I"));
+    iaction->setStatusTip(tr("Import an extra audio file into a new pane"));
+    connect(iaction, SIGNAL(triggered()), this, SLOT(importMoreAudio()));
+    connect(this, SIGNAL(canImportMoreAudio(bool)), iaction, SLOT(setEnabled(bool)));
+    m_keyReference->registerShortcut(iaction);
+
+    action = new QAction(tr("Open Lo&cation..."), this);
+    action->setShortcut(tr("Ctrl+Shift+O"));
+    action->setStatusTip(tr("Open or import a file from a remote URL"));
+    connect(action, SIGNAL(triggered()), this, SLOT(openLocation()));
+    m_keyReference->registerShortcut(action);
+    menu->addAction(action);
+
+    m_recentFilesMenu = menu->addMenu(tr("Open &Recent"));
+    m_recentFilesMenu->setTearOffEnabled(true);
+    setupRecentFilesMenu();
+    connect(&m_recentFiles, SIGNAL(recentChanged()),
+            this, SLOT(setupRecentFilesMenu()));
+
+    menu->addSeparator();
+
+    QString templatesMenuLabel = tr("Session Template for Audio Files");
+
+#ifdef Q_OS_MAC
+    // Normally this menu will go next to Preferences on the File
+    // menu.  But on OS/X Preferences doesn't appear on the File menu,
+    // so we put it next to the other Session stuff instead.
+    m_templatesMenu = menu->addMenu(templatesMenuLabel);
+    m_templatesMenu->setTearOffEnabled(true);
+    setupTemplatesMenu();
+    menu->addSeparator();
+#endif
 
     icon = il.load("filesave");
     icon.addPixmap(il.loadPixmap("filesave-22"));
@@ -427,6 +469,7 @@
 
     menu->addSeparator();
 
+/*
     icon = il.load("fileopenaudio");
     action = new QAction(icon, tr("&Import Audio File..."), this);
     action->setShortcut(tr("Ctrl+I"));
@@ -434,14 +477,10 @@
     connect(action, SIGNAL(triggered()), this, SLOT(importAudio()));
     m_keyReference->registerShortcut(action);
     menu->addAction(action);
-
-    action = new QAction(tr("Import Secondary Audio File..."), this);
-    action->setShortcut(tr("Ctrl+Shift+I"));
-    action->setStatusTip(tr("Import an extra audio file as a separate layer"));
-    connect(action, SIGNAL(triggered()), this, SLOT(importMoreAudio()));
-    connect(this, SIGNAL(canImportMoreAudio(bool)), action, SLOT(setEnabled(bool)));
-    m_keyReference->registerShortcut(action);
-    menu->addAction(action);
+*/
+
+    // the Import action we made earlier
+    menu->addAction(iaction);
 
     action = new QAction(tr("&Export Audio File..."), this);
     action->setStatusTip(tr("Export selection as an audio file"));
@@ -475,22 +514,13 @@
 
     menu->addSeparator();
 
-    action = new QAction(tr("Open Lo&cation..."), this);
-    action->setShortcut(tr("Ctrl+Shift+O"));
-    action->setStatusTip(tr("Open or import a file from a remote URL"));
-    connect(action, SIGNAL(triggered()), this, SLOT(openLocation()));
-    m_keyReference->registerShortcut(action);
-    menu->addAction(action);
-
-    menu->addSeparator();
-
-    m_recentFilesMenu = menu->addMenu(tr("&Recent Files"));
-    m_recentFilesMenu->setTearOffEnabled(true);
-    setupRecentFilesMenu();
-    connect(&m_recentFiles, SIGNAL(recentChanged()),
-            this, SLOT(setupRecentFilesMenu()));
-
-    menu->addSeparator();
+#ifndef Q_OS_MAC
+    // See note for Q_OS_MAC alternative above
+    m_templatesMenu = menu->addMenu(templatesMenuLabel);
+    m_templatesMenu->setTearOffEnabled(true);
+    setupTemplatesMenu();
+#endif
+
     action = new QAction(tr("&Preferences..."), this);
     action->setStatusTip(tr("Adjust the application preferences"));
     connect(action, SIGNAL(triggered()), this, SLOT(preferences()));
@@ -1617,6 +1647,86 @@
 }
 
 void
+MainWindow::setupTemplatesMenu()
+{
+    m_templatesMenu->clear();
+
+    QSettings settings;
+    settings.beginGroup("MainWindow");
+    QString deflt = settings.value("sessiontemplate", "").toString();
+    setDefaultSessionTemplate(deflt == "" ? "default" : deflt);
+
+    QActionGroup *templatesGroup = new QActionGroup(this);
+
+    bool haveFoundDefault = false;
+
+    QAction *defaultAction = new QAction(tr("Default"), this);
+    defaultAction->setObjectName("default");
+    connect(defaultAction, SIGNAL(triggered()), this, SLOT(changeTemplate()));
+    defaultAction->setCheckable(true);
+    if (deflt == "" || deflt == "default") {
+        defaultAction->setChecked(true);
+        haveFoundDefault = true;
+    }
+    templatesGroup->addAction(defaultAction);
+    m_templatesMenu->addAction(defaultAction);
+
+    m_templatesMenu->addSeparator();
+
+    QAction *action = 0;
+
+    QStringList templates = ResourceFinder().getResourceFiles("templates", "svt");
+
+    bool havePersonal = false;
+
+    // (ordered by name)
+    std::set<QString> byName;
+    foreach (QString t, templates) {
+        if (!t.startsWith(":")) havePersonal = true;
+        byName.insert(QFileInfo(t).baseName());
+    }
+
+    foreach (QString t, byName) {
+        if (t.toLower() == "default") continue;
+        action = new QAction(t, this);
+        connect(action, SIGNAL(triggered()), this, SLOT(changeTemplate()));
+        action->setCheckable(true);
+        if (deflt == t) {
+            action->setChecked(true);
+            haveFoundDefault = true;
+        }
+        templatesGroup->addAction(action);
+        m_templatesMenu->addAction(action);
+    }
+
+    if (!templates.empty()) m_templatesMenu->addSeparator();
+
+    if (!haveFoundDefault) {
+        defaultAction->setChecked(true);
+        setDefaultSessionTemplate("default");
+        settings.setValue("sessiontemplate", "");
+    }
+
+    settings.endGroup();
+
+    action = new QAction(tr("Save Template from Current Session..."), this);
+    connect(action, SIGNAL(triggered()), this, SLOT(saveSessionAsTemplate()));
+    m_templatesMenu->addAction(action);
+
+    action = new QAction(tr("Manage Saved Templates"), this);
+    connect(action, SIGNAL(triggered()), this, SLOT(manageSavedTemplates()));
+    action->setEnabled(havePersonal);
+    m_templatesMenu->addAction(action);
+
+    if (!m_templateWatcher) {
+        m_templateWatcher = new QFileSystemWatcher(this);
+        m_templateWatcher->addPath(ResourceFinder().getResourceSaveDir("templates"));
+        connect(m_templateWatcher, SIGNAL(directoryChanged(const QString &)),
+                this, SLOT(setupTemplatesMenu()));
+    }
+}
+
+void
 MainWindow::setupRecentTransformsMenu()
 {
     m_recentTransformsMenu->clear();
@@ -2149,7 +2259,7 @@
     QString path = getOpenFileName(FileFinder::AudioFile);
 
     if (path != "") {
-	if (openAudio(path, ReplaceMainModel) == FileOpenFailed) {
+	if (openAudio(path, ReplaceSession) == FileOpenFailed) {
             emit hideSplash();
 	    QMessageBox::critical(this, tr("Failed to open file"),
 				  tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path));
@@ -2673,7 +2783,7 @@
 
     if (path.isEmpty()) return;
 
-    FileOpenStatus status = open(path, AskUser);
+    FileOpenStatus status = open(path, ReplaceSession);
 
     if (status == FileOpenFailed) {
         emit hideSplash();
@@ -2705,7 +2815,7 @@
 
     if (text.isEmpty()) return;
 
-    FileOpenStatus status = open(text);
+    FileOpenStatus status = open(text, AskUser);
 
     if (status == FileOpenFailed) {
         emit hideSplash();
@@ -2733,7 +2843,7 @@
     QString path = action->text();
     if (path == "") return;
 
-    FileOpenStatus status = open(path);
+    FileOpenStatus status = open(path, ReplaceSession);
 
     if (status == FileOpenFailed) {
         emit hideSplash();
@@ -2747,6 +2857,68 @@
 }
 
 void
+MainWindow::changeTemplate()
+{
+    QObject *s = sender();
+    QAction *action = qobject_cast<QAction *>(s);
+
+    if (!action) {
+	std::cerr << "WARNING: MainWindow::changeTemplate: sender is not an action"
+		  << std::endl;
+	return;
+    }
+
+    QString n = action->objectName();
+    if (n == "") n = action->text();
+
+    if (n == "") {
+        std::cerr << "WARNING: MainWindow::changeTemplate: sender has no name"
+                  << std::endl;
+        return;
+    }
+
+    setDefaultSessionTemplate(n);
+
+    QSettings settings;
+    settings.beginGroup("MainWindow");
+    settings.setValue("sessiontemplate", n);
+    settings.endGroup();
+}
+
+void
+MainWindow::saveSessionAsTemplate()
+{
+    QString name = QInputDialog::getText
+        (this, tr("Enter template name"),
+         tr("Please enter a name for the saved template:"));
+    if (name == "") return;
+    
+    name.replace(QRegExp("[^\\w\\s\\.\"'-]"), "_");
+
+    ResourceFinder rf;
+    QString dir = rf.getResourceSaveDir("templates");
+    QString filename = QString("%1/%2.svt").arg(dir).arg(name);
+    if (QFile(filename).exists()) {
+        if (QMessageBox::warning(this,
+                                 tr("Template file exists"),
+                                 tr("<b>Template file exists</b><p>The template \"%1\" already exists.<br>Overwrite it?").arg(name),
+                                 QMessageBox::Ok | QMessageBox::Cancel,
+                                 QMessageBox::Cancel) != QMessageBox::Ok) {
+            return;
+        }
+    }
+
+    saveSessionTemplate(filename);
+}
+
+void
+MainWindow::manageSavedTemplates()
+{
+    ResourceFinder rf;
+    QDesktopServices::openUrl("file:" + rf.getResourceSaveDir("templates"));
+}
+
+void
 MainWindow::paneAdded(Pane *pane)
 {
     if (m_overview) m_overview->registerView(pane);
--- a/main/MainWindow.h	Wed May 11 11:05:10 2011 +0100
+++ b/main/MainWindow.h	Tue May 17 13:33:15 2011 +0100
@@ -58,6 +58,7 @@
 class KeyReference;
 class Labeller;
 class ActivityLog;
+class QFileSystemWatcher;
 
 class MainWindow : public MainWindowBase
 {
@@ -83,6 +84,7 @@
     virtual void openSomething();
     virtual void openLocation();
     virtual void openRecentFile();
+    virtual void changeTemplate();
     virtual void exportAudio();
     virtual void importLayer();
     virtual void exportLayer();
@@ -140,6 +142,7 @@
 
     virtual void setupRecentFilesMenu();
     virtual void setupRecentTransformsMenu();
+    virtual void setupTemplatesMenu();
 
     virtual void playSpeedChanged(int);
     virtual void playSoloToggled();
@@ -169,6 +172,9 @@
     virtual void midiEventsAvailable();
     virtual void playStatusChanged(bool);
 
+    virtual void saveSessionAsTemplate();
+    virtual void manageSavedTemplates();
+
     virtual void website();
     virtual void help();
     virtual void about();
@@ -190,6 +196,7 @@
     QMenu                   *m_sliceMenu;
     QMenu                   *m_recentFilesMenu;
     QMenu                   *m_recentTransformsMenu;
+    QMenu                   *m_templatesMenu;
     QMenu                   *m_rightButtonMenu;
     QMenu                   *m_rightButtonLayerMenu;
     QMenu                   *m_rightButtonTransformsMenu;
@@ -221,6 +228,8 @@
     ActivityLog             *m_activityLog;
     KeyReference            *m_keyReference;
 
+    QFileSystemWatcher      *m_templateWatcher;
+
     struct LayerConfiguration {
 	LayerConfiguration(LayerFactory::LayerType _layer
 			                       = LayerFactory::TimeRuler,
--- a/main/main.cpp	Wed May 11 11:05:10 2011 +0100
+++ b/main/main.cpp	Tue May 17 13:33:15 2011 +0100
@@ -468,7 +468,7 @@
     }
     if (status != MainWindow::FileOpenSucceeded) {
         if (!haveMainModel) {
-            status = m_mainWindow->open(path, MainWindow::ReplaceMainModel);
+            status = m_mainWindow->open(path, MainWindow::ReplaceSession);
             if (status == MainWindow::FileOpenSucceeded) {
                 haveMainModel = true;
             }
Binary file samples/silent.wav has changed
--- a/sonic-visualiser.qrc	Wed May 11 11:05:10 2011 +0100
+++ b/sonic-visualiser.qrc	Tue May 17 13:33:15 2011 +0100
@@ -100,10 +100,15 @@
     <file>samples/kick.wav</file>
     <file>samples/organ.wav</file>
     <file>samples/piano.wav</file>
+    <file>samples/silent.wav</file>
     <file>samples/snare.wav</file>
     <file>samples/stick.wav</file>
     <file>samples/strike.wav</file>
     <file>samples/tap.wav</file>
+    <file>templates/default.svt</file>
+    <file>templates/Scrolling Waveforms.svt</file>
+    <file>templates/Spectrograms.svt</file>
+    <file>templates/Waveform and Melodic Range Spectrogram.svt</file>
     <file>i18n/sonic-visualiser_ru.qm</file>
     <file>i18n/sonic-visualiser_en_GB.qm</file>
     <file>i18n/sonic-visualiser_en_US.qm</file>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/Scrolling Waveforms.svt	Tue May 17 13:33:15 2011 +0100
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE sonic-visualiser>
+<sv>
+<data>
+  <model id="7" name="placeholder" sampleRate="44100" type="wavefile" file=":samples/silent.wav" mainModel="true"/>
+  <playparameters mute="false" pan="0" gain="1" pluginId="" model="7"/>
+  <layer id="8" type="timeruler" name="Ruler &lt;2&gt;" model="7"  colourName="Black" colour="#000000" darkBackground="false" />
+  <layer id="3" type="spectrogram" name="Spectrogram &lt;3&gt;" model="7"  channel="0" windowSize="1024" windowHopLevel="2" gain="1" threshold="0" minFrequency="10" maxFrequency="0" colourScale="3" colourScheme="0" colourRotation="0" frequencyScale="0" binDisplay="0" normalizeColumns="false" normalizeVisibleArea="false"/>
+  <layer id="9" type="timeruler" name="Ruler &lt;4&gt;" model="7"  colourName="Black" colour="#000000" darkBackground="false" />
+  <layer id="10" type="waveform" name="Waveform &lt;3&gt;" model="7"  gain="1" showMeans="1" greyscale="1" channelMode="0" channel="-1" scale="0" aggressive="0" autoNormalize="0" colourName="Purple" colour="#c832ff" darkBackground="false" />
+  <layer id="11" type="timeruler" name="Ruler &lt;3&gt;" model="7"  colourName="Black" colour="#000000" darkBackground="false" />
+  <layer id="12" type="spectrogram" name="Spectrogram &lt;2&gt;" model="7"  channel="-1" windowSize="4096" windowHopLevel="5" gain="1" threshold="0" minFrequency="40" maxFrequency="2000" colourScale="0" colourScheme="0" colourRotation="0" frequencyScale="1" binDisplay="2" normalizeColumns="true" normalizeVisibleArea="false"/>
+  <layer id="13" type="waveform" name="Waveform" model="7"  gain="1" showMeans="1" greyscale="0" channelMode="0" channel="-1" scale="0" aggressive="0" autoNormalize="0" colourName="Black" colour="#000000" darkBackground="false" />
+  <layer id="14" type="waveform" name="Waveform &lt;2&gt;" model="7"  gain="1" showMeans="1" greyscale="1" channelMode="0" channel="-1" scale="0" aggressive="0" autoNormalize="0" colourName="Blue" colour="#000080" darkBackground="false" />
+  <layer id="15" type="spectrogram" name="Spectrogram" model="7"  channel="-1" windowSize="8192" windowHopLevel="4" gain="1" threshold="0" minFrequency="40" maxFrequency="1500" colourScale="0" colourScheme="1" colourRotation="0" frequencyScale="1" binDisplay="0" normalizeColumns="false" normalizeVisibleArea="false"/>
+  <layer id="16" type="timeruler" name="Ruler" model="7"  colourName="Black" colour="#000000" darkBackground="false" />
+</data>
+<display>
+  <window width="1216" height="701"/>
+  <view centre="0" zoom="1024" followPan="1" followZoom="1" tracking="scroll"  type="pane" centreLineVisible="1" height="210" >
+    <layer id="14" type="waveform" name="Waveform &lt;2&gt;" model="7" visible="true"/>
+    <layer id="11" type="timeruler" name="Ruler &lt;3&gt;" model="7" visible="true"/>
+  </view>
+  <view centre="0" zoom="16" followPan="1" followZoom="0" tracking="scroll"  type="pane" centreLineVisible="1" height="335" >
+    <layer id="9" type="timeruler" name="Ruler &lt;4&gt;" model="7" visible="false"/>
+    <layer id="10" type="waveform" name="Waveform &lt;3&gt;" model="7" visible="true"/>
+  </view>
+</display>
+<selections >
+</selections>
+</sv>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/Spectrograms.svt	Tue May 17 13:33:15 2011 +0100
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE sonic-visualiser>
+<sv>
+<data>
+  <model id="0" name="placeholder" sampleRate="44100" type="wavefile" file=":samples/silent.wav" mainModel="true"/>
+  <playparameters mute="false" pan="0" gain="1" pluginId="" model="0"/>
+  <layer id="1" type="timeruler" name="Ruler" model="0"  colourName="Black" colour="#000000" darkBackground="false" />
+  <layer id="2" type="waveform" name="Waveform" model="0"  gain="1" showMeans="1" greyscale="0" channelMode="0" channel="-1" scale="0" aggressive="0" autoNormalize="0" colourName="Black" colour="#000000" darkBackground="false" />
+  <layer id="3" type="spectrogram" name="Spectrogram" model="0"  channel="-1" windowSize="8192" windowHopLevel="4" gain="1" threshold="0" minFrequency="40" maxFrequency="1500" colourScale="0" colourScheme="1" colourRotation="0" frequencyScale="1" binDisplay="0" normalizeColumns="false" normalizeVisibleArea="false"/>
+  <layer id="4" type="timeruler" name="Ruler &lt;2&gt;" model="0"  colourName="Black" colour="#000000" darkBackground="false" />
+  <layer id="5" type="spectrogram" name="Spectrogram &lt;2&gt;" model="0"  channel="-1" windowSize="4096" windowHopLevel="5" gain="1" threshold="0" minFrequency="40" maxFrequency="2000" colourScale="0" colourScheme="0" colourRotation="0" frequencyScale="1" binDisplay="2" normalizeColumns="true" normalizeVisibleArea="false"/>
+  <layer id="6" type="spectrogram" name="Spectrogram &lt;3&gt;" model="0"  channel="0" windowSize="1024" windowHopLevel="2" gain="1" threshold="0" minFrequency="10" maxFrequency="0" colourScale="3" colourScheme="0" colourRotation="0" frequencyScale="0" binDisplay="0" normalizeColumns="false" normalizeVisibleArea="false"/>
+</data>
+<display>
+  <window width="1413" height="925"/>
+  <view centre="0" zoom="512" followPan="1" followZoom="1" tracking="page"  type="pane" centreLineVisible="1" height="254" >
+    <layer id="1" type="timeruler" name="Ruler" model="0" visible="true"/>
+    <layer id="2" type="waveform" name="Waveform" model="0" visible="true"/>
+    <layer id="6" type="spectrogram" name="Spectrogram &lt;3&gt;" model="0" visible="true"/>
+  </view>
+  <view centre="0" zoom="512" followPan="1" followZoom="1" tracking="page"  type="pane" centreLineVisible="1" height="255" >
+    <layer id="4" type="timeruler" name="Ruler &lt;2&gt;" model="0" visible="true"/>
+    <layer id="3" type="spectrogram" name="Spectrogram" model="0" visible="true"/>
+  </view>
+  <view centre="0" zoom="512" followPan="1" followZoom="1" tracking="page"  type="pane" centreLineVisible="1" height="254" >
+    <layer id="4" type="timeruler" name="Ruler &lt;2&gt;" model="0" visible="true"/>
+    <layer id="5" type="spectrogram" name="Spectrogram &lt;2&gt;" model="0" visible="true"/>
+  </view>
+</display>
+<selections >
+</selections>
+</sv>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/Waveform and Melodic Range Spectrogram.svt	Tue May 17 13:33:15 2011 +0100
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE sonic-visualiser>
+<sv>
+<data>
+  <model id="18" name="placeholder" sampleRate="44100" type="wavefile" file=":samples/silent.wav" mainModel="true"/>
+  <playparameters mute="false" pan="0" gain="1" pluginId="" model="18"/>
+  <layer id="19" type="waveform" name="Waveform" model="18"  gain="1" showMeans="1" greyscale="0" channelMode="0" channel="-1" scale="0" aggressive="0" autoNormalize="0" colourName="Bright Blue" colour="#1e96ff" darkBackground="true" />
+  <layer id="20" type="timeruler" name="Ruler" model="18"  colourName="Bright Orange" colour="#ffbc50" darkBackground="true" />
+  <layer id="21" type="timeruler" name="Ruler &lt;2&gt;" model="18"  colourName="Bright Orange" colour="#ffbc50" darkBackground="true" />
+  <layer id="22" type="spectrogram" name="Spectrogram" model="18"  channel="-1" windowSize="8192" windowHopLevel="4" gain="1" threshold="0" minFrequency="40" maxFrequency="1500" colourScale="0" colourScheme="1" colourRotation="0" frequencyScale="1" binDisplay="0" normalizeColumns="false" normalizeVisibleArea="false"/>
+</data>
+<display>
+  <window width="1147" height="686"/>
+  <view centre="0" zoom="1024" followPan="1" followZoom="1" tracking="page"  type="pane" centreLineVisible="1" height="197" >
+    <layer id="20" type="timeruler" name="Ruler" model="18" visible="true"/>
+    <layer id="19" type="waveform" name="Waveform" model="18" visible="true"/>
+  </view>
+  <view centre="0" zoom="1024" followPan="1" followZoom="1" tracking="page"  type="pane" centreLineVisible="1" height="333" >
+    <layer id="21" type="timeruler" name="Ruler &lt;2&gt;" model="18" visible="true"/>
+    <layer id="22" type="spectrogram" name="Spectrogram" model="18" visible="true"/>
+  </view>
+</display>
+<selections >
+</selections>
+</sv>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/default.svt	Tue May 17 13:33:15 2011 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE sonic-visualiser>
+<sv>
+<data>
+  <layer id="1" type="timeruler" name="Ruler" model="0"  colourName="Black" colour="#000000" darkBackground="false" />
+  <layer id="2" type="waveform" name="Waveform" model="0"  gain="1" showMeans="1" greyscale="1" channelMode="0" channel="-1" scale="0" aggressive="0" autoNormalize="0" colourName="Black" colour="#000000" darkBackground="false" />
+</data>
+<display>
+  <view centre="0" zoom="1024" followPan="1" followZoom="1" tracking="page"  type="pane" centreLineVisible="1">
+    <layer id="1" type="timeruler" name="Ruler" model="0" visible="true"/>
+    <layer id="2" type="waveform" name="Waveform" model="0" visible="true"/>
+  </view>
+</display>
+</sv>