Mercurial > hg > tony
view src/MainWindow.cpp @ 198:bb391844e2aa
Switching pitch candidate no longer wraps around: you can't go higher than the highest or lower than the lowest (though you can go either "up" or "down" if none of the alternate candidates has been selected yet, regardless of whether the candidates are higher or lower than the actual pitch track)
author | Chris Cannam |
---|---|
date | Wed, 05 Mar 2014 11:39:28 +0000 |
parents | 797395e56489 |
children | 0ba33d6c0a71 |
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ /* Tony An intonation analysis and annotation tool Centre for Digital Music, Queen Mary, University of London. This file copyright 2006-2012 Chris Cannam and QMUL. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See the file COPYING included with this distribution for more information. */ #include "../version.h" #include "MainWindow.h" #include "NetworkPermissionTester.h" #include "Analyser.h" #include "framework/Document.h" #include "framework/VersionTester.h" #include "view/Pane.h" #include "view/PaneStack.h" #include "data/model/WaveFileModel.h" #include "data/model/NoteModel.h" #include "data/model/FlexiNoteModel.h" #include "layer/FlexiNoteLayer.h" #include "data/model/NoteModel.h" #include "view/ViewManager.h" #include "base/Preferences.h" #include "layer/WaveformLayer.h" #include "layer/TimeInstantLayer.h" #include "layer/TimeValueLayer.h" #include "layer/SpectrogramLayer.h" #include "widgets/Fader.h" #include "view/Overview.h" #include "widgets/AudioDial.h" #include "widgets/IconLoader.h" #include "widgets/KeyReference.h" #include "audioio/AudioCallbackPlaySource.h" #include "audioio/AudioCallbackPlayTarget.h" #include "audioio/PlaySpeedRangeMapper.h" #include "base/Profiler.h" #include "base/UnitDatabase.h" #include "layer/ColourDatabase.h" #include "base/Selection.h" #include "rdf/RDFImporter.h" #include "data/fileio/DataFileReaderFactory.h" #include "data/fileio/CSVFormat.h" #include "data/fileio/CSVFileWriter.h" #include "data/fileio/MIDIFileWriter.h" #include "rdf/RDFExporter.h" // For version information #include "vamp/vamp.h" #include "vamp-sdk/PluginBase.h" #include "plugin/api/ladspa.h" #include "plugin/api/dssi.h" #include <QApplication> #include <QMessageBox> #include <QGridLayout> #include <QLabel> #include <QMenuBar> #include <QToolBar> #include <QToolButton> #include <QInputDialog> #include <QStatusBar> #include <QFileInfo> #include <QDir> #include <QProcess> #include <QPushButton> #include <QSettings> #include <QScrollArea> #include <QPainter> #include <iostream> #include <cstdio> #include <errno.h> using std::vector; MainWindow::MainWindow(bool withAudioOutput, bool withOSCSupport) : MainWindowBase(withAudioOutput, withOSCSupport, false), m_overview(0), m_mainMenusCreated(false), m_playbackMenu(0), m_recentFilesMenu(0), m_rightButtonMenu(0), m_rightButtonPlaybackMenu(0), m_deleteSelectedAction(0), m_ffwdAction(0), m_rwdAction(0), m_intelligentActionOn(true), //GF: !!! temporary m_keyReference(new KeyReference()) { setWindowTitle(QApplication::applicationName()); UnitDatabase *udb = UnitDatabase::getInstance(); udb->registerUnit("Hz"); udb->registerUnit("dB"); udb->registerUnit("s"); ColourDatabase *cdb = ColourDatabase::getInstance(); cdb->addColour(Qt::black, tr("Black")); cdb->addColour(Qt::darkRed, tr("Red")); cdb->addColour(Qt::darkBlue, tr("Blue")); cdb->addColour(Qt::darkGreen, tr("Green")); cdb->addColour(QColor(200, 50, 255), tr("Purple")); cdb->addColour(QColor(255, 150, 50), tr("Orange")); cdb->addColour(QColor(180, 180, 180), tr("Grey")); cdb->setUseDarkBackground(cdb->addColour(Qt::white, tr("White")), true); cdb->setUseDarkBackground(cdb->addColour(Qt::red, tr("Bright Red")), true); cdb->setUseDarkBackground(cdb->addColour(QColor(30, 150, 255), tr("Bright Blue")), true); cdb->setUseDarkBackground(cdb->addColour(Qt::green, tr("Bright Green")), true); cdb->setUseDarkBackground(cdb->addColour(QColor(225, 74, 255), tr("Bright Purple")), true); cdb->setUseDarkBackground(cdb->addColour(QColor(255, 188, 80), tr("Bright Orange")), true); Preferences::getInstance()->setResampleOnLoad(true); Preferences::getInstance()->setSpectrogramSmoothing (Preferences::SpectrogramInterpolated); QSettings settings; settings.beginGroup("MainWindow"); settings.setValue("showstatusbar", false); settings.endGroup(); settings.beginGroup("Transformer"); settings.setValue("use-flexi-note-model", true); settings.endGroup(); settings.beginGroup("LayerDefaults"); settings.setValue("waveform", QString("<layer scale=\"%1\" channelMode=\"%2\"/>") .arg(int(WaveformLayer::LinearScale)) .arg(int(WaveformLayer::MixChannels))); settings.endGroup(); m_viewManager->setAlignMode(false); m_viewManager->setPlaySoloMode(false); m_viewManager->setToolMode(ViewManager::NavigateMode); m_viewManager->setZoomWheelsEnabled(false); m_viewManager->setIlluminateLocalFeatures(true); m_viewManager->setShowWorkTitle(true); m_viewManager->setShowCentreLine(false); m_viewManager->setOverlayMode(ViewManager::MinimalOverlays); connect(m_viewManager, SIGNAL(selectionChangedByUser()), this, SLOT(selectionChangedByUser())); QFrame *frame = new QFrame; setCentralWidget(frame); QGridLayout *layout = new QGridLayout; QScrollArea *scroll = new QScrollArea(frame); scroll->setWidgetResizable(true); scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); scroll->setFrameShape(QFrame::NoFrame); // We have a pane stack: it comes with the territory. However, we // have a fixed and known number of panes in it -- it isn't // variable m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks); m_paneStack->setShowPaneAccessories(false); connect(m_paneStack, SIGNAL(doubleClickSelectInvoked(size_t)), this, SLOT(doubleClickSelectInvoked(size_t))); scroll->setWidget(m_paneStack); m_overview = new Overview(frame); m_overview->setViewManager(m_viewManager); m_overview->setFixedHeight(40); #ifndef _WIN32 // For some reason, the contents of the overview never appear if we // make this setting on Windows. I have no inclination at the moment // to track down the reason why. m_overview->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); #endif connect(m_overview, SIGNAL(contextHelpChanged(const QString &)), this, SLOT(contextHelpChanged(const QString &))); m_panLayer = new WaveformLayer; m_panLayer->setChannelMode(WaveformLayer::MergeChannels); m_panLayer->setAggressiveCacheing(true); m_overview->addLayer(m_panLayer); if (m_viewManager->getGlobalDarkBackground()) { m_panLayer->setBaseColour (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green"))); } else { m_panLayer->setBaseColour (ColourDatabase::getInstance()->getColourIndex(tr("Blue"))); } m_fader = new Fader(frame, false); connect(m_fader, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); connect(m_fader, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); m_playSpeed = new AudioDial(frame); m_playSpeed->setMinimum(0); m_playSpeed->setMaximum(200); m_playSpeed->setValue(100); m_playSpeed->setFixedWidth(24); m_playSpeed->setFixedHeight(24); m_playSpeed->setNotchesVisible(true); m_playSpeed->setPageStep(10); m_playSpeed->setObjectName(tr("Playback Speedup")); m_playSpeed->setDefaultValue(100); m_playSpeed->setRangeMapper(new PlaySpeedRangeMapper(0, 200)); m_playSpeed->setShowToolTip(true); connect(m_playSpeed, SIGNAL(valueChanged(int)), this, SLOT(playSpeedChanged(int))); connect(m_playSpeed, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); connect(m_playSpeed, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); // Gain controls m_gainAudio = new AudioDial(frame); m_gainAudio->setMinimum(-50); m_gainAudio->setMaximum(50); m_gainAudio->setValue(0); m_gainAudio->setDefaultValue(0); m_gainAudio->setFixedWidth(24); m_gainAudio->setFixedHeight(24); m_gainAudio->setNotchesVisible(true); m_gainAudio->setPageStep(10); m_gainAudio->setObjectName(tr("Audio Track Gain")); m_gainAudio->setRangeMapper(new LinearRangeMapper(-50, 50, -25, 25, tr("dB"))); m_gainAudio->setShowToolTip(true); connect(m_gainAudio, SIGNAL(valueChanged(int)), this, SLOT(audioGainChanged(int))); connect(m_gainAudio, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); connect(m_gainAudio, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); m_gainPitch = new AudioDial(frame); m_gainPitch->setMinimum(-50); m_gainPitch->setMaximum(50); m_gainPitch->setValue(0); m_gainPitch->setDefaultValue(0); m_gainPitch->setFixedWidth(24); m_gainPitch->setFixedHeight(24); m_gainPitch->setNotchesVisible(true); m_gainPitch->setPageStep(10); m_gainPitch->setObjectName(tr("Pitch Track Gain")); m_gainPitch->setRangeMapper(new LinearRangeMapper(-50, 50, -25, 25, tr("dB"))); m_gainPitch->setShowToolTip(true); connect(m_gainPitch, SIGNAL(valueChanged(int)), this, SLOT(pitchGainChanged(int))); connect(m_gainPitch, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); connect(m_gainPitch, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); m_gainNotes = new AudioDial(frame); m_gainNotes->setMinimum(-50); m_gainNotes->setMaximum(50); m_gainNotes->setValue(0); m_gainNotes->setDefaultValue(0); m_gainNotes->setFixedWidth(24); m_gainNotes->setFixedHeight(24); m_gainNotes->setNotchesVisible(true); m_gainNotes->setPageStep(10); m_gainNotes->setObjectName(tr("Pitch Track Gain")); m_gainNotes->setRangeMapper(new LinearRangeMapper(-50, 50, -25, 25, tr("dB"))); m_gainNotes->setShowToolTip(true); connect(m_gainNotes, SIGNAL(valueChanged(int)), this, SLOT(notesGainChanged(int))); connect(m_gainNotes, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); connect(m_gainNotes, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); // End of Gain controls // Pan controls m_panAudio = new AudioDial(frame); m_panAudio->setMinimum(-100); m_panAudio->setMaximum(100); m_panAudio->setValue(-100); m_panAudio->setDefaultValue(-100); m_panAudio->setFixedWidth(24); m_panAudio->setFixedHeight(24); m_panAudio->setNotchesVisible(true); m_panAudio->setPageStep(10); m_panAudio->setObjectName(tr("Audio Track Pan")); m_panAudio->setRangeMapper(new LinearRangeMapper(-100, 100, -100, 100, tr(""))); m_panAudio->setShowToolTip(true); connect(m_panAudio, SIGNAL(valueChanged(int)), this, SLOT(audioPanChanged(int))); connect(m_panAudio, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); connect(m_panAudio, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); m_panPitch = new AudioDial(frame); m_panPitch->setMinimum(-100); m_panPitch->setMaximum(100); m_panPitch->setValue(100); m_panPitch->setDefaultValue(100); m_panPitch->setFixedWidth(24); m_panPitch->setFixedHeight(24); m_panPitch->setNotchesVisible(true); m_panPitch->setPageStep(10); m_panPitch->setObjectName(tr("Pitch Track Pan")); m_panPitch->setRangeMapper(new LinearRangeMapper(-100, 100, -100, 100, tr(""))); m_panPitch->setShowToolTip(true); connect(m_panPitch, SIGNAL(valueChanged(int)), this, SLOT(pitchPanChanged(int))); connect(m_panPitch, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); connect(m_panPitch, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); m_panNotes = new AudioDial(frame); m_panNotes->setMinimum(-100); m_panNotes->setMaximum(100); m_panNotes->setValue(100); m_panNotes->setDefaultValue(100); m_panNotes->setFixedWidth(24); m_panNotes->setFixedHeight(24); m_panNotes->setNotchesVisible(true); m_panNotes->setPageStep(10); m_panNotes->setObjectName(tr("Notes Track Pan")); m_panNotes->setRangeMapper(new LinearRangeMapper(-100, 100, -100, 100, tr(""))); m_panNotes->setShowToolTip(true); connect(m_panNotes, SIGNAL(valueChanged(int)), this, SLOT(notesPanChanged(int))); connect(m_panNotes, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); connect(m_panNotes, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); // End of Pan controls layout->setSpacing(4); layout->addWidget(m_overview, 0, 1); layout->addWidget(scroll, 1, 1); layout->setColumnStretch(1, 10); frame->setLayout(layout); m_analyser = new Analyser(); connect(m_analyser, SIGNAL(layersChanged()), this, SLOT(updateLayerStatuses())); connect(m_analyser, SIGNAL(layersChanged()), this, SLOT(updateMenuStates())); setupMenus(); setupToolbars(); setupHelpMenu(); statusBar(); newSession(); settings.beginGroup("MainWindow"); settings.setValue("zoom-default", 512); settings.endGroup(); zoomDefault(); NetworkPermissionTester tester; bool networkPermission = tester.havePermission(); if (networkPermission) { m_versionTester = new VersionTester ("sonicvisualiser.org", "latest-tony-version.txt", TONY_VERSION); connect(m_versionTester, SIGNAL(newerVersionAvailable(QString)), this, SLOT(newerVersionAvailable(QString))); } else { m_versionTester = 0; } } MainWindow::~MainWindow() { delete m_analyser; delete m_keyReference; Profiles::getInstance()->dump(); } void MainWindow::setupMenus() { if (!m_mainMenusCreated) { m_rightButtonMenu = new QMenu(); } if (!m_mainMenusCreated) { CommandHistory::getInstance()->registerMenu(m_rightButtonMenu); m_rightButtonMenu->addSeparator(); } setupFileMenu(); setupEditMenu(); setupViewMenu(); m_mainMenusCreated = true; } void MainWindow::setupFileMenu() { if (m_mainMenusCreated) return; QMenu *menu = menuBar()->addMenu(tr("&File")); menu->setTearOffEnabled(true); QToolBar *toolbar = addToolBar(tr("File Toolbar")); m_keyReference->setCategory(tr("File and Session Management")); IconLoader il; QIcon icon; QAction *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 file")); connect(action, SIGNAL(triggered()), this, SLOT(openFile())); m_keyReference->registerShortcut(action); menu->addAction(action); toolbar->addAction(action); action = new QAction(tr("Open Lo&cation..."), this); action->setShortcut(tr("Ctrl+Shift+O")); action->setStatusTip(tr("Open 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(); action = new QAction(tr("Import Pitch Track Data..."), this); action->setStatusTip(tr("Import pitch-track data from a file")); connect(action, SIGNAL(triggered()), this, SLOT(importPitchLayer())); connect(this, SIGNAL(canImportLayer(bool)), action, SLOT(setEnabled(bool))); menu->addAction(action); action = new QAction(tr("Export Pitch Track Data..."), this); action->setStatusTip(tr("Export pitch-track data to a file")); connect(action, SIGNAL(triggered()), this, SLOT(exportPitchLayer())); connect(this, SIGNAL(canExportLayer(bool)), action, SLOT(setEnabled(bool))); menu->addAction(action); action = new QAction(tr("Export Note Data..."), this); action->setStatusTip(tr("Export note data to a file")); connect(action, SIGNAL(triggered()), this, SLOT(exportNoteLayer())); connect(this, SIGNAL(canExportLayer(bool)), action, SLOT(setEnabled(bool))); menu->addAction(action); menu->addSeparator(); action = new QAction(il.load("exit"), tr("&Quit"), this); action->setShortcut(tr("Ctrl+Q")); action->setStatusTip(tr("Exit %1").arg(QApplication::applicationName())); connect(action, SIGNAL(triggered()), this, SLOT(close())); m_keyReference->registerShortcut(action); menu->addAction(action); } void MainWindow::setupEditMenu() { if (m_mainMenusCreated) return; QMenu *menu = menuBar()->addMenu(tr("&Edit")); menu->setTearOffEnabled(true); CommandHistory::getInstance()->registerMenu(menu); menu->addSeparator(); QToolBar *toolbar = addToolBar(tr("Tools Toolbar")); CommandHistory::getInstance()->registerToolbar(toolbar); m_keyReference->setCategory(tr("Tool Selection")); QActionGroup *group = new QActionGroup(this); IconLoader il; QAction *action = toolbar->addAction(il.load("navigate"), tr("Navigate")); action->setCheckable(true); action->setChecked(true); action->setShortcut(tr("1")); action->setStatusTip(tr("Navigate")); connect(action, SIGNAL(triggered()), this, SLOT(toolNavigateSelected())); connect(this, SIGNAL(replacedDocument()), action, SLOT(trigger())); group->addAction(action); menu->addAction(action); m_keyReference->registerShortcut(action); action = toolbar->addAction(il.load("move"), tr("Edit")); action->setCheckable(true); action->setShortcut(tr("2")); action->setStatusTip(tr("Edit with Note Intelligence")); connect(action, SIGNAL(triggered()), this, SLOT(toolEditSelected())); connect(this, SIGNAL(canEditLayer(bool)), action, SLOT(setEnabled(bool))); group->addAction(action); menu->addAction(action); m_keyReference->registerShortcut(action); /* Remove for now... action = toolbar->addAction(il.load("notes"), tr("Free Edit")); action->setCheckable(true); action->setShortcut(tr("3")); action->setStatusTip(tr("Free Edit")); connect(action, SIGNAL(triggered()), this, SLOT(toolFreeEditSelected())); connect(this, SIGNAL(canEditLayer(bool)), action, SLOT(setEnabled(bool))); group->addAction(action); m_keyReference->registerShortcut(action); */ menu->addSeparator(); m_keyReference->setCategory(tr("Selection")); action = new QAction(tr("Select &All"), this); action->setShortcut(tr("Ctrl+A")); action->setStatusTip(tr("Select the whole duration of the current session")); connect(action, SIGNAL(triggered()), this, SLOT(selectAll())); connect(this, SIGNAL(canSelect(bool)), action, SLOT(setEnabled(bool))); m_keyReference->registerShortcut(action); menu->addAction(action); m_rightButtonMenu->addAction(action); action = new QAction(tr("C&lear Selection"), this); action->setShortcut(tr("Esc")); action->setStatusTip(tr("Clear the selection")); connect(action, SIGNAL(triggered()), this, SLOT(abandonSelection())); connect(this, SIGNAL(canClearSelection(bool)), action, SLOT(setEnabled(bool))); m_keyReference->registerShortcut(action); menu->addAction(action); m_rightButtonMenu->addAction(action); menu->addSeparator(); m_rightButtonMenu->addSeparator(); m_keyReference->setCategory(tr("Pitch Track")); m_showCandidatesAction = new QAction(tr("Show Pitch Candidates"), this); m_showCandidatesAction->setShortcut(tr("Ctrl+Return")); m_showCandidatesAction->setStatusTip(tr("Toggle the display of alternative pitch candidates for the selected region")); m_keyReference->registerShortcut(m_showCandidatesAction); connect(m_showCandidatesAction, SIGNAL(triggered()), this, SLOT(togglePitchCandidates())); connect(this, SIGNAL(canClearSelection(bool)), m_showCandidatesAction, SLOT(setEnabled(bool))); menu->addAction(m_showCandidatesAction); m_rightButtonMenu->addAction(m_showCandidatesAction); action = new QAction(tr("Pick Higher Pitch Candidate"), this); action->setShortcut(tr("Ctrl+Up")); action->setStatusTip(tr("Switch to the next higher pitch candidate in the selected region")); m_keyReference->registerShortcut(action); connect(action, SIGNAL(triggered()), this, SLOT(switchPitchUp())); connect(this, SIGNAL(canChangeToHigherCandidate(bool)), action, SLOT(setEnabled(bool))); menu->addAction(action); m_rightButtonMenu->addAction(action); action = new QAction(tr("Pick Lower Pitch Candidate"), this); action->setShortcut(tr("Ctrl+Down")); action->setStatusTip(tr("Switch to the next lower pitch candidate in the selected region")); m_keyReference->registerShortcut(action); connect(action, SIGNAL(triggered()), this, SLOT(switchPitchDown())); connect(this, SIGNAL(canChangeToLowerCandidate(bool)), action, SLOT(setEnabled(bool))); menu->addAction(action); m_rightButtonMenu->addAction(action); menu->addSeparator(); m_rightButtonMenu->addSeparator(); action = new QAction(tr("Octave Shift Up"), this); action->setShortcut(tr("PgUp")); action->setStatusTip(tr("Move all pitches up an octave in the selected region")); m_keyReference->registerShortcut(action); connect(action, SIGNAL(triggered()), this, SLOT(octaveShiftUp())); connect(this, SIGNAL(canClearSelection(bool)), action, SLOT(setEnabled(bool))); menu->addAction(action); m_rightButtonMenu->addAction(action); action = new QAction(tr("Octave Shift Down"), this); action->setShortcut(tr("PgDown")); action->setStatusTip(tr("Move all pitches down an octave in the selected region")); m_keyReference->registerShortcut(action); connect(action, SIGNAL(triggered()), this, SLOT(octaveShiftDown())); connect(this, SIGNAL(canClearSelection(bool)), action, SLOT(setEnabled(bool))); menu->addAction(action); m_rightButtonMenu->addAction(action); menu->addSeparator(); m_rightButtonMenu->addSeparator(); action = new QAction(tr("Remove Pitches"), this); action->setShortcut(tr("Ctrl+Backspace")); action->setStatusTip(tr("Remove all pitch estimates within the selected region (converting it to unvoiced)")); m_keyReference->registerShortcut(action); connect(action, SIGNAL(triggered()), this, SLOT(clearPitches())); connect(this, SIGNAL(canClearSelection(bool)), action, SLOT(setEnabled(bool))); menu->addAction(action); m_rightButtonMenu->addAction(action); } void MainWindow::setupViewMenu() { if (m_mainMenusCreated) return; IconLoader il; QAction *action = 0; m_keyReference->setCategory(tr("Panning and Navigation")); QMenu *menu = menuBar()->addMenu(tr("&View")); menu->setTearOffEnabled(true); action = new QAction(tr("Scroll &Left"), this); action->setShortcut(tr("Left")); action->setStatusTip(tr("Scroll the current pane to the left")); connect(action, SIGNAL(triggered()), this, SLOT(scrollLeft())); connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool))); m_keyReference->registerShortcut(action); menu->addAction(action); action = new QAction(tr("Scroll &Right"), this); action->setShortcut(tr("Right")); action->setStatusTip(tr("Scroll the current pane to the right")); connect(action, SIGNAL(triggered()), this, SLOT(scrollRight())); connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool))); m_keyReference->registerShortcut(action); menu->addAction(action); action = new QAction(tr("&Jump Left"), this); action->setShortcut(tr("Ctrl+Left")); action->setStatusTip(tr("Scroll the current pane a big step to the left")); connect(action, SIGNAL(triggered()), this, SLOT(jumpLeft())); connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool))); m_keyReference->registerShortcut(action); menu->addAction(action); action = new QAction(tr("J&ump Right"), this); action->setShortcut(tr("Ctrl+Right")); action->setStatusTip(tr("Scroll the current pane a big step to the right")); connect(action, SIGNAL(triggered()), this, SLOT(jumpRight())); connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool))); m_keyReference->registerShortcut(action); menu->addAction(action); menu->addSeparator(); m_keyReference->setCategory(tr("Zoom")); action = new QAction(il.load("zoom-in"), tr("Zoom &In"), this); action->setShortcut(tr("Up")); action->setStatusTip(tr("Increase the zoom level")); connect(action, SIGNAL(triggered()), this, SLOT(zoomIn())); connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool))); m_keyReference->registerShortcut(action); menu->addAction(action); action = new QAction(il.load("zoom-out"), tr("Zoom &Out"), this); action->setShortcut(tr("Down")); action->setStatusTip(tr("Decrease the zoom level")); connect(action, SIGNAL(triggered()), this, SLOT(zoomOut())); connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool))); m_keyReference->registerShortcut(action); menu->addAction(action); action = new QAction(tr("Restore &Default Zoom"), this); action->setStatusTip(tr("Restore the zoom level to the default")); connect(action, SIGNAL(triggered()), this, SLOT(zoomDefault())); connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool))); menu->addAction(action); action = new QAction(il.load("zoom-fit"), tr("Zoom to &Fit"), this); action->setShortcut(tr("F")); action->setStatusTip(tr("Zoom to show the whole file")); connect(action, SIGNAL(triggered()), this, SLOT(zoomToFit())); connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool))); m_keyReference->registerShortcut(action); menu->addAction(action); } void MainWindow::setupHelpMenu() { QMenu *menu = menuBar()->addMenu(tr("&Help")); menu->setTearOffEnabled(true); m_keyReference->setCategory(tr("Help")); IconLoader il; QString name = QApplication::applicationName(); QAction *action = new QAction(il.load("help"), tr("&Help Reference"), this); action->setShortcut(tr("F1")); action->setStatusTip(tr("Open the %1 reference manual").arg(name)); connect(action, SIGNAL(triggered()), this, SLOT(help())); m_keyReference->registerShortcut(action); menu->addAction(action); action = new QAction(tr("&Key and Mouse Reference"), this); action->setShortcut(tr("F2")); action->setStatusTip(tr("Open a window showing the keystrokes you can use in %1").arg(name)); connect(action, SIGNAL(triggered()), this, SLOT(keyReference())); m_keyReference->registerShortcut(action); menu->addAction(action); action = new QAction(tr("%1 on the &Web").arg(name), this); action->setStatusTip(tr("Open the %1 website").arg(name)); connect(action, SIGNAL(triggered()), this, SLOT(website())); menu->addAction(action); action = new QAction(tr("&About %1").arg(name), this); action->setStatusTip(tr("Show information about %1").arg(name)); connect(action, SIGNAL(triggered()), this, SLOT(about())); menu->addAction(action); } void MainWindow::setupRecentFilesMenu() { m_recentFilesMenu->clear(); vector<QString> files = m_recentFiles.getRecent(); for (size_t i = 0; i < files.size(); ++i) { QAction *action = new QAction(files[i], this); connect(action, SIGNAL(triggered()), this, SLOT(openRecentFile())); if (i == 0) { action->setShortcut(tr("Ctrl+R")); m_keyReference->registerShortcut (tr("Re-open"), action->shortcut().toString(), tr("Re-open the current or most recently opened file")); } m_recentFilesMenu->addAction(action); } } void MainWindow::setupToolbars() { m_keyReference->setCategory(tr("Playback and Transport Controls")); IconLoader il; QMenu *menu = m_playbackMenu = menuBar()->addMenu(tr("Play&back")); menu->setTearOffEnabled(true); m_rightButtonMenu->addSeparator(); m_rightButtonPlaybackMenu = m_rightButtonMenu->addMenu(tr("Playback")); QToolBar *toolbar = addToolBar(tr("Playback Toolbar")); QAction *rwdStartAction = toolbar->addAction(il.load("rewind-start"), tr("Rewind to Start")); rwdStartAction->setShortcut(tr("Home")); rwdStartAction->setStatusTip(tr("Rewind to the start")); connect(rwdStartAction, SIGNAL(triggered()), this, SLOT(rewindStart())); connect(this, SIGNAL(canPlay(bool)), rwdStartAction, SLOT(setEnabled(bool))); QAction *m_rwdAction = toolbar->addAction(il.load("rewind"), tr("Rewind")); m_rwdAction->setStatusTip(tr("Rewind to the previous time instant or time ruler notch")); connect(m_rwdAction, SIGNAL(triggered()), this, SLOT(rewind())); connect(this, SIGNAL(canRewind(bool)), m_rwdAction, SLOT(setEnabled(bool))); QAction *playAction = toolbar->addAction(il.load("playpause"), tr("Play / Pause")); playAction->setCheckable(true); playAction->setShortcut(tr("Space")); playAction->setStatusTip(tr("Start or stop playback from the current position")); connect(playAction, SIGNAL(triggered()), this, SLOT(play())); connect(m_playSource, SIGNAL(playStatusChanged(bool)), playAction, SLOT(setChecked(bool))); connect(this, SIGNAL(canPlay(bool)), playAction, SLOT(setEnabled(bool))); m_ffwdAction = toolbar->addAction(il.load("ffwd"), tr("Fast Forward")); m_ffwdAction->setStatusTip(tr("Fast-forward to the next time instant or time ruler notch")); connect(m_ffwdAction, SIGNAL(triggered()), this, SLOT(ffwd())); connect(this, SIGNAL(canFfwd(bool)), m_ffwdAction, SLOT(setEnabled(bool))); QAction *ffwdEndAction = toolbar->addAction(il.load("ffwd-end"), tr("Fast Forward to End")); ffwdEndAction->setShortcut(tr("End")); ffwdEndAction->setStatusTip(tr("Fast-forward to the end")); connect(ffwdEndAction, SIGNAL(triggered()), this, SLOT(ffwdEnd())); connect(this, SIGNAL(canPlay(bool)), ffwdEndAction, SLOT(setEnabled(bool))); toolbar = addToolBar(tr("Play Mode Toolbar")); QAction *psAction = toolbar->addAction(il.load("playselection"), tr("Constrain Playback to Selection")); psAction->setCheckable(true); psAction->setChecked(m_viewManager->getPlaySelectionMode()); psAction->setShortcut(tr("s")); psAction->setStatusTip(tr("Constrain playback to the selected regions")); connect(m_viewManager, SIGNAL(playSelectionModeChanged(bool)), psAction, SLOT(setChecked(bool))); connect(psAction, SIGNAL(triggered()), this, SLOT(playSelectionToggled())); connect(this, SIGNAL(canPlaySelection(bool)), psAction, SLOT(setEnabled(bool))); QAction *plAction = toolbar->addAction(il.load("playloop"), tr("Loop Playback")); plAction->setCheckable(true); plAction->setChecked(m_viewManager->getPlayLoopMode()); plAction->setShortcut(tr("l")); plAction->setStatusTip(tr("Loop playback")); connect(m_viewManager, SIGNAL(playLoopModeChanged(bool)), plAction, SLOT(setChecked(bool))); connect(plAction, SIGNAL(triggered()), this, SLOT(playLoopToggled())); connect(this, SIGNAL(canPlay(bool)), plAction, SLOT(setEnabled(bool))); m_keyReference->registerShortcut(psAction); m_keyReference->registerShortcut(plAction); m_keyReference->registerShortcut(playAction); m_keyReference->registerShortcut(m_rwdAction); m_keyReference->registerShortcut(m_ffwdAction); m_keyReference->registerShortcut(rwdStartAction); m_keyReference->registerShortcut(ffwdEndAction); menu->addAction(playAction); menu->addAction(psAction); menu->addAction(plAction); menu->addSeparator(); menu->addAction(m_rwdAction); menu->addAction(m_ffwdAction); menu->addSeparator(); menu->addAction(rwdStartAction); menu->addAction(ffwdEndAction); menu->addSeparator(); m_rightButtonPlaybackMenu->addAction(playAction); m_rightButtonPlaybackMenu->addAction(psAction); m_rightButtonPlaybackMenu->addAction(plAction); m_rightButtonPlaybackMenu->addSeparator(); m_rightButtonPlaybackMenu->addAction(m_rwdAction); m_rightButtonPlaybackMenu->addAction(m_ffwdAction); m_rightButtonPlaybackMenu->addSeparator(); m_rightButtonPlaybackMenu->addAction(rwdStartAction); m_rightButtonPlaybackMenu->addAction(ffwdEndAction); m_rightButtonPlaybackMenu->addSeparator(); QAction *fastAction = menu->addAction(tr("Speed Up")); fastAction->setShortcut(tr("Ctrl+PgUp")); fastAction->setStatusTip(tr("Time-stretch playback to speed it up without changing pitch")); connect(fastAction, SIGNAL(triggered()), this, SLOT(speedUpPlayback())); connect(this, SIGNAL(canSpeedUpPlayback(bool)), fastAction, SLOT(setEnabled(bool))); QAction *slowAction = menu->addAction(tr("Slow Down")); slowAction->setShortcut(tr("Ctrl+PgDown")); slowAction->setStatusTip(tr("Time-stretch playback to slow it down without changing pitch")); connect(slowAction, SIGNAL(triggered()), this, SLOT(slowDownPlayback())); connect(this, SIGNAL(canSlowDownPlayback(bool)), slowAction, SLOT(setEnabled(bool))); QAction *normalAction = menu->addAction(tr("Restore Normal Speed")); normalAction->setShortcut(tr("Ctrl+Home")); normalAction->setStatusTip(tr("Restore non-time-stretched playback")); connect(normalAction, SIGNAL(triggered()), this, SLOT(restoreNormalPlayback())); connect(this, SIGNAL(canChangePlaybackSpeed(bool)), normalAction, SLOT(setEnabled(bool))); m_keyReference->registerShortcut(fastAction); m_keyReference->registerShortcut(slowAction); m_keyReference->registerShortcut(normalAction); m_rightButtonPlaybackMenu->addAction(fastAction); m_rightButtonPlaybackMenu->addAction(slowAction); m_rightButtonPlaybackMenu->addAction(normalAction); toolbar = new QToolBar(tr("Playback Controls")); addToolBar(Qt::BottomToolBarArea, toolbar); toolbar->addWidget(m_playSpeed); toolbar->addWidget(m_fader); toolbar = addToolBar(tr("Show and Play")); /* ORIGINAL DESIGN QLabel *eye = new QLabel; eye->setFixedWidth(40); eye->setAlignment(Qt::AlignRight | Qt::AlignVCenter); eye->setPixmap(il.loadPixmap("eye")); toolbar->addWidget(eye); m_showAudio = toolbar->addAction(il.load("waveform"), tr("Show Audio")); m_showAudio->setCheckable(true); connect(m_showAudio, SIGNAL(triggered()), this, SLOT(showAudioToggled())); connect(this, SIGNAL(canPlay(bool)), m_showAudio, SLOT(setEnabled(bool))); m_showSpect = toolbar->addAction(il.load("spectrogram"), tr("Show Spectrogram")); m_showSpect->setCheckable(true); connect(m_showSpect, SIGNAL(triggered()), this, SLOT(showSpectToggled())); connect(this, SIGNAL(canPlay(bool)), m_showSpect, SLOT(setEnabled(bool))); m_showPitch = toolbar->addAction(il.load("values"), tr("Show Pitch Track")); m_showPitch->setCheckable(true); connect(m_showPitch, SIGNAL(triggered()), this, SLOT(showPitchToggled())); connect(this, SIGNAL(canPlay(bool)), m_showPitch, SLOT(setEnabled(bool))); m_showNotes = toolbar->addAction(il.load("notes"), tr("Show Notes")); m_showNotes->setCheckable(true); connect(m_showNotes, SIGNAL(triggered()), this, SLOT(showNotesToggled())); connect(this, SIGNAL(canPlay(bool)), m_showNotes, SLOT(setEnabled(bool))); QLabel *speaker = new QLabel; speaker->setFixedWidth(40); speaker->setAlignment(Qt::AlignRight | Qt::AlignVCenter); speaker->setPixmap(il.loadPixmap("speaker")); toolbar->addWidget(speaker); m_playAudio = toolbar->addAction(il.load("waveform"), tr("Play Audio")); m_playAudio->setCheckable(true); connect(m_playAudio, SIGNAL(triggered()), this, SLOT(playAudioToggled())); connect(this, SIGNAL(canPlay(bool)), m_playAudio, SLOT(setEnabled(bool))); m_playPitch = toolbar->addAction(il.load("values"), tr("Play Pitch Track")); m_playPitch->setCheckable(true); connect(m_playPitch, SIGNAL(triggered()), this, SLOT(playPitchToggled())); connect(this, SIGNAL(canPlay(bool)), m_playPitch, SLOT(setEnabled(bool))); m_playNotes = toolbar->addAction(il.load("notes"), tr("Play Notes")); m_playNotes->setCheckable(true); connect(m_playNotes, SIGNAL(triggered()), this, SLOT(playNotesToggled())); connect(this, SIGNAL(canPlay(bool)), m_playNotes, SLOT(setEnabled(bool))); */ // Audio QLabel *icon_audio = new QLabel; icon_audio->setFixedWidth(40); icon_audio->setAlignment(Qt::AlignRight | Qt::AlignVCenter); icon_audio->setPixmap(il.loadPixmap("waveform")); toolbar->addWidget(icon_audio); m_showAudio = toolbar->addAction(il.load("eye"), tr("Show Audio")); m_showAudio->setCheckable(true); connect(m_showAudio, SIGNAL(triggered()), this, SLOT(showAudioToggled())); connect(this, SIGNAL(canPlay(bool)), m_showAudio, SLOT(setEnabled(bool))); m_playAudio = toolbar->addAction(il.load("speaker"), tr("Play Audio")); m_playAudio->setCheckable(true); connect(m_playAudio, SIGNAL(triggered()), this, SLOT(playAudioToggled())); connect(this, SIGNAL(canPlay(bool)), m_playAudio, SLOT(setEnabled(bool))); toolbar->addWidget(m_gainAudio); toolbar->addWidget(m_panAudio); // Pitch (f0) QLabel *icon_pitch = new QLabel; icon_pitch->setFixedWidth(40); icon_pitch->setAlignment(Qt::AlignRight | Qt::AlignVCenter); icon_pitch->setPixmap(il.loadPixmap("values")); toolbar->addWidget(icon_pitch); m_showPitch = toolbar->addAction(il.load("eye"), tr("Show Pitch Track")); m_showPitch->setCheckable(true); connect(m_showPitch, SIGNAL(triggered()), this, SLOT(showPitchToggled())); connect(this, SIGNAL(canPlay(bool)), m_showPitch, SLOT(setEnabled(bool))); m_playPitch = toolbar->addAction(il.load("speaker"), tr("Play Pitch Track")); m_playPitch->setCheckable(true); connect(m_playPitch, SIGNAL(triggered()), this, SLOT(playPitchToggled())); connect(this, SIGNAL(canPlay(bool)), m_playPitch, SLOT(setEnabled(bool))); // JTEST: this resets the enabled state of m_playPitch. toolbar->addWidget(m_gainPitch); toolbar->addWidget(m_panPitch); // Notes QLabel *icon_notes = new QLabel; icon_notes->setFixedWidth(40); icon_notes->setAlignment(Qt::AlignRight | Qt::AlignVCenter); icon_notes->setPixmap(il.loadPixmap("notes")); toolbar->addWidget(icon_notes); m_showNotes = toolbar->addAction(il.load("eye"), tr("Show Notes")); m_showNotes->setCheckable(true); connect(m_showNotes, SIGNAL(triggered()), this, SLOT(showNotesToggled())); connect(this, SIGNAL(canPlay(bool)), m_showNotes, SLOT(setEnabled(bool))); m_playNotes = toolbar->addAction(il.load("speaker"), tr("Play Notes")); m_playNotes->setCheckable(true); connect(m_playNotes, SIGNAL(triggered()), this, SLOT(playNotesToggled())); connect(this, SIGNAL(canPlay(bool)), m_playNotes, SLOT(setEnabled(bool))); toolbar->addWidget(m_gainNotes); toolbar->addWidget(m_panNotes); // Spectrogram QLabel *icon_spectrogram = new QLabel; icon_spectrogram->setFixedWidth(40); icon_spectrogram->setAlignment(Qt::AlignRight | Qt::AlignVCenter); icon_spectrogram->setPixmap(il.loadPixmap("spectrogram")); toolbar->addWidget(icon_spectrogram); m_showSpect = toolbar->addAction(il.load("eye"), tr("Show Spectrogram")); m_showSpect->setCheckable(true); connect(m_showSpect, SIGNAL(triggered()), this, SLOT(showSpectToggled())); connect(this, SIGNAL(canPlay(bool)), m_showSpect, SLOT(setEnabled(bool))); Pane::registerShortcuts(*m_keyReference); } void MainWindow::toolNavigateSelected() { m_viewManager->setToolMode(ViewManager::NavigateMode); m_intelligentActionOn = true; } void MainWindow::toolEditSelected() { m_viewManager->setToolMode(ViewManager::NoteEditMode); m_intelligentActionOn = true; m_analyser->setIntelligentActions(m_intelligentActionOn); } void MainWindow::toolFreeEditSelected() { m_viewManager->setToolMode(ViewManager::NoteEditMode); m_intelligentActionOn = false; m_analyser->setIntelligentActions(m_intelligentActionOn); } void MainWindow::updateMenuStates() { MainWindowBase::updateMenuStates(); Pane *currentPane = 0; Layer *currentLayer = 0; if (m_paneStack) currentPane = m_paneStack->getCurrentPane(); if (currentPane) currentLayer = currentPane->getSelectedLayer(); bool haveCurrentPane = (currentPane != 0); bool haveCurrentLayer = (haveCurrentPane && (currentLayer != 0)); bool haveSelection = (m_viewManager && !m_viewManager->getSelections().empty()); bool haveCurrentEditableLayer = (haveCurrentLayer && currentLayer->isLayerEditable()); bool haveCurrentTimeInstantsLayer = (haveCurrentLayer && qobject_cast<TimeInstantLayer *>(currentLayer)); bool haveCurrentTimeValueLayer = (haveCurrentLayer && qobject_cast<TimeValueLayer *>(currentLayer)); bool pitchCandidatesVisible = m_analyser->arePitchCandidatesShown(); bool haveHigher = m_analyser->haveHigherPitchCandidate(); bool haveLower = m_analyser->haveLowerPitchCandidate(); emit canChangePlaybackSpeed(true); int v = m_playSpeed->value(); emit canSpeedUpPlayback(v < m_playSpeed->maximum()); emit canSlowDownPlayback(v > m_playSpeed->minimum()); emit canChangePitchCandidate(pitchCandidatesVisible && haveSelection); emit canChangeToHigherCandidate(pitchCandidatesVisible && haveSelection && haveHigher); emit canChangeToLowerCandidate(pitchCandidatesVisible && haveSelection && haveLower); if (pitchCandidatesVisible) { m_showCandidatesAction->setText(tr("Hide Pitch Candidates")); m_showCandidatesAction->setStatusTip(tr("Remove the display of alternate pitch candidates for the selected region")); } else { m_showCandidatesAction->setText(tr("Show Pitch Candidates")); m_showCandidatesAction->setStatusTip(tr("Show alternate pitch candidates for the selected region")); } if (m_ffwdAction && m_rwdAction) { if (haveCurrentTimeInstantsLayer) { m_ffwdAction->setText(tr("Fast Forward to Next Instant")); m_ffwdAction->setStatusTip(tr("Fast forward to the next time instant in the current layer")); m_rwdAction->setText(tr("Rewind to Previous Instant")); m_rwdAction->setStatusTip(tr("Rewind to the previous time instant in the current layer")); } else if (haveCurrentTimeValueLayer) { m_ffwdAction->setText(tr("Fast Forward to Next Point")); m_ffwdAction->setStatusTip(tr("Fast forward to the next point in the current layer")); m_rwdAction->setText(tr("Rewind to Previous Point")); m_rwdAction->setStatusTip(tr("Rewind to the previous point in the current layer")); } else { m_ffwdAction->setText(tr("Fast Forward")); m_ffwdAction->setStatusTip(tr("Fast forward")); m_rwdAction->setText(tr("Rewind")); m_rwdAction->setStatusTip(tr("Rewind")); } } } void MainWindow::showAudioToggled() { m_analyser->toggleVisible(Analyser::Audio); } void MainWindow::showPitchToggled() { m_analyser->toggleVisible(Analyser::PitchTrack); // JTEST if (!m_analyser->isVisible(Analyser::PitchTrack)) { m_analyser->setAudible(Analyser::PitchTrack,false); m_playPitch->setChecked(false); m_playPitch->setEnabled(false); } else { m_playPitch->setEnabled(true); } } void MainWindow::showSpectToggled() { m_analyser->toggleVisible(Analyser::Spectrogram); } void MainWindow::showNotesToggled() { m_analyser->toggleVisible(Analyser::Notes); } void MainWindow::playAudioToggled() { m_analyser->toggleAudible(Analyser::Audio); } void MainWindow::playPitchToggled() { m_analyser->toggleAudible(Analyser::PitchTrack); } void MainWindow::playNotesToggled() { m_analyser->toggleAudible(Analyser::Notes); } void MainWindow::updateLayerStatuses() { m_showAudio->setChecked(m_analyser->isVisible(Analyser::Audio)); m_showSpect->setChecked(m_analyser->isVisible(Analyser::Spectrogram)); m_showPitch->setChecked(m_analyser->isVisible(Analyser::PitchTrack)); m_showNotes->setChecked(m_analyser->isVisible(Analyser::Notes)); m_playAudio->setChecked(m_analyser->isAudible(Analyser::Audio)); m_playPitch->setChecked(m_analyser->isAudible(Analyser::PitchTrack)); m_playNotes->setChecked(m_analyser->isAudible(Analyser::Notes)); } void MainWindow::updateDescriptionLabel() { // Nothing, we don't have one } void MainWindow::documentModified() { MainWindowBase::documentModified(); } void MainWindow::documentRestored() { MainWindowBase::documentRestored(); } void MainWindow::newSession() { if (!checkSaveModified()) return; closeSession(); createDocument(); m_document->setAutoAlignment(true); Pane *pane = m_paneStack->addPane(); connect(pane, SIGNAL(contextHelpChanged(const QString &)), this, SLOT(contextHelpChanged(const QString &))); // Layer *waveform = m_document->createMainModelLayer(LayerFactory::Waveform); // m_document->addLayerToView(pane, waveform); m_overview->registerView(pane); CommandHistory::getInstance()->clear(); CommandHistory::getInstance()->documentSaved(); documentRestored(); updateMenuStates(); } void MainWindow::closeSession() { if (!checkSaveModified()) return; while (m_paneStack->getPaneCount() > 0) { Pane *pane = m_paneStack->getPane(m_paneStack->getPaneCount() - 1); while (pane->getLayerCount() > 0) { m_document->removeLayerFromView (pane, pane->getLayer(pane->getLayerCount() - 1)); } m_overview->unregisterView(pane); m_paneStack->deletePane(pane); } while (m_paneStack->getHiddenPaneCount() > 0) { Pane *pane = m_paneStack->getHiddenPane (m_paneStack->getHiddenPaneCount() - 1); while (pane->getLayerCount() > 0) { m_document->removeLayerFromView (pane, pane->getLayer(pane->getLayerCount() - 1)); } m_overview->unregisterView(pane); m_paneStack->deletePane(pane); } delete m_document; m_document = 0; m_viewManager->clearSelections(); m_timeRulerLayer = 0; // document owned this m_sessionFile = ""; CommandHistory::getInstance()->clear(); CommandHistory::getInstance()->documentSaved(); documentRestored(); } void MainWindow::openFile() { QString orig = m_audioFile; if (orig == "") orig = "."; else orig = QFileInfo(orig).absoluteDir().canonicalPath(); QString path = getOpenFileName(FileFinder::AnyFile); if (path.isEmpty()) return; FileOpenStatus status = open(path, ReplaceSession); if (status == FileOpenFailed) { QMessageBox::critical(this, tr("Failed to open file"), tr("<b>File open failed</b><p>File \"%1\" could not be opened").arg(path)); } else if (status == FileOpenWrongMode) { QMessageBox::critical(this, tr("Failed to open file"), tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data")); } } void MainWindow::openLocation() { QSettings settings; settings.beginGroup("MainWindow"); QString lastLocation = settings.value("lastremote", "").toString(); bool ok = false; QString text = QInputDialog::getText (this, tr("Open Location"), tr("Please enter the URL of the location to open:"), QLineEdit::Normal, lastLocation, &ok); if (!ok) return; settings.setValue("lastremote", text); if (text.isEmpty()) return; FileOpenStatus status = open(text, ReplaceSession); if (status == FileOpenFailed) { QMessageBox::critical(this, tr("Failed to open location"), tr("<b>Open failed</b><p>URL \"%1\" could not be opened").arg(text)); } else if (status == FileOpenWrongMode) { QMessageBox::critical(this, tr("Failed to open location"), tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data")); } } void MainWindow::openRecentFile() { QObject *obj = sender(); QAction *action = qobject_cast<QAction *>(obj); if (!action) { cerr << "WARNING: MainWindow::openRecentFile: sender is not an action" << endl; return; } QString path = action->text(); if (path == "") return; FileOpenStatus status = open(path, ReplaceSession); if (status == FileOpenFailed) { QMessageBox::critical(this, tr("Failed to open location"), tr("<b>Open failed</b><p>File or URL \"%1\" could not be opened").arg(path)); } else if (status == FileOpenWrongMode) { QMessageBox::critical(this, tr("Failed to open location"), tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data")); } } void MainWindow::paneAdded(Pane *pane) { pane->setPlaybackFollow(PlaybackScrollPage); m_paneStack->sizePanesEqually(); if (m_overview) m_overview->registerView(pane); } void MainWindow::paneHidden(Pane *pane) { if (m_overview) m_overview->unregisterView(pane); } void MainWindow::paneAboutToBeDeleted(Pane *pane) { if (m_overview) m_overview->unregisterView(pane); } void MainWindow::paneDropAccepted(Pane *pane, QStringList uriList) { if (pane) m_paneStack->setCurrentPane(pane); for (QStringList::iterator i = uriList.begin(); i != uriList.end(); ++i) { FileOpenStatus status = open(*i, ReplaceSession); if (status == FileOpenFailed) { QMessageBox::critical(this, tr("Failed to open dropped URL"), tr("<b>Open failed</b><p>Dropped URL \"%1\" could not be opened").arg(*i)); } else if (status == FileOpenWrongMode) { QMessageBox::critical(this, tr("Failed to open dropped URL"), tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data")); } } } void MainWindow::paneDropAccepted(Pane *pane, QString text) { if (pane) m_paneStack->setCurrentPane(pane); QUrl testUrl(text); if (testUrl.scheme() == "file" || testUrl.scheme() == "http" || testUrl.scheme() == "ftp") { QStringList list; list.push_back(text); paneDropAccepted(pane, list); return; } //!!! open as text -- but by importing as if a CSV, or just adding //to a text layer? } void MainWindow::closeEvent(QCloseEvent *e) { // cerr << "MainWindow::closeEvent" << endl; if (m_openingAudioFile) { // cerr << "Busy - ignoring close event" << endl; e->ignore(); return; } if (!m_abandoning && !checkSaveModified()) { // cerr << "Ignoring close event" << endl; e->ignore(); return; } QSettings settings; settings.beginGroup("MainWindow"); settings.setValue("size", size()); settings.setValue("position", pos()); settings.endGroup(); delete m_keyReference; m_keyReference = 0; closeSession(); e->accept(); return; } bool MainWindow::commitData(bool mayAskUser) { if (mayAskUser) { bool rv = checkSaveModified(); return rv; } else { if (!m_documentModified) return true; // If we can't check with the user first, then we can't save // to the original session file (even if we have it) -- have // to use a temporary file QString svDirBase = ".sv1"; QString svDir = QDir::home().filePath(svDirBase); if (!QFileInfo(svDir).exists()) { if (!QDir::home().mkdir(svDirBase)) return false; } else { if (!QFileInfo(svDir).isDir()) return false; } // This name doesn't have to be unguessable #ifndef _WIN32 QString fname = QString("tmp-%1-%2.sv") .arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz")) .arg(QProcess().pid()); #else QString fname = QString("tmp-%1.sv") .arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz")); #endif QString fpath = QDir(svDir).filePath(fname); if (saveSessionFile(fpath)) { m_recentFiles.addFile(fpath); return true; } else { return false; } } } bool MainWindow::checkSaveModified() { // Called before some destructive operation (e.g. new session, // exit program). Return true if we can safely proceed, false to // cancel. if (!m_documentModified) return true; int button = QMessageBox::warning(this, tr("Session modified"), tr("The current session has been modified.\nDo you want to save it?"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes); if (button == QMessageBox::Yes) { saveSession(); if (m_documentModified) { // save failed -- don't proceed! return false; } else { return true; // saved, so it's safe to continue now } } else if (button == QMessageBox::No) { m_documentModified = false; // so we know to abandon it return true; } // else cancel return false; } void MainWindow::saveSession() { if (m_sessionFile != "") { if (!saveSessionFile(m_sessionFile)) { QMessageBox::critical(this, tr("Failed to save file"), tr("Session file \"%1\" could not be saved.").arg(m_sessionFile)); } else { CommandHistory::getInstance()->documentSaved(); documentRestored(); } } else { saveSessionAs(); } } void MainWindow::saveSessionAs() { QString orig = m_audioFile; if (orig == "") orig = "."; else orig = QFileInfo(orig).absoluteDir().canonicalPath(); QString path = getSaveFileName(FileFinder::SessionFile); if (path == "") return; if (!saveSessionFile(path)) { QMessageBox::critical(this, tr("Failed to save file"), tr("Session file \"%1\" could not be saved.").arg(path)); } else { setWindowTitle(tr("%1: %2") .arg(QApplication::applicationName()) .arg(QFileInfo(path).fileName())); m_sessionFile = path; CommandHistory::getInstance()->documentSaved(); documentRestored(); m_recentFiles.addFile(path); } } QString MainWindow::exportToSVL(QString path, Layer *layer) { Model *model = layer->getModel(); QFile file(path); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return tr("Failed to open file %1 for writing").arg(path); } else { QTextStream out(&file); out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" << "<!DOCTYPE sonic-visualiser>\n" << "<sv>\n" << " <data>\n"; model->toXml(out, " "); out << " </data>\n" << " <display>\n"; layer->toXml(out, " "); out << " </display>\n" << "</sv>\n"; return ""; } } void MainWindow::importPitchLayer() { QString path = getOpenFileName(FileFinder::LayerFileNoMidiNonSV); if (path == "") return; FileOpenStatus status = importPitchLayer(path); if (status == FileOpenFailed) { emit hideSplash(); QMessageBox::critical(this, tr("Failed to open file"), tr("<b>File open failed</b><p>Layer file %1 could not be opened.").arg(path)); return; } else if (status == FileOpenWrongMode) { emit hideSplash(); QMessageBox::critical(this, tr("Failed to open file"), tr("<b>Audio required</b><p>Unable to load layer data from \"%1\" without an audio file.<br>Please load at least one audio file before importing annotations.").arg(path)); } } MainWindow::FileOpenStatus MainWindow::importPitchLayer(FileSource source) { if (!source.isAvailable()) return FileOpenFailed; source.waitForData(); QString path = source.getLocalFilename(); RDFImporter::RDFDocumentType rdfType = RDFImporter::identifyDocumentType(QUrl::fromLocalFile(path).toString()); if (rdfType != RDFImporter::NotRDF) { //!!! return FileOpenFailed; } else if (source.getExtension().toLower() == "svl" || (source.getExtension().toLower() == "xml" && (SVFileReader::identifyXmlFile(source.getLocalFilename()) == SVFileReader::SVLayerFile))) { //!!! return FileOpenFailed; } else { try { CSVFormat format(path); format.setSampleRate(getMainModel()->getSampleRate()); if (format.getModelType() != CSVFormat::TwoDimensionalModel) { //!!! error report return FileOpenFailed; } Model *model = DataFileReaderFactory::loadCSV (path, format, getMainModel()->getSampleRate()); if (model) { SVDEBUG << "MainWindow::importPitchLayer: Have model" << endl; CommandHistory::getInstance()->startCompoundOperation (tr("Import Pitch Track"), true); Layer *newLayer = m_document->createImportedLayer(model); m_analyser->takePitchTrackFrom(newLayer); m_document->deleteLayer(newLayer); CommandHistory::getInstance()->endCompoundOperation(); //!!! swap all data in to existing layer instead of this if (!source.isRemote()) { registerLastOpenedFilePath (FileFinder::LayerFile, path); // for file dialog } return FileOpenSucceeded; } } catch (DataFileReaderFactory::Exception e) { if (e == DataFileReaderFactory::ImportCancelled) { return FileOpenCancelled; } } } return FileOpenFailed; } void MainWindow::exportPitchLayer() { Layer *layer = m_analyser->getLayer(Analyser::PitchTrack); if (!layer) return; SparseTimeValueModel *model = qobject_cast<SparseTimeValueModel *>(layer->getModel()); if (!model) return; FileFinder::FileType type = FileFinder::LayerFileNoMidiNonSV; QString path = getSaveFileName(type); if (path == "") return; if (QFileInfo(path).suffix() == "") path += ".svl"; QString suffix = QFileInfo(path).suffix().toLower(); QString error; if (suffix == "xml" || suffix == "svl") { error = exportToSVL(path, layer); } else if (suffix == "ttl" || suffix == "n3") { RDFExporter exporter(path, model); exporter.write(); if (!exporter.isOK()) { error = exporter.getError(); } } else { CSVFileWriter writer(path, model, ((suffix == "csv") ? "," : "\t")); writer.write(); if (!writer.isOK()) { error = writer.getError(); } } if (error != "") { QMessageBox::critical(this, tr("Failed to write file"), error); } else { emit activity(tr("Export layer to \"%1\"").arg(path)); } } void MainWindow::exportNoteLayer() { Layer *layer = m_analyser->getLayer(Analyser::Notes); if (!layer) return; FlexiNoteModel *model = qobject_cast<FlexiNoteModel *>(layer->getModel()); if (!model) return; FileFinder::FileType type = FileFinder::LayerFileNonSV; QString path = getSaveFileName(type); if (path == "") return; if (QFileInfo(path).suffix() == "") path += ".svl"; QString suffix = QFileInfo(path).suffix().toLower(); QString error; if (suffix == "xml" || suffix == "svl") { error = exportToSVL(path, layer); } else if (suffix == "mid" || suffix == "midi") { MIDIFileWriter writer(path, model, model->getSampleRate()); writer.write(); if (!writer.isOK()) { error = writer.getError(); } } else if (suffix == "ttl" || suffix == "n3") { RDFExporter exporter(path, model); exporter.write(); if (!exporter.isOK()) { error = exporter.getError(); } } else { CSVFileWriter writer(path, model, ((suffix == "csv") ? "," : "\t")); writer.write(); if (!writer.isOK()) { error = writer.getError(); } } if (error != "") { QMessageBox::critical(this, tr("Failed to write file"), error); } else { emit activity(tr("Export layer to \"%1\"").arg(path)); } } void MainWindow::doubleClickSelectInvoked(size_t frame) { size_t f0, f1; m_analyser->getEnclosingSelectionScope(frame, f0, f1); cerr << "MainWindow::doubleClickSelectInvoked(" << frame << "): [" << f0 << "," << f1 << "]" << endl; Selection sel(f0, f1); m_viewManager->setSelection(sel); } void MainWindow::abandonSelection() { // Named abandonSelection rather than clearSelection to indicate // that this is an active operation -- it restores the original // content of the pitch track in the selected region rather than // simply un-selecting. cerr << "MainWindow::abandonSelection()" << endl; CommandHistory::getInstance()->startCompoundOperation(tr("Clear Selection"), true); MultiSelection::SelectionList selections = m_viewManager->getSelections(); if (!selections.empty()) { Selection sel = *selections.begin(); m_analyser->clearReAnalysis(sel); } MainWindowBase::clearSelection(); CommandHistory::getInstance()->endCompoundOperation(); } void MainWindow::selectionChangedByUser() { MultiSelection::SelectionList selections = m_viewManager->getSelections(); cerr << "MainWindow::selectionChangedByUser" << endl; m_analyser->showPitchCandidates(m_pendingConstraint.isConstrained()); if (!selections.empty()) { Selection sel = *selections.begin(); cerr << "MainWindow::selectionChangedByUser: have selection" << endl; QString error = m_analyser->reAnalyseSelection (sel, m_pendingConstraint); if (error != "") { QMessageBox::critical (this, tr("Failed to analyse selection"), tr("<b>Analysis failed</b><p>%2</p>").arg(error)); } } m_pendingConstraint = Analyser::FrequencyRange(); } void MainWindow::regionOutlined(QRect r) { cerr << "MainWindow::regionOutlined(" << r.x() << "," << r.y() << "," << r.width() << "," << r.height() << ")" << endl; Pane *pane = qobject_cast<Pane *>(sender()); if (!pane) { cerr << "MainWindow::regionOutlined: not sent by pane, ignoring" << endl; return; } if (!m_analyser) { cerr << "MainWindow::regionOutlined: no analyser, ignoring" << endl; return; } SpectrogramLayer *spectrogram = qobject_cast<SpectrogramLayer *> (m_analyser->getLayer(Analyser::Spectrogram)); if (!spectrogram) { cerr << "MainWindow::regionOutlined: no spectrogram layer, ignoring" << endl; return; } int f0 = pane->getFrameForX(r.x()); int f1 = pane->getFrameForX(r.x() + r.width()); float v0 = spectrogram->getFrequencyForY(pane, r.y() + r.height()); float v1 = spectrogram->getFrequencyForY(pane, r.y()); cerr << "MainWindow::regionOutlined: frame " << f0 << " -> " << f1 << ", frequency " << v0 << " -> " << v1 << endl; m_pendingConstraint = Analyser::FrequencyRange(v0, v1); Selection sel(f0, f1); m_viewManager->setSelection(sel); } void MainWindow::clearPitches() { MultiSelection::SelectionList selections = m_viewManager->getSelections(); CommandHistory::getInstance()->startCompoundOperation(tr("Clear Pitches"), true); for (MultiSelection::SelectionList::iterator k = selections.begin(); k != selections.end(); ++k) { m_analyser->deletePitches(*k); } CommandHistory::getInstance()->endCompoundOperation(); } void MainWindow::octaveShiftUp() { octaveShift(true); } void MainWindow::octaveShiftDown() { octaveShift(false); } void MainWindow::octaveShift(bool up) { MultiSelection::SelectionList selections = m_viewManager->getSelections(); CommandHistory::getInstance()->startCompoundOperation(tr("Octave Shift"), true); for (MultiSelection::SelectionList::iterator k = selections.begin(); k != selections.end(); ++k) { m_analyser->shiftOctave(*k, up); } CommandHistory::getInstance()->endCompoundOperation(); } void MainWindow::togglePitchCandidates() { m_analyser->showPitchCandidates(!m_analyser->arePitchCandidatesShown()); updateMenuStates(); } void MainWindow::switchPitchUp() { CommandHistory::getInstance()->startCompoundOperation (tr("Switch Pitch Candidate"), true); MultiSelection::SelectionList selections = m_viewManager->getSelections(); for (MultiSelection::SelectionList::iterator k = selections.begin(); k != selections.end(); ++k) { m_analyser->switchPitchCandidate(*k, true); } CommandHistory::getInstance()->endCompoundOperation(); } void MainWindow::switchPitchDown() { CommandHistory::getInstance()->startCompoundOperation (tr("Switch Pitch Candidate"), true); MultiSelection::SelectionList selections = m_viewManager->getSelections(); for (MultiSelection::SelectionList::iterator k = selections.begin(); k != selections.end(); ++k) { m_analyser->switchPitchCandidate(*k, false); } CommandHistory::getInstance()->endCompoundOperation(); } void MainWindow::playSpeedChanged(int position) { PlaySpeedRangeMapper mapper(0, 200); float percent = m_playSpeed->mappedValue(); float factor = mapper.getFactorForValue(percent); cerr << "speed = " << position << " percent = " << percent << " factor = " << factor << endl; bool something = (position != 100); int pc = lrintf(percent); if (!something) { contextHelpChanged(tr("Playback speed: Normal")); } else { contextHelpChanged(tr("Playback speed: %1%2%") .arg(position > 100 ? "+" : "") .arg(pc)); } m_playSource->setTimeStretch(factor); updateMenuStates(); } void MainWindow::playSharpenToggled() { QSettings settings; settings.beginGroup("MainWindow"); settings.setValue("playsharpen", m_playSharpen->isChecked()); settings.endGroup(); playSpeedChanged(m_playSpeed->value()); // TODO: pitch gain? } void MainWindow::playMonoToggled() { QSettings settings; settings.beginGroup("MainWindow"); settings.setValue("playmono", m_playMono->isChecked()); settings.endGroup(); playSpeedChanged(m_playSpeed->value()); // TODO: pitch gain? } void MainWindow::speedUpPlayback() { int value = m_playSpeed->value(); value = value + m_playSpeed->pageStep(); if (value > m_playSpeed->maximum()) value = m_playSpeed->maximum(); m_playSpeed->setValue(value); } void MainWindow::slowDownPlayback() { int value = m_playSpeed->value(); value = value - m_playSpeed->pageStep(); if (value < m_playSpeed->minimum()) value = m_playSpeed->minimum(); m_playSpeed->setValue(value); } void MainWindow::restoreNormalPlayback() { m_playSpeed->setValue(m_playSpeed->defaultValue()); } void MainWindow::audioGainChanged(int position) { float level = m_gainAudio->mappedValue(); float gain = powf(10, level / 20.0); cerr << "gain = " << gain << " (" << position << " dB)" << endl; contextHelpChanged(tr("Audio Gain: %1 dB").arg(position)); m_analyser->setGain(Analyser::Audio, gain); updateMenuStates(); } void MainWindow::increaseAudioGain() { int value = m_gainAudio->value(); value = value + m_gainAudio->pageStep(); if (value > m_gainAudio->maximum()) value = m_gainAudio->maximum(); m_gainAudio->setValue(value); } void MainWindow::decreaseAudioGain() { int value = m_gainAudio->value(); value = value - m_gainAudio->pageStep(); if (value < m_gainAudio->minimum()) value = m_gainAudio->minimum(); m_gainAudio->setValue(value); } void MainWindow::restoreNormalAudioGain() { m_gainAudio->setValue(m_gainAudio->defaultValue()); } void MainWindow::pitchGainChanged(int position) { float level = m_gainPitch->mappedValue(); float gain = powf(10, level / 20.0); cerr << "gain = " << gain << " (" << position << " dB)" << endl; contextHelpChanged(tr("Pitch Gain: %1 dB").arg(position)); m_analyser->setGain(Analyser::PitchTrack, gain); updateMenuStates(); } void MainWindow::increasePitchGain() { int value = m_gainPitch->value(); value = value + m_gainPitch->pageStep(); if (value > m_gainPitch->maximum()) value = m_gainPitch->maximum(); m_gainPitch->setValue(value); } void MainWindow::decreasePitchGain() { int value = m_gainPitch->value(); value = value - m_gainPitch->pageStep(); if (value < m_gainPitch->minimum()) value = m_gainPitch->minimum(); m_gainPitch->setValue(value); } void MainWindow::restoreNormalPitchGain() { m_gainPitch->setValue(m_gainPitch->defaultValue()); } void MainWindow::notesGainChanged(int position) { float level = m_gainNotes->mappedValue(); float gain = powf(10, level / 20.0); cerr << "gain = " << gain << " (" << position << " dB)" << endl; contextHelpChanged(tr("Notes Gain: %1 dB").arg(position)); m_analyser->setGain(Analyser::Notes, gain); updateMenuStates(); } void MainWindow::increaseNotesGain() { int value = m_gainNotes->value(); value = value + m_gainNotes->pageStep(); if (value > m_gainNotes->maximum()) value = m_gainNotes->maximum(); m_gainNotes->setValue(value); } void MainWindow::decreaseNotesGain() { int value = m_gainNotes->value(); value = value - m_gainNotes->pageStep(); if (value < m_gainNotes->minimum()) value = m_gainNotes->minimum(); m_gainNotes->setValue(value); } void MainWindow::restoreNormalNotesGain() { m_gainNotes->setValue(m_gainNotes->defaultValue()); } void MainWindow::audioPanChanged(int position) { float level = m_panAudio->mappedValue(); float pan = level/100.f; cerr << "pan = " << pan << " (" << position << ")" << endl; contextHelpChanged(tr("Audio Pan: %1").arg(position)); m_analyser->setPan(Analyser::Audio, pan); updateMenuStates(); } void MainWindow::increaseAudioPan() { int value = m_panAudio->value(); value = value + m_panAudio->pageStep(); if (value > m_panAudio->maximum()) value = m_panAudio->maximum(); m_panAudio->setValue(value); } void MainWindow::decreaseAudioPan() { int value = m_panAudio->value(); value = value - m_panAudio->pageStep(); if (value < m_panAudio->minimum()) value = m_panAudio->minimum(); m_panAudio->setValue(value); } void MainWindow::restoreNormalAudioPan() { m_panAudio->setValue(m_panAudio->defaultValue()); } void MainWindow::pitchPanChanged(int position) { float level = m_panPitch->mappedValue(); float pan = level/100.f; cerr << "pan = " << pan << " (" << position << ")" << endl; contextHelpChanged(tr("Pitch Pan: %1").arg(position)); m_analyser->setPan(Analyser::PitchTrack, pan); updateMenuStates(); } void MainWindow::increasePitchPan() { int value = m_panPitch->value(); value = value + m_panPitch->pageStep(); if (value > m_panPitch->maximum()) value = m_panPitch->maximum(); m_panPitch->setValue(value); } void MainWindow::decreasePitchPan() { int value = m_panPitch->value(); value = value - m_panPitch->pageStep(); if (value < m_panPitch->minimum()) value = m_panPitch->minimum(); m_panPitch->setValue(value); } void MainWindow::restoreNormalPitchPan() { m_panPitch->setValue(m_panPitch->defaultValue()); } void MainWindow::notesPanChanged(int position) { float level = m_panNotes->mappedValue(); float pan = level/100.f; cerr << "pan = " << pan << " (" << position << ")" << endl; contextHelpChanged(tr("Notes Pan: %1").arg(position)); m_analyser->setPan(Analyser::Notes, pan); updateMenuStates(); } void MainWindow::increaseNotesPan() { int value = m_panNotes->value(); value = value + m_panNotes->pageStep(); if (value > m_panNotes->maximum()) value = m_panNotes->maximum(); m_panNotes->setValue(value); } void MainWindow::decreaseNotesPan() { int value = m_panNotes->value(); value = value - m_panNotes->pageStep(); if (value < m_panNotes->minimum()) value = m_panNotes->minimum(); m_panNotes->setValue(value); } void MainWindow::restoreNormalNotesPan() { m_panNotes->setValue(m_panNotes->defaultValue()); } void MainWindow::updateVisibleRangeDisplay(Pane *p) const { if (!getMainModel() || !p) { return; } bool haveSelection = false; size_t startFrame = 0, endFrame = 0; if (m_viewManager && m_viewManager->haveInProgressSelection()) { bool exclusive = false; Selection s = m_viewManager->getInProgressSelection(exclusive); if (!s.isEmpty()) { haveSelection = true; startFrame = s.getStartFrame(); endFrame = s.getEndFrame(); } } if (!haveSelection) { startFrame = p->getFirstVisibleFrame(); endFrame = p->getLastVisibleFrame(); } RealTime start = RealTime::frame2RealTime (startFrame, getMainModel()->getSampleRate()); RealTime end = RealTime::frame2RealTime (endFrame, getMainModel()->getSampleRate()); RealTime duration = end - start; QString startStr, endStr, durationStr; startStr = start.toText(true).c_str(); endStr = end.toText(true).c_str(); durationStr = duration.toText(true).c_str(); if (haveSelection) { m_myStatusMessage = tr("Selection: %1 to %2 (duration %3)") .arg(startStr).arg(endStr).arg(durationStr); } else { m_myStatusMessage = tr("Visible: %1 to %2 (duration %3)") .arg(startStr).arg(endStr).arg(durationStr); } // scale Y axis FlexiNoteLayer *fnl = dynamic_cast<FlexiNoteLayer *>(p->getLayer(2)); if (fnl) { fnl->setVerticalRangeToNoteRange(p); } statusBar()->showMessage(m_myStatusMessage); } void MainWindow::updatePositionStatusDisplays() const { if (!statusBar()->isVisible()) return; } void MainWindow::outputLevelsChanged(float left, float right) { m_fader->setPeakLeft(left); m_fader->setPeakRight(right); } void MainWindow::sampleRateMismatch(size_t requested, size_t actual, bool willResample) { updateDescriptionLabel(); } void MainWindow::audioOverloadPluginDisabled() { QMessageBox::information (this, tr("Audio processing overload"), tr("<b>Overloaded</b><p>Audio effects plugin auditioning has been disabled due to a processing overload.")); } void MainWindow::audioTimeStretchMultiChannelDisabled() { static bool shownOnce = false; if (shownOnce) return; QMessageBox::information (this, tr("Audio processing overload"), tr("<b>Overloaded</b><p>Audio playback speed processing has been reduced to a single channel, due to a processing overload.")); shownOnce = true; } void MainWindow::layerRemoved(Layer *layer) { MainWindowBase::layerRemoved(layer); } void MainWindow::layerInAView(Layer *layer, bool inAView) { MainWindowBase::layerInAView(layer, inAView); } void MainWindow::modelAdded(Model *model) { MainWindowBase::modelAdded(model); DenseTimeValueModel *dtvm = qobject_cast<DenseTimeValueModel *>(model); if (dtvm) { cerr << "A dense time-value model (such as an audio file) has been loaded" << endl; } } void MainWindow::modelAboutToBeDeleted(Model *model) { MainWindowBase::modelAboutToBeDeleted(model); } void MainWindow::mainModelChanged(WaveFileModel *model) { m_panLayer->setModel(model); MainWindowBase::mainModelChanged(model); if (m_playTarget) { connect(m_fader, SIGNAL(valueChanged(float)), m_playTarget, SLOT(setOutputGain(float))); } if (model) { if (m_paneStack) { int pc = m_paneStack->getPaneCount(); Pane *pane = 0; if (pc < 1) { pane = m_paneStack->addPane(); Pane *selectionStrip = m_paneStack->addPane(); selectionStrip->setFixedHeight(26); m_document->addLayerToView (selectionStrip, m_document->createMainModelLayer(LayerFactory::TimeRuler)); m_paneStack->sizePanesEqually(); m_viewManager->clearToolModeOverrides(); m_viewManager->setToolModeFor(selectionStrip, ViewManager::SelectMode); } else { pane = m_paneStack->getPane(0); } if (pane) { disconnect(pane, SIGNAL(regionOutlined(QRect)), pane, SLOT(zoomToRegion(QRect))); connect(pane, SIGNAL(regionOutlined(QRect)), this, SLOT(regionOutlined(QRect))); QString error = m_analyser->newFileLoaded (m_document, getMainModel(), m_paneStack, pane); if (error != "") { QMessageBox::warning (this, tr("Failed to analyse audio"), tr("<b>Analysis failed</b><p>%1</p>").arg(error), QMessageBox::Ok); } } } } } void MainWindow::modelGenerationFailed(QString transformName, QString message) { if (message != "") { QMessageBox::warning (this, tr("Failed to generate layer"), tr("<b>Layer generation failed</b><p>Failed to generate derived layer.<p>The layer transform \"%1\" failed:<p>%2") .arg(transformName).arg(message), QMessageBox::Ok); } else { QMessageBox::warning (this, tr("Failed to generate layer"), tr("<b>Layer generation failed</b><p>Failed to generate a derived layer.<p>The layer transform \"%1\" failed.<p>No error information is available.") .arg(transformName), QMessageBox::Ok); } } void MainWindow::modelGenerationWarning(QString transformName, QString message) { QMessageBox::warning (this, tr("Warning"), message, QMessageBox::Ok); } void MainWindow::modelRegenerationFailed(QString layerName, QString transformName, QString message) { if (message != "") { QMessageBox::warning (this, tr("Failed to regenerate layer"), tr("<b>Layer generation failed</b><p>Failed to regenerate derived layer \"%1\" using new data model as input.<p>The layer transform \"%2\" failed:<p>%3") .arg(layerName).arg(transformName).arg(message), QMessageBox::Ok); } else { QMessageBox::warning (this, tr("Failed to regenerate layer"), tr("<b>Layer generation failed</b><p>Failed to regenerate derived layer \"%1\" using new data model as input.<p>The layer transform \"%2\" failed.<p>No error information is available.") .arg(layerName).arg(transformName), QMessageBox::Ok); } } void MainWindow::modelRegenerationWarning(QString layerName, QString transformName, QString message) { QMessageBox::warning (this, tr("Warning"), tr("<b>Warning when regenerating layer</b><p>When regenerating the derived layer \"%1\" using new data model as input:<p>%2").arg(layerName).arg(message), QMessageBox::Ok); } void MainWindow::alignmentFailed(QString transformName, QString message) { QMessageBox::warning (this, tr("Failed to calculate alignment"), tr("<b>Alignment calculation failed</b><p>Failed to calculate an audio alignment using transform \"%1\":<p>%2") .arg(transformName).arg(message), QMessageBox::Ok); } void MainWindow::rightButtonMenuRequested(Pane *pane, QPoint position) { // cerr << "MainWindow::rightButtonMenuRequested(" << pane << ", " << position.x() << ", " << position.y() << ")" << endl; m_paneStack->setCurrentPane(pane); m_rightButtonMenu->popup(position); } void MainWindow::handleOSCMessage(const OSCMessage &message) { cerr << "MainWindow::handleOSCMessage: Not implemented" << endl; } void MainWindow::mouseEnteredWidget() { QWidget *w = qobject_cast<QWidget *>(sender()); if (!w) return; if (w == m_fader) { contextHelpChanged(tr("Adjust the master playback level")); } else if (w == m_playSpeed) { contextHelpChanged(tr("Adjust the master playback speed")); } else if (w == m_playSharpen && w->isEnabled()) { contextHelpChanged(tr("Toggle transient sharpening for playback time scaling")); } else if (w == m_playMono && w->isEnabled()) { contextHelpChanged(tr("Toggle mono mode for playback time scaling")); } } void MainWindow::mouseLeftWidget() { contextHelpChanged(""); } void MainWindow::website() { //!!! todo: URL! openHelpUrl(tr("http://code.soundsoftware.ac.uk/projects/tony/")); } void MainWindow::help() { //!!! todo: help URL! openHelpUrl(tr("http://code.soundsoftware.ac.uk/projects/tony/")); } void MainWindow::about() { bool debug = false; QString version = "(unknown version)"; #ifdef BUILD_DEBUG debug = true; #endif version = tr("Release %1").arg(TONY_VERSION); QString aboutText; aboutText += tr("<h3>About Tony</h3>"); aboutText += tr("<p>Tony is a program for interactive note and pitch analysis and annotation.</p>"); aboutText += tr("<p>%1 : %2 configuration</p>") .arg(version) .arg(debug ? tr("Debug") : tr("Release")); aboutText += "<p>Copyright © 2005–2013 Chris Cannam, Matthias Mauch, George Fazekas, and Queen Mary University of London.</p>" "<p>This program is free software; you can redistribute it and/or " "modify it under the terms of the GNU General Public License as " "published by the Free Software Foundation; either version 2 of the " "License, or (at your option) any later version.<br>See the file " "COPYING included with this distribution for more information.</p>"; QMessageBox::about(this, tr("About %1").arg(QApplication::applicationName()), aboutText); } void MainWindow::keyReference() { m_keyReference->show(); }