comparison framework/MainWindowBase.cpp @ 481:52c0aff69478 3.0-integration

Merge from branch recording
author Chris Cannam
date Thu, 20 Aug 2015 13:15:19 +0100
parents 4480b031fe38 6f475df6f833
children 01aeda073720 111e976f9ed4
comparison
equal deleted inserted replaced
472:6ec35c1690c0 481:52c0aff69478
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"
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 "audio/AudioCallbackPlaySource.h" 50 #include "audio/AudioCallbackPlaySource.h"
51 #include "audio/AudioRecordTarget.h"
51 #include "audio/PlaySpeedRangeMapper.h" 52 #include "audio/PlaySpeedRangeMapper.h"
53
52 #include "data/fileio/DataFileReaderFactory.h" 54 #include "data/fileio/DataFileReaderFactory.h"
53 #include "data/fileio/PlaylistFileReader.h" 55 #include "data/fileio/PlaylistFileReader.h"
54 #include "data/fileio/WavFileWriter.h" 56 #include "data/fileio/WavFileWriter.h"
55 #include "data/fileio/MIDIFileWriter.h" 57 #include "data/fileio/MIDIFileWriter.h"
56 #include "data/fileio/BZipFileDevice.h" 58 #include "data/fileio/BZipFileDevice.h"
70 72
71 #include "data/osc/OSCQueue.h" 73 #include "data/osc/OSCQueue.h"
72 #include "data/midi/MIDIInput.h" 74 #include "data/midi/MIDIInput.h"
73 75
74 #include <bqaudioio/SystemPlaybackTarget.h> 76 #include <bqaudioio/SystemPlaybackTarget.h>
77 #include <bqaudioio/SystemAudioIO.h>
75 #include <bqaudioio/AudioFactory.h> 78 #include <bqaudioio/AudioFactory.h>
76 79
77 #include <QApplication> 80 #include <QApplication>
78 #include <QMessageBox> 81 #include <QMessageBox>
79 #include <QGridLayout> 82 #include <QGridLayout>
128 return 0; 131 return 0;
129 } 132 }
130 #undef Window 133 #undef Window
131 #endif 134 #endif
132 135
133 MainWindowBase::MainWindowBase(bool withAudioOutput, 136 MainWindowBase::MainWindowBase(SoundOptions options) :
134 bool withMIDIInput) :
135 m_document(0), 137 m_document(0),
136 m_paneStack(0), 138 m_paneStack(0),
137 m_viewManager(0), 139 m_viewManager(0),
138 m_timeRulerLayer(0), 140 m_timeRulerLayer(0),
139 m_audioOutput(withAudioOutput), 141 m_soundOptions(options),
140 m_playSource(0), 142 m_playSource(0),
143 m_recordTarget(0),
141 m_playTarget(0), 144 m_playTarget(0),
145 m_audioIO(0),
142 m_oscQueue(0), 146 m_oscQueue(0),
143 m_oscQueueStarter(0), 147 m_oscQueueStarter(0),
144 m_midiInput(0), 148 m_midiInput(0),
145 m_recentFiles("RecentFiles", 20), 149 m_recentFiles("RecentFiles", 20),
146 m_recentTransforms("RecentTransforms", 20), 150 m_recentTransforms("RecentTransforms", 20),
154 m_statusLabel(0), 158 m_statusLabel(0),
155 m_menuShortcutMapper(0) 159 m_menuShortcutMapper(0)
156 { 160 {
157 Profiler profiler("MainWindowBase::MainWindowBase"); 161 Profiler profiler("MainWindowBase::MainWindowBase");
158 162
163 if (options & WithAudioInput) {
164 if (!(options & WithAudioOutput)) {
165 cerr << "WARNING: MainWindowBase: WithAudioInput requires WithAudioOutput -- recording will not work" << endl;
166 }
167 }
168
159 qRegisterMetaType<sv_frame_t>("sv_frame_t"); 169 qRegisterMetaType<sv_frame_t>("sv_frame_t");
160 qRegisterMetaType<sv_samplerate_t>("sv_samplerate_t"); 170 qRegisterMetaType<sv_samplerate_t>("sv_samplerate_t");
161 171
162 #ifdef Q_WS_X11 172 #ifdef Q_WS_X11
163 XSetErrorHandler(handle_x11_error); 173 XSetErrorHandler(handle_x11_error);
215 connect(m_paneStack, SIGNAL(paneDeleteButtonClicked(Pane *)), 225 connect(m_paneStack, SIGNAL(paneDeleteButtonClicked(Pane *)),
216 this, SLOT(paneDeleteButtonClicked(Pane *))); 226 this, SLOT(paneDeleteButtonClicked(Pane *)));
217 227
218 m_playSource = new AudioCallbackPlaySource(m_viewManager, 228 m_playSource = new AudioCallbackPlaySource(m_viewManager,
219 QApplication::applicationName()); 229 QApplication::applicationName());
230 if (m_soundOptions & WithAudioInput) {
231 m_recordTarget = new AudioRecordTarget(m_viewManager,
232 QApplication::applicationName());
233 }
220 234
221 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)),
222 this, SLOT(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool))); 236 this, SLOT(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool)));
223 connect(m_playSource, SIGNAL(audioOverloadPluginDisabled()), 237 connect(m_playSource, SIGNAL(audioOverloadPluginDisabled()),
224 this, SLOT(audioOverloadPluginDisabled())); 238 this, SLOT(audioOverloadPluginDisabled()));
255 settings.endGroup(); 269 settings.endGroup();
256 270
257 m_labeller = new Labeller(labellerType); 271 m_labeller = new Labeller(labellerType);
258 m_labeller->setCounterCycleSize(cycle); 272 m_labeller->setCounterCycleSize(cycle);
259 273
260 if (withMIDIInput) { 274 if (m_soundOptions & WithMIDIInput) {
261 m_midiInput = new MIDIInput(QApplication::applicationName(), this); 275 m_midiInput = new MIDIInput(QApplication::applicationName(), this);
262 } 276 }
263 277
264 QTimer::singleShot(1500, this, SIGNAL(hideSplash())); 278 QTimer::singleShot(1500, this, SIGNAL(hideSplash()));
265 } 279 }
267 MainWindowBase::~MainWindowBase() 281 MainWindowBase::~MainWindowBase()
268 { 282 {
269 SVDEBUG << "MainWindowBase::~MainWindowBase" << endl; 283 SVDEBUG << "MainWindowBase::~MainWindowBase" << endl;
270 delete m_playTarget; 284 delete m_playTarget;
271 delete m_playSource; 285 delete m_playSource;
286 delete m_audioIO;
287 delete m_recordTarget;
272 delete m_viewManager; 288 delete m_viewManager;
273 delete m_oscQueue; 289 delete m_oscQueue;
274 delete m_oscQueueStarter; 290 delete m_oscQueueStarter;
275 delete m_midiInput; 291 delete m_midiInput;
276 Profiles::getInstance()->dump(); 292 Profiles::getInstance()->dump();
548 (haveCurrentPane && 564 (haveCurrentPane &&
549 (currentLayer != 0)); 565 (currentLayer != 0));
550 bool haveMainModel = 566 bool haveMainModel =
551 (getMainModel() != 0); 567 (getMainModel() != 0);
552 bool havePlayTarget = 568 bool havePlayTarget =
553 (m_playTarget != 0); 569 (m_playTarget != 0 || m_audioIO != 0);
554 bool haveSelection = 570 bool haveSelection =
555 (m_viewManager && 571 (m_viewManager &&
556 !m_viewManager->getSelections().empty()); 572 !m_viewManager->getSelections().empty());
557 bool haveCurrentEditableLayer = 573 bool haveCurrentEditableLayer =
558 (haveCurrentLayer && 574 (haveCurrentLayer &&
593 emit canEditLayer(haveCurrentEditableLayer); 609 emit canEditLayer(haveCurrentEditableLayer);
594 emit canEditLayerTabular(haveCurrentEditableLayer || haveTabularLayer); 610 emit canEditLayerTabular(haveCurrentEditableLayer || haveTabularLayer);
595 emit canMeasureLayer(haveCurrentLayer); 611 emit canMeasureLayer(haveCurrentLayer);
596 emit canSelect(haveMainModel && haveCurrentPane); 612 emit canSelect(haveMainModel && haveCurrentPane);
597 emit canPlay(haveMainModel && havePlayTarget); 613 emit canPlay(haveMainModel && havePlayTarget);
614 emit canRecord(m_soundOptions & WithAudioInput); // always possible then
598 emit canFfwd(haveMainModel); 615 emit canFfwd(haveMainModel);
599 emit canRewind(haveMainModel); 616 emit canRewind(haveMainModel);
600 emit canPaste(haveClipboardContents); 617 emit canPaste(haveClipboardContents);
601 emit canInsertInstant(haveCurrentPane); 618 emit canInsertInstant(haveCurrentPane);
602 emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection); 619 emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection);
1309 rate = Preferences::getInstance()->getFixedSampleRate(); 1326 rate = Preferences::getInstance()->getFixedSampleRate();
1310 } else if (Preferences::getInstance()->getResampleOnLoad()) { 1327 } else if (Preferences::getInstance()->getResampleOnLoad()) {
1311 rate = m_playSource->getSourceSampleRate(); 1328 rate = m_playSource->getSourceSampleRate();
1312 } 1329 }
1313 1330
1314 WaveFileModel *newModel = new WaveFileModel(source, rate); 1331 ReadOnlyWaveFileModel *newModel = new ReadOnlyWaveFileModel(source, rate);
1315 1332
1316 if (!newModel->isOK()) { 1333 if (!newModel->isOK()) {
1317 delete newModel; 1334 delete newModel;
1318 m_openingAudioFile = false; 1335 m_openingAudioFile = false;
1319 if (source.wasCancelled()) { 1336 if (source.wasCancelled()) {
2156 m_recentFiles.addFile(source.getLocation()); 2173 m_recentFiles.addFile(source.getLocation());
2157 return FileOpenSucceeded; 2174 return FileOpenSucceeded;
2158 } 2175 }
2159 2176
2160 void 2177 void
2161 MainWindowBase::createPlayTarget() 2178 MainWindowBase::createAudioIO()
2162 { 2179 {
2163 if (m_playTarget) return; 2180 if (m_playTarget || m_audioIO) return;
2181
2182 if (!(m_soundOptions & WithAudioOutput)) return;
2164 2183
2165 //!!! how to handle preferences 2184 //!!! how to handle preferences
2166 /* 2185 /*
2167 QSettings settings; 2186 QSettings settings;
2168 settings.beginGroup("Preferences"); 2187 settings.beginGroup("Preferences");
2170 settings.endGroup(); 2189 settings.endGroup();
2171 AudioTargetFactory *factory = AudioTargetFactory::getInstance(); 2190 AudioTargetFactory *factory = AudioTargetFactory::getInstance();
2172 2191
2173 factory->setDefaultCallbackTarget(targetName); 2192 factory->setDefaultCallbackTarget(targetName);
2174 */ 2193 */
2175 2194
2176 m_playTarget = 2195 if (m_soundOptions & WithAudioInput) {
2177 breakfastquay::AudioFactory::createCallbackPlayTarget(m_playSource); 2196 m_audioIO = breakfastquay::AudioFactory::
2178 2197 createCallbackIO(m_recordTarget, m_playSource);
2179 m_playSource->setSystemPlaybackTarget(m_playTarget); 2198 m_playSource->setSystemPlaybackTarget(m_audioIO);
2180 2199 } else {
2181 if (!m_playTarget) { 2200 m_playTarget = breakfastquay::AudioFactory::
2201 createCallbackPlayTarget(m_playSource);
2202 m_playSource->setSystemPlaybackTarget(m_playTarget);
2203 }
2204
2205 if (!m_playTarget && !m_audioIO) {
2182 emit hideSplash(); 2206 emit hideSplash();
2183 2207
2184 // if (factory->isAutoCallbackTarget(targetName)) { 2208 // if (factory->isAutoCallbackTarget(targetName)) {
2185 QMessageBox::warning 2209 QMessageBox::warning
2186 (this, tr("Couldn't open audio device"), 2210 (this, tr("Couldn't open audio device"),
2193 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>")
2194 .arg(factory->getCallbackTargetDescription(targetName)), 2218 .arg(factory->getCallbackTargetDescription(targetName)),
2195 QMessageBox::Ok); 2219 QMessageBox::Ok);
2196 } 2220 }
2197 */ 2221 */
2222 return;
2198 } 2223 }
2199 } 2224 }
2200 2225
2201 WaveFileModel * 2226 WaveFileModel *
2202 MainWindowBase::getMainModel() 2227 MainWindowBase::getMainModel()
2624 } 2649 }
2625 2650
2626 void 2651 void
2627 MainWindowBase::play() 2652 MainWindowBase::play()
2628 { 2653 {
2629 if (m_playSource->isPlaying()) { 2654 if (m_recordTarget->isRecording() || m_playSource->isPlaying()) {
2630 stop(); 2655 stop();
2656 QAction *action = qobject_cast<QAction *>(sender());
2657 if (action) action->setChecked(false);
2631 } else { 2658 } else {
2632 playbackFrameChanged(m_viewManager->getPlaybackFrame()); 2659 playbackFrameChanged(m_viewManager->getPlaybackFrame());
2633 m_playSource->play(m_viewManager->getPlaybackFrame()); 2660 m_playSource->play(m_viewManager->getPlaybackFrame());
2634 } 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());
2635 } 2780 }
2636 2781
2637 void 2782 void
2638 MainWindowBase::ffwd() 2783 MainWindowBase::ffwd()
2639 { 2784 {
2860 } 3005 }
2861 3006
2862 void 3007 void
2863 MainWindowBase::stop() 3008 MainWindowBase::stop()
2864 { 3009 {
3010 if (m_recordTarget->isRecording()) {
3011 m_recordTarget->stopRecording();
3012 emit audioFileLoaded();
3013 }
3014
2865 m_playSource->stop(); 3015 m_playSource->stop();
2866 3016
2867 if (m_paneStack && m_paneStack->getCurrentPane()) { 3017 if (m_paneStack && m_paneStack->getCurrentPane()) {
2868 updateVisibleRangeDisplay(m_paneStack->getCurrentPane()); 3018 updateVisibleRangeDisplay(m_paneStack->getCurrentPane());
2869 } else { 3019 } else {
3330 MainWindowBase::mainModelChanged(WaveFileModel *model) 3480 MainWindowBase::mainModelChanged(WaveFileModel *model)
3331 { 3481 {
3332 // SVDEBUG << "MainWindowBase::mainModelChanged(" << model << ")" << endl; 3482 // SVDEBUG << "MainWindowBase::mainModelChanged(" << model << ")" << endl;
3333 updateDescriptionLabel(); 3483 updateDescriptionLabel();
3334 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate()); 3484 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate());
3335 if (model && !m_playTarget && m_audioOutput) { 3485 if (model && !(m_playTarget || m_audioIO) &&
3336 createPlayTarget(); 3486 (m_soundOptions & WithAudioOutput)) {
3487 createAudioIO();
3337 } 3488 }
3338 } 3489 }
3339 3490
3340 void 3491 void
3341 MainWindowBase::modelAboutToBeDeleted(Model *model) 3492 MainWindowBase::modelAboutToBeDeleted(Model *model)