annotate src/MainWindow.cpp @ 390:09aaceb76251

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