1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 2 3 /* 4 Sonic Visualiser 5 An audio file viewer and annotation editor. 6 Centre for Digital Music, Queen Mary, University of London. 7 This file copyright 2006-2007 Chris Cannam and QMUL. 8 9 This program is free software; you can redistribute it and/or 10 modify it under the terms of the GNU General Public License as 11 published by the Free Software Foundation; either version 2 of the 12 License, or (at your option) any later version. See the file 13 COPYING included with this distribution for more information. 14 */ 15 16 #ifndef SV_MAIN_WINDOW_BASE_H 17 #define SV_MAIN_WINDOW_BASE_H 18 19 #include <QFrame> 20 #include <QString> 21 #include <QUrl> 22 #include <QMainWindow> 23 #include <QPointer> 24 #include <QThread> 25 26 #include "base/Command.h" 27 #include "view/ViewManager.h" 28 #include "view/PaneStack.h" 29 #include "base/PropertyContainer.h" 30 #include "base/RecentFiles.h" 31 #include "base/FrameTimer.h" 32 #include "layer/LayerFactory.h" 33 #include "transform/Transform.h" 34 #include "SVFileReader.h" 35 #include "data/fileio/FileFinder.h" 36 #include "data/fileio/FileSource.h" 37 #include "data/osc/OSCQueue.h" 38 #include "data/osc/OSCMessageCallback.h" 39 #include "data/model/Model.h" 40 41 #include <map> 42 43 class Document; 44 class PaneStack; 45 class Pane; 46 class View; 47 class Fader; 48 class Overview; 49 class Layer; 50 class WaveformLayer; 51 class WaveFileModel; 52 class AudioCallbackPlaySource; 53 class AudioCallbackRecordTarget; 54 class CommandHistory; 55 class QMenu; 56 class AudioDial; 57 class LevelPanWidget; 58 class LevelPanToolButton; 59 class QLabel; 60 class QCheckBox; 61 class PreferencesDialog; 62 class QTreeView; 63 class QPushButton; 64 class OSCMessage; 65 class OSCScript; 66 class MIDIInput; 67 class KeyReference; 68 class Labeller; 69 class ModelDataTableDialog; 70 class QSignalMapper; 71 class QShortcut; 72 class AlignmentModel; 73 74 namespace breakfastquay { 75 class SystemPlaybackTarget; 76 class SystemAudioIO; 77 class ResamplerWrapper; 78 } 79 80 /** 81 * The base class for the SV main window. This includes everything to 82 * do with general document and pane stack management, but nothing 83 * that involves user interaction -- this doesn't create the widget or 84 * menu structures or editing tools, and if a function needs to open a 85 * dialog, it shouldn't be in here. This permits "variations on SV" 86 * to use different subclasses retaining the same general structure. 87 */ 88 89 class MainWindowBase : public QMainWindow, 90 public FrameTimer, 91 public OSCMessageCallback 92 { 93 Q_OBJECT 94 95 public: 96 /** 97 * Determine what kind of audio device to open when the first 98 * model is loaded or record() is called. 99 */ 100 enum AudioMode { 101 102 /// Open no audio device, ever 103 AUDIO_NONE, 104 105 /// Open for playback, never for recording 106 AUDIO_PLAYBACK_ONLY, 107 108 /// Open for playback when model loaded, switch to I/O if record called 109 AUDIO_PLAYBACK_NOW_RECORD_LATER, 110 111 /// Open for I/O as soon as model loaded or record called 112 AUDIO_PLAYBACK_AND_RECORD 113 }; 114 115 /** 116 * Determine whether to open a MIDI input device. 117 */ 118 enum MIDIMode { 119 120 /// Open no MIDI device 121 MIDI_NONE, 122 123 /// Open a MIDI device and listen for MIDI input 124 MIDI_LISTEN 125 }; 126 127 MainWindowBase(AudioMode audioMode, MIDIMode midiMode, 128 PaneStack::Options paneStackOptions); 129 virtual ~MainWindowBase(); 130 131 enum AudioFileOpenMode { 132 ReplaceSession, 133 ReplaceMainModel, 134 CreateAdditionalModel, 135 ReplaceCurrentPane, 136 AskUser 137 }; 138 139 enum FileOpenStatus { 140 FileOpenSucceeded, 141 FileOpenFailed, 142 FileOpenCancelled, 143 FileOpenWrongMode // attempted to open layer when no main model present 144 }; 145 146 enum AudioRecordMode { 147 RecordReplaceSession, 148 RecordCreateAdditionalModel 149 }; 150 151 virtual FileOpenStatus open(FileSource source, AudioFileOpenMode = AskUser); 152 virtual FileOpenStatus openPath(QString fileOrUrl, AudioFileOpenMode = AskUser); 153 virtual FileOpenStatus openAudio(FileSource source, AudioFileOpenMode = AskUser, QString templateName = ""); 154 virtual FileOpenStatus openPlaylist(FileSource source, AudioFileOpenMode = AskUser); 155 virtual FileOpenStatus openLayer(FileSource source); 156 virtual FileOpenStatus openImage(FileSource source); 157 158 virtual FileOpenStatus openDirOfAudio(QString dirPath); 159 160 virtual FileOpenStatus openSession(FileSource source); 161 virtual FileOpenStatus openSessionPath(QString fileOrUrl); 162 virtual FileOpenStatus openSessionTemplate(QString templateName); 163 virtual FileOpenStatus openSessionTemplate(FileSource source); 164 165 virtual bool saveSessionFile(QString path); 166 virtual bool saveSessionTemplate(QString path); 167 168 virtual bool exportLayerTo(Layer *layer, QString path, QString &error); 169 170 void cueOSCScript(QString filename); 171 172 /// Implementation of FrameTimer interface method 173 sv_frame_t getFrame() const override; 174 setDefaultFfwdRwdStep(RealTime step)175 void setDefaultFfwdRwdStep(RealTime step) { 176 m_defaultFfwdRwdStep = step; 177 } 178 setAudioRecordMode(AudioRecordMode mode)179 void setAudioRecordMode(AudioRecordMode mode) { 180 m_audioRecordMode = mode; 181 } 182 183 signals: 184 // Used to toggle the availability of menu actions 185 void canAddPane(bool); 186 void canDeleteCurrentPane(bool); 187 void canAddLayer(bool); 188 void canImportMoreAudio(bool); 189 void canReplaceMainAudio(bool); 190 void canImportLayer(bool); 191 void canChangeSessionTemplate(bool); 192 void canExportAudio(bool); 193 void canExportLayer(bool); 194 void canExportImage(bool); 195 void canRenameLayer(bool); 196 void canEditLayer(bool); 197 void canEditLayerTabular(bool); 198 void canMeasureLayer(bool); 199 void canSelect(bool); 200 void canClearSelection(bool); 201 void canEditSelection(bool); 202 void canDeleteSelection(bool); 203 void canPaste(bool); 204 void canInsertInstant(bool); 205 void canInsertInstantsAtBoundaries(bool); 206 void canInsertItemAtSelection(bool); 207 void canRenumberInstants(bool); 208 void canSubdivideInstants(bool); 209 void canWinnowInstants(bool); 210 void canDeleteCurrentLayer(bool); 211 void canZoom(bool); 212 void canScroll(bool); 213 void canPlay(bool); 214 void canRecord(bool); 215 void canFfwd(bool); 216 void canRewind(bool); 217 void canPlaySelection(bool); 218 void canSpeedUpPlayback(bool); 219 void canSlowDownPlayback(bool); 220 void canChangePlaybackSpeed(bool); 221 void canSelectPreviousPane(bool); 222 void canSelectNextPane(bool); 223 void canSelectPreviousLayer(bool); 224 void canSelectNextLayer(bool); 225 void canSave(bool); 226 void canSaveAs(bool); 227 void hideSplash(); 228 void hideSplash(QWidget *); 229 void sessionLoaded(); 230 void audioFileLoaded(); 231 void replacedDocument(); 232 void activity(QString); 233 234 public slots: 235 virtual void preferenceChanged(PropertyContainer::PropertyName); 236 virtual void resizeConstrained(QSize); 237 virtual void recreateAudioIO(); 238 239 protected slots: 240 virtual void zoomIn(); 241 virtual void zoomOut(); 242 virtual void zoomToFit(); 243 virtual void zoomDefault(); 244 virtual void scrollLeft(); 245 virtual void scrollRight(); 246 virtual void jumpLeft(); 247 virtual void jumpRight(); 248 virtual void peekLeft(); 249 virtual void peekRight(); 250 251 virtual void showNoOverlays(); 252 virtual void showMinimalOverlays(); 253 virtual void showAllOverlays(); 254 255 virtual void toggleTimeRulers(); 256 virtual void toggleZoomWheels(); 257 virtual void togglePropertyBoxes(); 258 virtual void toggleStatusBar(); 259 virtual void toggleCentreLine(); 260 261 virtual void play(); 262 virtual void ffwd(); 263 virtual void ffwdEnd(); 264 virtual void rewind(); 265 virtual void rewindStart(); 266 virtual void record(); 267 virtual void stop(); 268 269 virtual void ffwdSimilar(); 270 virtual void rewindSimilar(); 271 272 virtual void deleteCurrentPane(); 273 virtual void deleteCurrentLayer(); 274 virtual void editCurrentLayer(); 275 276 virtual void previousPane(); 277 virtual void nextPane(); 278 virtual void previousLayer(); 279 virtual void nextLayer(); 280 281 virtual void playLoopToggled(); 282 virtual void playSelectionToggled(); 283 virtual void playSoloToggled(); 284 285 virtual void audioChannelCountIncreased(int count); 286 287 virtual void sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool) = 0; 288 virtual void audioOverloadPluginDisabled() = 0; 289 virtual void audioTimeStretchMultiChannelDisabled() = 0; 290 291 virtual void playbackFrameChanged(sv_frame_t); 292 virtual void globalCentreFrameChanged(sv_frame_t); 293 virtual void viewCentreFrameChanged(View *, sv_frame_t); 294 virtual void viewZoomLevelChanged(View *, ZoomLevel, bool); 295 virtual void monitoringLevelsChanged(float, float) = 0; 296 virtual void recordDurationChanged(sv_frame_t, sv_samplerate_t); 297 298 virtual void currentPaneChanged(Pane *); 299 virtual void currentLayerChanged(Pane *, Layer *); 300 301 virtual void selectAll(); 302 virtual void selectToStart(); 303 virtual void selectToEnd(); 304 virtual void selectVisible(); 305 virtual void clearSelection(); 306 307 virtual void cut(); 308 virtual void copy(); 309 virtual void paste(); 310 virtual void pasteAtPlaybackPosition(); 311 virtual void pasteRelative(sv_frame_t offset); 312 virtual void deleteSelected(); 313 314 virtual void insertInstant(); 315 virtual void insertInstantAt(sv_frame_t); 316 virtual void insertInstantsAtBoundaries(); 317 virtual void insertItemAtSelection(); 318 virtual void insertItemAt(sv_frame_t, sv_frame_t); 319 virtual void renumberInstants(); 320 virtual void subdivideInstantsBy(int); 321 virtual void winnowInstantsBy(int); 322 323 virtual void documentModified(); 324 virtual void documentRestored(); 325 326 virtual void layerAdded(Layer *); 327 virtual void layerRemoved(Layer *); 328 virtual void layerAboutToBeDeleted(Layer *); 329 virtual void layerInAView(Layer *, bool); 330 331 virtual void mainModelChanged(ModelId); 332 virtual void modelAdded(ModelId); 333 334 virtual void updateMenuStates(); 335 virtual void updateDescriptionLabel() = 0; 336 virtual void updateWindowTitle(); 337 338 virtual void modelGenerationFailed(QString, QString) = 0; 339 virtual void modelGenerationWarning(QString, QString) = 0; 340 virtual void modelRegenerationFailed(QString, QString, QString) = 0; 341 virtual void modelRegenerationWarning(QString, QString, QString) = 0; 342 343 virtual void alignmentComplete(ModelId); 344 virtual void alignmentFailed(QString) = 0; 345 346 virtual void rightButtonMenuRequested(Pane *, QPoint point) = 0; 347 348 virtual void paneAdded(Pane *) = 0; 349 virtual void paneHidden(Pane *) = 0; 350 virtual void paneAboutToBeDeleted(Pane *) = 0; 351 virtual void paneDropAccepted(Pane *, QStringList) = 0; 352 virtual void paneDropAccepted(Pane *, QString) = 0; 353 virtual void paneDeleteButtonClicked(Pane *); 354 355 virtual void oscReady(); 356 virtual void pollOSC(); 357 virtual void oscScriptFinished(); 358 359 virtual void contextHelpChanged(const QString &); 360 virtual void inProgressSelectionChanged(); 361 362 virtual FileOpenStatus openSessionFromRDF(FileSource source); 363 virtual FileOpenStatus openLayersFromRDF(FileSource source); 364 365 virtual void closeSession() = 0; 366 367 virtual void emitHideSplash(); 368 newerVersionAvailable(QString)369 virtual void newerVersionAvailable(QString) { } 370 371 virtual void menuActionMapperInvoked(QObject *); 372 373 protected: 374 QString m_sessionFile; 375 QString m_audioFile; 376 Document *m_document; 377 378 // This is used in the window title. It's the upstream location 379 // (maybe a URL) the user provided as source of the main model. It 380 // should be set in cases where there is no current session file 381 // and m_sessionFile is empty, or where a new main model has been 382 // imported into an existing session. It should be used only for 383 // user presentation, never parsed - treat it as an opaque label 384 QString m_originalLocation; 385 386 PaneStack *m_paneStack; 387 ViewManager *m_viewManager; 388 Layer *m_timeRulerLayer; 389 390 AudioMode m_audioMode; 391 MIDIMode m_midiMode; 392 393 AudioCallbackPlaySource *m_playSource; 394 AudioCallbackRecordTarget *m_recordTarget; 395 breakfastquay::ResamplerWrapper *m_resamplerWrapper; 396 breakfastquay::SystemPlaybackTarget *m_playTarget; // only one of this... 397 breakfastquay::SystemAudioIO *m_audioIO; // ... and this exists 398 399 class OSCQueueStarter : public QThread 400 { 401 public: OSCQueueStarter(MainWindowBase * mwb,bool withNetworkPort)402 OSCQueueStarter(MainWindowBase *mwb, bool withNetworkPort) : 403 QThread(mwb), m_mwb(mwb), m_withPort(withNetworkPort) { } 404 run()405 void run() override { 406 // NB creating the queue object can take a long time 407 OSCQueue *queue = new OSCQueue(m_withPort); 408 m_mwb->m_oscQueue = queue; 409 } 410 411 private: 412 MainWindowBase *m_mwb; 413 bool m_withPort; 414 }; 415 416 OSCQueue *m_oscQueue; 417 OSCQueueStarter *m_oscQueueStarter; 418 OSCScript *m_oscScript; 419 QString m_oscScriptFile; 420 421 void startOSCQueue(bool withNetworkPort); 422 void startOSCScript(); 423 424 MIDIInput *m_midiInput; 425 426 RecentFiles m_recentFiles; 427 RecentFiles m_recentTransforms; 428 429 bool m_documentModified; 430 bool m_openingAudioFile; 431 bool m_abandoning; 432 433 Labeller *m_labeller; 434 435 int m_lastPlayStatusSec; 436 mutable QString m_myStatusMessage; 437 438 bool m_initialDarkBackground; 439 440 RealTime m_defaultFfwdRwdStep; 441 442 AudioRecordMode m_audioRecordMode; 443 444 mutable QLabel *m_statusLabel; 445 QLabel *getStatusLabel() const; 446 447 ModelId getMainModelId() const; 448 std::shared_ptr<WaveFileModel> getMainModel() const; 449 void createDocument(); 450 451 FileOpenStatus addOpenedAudioModel(FileSource source, 452 ModelId model, 453 AudioFileOpenMode mode, 454 QString templateName, 455 bool registerSource); 456 457 sv_frame_t getModelsStartFrame() const; // earliest across all views 458 sv_frame_t getModelsEndFrame() const; // latest across all views 459 460 Pane *addPaneToStack(); 461 Layer *getSnapLayer() const; 462 463 typedef std::map<Layer *, QPointer<ModelDataTableDialog> > LayerDataDialogMap; 464 typedef std::set<QPointer<ModelDataTableDialog> > DataDialogSet; 465 typedef std::map<View *, DataDialogSet> ViewDataDialogMap; 466 467 LayerDataDialogMap m_layerDataDialogMap; 468 ViewDataDialogMap m_viewDataDialogMap; 469 470 void removeLayerEditDialog(Layer *); 471 472 class PaneCallback : public SVFileReaderPaneCallback 473 { 474 public: PaneCallback(MainWindowBase * mw)475 PaneCallback(MainWindowBase *mw) : m_mw(mw) { } addPane()476 Pane *addPane() override { return m_mw->addPaneToStack(); } setWindowSize(int width,int height)477 void setWindowSize(int width, int height) override { 478 m_mw->resizeConstrained(QSize(width, height)); 479 } addSelection(sv_frame_t start,sv_frame_t end)480 void addSelection(sv_frame_t start, sv_frame_t end) override { 481 m_mw->m_viewManager->addSelectionQuietly(Selection(start, end)); 482 } 483 protected: 484 MainWindowBase *m_mw; 485 }; 486 487 class AddPaneCommand : public Command 488 { 489 public: 490 AddPaneCommand(MainWindowBase *mw); 491 virtual ~AddPaneCommand(); 492 493 void execute() override; 494 void unexecute() override; 495 QString getName() const override; 496 getPane()497 Pane *getPane() { return m_pane; } 498 499 protected: 500 MainWindowBase *m_mw; 501 Pane *m_pane; // Main window owns this, but I determine its lifespan 502 Pane *m_prevCurrentPane; // I don't own this 503 bool m_added; 504 }; 505 506 class RemovePaneCommand : public Command 507 { 508 public: 509 RemovePaneCommand(MainWindowBase *mw, Pane *pane); 510 virtual ~RemovePaneCommand(); 511 512 void execute() override; 513 void unexecute() override; 514 QString getName() const override; 515 516 protected: 517 MainWindowBase *m_mw; 518 Pane *m_pane; // Main window owns this, but I determine its lifespan 519 Pane *m_prevCurrentPane; // I don't own this 520 bool m_added; 521 }; 522 523 virtual bool checkSaveModified() = 0; 524 525 virtual QString getOpenFileName(FileFinder::FileType type); 526 virtual QString getSaveFileName(FileFinder::FileType type); 527 virtual void registerLastOpenedFilePath(FileFinder::FileType type, QString path); 528 529 virtual QString getDefaultSessionTemplate() const; 530 virtual void setDefaultSessionTemplate(QString); 531 532 virtual void findTimeRulerLayer(); 533 534 virtual void createAudioIO(); 535 virtual void deleteAudioIO(); 536 537 virtual void openHelpUrl(QString url); 538 virtual void openLocalFolder(QString path); 539 540 virtual void setupMenus() = 0; 541 virtual void updateVisibleRangeDisplay(Pane *p) const = 0; 542 virtual void updatePositionStatusDisplays() const = 0; 543 544 // Call this after setting up the menu bar, to fix up single-key 545 // shortcuts on OS/X and do any other platform-specific tidying 546 virtual void finaliseMenus(); 547 virtual void finaliseMenu(QMenu *); 548 549 // Call before finaliseMenus if you wish to have a say in this question setIconsVisibleInMenus(bool visible)550 void setIconsVisibleInMenus(bool visible) { m_iconsVisibleInMenus = visible; } 551 bool m_iconsVisibleInMenus; 552 553 // Only used on OS/X to work around a Qt/Cocoa bug, see finaliseMenus 554 QSignalMapper *m_menuShortcutMapper; 555 QList<QShortcut *> m_appShortcuts; 556 shouldCreateNewSessionForRDFAudio(bool *)557 virtual bool shouldCreateNewSessionForRDFAudio(bool *) { return true; } 558 559 virtual void connectLayerEditDialog(ModelDataTableDialog *dialog); 560 561 virtual void toXml(QTextStream &stream, bool asTemplate); 562 }; 563 564 565 #endif 566