Mercurial > hg > svapp
comparison framework/MainWindowBase.cpp @ 548:baa11365ebdd bqaudioio
Merge from branch bqresample
| author | Chris Cannam | 
|---|---|
| date | Wed, 07 Dec 2016 11:51:42 +0000 | 
| parents | 82d7e5cf7517 0d5c3abc9658 | 
| children | b9d8c7a690d6 | 
   comparison
  equal
  deleted
  inserted
  replaced
| 547:82d7e5cf7517 | 548:baa11365ebdd | 
|---|---|
| 14 */ | 14 */ | 
| 15 | 15 | 
| 16 #include "MainWindowBase.h" | 16 #include "MainWindowBase.h" | 
| 17 #include "Document.h" | 17 #include "Document.h" | 
| 18 | 18 | 
| 19 | |
| 20 #include "view/Pane.h" | 19 #include "view/Pane.h" | 
| 21 #include "view/PaneStack.h" | 20 #include "view/PaneStack.h" | 
| 22 #include "data/model/WaveFileModel.h" | 21 #include "data/model/ReadOnlyWaveFileModel.h" | 
| 22 #include "data/model/WritableWaveFileModel.h" | |
| 23 #include "data/model/SparseOneDimensionalModel.h" | 23 #include "data/model/SparseOneDimensionalModel.h" | 
| 24 #include "data/model/NoteModel.h" | 24 #include "data/model/NoteModel.h" | 
| 25 #include "data/model/FlexiNoteModel.h" | 25 #include "data/model/FlexiNoteModel.h" | 
| 26 #include "data/model/Labeller.h" | 26 #include "data/model/Labeller.h" | 
| 27 #include "data/model/TabularModel.h" | 27 #include "data/model/TabularModel.h" | 
| 46 #include "widgets/CSVFormatDialog.h" | 46 #include "widgets/CSVFormatDialog.h" | 
| 47 #include "widgets/ModelDataTableDialog.h" | 47 #include "widgets/ModelDataTableDialog.h" | 
| 48 #include "widgets/InteractiveFileFinder.h" | 48 #include "widgets/InteractiveFileFinder.h" | 
| 49 | 49 | 
| 50 #include "audio/AudioCallbackPlaySource.h" | 50 #include "audio/AudioCallbackPlaySource.h" | 
| 51 #include "audio/AudioRecordTarget.h" | |
| 51 #include "audio/PlaySpeedRangeMapper.h" | 52 #include "audio/PlaySpeedRangeMapper.h" | 
| 53 | |
| 52 #include "data/fileio/DataFileReaderFactory.h" | 54 #include "data/fileio/DataFileReaderFactory.h" | 
| 53 #include "data/fileio/PlaylistFileReader.h" | 55 #include "data/fileio/PlaylistFileReader.h" | 
| 54 #include "data/fileio/WavFileWriter.h" | 56 #include "data/fileio/WavFileWriter.h" | 
| 55 #include "data/fileio/MIDIFileWriter.h" | 57 #include "data/fileio/MIDIFileWriter.h" | 
| 56 #include "data/fileio/BZipFileDevice.h" | 58 #include "data/fileio/BZipFileDevice.h" | 
| 57 #include "data/fileio/FileSource.h" | 59 #include "data/fileio/FileSource.h" | 
| 58 #include "data/fileio/AudioFileReaderFactory.h" | 60 #include "data/fileio/AudioFileReaderFactory.h" | 
| 59 #include "rdf/RDFImporter.h" | 61 #include "rdf/RDFImporter.h" | 
| 60 | 62 | 
| 61 #include "data/fft/FFTDataServer.h" | |
| 62 | |
| 63 #include "base/RecentFiles.h" | 63 #include "base/RecentFiles.h" | 
| 64 | 64 | 
| 65 #include "base/PlayParameterRepository.h" | 65 #include "base/PlayParameterRepository.h" | 
| 66 #include "base/XmlExportable.h" | 66 #include "base/XmlExportable.h" | 
| 67 #include "base/Profiler.h" | 67 #include "base/Profiler.h" | 
| 72 | 72 | 
| 73 #include "data/osc/OSCQueue.h" | 73 #include "data/osc/OSCQueue.h" | 
| 74 #include "data/midi/MIDIInput.h" | 74 #include "data/midi/MIDIInput.h" | 
| 75 | 75 | 
| 76 #include <bqaudioio/SystemPlaybackTarget.h> | 76 #include <bqaudioio/SystemPlaybackTarget.h> | 
| 77 #include <bqaudioio/SystemAudioIO.h> | |
| 77 #include <bqaudioio/AudioFactory.h> | 78 #include <bqaudioio/AudioFactory.h> | 
| 78 | 79 | 
| 79 #include <QApplication> | 80 #include <QApplication> | 
| 80 #include <QMessageBox> | 81 #include <QMessageBox> | 
| 81 #include <QGridLayout> | 82 #include <QGridLayout> | 
| 130 return 0; | 131 return 0; | 
| 131 } | 132 } | 
| 132 #undef Window | 133 #undef Window | 
| 133 #endif | 134 #endif | 
| 134 | 135 | 
| 135 MainWindowBase::MainWindowBase(bool withAudioOutput, | 136 MainWindowBase::MainWindowBase(SoundOptions options) : | 
| 136 bool withMIDIInput) : | |
| 137 m_document(0), | 137 m_document(0), | 
| 138 m_paneStack(0), | 138 m_paneStack(0), | 
| 139 m_viewManager(0), | 139 m_viewManager(0), | 
| 140 m_timeRulerLayer(0), | 140 m_timeRulerLayer(0), | 
| 141 m_audioOutput(withAudioOutput), | 141 m_soundOptions(options), | 
| 142 m_playSource(0), | 142 m_playSource(0), | 
| 143 m_recordTarget(0), | |
| 143 m_playTarget(0), | 144 m_playTarget(0), | 
| 145 m_audioIO(0), | |
| 144 m_oscQueue(0), | 146 m_oscQueue(0), | 
| 145 m_oscQueueStarter(0), | 147 m_oscQueueStarter(0), | 
| 146 m_midiInput(0), | 148 m_midiInput(0), | 
| 147 m_recentFiles("RecentFiles", 20), | 149 m_recentFiles("RecentFiles", 20), | 
| 148 m_recentTransforms("RecentTransforms", 20), | 150 m_recentTransforms("RecentTransforms", 20), | 
| 151 m_abandoning(false), | 153 m_abandoning(false), | 
| 152 m_labeller(0), | 154 m_labeller(0), | 
| 153 m_lastPlayStatusSec(0), | 155 m_lastPlayStatusSec(0), | 
| 154 m_initialDarkBackground(false), | 156 m_initialDarkBackground(false), | 
| 155 m_defaultFfwdRwdStep(2, 0), | 157 m_defaultFfwdRwdStep(2, 0), | 
| 158 m_audioRecordMode(RecordCreateAdditionalModel), | |
| 156 m_statusLabel(0), | 159 m_statusLabel(0), | 
| 160 m_iconsVisibleInMenus(true), | |
| 157 m_menuShortcutMapper(0) | 161 m_menuShortcutMapper(0) | 
| 158 { | 162 { | 
| 159 Profiler profiler("MainWindowBase::MainWindowBase"); | 163 Profiler profiler("MainWindowBase::MainWindowBase"); | 
| 160 | 164 | 
| 165 if (options & WithAudioInput) { | |
| 166 if (!(options & WithAudioOutput)) { | |
| 167 cerr << "WARNING: MainWindowBase: WithAudioInput requires WithAudioOutput -- recording will not work" << endl; | |
| 168 } | |
| 169 } | |
| 170 | |
| 161 qRegisterMetaType<sv_frame_t>("sv_frame_t"); | 171 qRegisterMetaType<sv_frame_t>("sv_frame_t"); | 
| 162 qRegisterMetaType<sv_samplerate_t>("sv_samplerate_t"); | 172 qRegisterMetaType<sv_samplerate_t>("sv_samplerate_t"); | 
| 163 | 173 | 
| 164 #ifdef Q_WS_X11 | 174 #ifdef Q_WS_X11 | 
| 165 XSetErrorHandler(handle_x11_error); | 175 XSetErrorHandler(handle_x11_error); | 
| 185 settings.beginGroup("Preferences"); | 195 settings.beginGroup("Preferences"); | 
| 186 viewFontSize = settings.value("view-font-size", viewFontSize).toInt(); | 196 viewFontSize = settings.value("view-font-size", viewFontSize).toInt(); | 
| 187 settings.setValue("view-font-size", viewFontSize); | 197 settings.setValue("view-font-size", viewFontSize); | 
| 188 settings.endGroup(); | 198 settings.endGroup(); | 
| 189 | 199 | 
| 200 #ifdef NOT_DEFINED // This no longer works correctly on any platform AFAICS | |
| 190 Preferences::BackgroundMode mode = | 201 Preferences::BackgroundMode mode = | 
| 191 Preferences::getInstance()->getBackgroundMode(); | 202 Preferences::getInstance()->getBackgroundMode(); | 
| 192 m_initialDarkBackground = m_viewManager->getGlobalDarkBackground(); | 203 m_initialDarkBackground = m_viewManager->getGlobalDarkBackground(); | 
| 193 if (mode != Preferences::BackgroundFromTheme) { | 204 if (mode != Preferences::BackgroundFromTheme) { | 
| 194 m_viewManager->setGlobalDarkBackground | 205 m_viewManager->setGlobalDarkBackground | 
| 195 (mode == Preferences::DarkBackground); | 206 (mode == Preferences::DarkBackground); | 
| 196 } | 207 } | 
| 208 #endif | |
| 197 | 209 | 
| 198 m_paneStack = new PaneStack(0, m_viewManager); | 210 m_paneStack = new PaneStack(0, m_viewManager); | 
| 199 connect(m_paneStack, SIGNAL(currentPaneChanged(Pane *)), | 211 connect(m_paneStack, SIGNAL(currentPaneChanged(Pane *)), | 
| 200 this, SLOT(currentPaneChanged(Pane *))); | 212 this, SLOT(currentPaneChanged(Pane *))); | 
| 201 connect(m_paneStack, SIGNAL(currentLayerChanged(Pane *, Layer *)), | 213 connect(m_paneStack, SIGNAL(currentLayerChanged(Pane *, Layer *)), | 
| 217 connect(m_paneStack, SIGNAL(paneDeleteButtonClicked(Pane *)), | 229 connect(m_paneStack, SIGNAL(paneDeleteButtonClicked(Pane *)), | 
| 218 this, SLOT(paneDeleteButtonClicked(Pane *))); | 230 this, SLOT(paneDeleteButtonClicked(Pane *))); | 
| 219 | 231 | 
| 220 m_playSource = new AudioCallbackPlaySource(m_viewManager, | 232 m_playSource = new AudioCallbackPlaySource(m_viewManager, | 
| 221 QApplication::applicationName()); | 233 QApplication::applicationName()); | 
| 234 if (m_soundOptions & WithAudioInput) { | |
| 235 m_recordTarget = new AudioRecordTarget(m_viewManager, | |
| 236 QApplication::applicationName()); | |
| 237 connect(m_recordTarget, SIGNAL(recordDurationChanged(sv_frame_t, sv_samplerate_t)), | |
| 238 this, SLOT(recordDurationChanged(sv_frame_t, sv_samplerate_t))); | |
| 239 } | |
| 222 | 240 | 
| 223 connect(m_playSource, SIGNAL(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool)), | 241 connect(m_playSource, SIGNAL(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool)), | 
| 224 this, SLOT(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool))); | 242 this, SLOT(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool))); | 
| 225 connect(m_playSource, SIGNAL(audioOverloadPluginDisabled()), | 243 connect(m_playSource, SIGNAL(audioOverloadPluginDisabled()), | 
| 226 this, SLOT(audioOverloadPluginDisabled())); | 244 this, SLOT(audioOverloadPluginDisabled())); | 
| 257 settings.endGroup(); | 275 settings.endGroup(); | 
| 258 | 276 | 
| 259 m_labeller = new Labeller(labellerType); | 277 m_labeller = new Labeller(labellerType); | 
| 260 m_labeller->setCounterCycleSize(cycle); | 278 m_labeller->setCounterCycleSize(cycle); | 
| 261 | 279 | 
| 262 if (withMIDIInput) { | 280 if (m_soundOptions & WithMIDIInput) { | 
| 263 m_midiInput = new MIDIInput(QApplication::applicationName(), this); | 281 m_midiInput = new MIDIInput(QApplication::applicationName(), this); | 
| 264 } | 282 } | 
| 265 | 283 | 
| 266 QTimer::singleShot(1500, this, SIGNAL(hideSplash())); | 284 QTimer::singleShot(1500, this, SIGNAL(hideSplash())); | 
| 267 } | 285 } | 
| 268 | 286 | 
| 269 MainWindowBase::~MainWindowBase() | 287 MainWindowBase::~MainWindowBase() | 
| 270 { | 288 { | 
| 271 SVDEBUG << "MainWindowBase::~MainWindowBase" << endl; | 289 SVDEBUG << "MainWindowBase::~MainWindowBase" << endl; | 
| 290 | |
| 291 // We have to delete the breakfastquay::SystemPlaybackTarget or | |
| 292 // breakfastquay::SystemAudioIO object (whichever we have -- it | |
| 293 // depends on whether we handle recording or not) before we delete | |
| 294 // the ApplicationPlaybackSource and ApplicationRecordTarget that | |
| 295 // they refer to. | |
| 296 | |
| 297 // First prevent this trying to call target. | |
| 298 if (m_playSource) m_playSource->setSystemPlaybackTarget(0); | |
| 299 | |
| 300 // Then delete the breakfastquay::System object. | |
| 301 // Only one of these two exists! | |
| 302 delete m_audioIO; | |
| 272 delete m_playTarget; | 303 delete m_playTarget; | 
| 304 | |
| 305 // Then delete the Application objects. | |
| 273 delete m_playSource; | 306 delete m_playSource; | 
| 307 delete m_recordTarget; | |
| 308 | |
| 274 delete m_viewManager; | 309 delete m_viewManager; | 
| 275 delete m_oscQueue; | 310 delete m_oscQueue; | 
| 276 delete m_oscQueueStarter; | 311 delete m_oscQueueStarter; | 
| 277 delete m_midiInput; | 312 delete m_midiInput; | 
| 278 Profiles::getInstance()->dump(); | 313 Profiles::getInstance()->dump(); | 
| 313 if (menu) finaliseMenu(menu); | 348 if (menu) finaliseMenu(menu); | 
| 314 } | 349 } | 
| 315 } | 350 } | 
| 316 | 351 | 
| 317 void | 352 void | 
| 318 MainWindowBase::finaliseMenu(QMenu * | 353 MainWindowBase::finaliseMenu(QMenu *menu) | 
| 319 #ifdef Q_OS_MAC | 354 { | 
| 320 menu | 355 foreach (QAction *a, menu->actions()) { | 
| 321 #endif | 356 a->setIconVisibleInMenu(m_iconsVisibleInMenus); | 
| 322 ) | 357 } | 
| 323 { | 358 | 
| 324 #ifdef Q_OS_MAC | 359 #ifdef Q_OS_MAC | 
| 325 // See https://bugreports.qt-project.org/browse/QTBUG-38256 and | 360 // See https://bugreports.qt-project.org/browse/QTBUG-38256 and | 
| 326 // our issue #890 http://code.soundsoftware.ac.uk/issues/890 -- | 361 // our issue #890 http://code.soundsoftware.ac.uk/issues/890 -- | 
| 327 // single-key shortcuts that are associated only with a menu | 362 // 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 | 363 // action (and not with a toolbar button) do not work with Qt 5.x | 
| 550 (haveCurrentPane && | 585 (haveCurrentPane && | 
| 551 (currentLayer != 0)); | 586 (currentLayer != 0)); | 
| 552 bool haveMainModel = | 587 bool haveMainModel = | 
| 553 (getMainModel() != 0); | 588 (getMainModel() != 0); | 
| 554 bool havePlayTarget = | 589 bool havePlayTarget = | 
| 555 (m_playTarget != 0); | 590 (m_playTarget != 0 || m_audioIO != 0); | 
| 556 bool haveSelection = | 591 bool haveSelection = | 
| 557 (m_viewManager && | 592 (m_viewManager && | 
| 558 !m_viewManager->getSelections().empty()); | 593 !m_viewManager->getSelections().empty()); | 
| 559 bool haveCurrentEditableLayer = | 594 bool haveCurrentEditableLayer = | 
| 560 (haveCurrentLayer && | 595 (haveCurrentLayer && | 
| 595 emit canEditLayer(haveCurrentEditableLayer); | 630 emit canEditLayer(haveCurrentEditableLayer); | 
| 596 emit canEditLayerTabular(haveCurrentEditableLayer || haveTabularLayer); | 631 emit canEditLayerTabular(haveCurrentEditableLayer || haveTabularLayer); | 
| 597 emit canMeasureLayer(haveCurrentLayer); | 632 emit canMeasureLayer(haveCurrentLayer); | 
| 598 emit canSelect(haveMainModel && haveCurrentPane); | 633 emit canSelect(haveMainModel && haveCurrentPane); | 
| 599 emit canPlay(haveMainModel && havePlayTarget); | 634 emit canPlay(haveMainModel && havePlayTarget); | 
| 635 emit canRecord(m_recordTarget != 0); | |
| 600 emit canFfwd(haveMainModel); | 636 emit canFfwd(haveMainModel); | 
| 601 emit canRewind(haveMainModel); | 637 emit canRewind(haveMainModel); | 
| 602 emit canPaste(haveClipboardContents); | 638 emit canPaste(haveClipboardContents); | 
| 603 emit canInsertInstant(haveCurrentPane); | 639 emit canInsertInstant(haveCurrentPane); | 
| 604 emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection); | 640 emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection); | 
| 605 emit canInsertItemAtSelection(haveCurrentPane && haveSelection && haveCurrentDurationLayer); | 641 emit canInsertItemAtSelection(haveCurrentPane && haveSelection && haveCurrentDurationLayer); | 
| 606 emit canRenumberInstants(haveCurrentTimeInstantsLayer && haveSelection); | 642 emit canRenumberInstants(haveCurrentTimeInstantsLayer && haveSelection); | 
| 643 emit canSubdivideInstants(haveCurrentTimeInstantsLayer && haveSelection); | |
| 644 emit canWinnowInstants(haveCurrentTimeInstantsLayer && haveSelection); | |
| 607 emit canPlaySelection(haveMainModel && havePlayTarget && haveSelection); | 645 emit canPlaySelection(haveMainModel && havePlayTarget && haveSelection); | 
| 608 emit canClearSelection(haveSelection); | 646 emit canClearSelection(haveSelection); | 
| 609 emit canEditSelection(haveSelection && haveCurrentEditableLayer); | 647 emit canEditSelection(haveSelection && haveCurrentEditableLayer); | 
| 610 emit canSave(m_sessionFile != "" && m_documentModified); | 648 emit canSave(m_sessionFile != "" && m_documentModified); | 
| 611 emit canSaveAs(haveMainModel); | 649 emit canSaveAs(haveMainModel); | 
| 1194 if (!m_labeller) return; | 1232 if (!m_labeller) return; | 
| 1195 | 1233 | 
| 1196 Labeller labeller(*m_labeller); | 1234 Labeller labeller(*m_labeller); | 
| 1197 labeller.setSampleRate(sodm->getSampleRate()); | 1235 labeller.setSampleRate(sodm->getSampleRate()); | 
| 1198 | 1236 | 
| 1199 // This uses a command | 1237 Command *c = labeller.labelAll<SparseOneDimensionalModel::Point>(*sodm, &ms); | 
| 1200 | 1238 if (c) CommandHistory::getInstance()->addCommand(c, false); | 
| 1201 labeller.labelAll<SparseOneDimensionalModel::Point>(*sodm, &ms); | 1239 } | 
| 1240 | |
| 1241 void | |
| 1242 MainWindowBase::subdivideInstantsBy(int n) | |
| 1243 { | |
| 1244 Pane *pane = m_paneStack->getCurrentPane(); | |
| 1245 if (!pane) return; | |
| 1246 | |
| 1247 Layer *layer = dynamic_cast<TimeInstantLayer *>(pane->getSelectedLayer()); | |
| 1248 if (!layer) return; | |
| 1249 | |
| 1250 MultiSelection ms(m_viewManager->getSelection()); | |
| 1251 | |
| 1252 Model *model = layer->getModel(); | |
| 1253 SparseOneDimensionalModel *sodm = | |
| 1254 dynamic_cast<SparseOneDimensionalModel *>(model); | |
| 1255 if (!sodm) return; | |
| 1256 | |
| 1257 if (!m_labeller) return; | |
| 1258 | |
| 1259 Labeller labeller(*m_labeller); | |
| 1260 labeller.setSampleRate(sodm->getSampleRate()); | |
| 1261 | |
| 1262 Command *c = labeller.subdivide<SparseOneDimensionalModel::Point> | |
| 1263 (*sodm, &ms, n); | |
| 1264 if (c) CommandHistory::getInstance()->addCommand(c, false); | |
| 1265 } | |
| 1266 | |
| 1267 void | |
| 1268 MainWindowBase::winnowInstantsBy(int n) | |
| 1269 { | |
| 1270 Pane *pane = m_paneStack->getCurrentPane(); | |
| 1271 if (!pane) return; | |
| 1272 | |
| 1273 Layer *layer = dynamic_cast<TimeInstantLayer *>(pane->getSelectedLayer()); | |
| 1274 if (!layer) return; | |
| 1275 | |
| 1276 MultiSelection ms(m_viewManager->getSelection()); | |
| 1277 | |
| 1278 Model *model = layer->getModel(); | |
| 1279 SparseOneDimensionalModel *sodm = | |
| 1280 dynamic_cast<SparseOneDimensionalModel *>(model); | |
| 1281 if (!sodm) return; | |
| 1282 | |
| 1283 if (!m_labeller) return; | |
| 1284 | |
| 1285 Labeller labeller(*m_labeller); | |
| 1286 labeller.setSampleRate(sodm->getSampleRate()); | |
| 1287 | |
| 1288 Command *c = labeller.winnow<SparseOneDimensionalModel::Point> | |
| 1289 (*sodm, &ms, n); | |
| 1290 if (c) CommandHistory::getInstance()->addCommand(c, false); | |
| 1202 } | 1291 } | 
| 1203 | 1292 | 
| 1204 MainWindowBase::FileOpenStatus | 1293 MainWindowBase::FileOpenStatus | 
| 1205 MainWindowBase::openPath(QString fileOrUrl, AudioFileOpenMode mode) | 1294 MainWindowBase::openPath(QString fileOrUrl, AudioFileOpenMode mode) | 
| 1206 { | 1295 { | 
| 1311 rate = Preferences::getInstance()->getFixedSampleRate(); | 1400 rate = Preferences::getInstance()->getFixedSampleRate(); | 
| 1312 } else if (Preferences::getInstance()->getResampleOnLoad()) { | 1401 } else if (Preferences::getInstance()->getResampleOnLoad()) { | 
| 1313 rate = m_playSource->getSourceSampleRate(); | 1402 rate = m_playSource->getSourceSampleRate(); | 
| 1314 } | 1403 } | 
| 1315 | 1404 | 
| 1316 WaveFileModel *newModel = new WaveFileModel(source, rate); | 1405 ReadOnlyWaveFileModel *newModel = new ReadOnlyWaveFileModel(source, rate); | 
| 1317 | 1406 | 
| 1318 if (!newModel->isOK()) { | 1407 if (!newModel->isOK()) { | 
| 1319 delete newModel; | 1408 delete newModel; | 
| 1320 m_openingAudioFile = false; | 1409 m_openingAudioFile = false; | 
| 1321 if (source.wasCancelled()) { | 1410 if (source.wasCancelled()) { | 
| 1765 | 1854 | 
| 1766 return FileOpenSucceeded; | 1855 return FileOpenSucceeded; | 
| 1767 } | 1856 } | 
| 1768 | 1857 | 
| 1769 MainWindowBase::FileOpenStatus | 1858 MainWindowBase::FileOpenStatus | 
| 1859 MainWindowBase::openDirOfAudio(QString dirPath) | |
| 1860 { | |
| 1861 QDir dir(dirPath); | |
| 1862 QStringList files = dir.entryList(QDir::Files | QDir::Readable); | |
| 1863 files.sort(); | |
| 1864 | |
| 1865 FileOpenStatus status = FileOpenFailed; | |
| 1866 bool first = true; | |
| 1867 bool cancelled = false; | |
| 1868 | |
| 1869 foreach (QString file, files) { | |
| 1870 | |
| 1871 FileSource source(dir.filePath(file)); | |
| 1872 if (!source.isAvailable()) { | |
| 1873 continue; | |
| 1874 } | |
| 1875 | |
| 1876 if (AudioFileReaderFactory::getKnownExtensions().contains | |
| 1877 (source.getExtension().toLower())) { | |
| 1878 | |
| 1879 AudioFileOpenMode mode = CreateAdditionalModel; | |
| 1880 if (first) mode = ReplaceSession; | |
| 1881 | |
| 1882 switch (openAudio(source, mode)) { | |
| 1883 case FileOpenSucceeded: | |
| 1884 status = FileOpenSucceeded; | |
| 1885 first = false; | |
| 1886 break; | |
| 1887 case FileOpenFailed: | |
| 1888 break; | |
| 1889 case FileOpenCancelled: | |
| 1890 cancelled = true; | |
| 1891 break; | |
| 1892 case FileOpenWrongMode: | |
| 1893 break; | |
| 1894 } | |
| 1895 } | |
| 1896 | |
| 1897 if (cancelled) break; | |
| 1898 } | |
| 1899 | |
| 1900 return status; | |
| 1901 } | |
| 1902 | |
| 1903 MainWindowBase::FileOpenStatus | |
| 1770 MainWindowBase::openSessionPath(QString fileOrUrl) | 1904 MainWindowBase::openSessionPath(QString fileOrUrl) | 
| 1771 { | 1905 { | 
| 1772 ProgressDialog dialog(tr("Opening session..."), true, 2000, this); | 1906 ProgressDialog dialog(tr("Opening session..."), true, 2000, this); | 
| 1773 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash())); | 1907 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash())); | 
| 1774 return openSession(FileSource(fileOrUrl, &dialog)); | 1908 return openSession(FileSource(fileOrUrl, &dialog)); | 
| 2158 m_recentFiles.addFile(source.getLocation()); | 2292 m_recentFiles.addFile(source.getLocation()); | 
| 2159 return FileOpenSucceeded; | 2293 return FileOpenSucceeded; | 
| 2160 } | 2294 } | 
| 2161 | 2295 | 
| 2162 void | 2296 void | 
| 2163 MainWindowBase::createPlayTarget() | 2297 MainWindowBase::createAudioIO() | 
| 2164 { | 2298 { | 
| 2165 if (m_playTarget) return; | 2299 if (m_playTarget || m_audioIO) return; | 
| 2300 | |
| 2301 if (!(m_soundOptions & WithAudioOutput)) return; | |
| 2166 | 2302 | 
| 2167 QSettings settings; | 2303 QSettings settings; | 
| 2168 settings.beginGroup("Preferences"); | 2304 settings.beginGroup("Preferences"); | 
| 2169 QString implementation = settings.value | 2305 QString implementation = settings.value | 
| 2170 ("audio-target", "").toString(); | 2306 ("audio-target", "").toString(); | 
| 2268 this, SLOT(modelRegenerationWarning(QString, QString, QString))); | 2404 this, SLOT(modelRegenerationWarning(QString, QString, QString))); | 
| 2269 connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)), | 2405 connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)), | 
| 2270 this, SLOT(modelGenerationFailed(QString, QString))); | 2406 this, SLOT(modelGenerationFailed(QString, QString))); | 
| 2271 connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)), | 2407 connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)), | 
| 2272 this, SLOT(modelRegenerationWarning(QString, QString, QString))); | 2408 this, SLOT(modelRegenerationWarning(QString, QString, QString))); | 
| 2273 connect(m_document, SIGNAL(alignmentFailed(QString, QString)), | 2409 connect(m_document, SIGNAL(alignmentComplete(AlignmentModel *)), | 
| 2274 this, SLOT(alignmentFailed(QString, QString))); | 2410 this, SLOT(alignmentComplete(AlignmentModel *))); | 
| 2411 connect(m_document, SIGNAL(alignmentFailed(QString)), | |
| 2412 this, SLOT(alignmentFailed(QString))); | |
| 2275 | 2413 | 
| 2276 emit replacedDocument(); | 2414 emit replacedDocument(); | 
| 2277 } | 2415 } | 
| 2278 | 2416 | 
| 2279 bool | 2417 bool | 
| 2653 } | 2791 } | 
| 2654 | 2792 | 
| 2655 void | 2793 void | 
| 2656 MainWindowBase::play() | 2794 MainWindowBase::play() | 
| 2657 { | 2795 { | 
| 2658 if (m_playSource->isPlaying()) { | 2796 if ((m_recordTarget && m_recordTarget->isRecording()) || | 
| 2797 (m_playSource && m_playSource->isPlaying())) { | |
| 2659 stop(); | 2798 stop(); | 
| 2799 QAction *action = qobject_cast<QAction *>(sender()); | |
| 2800 if (action) action->setChecked(false); | |
| 2660 } else { | 2801 } else { | 
| 2802 if (m_audioIO) m_audioIO->resume(); | |
| 2803 else if (m_playTarget) m_playTarget->resume(); | |
| 2661 playbackFrameChanged(m_viewManager->getPlaybackFrame()); | 2804 playbackFrameChanged(m_viewManager->getPlaybackFrame()); | 
| 2662 m_playSource->play(m_viewManager->getPlaybackFrame()); | 2805 m_playSource->play(m_viewManager->getPlaybackFrame()); | 
| 2663 } | 2806 } | 
| 2807 } | |
| 2808 | |
| 2809 void | |
| 2810 MainWindowBase::record() | |
| 2811 { | |
| 2812 if (!(m_soundOptions & WithAudioInput)) { | |
| 2813 return; | |
| 2814 } | |
| 2815 | |
| 2816 if (!m_recordTarget) { | |
| 2817 //!!! report | |
| 2818 return; | |
| 2819 } | |
| 2820 | |
| 2821 if (!m_audioIO) { | |
| 2822 createAudioIO(); | |
| 2823 } | |
| 2824 | |
| 2825 if (!m_audioIO) { | |
| 2826 //!!! report | |
| 2827 return; | |
| 2828 } | |
| 2829 | |
| 2830 if (m_recordTarget->isRecording()) { | |
| 2831 stop(); | |
| 2832 return; | |
| 2833 } | |
| 2834 | |
| 2835 QAction *action = qobject_cast<QAction *>(sender()); | |
| 2836 | |
| 2837 if (m_audioRecordMode == RecordReplaceSession) { | |
| 2838 if (!checkSaveModified()) { | |
| 2839 if (action) action->setChecked(false); | |
| 2840 return; | |
| 2841 } | |
| 2842 } | |
| 2843 | |
| 2844 m_audioIO->resume(); | |
| 2845 | |
| 2846 WritableWaveFileModel *model = m_recordTarget->startRecording(); | |
| 2847 if (!model) { | |
| 2848 cerr << "ERROR: MainWindowBase::record: Recording failed" << endl; | |
| 2849 //!!! report | |
| 2850 if (action) action->setChecked(false); | |
| 2851 return; | |
| 2852 } | |
| 2853 | |
| 2854 if (!model->isOK()) { | |
| 2855 m_recordTarget->stopRecording(); | |
| 2856 m_audioIO->suspend(); | |
| 2857 delete model; | |
| 2858 return; | |
| 2859 } | |
| 2860 | |
| 2861 PlayParameterRepository::getInstance()->addPlayable(model); | |
| 2862 | |
| 2863 if (m_audioRecordMode == RecordReplaceSession || !getMainModel()) { | |
| 2864 | |
| 2865 //!!! duplication with openAudio here | |
| 2866 | |
| 2867 QString templateName = getDefaultSessionTemplate(); | |
| 2868 bool loadedTemplate = false; | |
| 2869 | |
| 2870 if (templateName != "") { | |
| 2871 FileOpenStatus tplStatus = openSessionTemplate(templateName); | |
| 2872 if (tplStatus == FileOpenCancelled) { | |
| 2873 m_recordTarget->stopRecording(); | |
| 2874 m_audioIO->suspend(); | |
| 2875 PlayParameterRepository::getInstance()->removePlayable(model); | |
| 2876 return; | |
| 2877 } | |
| 2878 if (tplStatus != FileOpenFailed) { | |
| 2879 loadedTemplate = true; | |
| 2880 } | |
| 2881 } | |
| 2882 | |
| 2883 if (!loadedTemplate) { | |
| 2884 closeSession(); | |
| 2885 createDocument(); | |
| 2886 } | |
| 2887 | |
| 2888 Model *prevMain = getMainModel(); | |
| 2889 if (prevMain) { | |
| 2890 m_playSource->removeModel(prevMain); | |
| 2891 PlayParameterRepository::getInstance()->removePlayable(prevMain); | |
| 2892 } | |
| 2893 | |
| 2894 m_document->setMainModel(model); | |
| 2895 setupMenus(); | |
| 2896 | |
| 2897 if (loadedTemplate || (m_sessionFile == "")) { | |
| 2898 //!!! shouldn't be dealing directly with title from here -- call a method | |
| 2899 setWindowTitle(tr("%1: %2") | |
| 2900 .arg(QApplication::applicationName()) | |
| 2901 .arg(model->getLocation())); | |
| 2902 CommandHistory::getInstance()->clear(); | |
| 2903 CommandHistory::getInstance()->documentSaved(); | |
| 2904 m_documentModified = false; | |
| 2905 } else { | |
| 2906 setWindowTitle(tr("%1: %2 [%3]") | |
| 2907 .arg(QApplication::applicationName()) | |
| 2908 .arg(QFileInfo(m_sessionFile).fileName()) | |
| 2909 .arg(model->getLocation())); | |
| 2910 if (m_documentModified) { | |
| 2911 m_documentModified = false; | |
| 2912 documentModified(); // so as to restore "(modified)" window title | |
| 2913 } | |
| 2914 } | |
| 2915 | |
| 2916 } else { | |
| 2917 | |
| 2918 CommandHistory::getInstance()->startCompoundOperation | |
| 2919 (tr("Import Recorded Audio"), true); | |
| 2920 | |
| 2921 m_document->addImportedModel(model); | |
| 2922 | |
| 2923 AddPaneCommand *command = new AddPaneCommand(this); | |
| 2924 CommandHistory::getInstance()->addCommand(command); | |
| 2925 | |
| 2926 Pane *pane = command->getPane(); | |
| 2927 | |
| 2928 if (m_timeRulerLayer) { | |
| 2929 m_document->addLayerToView(pane, m_timeRulerLayer); | |
| 2930 } | |
| 2931 | |
| 2932 Layer *newLayer = m_document->createImportedLayer(model); | |
| 2933 | |
| 2934 if (newLayer) { | |
| 2935 m_document->addLayerToView(pane, newLayer); | |
| 2936 } | |
| 2937 | |
| 2938 CommandHistory::getInstance()->endCompoundOperation(); | |
| 2939 } | |
| 2940 | |
| 2941 updateMenuStates(); | |
| 2942 m_recentFiles.addFile(model->getLocation()); | |
| 2943 currentPaneChanged(m_paneStack->getCurrentPane()); | |
| 2944 | |
| 2945 emit audioFileLoaded(); | |
| 2664 } | 2946 } | 
| 2665 | 2947 | 
| 2666 void | 2948 void | 
| 2667 MainWindowBase::ffwd() | 2949 MainWindowBase::ffwd() | 
| 2668 { | 2950 { | 
| 2889 } | 3171 } | 
| 2890 | 3172 | 
| 2891 void | 3173 void | 
| 2892 MainWindowBase::stop() | 3174 MainWindowBase::stop() | 
| 2893 { | 3175 { | 
| 3176 if (m_recordTarget && | |
| 3177 m_recordTarget->isRecording()) { | |
| 3178 m_recordTarget->stopRecording(); | |
| 3179 } | |
| 3180 | |
| 3181 if (!m_playSource) return; | |
| 3182 | |
| 2894 m_playSource->stop(); | 3183 m_playSource->stop(); | 
| 2895 | 3184 | 
| 3185 if (m_audioIO) m_audioIO->suspend(); | |
| 3186 else if (m_playTarget) m_playTarget->suspend(); | |
| 3187 | |
| 2896 if (m_paneStack && m_paneStack->getCurrentPane()) { | 3188 if (m_paneStack && m_paneStack->getCurrentPane()) { | 
| 2897 updateVisibleRangeDisplay(m_paneStack->getCurrentPane()); | 3189 updateVisibleRangeDisplay(m_paneStack->getCurrentPane()); | 
| 2898 } else { | 3190 } else { | 
| 2899 m_myStatusMessage = ""; | 3191 m_myStatusMessage = ""; | 
| 2900 getStatusLabel()->setText(""); | 3192 getStatusLabel()->setText(""); | 
| 3224 remainingStr = (then - now).toText(true).c_str(); | 3516 remainingStr = (then - now).toText(true).c_str(); | 
| 3225 } | 3517 } | 
| 3226 | 3518 | 
| 3227 m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)") | 3519 m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)") | 
| 3228 .arg(nowStr).arg(thenStr).arg(remainingStr); | 3520 .arg(nowStr).arg(thenStr).arg(remainingStr); | 
| 3521 | |
| 3522 getStatusLabel()->setText(m_myStatusMessage); | |
| 3523 } | |
| 3524 | |
| 3525 void | |
| 3526 MainWindowBase::recordDurationChanged(sv_frame_t frame, sv_samplerate_t rate) | |
| 3527 { | |
| 3528 RealTime duration = RealTime::frame2RealTime(frame, rate); | |
| 3529 QString durStr = duration.toSecText().c_str(); | |
| 3530 | |
| 3531 m_myStatusMessage = tr("Recording: %1").arg(durStr); | |
| 3229 | 3532 | 
| 3230 getStatusLabel()->setText(m_myStatusMessage); | 3533 getStatusLabel()->setText(m_myStatusMessage); | 
| 3231 } | 3534 } | 
| 3232 | 3535 | 
| 3233 void | 3536 void | 
| 3359 MainWindowBase::mainModelChanged(WaveFileModel *model) | 3662 MainWindowBase::mainModelChanged(WaveFileModel *model) | 
| 3360 { | 3663 { | 
| 3361 // SVDEBUG << "MainWindowBase::mainModelChanged(" << model << ")" << endl; | 3664 // SVDEBUG << "MainWindowBase::mainModelChanged(" << model << ")" << endl; | 
| 3362 updateDescriptionLabel(); | 3665 updateDescriptionLabel(); | 
| 3363 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate()); | 3666 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate()); | 
| 3364 if (model && !m_playTarget && m_audioOutput) { | 3667 if (model && !(m_playTarget || m_audioIO) && | 
| 3365 createPlayTarget(); | 3668 (m_soundOptions & WithAudioOutput)) { | 
| 3669 createAudioIO(); | |
| 3366 } | 3670 } | 
| 3367 } | 3671 } | 
| 3368 | 3672 | 
| 3369 void | 3673 void | 
| 3370 MainWindowBase::modelAboutToBeDeleted(Model *model) | 3674 MainWindowBase::modelAboutToBeDeleted(Model *model) | 
| 3372 // SVDEBUG << "MainWindowBase::modelAboutToBeDeleted(" << model << ")" << endl; | 3676 // SVDEBUG << "MainWindowBase::modelAboutToBeDeleted(" << model << ")" << endl; | 
| 3373 if (model == m_viewManager->getPlaybackModel()) { | 3677 if (model == m_viewManager->getPlaybackModel()) { | 
| 3374 m_viewManager->setPlaybackModel(0); | 3678 m_viewManager->setPlaybackModel(0); | 
| 3375 } | 3679 } | 
| 3376 m_playSource->removeModel(model); | 3680 m_playSource->removeModel(model); | 
| 3377 FFTDataServer::modelAboutToBeDeleted(model); | |
| 3378 } | 3681 } | 
| 3379 | 3682 | 
| 3380 void | 3683 void | 
| 3381 MainWindowBase::paneDeleteButtonClicked(Pane *pane) | 3684 MainWindowBase::paneDeleteButtonClicked(Pane *pane) | 
| 3382 { | 3685 { | 
| 3409 CommandHistory::getInstance()->addCommand(command); | 3712 CommandHistory::getInstance()->addCommand(command); | 
| 3410 | 3713 | 
| 3411 CommandHistory::getInstance()->endCompoundOperation(); | 3714 CommandHistory::getInstance()->endCompoundOperation(); | 
| 3412 | 3715 | 
| 3413 updateMenuStates(); | 3716 updateMenuStates(); | 
| 3717 } | |
| 3718 | |
| 3719 void | |
| 3720 MainWindowBase::alignmentComplete(AlignmentModel *model) | |
| 3721 { | |
| 3722 cerr << "MainWindowBase::alignmentComplete(" << model << ")" << endl; | |
| 3414 } | 3723 } | 
| 3415 | 3724 | 
| 3416 void | 3725 void | 
| 3417 MainWindowBase::pollOSC() | 3726 MainWindowBase::pollOSC() | 
| 3418 { | 3727 { | 
| 3490 } | 3799 } | 
| 3491 #endif | 3800 #endif | 
| 3492 #endif | 3801 #endif | 
| 3493 } | 3802 } | 
| 3494 | 3803 | 
| 3495 | 3804 void | 
| 3805 MainWindowBase::openLocalFolder(QString path) | |
| 3806 { | |
| 3807 QDir d(path); | |
| 3808 if (d.exists()) { | |
| 3809 QStringList args; | |
| 3810 QString path = d.canonicalPath(); | |
| 3811 #if defined Q_OS_WIN32 | |
| 3812 // Although the Win32 API is quite happy to have | |
| 3813 // forward slashes as directory separators, Windows | |
| 3814 // Explorer is not | |
| 3815 path = path.replace('/', '\\'); | |
| 3816 args << path; | |
| 3817 QProcess::execute("c:/windows/explorer.exe", args); | |
| 3818 #else | |
| 3819 args << path; | |
| 3820 QProcess::execute( | |
| 3821 #if defined Q_OS_MAC | |
| 3822 "/usr/bin/open", | |
| 3823 #else | |
| 3824 "/usr/bin/xdg-open", | |
| 3825 #endif | |
| 3826 args); | |
| 3827 #endif | |
| 3828 } | |
| 3829 } | |
| 3830 | 
