Mercurial > hg > sonic-visualiser
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; }
--- 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 <2>" model="7" colourName="Black" colour="#000000" darkBackground="false" /> + <layer id="3" type="spectrogram" name="Spectrogram <3>" 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 <4>" model="7" colourName="Black" colour="#000000" darkBackground="false" /> + <layer id="10" type="waveform" name="Waveform <3>" 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 <3>" model="7" colourName="Black" colour="#000000" darkBackground="false" /> + <layer id="12" type="spectrogram" name="Spectrogram <2>" 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 <2>" 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 <2>" model="7" visible="true"/> + <layer id="11" type="timeruler" name="Ruler <3>" 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 <4>" model="7" visible="false"/> + <layer id="10" type="waveform" name="Waveform <3>" 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 <2>" model="0" colourName="Black" colour="#000000" darkBackground="false" /> + <layer id="5" type="spectrogram" name="Spectrogram <2>" 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 <3>" 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 <3>" 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 <2>" 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 <2>" model="0" visible="true"/> + <layer id="5" type="spectrogram" name="Spectrogram <2>" 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 <2>" 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 <2>" 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>