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