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