Mercurial > hg > svapp
comparison framework/MainWindowBase.cpp @ 582:b2d49e7c4149
Merge from branch 3.0-integration
author | Chris Cannam |
---|---|
date | Fri, 13 Jan 2017 10:29:55 +0000 |
parents | 1a8a8980f39a |
children | 48cfa4e2bfc1 |
comparison
equal
deleted
inserted
replaced
513:d65ce7e55346 | 582:b2d49e7c4149 |
---|---|
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/AudioCallbackRecordTarget.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> | |
79 #include <bqaudioio/ResamplerWrapper.h> | |
77 | 80 |
78 #include <QApplication> | 81 #include <QApplication> |
79 #include <QMessageBox> | 82 #include <QMessageBox> |
80 #include <QGridLayout> | 83 #include <QGridLayout> |
81 #include <QLabel> | 84 #include <QLabel> |
129 return 0; | 132 return 0; |
130 } | 133 } |
131 #undef Window | 134 #undef Window |
132 #endif | 135 #endif |
133 | 136 |
134 MainWindowBase::MainWindowBase(bool withAudioOutput, | 137 MainWindowBase::MainWindowBase(SoundOptions options) : |
135 bool withMIDIInput) : | |
136 m_document(0), | 138 m_document(0), |
137 m_paneStack(0), | 139 m_paneStack(0), |
138 m_viewManager(0), | 140 m_viewManager(0), |
139 m_timeRulerLayer(0), | 141 m_timeRulerLayer(0), |
140 m_audioOutput(withAudioOutput), | 142 m_soundOptions(options), |
141 m_playSource(0), | 143 m_playSource(0), |
144 m_recordTarget(0), | |
145 m_resamplerWrapper(0), | |
142 m_playTarget(0), | 146 m_playTarget(0), |
147 m_audioIO(0), | |
143 m_oscQueue(0), | 148 m_oscQueue(0), |
144 m_oscQueueStarter(0), | 149 m_oscQueueStarter(0), |
145 m_midiInput(0), | 150 m_midiInput(0), |
146 m_recentFiles("RecentFiles", 20), | 151 m_recentFiles("RecentFiles", 20), |
147 m_recentTransforms("RecentTransforms", 20), | 152 m_recentTransforms("RecentTransforms", 20), |
150 m_abandoning(false), | 155 m_abandoning(false), |
151 m_labeller(0), | 156 m_labeller(0), |
152 m_lastPlayStatusSec(0), | 157 m_lastPlayStatusSec(0), |
153 m_initialDarkBackground(false), | 158 m_initialDarkBackground(false), |
154 m_defaultFfwdRwdStep(2, 0), | 159 m_defaultFfwdRwdStep(2, 0), |
160 m_audioRecordMode(RecordCreateAdditionalModel), | |
155 m_statusLabel(0), | 161 m_statusLabel(0), |
162 m_iconsVisibleInMenus(true), | |
156 m_menuShortcutMapper(0) | 163 m_menuShortcutMapper(0) |
157 { | 164 { |
158 Profiler profiler("MainWindowBase::MainWindowBase"); | 165 Profiler profiler("MainWindowBase::MainWindowBase"); |
159 | 166 |
167 if (options & WithAudioInput) { | |
168 if (!(options & WithAudioOutput)) { | |
169 cerr << "WARNING: MainWindowBase: WithAudioInput requires WithAudioOutput -- recording will not work" << endl; | |
170 } | |
171 } | |
172 | |
160 qRegisterMetaType<sv_frame_t>("sv_frame_t"); | 173 qRegisterMetaType<sv_frame_t>("sv_frame_t"); |
161 qRegisterMetaType<sv_samplerate_t>("sv_samplerate_t"); | 174 qRegisterMetaType<sv_samplerate_t>("sv_samplerate_t"); |
162 | 175 |
163 #ifdef Q_WS_X11 | 176 #ifdef Q_WS_X11 |
164 XSetErrorHandler(handle_x11_error); | 177 XSetErrorHandler(handle_x11_error); |
184 settings.beginGroup("Preferences"); | 197 settings.beginGroup("Preferences"); |
185 viewFontSize = settings.value("view-font-size", viewFontSize).toInt(); | 198 viewFontSize = settings.value("view-font-size", viewFontSize).toInt(); |
186 settings.setValue("view-font-size", viewFontSize); | 199 settings.setValue("view-font-size", viewFontSize); |
187 settings.endGroup(); | 200 settings.endGroup(); |
188 | 201 |
202 #ifdef NOT_DEFINED // This no longer works correctly on any platform AFAICS | |
189 Preferences::BackgroundMode mode = | 203 Preferences::BackgroundMode mode = |
190 Preferences::getInstance()->getBackgroundMode(); | 204 Preferences::getInstance()->getBackgroundMode(); |
191 m_initialDarkBackground = m_viewManager->getGlobalDarkBackground(); | 205 m_initialDarkBackground = m_viewManager->getGlobalDarkBackground(); |
192 if (mode != Preferences::BackgroundFromTheme) { | 206 if (mode != Preferences::BackgroundFromTheme) { |
193 m_viewManager->setGlobalDarkBackground | 207 m_viewManager->setGlobalDarkBackground |
194 (mode == Preferences::DarkBackground); | 208 (mode == Preferences::DarkBackground); |
195 } | 209 } |
210 #endif | |
196 | 211 |
197 m_paneStack = new PaneStack(0, m_viewManager); | 212 m_paneStack = new PaneStack(0, m_viewManager); |
198 connect(m_paneStack, SIGNAL(currentPaneChanged(Pane *)), | 213 connect(m_paneStack, SIGNAL(currentPaneChanged(Pane *)), |
199 this, SLOT(currentPaneChanged(Pane *))); | 214 this, SLOT(currentPaneChanged(Pane *))); |
200 connect(m_paneStack, SIGNAL(currentLayerChanged(Pane *, Layer *)), | 215 connect(m_paneStack, SIGNAL(currentLayerChanged(Pane *, Layer *)), |
213 this, SLOT(paneDropAccepted(Pane *, QStringList))); | 228 this, SLOT(paneDropAccepted(Pane *, QStringList))); |
214 connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QString)), | 229 connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QString)), |
215 this, SLOT(paneDropAccepted(Pane *, QString))); | 230 this, SLOT(paneDropAccepted(Pane *, QString))); |
216 connect(m_paneStack, SIGNAL(paneDeleteButtonClicked(Pane *)), | 231 connect(m_paneStack, SIGNAL(paneDeleteButtonClicked(Pane *)), |
217 this, SLOT(paneDeleteButtonClicked(Pane *))); | 232 this, SLOT(paneDeleteButtonClicked(Pane *))); |
218 | 233 |
219 m_playSource = new AudioCallbackPlaySource(m_viewManager, | 234 m_playSource = new AudioCallbackPlaySource |
220 QApplication::applicationName()); | 235 (m_viewManager, QApplication::applicationName()); |
236 | |
237 if (m_soundOptions & WithAudioInput) { | |
238 m_recordTarget = new AudioCallbackRecordTarget | |
239 (m_viewManager, QApplication::applicationName()); | |
240 connect(m_recordTarget, | |
241 SIGNAL(recordDurationChanged(sv_frame_t, sv_samplerate_t)), | |
242 this, | |
243 SLOT(recordDurationChanged(sv_frame_t, sv_samplerate_t))); | |
244 } | |
221 | 245 |
222 connect(m_playSource, SIGNAL(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool)), | 246 connect(m_playSource, SIGNAL(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool)), |
223 this, SLOT(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool))); | 247 this, SLOT(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool))); |
248 connect(m_playSource, SIGNAL(channelCountIncreased(int)), | |
249 this, SLOT(audioChannelCountIncreased(int))); | |
224 connect(m_playSource, SIGNAL(audioOverloadPluginDisabled()), | 250 connect(m_playSource, SIGNAL(audioOverloadPluginDisabled()), |
225 this, SLOT(audioOverloadPluginDisabled())); | 251 this, SLOT(audioOverloadPluginDisabled())); |
226 connect(m_playSource, SIGNAL(audioTimeStretchMultiChannelDisabled()), | 252 connect(m_playSource, SIGNAL(audioTimeStretchMultiChannelDisabled()), |
227 this, SLOT(audioTimeStretchMultiChannelDisabled())); | 253 this, SLOT(audioTimeStretchMultiChannelDisabled())); |
228 | 254 |
229 connect(m_viewManager, SIGNAL(outputLevelsChanged(float, float)), | 255 connect(m_viewManager, SIGNAL(monitoringLevelsChanged(float, float)), |
230 this, SLOT(outputLevelsChanged(float, float))); | 256 this, SLOT(monitoringLevelsChanged(float, float))); |
231 | 257 |
232 connect(m_viewManager, SIGNAL(playbackFrameChanged(sv_frame_t)), | 258 connect(m_viewManager, SIGNAL(playbackFrameChanged(sv_frame_t)), |
233 this, SLOT(playbackFrameChanged(sv_frame_t))); | 259 this, SLOT(playbackFrameChanged(sv_frame_t))); |
234 | 260 |
235 connect(m_viewManager, SIGNAL(globalCentreFrameChanged(sv_frame_t)), | 261 connect(m_viewManager, SIGNAL(globalCentreFrameChanged(sv_frame_t)), |
256 settings.endGroup(); | 282 settings.endGroup(); |
257 | 283 |
258 m_labeller = new Labeller(labellerType); | 284 m_labeller = new Labeller(labellerType); |
259 m_labeller->setCounterCycleSize(cycle); | 285 m_labeller->setCounterCycleSize(cycle); |
260 | 286 |
261 if (withMIDIInput) { | 287 if (m_soundOptions & WithMIDIInput) { |
262 m_midiInput = new MIDIInput(QApplication::applicationName(), this); | 288 m_midiInput = new MIDIInput(QApplication::applicationName(), this); |
263 } | 289 } |
264 | 290 |
265 QTimer::singleShot(1500, this, SIGNAL(hideSplash())); | 291 QTimer::singleShot(1500, this, SIGNAL(hideSplash())); |
266 } | 292 } |
267 | 293 |
268 MainWindowBase::~MainWindowBase() | 294 MainWindowBase::~MainWindowBase() |
269 { | 295 { |
270 SVDEBUG << "MainWindowBase::~MainWindowBase" << endl; | 296 SVDEBUG << "MainWindowBase::~MainWindowBase" << endl; |
271 if (m_playTarget) m_playTarget->shutdown(); | 297 |
272 // delete m_playTarget; | 298 // We have to delete the breakfastquay::SystemPlaybackTarget or |
299 // breakfastquay::SystemAudioIO object (whichever we have -- it | |
300 // depends on whether we handle recording or not) before we delete | |
301 // the ApplicationPlaybackSource and ApplicationRecordTarget that | |
302 // they refer to. | |
303 | |
304 deleteAudioIO(); | |
305 | |
306 // Then delete the Application objects. | |
273 delete m_playSource; | 307 delete m_playSource; |
308 delete m_recordTarget; | |
309 | |
274 delete m_viewManager; | 310 delete m_viewManager; |
275 delete m_oscQueue; | 311 delete m_oscQueue; |
276 delete m_oscQueueStarter; | 312 delete m_oscQueueStarter; |
277 delete m_midiInput; | 313 delete m_midiInput; |
278 Profiles::getInstance()->dump(); | 314 Profiles::getInstance()->dump(); |
313 if (menu) finaliseMenu(menu); | 349 if (menu) finaliseMenu(menu); |
314 } | 350 } |
315 } | 351 } |
316 | 352 |
317 void | 353 void |
318 MainWindowBase::finaliseMenu(QMenu * | 354 MainWindowBase::finaliseMenu(QMenu *menu) |
319 #ifdef Q_OS_MAC | 355 { |
320 menu | 356 foreach (QAction *a, menu->actions()) { |
321 #endif | 357 a->setIconVisibleInMenu(m_iconsVisibleInMenus); |
322 ) | 358 } |
323 { | 359 |
324 #ifdef Q_OS_MAC | 360 #ifdef Q_OS_MAC |
325 // See https://bugreports.qt-project.org/browse/QTBUG-38256 and | 361 // See https://bugreports.qt-project.org/browse/QTBUG-38256 and |
326 // our issue #890 http://code.soundsoftware.ac.uk/issues/890 -- | 362 // our issue #890 http://code.soundsoftware.ac.uk/issues/890 -- |
327 // single-key shortcuts that are associated only with a menu | 363 // single-key shortcuts that are associated only with a menu |
328 // action (and not with a toolbar button) do not work with Qt 5.x | 364 // action (and not with a toolbar button) do not work with Qt 5.x |
445 if (m_oscQueue && m_oscQueue->isOK()) { | 481 if (m_oscQueue && m_oscQueue->isOK()) { |
446 connect(m_oscQueue, SIGNAL(messagesAvailable()), this, SLOT(pollOSC())); | 482 connect(m_oscQueue, SIGNAL(messagesAvailable()), this, SLOT(pollOSC())); |
447 QTimer *oscTimer = new QTimer(this); | 483 QTimer *oscTimer = new QTimer(this); |
448 connect(oscTimer, SIGNAL(timeout()), this, SLOT(pollOSC())); | 484 connect(oscTimer, SIGNAL(timeout()), this, SLOT(pollOSC())); |
449 oscTimer->start(1000); | 485 oscTimer->start(1000); |
450 cerr << "Finished setting up OSC interface" << endl; | 486 SVCERR << "Finished setting up OSC interface" << endl; |
451 } | 487 } |
452 } | 488 } |
453 | 489 |
454 QString | 490 QString |
455 MainWindowBase::getOpenFileName(FileFinder::FileType type) | 491 MainWindowBase::getOpenFileName(FileFinder::FileType type) |
550 (haveCurrentPane && | 586 (haveCurrentPane && |
551 (currentLayer != 0)); | 587 (currentLayer != 0)); |
552 bool haveMainModel = | 588 bool haveMainModel = |
553 (getMainModel() != 0); | 589 (getMainModel() != 0); |
554 bool havePlayTarget = | 590 bool havePlayTarget = |
555 (m_playTarget != 0); | 591 (m_playTarget != 0 || m_audioIO != 0); |
556 bool haveSelection = | 592 bool haveSelection = |
557 (m_viewManager && | 593 (m_viewManager && |
558 !m_viewManager->getSelections().empty()); | 594 !m_viewManager->getSelections().empty()); |
559 bool haveCurrentEditableLayer = | 595 bool haveCurrentEditableLayer = |
560 (haveCurrentLayer && | 596 (haveCurrentLayer && |
595 emit canEditLayer(haveCurrentEditableLayer); | 631 emit canEditLayer(haveCurrentEditableLayer); |
596 emit canEditLayerTabular(haveCurrentEditableLayer || haveTabularLayer); | 632 emit canEditLayerTabular(haveCurrentEditableLayer || haveTabularLayer); |
597 emit canMeasureLayer(haveCurrentLayer); | 633 emit canMeasureLayer(haveCurrentLayer); |
598 emit canSelect(haveMainModel && haveCurrentPane); | 634 emit canSelect(haveMainModel && haveCurrentPane); |
599 emit canPlay(haveMainModel && havePlayTarget); | 635 emit canPlay(haveMainModel && havePlayTarget); |
636 emit canRecord(m_recordTarget != 0); | |
600 emit canFfwd(haveMainModel); | 637 emit canFfwd(haveMainModel); |
601 emit canRewind(haveMainModel); | 638 emit canRewind(haveMainModel); |
602 emit canPaste(haveClipboardContents); | 639 emit canPaste(haveClipboardContents); |
603 emit canInsertInstant(haveCurrentPane); | 640 emit canInsertInstant(haveCurrentPane); |
604 emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection); | 641 emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection); |
605 emit canInsertItemAtSelection(haveCurrentPane && haveSelection && haveCurrentDurationLayer); | 642 emit canInsertItemAtSelection(haveCurrentPane && haveSelection && haveCurrentDurationLayer); |
606 emit canRenumberInstants(haveCurrentTimeInstantsLayer && haveSelection); | 643 emit canRenumberInstants(haveCurrentTimeInstantsLayer && haveSelection); |
644 emit canSubdivideInstants(haveCurrentTimeInstantsLayer && haveSelection); | |
645 emit canWinnowInstants(haveCurrentTimeInstantsLayer && haveSelection); | |
607 emit canPlaySelection(haveMainModel && havePlayTarget && haveSelection); | 646 emit canPlaySelection(haveMainModel && havePlayTarget && haveSelection); |
608 emit canClearSelection(haveSelection); | 647 emit canClearSelection(haveSelection); |
609 emit canEditSelection(haveSelection && haveCurrentEditableLayer); | 648 emit canEditSelection(haveSelection && haveCurrentEditableLayer); |
610 emit canSave(m_sessionFile != "" && m_documentModified); | 649 emit canSave(m_sessionFile != "" && m_documentModified); |
611 emit canSaveAs(haveMainModel); | 650 emit canSaveAs(haveMainModel); |
1194 if (!m_labeller) return; | 1233 if (!m_labeller) return; |
1195 | 1234 |
1196 Labeller labeller(*m_labeller); | 1235 Labeller labeller(*m_labeller); |
1197 labeller.setSampleRate(sodm->getSampleRate()); | 1236 labeller.setSampleRate(sodm->getSampleRate()); |
1198 | 1237 |
1199 // This uses a command | 1238 Command *c = labeller.labelAll<SparseOneDimensionalModel::Point>(*sodm, &ms); |
1200 | 1239 if (c) CommandHistory::getInstance()->addCommand(c, false); |
1201 labeller.labelAll<SparseOneDimensionalModel::Point>(*sodm, &ms); | 1240 } |
1241 | |
1242 void | |
1243 MainWindowBase::subdivideInstantsBy(int n) | |
1244 { | |
1245 Pane *pane = m_paneStack->getCurrentPane(); | |
1246 if (!pane) return; | |
1247 | |
1248 Layer *layer = dynamic_cast<TimeInstantLayer *>(pane->getSelectedLayer()); | |
1249 if (!layer) return; | |
1250 | |
1251 MultiSelection ms(m_viewManager->getSelection()); | |
1252 | |
1253 Model *model = layer->getModel(); | |
1254 SparseOneDimensionalModel *sodm = | |
1255 dynamic_cast<SparseOneDimensionalModel *>(model); | |
1256 if (!sodm) return; | |
1257 | |
1258 if (!m_labeller) return; | |
1259 | |
1260 Labeller labeller(*m_labeller); | |
1261 labeller.setSampleRate(sodm->getSampleRate()); | |
1262 | |
1263 Command *c = labeller.subdivide<SparseOneDimensionalModel::Point> | |
1264 (*sodm, &ms, n); | |
1265 if (c) CommandHistory::getInstance()->addCommand(c, false); | |
1266 } | |
1267 | |
1268 void | |
1269 MainWindowBase::winnowInstantsBy(int n) | |
1270 { | |
1271 Pane *pane = m_paneStack->getCurrentPane(); | |
1272 if (!pane) return; | |
1273 | |
1274 Layer *layer = dynamic_cast<TimeInstantLayer *>(pane->getSelectedLayer()); | |
1275 if (!layer) return; | |
1276 | |
1277 MultiSelection ms(m_viewManager->getSelection()); | |
1278 | |
1279 Model *model = layer->getModel(); | |
1280 SparseOneDimensionalModel *sodm = | |
1281 dynamic_cast<SparseOneDimensionalModel *>(model); | |
1282 if (!sodm) return; | |
1283 | |
1284 if (!m_labeller) return; | |
1285 | |
1286 Labeller labeller(*m_labeller); | |
1287 labeller.setSampleRate(sodm->getSampleRate()); | |
1288 | |
1289 Command *c = labeller.winnow<SparseOneDimensionalModel::Point> | |
1290 (*sodm, &ms, n); | |
1291 if (c) CommandHistory::getInstance()->addCommand(c, false); | |
1202 } | 1292 } |
1203 | 1293 |
1204 MainWindowBase::FileOpenStatus | 1294 MainWindowBase::FileOpenStatus |
1205 MainWindowBase::openPath(QString fileOrUrl, AudioFileOpenMode mode) | 1295 MainWindowBase::openPath(QString fileOrUrl, AudioFileOpenMode mode) |
1206 { | 1296 { |
1239 } else if (rdfType == RDFImporter::NotRDF) { | 1329 } else if (rdfType == RDFImporter::NotRDF) { |
1240 rdf = false; | 1330 rdf = false; |
1241 } | 1331 } |
1242 } | 1332 } |
1243 | 1333 |
1244 if (rdf) { | 1334 try { |
1245 if (rdfSession) { | 1335 if (rdf) { |
1246 bool cancel = false; | 1336 if (rdfSession) { |
1247 if (!canImportLayer || shouldCreateNewSessionForRDFAudio(&cancel)) { | 1337 bool cancel = false; |
1248 return openSession(source); | 1338 if (!canImportLayer || shouldCreateNewSessionForRDFAudio(&cancel)) { |
1249 } else if (cancel) { | 1339 return openSession(source); |
1250 return FileOpenCancelled; | 1340 } else if (cancel) { |
1341 return FileOpenCancelled; | |
1342 } else { | |
1343 return openLayer(source); | |
1344 } | |
1251 } else { | 1345 } else { |
1252 return openLayer(source); | 1346 if ((status = openSession(source)) != FileOpenFailed) { |
1347 return status; | |
1348 } else if (!canImportLayer) { | |
1349 return FileOpenWrongMode; | |
1350 } else if ((status = openLayer(source)) != FileOpenFailed) { | |
1351 return status; | |
1352 } else { | |
1353 return FileOpenFailed; | |
1354 } | |
1253 } | 1355 } |
1356 } | |
1357 | |
1358 if (audio && (status = openAudio(source, mode)) != FileOpenFailed) { | |
1359 return status; | |
1360 } else if ((status = openSession(source)) != FileOpenFailed) { | |
1361 return status; | |
1362 } else if ((status = openPlaylist(source, mode)) != FileOpenFailed) { | |
1363 return status; | |
1364 } else if (!canImportLayer) { | |
1365 return FileOpenWrongMode; | |
1366 } else if ((status = openImage(source)) != FileOpenFailed) { | |
1367 return status; | |
1368 } else if ((status = openLayer(source)) != FileOpenFailed) { | |
1369 return status; | |
1254 } else { | 1370 } else { |
1255 if ((status = openSession(source)) != FileOpenFailed) { | 1371 return FileOpenFailed; |
1256 return status; | 1372 } |
1257 } else if (!canImportLayer) { | 1373 } catch (const InsufficientDiscSpace &e) { |
1258 return FileOpenWrongMode; | 1374 emit hideSplash(); |
1259 } else if ((status = openLayer(source)) != FileOpenFailed) { | 1375 m_openingAudioFile = false; |
1260 return status; | 1376 QMessageBox::critical |
1261 } else { | 1377 (this, tr("Not enough disc space"), |
1262 return FileOpenFailed; | 1378 tr("<b>Not enough disc space</b><p>There doesn't appear to be enough spare disc space to accommodate any necessary temporary files.</p><p>Please clear some space and try again.</p>").arg(e.what())); |
1263 } | 1379 return FileOpenFailed; |
1264 } | |
1265 } | |
1266 | |
1267 if (audio && (status = openAudio(source, mode)) != FileOpenFailed) { | |
1268 return status; | |
1269 } else if ((status = openSession(source)) != FileOpenFailed) { | |
1270 return status; | |
1271 } else if ((status = openPlaylist(source, mode)) != FileOpenFailed) { | |
1272 return status; | |
1273 } else if (!canImportLayer) { | |
1274 return FileOpenWrongMode; | |
1275 } else if ((status = openImage(source)) != FileOpenFailed) { | |
1276 return status; | |
1277 } else if ((status = openLayer(source)) != FileOpenFailed) { | |
1278 return status; | |
1279 } else { | |
1280 return FileOpenFailed; | |
1281 } | 1380 } |
1282 } | 1381 } |
1283 | 1382 |
1284 MainWindowBase::FileOpenStatus | 1383 MainWindowBase::FileOpenStatus |
1285 MainWindowBase::openAudio(FileSource source, AudioFileOpenMode mode, | 1384 MainWindowBase::openAudio(FileSource source, AudioFileOpenMode mode, |
1287 { | 1386 { |
1288 SVDEBUG << "MainWindowBase::openAudio(" << source.getLocation() << ") with mode " << mode << " and template " << templateName << endl; | 1387 SVDEBUG << "MainWindowBase::openAudio(" << source.getLocation() << ") with mode " << mode << " and template " << templateName << endl; |
1289 | 1388 |
1290 if (templateName == "") { | 1389 if (templateName == "") { |
1291 templateName = getDefaultSessionTemplate(); | 1390 templateName = getDefaultSessionTemplate(); |
1391 SVDEBUG << "(Default template is: \"" << templateName << "\")" << endl; | |
1292 } | 1392 } |
1293 | 1393 |
1294 // cerr << "template is: \"" << templateName << "\"" << endl; | 1394 // cerr << "template is: \"" << templateName << "\"" << endl; |
1295 | 1395 |
1296 if (!source.isAvailable()) { | 1396 if (!source.isAvailable()) { |
1308 sv_samplerate_t rate = 0; | 1408 sv_samplerate_t rate = 0; |
1309 | 1409 |
1310 if (Preferences::getInstance()->getFixedSampleRate() != 0) { | 1410 if (Preferences::getInstance()->getFixedSampleRate() != 0) { |
1311 rate = Preferences::getInstance()->getFixedSampleRate(); | 1411 rate = Preferences::getInstance()->getFixedSampleRate(); |
1312 } else if (Preferences::getInstance()->getResampleOnLoad()) { | 1412 } else if (Preferences::getInstance()->getResampleOnLoad()) { |
1313 rate = m_playSource->getSourceSampleRate(); | 1413 if (getMainModel()) { |
1314 } | 1414 rate = getMainModel()->getSampleRate(); |
1315 | 1415 } |
1316 WaveFileModel *newModel = new WaveFileModel(source, rate); | 1416 } |
1417 | |
1418 ReadOnlyWaveFileModel *newModel = new ReadOnlyWaveFileModel(source, rate); | |
1317 | 1419 |
1318 if (!newModel->isOK()) { | 1420 if (!newModel->isOK()) { |
1319 delete newModel; | 1421 delete newModel; |
1320 m_openingAudioFile = false; | 1422 m_openingAudioFile = false; |
1321 if (source.wasCancelled()) { | 1423 if (source.wasCancelled()) { |
1405 | 1507 |
1406 SVDEBUG << "SV looking for template " << templateName << endl; | 1508 SVDEBUG << "SV looking for template " << templateName << endl; |
1407 if (templateName != "") { | 1509 if (templateName != "") { |
1408 FileOpenStatus tplStatus = openSessionTemplate(templateName); | 1510 FileOpenStatus tplStatus = openSessionTemplate(templateName); |
1409 if (tplStatus == FileOpenCancelled) { | 1511 if (tplStatus == FileOpenCancelled) { |
1410 cerr << "Template load cancelled" << endl; | 1512 SVDEBUG << "Template load cancelled" << endl; |
1411 return FileOpenCancelled; | 1513 return FileOpenCancelled; |
1412 } | 1514 } |
1413 if (tplStatus != FileOpenFailed) { | 1515 if (tplStatus != FileOpenFailed) { |
1414 cerr << "Template load succeeded" << endl; | 1516 SVDEBUG << "Template load succeeded" << endl; |
1415 loadedTemplate = true; | 1517 loadedTemplate = true; |
1416 } | 1518 } |
1417 } | 1519 } |
1418 | 1520 |
1419 if (!loadedTemplate) { | 1521 if (!loadedTemplate) { |
1464 | 1566 |
1465 if (!source.isRemote()) m_audioFile = source.getLocalFilename(); | 1567 if (!source.isRemote()) m_audioFile = source.getLocalFilename(); |
1466 | 1568 |
1467 } else if (mode == CreateAdditionalModel) { | 1569 } else if (mode == CreateAdditionalModel) { |
1468 | 1570 |
1571 SVCERR << "Mode is CreateAdditionalModel" << endl; | |
1572 | |
1469 CommandHistory::getInstance()->startCompoundOperation | 1573 CommandHistory::getInstance()->startCompoundOperation |
1470 (tr("Import \"%1\"").arg(source.getBasename()), true); | 1574 (tr("Import \"%1\"").arg(source.getBasename()), true); |
1471 | 1575 |
1472 m_document->addImportedModel(newModel); | 1576 m_document->addImportedModel(newModel); |
1473 | 1577 |
1475 CommandHistory::getInstance()->addCommand(command); | 1579 CommandHistory::getInstance()->addCommand(command); |
1476 | 1580 |
1477 Pane *pane = command->getPane(); | 1581 Pane *pane = command->getPane(); |
1478 | 1582 |
1479 if (m_timeRulerLayer) { | 1583 if (m_timeRulerLayer) { |
1584 SVCERR << "Have time ruler, adding it" << endl; | |
1480 m_document->addLayerToView(pane, m_timeRulerLayer); | 1585 m_document->addLayerToView(pane, m_timeRulerLayer); |
1586 } else { | |
1587 SVCERR << "Do not have time ruler" << endl; | |
1481 } | 1588 } |
1482 | 1589 |
1483 Layer *newLayer = m_document->createImportedLayer(newModel); | 1590 Layer *newLayer = m_document->createImportedLayer(newModel); |
1484 | 1591 |
1485 if (newLayer) { | 1592 if (newLayer) { |
1765 | 1872 |
1766 return FileOpenSucceeded; | 1873 return FileOpenSucceeded; |
1767 } | 1874 } |
1768 | 1875 |
1769 MainWindowBase::FileOpenStatus | 1876 MainWindowBase::FileOpenStatus |
1877 MainWindowBase::openDirOfAudio(QString dirPath) | |
1878 { | |
1879 QDir dir(dirPath); | |
1880 QStringList files = dir.entryList(QDir::Files | QDir::Readable); | |
1881 files.sort(); | |
1882 | |
1883 FileOpenStatus status = FileOpenFailed; | |
1884 bool first = true; | |
1885 bool cancelled = false; | |
1886 | |
1887 foreach (QString file, files) { | |
1888 | |
1889 FileSource source(dir.filePath(file)); | |
1890 if (!source.isAvailable()) { | |
1891 continue; | |
1892 } | |
1893 | |
1894 if (AudioFileReaderFactory::getKnownExtensions().contains | |
1895 (source.getExtension().toLower())) { | |
1896 | |
1897 AudioFileOpenMode mode = CreateAdditionalModel; | |
1898 if (first) mode = ReplaceSession; | |
1899 | |
1900 switch (openAudio(source, mode)) { | |
1901 case FileOpenSucceeded: | |
1902 status = FileOpenSucceeded; | |
1903 first = false; | |
1904 break; | |
1905 case FileOpenFailed: | |
1906 break; | |
1907 case FileOpenCancelled: | |
1908 cancelled = true; | |
1909 break; | |
1910 case FileOpenWrongMode: | |
1911 break; | |
1912 } | |
1913 } | |
1914 | |
1915 if (cancelled) break; | |
1916 } | |
1917 | |
1918 return status; | |
1919 } | |
1920 | |
1921 MainWindowBase::FileOpenStatus | |
1770 MainWindowBase::openSessionPath(QString fileOrUrl) | 1922 MainWindowBase::openSessionPath(QString fileOrUrl) |
1771 { | 1923 { |
1772 ProgressDialog dialog(tr("Opening session..."), true, 2000, this); | 1924 ProgressDialog dialog(tr("Opening session..."), true, 2000, this); |
1773 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash())); | 1925 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash())); |
1774 return openSession(FileSource(fileOrUrl, &dialog)); | 1926 return openSession(FileSource(fileOrUrl, &dialog)); |
1874 .arg(source.getLocation())); | 2026 .arg(source.getLocation())); |
1875 | 2027 |
1876 if (!source.isRemote()) m_sessionFile = source.getLocalFilename(); | 2028 if (!source.isRemote()) m_sessionFile = source.getLocalFilename(); |
1877 | 2029 |
1878 setupMenus(); | 2030 setupMenus(); |
2031 findTimeRulerLayer(); | |
1879 | 2032 |
1880 CommandHistory::getInstance()->clear(); | 2033 CommandHistory::getInstance()->clear(); |
1881 CommandHistory::getInstance()->documentSaved(); | 2034 CommandHistory::getInstance()->documentSaved(); |
1882 m_documentModified = false; | 2035 m_documentModified = false; |
1883 updateMenuStates(); | 2036 updateMenuStates(); |
1966 if (ok) { | 2119 if (ok) { |
1967 | 2120 |
1968 emit activity(tr("Open session template \"%1\"").arg(source.getLocation())); | 2121 emit activity(tr("Open session template \"%1\"").arg(source.getLocation())); |
1969 | 2122 |
1970 setupMenus(); | 2123 setupMenus(); |
2124 findTimeRulerLayer(); | |
1971 | 2125 |
1972 CommandHistory::getInstance()->clear(); | 2126 CommandHistory::getInstance()->clear(); |
1973 CommandHistory::getInstance()->documentSaved(); | 2127 CommandHistory::getInstance()->documentSaved(); |
1974 m_documentModified = false; | 2128 m_documentModified = false; |
1975 updateMenuStates(); | 2129 updateMenuStates(); |
1996 createDocument(); | 2150 createDocument(); |
1997 | 2151 |
1998 FileOpenStatus status = openLayersFromRDF(source); | 2152 FileOpenStatus status = openLayersFromRDF(source); |
1999 | 2153 |
2000 setupMenus(); | 2154 setupMenus(); |
2155 findTimeRulerLayer(); | |
2001 | 2156 |
2002 setWindowTitle(tr("%1: %2") | 2157 setWindowTitle(tr("%1: %2") |
2003 .arg(QApplication::applicationName()) | 2158 .arg(QApplication::applicationName()) |
2004 .arg(source.getLocation())); | 2159 .arg(source.getLocation())); |
2005 CommandHistory::getInstance()->clear(); | 2160 CommandHistory::getInstance()->clear(); |
2022 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash())); | 2177 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash())); |
2023 | 2178 |
2024 if (getMainModel()) { | 2179 if (getMainModel()) { |
2025 rate = getMainModel()->getSampleRate(); | 2180 rate = getMainModel()->getSampleRate(); |
2026 } else if (Preferences::getInstance()->getResampleOnLoad()) { | 2181 } else if (Preferences::getInstance()->getResampleOnLoad()) { |
2027 rate = m_playSource->getSourceSampleRate(); | 2182 if (getMainModel()) { |
2183 rate = getMainModel()->getSampleRate(); | |
2184 } | |
2028 } | 2185 } |
2029 | 2186 |
2030 RDFImporter importer | 2187 RDFImporter importer |
2031 (QUrl::fromLocalFile(source.getLocalFilename()).toString(), rate); | 2188 (QUrl::fromLocalFile(source.getLocalFilename()).toString(), rate); |
2032 | 2189 |
2158 m_recentFiles.addFile(source.getLocation()); | 2315 m_recentFiles.addFile(source.getLocation()); |
2159 return FileOpenSucceeded; | 2316 return FileOpenSucceeded; |
2160 } | 2317 } |
2161 | 2318 |
2162 void | 2319 void |
2163 MainWindowBase::createPlayTarget() | 2320 MainWindowBase::createAudioIO() |
2164 { | 2321 { |
2165 if (m_playTarget) return; | 2322 if (m_playTarget || m_audioIO) return; |
2323 | |
2324 if (!(m_soundOptions & WithAudioOutput)) return; | |
2166 | 2325 |
2167 QSettings settings; | 2326 QSettings settings; |
2168 settings.beginGroup("Preferences"); | 2327 settings.beginGroup("Preferences"); |
2169 QString targetName = settings.value("audio-target", "").toString(); | 2328 QString implementation = settings.value |
2329 ("audio-target", "").toString(); | |
2330 QString suffix; | |
2331 if (implementation != "") suffix = "-" + implementation; | |
2332 QString recordDevice = settings.value | |
2333 ("audio-record-device" + suffix, "").toString(); | |
2334 QString playbackDevice = settings.value | |
2335 ("audio-playback-device" + suffix, "").toString(); | |
2170 settings.endGroup(); | 2336 settings.endGroup(); |
2171 | 2337 |
2172 AudioTargetFactory *factory = AudioTargetFactory::getInstance(); | 2338 if (implementation == "auto") { |
2173 | 2339 implementation = ""; |
2174 factory->setDefaultCallbackTarget(targetName); | 2340 } |
2175 m_playTarget = factory->createCallbackTarget(m_playSource); | 2341 |
2176 | 2342 breakfastquay::AudioFactory::Preference preference; |
2177 if (!m_playTarget) { | 2343 preference.implementation = implementation.toStdString(); |
2344 preference.recordDevice = recordDevice.toStdString(); | |
2345 preference.playbackDevice = playbackDevice.toStdString(); | |
2346 | |
2347 SVCERR << "createAudioIO: Preferred implementation = \"" | |
2348 << preference.implementation << "\"" << endl; | |
2349 SVCERR << "createAudioIO: Preferred playback device = \"" | |
2350 << preference.playbackDevice << "\"" << endl; | |
2351 SVCERR << "createAudioIO: Preferred record device = \"" | |
2352 << preference.recordDevice << "\"" << endl; | |
2353 | |
2354 if (!m_resamplerWrapper) { | |
2355 m_resamplerWrapper = new breakfastquay::ResamplerWrapper(m_playSource); | |
2356 m_playSource->setResamplerWrapper(m_resamplerWrapper); | |
2357 } | |
2358 | |
2359 std::string errorString; | |
2360 | |
2361 if (m_soundOptions & WithAudioInput) { | |
2362 m_audioIO = breakfastquay::AudioFactory:: | |
2363 createCallbackIO(m_recordTarget, m_resamplerWrapper, | |
2364 preference, errorString); | |
2365 if (m_audioIO) { | |
2366 m_audioIO->suspend(); // start in suspended state | |
2367 m_playSource->setSystemPlaybackTarget(m_audioIO); | |
2368 } | |
2369 } else { | |
2370 m_playTarget = breakfastquay::AudioFactory:: | |
2371 createCallbackPlayTarget(m_resamplerWrapper, | |
2372 preference, errorString); | |
2373 if (m_playTarget) { | |
2374 m_playTarget->suspend(); // start in suspended state | |
2375 m_playSource->setSystemPlaybackTarget(m_playTarget); | |
2376 } | |
2377 } | |
2378 | |
2379 if (!m_playTarget && !m_audioIO) { | |
2178 emit hideSplash(); | 2380 emit hideSplash(); |
2179 | 2381 QString message; |
2180 if (factory->isAutoCallbackTarget(targetName)) { | 2382 QString error = errorString.c_str(); |
2181 QMessageBox::warning | 2383 QString firstBit, secondBit; |
2182 (this, tr("Couldn't open audio device"), | 2384 if (implementation == "") { |
2183 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>"), | 2385 if (error == "") { |
2184 QMessageBox::Ok); | 2386 firstBit = tr("<b>No audio available</b><p>Could not open an audio device.</p>"); |
2387 } else { | |
2388 firstBit = tr("<b>No audio available</b><p>Could not open audio device: %1</p>").arg(error); | |
2389 } | |
2390 if (m_soundOptions & WithAudioInput) { | |
2391 secondBit = tr("<p>Automatic audio device detection failed. Audio playback and recording will not be available during this session.</p>"); | |
2392 } else { | |
2393 secondBit = tr("<p>Automatic audio device detection failed. Audio playback will not be available during this session.</p>"); | |
2394 } | |
2185 } else { | 2395 } else { |
2186 QMessageBox::warning | 2396 QString driverName = breakfastquay::AudioFactory:: |
2187 (this, tr("Couldn't open audio device"), | 2397 getImplementationDescription(implementation.toStdString()) |
2188 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>") | 2398 .c_str(); |
2189 .arg(factory->getCallbackTargetDescription(targetName)), | 2399 if (error == "") { |
2190 QMessageBox::Ok); | 2400 firstBit = tr("<b>No audio available</b><p>Failed to open your preferred audio driver (\"%1\").</p>").arg(driverName); |
2191 } | 2401 } else { |
2192 } | 2402 firstBit = tr("<b>No audio available</b><p>Failed to open your preferred audio driver (\"%1\"): %2.</p>").arg(driverName).arg(error); |
2403 } | |
2404 if (m_soundOptions & WithAudioInput) { | |
2405 secondBit = tr("<p>Audio playback and recording will not be available during this session.</p>"); | |
2406 } else { | |
2407 secondBit = tr("<p>Audio playback will not be available during this session.</p>"); | |
2408 } | |
2409 } | |
2410 SVDEBUG << "createAudioIO: ERROR: Failed to open audio device \"" | |
2411 << implementation << "\": error is: " << error << endl; | |
2412 QMessageBox::warning(this, tr("Couldn't open audio device"), | |
2413 firstBit + secondBit, QMessageBox::Ok); | |
2414 } | |
2415 } | |
2416 | |
2417 void | |
2418 MainWindowBase::deleteAudioIO() | |
2419 { | |
2420 // First prevent this trying to call target. | |
2421 if (m_playSource) { | |
2422 m_playSource->setSystemPlaybackTarget(0); | |
2423 m_playSource->setResamplerWrapper(0); | |
2424 } | |
2425 | |
2426 // Then delete the breakfastquay::System object. | |
2427 // Only one of these two exists! | |
2428 delete m_audioIO; | |
2429 delete m_playTarget; | |
2430 | |
2431 // And the breakfastquay resampler wrapper. We need to | |
2432 // delete/recreate this if the channel count changes, which is one | |
2433 // of the use cases for recreateAudioIO() calling this | |
2434 delete m_resamplerWrapper; | |
2435 | |
2436 m_audioIO = 0; | |
2437 m_playTarget = 0; | |
2438 m_resamplerWrapper = 0; | |
2439 } | |
2440 | |
2441 void | |
2442 MainWindowBase::recreateAudioIO() | |
2443 { | |
2444 deleteAudioIO(); | |
2445 createAudioIO(); | |
2446 } | |
2447 | |
2448 void | |
2449 MainWindowBase::audioChannelCountIncreased(int) | |
2450 { | |
2451 recreateAudioIO(); | |
2193 } | 2452 } |
2194 | 2453 |
2195 WaveFileModel * | 2454 WaveFileModel * |
2196 MainWindowBase::getMainModel() | 2455 MainWindowBase::getMainModel() |
2197 { | 2456 { |
2233 this, SLOT(modelRegenerationWarning(QString, QString, QString))); | 2492 this, SLOT(modelRegenerationWarning(QString, QString, QString))); |
2234 connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)), | 2493 connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)), |
2235 this, SLOT(modelGenerationFailed(QString, QString))); | 2494 this, SLOT(modelGenerationFailed(QString, QString))); |
2236 connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)), | 2495 connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)), |
2237 this, SLOT(modelRegenerationWarning(QString, QString, QString))); | 2496 this, SLOT(modelRegenerationWarning(QString, QString, QString))); |
2238 connect(m_document, SIGNAL(alignmentFailed(QString, QString)), | 2497 connect(m_document, SIGNAL(alignmentComplete(AlignmentModel *)), |
2239 this, SLOT(alignmentFailed(QString, QString))); | 2498 this, SLOT(alignmentComplete(AlignmentModel *))); |
2499 connect(m_document, SIGNAL(alignmentFailed(QString)), | |
2500 this, SLOT(alignmentFailed(QString))); | |
2240 | 2501 |
2241 emit replacedDocument(); | 2502 emit replacedDocument(); |
2242 } | 2503 } |
2243 | 2504 |
2244 bool | 2505 bool |
2478 | 2739 |
2479 void | 2740 void |
2480 MainWindowBase::showAllOverlays() | 2741 MainWindowBase::showAllOverlays() |
2481 { | 2742 { |
2482 m_viewManager->setOverlayMode(ViewManager::AllOverlays); | 2743 m_viewManager->setOverlayMode(ViewManager::AllOverlays); |
2744 } | |
2745 | |
2746 void | |
2747 MainWindowBase::findTimeRulerLayer() | |
2748 { | |
2749 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) { | |
2750 Pane *pane = m_paneStack->getPane(i); | |
2751 if (!pane) continue; | |
2752 for (int j = 0; j < pane->getLayerCount(); ++j) { | |
2753 Layer *layer = pane->getLayer(j); | |
2754 if (!dynamic_cast<TimeRulerLayer *>(layer)) continue; | |
2755 m_timeRulerLayer = layer; | |
2756 return; | |
2757 } | |
2758 } | |
2759 if (m_timeRulerLayer) { | |
2760 SVCERR << "WARNING: Time ruler layer was not reset to 0 before session template loaded?" << endl; | |
2761 delete m_timeRulerLayer; | |
2762 m_timeRulerLayer = 0; | |
2763 } | |
2483 } | 2764 } |
2484 | 2765 |
2485 void | 2766 void |
2486 MainWindowBase::toggleTimeRulers() | 2767 MainWindowBase::toggleTimeRulers() |
2487 { | 2768 { |
2618 } | 2899 } |
2619 | 2900 |
2620 void | 2901 void |
2621 MainWindowBase::play() | 2902 MainWindowBase::play() |
2622 { | 2903 { |
2623 if (m_playSource->isPlaying()) { | 2904 if ((m_recordTarget && m_recordTarget->isRecording()) || |
2905 (m_playSource && m_playSource->isPlaying())) { | |
2624 stop(); | 2906 stop(); |
2907 QAction *action = qobject_cast<QAction *>(sender()); | |
2908 if (action) action->setChecked(false); | |
2625 } else { | 2909 } else { |
2910 if (m_audioIO) m_audioIO->resume(); | |
2911 else if (m_playTarget) m_playTarget->resume(); | |
2626 playbackFrameChanged(m_viewManager->getPlaybackFrame()); | 2912 playbackFrameChanged(m_viewManager->getPlaybackFrame()); |
2627 m_playSource->play(m_viewManager->getPlaybackFrame()); | 2913 m_playSource->play(m_viewManager->getPlaybackFrame()); |
2628 } | 2914 } |
2915 } | |
2916 | |
2917 void | |
2918 MainWindowBase::record() | |
2919 { | |
2920 if (!(m_soundOptions & WithAudioInput)) { | |
2921 return; | |
2922 } | |
2923 | |
2924 if (!m_recordTarget) { | |
2925 //!!! report | |
2926 return; | |
2927 } | |
2928 | |
2929 if (!m_audioIO) { | |
2930 cerr << "MainWindowBase::record: about to create audio IO" << endl; | |
2931 createAudioIO(); | |
2932 } | |
2933 | |
2934 if (!m_audioIO) { | |
2935 // don't need to report this, createAudioIO already should have | |
2936 return; | |
2937 } | |
2938 | |
2939 if (m_recordTarget->isRecording()) { | |
2940 stop(); | |
2941 return; | |
2942 } | |
2943 | |
2944 QAction *action = qobject_cast<QAction *>(sender()); | |
2945 | |
2946 if (m_audioRecordMode == RecordReplaceSession) { | |
2947 if (!checkSaveModified()) { | |
2948 if (action) action->setChecked(false); | |
2949 return; | |
2950 } | |
2951 } | |
2952 | |
2953 if (m_viewManager) m_viewManager->setGlobalCentreFrame(0); | |
2954 | |
2955 cerr << "MainWindowBase::record: about to resume" << endl; | |
2956 m_audioIO->resume(); | |
2957 | |
2958 WritableWaveFileModel *model = m_recordTarget->startRecording(); | |
2959 if (!model) { | |
2960 cerr << "ERROR: MainWindowBase::record: Recording failed" << endl; | |
2961 //!!! report | |
2962 if (action) action->setChecked(false); | |
2963 return; | |
2964 } | |
2965 | |
2966 if (!model->isOK()) { | |
2967 m_recordTarget->stopRecording(); | |
2968 m_audioIO->suspend(); | |
2969 delete model; | |
2970 return; | |
2971 } | |
2972 | |
2973 PlayParameterRepository::getInstance()->addPlayable(model); | |
2974 | |
2975 if (m_audioRecordMode == RecordReplaceSession || !getMainModel()) { | |
2976 | |
2977 //!!! duplication with openAudio here | |
2978 | |
2979 QString templateName = getDefaultSessionTemplate(); | |
2980 bool loadedTemplate = false; | |
2981 | |
2982 if (templateName != "") { | |
2983 FileOpenStatus tplStatus = openSessionTemplate(templateName); | |
2984 if (tplStatus == FileOpenCancelled) { | |
2985 m_recordTarget->stopRecording(); | |
2986 m_audioIO->suspend(); | |
2987 PlayParameterRepository::getInstance()->removePlayable(model); | |
2988 return; | |
2989 } | |
2990 if (tplStatus != FileOpenFailed) { | |
2991 loadedTemplate = true; | |
2992 } | |
2993 } | |
2994 | |
2995 if (!loadedTemplate) { | |
2996 closeSession(); | |
2997 createDocument(); | |
2998 } | |
2999 | |
3000 Model *prevMain = getMainModel(); | |
3001 if (prevMain) { | |
3002 m_playSource->removeModel(prevMain); | |
3003 PlayParameterRepository::getInstance()->removePlayable(prevMain); | |
3004 } | |
3005 | |
3006 m_document->setMainModel(model); | |
3007 setupMenus(); | |
3008 findTimeRulerLayer(); | |
3009 | |
3010 if (loadedTemplate || (m_sessionFile == "")) { | |
3011 //!!! shouldn't be dealing directly with title from here -- call a method | |
3012 setWindowTitle(tr("%1: %2") | |
3013 .arg(QApplication::applicationName()) | |
3014 .arg(model->getLocation())); | |
3015 CommandHistory::getInstance()->clear(); | |
3016 CommandHistory::getInstance()->documentSaved(); | |
3017 m_documentModified = false; | |
3018 } else { | |
3019 setWindowTitle(tr("%1: %2 [%3]") | |
3020 .arg(QApplication::applicationName()) | |
3021 .arg(QFileInfo(m_sessionFile).fileName()) | |
3022 .arg(model->getLocation())); | |
3023 if (m_documentModified) { | |
3024 m_documentModified = false; | |
3025 documentModified(); // so as to restore "(modified)" window title | |
3026 } | |
3027 } | |
3028 | |
3029 } else { | |
3030 | |
3031 CommandHistory::getInstance()->startCompoundOperation | |
3032 (tr("Import Recorded Audio"), true); | |
3033 | |
3034 m_document->addImportedModel(model); | |
3035 | |
3036 AddPaneCommand *command = new AddPaneCommand(this); | |
3037 CommandHistory::getInstance()->addCommand(command); | |
3038 | |
3039 Pane *pane = command->getPane(); | |
3040 | |
3041 if (m_timeRulerLayer) { | |
3042 m_document->addLayerToView(pane, m_timeRulerLayer); | |
3043 } | |
3044 | |
3045 Layer *newLayer = m_document->createImportedLayer(model); | |
3046 | |
3047 if (newLayer) { | |
3048 m_document->addLayerToView(pane, newLayer); | |
3049 } | |
3050 | |
3051 CommandHistory::getInstance()->endCompoundOperation(); | |
3052 } | |
3053 | |
3054 updateMenuStates(); | |
3055 m_recentFiles.addFile(model->getLocation()); | |
3056 currentPaneChanged(m_paneStack->getCurrentPane()); | |
3057 | |
3058 emit audioFileLoaded(); | |
2629 } | 3059 } |
2630 | 3060 |
2631 void | 3061 void |
2632 MainWindowBase::ffwd() | 3062 MainWindowBase::ffwd() |
2633 { | 3063 { |
2854 } | 3284 } |
2855 | 3285 |
2856 void | 3286 void |
2857 MainWindowBase::stop() | 3287 MainWindowBase::stop() |
2858 { | 3288 { |
3289 if (m_recordTarget && | |
3290 m_recordTarget->isRecording()) { | |
3291 m_recordTarget->stopRecording(); | |
3292 } | |
3293 | |
3294 if (!m_playSource) return; | |
3295 | |
2859 m_playSource->stop(); | 3296 m_playSource->stop(); |
2860 | 3297 |
3298 if (m_audioIO) m_audioIO->suspend(); | |
3299 else if (m_playTarget) m_playTarget->suspend(); | |
3300 | |
2861 if (m_paneStack && m_paneStack->getCurrentPane()) { | 3301 if (m_paneStack && m_paneStack->getCurrentPane()) { |
2862 updateVisibleRangeDisplay(m_paneStack->getCurrentPane()); | 3302 updateVisibleRangeDisplay(m_paneStack->getCurrentPane()); |
2863 } else { | 3303 } else { |
2864 m_myStatusMessage = ""; | 3304 m_myStatusMessage = ""; |
2865 getStatusLabel()->setText(""); | 3305 getStatusLabel()->setText(""); |
3189 remainingStr = (then - now).toText(true).c_str(); | 3629 remainingStr = (then - now).toText(true).c_str(); |
3190 } | 3630 } |
3191 | 3631 |
3192 m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)") | 3632 m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)") |
3193 .arg(nowStr).arg(thenStr).arg(remainingStr); | 3633 .arg(nowStr).arg(thenStr).arg(remainingStr); |
3634 | |
3635 getStatusLabel()->setText(m_myStatusMessage); | |
3636 } | |
3637 | |
3638 void | |
3639 MainWindowBase::recordDurationChanged(sv_frame_t frame, sv_samplerate_t rate) | |
3640 { | |
3641 RealTime duration = RealTime::frame2RealTime(frame, rate); | |
3642 QString durStr = duration.toSecText().c_str(); | |
3643 | |
3644 m_myStatusMessage = tr("Recording: %1").arg(durStr); | |
3194 | 3645 |
3195 getStatusLabel()->setText(m_myStatusMessage); | 3646 getStatusLabel()->setText(m_myStatusMessage); |
3196 } | 3647 } |
3197 | 3648 |
3198 void | 3649 void |
3324 MainWindowBase::mainModelChanged(WaveFileModel *model) | 3775 MainWindowBase::mainModelChanged(WaveFileModel *model) |
3325 { | 3776 { |
3326 // SVDEBUG << "MainWindowBase::mainModelChanged(" << model << ")" << endl; | 3777 // SVDEBUG << "MainWindowBase::mainModelChanged(" << model << ")" << endl; |
3327 updateDescriptionLabel(); | 3778 updateDescriptionLabel(); |
3328 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate()); | 3779 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate()); |
3329 if (model && !m_playTarget && m_audioOutput) { | 3780 if (model && !(m_playTarget || m_audioIO) && |
3330 createPlayTarget(); | 3781 (m_soundOptions & WithAudioOutput)) { |
3782 createAudioIO(); | |
3331 } | 3783 } |
3332 } | 3784 } |
3333 | 3785 |
3334 void | 3786 void |
3335 MainWindowBase::modelAboutToBeDeleted(Model *model) | 3787 MainWindowBase::modelAboutToBeDeleted(Model *model) |
3337 // SVDEBUG << "MainWindowBase::modelAboutToBeDeleted(" << model << ")" << endl; | 3789 // SVDEBUG << "MainWindowBase::modelAboutToBeDeleted(" << model << ")" << endl; |
3338 if (model == m_viewManager->getPlaybackModel()) { | 3790 if (model == m_viewManager->getPlaybackModel()) { |
3339 m_viewManager->setPlaybackModel(0); | 3791 m_viewManager->setPlaybackModel(0); |
3340 } | 3792 } |
3341 m_playSource->removeModel(model); | 3793 m_playSource->removeModel(model); |
3342 FFTDataServer::modelAboutToBeDeleted(model); | |
3343 } | 3794 } |
3344 | 3795 |
3345 void | 3796 void |
3346 MainWindowBase::paneDeleteButtonClicked(Pane *pane) | 3797 MainWindowBase::paneDeleteButtonClicked(Pane *pane) |
3347 { | 3798 { |
3374 CommandHistory::getInstance()->addCommand(command); | 3825 CommandHistory::getInstance()->addCommand(command); |
3375 | 3826 |
3376 CommandHistory::getInstance()->endCompoundOperation(); | 3827 CommandHistory::getInstance()->endCompoundOperation(); |
3377 | 3828 |
3378 updateMenuStates(); | 3829 updateMenuStates(); |
3830 } | |
3831 | |
3832 void | |
3833 MainWindowBase::alignmentComplete(AlignmentModel *model) | |
3834 { | |
3835 cerr << "MainWindowBase::alignmentComplete(" << model << ")" << endl; | |
3379 } | 3836 } |
3380 | 3837 |
3381 void | 3838 void |
3382 MainWindowBase::pollOSC() | 3839 MainWindowBase::pollOSC() |
3383 { | 3840 { |
3455 } | 3912 } |
3456 #endif | 3913 #endif |
3457 #endif | 3914 #endif |
3458 } | 3915 } |
3459 | 3916 |
3460 | 3917 void |
3918 MainWindowBase::openLocalFolder(QString path) | |
3919 { | |
3920 QDir d(path); | |
3921 if (d.exists()) { | |
3922 QStringList args; | |
3923 QString path = d.canonicalPath(); | |
3924 #if defined Q_OS_WIN32 | |
3925 // Although the Win32 API is quite happy to have | |
3926 // forward slashes as directory separators, Windows | |
3927 // Explorer is not | |
3928 path = path.replace('/', '\\'); | |
3929 args << path; | |
3930 QProcess::execute("c:/windows/explorer.exe", args); | |
3931 #else | |
3932 args << path; | |
3933 QProcess::execute( | |
3934 #if defined Q_OS_MAC | |
3935 "/usr/bin/open", | |
3936 #else | |
3937 "/usr/bin/xdg-open", | |
3938 #endif | |
3939 args); | |
3940 #endif | |
3941 } | |
3942 } | |
3943 |