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 |