comparison framework/MainWindowBase.cpp @ 482:01669adb0956 tony-2.0-integration

Merge through to branch for Tony 2.0
author Chris Cannam
date Thu, 20 Aug 2015 14:54:21 +0100
parents 52c0aff69478
children 01aeda073720 111e976f9ed4
comparison
equal deleted inserted replaced
448:b36042cb972a 482:01669adb0956
14 */ 14 */
15 15
16 #include "MainWindowBase.h" 16 #include "MainWindowBase.h"
17 #include "Document.h" 17 #include "Document.h"
18 18
19
20 #include "view/Pane.h" 19 #include "view/Pane.h"
21 #include "view/PaneStack.h" 20 #include "view/PaneStack.h"
22 #include "data/model/WaveFileModel.h" 21 #include "data/model/ReadOnlyWaveFileModel.h"
22 #include "data/model/WritableWaveFileModel.h"
23 #include "data/model/SparseOneDimensionalModel.h" 23 #include "data/model/SparseOneDimensionalModel.h"
24 #include "data/model/NoteModel.h" 24 #include "data/model/NoteModel.h"
25 #include "data/model/FlexiNoteModel.h" 25 #include "data/model/FlexiNoteModel.h"
26 #include "data/model/Labeller.h" 26 #include "data/model/Labeller.h"
27 #include "data/model/TabularModel.h" 27 #include "data/model/TabularModel.h"
45 #include "widgets/MIDIFileImportDialog.h" 45 #include "widgets/MIDIFileImportDialog.h"
46 #include "widgets/CSVFormatDialog.h" 46 #include "widgets/CSVFormatDialog.h"
47 #include "widgets/ModelDataTableDialog.h" 47 #include "widgets/ModelDataTableDialog.h"
48 #include "widgets/InteractiveFileFinder.h" 48 #include "widgets/InteractiveFileFinder.h"
49 49
50 #include "audioio/AudioCallbackPlaySource.h" 50 #include "audio/AudioCallbackPlaySource.h"
51 #include "audioio/AudioCallbackPlayTarget.h" 51 #include "audio/AudioRecordTarget.h"
52 #include "audioio/AudioTargetFactory.h" 52 #include "audio/PlaySpeedRangeMapper.h"
53 #include "audioio/PlaySpeedRangeMapper.h" 53
54 #include "data/fileio/DataFileReaderFactory.h" 54 #include "data/fileio/DataFileReaderFactory.h"
55 #include "data/fileio/PlaylistFileReader.h" 55 #include "data/fileio/PlaylistFileReader.h"
56 #include "data/fileio/WavFileWriter.h" 56 #include "data/fileio/WavFileWriter.h"
57 #include "data/fileio/MIDIFileWriter.h" 57 #include "data/fileio/MIDIFileWriter.h"
58 #include "data/fileio/BZipFileDevice.h" 58 #include "data/fileio/BZipFileDevice.h"
59 #include "data/fileio/FileSource.h" 59 #include "data/fileio/FileSource.h"
60 #include "data/fileio/AudioFileReaderFactory.h" 60 #include "data/fileio/AudioFileReaderFactory.h"
61 #include "rdf/RDFImporter.h" 61 #include "rdf/RDFImporter.h"
62 62
63 #include "data/fft/FFTDataServer.h"
64
65 #include "base/RecentFiles.h" 63 #include "base/RecentFiles.h"
66 64
67 #include "base/PlayParameterRepository.h" 65 #include "base/PlayParameterRepository.h"
68 #include "base/XmlExportable.h" 66 #include "base/XmlExportable.h"
69 #include "base/Profiler.h" 67 #include "base/Profiler.h"
72 #include "base/Exceptions.h" 70 #include "base/Exceptions.h"
73 #include "base/ResourceFinder.h" 71 #include "base/ResourceFinder.h"
74 72
75 #include "data/osc/OSCQueue.h" 73 #include "data/osc/OSCQueue.h"
76 #include "data/midi/MIDIInput.h" 74 #include "data/midi/MIDIInput.h"
75
76 #include <bqaudioio/SystemPlaybackTarget.h>
77 #include <bqaudioio/SystemAudioIO.h>
78 #include <bqaudioio/AudioFactory.h>
77 79
78 #include <QApplication> 80 #include <QApplication>
79 #include <QMessageBox> 81 #include <QMessageBox>
80 #include <QGridLayout> 82 #include <QGridLayout>
81 #include <QLabel> 83 #include <QLabel>
129 return 0; 131 return 0;
130 } 132 }
131 #undef Window 133 #undef Window
132 #endif 134 #endif
133 135
134 MainWindowBase::MainWindowBase(bool withAudioOutput, 136 MainWindowBase::MainWindowBase(SoundOptions options) :
135 bool withMIDIInput) :
136 m_document(0), 137 m_document(0),
137 m_paneStack(0), 138 m_paneStack(0),
138 m_viewManager(0), 139 m_viewManager(0),
139 m_timeRulerLayer(0), 140 m_timeRulerLayer(0),
140 m_audioOutput(withAudioOutput), 141 m_soundOptions(options),
141 m_playSource(0), 142 m_playSource(0),
143 m_recordTarget(0),
142 m_playTarget(0), 144 m_playTarget(0),
145 m_audioIO(0),
143 m_oscQueue(0), 146 m_oscQueue(0),
144 m_oscQueueStarter(0), 147 m_oscQueueStarter(0),
145 m_midiInput(0), 148 m_midiInput(0),
146 m_recentFiles("RecentFiles", 20), 149 m_recentFiles("RecentFiles", 20),
147 m_recentTransforms("RecentTransforms", 20), 150 m_recentTransforms("RecentTransforms", 20),
155 m_statusLabel(0), 158 m_statusLabel(0),
156 m_menuShortcutMapper(0) 159 m_menuShortcutMapper(0)
157 { 160 {
158 Profiler profiler("MainWindowBase::MainWindowBase"); 161 Profiler profiler("MainWindowBase::MainWindowBase");
159 162
163 if (options & WithAudioInput) {
164 if (!(options & WithAudioOutput)) {
165 cerr << "WARNING: MainWindowBase: WithAudioInput requires WithAudioOutput -- recording will not work" << endl;
166 }
167 }
168
160 qRegisterMetaType<sv_frame_t>("sv_frame_t"); 169 qRegisterMetaType<sv_frame_t>("sv_frame_t");
161 qRegisterMetaType<sv_samplerate_t>("sv_samplerate_t"); 170 qRegisterMetaType<sv_samplerate_t>("sv_samplerate_t");
162 171
163 #ifdef Q_WS_X11 172 #ifdef Q_WS_X11
164 XSetErrorHandler(handle_x11_error); 173 XSetErrorHandler(handle_x11_error);
165 #endif 174 #endif
166 175
176 connect(this, SIGNAL(hideSplash()), this, SLOT(emitHideSplash()));
177
167 connect(CommandHistory::getInstance(), SIGNAL(commandExecuted()), 178 connect(CommandHistory::getInstance(), SIGNAL(commandExecuted()),
168 this, SLOT(documentModified())); 179 this, SLOT(documentModified()));
169 connect(CommandHistory::getInstance(), SIGNAL(documentRestored()), 180 connect(CommandHistory::getInstance(), SIGNAL(documentRestored()),
170 this, SLOT(documentRestored())); 181 this, SLOT(documentRestored()));
171 182
214 connect(m_paneStack, SIGNAL(paneDeleteButtonClicked(Pane *)), 225 connect(m_paneStack, SIGNAL(paneDeleteButtonClicked(Pane *)),
215 this, SLOT(paneDeleteButtonClicked(Pane *))); 226 this, SLOT(paneDeleteButtonClicked(Pane *)));
216 227
217 m_playSource = new AudioCallbackPlaySource(m_viewManager, 228 m_playSource = new AudioCallbackPlaySource(m_viewManager,
218 QApplication::applicationName()); 229 QApplication::applicationName());
230 if (m_soundOptions & WithAudioInput) {
231 m_recordTarget = new AudioRecordTarget(m_viewManager,
232 QApplication::applicationName());
233 }
219 234
220 connect(m_playSource, SIGNAL(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool)), 235 connect(m_playSource, SIGNAL(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool)),
221 this, SLOT(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool))); 236 this, SLOT(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool)));
222 connect(m_playSource, SIGNAL(audioOverloadPluginDisabled()), 237 connect(m_playSource, SIGNAL(audioOverloadPluginDisabled()),
223 this, SLOT(audioOverloadPluginDisabled())); 238 this, SLOT(audioOverloadPluginDisabled()));
254 settings.endGroup(); 269 settings.endGroup();
255 270
256 m_labeller = new Labeller(labellerType); 271 m_labeller = new Labeller(labellerType);
257 m_labeller->setCounterCycleSize(cycle); 272 m_labeller->setCounterCycleSize(cycle);
258 273
259 if (withMIDIInput) { 274 if (m_soundOptions & WithMIDIInput) {
260 m_midiInput = new MIDIInput(QApplication::applicationName(), this); 275 m_midiInput = new MIDIInput(QApplication::applicationName(), this);
261 } 276 }
277
278 QTimer::singleShot(1500, this, SIGNAL(hideSplash()));
262 } 279 }
263 280
264 MainWindowBase::~MainWindowBase() 281 MainWindowBase::~MainWindowBase()
265 { 282 {
266 SVDEBUG << "MainWindowBase::~MainWindowBase" << endl; 283 SVDEBUG << "MainWindowBase::~MainWindowBase" << endl;
267 if (m_playTarget) m_playTarget->shutdown(); 284 delete m_playTarget;
268 // delete m_playTarget;
269 delete m_playSource; 285 delete m_playSource;
286 delete m_audioIO;
287 delete m_recordTarget;
270 delete m_viewManager; 288 delete m_viewManager;
271 delete m_oscQueue; 289 delete m_oscQueue;
272 delete m_oscQueueStarter; 290 delete m_oscQueueStarter;
273 delete m_midiInput; 291 delete m_midiInput;
274 Profiles::getInstance()->dump(); 292 Profiles::getInstance()->dump();
293 }
294
295 void
296 MainWindowBase::emitHideSplash()
297 {
298 emit hideSplash(this);
275 } 299 }
276 300
277 void 301 void
278 MainWindowBase::finaliseMenus() 302 MainWindowBase::finaliseMenus()
279 { 303 {
540 (haveCurrentPane && 564 (haveCurrentPane &&
541 (currentLayer != 0)); 565 (currentLayer != 0));
542 bool haveMainModel = 566 bool haveMainModel =
543 (getMainModel() != 0); 567 (getMainModel() != 0);
544 bool havePlayTarget = 568 bool havePlayTarget =
545 (m_playTarget != 0); 569 (m_playTarget != 0 || m_audioIO != 0);
546 bool haveSelection = 570 bool haveSelection =
547 (m_viewManager && 571 (m_viewManager &&
548 !m_viewManager->getSelections().empty()); 572 !m_viewManager->getSelections().empty());
549 bool haveCurrentEditableLayer = 573 bool haveCurrentEditableLayer =
550 (haveCurrentLayer && 574 (haveCurrentLayer &&
585 emit canEditLayer(haveCurrentEditableLayer); 609 emit canEditLayer(haveCurrentEditableLayer);
586 emit canEditLayerTabular(haveCurrentEditableLayer || haveTabularLayer); 610 emit canEditLayerTabular(haveCurrentEditableLayer || haveTabularLayer);
587 emit canMeasureLayer(haveCurrentLayer); 611 emit canMeasureLayer(haveCurrentLayer);
588 emit canSelect(haveMainModel && haveCurrentPane); 612 emit canSelect(haveMainModel && haveCurrentPane);
589 emit canPlay(haveMainModel && havePlayTarget); 613 emit canPlay(haveMainModel && havePlayTarget);
590 emit canFfwd(true); 614 emit canRecord(m_soundOptions & WithAudioInput); // always possible then
591 emit canRewind(true); 615 emit canFfwd(haveMainModel);
616 emit canRewind(haveMainModel);
592 emit canPaste(haveClipboardContents); 617 emit canPaste(haveClipboardContents);
593 emit canInsertInstant(haveCurrentPane); 618 emit canInsertInstant(haveCurrentPane);
594 emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection); 619 emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection);
595 emit canInsertItemAtSelection(haveCurrentPane && haveSelection && haveCurrentDurationLayer); 620 emit canInsertItemAtSelection(haveCurrentPane && haveSelection && haveCurrentDurationLayer);
596 emit canRenumberInstants(haveCurrentTimeInstantsLayer && haveSelection); 621 emit canRenumberInstants(haveCurrentTimeInstantsLayer && haveSelection);
1301 rate = Preferences::getInstance()->getFixedSampleRate(); 1326 rate = Preferences::getInstance()->getFixedSampleRate();
1302 } else if (Preferences::getInstance()->getResampleOnLoad()) { 1327 } else if (Preferences::getInstance()->getResampleOnLoad()) {
1303 rate = m_playSource->getSourceSampleRate(); 1328 rate = m_playSource->getSourceSampleRate();
1304 } 1329 }
1305 1330
1306 WaveFileModel *newModel = new WaveFileModel(source, rate); 1331 ReadOnlyWaveFileModel *newModel = new ReadOnlyWaveFileModel(source, rate);
1307 1332
1308 if (!newModel->isOK()) { 1333 if (!newModel->isOK()) {
1309 delete newModel; 1334 delete newModel;
1310 m_openingAudioFile = false; 1335 m_openingAudioFile = false;
1311 if (source.wasCancelled()) { 1336 if (source.wasCancelled()) {
2148 m_recentFiles.addFile(source.getLocation()); 2173 m_recentFiles.addFile(source.getLocation());
2149 return FileOpenSucceeded; 2174 return FileOpenSucceeded;
2150 } 2175 }
2151 2176
2152 void 2177 void
2153 MainWindowBase::createPlayTarget() 2178 MainWindowBase::createAudioIO()
2154 { 2179 {
2155 if (m_playTarget) return; 2180 if (m_playTarget || m_audioIO) return;
2156 2181
2182 if (!(m_soundOptions & WithAudioOutput)) return;
2183
2184 //!!! how to handle preferences
2185 /*
2157 QSettings settings; 2186 QSettings settings;
2158 settings.beginGroup("Preferences"); 2187 settings.beginGroup("Preferences");
2159 QString targetName = settings.value("audio-target", "").toString(); 2188 QString targetName = settings.value("audio-target", "").toString();
2160 settings.endGroup(); 2189 settings.endGroup();
2161
2162 AudioTargetFactory *factory = AudioTargetFactory::getInstance(); 2190 AudioTargetFactory *factory = AudioTargetFactory::getInstance();
2163 2191
2164 factory->setDefaultCallbackTarget(targetName); 2192 factory->setDefaultCallbackTarget(targetName);
2165 m_playTarget = factory->createCallbackTarget(m_playSource); 2193 */
2166 2194
2167 if (!m_playTarget) { 2195 if (m_soundOptions & WithAudioInput) {
2196 m_audioIO = breakfastquay::AudioFactory::
2197 createCallbackIO(m_recordTarget, m_playSource);
2198 m_playSource->setSystemPlaybackTarget(m_audioIO);
2199 } else {
2200 m_playTarget = breakfastquay::AudioFactory::
2201 createCallbackPlayTarget(m_playSource);
2202 m_playSource->setSystemPlaybackTarget(m_playTarget);
2203 }
2204
2205 if (!m_playTarget && !m_audioIO) {
2168 emit hideSplash(); 2206 emit hideSplash();
2169 2207
2170 if (factory->isAutoCallbackTarget(targetName)) { 2208 // if (factory->isAutoCallbackTarget(targetName)) {
2171 QMessageBox::warning 2209 QMessageBox::warning
2172 (this, tr("Couldn't open audio device"), 2210 (this, tr("Couldn't open audio device"),
2173 tr("<b>No audio available</b><p>Could not open an audio device for playback.<p>Automatic audio device detection failed. Audio playback will not be available during this session.</p>"), 2211 tr("<b>No audio available</b><p>Could not open an audio device for playback.<p>Automatic audio device detection failed. Audio playback will not be available during this session.</p>"),
2174 QMessageBox::Ok); 2212 QMessageBox::Ok);
2213 /*
2175 } else { 2214 } else {
2176 QMessageBox::warning 2215 QMessageBox::warning
2177 (this, tr("Couldn't open audio device"), 2216 (this, tr("Couldn't open audio device"),
2178 tr("<b>No audio available</b><p>Failed to open your preferred audio device (\"%1\").<p>Audio playback will not be available during this session.</p>") 2217 tr("<b>No audio available</b><p>Failed to open your preferred audio device (\"%1\").<p>Audio playback will not be available during this session.</p>")
2179 .arg(factory->getCallbackTargetDescription(targetName)), 2218 .arg(factory->getCallbackTargetDescription(targetName)),
2180 QMessageBox::Ok); 2219 QMessageBox::Ok);
2181 } 2220 }
2221 */
2222 return;
2182 } 2223 }
2183 } 2224 }
2184 2225
2185 WaveFileModel * 2226 WaveFileModel *
2186 MainWindowBase::getMainModel() 2227 MainWindowBase::getMainModel()
2608 } 2649 }
2609 2650
2610 void 2651 void
2611 MainWindowBase::play() 2652 MainWindowBase::play()
2612 { 2653 {
2613 if (m_playSource->isPlaying()) { 2654 if (m_recordTarget->isRecording() || m_playSource->isPlaying()) {
2614 stop(); 2655 stop();
2656 QAction *action = qobject_cast<QAction *>(sender());
2657 if (action) action->setChecked(false);
2615 } else { 2658 } else {
2616 playbackFrameChanged(m_viewManager->getPlaybackFrame()); 2659 playbackFrameChanged(m_viewManager->getPlaybackFrame());
2617 m_playSource->play(m_viewManager->getPlaybackFrame()); 2660 m_playSource->play(m_viewManager->getPlaybackFrame());
2618 } 2661 }
2662 }
2663
2664 void
2665 MainWindowBase::record()
2666 {
2667 if (!(m_soundOptions & WithAudioInput)) {
2668 return;
2669 }
2670
2671 if (!m_recordTarget) {
2672 //!!! report
2673 return;
2674 }
2675
2676 if (!m_audioIO) {
2677 createAudioIO();
2678 }
2679
2680 if (m_recordTarget->isRecording()) {
2681 m_recordTarget->stopRecording();
2682 emit audioFileLoaded();
2683 return;
2684 }
2685
2686 WritableWaveFileModel *model = m_recordTarget->startRecording();
2687 if (!model) {
2688 cerr << "ERROR: MainWindowBase::record: Recording failed" << endl;
2689 //!!! report
2690 return;
2691 }
2692
2693 if (!model->isOK()) {
2694 m_recordTarget->stopRecording();
2695 delete model;
2696 //!!! ???
2697 return;
2698 }
2699
2700 PlayParameterRepository::getInstance()->addPlayable(model);
2701
2702 if (!getMainModel()) {
2703
2704 //!!! duplication with openAudio here
2705
2706 QString templateName = getDefaultSessionTemplate();
2707 bool loadedTemplate = false;
2708
2709 if (templateName != "") {
2710 FileOpenStatus tplStatus = openSessionTemplate(templateName);
2711 if (tplStatus == FileOpenCancelled) {
2712 return;
2713 }
2714 if (tplStatus != FileOpenFailed) {
2715 loadedTemplate = true;
2716 }
2717 }
2718
2719 if (!loadedTemplate) {
2720 closeSession();
2721 createDocument();
2722 }
2723
2724 Model *prevMain = getMainModel();
2725 if (prevMain) {
2726 m_playSource->removeModel(prevMain);
2727 PlayParameterRepository::getInstance()->removePlayable(prevMain);
2728 }
2729
2730 m_document->setMainModel(model);
2731 setupMenus();
2732
2733 if (loadedTemplate || (m_sessionFile == "")) {
2734 //!!! shouldn't be dealing directly with title from here -- call a method
2735 setWindowTitle(tr("%1: %2")
2736 .arg(QApplication::applicationName())
2737 .arg(model->getLocation()));
2738 CommandHistory::getInstance()->clear();
2739 CommandHistory::getInstance()->documentSaved();
2740 m_documentModified = false;
2741 } else {
2742 setWindowTitle(tr("%1: %2 [%3]")
2743 .arg(QApplication::applicationName())
2744 .arg(QFileInfo(m_sessionFile).fileName())
2745 .arg(model->getLocation()));
2746 if (m_documentModified) {
2747 m_documentModified = false;
2748 documentModified(); // so as to restore "(modified)" window title
2749 }
2750 }
2751
2752 } else {
2753
2754 CommandHistory::getInstance()->startCompoundOperation
2755 (tr("Import Recorded Audio"), true);
2756
2757 m_document->addImportedModel(model);
2758
2759 AddPaneCommand *command = new AddPaneCommand(this);
2760 CommandHistory::getInstance()->addCommand(command);
2761
2762 Pane *pane = command->getPane();
2763
2764 if (m_timeRulerLayer) {
2765 m_document->addLayerToView(pane, m_timeRulerLayer);
2766 }
2767
2768 Layer *newLayer = m_document->createImportedLayer(model);
2769
2770 if (newLayer) {
2771 m_document->addLayerToView(pane, newLayer);
2772 }
2773
2774 CommandHistory::getInstance()->endCompoundOperation();
2775 }
2776
2777 updateMenuStates();
2778 m_recentFiles.addFile(model->getLocation());
2779 currentPaneChanged(m_paneStack->getCurrentPane());
2619 } 2780 }
2620 2781
2621 void 2782 void
2622 MainWindowBase::ffwd() 2783 MainWindowBase::ffwd()
2623 { 2784 {
2844 } 3005 }
2845 3006
2846 void 3007 void
2847 MainWindowBase::stop() 3008 MainWindowBase::stop()
2848 { 3009 {
3010 if (m_recordTarget->isRecording()) {
3011 m_recordTarget->stopRecording();
3012 emit audioFileLoaded();
3013 }
3014
2849 m_playSource->stop(); 3015 m_playSource->stop();
2850 3016
2851 if (m_paneStack && m_paneStack->getCurrentPane()) { 3017 if (m_paneStack && m_paneStack->getCurrentPane()) {
2852 updateVisibleRangeDisplay(m_paneStack->getCurrentPane()); 3018 updateVisibleRangeDisplay(m_paneStack->getCurrentPane());
2853 } else { 3019 } else {
3314 MainWindowBase::mainModelChanged(WaveFileModel *model) 3480 MainWindowBase::mainModelChanged(WaveFileModel *model)
3315 { 3481 {
3316 // SVDEBUG << "MainWindowBase::mainModelChanged(" << model << ")" << endl; 3482 // SVDEBUG << "MainWindowBase::mainModelChanged(" << model << ")" << endl;
3317 updateDescriptionLabel(); 3483 updateDescriptionLabel();
3318 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate()); 3484 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate());
3319 if (model && !m_playTarget && m_audioOutput) { 3485 if (model && !(m_playTarget || m_audioIO) &&
3320 createPlayTarget(); 3486 (m_soundOptions & WithAudioOutput)) {
3487 createAudioIO();
3321 } 3488 }
3322 } 3489 }
3323 3490
3324 void 3491 void
3325 MainWindowBase::modelAboutToBeDeleted(Model *model) 3492 MainWindowBase::modelAboutToBeDeleted(Model *model)
3327 // SVDEBUG << "MainWindowBase::modelAboutToBeDeleted(" << model << ")" << endl; 3494 // SVDEBUG << "MainWindowBase::modelAboutToBeDeleted(" << model << ")" << endl;
3328 if (model == m_viewManager->getPlaybackModel()) { 3495 if (model == m_viewManager->getPlaybackModel()) {
3329 m_viewManager->setPlaybackModel(0); 3496 m_viewManager->setPlaybackModel(0);
3330 } 3497 }
3331 m_playSource->removeModel(model); 3498 m_playSource->removeModel(model);
3332 FFTDataServer::modelAboutToBeDeleted(model);
3333 } 3499 }
3334 3500
3335 void 3501 void
3336 MainWindowBase::paneDeleteButtonClicked(Pane *pane) 3502 MainWindowBase::paneDeleteButtonClicked(Pane *pane)
3337 { 3503 {