annotate src/MainWindow.cpp @ 516:449a0355f864 v2.0_osx_deploy

Deployment fixes. Qt on OSX now seems to depend on QtDBus, so copy that in, and also fail if anything is found to depend on an absent Qt framework.
author Chris Cannam
date Fri, 23 Oct 2015 08:50:39 +0100
parents d8013f97df3c
children 30fbc53d8150
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 Tony
Chris@0 5 An intonation analysis and annotation tool
Chris@0 6 Centre for Digital Music, Queen Mary, University of London.
Chris@0 7 This file copyright 2006-2012 Chris Cannam and QMUL.
Chris@0 8
Chris@0 9 This program is free software; you can redistribute it and/or
Chris@0 10 modify it under the terms of the GNU General Public License as
Chris@0 11 published by the Free Software Foundation; either version 2 of the
Chris@0 12 License, or (at your option) any later version. See the file
Chris@0 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include "../version.h"
Chris@0 17
Chris@0 18 #include "MainWindow.h"
Chris@95 19 #include "NetworkPermissionTester.h"
Chris@6 20 #include "Analyser.h"
Chris@6 21
Chris@0 22 #include "framework/Document.h"
Chris@95 23 #include "framework/VersionTester.h"
Chris@0 24
Chris@0 25 #include "view/Pane.h"
Chris@0 26 #include "view/PaneStack.h"
Chris@0 27 #include "data/model/WaveFileModel.h"
matthiasm@26 28 #include "data/model/NoteModel.h"
matthiasm@26 29 #include "data/model/FlexiNoteModel.h"
matthiasm@42 30 #include "layer/FlexiNoteLayer.h"
matthiasm@26 31 #include "data/model/NoteModel.h"
Chris@0 32 #include "view/ViewManager.h"
Chris@0 33 #include "base/Preferences.h"
Chris@404 34 #include "base/AudioLevel.h"
Chris@0 35 #include "layer/WaveformLayer.h"
Chris@0 36 #include "layer/TimeInstantLayer.h"
Chris@0 37 #include "layer/TimeValueLayer.h"
Chris@192 38 #include "layer/SpectrogramLayer.h"
Chris@0 39 #include "widgets/Fader.h"
Chris@0 40 #include "view/Overview.h"
Chris@0 41 #include "widgets/AudioDial.h"
Chris@0 42 #include "widgets/IconLoader.h"
Chris@0 43 #include "widgets/KeyReference.h"
Chris@414 44 #include "widgets/LevelPanToolButton.h"
Chris@474 45 #include "audio/AudioCallbackPlaySource.h"
Chris@474 46 #include "audio/AudioRecordTarget.h"
Chris@474 47 #include "audio/PlaySpeedRangeMapper.h"
Chris@0 48 #include "base/Profiler.h"
Chris@0 49 #include "base/UnitDatabase.h"
Chris@0 50 #include "layer/ColourDatabase.h"
Chris@139 51 #include "base/Selection.h"
Chris@0 52
Chris@174 53 #include "rdf/RDFImporter.h"
Chris@174 54 #include "data/fileio/DataFileReaderFactory.h"
Chris@174 55 #include "data/fileio/CSVFormat.h"
matthiasm@26 56 #include "data/fileio/CSVFileWriter.h"
matthiasm@26 57 #include "data/fileio/MIDIFileWriter.h"
matthiasm@26 58 #include "rdf/RDFExporter.h"
matthiasm@26 59
Chris@227 60 #include "widgets/RangeInputDialog.h"
Chris@244 61 #include "widgets/ActivityLog.h"
Chris@227 62
Chris@0 63 // For version information
Chris@0 64 #include "vamp/vamp.h"
Chris@0 65 #include "vamp-sdk/PluginBase.h"
Chris@0 66 #include "plugin/api/ladspa.h"
Chris@0 67 #include "plugin/api/dssi.h"
Chris@0 68
Chris@474 69 #include <bqaudioio/SystemPlaybackTarget.h>
Chris@479 70 #include <bqaudioio/SystemAudioIO.h>
Chris@474 71
Chris@0 72 #include <QApplication>
Chris@0 73 #include <QMessageBox>
Chris@0 74 #include <QGridLayout>
Chris@0 75 #include <QLabel>
Chris@0 76 #include <QMenuBar>
Chris@0 77 #include <QToolBar>
Chris@0 78 #include <QToolButton>
Chris@0 79 #include <QInputDialog>
Chris@0 80 #include <QStatusBar>
Chris@0 81 #include <QFileInfo>
Chris@0 82 #include <QDir>
Chris@0 83 #include <QProcess>
Chris@2 84 #include <QPushButton>
Chris@0 85 #include <QSettings>
Chris@0 86 #include <QScrollArea>
Chris@128 87 #include <QPainter>
Chris@413 88 #include <QWidgetAction>
Chris@0 89
Chris@0 90 #include <iostream>
Chris@0 91 #include <cstdio>
Chris@0 92 #include <errno.h>
Chris@0 93
Chris@0 94 using std::vector;
Chris@0 95
Chris@0 96
Chris@474 97 MainWindow::MainWindow(SoundOptions options, bool withSonification, bool withSpectrogram) :
Chris@474 98 MainWindowBase(options),
Chris@0 99 m_overview(0),
Chris@0 100 m_mainMenusCreated(false),
Chris@0 101 m_playbackMenu(0),
gyorgyf@45 102 m_recentFilesMenu(0),
Chris@0 103 m_rightButtonMenu(0),
Chris@0 104 m_rightButtonPlaybackMenu(0),
Chris@0 105 m_deleteSelectedAction(0),
Chris@0 106 m_ffwdAction(0),
Chris@0 107 m_rwdAction(0),
Chris@168 108 m_intelligentActionOn(true), //GF: !!! temporary
Chris@244 109 m_activityLog(new ActivityLog()),
matthiasm@296 110 m_keyReference(new KeyReference()),
matthiasm@364 111 m_selectionAnchor(0),
matthiasm@364 112 m_withSonification(withSonification),
matthiasm@364 113 m_withSpectrogram(withSpectrogram)
Chris@0 114 {
Chris@0 115 setWindowTitle(QApplication::applicationName());
Chris@0 116
Chris@206 117 #ifdef Q_OS_MAC
Chris@206 118 #if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
Chris@206 119 setUnifiedTitleAndToolBarOnMac(true);
Chris@206 120 #endif
Chris@206 121 #endif
Chris@206 122
Chris@0 123 UnitDatabase *udb = UnitDatabase::getInstance();
Chris@0 124 udb->registerUnit("Hz");
Chris@0 125 udb->registerUnit("dB");
Chris@0 126 udb->registerUnit("s");
Chris@0 127
Chris@0 128 ColourDatabase *cdb = ColourDatabase::getInstance();
Chris@0 129 cdb->addColour(Qt::black, tr("Black"));
Chris@0 130 cdb->addColour(Qt::darkRed, tr("Red"));
Chris@0 131 cdb->addColour(Qt::darkBlue, tr("Blue"));
Chris@0 132 cdb->addColour(Qt::darkGreen, tr("Green"));
Chris@0 133 cdb->addColour(QColor(200, 50, 255), tr("Purple"));
Chris@0 134 cdb->addColour(QColor(255, 150, 50), tr("Orange"));
Chris@120 135 cdb->addColour(QColor(180, 180, 180), tr("Grey"));
Chris@0 136 cdb->setUseDarkBackground(cdb->addColour(Qt::white, tr("White")), true);
Chris@0 137 cdb->setUseDarkBackground(cdb->addColour(Qt::red, tr("Bright Red")), true);
Chris@0 138 cdb->setUseDarkBackground(cdb->addColour(QColor(30, 150, 255), tr("Bright Blue")), true);
Chris@0 139 cdb->setUseDarkBackground(cdb->addColour(Qt::green, tr("Bright Green")), true);
Chris@0 140 cdb->setUseDarkBackground(cdb->addColour(QColor(225, 74, 255), tr("Bright Purple")), true);
Chris@0 141 cdb->setUseDarkBackground(cdb->addColour(QColor(255, 188, 80), tr("Bright Orange")), true);
Chris@0 142
Chris@0 143 Preferences::getInstance()->setResampleOnLoad(true);
Chris@315 144 Preferences::getInstance()->setFixedSampleRate(44100);
Chris@0 145 Preferences::getInstance()->setSpectrogramSmoothing
Chris@0 146 (Preferences::SpectrogramInterpolated);
Chris@332 147 Preferences::getInstance()->setNormaliseAudio(true);
Chris@0 148
Chris@0 149 QSettings settings;
Chris@0 150
Chris@0 151 settings.beginGroup("MainWindow");
Chris@0 152 settings.setValue("showstatusbar", false);
Chris@0 153 settings.endGroup();
Chris@0 154
Chris@96 155 settings.beginGroup("Transformer");
Chris@96 156 settings.setValue("use-flexi-note-model", true);
Chris@96 157 settings.endGroup();
Chris@96 158
Chris@73 159 settings.beginGroup("LayerDefaults");
Chris@73 160 settings.setValue("waveform",
Chris@73 161 QString("<layer scale=\"%1\" channelMode=\"%2\"/>")
Chris@73 162 .arg(int(WaveformLayer::LinearScale))
Chris@73 163 .arg(int(WaveformLayer::MixChannels)));
Chris@73 164 settings.endGroup();
Chris@73 165
Chris@6 166 m_viewManager->setAlignMode(false);
Chris@6 167 m_viewManager->setPlaySoloMode(false);
Chris@392 168 m_viewManager->setToolMode(ViewManager::NavigateMode);
Chris@0 169 m_viewManager->setZoomWheelsEnabled(false);
Chris@6 170 m_viewManager->setIlluminateLocalFeatures(true);
matthiasm@368 171 m_viewManager->setShowWorkTitle(false);
Chris@6 172 m_viewManager->setShowCentreLine(false);
matthiasm@368 173 m_viewManager->setShowDuration(false);
Chris@213 174 m_viewManager->setOverlayMode(ViewManager::GlobalOverlays);
Chris@0 175
Chris@192 176 connect(m_viewManager, SIGNAL(selectionChangedByUser()),
Chris@192 177 this, SLOT(selectionChangedByUser()));
Chris@164 178
Chris@0 179 QFrame *frame = new QFrame;
Chris@0 180 setCentralWidget(frame);
Chris@0 181
Chris@0 182 QGridLayout *layout = new QGridLayout;
Chris@0 183
Chris@0 184 QScrollArea *scroll = new QScrollArea(frame);
Chris@0 185 scroll->setWidgetResizable(true);
Chris@0 186 scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
Chris@0 187 scroll->setFrameShape(QFrame::NoFrame);
Chris@0 188
Chris@6 189 // We have a pane stack: it comes with the territory. However, we
Chris@120 190 // have a fixed and known number of panes in it -- it isn't
Chris@120 191 // variable
Chris@0 192 m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks);
Chris@137 193 m_paneStack->setShowPaneAccessories(false);
Chris@399 194 connect(m_paneStack, SIGNAL(doubleClickSelectInvoked(sv_frame_t)),
Chris@399 195 this, SLOT(doubleClickSelectInvoked(sv_frame_t)));
Chris@0 196 scroll->setWidget(m_paneStack);
Chris@6 197
Chris@0 198 m_overview = new Overview(frame);
Chris@362 199 m_overview->setPlaybackFollow(PlaybackScrollPage);
Chris@0 200 m_overview->setViewManager(m_viewManager);
Chris@393 201 m_overview->setFixedHeight(60);
Chris@0 202 #ifndef _WIN32
Chris@0 203 // For some reason, the contents of the overview never appear if we
Chris@0 204 // make this setting on Windows. I have no inclination at the moment
Chris@0 205 // to track down the reason why.
Chris@0 206 m_overview->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
Chris@0 207 #endif
Chris@0 208 connect(m_overview, SIGNAL(contextHelpChanged(const QString &)),
Chris@0 209 this, SLOT(contextHelpChanged(const QString &)));
Chris@0 210
Chris@0 211 m_panLayer = new WaveformLayer;
Chris@0 212 m_panLayer->setChannelMode(WaveformLayer::MergeChannels);
Chris@0 213 m_panLayer->setAggressiveCacheing(true);
Chris@393 214 m_panLayer->setGain(0.5);
Chris@0 215 m_overview->addLayer(m_panLayer);
Chris@0 216
Chris@0 217 if (m_viewManager->getGlobalDarkBackground()) {
Chris@0 218 m_panLayer->setBaseColour
Chris@0 219 (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green")));
Chris@0 220 } else {
Chris@0 221 m_panLayer->setBaseColour
matthiasm@13 222 (ColourDatabase::getInstance()->getColourIndex(tr("Blue")));
Chris@0 223 }
Chris@0 224
Chris@0 225 m_fader = new Fader(frame, false);
Chris@0 226 connect(m_fader, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@0 227 connect(m_fader, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@0 228
Chris@0 229 m_playSpeed = new AudioDial(frame);
Chris@343 230 m_playSpeed->setMeterColor(Qt::darkBlue);
Chris@0 231 m_playSpeed->setMinimum(0);
Chris@477 232 m_playSpeed->setMaximum(120);
Chris@502 233 m_playSpeed->setValue(60);
Chris@0 234 m_playSpeed->setFixedWidth(24);
Chris@0 235 m_playSpeed->setFixedHeight(24);
Chris@0 236 m_playSpeed->setNotchesVisible(true);
Chris@0 237 m_playSpeed->setPageStep(10);
Chris@477 238 m_playSpeed->setObjectName(tr("Playback Speed"));
Chris@477 239 m_playSpeed->setDefaultValue(60);
Chris@474 240 m_playSpeed->setRangeMapper(new PlaySpeedRangeMapper);
Chris@0 241 m_playSpeed->setShowToolTip(true);
Chris@0 242 connect(m_playSpeed, SIGNAL(valueChanged(int)),
gyorgyf@27 243 this, SLOT(playSpeedChanged(int)));
Chris@0 244 connect(m_playSpeed, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@0 245 connect(m_playSpeed, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@0 246
Chris@414 247 m_audioLPW = new LevelPanToolButton(frame);
Chris@434 248 m_audioLPW->setIncludeMute(false);
Chris@404 249 m_audioLPW->setObjectName(tr("Audio Track Level and Pan"));
Chris@404 250 connect(m_audioLPW, SIGNAL(levelChanged(float)), this, SLOT(audioGainChanged(float)));
Chris@404 251 connect(m_audioLPW, SIGNAL(panChanged(float)), this, SLOT(audioPanChanged(float)));
Chris@404 252
Chris@404 253 if (m_withSonification) {
Chris@404 254
Chris@414 255 m_pitchLPW = new LevelPanToolButton(frame);
Chris@434 256 m_pitchLPW->setIncludeMute(false);
Chris@404 257 m_pitchLPW->setObjectName(tr("Pitch Track Level and Pan"));
Chris@404 258 connect(m_pitchLPW, SIGNAL(levelChanged(float)), this, SLOT(pitchGainChanged(float)));
Chris@404 259 connect(m_pitchLPW, SIGNAL(panChanged(float)), this, SLOT(pitchPanChanged(float)));
Chris@404 260
Chris@414 261 m_notesLPW = new LevelPanToolButton(frame);
Chris@434 262 m_notesLPW->setIncludeMute(false);
Chris@404 263 m_notesLPW->setObjectName(tr("Note Track Level and Pan"));
Chris@404 264 connect(m_notesLPW, SIGNAL(levelChanged(float)), this, SLOT(notesGainChanged(float)));
Chris@404 265 connect(m_notesLPW, SIGNAL(panChanged(float)), this, SLOT(notesPanChanged(float)));
matthiasm@366 266 }
justin@160 267
Chris@0 268 layout->setSpacing(4);
Chris@6 269 layout->addWidget(m_overview, 0, 1);
Chris@6 270 layout->addWidget(scroll, 1, 1);
Chris@0 271
Chris@0 272 layout->setColumnStretch(1, 10);
Chris@0 273
Chris@0 274 frame->setLayout(layout);
Chris@0 275
gyorgyf@21 276 m_analyser = new Analyser();
Chris@128 277 connect(m_analyser, SIGNAL(layersChanged()),
Chris@128 278 this, SLOT(updateLayerStatuses()));
Chris@187 279 connect(m_analyser, SIGNAL(layersChanged()),
Chris@187 280 this, SLOT(updateMenuStates()));
gyorgyf@21 281
Chris@0 282 setupMenus();
Chris@0 283 setupToolbars();
Chris@0 284 setupHelpMenu();
Chris@0 285
Chris@0 286 statusBar();
Chris@0 287
Chris@288 288 finaliseMenus();
Chris@288 289
Chris@244 290 connect(m_viewManager, SIGNAL(activity(QString)),
Chris@244 291 m_activityLog, SLOT(activityHappened(QString)));
Chris@244 292 connect(m_playSource, SIGNAL(activity(QString)),
Chris@244 293 m_activityLog, SLOT(activityHappened(QString)));
Chris@244 294 connect(CommandHistory::getInstance(), SIGNAL(activity(QString)),
Chris@244 295 m_activityLog, SLOT(activityHappened(QString)));
Chris@244 296 connect(this, SIGNAL(activity(QString)),
Chris@244 297 m_activityLog, SLOT(activityHappened(QString)));
Chris@244 298 connect(this, SIGNAL(replacedDocument()), this, SLOT(documentReplaced()));
Chris@260 299 connect(this, SIGNAL(sessionLoaded()), this, SLOT(analyseNewMainModel()));
Chris@260 300 connect(this, SIGNAL(audioFileLoaded()), this, SLOT(analyseNewMainModel()));
Chris@244 301 m_activityLog->hide();
Chris@244 302
Chris@485 303 setAudioRecordMode(RecordReplaceSession);
Chris@485 304
Chris@95 305 newSession();
Chris@6 306
Chris@95 307 settings.beginGroup("MainWindow");
Chris@95 308 settings.setValue("zoom-default", 512);
Chris@95 309 settings.endGroup();
Chris@95 310 zoomDefault();
Chris@95 311
Chris@95 312 NetworkPermissionTester tester;
Chris@95 313 bool networkPermission = tester.havePermission();
Chris@95 314 if (networkPermission) {
Chris@95 315 m_versionTester = new VersionTester
Chris@95 316 ("sonicvisualiser.org", "latest-tony-version.txt", TONY_VERSION);
Chris@95 317 connect(m_versionTester, SIGNAL(newerVersionAvailable(QString)),
Chris@95 318 this, SLOT(newerVersionAvailable(QString)));
Chris@95 319 } else {
Chris@95 320 m_versionTester = 0;
Chris@95 321 }
Chris@0 322 }
Chris@0 323
Chris@0 324 MainWindow::~MainWindow()
Chris@0 325 {
Chris@6 326 delete m_analyser;
Chris@0 327 delete m_keyReference;
Chris@0 328 Profiles::getInstance()->dump();
Chris@0 329 }
Chris@0 330
Chris@0 331 void
Chris@0 332 MainWindow::setupMenus()
Chris@0 333 {
Chris@0 334 if (!m_mainMenusCreated) {
Chris@385 335
Chris@385 336 #ifdef Q_OS_LINUX
Chris@385 337 // In Ubuntu 14.04 the window's menu bar goes missing entirely
Chris@385 338 // if the user is running any desktop environment other than Unity
Chris@385 339 // (in which the faux single-menubar appears). The user has a
Chris@385 340 // workaround, to remove the appmenu-qt5 package, but that is
Chris@385 341 // awkward and the problem is so severe that it merits disabling
Chris@385 342 // the system menubar integration altogether. Like this:
Chris@385 343 menuBar()->setNativeMenuBar(false);
Chris@385 344 #endif
Chris@385 345
Chris@0 346 m_rightButtonMenu = new QMenu();
Chris@0 347 }
Chris@0 348
Chris@0 349 if (!m_mainMenusCreated) {
Chris@0 350 CommandHistory::getInstance()->registerMenu(m_rightButtonMenu);
Chris@0 351 m_rightButtonMenu->addSeparator();
Chris@0 352 }
Chris@0 353
Chris@0 354 setupFileMenu();
Chris@0 355 setupEditMenu();
Chris@0 356 setupViewMenu();
matthiasm@317 357 setupAnalysisMenu();
Chris@0 358
Chris@0 359 m_mainMenusCreated = true;
Chris@0 360 }
Chris@0 361
Chris@0 362 void
Chris@0 363 MainWindow::setupFileMenu()
Chris@0 364 {
Chris@0 365 if (m_mainMenusCreated) return;
Chris@0 366
Chris@0 367 QMenu *menu = menuBar()->addMenu(tr("&File"));
Chris@0 368 menu->setTearOffEnabled(true);
Chris@0 369 QToolBar *toolbar = addToolBar(tr("File Toolbar"));
Chris@0 370
Chris@0 371 m_keyReference->setCategory(tr("File and Session Management"));
Chris@0 372
Chris@0 373 IconLoader il;
Chris@1 374 QIcon icon;
Chris@1 375 QAction *action;
Chris@0 376
Chris@0 377 icon = il.load("fileopen");
Chris@1 378 action = new QAction(icon, tr("&Open..."), this);
Chris@0 379 action->setShortcut(tr("Ctrl+O"));
Chris@257 380 action->setStatusTip(tr("Open a session or audio file"));
Chris@0 381 connect(action, SIGNAL(triggered()), this, SLOT(openFile()));
Chris@0 382 m_keyReference->registerShortcut(action);
Chris@0 383 menu->addAction(action);
Chris@0 384 toolbar->addAction(action);
Chris@0 385
Chris@1 386 action = new QAction(tr("Open Lo&cation..."), this);
Chris@0 387 action->setShortcut(tr("Ctrl+Shift+O"));
Chris@1 388 action->setStatusTip(tr("Open a file from a remote URL"));
Chris@0 389 connect(action, SIGNAL(triggered()), this, SLOT(openLocation()));
Chris@0 390 m_keyReference->registerShortcut(action);
Chris@0 391 menu->addAction(action);
Chris@0 392
Chris@1 393 m_recentFilesMenu = menu->addMenu(tr("Open &Recent"));
Chris@0 394 m_recentFilesMenu->setTearOffEnabled(true);
Chris@0 395 setupRecentFilesMenu();
Chris@0 396 connect(&m_recentFiles, SIGNAL(recentChanged()),
Chris@0 397 this, SLOT(setupRecentFilesMenu()));
Chris@0 398
Chris@0 399 menu->addSeparator();
Chris@257 400
Chris@257 401 icon = il.load("filesave");
Chris@257 402 action = new QAction(icon, tr("&Save Session"), this);
Chris@257 403 action->setShortcut(tr("Ctrl+S"));
Chris@257 404 action->setStatusTip(tr("Save the current session into a %1 session file").arg(QApplication::applicationName()));
Chris@257 405 connect(action, SIGNAL(triggered()), this, SLOT(saveSession()));
Chris@257 406 connect(this, SIGNAL(canSave(bool)), action, SLOT(setEnabled(bool)));
Chris@257 407 m_keyReference->registerShortcut(action);
Chris@257 408 menu->addAction(action);
Chris@257 409 toolbar->addAction(action);
Chris@257 410
Chris@257 411 icon = il.load("filesaveas");
Chris@257 412 action = new QAction(icon, tr("Save Session &As..."), this);
Chris@257 413 action->setShortcut(tr("Ctrl+Shift+S"));
Chris@257 414 action->setStatusTip(tr("Save the current session into a new %1 session file").arg(QApplication::applicationName()));
Chris@257 415 connect(action, SIGNAL(triggered()), this, SLOT(saveSessionAs()));
Chris@313 416 connect(this, SIGNAL(canSaveAs(bool)), action, SLOT(setEnabled(bool)));
Chris@257 417 menu->addAction(action);
Chris@257 418 toolbar->addAction(action);
Chris@257 419
Chris@486 420 action = new QAction(tr("Save Session to Audio File &Path"), this);
matthiasm@310 421 action->setShortcut(tr("Ctrl+Alt+S"));
Chris@313 422 action->setStatusTip(tr("Save the current session into a %1 session file with the same filename as the audio but a .ton extension.").arg(QApplication::applicationName()));
matthiasm@310 423 connect(action, SIGNAL(triggered()), this, SLOT(saveSessionInAudioPath()));
Chris@313 424 connect(this, SIGNAL(canSaveAs(bool)), action, SLOT(setEnabled(bool)));
matthiasm@310 425 menu->addAction(action);
matthiasm@310 426
Chris@257 427 menu->addSeparator();
Chris@257 428
Chris@253 429 action = new QAction(tr("I&mport Pitch Track Data..."), this);
Chris@253 430 action->setStatusTip(tr("Import pitch-track data from a CSV, RDF, or layer XML file"));
Chris@174 431 connect(action, SIGNAL(triggered()), this, SLOT(importPitchLayer()));
Chris@174 432 connect(this, SIGNAL(canImportLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@174 433 menu->addAction(action);
Chris@174 434
Chris@253 435 action = new QAction(tr("E&xport Pitch Track Data..."), this);
Chris@253 436 action->setStatusTip(tr("Export pitch-track data to a CSV, RDF, or layer XML file"));
Chris@85 437 connect(action, SIGNAL(triggered()), this, SLOT(exportPitchLayer()));
Chris@224 438 connect(this, SIGNAL(canExportPitchTrack(bool)), action, SLOT(setEnabled(bool)));
Chris@85 439 menu->addAction(action);
Chris@85 440
Chris@253 441 action = new QAction(tr("&Export Note Data..."), this);
Chris@253 442 action->setStatusTip(tr("Export note data to a CSV, RDF, layer XML, or MIDI file"));
Chris@85 443 connect(action, SIGNAL(triggered()), this, SLOT(exportNoteLayer()));
Chris@224 444 connect(this, SIGNAL(canExportNotes(bool)), action, SLOT(setEnabled(bool)));
matthiasm@26 445 menu->addAction(action);
matthiasm@26 446
matthiasm@26 447 menu->addSeparator();
Chris@485 448
Chris@485 449 action = new QAction(tr("Browse Recorded Audio"), this);
Chris@485 450 action->setStatusTip(tr("Open the Recorded Audio folder in the system file browser"));
Chris@485 451 connect(action, SIGNAL(triggered()), this, SLOT(browseRecordedAudio()));
Chris@485 452 menu->addAction(action);
Chris@485 453
Chris@485 454 menu->addSeparator();
Chris@485 455
Chris@0 456 action = new QAction(il.load("exit"), tr("&Quit"), this);
Chris@0 457 action->setShortcut(tr("Ctrl+Q"));
Chris@0 458 action->setStatusTip(tr("Exit %1").arg(QApplication::applicationName()));
Chris@0 459 connect(action, SIGNAL(triggered()), this, SLOT(close()));
Chris@0 460 m_keyReference->registerShortcut(action);
Chris@0 461 menu->addAction(action);
Chris@0 462 }
Chris@0 463
Chris@0 464 void
Chris@0 465 MainWindow::setupEditMenu()
Chris@0 466 {
Chris@0 467 if (m_mainMenusCreated) return;
Chris@0 468
Chris@0 469 QMenu *menu = menuBar()->addMenu(tr("&Edit"));
Chris@0 470 menu->setTearOffEnabled(true);
Chris@0 471 CommandHistory::getInstance()->registerMenu(menu);
Chris@126 472 menu->addSeparator();
Chris@126 473
Chris@254 474 m_keyReference->setCategory
Chris@254 475 (tr("Selection Strip Mouse Actions"));
Chris@254 476 m_keyReference->registerShortcut
Chris@254 477 (tr("Jump"), tr("Left"),
Chris@254 478 tr("Click left button to move the playback position to a time"));
Chris@254 479 m_keyReference->registerShortcut
Chris@254 480 (tr("Select"), tr("Left"),
Chris@254 481 tr("Click left button and drag to select a region of time"));
Chris@254 482 m_keyReference->registerShortcut
Chris@254 483 (tr("Select Note Duration"), tr("Double-Click Left"),
Chris@254 484 tr("Double-click left button to select the region of time corresponding to a note"));
Chris@254 485
Chris@126 486 QToolBar *toolbar = addToolBar(tr("Tools Toolbar"));
Chris@126 487
Chris@126 488 CommandHistory::getInstance()->registerToolbar(toolbar);
Chris@126 489
Chris@250 490 QActionGroup *group = new QActionGroup(this);
Chris@250 491
Chris@250 492 IconLoader il;
Chris@250 493
Chris@126 494 m_keyReference->setCategory(tr("Tool Selection"));
Chris@126 495 QAction *action = toolbar->addAction(il.load("navigate"),
Chris@126 496 tr("Navigate"));
Chris@126 497 action->setCheckable(true);
Chris@126 498 action->setChecked(true);
Chris@126 499 action->setShortcut(tr("1"));
Chris@126 500 action->setStatusTip(tr("Navigate"));
Chris@126 501 connect(action, SIGNAL(triggered()), this, SLOT(toolNavigateSelected()));
Chris@126 502 connect(this, SIGNAL(replacedDocument()), action, SLOT(trigger()));
Chris@126 503 group->addAction(action);
Chris@126 504 menu->addAction(action);
Chris@126 505 m_keyReference->registerShortcut(action);
Chris@126 506
Chris@250 507 m_keyReference->setCategory
Chris@250 508 (tr("Navigate Tool Mouse Actions"));
Chris@250 509 m_keyReference->registerShortcut
Chris@250 510 (tr("Navigate"), tr("Left"),
Chris@250 511 tr("Click left button and drag to move around"));
Chris@250 512 m_keyReference->registerShortcut
Chris@250 513 (tr("Re-Analyse Area"), tr("Shift+Left"),
Chris@250 514 tr("Shift-click left button and drag to define a specific pitch and time range to re-analyse"));
Chris@250 515 m_keyReference->registerShortcut
Chris@250 516 (tr("Edit"), tr("Double-Click Left"),
Chris@250 517 tr("Double-click left button on an item to edit it"));
Chris@392 518
Chris@250 519 m_keyReference->setCategory(tr("Tool Selection"));
Chris@126 520 action = toolbar->addAction(il.load("move"),
Chris@126 521 tr("Edit"));
Chris@126 522 action->setCheckable(true);
Chris@126 523 action->setShortcut(tr("2"));
Chris@126 524 action->setStatusTip(tr("Edit with Note Intelligence"));
Chris@126 525 connect(action, SIGNAL(triggered()), this, SLOT(toolEditSelected()));
Chris@126 526 group->addAction(action);
Chris@126 527 menu->addAction(action);
Chris@126 528 m_keyReference->registerShortcut(action);
Chris@126 529
Chris@250 530 m_keyReference->setCategory
Chris@250 531 (tr("Note Edit Tool Mouse Actions"));
Chris@250 532 m_keyReference->registerShortcut
Chris@250 533 (tr("Adjust Pitch"), tr("Left"),
Chris@250 534 tr("Click left button on the main part of a note and drag to move it up or down"));
Chris@250 535 m_keyReference->registerShortcut
Chris@250 536 (tr("Split"), tr("Left"),
Chris@250 537 tr("Click left button on the bottom edge of a note to split it at the click point"));
Chris@250 538 m_keyReference->registerShortcut
Chris@250 539 (tr("Resize"), tr("Left"),
Chris@250 540 tr("Click left button on the left or right edge of a note and drag to change the time or duration of the note"));
Chris@250 541 m_keyReference->registerShortcut
Chris@250 542 (tr("Erase"), tr("Shift+Left"),
Chris@250 543 tr("Shift-click left button on a note to remove it"));
Chris@250 544
Chris@250 545
Chris@126 546 /* Remove for now...
Chris@126 547
Chris@250 548 m_keyReference->setCategory(tr("Tool Selection"));
Chris@126 549 action = toolbar->addAction(il.load("notes"),
Chris@126 550 tr("Free Edit"));
Chris@126 551 action->setCheckable(true);
Chris@126 552 action->setShortcut(tr("3"));
Chris@126 553 action->setStatusTip(tr("Free Edit"));
Chris@126 554 connect(action, SIGNAL(triggered()), this, SLOT(toolFreeEditSelected()));
Chris@126 555 group->addAction(action);
Chris@126 556 m_keyReference->registerShortcut(action);
Chris@126 557 */
Chris@142 558
Chris@142 559 menu->addSeparator();
Chris@142 560
Chris@143 561 m_keyReference->setCategory(tr("Selection"));
Chris@143 562
Chris@143 563 action = new QAction(tr("Select &All"), this);
Chris@143 564 action->setShortcut(tr("Ctrl+A"));
Chris@143 565 action->setStatusTip(tr("Select the whole duration of the current session"));
Chris@143 566 connect(action, SIGNAL(triggered()), this, SLOT(selectAll()));
Chris@143 567 connect(this, SIGNAL(canSelect(bool)), action, SLOT(setEnabled(bool)));
Chris@143 568 m_keyReference->registerShortcut(action);
Chris@143 569 menu->addAction(action);
Chris@143 570 m_rightButtonMenu->addAction(action);
Chris@143 571
Chris@287 572 action = new QAction(tr("C&lear Selection"), this);
Chris@211 573 action->setShortcuts(QList<QKeySequence>()
Chris@211 574 << QKeySequence(tr("Esc"))
Chris@211 575 << QKeySequence(tr("Ctrl+Esc")));
Chris@211 576 action->setStatusTip(tr("Clear the selection and abandon any pending pitch choices in it"));
Chris@194 577 connect(action, SIGNAL(triggered()), this, SLOT(abandonSelection()));
Chris@143 578 connect(this, SIGNAL(canClearSelection(bool)), action, SLOT(setEnabled(bool)));
Chris@143 579 m_keyReference->registerShortcut(action);
Chris@211 580 m_keyReference->registerAlternativeShortcut(action, QKeySequence(tr("Ctrl+Esc")));
Chris@143 581 menu->addAction(action);
Chris@143 582 m_rightButtonMenu->addAction(action);
Chris@143 583
Chris@143 584 menu->addSeparator();
Chris@189 585 m_rightButtonMenu->addSeparator();
Chris@143 586
Chris@189 587 m_keyReference->setCategory(tr("Pitch Track"));
Chris@211 588
Chris@211 589 action = new QAction(tr("Choose Higher Pitch"), this);
Chris@211 590 action->setShortcut(tr("Ctrl+Up"));
Chris@211 591 action->setStatusTip(tr("Move pitches up an octave, or to the next higher pitch candidate"));
Chris@211 592 m_keyReference->registerShortcut(action);
Chris@211 593 connect(action, SIGNAL(triggered()), this, SLOT(switchPitchUp()));
Chris@211 594 connect(this, SIGNAL(canClearSelection(bool)), action, SLOT(setEnabled(bool)));
Chris@211 595 menu->addAction(action);
Chris@211 596 m_rightButtonMenu->addAction(action);
Chris@211 597
Chris@211 598 action = new QAction(tr("Choose Lower Pitch"), this);
Chris@211 599 action->setShortcut(tr("Ctrl+Down"));
Chris@211 600 action->setStatusTip(tr("Move pitches down an octave, or to the next lower pitch candidate"));
Chris@211 601 m_keyReference->registerShortcut(action);
Chris@211 602 connect(action, SIGNAL(triggered()), this, SLOT(switchPitchDown()));
Chris@211 603 connect(this, SIGNAL(canClearSelection(bool)), action, SLOT(setEnabled(bool)));
Chris@211 604 menu->addAction(action);
Chris@211 605 m_rightButtonMenu->addAction(action);
Chris@189 606
Chris@187 607 m_showCandidatesAction = new QAction(tr("Show Pitch Candidates"), this);
Chris@187 608 m_showCandidatesAction->setShortcut(tr("Ctrl+Return"));
Chris@189 609 m_showCandidatesAction->setStatusTip(tr("Toggle the display of alternative pitch candidates for the selected region"));
Chris@189 610 m_keyReference->registerShortcut(m_showCandidatesAction);
Chris@187 611 connect(m_showCandidatesAction, SIGNAL(triggered()), this, SLOT(togglePitchCandidates()));
Chris@187 612 connect(this, SIGNAL(canClearSelection(bool)), m_showCandidatesAction, SLOT(setEnabled(bool)));
Chris@187 613 menu->addAction(m_showCandidatesAction);
Chris@189 614 m_rightButtonMenu->addAction(m_showCandidatesAction);
Chris@187 615
Chris@287 616 action = new QAction(tr("Remove Pitches"), this);
matthiasm@327 617 action->setShortcut(tr("Ctrl+Backspace"));
Chris@211 618 action->setStatusTip(tr("Remove all pitch estimates within the selected region, making it unvoiced"));
Chris@189 619 m_keyReference->registerShortcut(action);
Chris@187 620 connect(action, SIGNAL(triggered()), this, SLOT(clearPitches()));
Chris@167 621 connect(this, SIGNAL(canClearSelection(bool)), action, SLOT(setEnabled(bool)));
Chris@167 622 menu->addAction(action);
Chris@189 623 m_rightButtonMenu->addAction(action);
Chris@237 624
Chris@237 625 menu->addSeparator();
Chris@237 626 m_rightButtonMenu->addSeparator();
Chris@237 627
matthiasm@327 628 m_keyReference->setCategory(tr("Note Track"));
matthiasm@327 629
Chris@287 630 action = new QAction(tr("Split Note"), this);
matthiasm@327 631 action->setShortcut(tr("/"));
Chris@240 632 action->setStatusTip(tr("Split the note at the current playback position into two"));
Chris@237 633 m_keyReference->registerShortcut(action);
Chris@240 634 connect(action, SIGNAL(triggered()), this, SLOT(splitNote()));
Chris@240 635 connect(this, SIGNAL(canExportNotes(bool)), action, SLOT(setEnabled(bool)));
Chris@237 636 menu->addAction(action);
Chris@237 637 m_rightButtonMenu->addAction(action);
Chris@238 638
Chris@287 639 action = new QAction(tr("Merge Notes"), this);
matthiasm@327 640 action->setShortcut(tr("\\"));
Chris@238 641 action->setStatusTip(tr("Merge all notes within the selected region into a single note"));
Chris@238 642 m_keyReference->registerShortcut(action);
Chris@238 643 connect(action, SIGNAL(triggered()), this, SLOT(mergeNotes()));
Chris@238 644 connect(this, SIGNAL(canSnapNotes(bool)), action, SLOT(setEnabled(bool)));
Chris@238 645 menu->addAction(action);
Chris@238 646 m_rightButtonMenu->addAction(action);
matthiasm@292 647
matthiasm@292 648 action = new QAction(tr("Delete Notes"), this);
matthiasm@327 649 action->setShortcut(tr("Backspace"));
matthiasm@327 650 action->setStatusTip(tr("Delete all notes within the selected region"));
matthiasm@292 651 m_keyReference->registerShortcut(action);
matthiasm@292 652 connect(action, SIGNAL(triggered()), this, SLOT(deleteNotes()));
matthiasm@292 653 connect(this, SIGNAL(canSnapNotes(bool)), action, SLOT(setEnabled(bool)));
matthiasm@292 654 menu->addAction(action);
matthiasm@292 655 m_rightButtonMenu->addAction(action);
Chris@238 656
Chris@240 657 action = new QAction(tr("Form Note from Selection"), this);
matthiasm@327 658 action->setShortcut(tr("="));
Chris@240 659 action->setStatusTip(tr("Form a note spanning the selected region, splitting any existing notes at its boundaries"));
Chris@240 660 m_keyReference->registerShortcut(action);
Chris@240 661 connect(action, SIGNAL(triggered()), this, SLOT(formNoteFromSelection()));
Chris@240 662 connect(this, SIGNAL(canSnapNotes(bool)), action, SLOT(setEnabled(bool)));
Chris@240 663 menu->addAction(action);
Chris@240 664 m_rightButtonMenu->addAction(action);
Chris@247 665
Chris@238 666 action = new QAction(tr("Snap Notes to Pitch Track"), this);
Chris@238 667 action->setStatusTip(tr("Set notes within the selected region to the median frequency of their underlying pitches, or remove them if there are no underlying pitches"));
matthiasm@327 668 // m_keyReference->registerShortcut(action);
Chris@238 669 connect(action, SIGNAL(triggered()), this, SLOT(snapNotesToPitches()));
Chris@238 670 connect(this, SIGNAL(canSnapNotes(bool)), action, SLOT(setEnabled(bool)));
Chris@238 671 menu->addAction(action);
Chris@238 672 m_rightButtonMenu->addAction(action);
Chris@0 673 }
Chris@0 674
Chris@0 675 void
Chris@0 676 MainWindow::setupViewMenu()
Chris@0 677 {
Chris@0 678 if (m_mainMenusCreated) return;
Chris@0 679
Chris@0 680 IconLoader il;
Chris@0 681
Chris@0 682 QAction *action = 0;
Chris@0 683
Chris@0 684 m_keyReference->setCategory(tr("Panning and Navigation"));
Chris@0 685
Chris@0 686 QMenu *menu = menuBar()->addMenu(tr("&View"));
Chris@0 687 menu->setTearOffEnabled(true);
Chris@300 688 action = new QAction(tr("Peek &Left"), this);
Chris@300 689 action->setShortcut(tr("Alt+Left"));
Chris@300 690 action->setStatusTip(tr("Scroll the current pane to the left without changing the play position"));
Chris@0 691 connect(action, SIGNAL(triggered()), this, SLOT(scrollLeft()));
Chris@0 692 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
Chris@0 693 m_keyReference->registerShortcut(action);
Chris@0 694 menu->addAction(action);
gyorgyf@27 695
Chris@300 696 action = new QAction(tr("Peek &Right"), this);
Chris@300 697 action->setShortcut(tr("Alt+Right"));
Chris@300 698 action->setStatusTip(tr("Scroll the current pane to the right without changing the play position"));
Chris@0 699 connect(action, SIGNAL(triggered()), this, SLOT(scrollRight()));
Chris@0 700 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
Chris@0 701 m_keyReference->registerShortcut(action);
Chris@0 702 menu->addAction(action);
matthiasm@283 703
Chris@0 704 menu->addSeparator();
Chris@0 705
Chris@0 706 m_keyReference->setCategory(tr("Zoom"));
Chris@0 707
Chris@0 708 action = new QAction(il.load("zoom-in"),
Chris@0 709 tr("Zoom &In"), this);
Chris@0 710 action->setShortcut(tr("Up"));
Chris@0 711 action->setStatusTip(tr("Increase the zoom level"));
Chris@0 712 connect(action, SIGNAL(triggered()), this, SLOT(zoomIn()));
Chris@0 713 connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool)));
Chris@0 714 m_keyReference->registerShortcut(action);
Chris@0 715 menu->addAction(action);
gyorgyf@27 716
Chris@0 717 action = new QAction(il.load("zoom-out"),
Chris@0 718 tr("Zoom &Out"), this);
Chris@0 719 action->setShortcut(tr("Down"));
Chris@0 720 action->setStatusTip(tr("Decrease the zoom level"));
Chris@0 721 connect(action, SIGNAL(triggered()), this, SLOT(zoomOut()));
Chris@0 722 connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool)));
Chris@0 723 m_keyReference->registerShortcut(action);
Chris@0 724 menu->addAction(action);
gyorgyf@27 725
Chris@0 726 action = new QAction(tr("Restore &Default Zoom"), this);
Chris@0 727 action->setStatusTip(tr("Restore the zoom level to the default"));
Chris@0 728 connect(action, SIGNAL(triggered()), this, SLOT(zoomDefault()));
Chris@0 729 connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool)));
Chris@0 730 menu->addAction(action);
Chris@0 731
Chris@0 732 action = new QAction(il.load("zoom-fit"),
Chris@0 733 tr("Zoom to &Fit"), this);
Chris@0 734 action->setShortcut(tr("F"));
Chris@0 735 action->setStatusTip(tr("Zoom to show the whole file"));
Chris@0 736 connect(action, SIGNAL(triggered()), this, SLOT(zoomToFit()));
Chris@0 737 connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool)));
Chris@0 738 m_keyReference->registerShortcut(action);
Chris@0 739 menu->addAction(action);
Chris@227 740
Chris@227 741 menu->addSeparator();
Chris@227 742
Chris@227 743 action = new QAction(tr("Set Displayed Fre&quency Range..."), this);
Chris@227 744 action->setStatusTip(tr("Set the minimum and maximum frequencies in the visible display"));
Chris@227 745 connect(action, SIGNAL(triggered()), this, SLOT(editDisplayExtents()));
Chris@227 746 menu->addAction(action);
Chris@0 747 }
Chris@0 748
Chris@0 749 void
matthiasm@317 750 MainWindow::setupAnalysisMenu()
matthiasm@317 751 {
matthiasm@317 752 if (m_mainMenusCreated) return;
matthiasm@317 753
matthiasm@317 754 IconLoader il;
matthiasm@317 755
matthiasm@317 756 QAction *action = 0;
matthiasm@317 757
matthiasm@317 758 QMenu *menu = menuBar()->addMenu(tr("&Analysis"));
matthiasm@317 759 menu->setTearOffEnabled(true);
matthiasm@317 760
Chris@427 761 m_autoAnalyse = new QAction(tr("Auto-Analyse &New Audio"), this);
Chris@427 762 m_autoAnalyse->setStatusTip(tr("Automatically trigger analysis upon opening of a new audio file."));
Chris@427 763 m_autoAnalyse->setCheckable(true);
Chris@427 764 connect(m_autoAnalyse, SIGNAL(triggered()), this, SLOT(autoAnalysisToggled()));
Chris@427 765 menu->addAction(m_autoAnalyse);
Chris@427 766
Chris@427 767 action = new QAction(tr("&Analyse Now!"), this);
Chris@427 768 action->setStatusTip(tr("Trigger analysis of pitches and notes. (This will delete all existing pitches and notes.)"));
Chris@427 769 connect(action, SIGNAL(triggered()), this, SLOT(analyseNow()));
Chris@427 770 menu->addAction(action);
Chris@427 771 m_keyReference->registerShortcut(action);
Chris@427 772
Chris@427 773 menu->addSeparator();
Chris@427 774
Chris@427 775 m_precise = new QAction(tr("&Unbiased Timing (slow)"), this);
Chris@427 776 m_precise->setStatusTip(tr("Use a symmetric window in YIN to remove frequency-dependent timing bias. (This is slow!)"));
Chris@427 777 m_precise->setCheckable(true);
Chris@427 778 connect(m_precise, SIGNAL(triggered()), this, SLOT(precisionAnalysisToggled()));
Chris@427 779 menu->addAction(m_precise);
Chris@427 780
Chris@427 781 m_lowamp = new QAction(tr("&Penalise Soft Pitches"), this);
Chris@427 782 m_lowamp->setStatusTip(tr("Reduce the likelihood of detecting a pitch when the signal has low amplitude."));
Chris@427 783 m_lowamp->setCheckable(true);
Chris@427 784 connect(m_lowamp, SIGNAL(triggered()), this, SLOT(lowampAnalysisToggled()));
Chris@427 785 menu->addAction(m_lowamp);
Chris@427 786
Chris@427 787 m_onset = new QAction(tr("&High Onset Sensitivity"), this);
Chris@427 788 m_onset->setStatusTip(tr("Increase likelihood of separating notes, especially consecutive notes at the same pitch."));
Chris@427 789 m_onset->setCheckable(true);
Chris@427 790 connect(m_onset, SIGNAL(triggered()), this, SLOT(onsetAnalysisToggled()));
Chris@427 791 menu->addAction(m_onset);
Chris@427 792
Chris@427 793 m_prune = new QAction(tr("&Drop Short Notes"), this);
Chris@427 794 m_prune->setStatusTip(tr("Duration-based pruning: automatic note estimator will not output notes of less than 100ms duration."));
Chris@427 795 m_prune->setCheckable(true);
Chris@427 796 connect(m_prune, SIGNAL(triggered()), this, SLOT(pruneAnalysisToggled()));
Chris@427 797 menu->addAction(m_prune);
Chris@427 798
Chris@427 799 menu->addSeparator();
Chris@427 800
Chris@427 801 action = new QAction(tr("Reset Options to Defaults"), this);
Chris@427 802 action->setStatusTip(tr("Reset all of the Analyse menu options to their default settings."));
Chris@427 803 connect(action, SIGNAL(triggered()), this, SLOT(resetAnalyseOptions()));
Chris@427 804 menu->addAction(action);
Chris@427 805
Chris@427 806 updateAnalyseStates();
Chris@427 807 }
Chris@427 808
Chris@427 809 void
Chris@427 810 MainWindow::resetAnalyseOptions()
Chris@427 811 {
Chris@427 812 //!!! oh no, we need to update the menu states as well...
Chris@427 813 QSettings settings;
Chris@427 814 settings.beginGroup("Analyser");
Chris@427 815 settings.setValue("auto-analysis", true);
Chris@427 816 settings.setValue("precision-analysis", false);
Chris@427 817 settings.setValue("lowamp-analysis", true);
Chris@427 818 settings.setValue("onset-analysis", true);
Chris@427 819 settings.setValue("prune-analysis", true);
Chris@427 820 settings.endGroup();
Chris@427 821 updateAnalyseStates();
Chris@427 822 }
Chris@427 823
Chris@427 824 void
Chris@427 825 MainWindow::updateAnalyseStates()
Chris@427 826 {
Chris@323 827 QSettings settings;
Chris@323 828 settings.beginGroup("Analyser");
Chris@323 829 bool autoAnalyse = settings.value("auto-analysis", true).toBool();
Chris@323 830 bool precise = settings.value("precision-analysis", false).toBool();
matthiasm@345 831 bool lowamp = settings.value("lowamp-analysis", true).toBool();
matthiasm@423 832 bool onset = settings.value("onset-analysis", true).toBool();
matthiasm@423 833 bool prune = settings.value("prune-analysis", true).toBool();
Chris@323 834 settings.endGroup();
Chris@323 835
Chris@427 836 m_autoAnalyse->setChecked(autoAnalyse);
Chris@427 837 m_precise->setChecked(precise);
Chris@427 838 m_lowamp->setChecked(lowamp);
Chris@427 839 m_onset->setChecked(onset);
Chris@427 840 m_prune->setChecked(prune);
Chris@323 841 }
Chris@323 842
Chris@323 843 void
Chris@323 844 MainWindow::autoAnalysisToggled()
Chris@323 845 {
Chris@323 846 QAction *a = qobject_cast<QAction *>(sender());
Chris@323 847 if (!a) return;
Chris@323 848
Chris@323 849 bool set = a->isChecked();
Chris@323 850
Chris@323 851 QSettings settings;
Chris@323 852 settings.beginGroup("Analyser");
Chris@323 853 settings.setValue("auto-analysis", set);
Chris@323 854 settings.endGroup();
Chris@323 855 }
Chris@323 856
Chris@323 857 void
Chris@323 858 MainWindow::precisionAnalysisToggled()
Chris@323 859 {
Chris@323 860 QAction *a = qobject_cast<QAction *>(sender());
Chris@323 861 if (!a) return;
Chris@323 862
Chris@323 863 bool set = a->isChecked();
Chris@323 864
Chris@323 865 QSettings settings;
Chris@323 866 settings.beginGroup("Analyser");
Chris@323 867 settings.setValue("precision-analysis", set);
Chris@323 868 settings.endGroup();
Chris@323 869
Chris@326 870 // don't run analyseNow() automatically -- it's a destructive operation
matthiasm@317 871 }
matthiasm@317 872
matthiasm@317 873 void
matthiasm@345 874 MainWindow::lowampAnalysisToggled()
matthiasm@345 875 {
matthiasm@345 876 QAction *a = qobject_cast<QAction *>(sender());
matthiasm@345 877 if (!a) return;
matthiasm@345 878
matthiasm@345 879 bool set = a->isChecked();
matthiasm@345 880
matthiasm@345 881 QSettings settings;
matthiasm@345 882 settings.beginGroup("Analyser");
matthiasm@345 883 settings.setValue("lowamp-analysis", set);
matthiasm@345 884 settings.endGroup();
matthiasm@345 885
matthiasm@345 886 // don't run analyseNow() automatically -- it's a destructive operation
matthiasm@345 887 }
matthiasm@345 888
matthiasm@345 889 void
matthiasm@423 890 MainWindow::onsetAnalysisToggled()
matthiasm@423 891 {
matthiasm@423 892 QAction *a = qobject_cast<QAction *>(sender());
matthiasm@423 893 if (!a) return;
matthiasm@423 894
matthiasm@423 895 bool set = a->isChecked();
matthiasm@423 896
matthiasm@423 897 QSettings settings;
matthiasm@423 898 settings.beginGroup("Analyser");
matthiasm@423 899 settings.setValue("onset-analysis", set);
matthiasm@423 900 settings.endGroup();
matthiasm@423 901
matthiasm@423 902 // don't run analyseNow() automatically -- it's a destructive operation
matthiasm@423 903 }
matthiasm@423 904
matthiasm@423 905 void
matthiasm@423 906 MainWindow::pruneAnalysisToggled()
matthiasm@423 907 {
matthiasm@423 908 QAction *a = qobject_cast<QAction *>(sender());
matthiasm@423 909 if (!a) return;
matthiasm@423 910
matthiasm@423 911 bool set = a->isChecked();
matthiasm@423 912
matthiasm@423 913 QSettings settings;
matthiasm@423 914 settings.beginGroup("Analyser");
matthiasm@423 915 settings.setValue("prune-analysis", set);
matthiasm@423 916 settings.endGroup();
matthiasm@423 917
matthiasm@423 918 // don't run analyseNow() automatically -- it's a destructive operation
matthiasm@423 919 }
matthiasm@423 920
matthiasm@423 921 void
Chris@0 922 MainWindow::setupHelpMenu()
Chris@0 923 {
Chris@0 924 QMenu *menu = menuBar()->addMenu(tr("&Help"));
Chris@0 925 menu->setTearOffEnabled(true);
Chris@0 926
Chris@0 927 m_keyReference->setCategory(tr("Help"));
Chris@0 928
Chris@0 929 IconLoader il;
Chris@0 930
Chris@1 931 QString name = QApplication::applicationName();
matthiasm@367 932 QAction *action;
matthiasm@367 933
Chris@0 934 action = new QAction(tr("&Key and Mouse Reference"), this);
Chris@0 935 action->setShortcut(tr("F2"));
Chris@1 936 action->setStatusTip(tr("Open a window showing the keystrokes you can use in %1").arg(name));
Chris@0 937 connect(action, SIGNAL(triggered()), this, SLOT(keyReference()));
Chris@0 938 m_keyReference->registerShortcut(action);
Chris@0 939 menu->addAction(action);
matthiasm@369 940
matthiasm@369 941 action = new QAction(il.load("help"),
matthiasm@369 942 tr("&Help Reference"), this);
matthiasm@369 943 action->setShortcut(tr("F1"));
matthiasm@369 944 action->setStatusTip(tr("Open the %1 reference manual").arg(name));
matthiasm@369 945 connect(action, SIGNAL(triggered()), this, SLOT(help()));
matthiasm@369 946 m_keyReference->registerShortcut(action);
matthiasm@369 947 menu->addAction(action);
matthiasm@369 948
Chris@0 949
Chris@1 950 action = new QAction(tr("%1 on the &Web").arg(name), this);
Chris@1 951 action->setStatusTip(tr("Open the %1 website").arg(name));
Chris@0 952 connect(action, SIGNAL(triggered()), this, SLOT(website()));
Chris@0 953 menu->addAction(action);
Chris@0 954
Chris@1 955 action = new QAction(tr("&About %1").arg(name), this);
Chris@1 956 action->setStatusTip(tr("Show information about %1").arg(name));
Chris@0 957 connect(action, SIGNAL(triggered()), this, SLOT(about()));
Chris@0 958 menu->addAction(action);
Chris@0 959 }
Chris@0 960
Chris@0 961 void
Chris@0 962 MainWindow::setupRecentFilesMenu()
Chris@0 963 {
Chris@0 964 m_recentFilesMenu->clear();
Chris@0 965 vector<QString> files = m_recentFiles.getRecent();
Chris@0 966 for (size_t i = 0; i < files.size(); ++i) {
Chris@50 967 QAction *action = new QAction(files[i], this);
Chris@50 968 connect(action, SIGNAL(triggered()), this, SLOT(openRecentFile()));
Chris@0 969 if (i == 0) {
Chris@0 970 action->setShortcut(tr("Ctrl+R"));
Chris@0 971 m_keyReference->registerShortcut
Chris@0 972 (tr("Re-open"),
Chris@50 973 action->shortcut().toString(),
Chris@0 974 tr("Re-open the current or most recently opened file"));
Chris@0 975 }
Chris@50 976 m_recentFilesMenu->addAction(action);
Chris@0 977 }
Chris@0 978 }
Chris@0 979
Chris@0 980 void
Chris@0 981 MainWindow::setupToolbars()
Chris@0 982 {
Chris@0 983 m_keyReference->setCategory(tr("Playback and Transport Controls"));
Chris@0 984
Chris@0 985 IconLoader il;
Chris@0 986
Chris@0 987 QMenu *menu = m_playbackMenu = menuBar()->addMenu(tr("Play&back"));
Chris@0 988 menu->setTearOffEnabled(true);
Chris@0 989 m_rightButtonMenu->addSeparator();
Chris@0 990 m_rightButtonPlaybackMenu = m_rightButtonMenu->addMenu(tr("Playback"));
Chris@0 991
Chris@0 992 QToolBar *toolbar = addToolBar(tr("Playback Toolbar"));
Chris@0 993
Chris@0 994 QAction *rwdStartAction = toolbar->addAction(il.load("rewind-start"),
Chris@0 995 tr("Rewind to Start"));
Chris@0 996 rwdStartAction->setShortcut(tr("Home"));
Chris@0 997 rwdStartAction->setStatusTip(tr("Rewind to the start"));
Chris@0 998 connect(rwdStartAction, SIGNAL(triggered()), this, SLOT(rewindStart()));
Chris@0 999 connect(this, SIGNAL(canPlay(bool)), rwdStartAction, SLOT(setEnabled(bool)));
Chris@0 1000
Chris@0 1001 QAction *m_rwdAction = toolbar->addAction(il.load("rewind"),
Chris@0 1002 tr("Rewind"));
Chris@300 1003 m_rwdAction->setShortcut(tr("Left"));
Chris@300 1004 m_rwdAction->setStatusTip(tr("Rewind to the previous one-second boundary"));
Chris@0 1005 connect(m_rwdAction, SIGNAL(triggered()), this, SLOT(rewind()));
Chris@0 1006 connect(this, SIGNAL(canRewind(bool)), m_rwdAction, SLOT(setEnabled(bool)));
Chris@0 1007
Chris@300 1008 setDefaultFfwdRwdStep(RealTime(1, 0));
Chris@300 1009
Chris@0 1010 QAction *playAction = toolbar->addAction(il.load("playpause"),
Chris@0 1011 tr("Play / Pause"));
Chris@0 1012 playAction->setCheckable(true);
Chris@0 1013 playAction->setShortcut(tr("Space"));
Chris@0 1014 playAction->setStatusTip(tr("Start or stop playback from the current position"));
Chris@0 1015 connect(playAction, SIGNAL(triggered()), this, SLOT(play()));
Chris@0 1016 connect(m_playSource, SIGNAL(playStatusChanged(bool)),
gyorgyf@27 1017 playAction, SLOT(setChecked(bool)));
Chris@0 1018 connect(this, SIGNAL(canPlay(bool)), playAction, SLOT(setEnabled(bool)));
Chris@0 1019
Chris@0 1020 m_ffwdAction = toolbar->addAction(il.load("ffwd"),
Chris@0 1021 tr("Fast Forward"));
Chris@300 1022 m_ffwdAction->setShortcut(tr("Right"));
Chris@300 1023 m_ffwdAction->setStatusTip(tr("Fast-forward to the next one-second boundary"));
Chris@0 1024 connect(m_ffwdAction, SIGNAL(triggered()), this, SLOT(ffwd()));
Chris@0 1025 connect(this, SIGNAL(canFfwd(bool)), m_ffwdAction, SLOT(setEnabled(bool)));
Chris@0 1026
Chris@0 1027 QAction *ffwdEndAction = toolbar->addAction(il.load("ffwd-end"),
Chris@0 1028 tr("Fast Forward to End"));
Chris@0 1029 ffwdEndAction->setShortcut(tr("End"));
Chris@0 1030 ffwdEndAction->setStatusTip(tr("Fast-forward to the end"));
Chris@0 1031 connect(ffwdEndAction, SIGNAL(triggered()), this, SLOT(ffwdEnd()));
Chris@0 1032 connect(this, SIGNAL(canPlay(bool)), ffwdEndAction, SLOT(setEnabled(bool)));
Chris@6 1033
Chris@476 1034 QAction *recordAction = toolbar->addAction(il.load("record"),
Chris@476 1035 tr("Record"));
Chris@476 1036 recordAction->setCheckable(true);
Chris@476 1037 recordAction->setShortcut(tr("Ctrl+Space"));
Chris@476 1038 recordAction->setStatusTip(tr("Record a new audio file"));
Chris@476 1039 connect(recordAction, SIGNAL(triggered()), this, SLOT(record()));
Chris@476 1040 connect(m_recordTarget, SIGNAL(recordStatusChanged(bool)),
Chris@476 1041 recordAction, SLOT(setChecked(bool)));
Chris@497 1042 connect(m_recordTarget, SIGNAL(recordCompleted()),
Chris@497 1043 this, SLOT(analyseNow()));
Chris@476 1044 connect(this, SIGNAL(canRecord(bool)),
Chris@476 1045 recordAction, SLOT(setEnabled(bool)));
Chris@476 1046
Chris@0 1047 toolbar = addToolBar(tr("Play Mode Toolbar"));
Chris@0 1048
Chris@0 1049 QAction *psAction = toolbar->addAction(il.load("playselection"),
Chris@0 1050 tr("Constrain Playback to Selection"));
Chris@0 1051 psAction->setCheckable(true);
Chris@0 1052 psAction->setChecked(m_viewManager->getPlaySelectionMode());
Chris@0 1053 psAction->setShortcut(tr("s"));
Chris@0 1054 psAction->setStatusTip(tr("Constrain playback to the selected regions"));
Chris@0 1055 connect(m_viewManager, SIGNAL(playSelectionModeChanged(bool)),
Chris@0 1056 psAction, SLOT(setChecked(bool)));
Chris@0 1057 connect(psAction, SIGNAL(triggered()), this, SLOT(playSelectionToggled()));
Chris@0 1058 connect(this, SIGNAL(canPlaySelection(bool)), psAction, SLOT(setEnabled(bool)));
Chris@0 1059
Chris@0 1060 QAction *plAction = toolbar->addAction(il.load("playloop"),
Chris@0 1061 tr("Loop Playback"));
Chris@0 1062 plAction->setCheckable(true);
Chris@0 1063 plAction->setChecked(m_viewManager->getPlayLoopMode());
Chris@0 1064 plAction->setShortcut(tr("l"));
Chris@0 1065 plAction->setStatusTip(tr("Loop playback"));
Chris@0 1066 connect(m_viewManager, SIGNAL(playLoopModeChanged(bool)),
Chris@0 1067 plAction, SLOT(setChecked(bool)));
Chris@0 1068 connect(plAction, SIGNAL(triggered()), this, SLOT(playLoopToggled()));
Chris@0 1069 connect(this, SIGNAL(canPlay(bool)), plAction, SLOT(setEnabled(bool)));
Chris@0 1070
Chris@300 1071 QAction *oneLeftAction = new QAction(tr("&One Note Left"), this);
Chris@300 1072 oneLeftAction->setShortcut(tr("Ctrl+Left"));
Chris@300 1073 oneLeftAction->setStatusTip(tr("Move cursor to the preceding note (or silence) onset."));
Chris@300 1074 connect(oneLeftAction, SIGNAL(triggered()), this, SLOT(moveOneNoteLeft()));
Chris@300 1075 connect(this, SIGNAL(canScroll(bool)), oneLeftAction, SLOT(setEnabled(bool)));
Chris@300 1076
Chris@300 1077 QAction *oneRightAction = new QAction(tr("O&ne Note Right"), this);
Chris@300 1078 oneRightAction->setShortcut(tr("Ctrl+Right"));
Chris@300 1079 oneRightAction->setStatusTip(tr("Move cursor to the succeeding note (or silence)."));
Chris@300 1080 connect(oneRightAction, SIGNAL(triggered()), this, SLOT(moveOneNoteRight()));
Chris@300 1081 connect(this, SIGNAL(canScroll(bool)), oneRightAction, SLOT(setEnabled(bool)));
Chris@300 1082
Chris@300 1083 QAction *selectOneLeftAction = new QAction(tr("&Select One Note Left"), this);
Chris@300 1084 selectOneLeftAction->setShortcut(tr("Ctrl+Shift+Left"));
Chris@300 1085 selectOneLeftAction->setStatusTip(tr("Select to the preceding note (or silence) onset."));
Chris@300 1086 connect(selectOneLeftAction, SIGNAL(triggered()), this, SLOT(selectOneNoteLeft()));
Chris@300 1087 connect(this, SIGNAL(canScroll(bool)), selectOneLeftAction, SLOT(setEnabled(bool)));
Chris@300 1088
Chris@300 1089 QAction *selectOneRightAction = new QAction(tr("S&elect One Note Right"), this);
Chris@300 1090 selectOneRightAction->setShortcut(tr("Ctrl+Shift+Right"));
Chris@300 1091 selectOneRightAction->setStatusTip(tr("Select to the succeeding note (or silence)."));
Chris@300 1092 connect(selectOneRightAction, SIGNAL(triggered()), this, SLOT(selectOneNoteRight()));
Chris@300 1093 connect(this, SIGNAL(canScroll(bool)), selectOneRightAction, SLOT(setEnabled(bool)));
Chris@300 1094
Chris@0 1095 m_keyReference->registerShortcut(psAction);
Chris@0 1096 m_keyReference->registerShortcut(plAction);
Chris@0 1097 m_keyReference->registerShortcut(playAction);
Chris@476 1098 m_keyReference->registerShortcut(recordAction);
Chris@0 1099 m_keyReference->registerShortcut(m_rwdAction);
Chris@0 1100 m_keyReference->registerShortcut(m_ffwdAction);
Chris@0 1101 m_keyReference->registerShortcut(rwdStartAction);
Chris@0 1102 m_keyReference->registerShortcut(ffwdEndAction);
Chris@476 1103 m_keyReference->registerShortcut(recordAction);
Chris@300 1104 m_keyReference->registerShortcut(oneLeftAction);
Chris@300 1105 m_keyReference->registerShortcut(oneRightAction);
Chris@300 1106 m_keyReference->registerShortcut(selectOneLeftAction);
Chris@300 1107 m_keyReference->registerShortcut(selectOneRightAction);
Chris@0 1108
Chris@6 1109 menu->addAction(playAction);
Chris@0 1110 menu->addAction(psAction);
Chris@0 1111 menu->addAction(plAction);
Chris@0 1112 menu->addSeparator();
Chris@0 1113 menu->addAction(m_rwdAction);
Chris@0 1114 menu->addAction(m_ffwdAction);
Chris@0 1115 menu->addSeparator();
Chris@0 1116 menu->addAction(rwdStartAction);
Chris@0 1117 menu->addAction(ffwdEndAction);
Chris@0 1118 menu->addSeparator();
Chris@300 1119 menu->addAction(oneLeftAction);
Chris@300 1120 menu->addAction(oneRightAction);
Chris@300 1121 menu->addAction(selectOneLeftAction);
Chris@300 1122 menu->addAction(selectOneRightAction);
Chris@300 1123 menu->addSeparator();
Chris@476 1124 menu->addAction(recordAction);
Chris@476 1125 menu->addSeparator();
Chris@0 1126
Chris@0 1127 m_rightButtonPlaybackMenu->addAction(playAction);
Chris@0 1128 m_rightButtonPlaybackMenu->addAction(psAction);
Chris@0 1129 m_rightButtonPlaybackMenu->addAction(plAction);
Chris@0 1130 m_rightButtonPlaybackMenu->addSeparator();
Chris@0 1131 m_rightButtonPlaybackMenu->addAction(m_rwdAction);
Chris@0 1132 m_rightButtonPlaybackMenu->addAction(m_ffwdAction);
Chris@0 1133 m_rightButtonPlaybackMenu->addSeparator();
Chris@0 1134 m_rightButtonPlaybackMenu->addAction(rwdStartAction);
Chris@0 1135 m_rightButtonPlaybackMenu->addAction(ffwdEndAction);
Chris@0 1136 m_rightButtonPlaybackMenu->addSeparator();
Chris@300 1137 m_rightButtonPlaybackMenu->addAction(oneLeftAction);
Chris@300 1138 m_rightButtonPlaybackMenu->addAction(oneRightAction);
Chris@300 1139 m_rightButtonPlaybackMenu->addAction(selectOneLeftAction);
Chris@300 1140 m_rightButtonPlaybackMenu->addAction(selectOneRightAction);
Chris@300 1141 m_rightButtonPlaybackMenu->addSeparator();
Chris@476 1142 m_rightButtonPlaybackMenu->addAction(recordAction);
Chris@476 1143 m_rightButtonPlaybackMenu->addSeparator();
Chris@0 1144
Chris@0 1145 QAction *fastAction = menu->addAction(tr("Speed Up"));
Chris@0 1146 fastAction->setShortcut(tr("Ctrl+PgUp"));
Chris@0 1147 fastAction->setStatusTip(tr("Time-stretch playback to speed it up without changing pitch"));
Chris@0 1148 connect(fastAction, SIGNAL(triggered()), this, SLOT(speedUpPlayback()));
Chris@0 1149 connect(this, SIGNAL(canSpeedUpPlayback(bool)), fastAction, SLOT(setEnabled(bool)));
Chris@0 1150
Chris@0 1151 QAction *slowAction = menu->addAction(tr("Slow Down"));
Chris@0 1152 slowAction->setShortcut(tr("Ctrl+PgDown"));
Chris@0 1153 slowAction->setStatusTip(tr("Time-stretch playback to slow it down without changing pitch"));
Chris@0 1154 connect(slowAction, SIGNAL(triggered()), this, SLOT(slowDownPlayback()));
Chris@0 1155 connect(this, SIGNAL(canSlowDownPlayback(bool)), slowAction, SLOT(setEnabled(bool)));
Chris@0 1156
Chris@0 1157 QAction *normalAction = menu->addAction(tr("Restore Normal Speed"));
Chris@0 1158 normalAction->setShortcut(tr("Ctrl+Home"));
Chris@0 1159 normalAction->setStatusTip(tr("Restore non-time-stretched playback"));
Chris@0 1160 connect(normalAction, SIGNAL(triggered()), this, SLOT(restoreNormalPlayback()));
Chris@0 1161 connect(this, SIGNAL(canChangePlaybackSpeed(bool)), normalAction, SLOT(setEnabled(bool)));
Chris@0 1162
Chris@0 1163 m_keyReference->registerShortcut(fastAction);
Chris@0 1164 m_keyReference->registerShortcut(slowAction);
Chris@0 1165 m_keyReference->registerShortcut(normalAction);
Chris@0 1166
Chris@0 1167 m_rightButtonPlaybackMenu->addAction(fastAction);
Chris@0 1168 m_rightButtonPlaybackMenu->addAction(slowAction);
Chris@0 1169 m_rightButtonPlaybackMenu->addAction(normalAction);
Chris@6 1170
Chris@195 1171 toolbar = new QToolBar(tr("Playback Controls"));
Chris@195 1172 addToolBar(Qt::BottomToolBarArea, toolbar);
Chris@195 1173
Chris@6 1174 toolbar->addWidget(m_playSpeed);
Chris@6 1175 toolbar->addWidget(m_fader);
Chris@0 1176
Chris@128 1177 toolbar = addToolBar(tr("Show and Play"));
matthiasm@258 1178 addToolBar(Qt::BottomToolBarArea, toolbar);
Chris@144 1179
Chris@144 1180 m_showAudio = toolbar->addAction(il.load("waveform"), tr("Show Audio"));
Chris@144 1181 m_showAudio->setCheckable(true);
Chris@144 1182 connect(m_showAudio, SIGNAL(triggered()), this, SLOT(showAudioToggled()));
Chris@144 1183 connect(this, SIGNAL(canPlay(bool)), m_showAudio, SLOT(setEnabled(bool)));
Chris@144 1184
Chris@424 1185 m_playAudio = toolbar->addAction(il.load("speaker"), tr("Play Audio"));
Chris@424 1186 m_playAudio->setCheckable(true);
Chris@424 1187 connect(m_playAudio, SIGNAL(triggered()), this, SLOT(playAudioToggled()));
Chris@424 1188 connect(this, SIGNAL(canPlayWaveform(bool)), m_playAudio, SLOT(setEnabled(bool)));
Chris@424 1189
Chris@440 1190 int lpwSize, bigLpwSize;
Chris@440 1191 #ifdef Q_OS_MAC
Chris@440 1192 lpwSize = m_viewManager->scalePixelSize(32); // Mac toolbars are fatter
Chris@442 1193 bigLpwSize = int(lpwSize * 2.2);
Chris@440 1194 #else
Chris@440 1195 lpwSize = m_viewManager->scalePixelSize(26);
Chris@442 1196 bigLpwSize = int(lpwSize * 2.8);
Chris@440 1197 #endif
Chris@440 1198
Chris@440 1199 m_audioLPW->setImageSize(lpwSize);
Chris@440 1200 m_audioLPW->setBigImageSize(bigLpwSize);
Chris@414 1201 toolbar->addWidget(m_audioLPW);
Chris@414 1202
Chris@290 1203 // Pitch (f0)
Chris@290 1204 QLabel *spacer = new QLabel; // blank
Chris@419 1205 spacer->setFixedWidth(m_viewManager->scalePixelSize(30));
Chris@290 1206 toolbar->addWidget(spacer);
Chris@145 1207
Chris@144 1208 m_showPitch = toolbar->addAction(il.load("values"), tr("Show Pitch Track"));
Chris@144 1209 m_showPitch->setCheckable(true);
Chris@144 1210 connect(m_showPitch, SIGNAL(triggered()), this, SLOT(showPitchToggled()));
Chris@144 1211 connect(this, SIGNAL(canPlay(bool)), m_showPitch, SLOT(setEnabled(bool)));
Chris@144 1212
Chris@405 1213 if (m_withSonification) {
Chris@424 1214 m_playPitch = toolbar->addAction(il.load("speaker"), tr("Play Pitch Track"));
Chris@424 1215 m_playPitch->setCheckable(true);
Chris@424 1216 connect(m_playPitch, SIGNAL(triggered()), this, SLOT(playPitchToggled()));
Chris@424 1217 connect(this, SIGNAL(canPlayPitch(bool)), m_playPitch, SLOT(setEnabled(bool)));
Chris@424 1218
Chris@440 1219 m_pitchLPW->setImageSize(lpwSize);
Chris@440 1220 m_pitchLPW->setBigImageSize(bigLpwSize);
Chris@404 1221 toolbar->addWidget(m_pitchLPW);
Chris@424 1222 } else {
Chris@424 1223 m_playPitch = 0;
matthiasm@366 1224 }
Chris@404 1225
Chris@290 1226 // Notes
Chris@290 1227 spacer = new QLabel;
Chris@419 1228 spacer->setFixedWidth(m_viewManager->scalePixelSize(30));
Chris@290 1229 toolbar->addWidget(spacer);
Chris@290 1230
Chris@144 1231 m_showNotes = toolbar->addAction(il.load("notes"), tr("Show Notes"));
Chris@144 1232 m_showNotes->setCheckable(true);
Chris@144 1233 connect(m_showNotes, SIGNAL(triggered()), this, SLOT(showNotesToggled()));
Chris@144 1234 connect(this, SIGNAL(canPlay(bool)), m_showNotes, SLOT(setEnabled(bool)));
justin@156 1235
Chris@405 1236 if (m_withSonification) {
Chris@424 1237 m_playNotes = toolbar->addAction(il.load("speaker"), tr("Play Notes"));
Chris@424 1238 m_playNotes->setCheckable(true);
Chris@424 1239 connect(m_playNotes, SIGNAL(triggered()), this, SLOT(playNotesToggled()));
Chris@424 1240 connect(this, SIGNAL(canPlayNotes(bool)), m_playNotes, SLOT(setEnabled(bool)));
Chris@424 1241
Chris@440 1242 m_notesLPW->setImageSize(lpwSize);
Chris@440 1243 m_notesLPW->setBigImageSize(bigLpwSize);
Chris@404 1244 toolbar->addWidget(m_notesLPW);
Chris@424 1245 } else {
Chris@424 1246 m_playNotes = 0;
matthiasm@366 1247 }
justin@156 1248
justin@156 1249 // Spectrogram
Chris@290 1250 spacer = new QLabel;
Chris@419 1251 spacer->setFixedWidth(m_viewManager->scalePixelSize(30));
Chris@290 1252 toolbar->addWidget(spacer);
Chris@290 1253
matthiasm@366 1254 if (!m_withSpectrogram)
matthiasm@366 1255 {
matthiasm@366 1256 m_showSpect = new QAction(tr("Show Spectrogram"), this);
matthiasm@366 1257 } else {
matthiasm@366 1258 m_showSpect = toolbar->addAction(il.load("spectrogram"), tr("Show Spectrogram"));
matthiasm@366 1259 }
justin@156 1260 m_showSpect->setCheckable(true);
justin@156 1261 connect(m_showSpect, SIGNAL(triggered()), this, SLOT(showSpectToggled()));
justin@156 1262 connect(this, SIGNAL(canPlay(bool)), m_showSpect, SLOT(setEnabled(bool)));
Chris@128 1263
Chris@0 1264 Pane::registerShortcuts(*m_keyReference);
matthiasm@366 1265
Chris@405 1266 updateLayerStatuses();
Chris@0 1267 }
Chris@0 1268
matthiasm@281 1269
matthiasm@281 1270 void
matthiasm@281 1271 MainWindow::moveOneNoteRight()
matthiasm@281 1272 {
matthiasm@281 1273 // cerr << "MainWindow::moveOneNoteRight" << endl;
matthiasm@296 1274 moveByOneNote(true, false);
matthiasm@281 1275 }
matthiasm@281 1276
matthiasm@281 1277 void
matthiasm@281 1278 MainWindow::moveOneNoteLeft()
matthiasm@281 1279 {
matthiasm@281 1280 // cerr << "MainWindow::moveOneNoteLeft" << endl;
matthiasm@296 1281 moveByOneNote(false, false);
matthiasm@281 1282 }
matthiasm@281 1283
matthiasm@281 1284 void
matthiasm@283 1285 MainWindow::selectOneNoteRight()
matthiasm@283 1286 {
matthiasm@296 1287 moveByOneNote(true, true);
matthiasm@283 1288 }
matthiasm@283 1289
matthiasm@283 1290 void
matthiasm@283 1291 MainWindow::selectOneNoteLeft()
matthiasm@283 1292 {
matthiasm@296 1293 moveByOneNote(false, true);
matthiasm@283 1294 }
matthiasm@283 1295
matthiasm@283 1296
matthiasm@283 1297 void
matthiasm@296 1298 MainWindow::moveByOneNote(bool right, bool doSelect)
matthiasm@281 1299 {
Chris@399 1300 sv_frame_t frame = m_viewManager->getPlaybackFrame();
matthiasm@301 1301 cerr << "MainWindow::moveByOneNote startframe: " << frame << endl;
matthiasm@281 1302
matthiasm@304 1303 bool isAtSelectionBoundary = false;
matthiasm@304 1304 MultiSelection::SelectionList selections = m_viewManager->getSelections();
matthiasm@304 1305 if (!selections.empty()) {
matthiasm@304 1306 Selection sel = *selections.begin();
matthiasm@342 1307 isAtSelectionBoundary = (frame == sel.getStartFrame()) || (frame == sel.getEndFrame());
matthiasm@304 1308 }
matthiasm@304 1309 if (!doSelect || !isAtSelectionBoundary) {
matthiasm@296 1310 m_selectionAnchor = frame;
matthiasm@296 1311 }
matthiasm@296 1312
matthiasm@281 1313 Layer *layer = m_analyser->getLayer(Analyser::Notes);
matthiasm@281 1314 if (!layer) return;
matthiasm@281 1315
matthiasm@281 1316 FlexiNoteModel *model = qobject_cast<FlexiNoteModel *>(layer->getModel());
matthiasm@281 1317 if (!model) return;
matthiasm@281 1318
matthiasm@281 1319 FlexiNoteModel::PointList points = model->getPoints();
matthiasm@281 1320 if (points.empty()) return;
matthiasm@281 1321
matthiasm@281 1322 FlexiNoteModel::PointList::iterator i = points.begin();
Chris@399 1323 std::set<sv_frame_t> snapFrames;
matthiasm@281 1324 snapFrames.insert(0);
matthiasm@281 1325 while (i != points.end()) {
matthiasm@281 1326 snapFrames.insert(i->frame);
matthiasm@281 1327 snapFrames.insert(i->frame + i->duration + 1);
matthiasm@281 1328 ++i;
matthiasm@281 1329 }
Chris@399 1330 std::set<sv_frame_t>::iterator i2;
Chris@399 1331 if (snapFrames.find(frame) == snapFrames.end()) {
matthiasm@281 1332 // we're not on an existing snap point, so go to previous
matthiasm@281 1333 snapFrames.insert(frame);
matthiasm@281 1334 }
matthiasm@281 1335 i2 = snapFrames.find(frame);
Chris@399 1336 if (right) {
matthiasm@281 1337 i2++;
matthiasm@281 1338 if (i2 == snapFrames.end()) i2--;
matthiasm@281 1339 } else {
matthiasm@281 1340 if (i2 != snapFrames.begin()) i2--;
matthiasm@281 1341 }
matthiasm@281 1342 frame = *i2;
matthiasm@281 1343 m_viewManager->setPlaybackFrame(frame);
matthiasm@296 1344 if (doSelect) {
matthiasm@296 1345 Selection sel;
matthiasm@296 1346 if (frame > m_selectionAnchor) {
matthiasm@342 1347 sel = Selection(m_selectionAnchor, frame);
matthiasm@296 1348 } else {
matthiasm@342 1349 sel = Selection(frame, m_selectionAnchor);
matthiasm@296 1350 }
matthiasm@296 1351 m_viewManager->setSelection(sel);
matthiasm@296 1352 }
matthiasm@301 1353 cerr << "MainWindow::moveByOneNote endframe: " << frame << endl;
matthiasm@281 1354 }
matthiasm@281 1355
Chris@0 1356 void
Chris@70 1357 MainWindow::toolNavigateSelected()
Chris@70 1358 {
Chris@70 1359 m_viewManager->setToolMode(ViewManager::NavigateMode);
Chris@70 1360 m_intelligentActionOn = true;
Chris@70 1361 }
Chris@70 1362
Chris@70 1363 void
Chris@70 1364 MainWindow::toolEditSelected()
Chris@70 1365 {
matthiasm@294 1366 cerr << "MainWindow::toolEditSelected" << endl;
Chris@77 1367 m_viewManager->setToolMode(ViewManager::NoteEditMode);
Chris@70 1368 m_intelligentActionOn = true;
Chris@70 1369 m_analyser->setIntelligentActions(m_intelligentActionOn);
Chris@70 1370 }
Chris@70 1371
Chris@70 1372 void
Chris@70 1373 MainWindow::toolFreeEditSelected()
Chris@70 1374 {
Chris@77 1375 m_viewManager->setToolMode(ViewManager::NoteEditMode);
Chris@70 1376 m_intelligentActionOn = false;
Chris@70 1377 m_analyser->setIntelligentActions(m_intelligentActionOn);
Chris@70 1378 }
Chris@70 1379
gyorgyf@21 1380 void
Chris@0 1381 MainWindow::updateMenuStates()
Chris@0 1382 {
Chris@0 1383 MainWindowBase::updateMenuStates();
Chris@0 1384
Chris@0 1385 Pane *currentPane = 0;
Chris@0 1386 Layer *currentLayer = 0;
Chris@0 1387
Chris@0 1388 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
Chris@0 1389 if (currentPane) currentLayer = currentPane->getSelectedLayer();
Chris@0 1390
Chris@291 1391 bool haveMainModel =
Chris@291 1392 (getMainModel() != 0);
Chris@291 1393 bool havePlayTarget =
Chris@479 1394 (m_playTarget != 0 || m_audioIO != 0);
Chris@0 1395 bool haveCurrentPane =
Chris@0 1396 (currentPane != 0);
Chris@0 1397 bool haveCurrentLayer =
Chris@0 1398 (haveCurrentPane &&
Chris@0 1399 (currentLayer != 0));
Chris@0 1400 bool haveSelection =
Chris@187 1401 (m_viewManager &&
Chris@187 1402 !m_viewManager->getSelections().empty());
Chris@0 1403 bool haveCurrentTimeInstantsLayer =
Chris@187 1404 (haveCurrentLayer &&
Chris@187 1405 qobject_cast<TimeInstantLayer *>(currentLayer));
Chris@0 1406 bool haveCurrentTimeValueLayer =
Chris@187 1407 (haveCurrentLayer &&
Chris@187 1408 qobject_cast<TimeValueLayer *>(currentLayer));
Chris@187 1409 bool pitchCandidatesVisible =
Chris@187 1410 m_analyser->arePitchCandidatesShown();
Chris@0 1411
Chris@0 1412 emit canChangePlaybackSpeed(true);
Chris@0 1413 int v = m_playSpeed->value();
Chris@0 1414 emit canSpeedUpPlayback(v < m_playSpeed->maximum());
Chris@0 1415 emit canSlowDownPlayback(v > m_playSpeed->minimum());
Chris@0 1416
Chris@291 1417 bool haveWaveform =
Chris@291 1418 m_analyser->isVisible(Analyser::Audio) &&
Chris@291 1419 m_analyser->getLayer(Analyser::Audio);
Chris@291 1420
Chris@237 1421 bool havePitchTrack =
Chris@237 1422 m_analyser->isVisible(Analyser::PitchTrack) &&
Chris@237 1423 m_analyser->getLayer(Analyser::PitchTrack);
Chris@237 1424
Chris@237 1425 bool haveNotes =
Chris@237 1426 m_analyser->isVisible(Analyser::Notes) &&
Chris@237 1427 m_analyser->getLayer(Analyser::Notes);
Chris@237 1428
Chris@237 1429 emit canExportPitchTrack(havePitchTrack);
Chris@237 1430 emit canExportNotes(haveNotes);
Chris@237 1431 emit canSnapNotes(haveSelection && haveNotes);
Chris@224 1432
Chris@291 1433 emit canPlayWaveform(haveWaveform && haveMainModel && havePlayTarget);
Chris@291 1434 emit canPlayPitch(havePitchTrack && haveMainModel && havePlayTarget);
Chris@291 1435 emit canPlayNotes(haveNotes && haveMainModel && havePlayTarget);
Chris@291 1436
Chris@187 1437 if (pitchCandidatesVisible) {
Chris@187 1438 m_showCandidatesAction->setText(tr("Hide Pitch Candidates"));
Chris@187 1439 m_showCandidatesAction->setStatusTip(tr("Remove the display of alternate pitch candidates for the selected region"));
Chris@187 1440 } else {
Chris@187 1441 m_showCandidatesAction->setText(tr("Show Pitch Candidates"));
Chris@187 1442 m_showCandidatesAction->setStatusTip(tr("Show alternate pitch candidates for the selected region"));
Chris@187 1443 }
Chris@187 1444
Chris@0 1445 if (m_ffwdAction && m_rwdAction) {
Chris@0 1446 if (haveCurrentTimeInstantsLayer) {
Chris@0 1447 m_ffwdAction->setText(tr("Fast Forward to Next Instant"));
Chris@0 1448 m_ffwdAction->setStatusTip(tr("Fast forward to the next time instant in the current layer"));
Chris@0 1449 m_rwdAction->setText(tr("Rewind to Previous Instant"));
Chris@0 1450 m_rwdAction->setStatusTip(tr("Rewind to the previous time instant in the current layer"));
Chris@0 1451 } else if (haveCurrentTimeValueLayer) {
Chris@0 1452 m_ffwdAction->setText(tr("Fast Forward to Next Point"));
Chris@0 1453 m_ffwdAction->setStatusTip(tr("Fast forward to the next point in the current layer"));
Chris@0 1454 m_rwdAction->setText(tr("Rewind to Previous Point"));
Chris@0 1455 m_rwdAction->setStatusTip(tr("Rewind to the previous point in the current layer"));
Chris@0 1456 } else {
Chris@0 1457 m_ffwdAction->setText(tr("Fast Forward"));
Chris@0 1458 m_ffwdAction->setStatusTip(tr("Fast forward"));
Chris@0 1459 m_rwdAction->setText(tr("Rewind"));
Chris@0 1460 m_rwdAction->setStatusTip(tr("Rewind"));
Chris@0 1461 }
Chris@0 1462 }
Chris@0 1463 }
Chris@0 1464
Chris@0 1465 void
Chris@144 1466 MainWindow::showAudioToggled()
Chris@128 1467 {
Chris@144 1468 m_analyser->toggleVisible(Analyser::Audio);
justin@220 1469
Chris@424 1470 QSettings settings;
Chris@424 1471 settings.beginGroup("MainWindow");
Chris@424 1472
Chris@424 1473 bool playOn = false;
Chris@424 1474 if (m_analyser->isVisible(Analyser::Audio)) {
Chris@424 1475 // just switched layer on; check whether playback was also on previously
Chris@424 1476 playOn = settings.value("playaudiowas", true).toBool();
Chris@424 1477 } else {
Chris@424 1478 settings.setValue("playaudiowas", m_playAudio->isChecked());
Chris@424 1479 }
Chris@291 1480 m_analyser->setAudible(Analyser::Audio, playOn);
Chris@424 1481
Chris@424 1482 settings.endGroup();
Chris@291 1483
Chris@291 1484 updateMenuStates();
Chris@424 1485 updateLayerStatuses();
Chris@128 1486 }
Chris@128 1487
Chris@128 1488 void
Chris@144 1489 MainWindow::showPitchToggled()
Chris@128 1490 {
Chris@144 1491 m_analyser->toggleVisible(Analyser::PitchTrack);
justin@185 1492
Chris@424 1493 QSettings settings;
Chris@424 1494 settings.beginGroup("MainWindow");
Chris@424 1495
Chris@424 1496 bool playOn = false;
Chris@424 1497 if (m_analyser->isVisible(Analyser::PitchTrack)) {
Chris@424 1498 // just switched layer on; check whether playback was also on previously
Chris@424 1499 playOn = settings.value("playpitchwas", true).toBool();
Chris@424 1500 } else {
Chris@424 1501 settings.setValue("playpitchwas", m_playPitch->isChecked());
Chris@424 1502 }
Chris@424 1503 m_analyser->setAudible(Analyser::PitchTrack, playOn);
Chris@424 1504
Chris@424 1505 settings.endGroup();
Chris@291 1506
Chris@291 1507 updateMenuStates();
Chris@424 1508 updateLayerStatuses();
Chris@128 1509 }
Chris@128 1510
Chris@128 1511 void
Chris@145 1512 MainWindow::showSpectToggled()
Chris@145 1513 {
Chris@145 1514 m_analyser->toggleVisible(Analyser::Spectrogram);
Chris@145 1515 }
Chris@145 1516
Chris@145 1517 void
Chris@144 1518 MainWindow::showNotesToggled()
Chris@128 1519 {
Chris@144 1520 m_analyser->toggleVisible(Analyser::Notes);
justin@220 1521
Chris@424 1522 QSettings settings;
Chris@424 1523 settings.beginGroup("MainWindow");
Chris@424 1524
Chris@424 1525 bool playOn = false;
Chris@424 1526 if (m_analyser->isVisible(Analyser::Notes)) {
Chris@424 1527 // just switched layer on; check whether playback was also on previously
Chris@424 1528 playOn = settings.value("playnoteswas", true).toBool();
Chris@424 1529 } else {
Chris@424 1530 settings.setValue("playnoteswas", m_playNotes->isChecked());
Chris@424 1531 }
Chris@424 1532 m_analyser->setAudible(Analyser::Notes, playOn);
Chris@424 1533
Chris@424 1534 settings.endGroup();
Chris@291 1535
Chris@291 1536 updateMenuStates();
Chris@424 1537 updateLayerStatuses();
Chris@144 1538 }
Chris@144 1539
Chris@144 1540 void
Chris@144 1541 MainWindow::playAudioToggled()
Chris@144 1542 {
Chris@144 1543 m_analyser->toggleAudible(Analyser::Audio);
Chris@424 1544 updateLayerStatuses();
Chris@144 1545 }
Chris@144 1546
Chris@144 1547 void
Chris@144 1548 MainWindow::playPitchToggled()
Chris@144 1549 {
Chris@144 1550 m_analyser->toggleAudible(Analyser::PitchTrack);
Chris@424 1551 updateLayerStatuses();
Chris@144 1552 }
Chris@144 1553
Chris@144 1554 void
Chris@144 1555 MainWindow::playNotesToggled()
Chris@144 1556 {
Chris@144 1557 m_analyser->toggleAudible(Analyser::Notes);
Chris@424 1558 updateLayerStatuses();
Chris@144 1559 }
Chris@144 1560
Chris@144 1561 void
Chris@144 1562 MainWindow::updateLayerStatuses()
Chris@144 1563 {
Chris@144 1564 m_showAudio->setChecked(m_analyser->isVisible(Analyser::Audio));
Chris@424 1565 m_playAudio->setChecked(m_analyser->isAudible(Analyser::Audio));
Chris@424 1566 m_audioLPW->setEnabled(m_analyser->isAudible(Analyser::Audio));
Chris@405 1567 m_audioLPW->setLevel(m_analyser->getGain(Analyser::Audio));
Chris@405 1568 m_audioLPW->setPan(m_analyser->getPan(Analyser::Audio));
Chris@424 1569
Chris@405 1570 m_showPitch->setChecked(m_analyser->isVisible(Analyser::PitchTrack));
Chris@424 1571 m_playPitch->setChecked(m_analyser->isAudible(Analyser::PitchTrack));
Chris@424 1572 m_pitchLPW->setEnabled(m_analyser->isAudible(Analyser::PitchTrack));
Chris@405 1573 m_pitchLPW->setLevel(m_analyser->getGain(Analyser::PitchTrack));
Chris@405 1574 m_pitchLPW->setPan(m_analyser->getPan(Analyser::PitchTrack));
Chris@405 1575
Chris@405 1576 m_showNotes->setChecked(m_analyser->isVisible(Analyser::Notes));
Chris@424 1577 m_playNotes->setChecked(m_analyser->isAudible(Analyser::Notes));
Chris@424 1578 m_notesLPW->setEnabled(m_analyser->isAudible(Analyser::Notes));
Chris@405 1579 m_notesLPW->setLevel(m_analyser->getGain(Analyser::Notes));
Chris@405 1580 m_notesLPW->setPan(m_analyser->getPan(Analyser::Notes));
Chris@405 1581
Chris@145 1582 m_showSpect->setChecked(m_analyser->isVisible(Analyser::Spectrogram));
Chris@128 1583 }
Chris@128 1584
Chris@128 1585 void
Chris@227 1586 MainWindow::editDisplayExtents()
Chris@227 1587 {
Chris@399 1588 double min, max;
Chris@399 1589 double vmin = 0;
Chris@399 1590 double vmax = getMainModel()->getSampleRate() /2;
Chris@227 1591
Chris@227 1592 if (!m_analyser->getDisplayFrequencyExtents(min, max)) {
Chris@227 1593 //!!!
Chris@227 1594 return;
Chris@227 1595 }
Chris@227 1596
Chris@227 1597 RangeInputDialog dialog(tr("Set frequency range"),
Chris@227 1598 tr("Enter new frequency range, from %1 to %2 Hz.\nThese values will be rounded to the nearest spectrogram bin.")
Chris@227 1599 .arg(vmin).arg(vmax),
Chris@399 1600 "Hz", float(vmin), float(vmax), this);
Chris@399 1601 dialog.setRange(float(min), float(max));
Chris@227 1602
Chris@227 1603 if (dialog.exec() == QDialog::Accepted) {
Chris@399 1604 float fmin, fmax;
Chris@399 1605 dialog.getRange(fmin, fmax);
Chris@399 1606 min = fmin;
Chris@399 1607 max = fmax;
Chris@227 1608 if (min > max) {
Chris@399 1609 double tmp = max;
Chris@227 1610 max = min;
Chris@227 1611 min = tmp;
Chris@227 1612 }
Chris@227 1613 m_analyser->setDisplayFrequencyExtents(min, max);
Chris@227 1614 }
Chris@227 1615 }
Chris@227 1616
Chris@227 1617 void
Chris@0 1618 MainWindow::updateDescriptionLabel()
Chris@0 1619 {
Chris@6 1620 // Nothing, we don't have one
Chris@0 1621 }
Chris@0 1622
Chris@0 1623 void
Chris@0 1624 MainWindow::documentModified()
Chris@0 1625 {
Chris@0 1626 MainWindowBase::documentModified();
Chris@0 1627 }
Chris@0 1628
Chris@0 1629 void
Chris@0 1630 MainWindow::documentRestored()
Chris@0 1631 {
Chris@0 1632 MainWindowBase::documentRestored();
Chris@0 1633 }
Chris@0 1634
Chris@0 1635 void
Chris@0 1636 MainWindow::newSession()
Chris@0 1637 {
Chris@0 1638 if (!checkSaveModified()) return;
Chris@0 1639
Chris@0 1640 closeSession();
Chris@0 1641 createDocument();
Chris@0 1642 m_document->setAutoAlignment(true);
Chris@0 1643
Chris@0 1644 Pane *pane = m_paneStack->addPane();
Chris@362 1645 pane->setPlaybackFollow(PlaybackScrollPage);
Chris@0 1646
Chris@391 1647 m_viewManager->setGlobalCentreFrame
Chris@391 1648 (pane->getFrameForX(width() / 2));
Chris@391 1649
Chris@0 1650 connect(pane, SIGNAL(contextHelpChanged(const QString &)),
Chris@0 1651 this, SLOT(contextHelpChanged(const QString &)));
Chris@0 1652
Chris@6 1653 // Layer *waveform = m_document->createMainModelLayer(LayerFactory::Waveform);
Chris@6 1654 // m_document->addLayerToView(pane, waveform);
Chris@0 1655
Chris@0 1656 m_overview->registerView(pane);
Chris@0 1657
Chris@0 1658 CommandHistory::getInstance()->clear();
Chris@0 1659 CommandHistory::getInstance()->documentSaved();
Chris@0 1660 documentRestored();
Chris@0 1661 updateMenuStates();
Chris@0 1662 }
Chris@0 1663
Chris@0 1664 void
Chris@244 1665 MainWindow::documentReplaced()
Chris@244 1666 {
Chris@244 1667 if (m_document) {
Chris@244 1668 connect(m_document, SIGNAL(activity(QString)),
Chris@244 1669 m_activityLog, SLOT(activityHappened(QString)));
Chris@244 1670 }
Chris@244 1671 }
Chris@244 1672
Chris@244 1673 void
Chris@0 1674 MainWindow::closeSession()
Chris@0 1675 {
Chris@0 1676 if (!checkSaveModified()) return;
Chris@0 1677
Chris@226 1678 m_analyser->fileClosed();
Chris@226 1679
Chris@0 1680 while (m_paneStack->getPaneCount() > 0) {
Chris@0 1681
Chris@167 1682 Pane *pane = m_paneStack->getPane(m_paneStack->getPaneCount() - 1);
Chris@0 1683
Chris@167 1684 while (pane->getLayerCount() > 0) {
Chris@167 1685 m_document->removeLayerFromView
Chris@167 1686 (pane, pane->getLayer(pane->getLayerCount() - 1));
Chris@167 1687 }
Chris@167 1688
Chris@167 1689 m_overview->unregisterView(pane);
Chris@167 1690 m_paneStack->deletePane(pane);
Chris@0 1691 }
Chris@0 1692
Chris@0 1693 while (m_paneStack->getHiddenPaneCount() > 0) {
Chris@0 1694
Chris@167 1695 Pane *pane = m_paneStack->getHiddenPane
Chris@167 1696 (m_paneStack->getHiddenPaneCount() - 1);
Chris@167 1697
Chris@167 1698 while (pane->getLayerCount() > 0) {
Chris@167 1699 m_document->removeLayerFromView
Chris@167 1700 (pane, pane->getLayer(pane->getLayerCount() - 1));
Chris@167 1701 }
Chris@167 1702
Chris@167 1703 m_overview->unregisterView(pane);
Chris@167 1704 m_paneStack->deletePane(pane);
Chris@0 1705 }
Chris@0 1706
Chris@0 1707 delete m_document;
Chris@0 1708 m_document = 0;
Chris@0 1709 m_viewManager->clearSelections();
Chris@0 1710 m_timeRulerLayer = 0; // document owned this
Chris@0 1711
Chris@0 1712 m_sessionFile = "";
Chris@0 1713
Chris@0 1714 CommandHistory::getInstance()->clear();
Chris@0 1715 CommandHistory::getInstance()->documentSaved();
Chris@0 1716 documentRestored();
Chris@0 1717 }
Chris@0 1718
Chris@0 1719 void
Chris@0 1720 MainWindow::openFile()
Chris@0 1721 {
Chris@0 1722 QString orig = m_audioFile;
Chris@0 1723 if (orig == "") orig = ".";
Chris@0 1724 else orig = QFileInfo(orig).absoluteDir().canonicalPath();
Chris@0 1725
Chris@0 1726 QString path = getOpenFileName(FileFinder::AnyFile);
Chris@0 1727
Chris@0 1728 if (path.isEmpty()) return;
Chris@0 1729
Chris@387 1730 FileOpenStatus status = openPath(path, ReplaceSession);
Chris@0 1731
Chris@0 1732 if (status == FileOpenFailed) {
Chris@0 1733 QMessageBox::critical(this, tr("Failed to open file"),
Chris@0 1734 tr("<b>File open failed</b><p>File \"%1\" could not be opened").arg(path));
Chris@0 1735 } else if (status == FileOpenWrongMode) {
Chris@0 1736 QMessageBox::critical(this, tr("Failed to open file"),
Chris@0 1737 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@0 1738 }
Chris@0 1739 }
Chris@0 1740
Chris@0 1741 void
Chris@0 1742 MainWindow::openLocation()
Chris@0 1743 {
Chris@0 1744 QSettings settings;
Chris@0 1745 settings.beginGroup("MainWindow");
Chris@0 1746 QString lastLocation = settings.value("lastremote", "").toString();
Chris@0 1747
Chris@0 1748 bool ok = false;
Chris@0 1749 QString text = QInputDialog::getText
Chris@0 1750 (this, tr("Open Location"),
Chris@0 1751 tr("Please enter the URL of the location to open:"),
Chris@0 1752 QLineEdit::Normal, lastLocation, &ok);
Chris@0 1753
Chris@0 1754 if (!ok) return;
Chris@0 1755
Chris@0 1756 settings.setValue("lastremote", text);
Chris@0 1757
Chris@0 1758 if (text.isEmpty()) return;
Chris@0 1759
Chris@387 1760 FileOpenStatus status = openPath(text, ReplaceSession);
Chris@0 1761
Chris@0 1762 if (status == FileOpenFailed) {
Chris@0 1763 QMessageBox::critical(this, tr("Failed to open location"),
Chris@0 1764 tr("<b>Open failed</b><p>URL \"%1\" could not be opened").arg(text));
Chris@0 1765 } else if (status == FileOpenWrongMode) {
Chris@0 1766 QMessageBox::critical(this, tr("Failed to open location"),
Chris@0 1767 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@0 1768 }
Chris@0 1769 }
Chris@0 1770
Chris@0 1771 void
Chris@0 1772 MainWindow::openRecentFile()
Chris@0 1773 {
Chris@0 1774 QObject *obj = sender();
Chris@3 1775 QAction *action = qobject_cast<QAction *>(obj);
Chris@0 1776
Chris@0 1777 if (!action) {
Chris@188 1778 cerr << "WARNING: MainWindow::openRecentFile: sender is not an action"
Chris@188 1779 << endl;
Chris@188 1780 return;
Chris@0 1781 }
Chris@0 1782
Chris@0 1783 QString path = action->text();
Chris@0 1784 if (path == "") return;
Chris@0 1785
Chris@387 1786 FileOpenStatus status = openPath(path, ReplaceSession);
Chris@0 1787
Chris@0 1788 if (status == FileOpenFailed) {
Chris@0 1789 QMessageBox::critical(this, tr("Failed to open location"),
Chris@0 1790 tr("<b>Open failed</b><p>File or URL \"%1\" could not be opened").arg(path));
Chris@0 1791 } else if (status == FileOpenWrongMode) {
Chris@0 1792 QMessageBox::critical(this, tr("Failed to open location"),
Chris@0 1793 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@0 1794 }
Chris@0 1795 }
Chris@0 1796
Chris@0 1797 void
Chris@0 1798 MainWindow::paneAdded(Pane *pane)
Chris@0 1799 {
Chris@6 1800 pane->setPlaybackFollow(PlaybackScrollPage);
Chris@0 1801 m_paneStack->sizePanesEqually();
Chris@0 1802 if (m_overview) m_overview->registerView(pane);
Chris@0 1803 }
Chris@0 1804
Chris@0 1805 void
Chris@0 1806 MainWindow::paneHidden(Pane *pane)
Chris@0 1807 {
Chris@0 1808 if (m_overview) m_overview->unregisterView(pane);
Chris@0 1809 }
Chris@0 1810
Chris@0 1811 void
Chris@0 1812 MainWindow::paneAboutToBeDeleted(Pane *pane)
Chris@0 1813 {
Chris@0 1814 if (m_overview) m_overview->unregisterView(pane);
Chris@0 1815 }
Chris@0 1816
Chris@0 1817 void
Chris@0 1818 MainWindow::paneDropAccepted(Pane *pane, QStringList uriList)
Chris@0 1819 {
Chris@4 1820 if (pane) m_paneStack->setCurrentPane(pane);
Chris@0 1821
Chris@0 1822 for (QStringList::iterator i = uriList.begin(); i != uriList.end(); ++i) {
Chris@0 1823
Chris@387 1824 FileOpenStatus status = openPath(*i, ReplaceSession);
Chris@0 1825
Chris@0 1826 if (status == FileOpenFailed) {
Chris@0 1827 QMessageBox::critical(this, tr("Failed to open dropped URL"),
Chris@0 1828 tr("<b>Open failed</b><p>Dropped URL \"%1\" could not be opened").arg(*i));
Chris@0 1829 } else if (status == FileOpenWrongMode) {
Chris@0 1830 QMessageBox::critical(this, tr("Failed to open dropped URL"),
Chris@0 1831 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@0 1832 }
Chris@0 1833 }
Chris@0 1834 }
Chris@0 1835
Chris@0 1836 void
Chris@0 1837 MainWindow::paneDropAccepted(Pane *pane, QString text)
Chris@0 1838 {
Chris@0 1839 if (pane) m_paneStack->setCurrentPane(pane);
Chris@0 1840
Chris@0 1841 QUrl testUrl(text);
Chris@0 1842 if (testUrl.scheme() == "file" ||
Chris@0 1843 testUrl.scheme() == "http" ||
Chris@0 1844 testUrl.scheme() == "ftp") {
Chris@0 1845 QStringList list;
Chris@0 1846 list.push_back(text);
Chris@0 1847 paneDropAccepted(pane, list);
Chris@0 1848 return;
Chris@0 1849 }
Chris@0 1850
Chris@0 1851 //!!! open as text -- but by importing as if a CSV, or just adding
Chris@0 1852 //to a text layer?
Chris@0 1853 }
Chris@0 1854
Chris@0 1855 void
Chris@0 1856 MainWindow::closeEvent(QCloseEvent *e)
Chris@0 1857 {
Chris@70 1858 // cerr << "MainWindow::closeEvent" << endl;
Chris@0 1859
Chris@0 1860 if (m_openingAudioFile) {
Chris@70 1861 // cerr << "Busy - ignoring close event" << endl;
Chris@257 1862 e->ignore();
Chris@257 1863 return;
Chris@0 1864 }
Chris@0 1865
Chris@0 1866 if (!m_abandoning && !checkSaveModified()) {
Chris@70 1867 // cerr << "Ignoring close event" << endl;
Chris@257 1868 e->ignore();
Chris@257 1869 return;
Chris@0 1870 }
Chris@0 1871
Chris@0 1872 QSettings settings;
Chris@0 1873 settings.beginGroup("MainWindow");
Chris@0 1874 settings.setValue("size", size());
Chris@0 1875 settings.setValue("position", pos());
Chris@0 1876 settings.endGroup();
Chris@0 1877
Chris@0 1878 delete m_keyReference;
Chris@0 1879 m_keyReference = 0;
Chris@0 1880
Chris@0 1881 closeSession();
Chris@0 1882
Chris@0 1883 e->accept();
Chris@0 1884 return;
Chris@0 1885 }
Chris@0 1886
Chris@0 1887 bool
Chris@0 1888 MainWindow::commitData(bool mayAskUser)
Chris@0 1889 {
Chris@0 1890 if (mayAskUser) {
Chris@0 1891 bool rv = checkSaveModified();
Chris@0 1892 return rv;
Chris@0 1893 } else {
Chris@0 1894 if (!m_documentModified) return true;
Chris@0 1895
Chris@0 1896 // If we can't check with the user first, then we can't save
Chris@0 1897 // to the original session file (even if we have it) -- have
Chris@0 1898 // to use a temporary file
Chris@0 1899
Chris@0 1900 QString svDirBase = ".sv1";
Chris@0 1901 QString svDir = QDir::home().filePath(svDirBase);
Chris@0 1902
Chris@0 1903 if (!QFileInfo(svDir).exists()) {
Chris@0 1904 if (!QDir::home().mkdir(svDirBase)) return false;
Chris@0 1905 } else {
Chris@0 1906 if (!QFileInfo(svDir).isDir()) return false;
Chris@0 1907 }
Chris@0 1908
Chris@0 1909 // This name doesn't have to be unguessable
Chris@0 1910 #ifndef _WIN32
Chris@0 1911 QString fname = QString("tmp-%1-%2.sv")
Chris@0 1912 .arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"))
Chris@0 1913 .arg(QProcess().pid());
Chris@0 1914 #else
Chris@0 1915 QString fname = QString("tmp-%1.sv")
Chris@0 1916 .arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"));
Chris@0 1917 #endif
Chris@0 1918 QString fpath = QDir(svDir).filePath(fname);
Chris@0 1919 if (saveSessionFile(fpath)) {
Chris@0 1920 m_recentFiles.addFile(fpath);
Chris@0 1921 return true;
Chris@0 1922 } else {
Chris@0 1923 return false;
Chris@0 1924 }
Chris@0 1925 }
Chris@0 1926 }
Chris@0 1927
Chris@0 1928 bool
Chris@0 1929 MainWindow::checkSaveModified()
Chris@0 1930 {
Chris@0 1931 // Called before some destructive operation (e.g. new session,
Chris@0 1932 // exit program). Return true if we can safely proceed, false to
Chris@0 1933 // cancel.
Chris@0 1934
Chris@0 1935 if (!m_documentModified) return true;
Chris@0 1936
Chris@0 1937 int button =
Chris@257 1938 QMessageBox::warning(this,
Chris@257 1939 tr("Session modified"),
Chris@257 1940 tr("The current session has been modified.\nDo you want to save it?"),
Chris@257 1941 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
Chris@0 1942 QMessageBox::Yes);
Chris@0 1943
Chris@0 1944 if (button == QMessageBox::Yes) {
Chris@257 1945 saveSession();
Chris@257 1946 if (m_documentModified) { // save failed -- don't proceed!
Chris@257 1947 return false;
Chris@257 1948 } else {
Chris@0 1949 return true; // saved, so it's safe to continue now
Chris@0 1950 }
Chris@0 1951 } else if (button == QMessageBox::No) {
Chris@257 1952 m_documentModified = false; // so we know to abandon it
Chris@257 1953 return true;
Chris@0 1954 }
Chris@0 1955
Chris@0 1956 // else cancel
Chris@0 1957 return false;
Chris@0 1958 }
Chris@0 1959
Chris@314 1960 bool
Chris@314 1961 MainWindow::waitForInitialAnalysis()
Chris@314 1962 {
Chris@314 1963 // Called before saving a session. We can't safely save while the
Chris@314 1964 // initial analysis is happening, because then we end up with an
Chris@314 1965 // incomplete session on reload. There are certainly theoretically
Chris@314 1966 // better ways to handle this...
Chris@314 1967
Chris@330 1968 QSettings settings;
Chris@330 1969 settings.beginGroup("Analyser");
Chris@330 1970 bool autoAnalyse = settings.value("auto-analysis", true).toBool();
Chris@330 1971 settings.endGroup();
Chris@330 1972
Chris@330 1973 if (!autoAnalyse) {
Chris@330 1974 return true;
Chris@330 1975 }
Chris@330 1976
Chris@314 1977 if (!m_analyser || m_analyser->getInitialAnalysisCompletion() >= 100) {
Chris@314 1978 return true;
Chris@314 1979 }
Chris@314 1980
Chris@314 1981 QMessageBox mb(QMessageBox::Information,
Chris@314 1982 tr("Waiting for analysis"),
Chris@442 1983 tr("Waiting for initial analysis to finish before loading or saving..."),
Chris@314 1984 QMessageBox::Cancel,
Chris@314 1985 this);
Chris@314 1986
Chris@314 1987 connect(m_analyser, SIGNAL(initialAnalysisCompleted()),
Chris@314 1988 &mb, SLOT(accept()));
Chris@314 1989
Chris@314 1990 if (mb.exec() == QDialog::Accepted) {
Chris@314 1991 return true;
Chris@314 1992 } else {
Chris@314 1993 return false;
Chris@314 1994 }
Chris@314 1995 }
Chris@314 1996
Chris@0 1997 void
Chris@0 1998 MainWindow::saveSession()
Chris@0 1999 {
Chris@269 2000 // We do not want to save mid-analysis regions -- that would cause
Chris@269 2001 // confusion on reloading
Chris@269 2002 m_analyser->clearReAnalysis();
Chris@269 2003 clearSelection();
Chris@269 2004
Chris@0 2005 if (m_sessionFile != "") {
Chris@257 2006 if (!saveSessionFile(m_sessionFile)) {
Chris@257 2007 QMessageBox::critical
Chris@257 2008 (this, tr("Failed to save file"),
Chris@257 2009 tr("Session file \"%1\" could not be saved.").arg(m_sessionFile));
Chris@257 2010 } else {
Chris@257 2011 CommandHistory::getInstance()->documentSaved();
Chris@257 2012 documentRestored();
Chris@257 2013 }
Chris@0 2014 } else {
Chris@257 2015 saveSessionAs();
Chris@0 2016 }
Chris@0 2017 }
Chris@0 2018
Chris@0 2019 void
matthiasm@310 2020 MainWindow::saveSessionInAudioPath()
matthiasm@310 2021 {
matthiasm@311 2022 if (m_audioFile == "") return;
matthiasm@311 2023
Chris@314 2024 if (!waitForInitialAnalysis()) return;
Chris@314 2025
matthiasm@310 2026 // We do not want to save mid-analysis regions -- that would cause
matthiasm@310 2027 // confusion on reloading
matthiasm@310 2028 m_analyser->clearReAnalysis();
matthiasm@310 2029 clearSelection();
matthiasm@310 2030
matthiasm@310 2031 QString filepath = QFileInfo(m_audioFile).absoluteDir().canonicalPath();
matthiasm@310 2032 QString basename = QFileInfo(m_audioFile).completeBaseName();
matthiasm@310 2033
matthiasm@310 2034 QString path = QDir(filepath).filePath(basename + ".ton");
matthiasm@310 2035
matthiasm@310 2036 cerr << path << endl;
matthiasm@310 2037
Chris@313 2038 // We don't want to overwrite an existing .ton file unless we put
Chris@313 2039 // it there in the first place
Chris@313 2040 bool shouldVerify = true;
Chris@313 2041 if (m_sessionFile == path) {
Chris@313 2042 shouldVerify = false;
Chris@313 2043 }
Chris@313 2044
Chris@313 2045 if (shouldVerify && QFileInfo(path).exists()) {
Chris@313 2046 if (QMessageBox::question(0, tr("File exists"),
Chris@313 2047 tr("<b>File exists</b><p>The file \"%1\" already exists.\nDo you want to overwrite it?").arg(path),
Chris@313 2048 QMessageBox::Ok,
Chris@313 2049 QMessageBox::Cancel) != QMessageBox::Ok) {
Chris@313 2050 return;
Chris@313 2051 }
Chris@313 2052 }
Chris@313 2053
Chris@314 2054 if (!waitForInitialAnalysis()) {
Chris@314 2055 QMessageBox::warning(this, tr("File not saved"),
Chris@314 2056 tr("Wait cancelled: the session has not been saved."));
Chris@314 2057 }
Chris@314 2058
matthiasm@310 2059 if (!saveSessionFile(path)) {
matthiasm@310 2060 QMessageBox::critical(this, tr("Failed to save file"),
matthiasm@310 2061 tr("Session file \"%1\" could not be saved.").arg(path));
matthiasm@310 2062 } else {
matthiasm@310 2063 setWindowTitle(tr("%1: %2")
matthiasm@310 2064 .arg(QApplication::applicationName())
matthiasm@310 2065 .arg(QFileInfo(path).fileName()));
matthiasm@310 2066 m_sessionFile = path;
matthiasm@310 2067 CommandHistory::getInstance()->documentSaved();
matthiasm@310 2068 documentRestored();
matthiasm@310 2069 m_recentFiles.addFile(path);
matthiasm@310 2070 }
matthiasm@310 2071 }
matthiasm@310 2072
matthiasm@310 2073 void
Chris@0 2074 MainWindow::saveSessionAs()
Chris@0 2075 {
Chris@270 2076 // We do not want to save mid-analysis regions -- that would cause
Chris@270 2077 // confusion on reloading
Chris@270 2078 m_analyser->clearReAnalysis();
Chris@270 2079 clearSelection();
Chris@270 2080
Chris@0 2081 QString path = getSaveFileName(FileFinder::SessionFile);
Chris@0 2082
Chris@309 2083 if (path == "") {
Chris@309 2084 return;
Chris@309 2085 }
Chris@0 2086
Chris@314 2087 if (!waitForInitialAnalysis()) {
Chris@314 2088 QMessageBox::warning(this, tr("File not saved"),
Chris@314 2089 tr("Wait cancelled: the session has not been saved."));
Chris@314 2090 return;
Chris@314 2091 }
Chris@314 2092
Chris@0 2093 if (!saveSessionFile(path)) {
Chris@85 2094 QMessageBox::critical(this, tr("Failed to save file"),
Chris@85 2095 tr("Session file \"%1\" could not be saved.").arg(path));
Chris@0 2096 } else {
Chris@85 2097 setWindowTitle(tr("%1: %2")
Chris@0 2098 .arg(QApplication::applicationName())
Chris@85 2099 .arg(QFileInfo(path).fileName()));
Chris@85 2100 m_sessionFile = path;
Chris@85 2101 CommandHistory::getInstance()->documentSaved();
Chris@85 2102 documentRestored();
Chris@0 2103 m_recentFiles.addFile(path);
Chris@0 2104 }
Chris@0 2105 }
Chris@0 2106
Chris@85 2107 QString
Chris@85 2108 MainWindow::exportToSVL(QString path, Layer *layer)
Chris@85 2109 {
Chris@85 2110 Model *model = layer->getModel();
Chris@85 2111
Chris@85 2112 QFile file(path);
Chris@85 2113 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
Chris@85 2114 return tr("Failed to open file %1 for writing").arg(path);
Chris@85 2115 } else {
Chris@85 2116 QTextStream out(&file);
Chris@85 2117 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
Chris@85 2118 << "<!DOCTYPE sonic-visualiser>\n"
Chris@85 2119 << "<sv>\n"
Chris@85 2120 << " <data>\n";
Chris@85 2121
Chris@85 2122 model->toXml(out, " ");
Chris@85 2123
Chris@85 2124 out << " </data>\n"
Chris@85 2125 << " <display>\n";
Chris@85 2126
Chris@85 2127 layer->toXml(out, " ");
Chris@85 2128
Chris@85 2129 out << " </display>\n"
Chris@85 2130 << "</sv>\n";
Chris@85 2131
Chris@85 2132 return "";
Chris@85 2133 }
Chris@85 2134 }
Chris@85 2135
Chris@0 2136 void
Chris@174 2137 MainWindow::importPitchLayer()
Chris@174 2138 {
Chris@174 2139 QString path = getOpenFileName(FileFinder::LayerFileNoMidiNonSV);
Chris@174 2140 if (path == "") return;
Chris@174 2141
Chris@174 2142 FileOpenStatus status = importPitchLayer(path);
Chris@174 2143
Chris@174 2144 if (status == FileOpenFailed) {
Chris@174 2145 emit hideSplash();
Chris@174 2146 QMessageBox::critical(this, tr("Failed to open file"),
Chris@174 2147 tr("<b>File open failed</b><p>Layer file %1 could not be opened.").arg(path));
Chris@174 2148 return;
Chris@174 2149 } else if (status == FileOpenWrongMode) {
Chris@174 2150 emit hideSplash();
Chris@174 2151 QMessageBox::critical(this, tr("Failed to open file"),
Chris@174 2152 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));
Chris@174 2153 }
Chris@174 2154 }
Chris@174 2155
Chris@174 2156 MainWindow::FileOpenStatus
Chris@174 2157 MainWindow::importPitchLayer(FileSource source)
Chris@174 2158 {
Chris@174 2159 if (!source.isAvailable()) return FileOpenFailed;
Chris@174 2160 source.waitForData();
Chris@174 2161
Chris@442 2162 if (!waitForInitialAnalysis()) return FileOpenCancelled;
Chris@442 2163
Chris@174 2164 QString path = source.getLocalFilename();
Chris@174 2165
Chris@174 2166 RDFImporter::RDFDocumentType rdfType =
Chris@174 2167 RDFImporter::identifyDocumentType(QUrl::fromLocalFile(path).toString());
Chris@174 2168
Chris@174 2169 if (rdfType != RDFImporter::NotRDF) {
Chris@174 2170
Chris@174 2171 //!!!
Chris@174 2172 return FileOpenFailed;
Chris@174 2173
Chris@174 2174 } else if (source.getExtension().toLower() == "svl" ||
Chris@174 2175 (source.getExtension().toLower() == "xml" &&
Chris@174 2176 (SVFileReader::identifyXmlFile(source.getLocalFilename())
Chris@174 2177 == SVFileReader::SVLayerFile))) {
Chris@174 2178
Chris@174 2179 //!!!
Chris@174 2180 return FileOpenFailed;
Chris@174 2181
Chris@174 2182 } else {
Chris@174 2183
Chris@174 2184 try {
Chris@174 2185
Chris@174 2186 CSVFormat format(path);
Chris@174 2187 format.setSampleRate(getMainModel()->getSampleRate());
Chris@174 2188
Chris@174 2189 if (format.getModelType() != CSVFormat::TwoDimensionalModel) {
Chris@174 2190 //!!! error report
Chris@174 2191 return FileOpenFailed;
Chris@174 2192 }
Chris@174 2193
Chris@174 2194 Model *model = DataFileReaderFactory::loadCSV
Chris@174 2195 (path, format, getMainModel()->getSampleRate());
Chris@174 2196
Chris@174 2197 if (model) {
Chris@174 2198
Chris@174 2199 SVDEBUG << "MainWindow::importPitchLayer: Have model" << endl;
Chris@174 2200
Chris@174 2201 CommandHistory::getInstance()->startCompoundOperation
Chris@174 2202 (tr("Import Pitch Track"), true);
Chris@174 2203
Chris@174 2204 Layer *newLayer = m_document->createImportedLayer(model);
Chris@174 2205
Chris@174 2206 m_analyser->takePitchTrackFrom(newLayer);
Chris@174 2207
Chris@174 2208 m_document->deleteLayer(newLayer);
Chris@174 2209
Chris@174 2210 CommandHistory::getInstance()->endCompoundOperation();
Chris@174 2211
Chris@174 2212 //!!! swap all data in to existing layer instead of this
Chris@174 2213
Chris@174 2214 if (!source.isRemote()) {
Chris@174 2215 registerLastOpenedFilePath
Chris@174 2216 (FileFinder::LayerFile,
Chris@174 2217 path); // for file dialog
Chris@174 2218 }
Chris@174 2219
Chris@174 2220 return FileOpenSucceeded;
Chris@174 2221 }
Chris@174 2222 } catch (DataFileReaderFactory::Exception e) {
Chris@174 2223 if (e == DataFileReaderFactory::ImportCancelled) {
Chris@174 2224 return FileOpenCancelled;
Chris@174 2225 }
Chris@174 2226 }
Chris@174 2227 }
Chris@174 2228
Chris@174 2229 return FileOpenFailed;
Chris@174 2230 }
Chris@174 2231
Chris@174 2232 void
Chris@85 2233 MainWindow::exportPitchLayer()
matthiasm@26 2234 {
Chris@174 2235 Layer *layer = m_analyser->getLayer(Analyser::PitchTrack);
matthiasm@26 2236 if (!layer) return;
matthiasm@26 2237
Chris@85 2238 SparseTimeValueModel *model =
Chris@85 2239 qobject_cast<SparseTimeValueModel *>(layer->getModel());
matthiasm@26 2240 if (!model) return;
matthiasm@26 2241
Chris@96 2242 FileFinder::FileType type = FileFinder::LayerFileNoMidiNonSV;
matthiasm@26 2243
matthiasm@26 2244 QString path = getSaveFileName(type);
matthiasm@26 2245
matthiasm@26 2246 if (path == "") return;
matthiasm@26 2247
Chris@442 2248 if (!waitForInitialAnalysis()) return;
Chris@442 2249
matthiasm@26 2250 if (QFileInfo(path).suffix() == "") path += ".svl";
matthiasm@26 2251
matthiasm@26 2252 QString suffix = QFileInfo(path).suffix().toLower();
matthiasm@26 2253
matthiasm@26 2254 QString error;
matthiasm@26 2255
matthiasm@26 2256 if (suffix == "xml" || suffix == "svl") {
matthiasm@26 2257
Chris@85 2258 error = exportToSVL(path, layer);
matthiasm@26 2259
matthiasm@26 2260 } else if (suffix == "ttl" || suffix == "n3") {
matthiasm@26 2261
Chris@85 2262 RDFExporter exporter(path, model);
Chris@85 2263 exporter.write();
Chris@85 2264 if (!exporter.isOK()) {
Chris@85 2265 error = exporter.getError();
Chris@85 2266 }
Chris@85 2267
Chris@85 2268 } else {
Chris@85 2269
Chris@429 2270 DataExportOptions options = DataExportFillGaps;
Chris@429 2271
Chris@85 2272 CSVFileWriter writer(path, model,
Chris@429 2273 ((suffix == "csv") ? "," : "\t"),
Chris@429 2274 options);
Chris@85 2275 writer.write();
Chris@85 2276
Chris@85 2277 if (!writer.isOK()) {
Chris@85 2278 error = writer.getError();
Chris@85 2279 }
Chris@85 2280 }
Chris@85 2281
Chris@85 2282 if (error != "") {
Chris@85 2283 QMessageBox::critical(this, tr("Failed to write file"), error);
Chris@85 2284 } else {
Chris@85 2285 emit activity(tr("Export layer to \"%1\"").arg(path));
Chris@85 2286 }
Chris@85 2287 }
Chris@85 2288
Chris@85 2289 void
Chris@85 2290 MainWindow::exportNoteLayer()
Chris@85 2291 {
Chris@174 2292 Layer *layer = m_analyser->getLayer(Analyser::Notes);
Chris@85 2293 if (!layer) return;
Chris@85 2294
Chris@85 2295 FlexiNoteModel *model = qobject_cast<FlexiNoteModel *>(layer->getModel());
Chris@85 2296 if (!model) return;
Chris@85 2297
Chris@96 2298 FileFinder::FileType type = FileFinder::LayerFileNonSV;
Chris@85 2299
Chris@85 2300 QString path = getSaveFileName(type);
Chris@85 2301
Chris@85 2302 if (path == "") return;
Chris@85 2303
Chris@85 2304 if (QFileInfo(path).suffix() == "") path += ".svl";
Chris@85 2305
Chris@85 2306 QString suffix = QFileInfo(path).suffix().toLower();
Chris@85 2307
Chris@85 2308 QString error;
Chris@85 2309
Chris@85 2310 if (suffix == "xml" || suffix == "svl") {
Chris@85 2311
Chris@85 2312 error = exportToSVL(path, layer);
Chris@85 2313
Chris@85 2314 } else if (suffix == "mid" || suffix == "midi") {
Chris@85 2315
Chris@85 2316 MIDIFileWriter writer(path, model, model->getSampleRate());
Chris@85 2317 writer.write();
Chris@85 2318 if (!writer.isOK()) {
Chris@85 2319 error = writer.getError();
Chris@85 2320 }
Chris@85 2321
Chris@85 2322 } else if (suffix == "ttl" || suffix == "n3") {
Chris@85 2323
Chris@85 2324 RDFExporter exporter(path, model);
Chris@85 2325 exporter.write();
Chris@85 2326 if (!exporter.isOK()) {
Chris@85 2327 error = exporter.getError();
matthiasm@26 2328 }
matthiasm@26 2329
matthiasm@26 2330 } else {
matthiasm@26 2331
Chris@429 2332 DataExportOptions options = DataExportOmitLevels;
Chris@429 2333
matthiasm@26 2334 CSVFileWriter writer(path, model,
Chris@429 2335 ((suffix == "csv") ? "," : "\t"),
Chris@429 2336 options);
matthiasm@26 2337 writer.write();
matthiasm@26 2338
matthiasm@26 2339 if (!writer.isOK()) {
matthiasm@26 2340 error = writer.getError();
matthiasm@26 2341 }
matthiasm@26 2342 }
matthiasm@26 2343
matthiasm@26 2344 if (error != "") {
matthiasm@26 2345 QMessageBox::critical(this, tr("Failed to write file"), error);
matthiasm@26 2346 } else {
matthiasm@26 2347 emit activity(tr("Export layer to \"%1\"").arg(path));
matthiasm@26 2348 }
matthiasm@26 2349 }
matthiasm@26 2350
Chris@139 2351 void
Chris@485 2352 MainWindow::browseRecordedAudio()
Chris@485 2353 {
Chris@485 2354 if (!m_recordTarget) return;
Chris@485 2355
Chris@501 2356 QString path = m_recordTarget->getRecordContainerFolder();
Chris@485 2357 if (path == "") return;
Chris@485 2358
Chris@485 2359 openLocalFolder(path);
Chris@485 2360 }
Chris@485 2361
Chris@485 2362 void
Chris@399 2363 MainWindow::doubleClickSelectInvoked(sv_frame_t frame)
Chris@139 2364 {
Chris@399 2365 sv_frame_t f0, f1;
Chris@139 2366 m_analyser->getEnclosingSelectionScope(frame, f0, f1);
Chris@139 2367
Chris@139 2368 cerr << "MainWindow::doubleClickSelectInvoked(" << frame << "): [" << f0 << "," << f1 << "]" << endl;
Chris@139 2369
Chris@164 2370 Selection sel(f0, f1);
Chris@164 2371 m_viewManager->setSelection(sel);
Chris@164 2372 }
Chris@164 2373
Chris@164 2374 void
Chris@194 2375 MainWindow::abandonSelection()
Chris@167 2376 {
Chris@194 2377 // Named abandonSelection rather than clearSelection to indicate
Chris@194 2378 // that this is an active operation -- it restores the original
Chris@194 2379 // content of the pitch track in the selected region rather than
Chris@194 2380 // simply un-selecting.
Chris@194 2381
Chris@194 2382 cerr << "MainWindow::abandonSelection()" << endl;
Chris@167 2383
Chris@199 2384 CommandHistory::getInstance()->startCompoundOperation(tr("Abandon Selection"), true);
Chris@168 2385
Chris@194 2386 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@194 2387 if (!selections.empty()) {
Chris@194 2388 Selection sel = *selections.begin();
Chris@199 2389 m_analyser->abandonReAnalysis(sel);
Chris@252 2390 auxSnapNotes(sel);
Chris@194 2391 }
Chris@194 2392
Chris@167 2393 MainWindowBase::clearSelection();
Chris@168 2394
Chris@168 2395 CommandHistory::getInstance()->endCompoundOperation();
Chris@167 2396 }
Chris@167 2397
Chris@167 2398 void
Chris@192 2399 MainWindow::selectionChangedByUser()
Chris@164 2400 {
Chris@221 2401 if (!m_document) {
Chris@221 2402 // we're exiting, most likely
Chris@221 2403 return;
Chris@221 2404 }
Chris@221 2405
Chris@164 2406 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@164 2407
Chris@192 2408 cerr << "MainWindow::selectionChangedByUser" << endl;
Chris@192 2409
Chris@192 2410 m_analyser->showPitchCandidates(m_pendingConstraint.isConstrained());
Chris@190 2411
Chris@164 2412 if (!selections.empty()) {
Chris@164 2413 Selection sel = *selections.begin();
Chris@192 2414 cerr << "MainWindow::selectionChangedByUser: have selection" << endl;
Chris@192 2415 QString error = m_analyser->reAnalyseSelection
Chris@192 2416 (sel, m_pendingConstraint);
Chris@164 2417 if (error != "") {
Chris@164 2418 QMessageBox::critical
Chris@164 2419 (this, tr("Failed to analyse selection"),
Chris@164 2420 tr("<b>Analysis failed</b><p>%2</p>").arg(error));
Chris@164 2421 }
Chris@164 2422 }
Chris@192 2423
Chris@192 2424 m_pendingConstraint = Analyser::FrequencyRange();
Chris@192 2425 }
Chris@192 2426
Chris@192 2427 void
Chris@192 2428 MainWindow::regionOutlined(QRect r)
Chris@192 2429 {
Chris@192 2430 cerr << "MainWindow::regionOutlined(" << r.x() << "," << r.y() << "," << r.width() << "," << r.height() << ")" << endl;
Chris@192 2431
Chris@192 2432 Pane *pane = qobject_cast<Pane *>(sender());
Chris@192 2433 if (!pane) {
Chris@192 2434 cerr << "MainWindow::regionOutlined: not sent by pane, ignoring" << endl;
Chris@192 2435 return;
Chris@192 2436 }
Chris@192 2437
Chris@192 2438 if (!m_analyser) {
Chris@192 2439 cerr << "MainWindow::regionOutlined: no analyser, ignoring" << endl;
Chris@192 2440 return;
Chris@192 2441 }
Chris@192 2442
Chris@192 2443 SpectrogramLayer *spectrogram = qobject_cast<SpectrogramLayer *>
Chris@192 2444 (m_analyser->getLayer(Analyser::Spectrogram));
Chris@192 2445 if (!spectrogram) {
Chris@192 2446 cerr << "MainWindow::regionOutlined: no spectrogram layer, ignoring" << endl;
Chris@192 2447 return;
Chris@192 2448 }
Chris@192 2449
Chris@399 2450 sv_frame_t f0 = pane->getFrameForX(r.x());
Chris@399 2451 sv_frame_t f1 = pane->getFrameForX(r.x() + r.width());
Chris@192 2452
Chris@399 2453 double v0 = spectrogram->getFrequencyForY(pane, r.y() + r.height());
Chris@399 2454 double v1 = spectrogram->getFrequencyForY(pane, r.y());
Chris@192 2455
Chris@192 2456 cerr << "MainWindow::regionOutlined: frame " << f0 << " -> " << f1
Chris@192 2457 << ", frequency " << v0 << " -> " << v1 << endl;
Chris@192 2458
Chris@192 2459 m_pendingConstraint = Analyser::FrequencyRange(v0, v1);
Chris@192 2460
Chris@192 2461 Selection sel(f0, f1);
Chris@192 2462 m_viewManager->setSelection(sel);
Chris@0 2463 }
Chris@0 2464
Chris@0 2465 void
Chris@168 2466 MainWindow::clearPitches()
Chris@168 2467 {
Chris@168 2468 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@168 2469
Chris@168 2470 CommandHistory::getInstance()->startCompoundOperation(tr("Clear Pitches"), true);
Chris@168 2471
Chris@168 2472 for (MultiSelection::SelectionList::iterator k = selections.begin();
Chris@168 2473 k != selections.end(); ++k) {
Chris@184 2474 m_analyser->deletePitches(*k);
Chris@252 2475 auxSnapNotes(*k);
Chris@168 2476 }
Chris@168 2477
Chris@168 2478 CommandHistory::getInstance()->endCompoundOperation();
Chris@168 2479 }
Chris@168 2480
Chris@168 2481 void
Chris@142 2482 MainWindow::octaveShift(bool up)
Chris@142 2483 {
Chris@142 2484 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@142 2485
Chris@211 2486 CommandHistory::getInstance()->startCompoundOperation
Chris@211 2487 (up ? tr("Choose Higher Octave") : tr("Choose Lower Octave"), true);
Chris@142 2488
Chris@168 2489 for (MultiSelection::SelectionList::iterator k = selections.begin();
Chris@168 2490 k != selections.end(); ++k) {
Chris@142 2491
Chris@168 2492 m_analyser->shiftOctave(*k, up);
Chris@252 2493 auxSnapNotes(*k);
Chris@142 2494 }
Chris@142 2495
Chris@142 2496 CommandHistory::getInstance()->endCompoundOperation();
Chris@142 2497 }
Chris@142 2498
Chris@142 2499 void
Chris@184 2500 MainWindow::togglePitchCandidates()
Chris@184 2501 {
Chris@199 2502 CommandHistory::getInstance()->startCompoundOperation(tr("Toggle Pitch Candidates"), true);
Chris@199 2503
Chris@184 2504 m_analyser->showPitchCandidates(!m_analyser->arePitchCandidatesShown());
Chris@199 2505
Chris@199 2506 CommandHistory::getInstance()->endCompoundOperation();
Chris@199 2507
Chris@187 2508 updateMenuStates();
Chris@184 2509 }
Chris@184 2510
Chris@184 2511 void
Chris@184 2512 MainWindow::switchPitchUp()
Chris@167 2513 {
Chris@211 2514 if (m_analyser->arePitchCandidatesShown()) {
Chris@211 2515 if (m_analyser->haveHigherPitchCandidate()) {
Chris@211 2516
Chris@211 2517 CommandHistory::getInstance()->startCompoundOperation
Chris@211 2518 (tr("Choose Higher Pitch Candidate"), true);
Chris@211 2519
Chris@211 2520 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@211 2521
Chris@211 2522 for (MultiSelection::SelectionList::iterator k = selections.begin();
Chris@211 2523 k != selections.end(); ++k) {
Chris@211 2524 m_analyser->switchPitchCandidate(*k, true);
Chris@252 2525 auxSnapNotes(*k);
Chris@211 2526 }
Chris@211 2527
Chris@211 2528 CommandHistory::getInstance()->endCompoundOperation();
Chris@211 2529 }
Chris@211 2530 } else {
Chris@211 2531 octaveShift(true);
Chris@167 2532 }
Chris@167 2533 }
Chris@167 2534
Chris@167 2535 void
Chris@184 2536 MainWindow::switchPitchDown()
Chris@184 2537 {
Chris@211 2538 if (m_analyser->arePitchCandidatesShown()) {
Chris@211 2539 if (m_analyser->haveLowerPitchCandidate()) {
Chris@211 2540
Chris@211 2541 CommandHistory::getInstance()->startCompoundOperation
Chris@211 2542 (tr("Choose Lower Pitch Candidate"), true);
Chris@211 2543
Chris@211 2544 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@211 2545
Chris@211 2546 for (MultiSelection::SelectionList::iterator k = selections.begin();
Chris@211 2547 k != selections.end(); ++k) {
Chris@211 2548 m_analyser->switchPitchCandidate(*k, false);
Chris@252 2549 auxSnapNotes(*k);
Chris@211 2550 }
Chris@211 2551
Chris@211 2552 CommandHistory::getInstance()->endCompoundOperation();
Chris@211 2553 }
Chris@211 2554 } else {
Chris@211 2555 octaveShift(false);
Chris@184 2556 }
Chris@184 2557 }
Chris@184 2558
Chris@184 2559 void
Chris@237 2560 MainWindow::snapNotesToPitches()
Chris@237 2561 {
matthiasm@274 2562 cerr << "in snapNotesToPitches" << endl;
Chris@237 2563 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@237 2564
Chris@237 2565 if (!selections.empty()) {
Chris@237 2566
Chris@237 2567 CommandHistory::getInstance()->startCompoundOperation
Chris@237 2568 (tr("Snap Notes to Pitches"), true);
Chris@237 2569
Chris@237 2570 for (MultiSelection::SelectionList::iterator k = selections.begin();
Chris@237 2571 k != selections.end(); ++k) {
Chris@239 2572 auxSnapNotes(*k);
Chris@237 2573 }
Chris@237 2574
Chris@237 2575 CommandHistory::getInstance()->endCompoundOperation();
Chris@237 2576 }
Chris@237 2577 }
Chris@237 2578
Chris@237 2579 void
Chris@239 2580 MainWindow::auxSnapNotes(Selection s)
Chris@239 2581 {
matthiasm@274 2582 cerr << "in auxSnapNotes" << endl;
Chris@239 2583 FlexiNoteLayer *layer =
Chris@239 2584 qobject_cast<FlexiNoteLayer *>(m_analyser->getLayer(Analyser::Notes));
Chris@239 2585 if (!layer) return;
Chris@239 2586
Chris@239 2587 layer->snapSelectedNotesToPitchTrack(m_analyser->getPane(), s);
Chris@239 2588 }
Chris@239 2589
Chris@239 2590 void
Chris@240 2591 MainWindow::splitNote()
Chris@237 2592 {
Chris@237 2593 FlexiNoteLayer *layer =
Chris@237 2594 qobject_cast<FlexiNoteLayer *>(m_analyser->getLayer(Analyser::Notes));
Chris@237 2595 if (!layer) return;
Chris@237 2596
Chris@240 2597 layer->splitNotesAt(m_analyser->getPane(), m_viewManager->getPlaybackFrame());
Chris@237 2598 }
Chris@237 2599
Chris@237 2600 void
Chris@238 2601 MainWindow::mergeNotes()
Chris@238 2602 {
Chris@238 2603 FlexiNoteLayer *layer =
Chris@238 2604 qobject_cast<FlexiNoteLayer *>(m_analyser->getLayer(Analyser::Notes));
Chris@238 2605 if (!layer) return;
Chris@238 2606
Chris@238 2607 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@238 2608
Chris@238 2609 if (!selections.empty()) {
Chris@238 2610
Chris@238 2611 CommandHistory::getInstance()->startCompoundOperation
Chris@238 2612 (tr("Merge Notes"), true);
Chris@238 2613
Chris@238 2614 for (MultiSelection::SelectionList::iterator k = selections.begin();
Chris@238 2615 k != selections.end(); ++k) {
Chris@240 2616 layer->mergeNotes(m_analyser->getPane(), *k, true);
Chris@238 2617 }
Chris@238 2618
Chris@238 2619 CommandHistory::getInstance()->endCompoundOperation();
Chris@238 2620 }
Chris@238 2621 }
Chris@238 2622
Chris@238 2623 void
matthiasm@292 2624 MainWindow::deleteNotes()
matthiasm@292 2625 {
matthiasm@292 2626 FlexiNoteLayer *layer =
matthiasm@292 2627 qobject_cast<FlexiNoteLayer *>(m_analyser->getLayer(Analyser::Notes));
matthiasm@292 2628 if (!layer) return;
matthiasm@292 2629
matthiasm@292 2630 MultiSelection::SelectionList selections = m_viewManager->getSelections();
matthiasm@292 2631
matthiasm@292 2632 if (!selections.empty()) {
matthiasm@292 2633
matthiasm@292 2634 CommandHistory::getInstance()->startCompoundOperation
matthiasm@292 2635 (tr("Delete Notes"), true);
matthiasm@292 2636
matthiasm@292 2637 for (MultiSelection::SelectionList::iterator k = selections.begin();
matthiasm@292 2638 k != selections.end(); ++k) {
matthiasm@294 2639 layer->deleteSelectionInclusive(*k);
matthiasm@292 2640 }
matthiasm@292 2641
matthiasm@292 2642 CommandHistory::getInstance()->endCompoundOperation();
matthiasm@292 2643 }
matthiasm@292 2644 }
matthiasm@292 2645
matthiasm@292 2646
matthiasm@292 2647 void
Chris@240 2648 MainWindow::formNoteFromSelection()
Chris@240 2649 {
matthiasm@293 2650 Layer *layer0 = m_analyser->getLayer(Analyser::Notes);
matthiasm@293 2651 FlexiNoteModel *model = qobject_cast<FlexiNoteModel *>(layer0->getModel());
matthiasm@293 2652
Chris@240 2653 FlexiNoteLayer *layer =
Chris@240 2654 qobject_cast<FlexiNoteLayer *>(m_analyser->getLayer(Analyser::Notes));
Chris@240 2655 if (!layer) return;
Chris@240 2656
Chris@240 2657 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@240 2658
Chris@240 2659 if (!selections.empty()) {
Chris@240 2660
Chris@240 2661 CommandHistory::getInstance()->startCompoundOperation
Chris@240 2662 (tr("Form Note from Selection"), true);
Chris@240 2663 for (MultiSelection::SelectionList::iterator k = selections.begin();
Chris@240 2664 k != selections.end(); ++k) {
Chris@355 2665 if (!model->getNotesWithin(k->getStartFrame(), k->getEndFrame()).empty()) {
matthiasm@293 2666 layer->splitNotesAt(m_analyser->getPane(), k->getStartFrame());
matthiasm@293 2667 layer->splitNotesAt(m_analyser->getPane(), k->getEndFrame());
matthiasm@293 2668 layer->mergeNotes(m_analyser->getPane(), *k, false);
matthiasm@293 2669 } else {
matthiasm@293 2670 layer->addNoteOn(k->getStartFrame(), 100, 100);
matthiasm@293 2671 layer->addNoteOff(k->getEndFrame(), 100);
matthiasm@293 2672 layer->mergeNotes(m_analyser->getPane(), *k, false); // only so the note adapts in case of exisitng pitch track
matthiasm@293 2673 }
Chris@240 2674 }
Chris@240 2675
matthiasm@293 2676 CommandHistory::getInstance()->endCompoundOperation();
Chris@240 2677 }
Chris@240 2678 }
Chris@240 2679
Chris@240 2680 void
Chris@0 2681 MainWindow::playSpeedChanged(int position)
Chris@0 2682 {
Chris@474 2683 PlaySpeedRangeMapper mapper;
Chris@0 2684
Chris@399 2685 double percent = m_playSpeed->mappedValue();
Chris@399 2686 double factor = mapper.getFactorForValue(percent);
Chris@0 2687
Chris@474 2688 int centre = m_playSpeed->defaultValue();
Chris@474 2689
Chris@474 2690 // Percentage is shown to 0dp if >100, to 1dp if <100; factor is
Chris@474 2691 // shown to 3sf
Chris@474 2692
Chris@474 2693 char pcbuf[30];
Chris@474 2694 char facbuf[30];
Chris@474 2695
Chris@474 2696 if (position == centre) {
Chris@0 2697 contextHelpChanged(tr("Playback speed: Normal"));
Chris@474 2698 } else if (position < centre) {
Chris@474 2699 sprintf(pcbuf, "%.1f", percent);
Chris@474 2700 sprintf(facbuf, "%.3g", 1.0 / factor);
Chris@474 2701 contextHelpChanged(tr("Playback speed: %1% (%2x slower)")
Chris@474 2702 .arg(pcbuf)
Chris@474 2703 .arg(facbuf));
Chris@0 2704 } else {
Chris@474 2705 sprintf(pcbuf, "%.0f", percent);
Chris@474 2706 sprintf(facbuf, "%.3g", factor);
Chris@474 2707 contextHelpChanged(tr("Playback speed: %1% (%2x faster)")
Chris@474 2708 .arg(pcbuf)
Chris@474 2709 .arg(facbuf));
Chris@0 2710 }
Chris@0 2711
Chris@474 2712 m_playSource->setTimeStretch(1.0 / factor); // factor is a speedup
Chris@0 2713
Chris@0 2714 updateMenuStates();
Chris@0 2715 }
Chris@0 2716
Chris@0 2717 void
Chris@0 2718 MainWindow::playSharpenToggled()
Chris@0 2719 {
Chris@0 2720 QSettings settings;
Chris@0 2721 settings.beginGroup("MainWindow");
Chris@0 2722 settings.setValue("playsharpen", m_playSharpen->isChecked());
Chris@0 2723 settings.endGroup();
Chris@0 2724
Chris@0 2725 playSpeedChanged(m_playSpeed->value());
justin@157 2726 // TODO: pitch gain?
Chris@0 2727 }
Chris@0 2728
Chris@0 2729 void
Chris@0 2730 MainWindow::playMonoToggled()
Chris@0 2731 {
Chris@0 2732 QSettings settings;
Chris@0 2733 settings.beginGroup("MainWindow");
Chris@0 2734 settings.setValue("playmono", m_playMono->isChecked());
Chris@0 2735 settings.endGroup();
Chris@0 2736
Chris@0 2737 playSpeedChanged(m_playSpeed->value());
justin@157 2738 // TODO: pitch gain?
Chris@0 2739 }
Chris@0 2740
Chris@0 2741 void
Chris@0 2742 MainWindow::speedUpPlayback()
Chris@0 2743 {
Chris@0 2744 int value = m_playSpeed->value();
Chris@0 2745 value = value + m_playSpeed->pageStep();
Chris@0 2746 if (value > m_playSpeed->maximum()) value = m_playSpeed->maximum();
Chris@0 2747 m_playSpeed->setValue(value);
Chris@0 2748 }
Chris@0 2749
Chris@0 2750 void
Chris@0 2751 MainWindow::slowDownPlayback()
Chris@0 2752 {
Chris@0 2753 int value = m_playSpeed->value();
Chris@0 2754 value = value - m_playSpeed->pageStep();
Chris@0 2755 if (value < m_playSpeed->minimum()) value = m_playSpeed->minimum();
Chris@0 2756 m_playSpeed->setValue(value);
Chris@0 2757 }
Chris@0 2758
Chris@0 2759 void
Chris@0 2760 MainWindow::restoreNormalPlayback()
Chris@0 2761 {
Chris@0 2762 m_playSpeed->setValue(m_playSpeed->defaultValue());
Chris@0 2763 }
Chris@0 2764
justin@157 2765 void
Chris@404 2766 MainWindow::audioGainChanged(float gain)
justin@159 2767 {
Chris@404 2768 double db = AudioLevel::multiplier_to_dB(gain);
Chris@404 2769 cerr << "gain = " << gain << " (" << db << " dB)" << endl;
Chris@404 2770 contextHelpChanged(tr("Audio Gain: %1 dB").arg(db));
Chris@417 2771 if (gain == 0.f) {
Chris@417 2772 m_analyser->setAudible(Analyser::Audio, false);
Chris@417 2773 } else {
Chris@417 2774 m_analyser->setAudible(Analyser::Audio, true);
Chris@417 2775 m_analyser->setGain(Analyser::Audio, gain);
Chris@417 2776 }
justin@159 2777 updateMenuStates();
justin@159 2778 }
justin@159 2779
justin@159 2780 void
Chris@404 2781 MainWindow::pitchGainChanged(float gain)
justin@159 2782 {
Chris@404 2783 double db = AudioLevel::multiplier_to_dB(gain);
Chris@404 2784 cerr << "gain = " << gain << " (" << db << " dB)" << endl;
Chris@404 2785 contextHelpChanged(tr("Pitch Gain: %1 dB").arg(db));
Chris@417 2786 if (gain == 0.f) {
Chris@417 2787 m_analyser->setAudible(Analyser::PitchTrack, false);
Chris@417 2788 } else {
Chris@417 2789 m_analyser->setAudible(Analyser::PitchTrack, true);
Chris@417 2790 m_analyser->setGain(Analyser::PitchTrack, gain);
Chris@417 2791 }
justin@157 2792 updateMenuStates();
justin@157 2793 }
justin@157 2794
justin@157 2795 void
Chris@404 2796 MainWindow::notesGainChanged(float gain)
justin@157 2797 {
Chris@404 2798 double db = AudioLevel::multiplier_to_dB(gain);
Chris@404 2799 cerr << "gain = " << gain << " (" << db << " dB)" << endl;
Chris@404 2800 contextHelpChanged(tr("Notes Gain: %1 dB").arg(db));
Chris@417 2801 if (gain == 0.f) {
Chris@417 2802 m_analyser->setAudible(Analyser::Notes, false);
Chris@417 2803 } else {
Chris@417 2804 m_analyser->setAudible(Analyser::Notes, true);
Chris@417 2805 m_analyser->setGain(Analyser::Notes, gain);
Chris@417 2806 }
justin@159 2807 updateMenuStates();
justin@159 2808 }
justin@159 2809
justin@159 2810 void
Chris@404 2811 MainWindow::audioPanChanged(float pan)
justin@159 2812 {
Chris@404 2813 contextHelpChanged(tr("Audio Pan: %1").arg(pan));
Chris@404 2814 m_analyser->setPan(Analyser::Audio, pan);
justin@160 2815 updateMenuStates();
justin@160 2816 }
justin@160 2817
justin@160 2818 void
Chris@404 2819 MainWindow::pitchPanChanged(float pan)
justin@160 2820 {
Chris@404 2821 contextHelpChanged(tr("Pitch Pan: %1").arg(pan));
Chris@404 2822 m_analyser->setPan(Analyser::PitchTrack, pan);
justin@160 2823 updateMenuStates();
justin@160 2824 }
justin@160 2825
justin@160 2826 void
Chris@404 2827 MainWindow::notesPanChanged(float pan)
justin@160 2828 {
Chris@404 2829 contextHelpChanged(tr("Notes Pan: %1").arg(pan));
Chris@404 2830 m_analyser->setPan(Analyser::Notes, pan);
justin@160 2831 updateMenuStates();
justin@160 2832 }
justin@160 2833
justin@160 2834 void
Chris@0 2835 MainWindow::updateVisibleRangeDisplay(Pane *p) const
Chris@0 2836 {
Chris@0 2837 if (!getMainModel() || !p) {
Chris@0 2838 return;
Chris@0 2839 }
Chris@0 2840
Chris@0 2841 bool haveSelection = false;
Chris@403 2842 sv_frame_t startFrame = 0, endFrame = 0;
Chris@0 2843
Chris@0 2844 if (m_viewManager && m_viewManager->haveInProgressSelection()) {
Chris@0 2845
Chris@0 2846 bool exclusive = false;
Chris@0 2847 Selection s = m_viewManager->getInProgressSelection(exclusive);
Chris@0 2848
Chris@0 2849 if (!s.isEmpty()) {
Chris@0 2850 haveSelection = true;
Chris@0 2851 startFrame = s.getStartFrame();
Chris@0 2852 endFrame = s.getEndFrame();
Chris@0 2853 }
Chris@0 2854 }
Chris@0 2855
Chris@0 2856 if (!haveSelection) {
Chris@0 2857 startFrame = p->getFirstVisibleFrame();
Chris@0 2858 endFrame = p->getLastVisibleFrame();
Chris@0 2859 }
Chris@0 2860
Chris@0 2861 RealTime start = RealTime::frame2RealTime
Chris@0 2862 (startFrame, getMainModel()->getSampleRate());
Chris@0 2863
Chris@0 2864 RealTime end = RealTime::frame2RealTime
Chris@0 2865 (endFrame, getMainModel()->getSampleRate());
Chris@0 2866
Chris@0 2867 RealTime duration = end - start;
Chris@0 2868
Chris@0 2869 QString startStr, endStr, durationStr;
Chris@0 2870 startStr = start.toText(true).c_str();
Chris@0 2871 endStr = end.toText(true).c_str();
Chris@0 2872 durationStr = duration.toText(true).c_str();
Chris@0 2873
Chris@0 2874 if (haveSelection) {
Chris@0 2875 m_myStatusMessage = tr("Selection: %1 to %2 (duration %3)")
Chris@0 2876 .arg(startStr).arg(endStr).arg(durationStr);
Chris@0 2877 } else {
Chris@0 2878 m_myStatusMessage = tr("Visible: %1 to %2 (duration %3)")
Chris@0 2879 .arg(startStr).arg(endStr).arg(durationStr);
Chris@0 2880 }
matthiasm@42 2881
Chris@362 2882 getStatusLabel()->setText(m_myStatusMessage);
Chris@0 2883 }
Chris@0 2884
Chris@0 2885 void
Chris@0 2886 MainWindow::updatePositionStatusDisplays() const
Chris@0 2887 {
Chris@0 2888 if (!statusBar()->isVisible()) return;
Chris@0 2889
Chris@0 2890 }
Chris@0 2891
Chris@0 2892 void
Chris@0 2893 MainWindow::outputLevelsChanged(float left, float right)
Chris@0 2894 {
Chris@0 2895 m_fader->setPeakLeft(left);
Chris@0 2896 m_fader->setPeakRight(right);
Chris@0 2897 }
Chris@0 2898
Chris@0 2899 void
Chris@399 2900 MainWindow::sampleRateMismatch(sv_samplerate_t ,
Chris@399 2901 sv_samplerate_t ,
Chris@399 2902 bool )
Chris@0 2903 {
Chris@0 2904 updateDescriptionLabel();
Chris@0 2905 }
Chris@0 2906
Chris@0 2907 void
Chris@0 2908 MainWindow::audioOverloadPluginDisabled()
Chris@0 2909 {
Chris@0 2910 QMessageBox::information
Chris@0 2911 (this, tr("Audio processing overload"),
Chris@0 2912 tr("<b>Overloaded</b><p>Audio effects plugin auditioning has been disabled due to a processing overload."));
Chris@0 2913 }
Chris@0 2914
Chris@0 2915 void
Chris@0 2916 MainWindow::audioTimeStretchMultiChannelDisabled()
Chris@0 2917 {
Chris@0 2918 static bool shownOnce = false;
Chris@0 2919 if (shownOnce) return;
Chris@0 2920 QMessageBox::information
Chris@0 2921 (this, tr("Audio processing overload"),
Chris@0 2922 tr("<b>Overloaded</b><p>Audio playback speed processing has been reduced to a single channel, due to a processing overload."));
Chris@0 2923 shownOnce = true;
Chris@0 2924 }
Chris@0 2925
Chris@0 2926 void
Chris@0 2927 MainWindow::layerRemoved(Layer *layer)
Chris@0 2928 {
Chris@0 2929 MainWindowBase::layerRemoved(layer);
Chris@0 2930 }
Chris@0 2931
Chris@0 2932 void
Chris@0 2933 MainWindow::layerInAView(Layer *layer, bool inAView)
Chris@0 2934 {
Chris@0 2935 MainWindowBase::layerInAView(layer, inAView);
Chris@0 2936 }
Chris@0 2937
Chris@0 2938 void
Chris@0 2939 MainWindow::modelAdded(Model *model)
Chris@0 2940 {
Chris@0 2941 MainWindowBase::modelAdded(model);
Chris@3 2942 DenseTimeValueModel *dtvm = qobject_cast<DenseTimeValueModel *>(model);
Chris@0 2943 if (dtvm) {
Chris@70 2944 cerr << "A dense time-value model (such as an audio file) has been loaded" << endl;
Chris@0 2945 }
Chris@0 2946 }
Chris@0 2947
Chris@0 2948 void
Chris@0 2949 MainWindow::modelAboutToBeDeleted(Model *model)
Chris@0 2950 {
Chris@0 2951 MainWindowBase::modelAboutToBeDeleted(model);
Chris@0 2952 }
Chris@0 2953
Chris@0 2954 void
Chris@0 2955 MainWindow::mainModelChanged(WaveFileModel *model)
Chris@0 2956 {
Chris@0 2957 m_panLayer->setModel(model);
Chris@0 2958
Chris@0 2959 MainWindowBase::mainModelChanged(model);
Chris@0 2960
Chris@479 2961 if (m_playTarget || m_audioIO) {
Chris@0 2962 connect(m_fader, SIGNAL(valueChanged(float)),
Chris@474 2963 this, SLOT(mainModelGainChanged(float)));
Chris@474 2964 }
Chris@474 2965 }
Chris@474 2966
Chris@474 2967 void
Chris@474 2968 MainWindow::mainModelGainChanged(float gain)
Chris@474 2969 {
Chris@474 2970 if (m_playTarget) {
Chris@474 2971 m_playTarget->setOutputGain(gain);
Chris@479 2972 } else if (m_audioIO) {
Chris@479 2973 m_audioIO->setOutputGain(gain);
Chris@0 2974 }
Chris@259 2975 }
Chris@259 2976
Chris@259 2977 void
Chris@323 2978 MainWindow::analyseNow()
Chris@323 2979 {
Chris@323 2980 cerr << "analyseNow called" << endl;
Chris@325 2981 if (!m_analyser) return;
Chris@325 2982
Chris@325 2983 CommandHistory::getInstance()->startCompoundOperation
Chris@325 2984 (tr("Analyse Audio"), true);
Chris@325 2985
Chris@325 2986 QString error = m_analyser->analyseExistingFile();
Chris@325 2987
Chris@325 2988 CommandHistory::getInstance()->endCompoundOperation();
Chris@325 2989
Chris@325 2990 if (error != "") {
Chris@325 2991 QMessageBox::warning
Chris@325 2992 (this,
Chris@325 2993 tr("Failed to analyse audio"),
Chris@325 2994 tr("<b>Analysis failed</b><p>%1</p>").arg(error),
Chris@325 2995 QMessageBox::Ok);
Chris@325 2996 }
Chris@323 2997 }
Chris@323 2998
Chris@323 2999 void
Chris@259 3000 MainWindow::analyseNewMainModel()
Chris@259 3001 {
Chris@259 3002 WaveFileModel *model = getMainModel();
Chris@260 3003
Chris@260 3004 cerr << "MainWindow::analyseNewMainModel: main model is " << model << endl;
Chris@260 3005
Chris@260 3006 cerr << "(document is " << m_document << ", it says main model is " << m_document->getMainModel() << ")" << endl;
Chris@259 3007
Chris@324 3008 if (!model) {
Chris@324 3009 cerr << "no main model!" << endl;
Chris@324 3010 return;
Chris@324 3011 }
Chris@324 3012
Chris@324 3013 if (!m_paneStack) {
Chris@324 3014 cerr << "no pane stack!" << endl;
Chris@324 3015 return;
Chris@324 3016 }
Chris@324 3017
Chris@324 3018 int pc = m_paneStack->getPaneCount();
Chris@324 3019 Pane *pane = 0;
Chris@324 3020 Pane *selectionStrip = 0;
Chris@324 3021
Chris@324 3022 if (pc < 2) {
Chris@324 3023 pane = m_paneStack->addPane();
Chris@324 3024 selectionStrip = m_paneStack->addPane();
Chris@324 3025 m_document->addLayerToView
Chris@324 3026 (selectionStrip,
Chris@324 3027 m_document->createMainModelLayer(LayerFactory::TimeRuler));
Chris@324 3028 } else {
Chris@324 3029 pane = m_paneStack->getPane(0);
Chris@324 3030 selectionStrip = m_paneStack->getPane(1);
Chris@324 3031 }
Chris@324 3032
Chris@362 3033 pane->setPlaybackFollow(PlaybackScrollPage);
Chris@362 3034
Chris@324 3035 if (selectionStrip) {
Chris@362 3036 selectionStrip->setPlaybackFollow(PlaybackScrollPage);
Chris@324 3037 selectionStrip->setFixedHeight(26);
Chris@324 3038 m_paneStack->sizePanesEqually();
Chris@324 3039 m_viewManager->clearToolModeOverrides();
Chris@324 3040 m_viewManager->setToolModeFor(selectionStrip,
Chris@324 3041 ViewManager::SelectMode);
Chris@324 3042 }
Chris@324 3043
Chris@324 3044 if (pane) {
Chris@324 3045
Chris@324 3046 disconnect(pane, SIGNAL(regionOutlined(QRect)),
Chris@324 3047 pane, SLOT(zoomToRegion(QRect)));
Chris@324 3048 connect(pane, SIGNAL(regionOutlined(QRect)),
Chris@324 3049 this, SLOT(regionOutlined(QRect)));
Chris@324 3050
Chris@324 3051 QString error = m_analyser->newFileLoaded
Chris@324 3052 (m_document, getMainModel(), m_paneStack, pane);
Chris@324 3053 if (error != "") {
Chris@324 3054 QMessageBox::warning
Chris@324 3055 (this,
Chris@324 3056 tr("Failed to analyse audio"),
Chris@324 3057 tr("<b>Analysis failed</b><p>%1</p>").arg(error),
Chris@324 3058 QMessageBox::Ok);
Chris@72 3059 }
Chris@72 3060 }
matthiasm@366 3061
matthiasm@366 3062 if (!m_withSpectrogram)
matthiasm@366 3063 {
matthiasm@366 3064 m_analyser->setVisible(Analyser::Spectrogram, false);
matthiasm@366 3065 }
matthiasm@366 3066
matthiasm@366 3067 if (!m_withSonification)
matthiasm@366 3068 {
matthiasm@366 3069 m_analyser->setAudible(Analyser::PitchTrack, false);
matthiasm@366 3070 m_analyser->setAudible(Analyser::Notes, false);
matthiasm@366 3071 }
Chris@419 3072
Chris@419 3073 updateLayerStatuses();
Chris@487 3074 documentRestored();
Chris@0 3075 }
Chris@0 3076
Chris@0 3077 void
Chris@0 3078 MainWindow::modelGenerationFailed(QString transformName, QString message)
Chris@0 3079 {
Chris@0 3080 if (message != "") {
Chris@0 3081
Chris@0 3082 QMessageBox::warning
Chris@0 3083 (this,
Chris@0 3084 tr("Failed to generate layer"),
Chris@0 3085 tr("<b>Layer generation failed</b><p>Failed to generate derived layer.<p>The layer transform \"%1\" failed:<p>%2")
Chris@0 3086 .arg(transformName).arg(message),
Chris@0 3087 QMessageBox::Ok);
Chris@0 3088 } else {
Chris@0 3089 QMessageBox::warning
Chris@0 3090 (this,
Chris@0 3091 tr("Failed to generate layer"),
Chris@0 3092 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.")
Chris@0 3093 .arg(transformName),
Chris@0 3094 QMessageBox::Ok);
Chris@0 3095 }
Chris@0 3096 }
Chris@0 3097
Chris@0 3098 void
Chris@355 3099 MainWindow::modelGenerationWarning(QString /* transformName */, QString message)
Chris@0 3100 {
Chris@0 3101 QMessageBox::warning
Chris@0 3102 (this, tr("Warning"), message, QMessageBox::Ok);
Chris@0 3103 }
Chris@0 3104
Chris@0 3105 void
Chris@0 3106 MainWindow::modelRegenerationFailed(QString layerName,
Chris@399 3107 QString transformName,
Chris@399 3108 QString message)
Chris@0 3109 {
Chris@0 3110 if (message != "") {
Chris@0 3111
Chris@0 3112 QMessageBox::warning
Chris@0 3113 (this,
Chris@0 3114 tr("Failed to regenerate layer"),
Chris@0 3115 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")
Chris@0 3116 .arg(layerName).arg(transformName).arg(message),
Chris@0 3117 QMessageBox::Ok);
Chris@0 3118 } else {
Chris@0 3119 QMessageBox::warning
Chris@0 3120 (this,
Chris@0 3121 tr("Failed to regenerate layer"),
Chris@0 3122 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.")
Chris@0 3123 .arg(layerName).arg(transformName),
Chris@0 3124 QMessageBox::Ok);
Chris@0 3125 }
Chris@0 3126 }
Chris@0 3127
Chris@0 3128 void
Chris@0 3129 MainWindow::modelRegenerationWarning(QString layerName,
Chris@355 3130 QString /* transformName */,
Chris@355 3131 QString message)
Chris@0 3132 {
Chris@0 3133 QMessageBox::warning
Chris@0 3134 (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);
Chris@0 3135 }
Chris@0 3136
Chris@0 3137 void
Chris@0 3138 MainWindow::alignmentFailed(QString transformName, QString message)
Chris@0 3139 {
Chris@0 3140 QMessageBox::warning
Chris@0 3141 (this,
Chris@0 3142 tr("Failed to calculate alignment"),
Chris@0 3143 tr("<b>Alignment calculation failed</b><p>Failed to calculate an audio alignment using transform \"%1\":<p>%2")
Chris@0 3144 .arg(transformName).arg(message),
Chris@0 3145 QMessageBox::Ok);
Chris@0 3146 }
Chris@0 3147
Chris@0 3148 void
Chris@0 3149 MainWindow::rightButtonMenuRequested(Pane *pane, QPoint position)
Chris@0 3150 {
Chris@70 3151 // cerr << "MainWindow::rightButtonMenuRequested(" << pane << ", " << position.x() << ", " << position.y() << ")" << endl;
Chris@0 3152 m_paneStack->setCurrentPane(pane);
Chris@0 3153 m_rightButtonMenu->popup(position);
Chris@0 3154 }
Chris@0 3155
Chris@0 3156 void
Chris@355 3157 MainWindow::handleOSCMessage(const OSCMessage &)
Chris@0 3158 {
Chris@70 3159 cerr << "MainWindow::handleOSCMessage: Not implemented" << endl;
Chris@0 3160 }
Chris@0 3161
Chris@0 3162 void
Chris@0 3163 MainWindow::mouseEnteredWidget()
Chris@0 3164 {
Chris@3 3165 QWidget *w = qobject_cast<QWidget *>(sender());
Chris@0 3166 if (!w) return;
Chris@0 3167
Chris@0 3168 if (w == m_fader) {
Chris@0 3169 contextHelpChanged(tr("Adjust the master playback level"));
Chris@0 3170 } else if (w == m_playSpeed) {
Chris@0 3171 contextHelpChanged(tr("Adjust the master playback speed"));
Chris@0 3172 } else if (w == m_playSharpen && w->isEnabled()) {
Chris@0 3173 contextHelpChanged(tr("Toggle transient sharpening for playback time scaling"));
Chris@0 3174 } else if (w == m_playMono && w->isEnabled()) {
Chris@0 3175 contextHelpChanged(tr("Toggle mono mode for playback time scaling"));
Chris@0 3176 }
Chris@0 3177 }
Chris@0 3178
Chris@0 3179 void
Chris@0 3180 MainWindow::mouseLeftWidget()
Chris@0 3181 {
Chris@0 3182 contextHelpChanged("");
Chris@0 3183 }
Chris@0 3184
Chris@0 3185 void
Chris@0 3186 MainWindow::website()
Chris@0 3187 {
Chris@4 3188 //!!! todo: URL!
Chris@4 3189 openHelpUrl(tr("http://code.soundsoftware.ac.uk/projects/tony/"));
Chris@0 3190 }
Chris@0 3191
Chris@0 3192 void
Chris@0 3193 MainWindow::help()
Chris@0 3194 {
Chris@4 3195 //!!! todo: help URL!
matthiasm@369 3196 openHelpUrl(tr("http://code.soundsoftware.ac.uk/projects/tony/wiki/Reference"));
Chris@0 3197 }
Chris@0 3198
Chris@0 3199 void
Chris@0 3200 MainWindow::about()
Chris@0 3201 {
Chris@0 3202 bool debug = false;
Chris@0 3203 QString version = "(unknown version)";
Chris@0 3204
Chris@0 3205 #ifdef BUILD_DEBUG
Chris@0 3206 debug = true;
Chris@0 3207 #endif
Chris@0 3208 version = tr("Release %1").arg(TONY_VERSION);
Chris@0 3209
Chris@0 3210 QString aboutText;
Chris@0 3211
Chris@0 3212 aboutText += tr("<h3>About Tony</h3>");
Chris@0 3213 aboutText += tr("<p>Tony is a program for interactive note and pitch analysis and annotation.</p>");
Chris@0 3214 aboutText += tr("<p>%1 : %2 configuration</p>")
Chris@0 3215 .arg(version)
Chris@0 3216 .arg(debug ? tr("Debug") : tr("Release"));
Chris@212 3217 aboutText += tr("<p>Using Qt framework version %1.</p>")
Chris@206 3218 .arg(QT_VERSION_STR);
Chris@0 3219
Chris@0 3220 aboutText +=
Chris@508 3221 "<p>Copyright &copy; 2005&ndash;2015 Chris Cannam, Queen Mary University of London, and the Tony project authors: Matthias Mauch, George Fazekas, Justin Salamon, and Rachel Bittner.</p>"
Chris@212 3222 "<p>pYIN analysis plugin written by Matthias Mauch.</p>"
Chris@90 3223 "<p>This program is free software; you can redistribute it and/or "
Chris@90 3224 "modify it under the terms of the GNU General Public License as "
Chris@90 3225 "published by the Free Software Foundation; either version 2 of the "
Chris@0 3226 "License, or (at your option) any later version.<br>See the file "
Chris@0 3227 "COPYING included with this distribution for more information.</p>";
Chris@0 3228
Chris@0 3229 QMessageBox::about(this, tr("About %1").arg(QApplication::applicationName()), aboutText);
Chris@0 3230 }
Chris@0 3231
Chris@0 3232 void
Chris@0 3233 MainWindow::keyReference()
Chris@0 3234 {
Chris@0 3235 m_keyReference->show();
Chris@0 3236 }
Chris@0 3237
Chris@231 3238 void
Chris@231 3239 MainWindow::newerVersionAvailable(QString version)
Chris@231 3240 {
Chris@231 3241 //!!! nicer URL would be nicer
Chris@231 3242 QSettings settings;
Chris@231 3243 settings.beginGroup("NewerVersionWarning");
Chris@231 3244 QString tag = QString("version-%1-available-show").arg(version);
Chris@231 3245 if (settings.value(tag, true).toBool()) {
Chris@231 3246 QString title(tr("Newer version available"));
Chris@231 3247 QString text(tr("<h3>Newer version available</h3><p>You are using version %1 of Tony, but version %2 is now available.</p><p>Please see the <a href=\"http://code.soundsoftware.ac.uk/projects/tony/\">Tony website</a> for more information.</p>").arg(TONY_VERSION).arg(version));
Chris@231 3248 QMessageBox::information(this, title, text);
Chris@231 3249 settings.setValue(tag, false);
Chris@231 3250 }
Chris@231 3251 settings.endGroup();
Chris@231 3252 }
Chris@231 3253
matthiasm@356 3254 void
matthiasm@356 3255 MainWindow::ffwd()
matthiasm@356 3256 {
matthiasm@356 3257 if (!getMainModel()) return;
matthiasm@356 3258
Chris@403 3259 sv_frame_t frame = m_viewManager->getPlaybackFrame();
matthiasm@356 3260 ++frame;
matthiasm@356 3261
Chris@403 3262 sv_samplerate_t sr = getMainModel()->getSampleRate();
matthiasm@356 3263
matthiasm@356 3264 // The step is supposed to scale and be as wide as a step of
matthiasm@357 3265 // m_defaultFfwdRwdStep seconds at zoom level 720 and sr = 44100
Chris@403 3266 int framesPerPixel = m_viewManager->getGlobalZoom();
Chris@403 3267
Chris@403 3268 double defaultZoom = (720 * 44100) / sr;
Chris@403 3269 double scaler = framesPerPixel / defaultZoom;
Chris@403 3270 RealTime step = m_defaultFfwdRwdStep * scaler;
Chris@403 3271
matthiasm@356 3272 frame = RealTime::realTime2Frame
Chris@403 3273 (RealTime::frame2RealTime(frame, sr) + step, sr);
Chris@403 3274
Chris@403 3275 if (frame > getMainModel()->getEndFrame()) {
matthiasm@356 3276 frame = getMainModel()->getEndFrame();
matthiasm@356 3277 }
Chris@403 3278
matthiasm@356 3279 if (frame < 0) frame = 0;
matthiasm@356 3280
matthiasm@356 3281 if (m_viewManager->getPlaySelectionMode()) {
Chris@403 3282 frame = m_viewManager->constrainFrameToSelection(frame);
matthiasm@356 3283 }
matthiasm@356 3284
matthiasm@356 3285 m_viewManager->setPlaybackFrame(frame);
matthiasm@356 3286
Chris@403 3287 if (frame == getMainModel()->getEndFrame() &&
matthiasm@356 3288 m_playSource &&
matthiasm@356 3289 m_playSource->isPlaying() &&
matthiasm@356 3290 !m_viewManager->getPlayLoopMode()) {
matthiasm@356 3291 stop();
matthiasm@356 3292 }
matthiasm@356 3293 }
matthiasm@356 3294
matthiasm@356 3295 void
matthiasm@356 3296 MainWindow::rewind()
matthiasm@356 3297 {
matthiasm@356 3298 if (!getMainModel()) return;
matthiasm@356 3299
Chris@403 3300 sv_frame_t frame = m_viewManager->getPlaybackFrame();
matthiasm@356 3301 if (frame > 0) --frame;
matthiasm@356 3302
Chris@403 3303 sv_samplerate_t sr = getMainModel()->getSampleRate();
matthiasm@356 3304
matthiasm@356 3305 // The step is supposed to scale and be as wide as a step of
matthiasm@357 3306 // m_defaultFfwdRwdStep seconds at zoom level 720 and sr = 44100
Chris@403 3307 int framesPerPixel = m_viewManager->getGlobalZoom();
Chris@403 3308
Chris@403 3309 double defaultZoom = (720 * 44100) / sr;
Chris@403 3310 double scaler = framesPerPixel / defaultZoom;
Chris@403 3311 RealTime step = m_defaultFfwdRwdStep * scaler;
Chris@403 3312
matthiasm@356 3313 frame = RealTime::realTime2Frame
Chris@403 3314 (RealTime::frame2RealTime(frame, sr) - step, sr);
Chris@403 3315
Chris@403 3316 if (frame < getMainModel()->getStartFrame()) {
matthiasm@356 3317 frame = getMainModel()->getStartFrame();
matthiasm@356 3318 }
matthiasm@356 3319
matthiasm@356 3320 if (frame < 0) frame = 0;
matthiasm@356 3321
matthiasm@356 3322 if (m_viewManager->getPlaySelectionMode()) {
Chris@403 3323 frame = m_viewManager->constrainFrameToSelection(frame);
matthiasm@356 3324 }
matthiasm@356 3325
matthiasm@356 3326 m_viewManager->setPlaybackFrame(frame);
matthiasm@356 3327 }