19 #include "view/Pane.h" 20 #include "view/PaneStack.h" 21 #include "data/model/ReadOnlyWaveFileModel.h" 22 #include "data/model/WritableWaveFileModel.h" 23 #include "data/model/SparseOneDimensionalModel.h" 24 #include "data/model/NoteModel.h" 25 #include "data/model/Labeller.h" 26 #include "data/model/TabularModel.h" 27 #include "view/ViewManager.h" 29 #include "layer/WaveformLayer.h" 30 #include "layer/TimeRulerLayer.h" 31 #include "layer/TimeInstantLayer.h" 32 #include "layer/TimeValueLayer.h" 33 #include "layer/Colour3DPlotLayer.h" 34 #include "layer/SliceLayer.h" 35 #include "layer/SliceableLayer.h" 36 #include "layer/ImageLayer.h" 37 #include "layer/NoteLayer.h" 38 #include "layer/FlexiNoteLayer.h" 39 #include "layer/RegionLayer.h" 40 #include "layer/SpectrogramLayer.h" 42 #include "widgets/ListInputDialog.h" 43 #include "widgets/CommandHistory.h" 44 #include "widgets/ProgressDialog.h" 45 #include "widgets/MIDIFileImportDialog.h" 46 #include "widgets/CSVFormatDialog.h" 47 #include "widgets/ModelDataTableDialog.h" 48 #include "widgets/InteractiveFileFinder.h" 50 #include "audio/AudioCallbackPlaySource.h" 51 #include "audio/AudioCallbackRecordTarget.h" 52 #include "audio/PlaySpeedRangeMapper.h" 54 #include "data/fileio/DataFileReaderFactory.h" 55 #include "data/fileio/PlaylistFileReader.h" 56 #include "data/fileio/WavFileWriter.h" 57 #include "data/fileio/MIDIFileWriter.h" 58 #include "data/fileio/CSVFileWriter.h" 59 #include "data/fileio/BZipFileDevice.h" 60 #include "data/fileio/FileSource.h" 61 #include "data/fileio/AudioFileReaderFactory.h" 62 #include "data/fileio/TextTest.h" 63 #include "rdf/RDFImporter.h" 64 #include "rdf/RDFExporter.h" 66 #include "transform/ModelTransformerFactory.h" 68 #include "base/RecentFiles.h" 70 #include "base/XmlExportable.h" 71 #include "base/Profiler.h" 72 #include "base/Preferences.h" 73 #include "base/TempWriteFile.h" 74 #include "base/Exceptions.h" 75 #include "base/ResourceFinder.h" 77 #include "data/osc/OSCQueue.h" 78 #include "data/midi/MIDIInput.h" 81 #include "system/System.h" 83 #include <bqaudioio/SystemPlaybackTarget.h> 84 #include <bqaudioio/SystemAudioIO.h> 85 #include <bqaudioio/AudioFactory.h> 87 #include <QApplication> 88 #include <QMessageBox> 89 #include <QGridLayout> 94 #include <QInputDialog> 100 #include <QTextStream> 101 #include <QTextCodec> 109 #include <QScrollArea> 111 #include <QSignalMapper> 122 #define Window X11Window 123 #include <X11/Xlib.h> 124 #include <X11/Xutil.h> 125 #include <X11/Xatom.h> 126 #include <X11/SM/SMlib.h> 128 static int handle_x11_error(Display *dpy, XErrorEvent *err)
131 XGetErrorText(dpy, err->error_code, errstr, 256);
132 if (err->error_code != BadWindow) {
133 cerr <<
"Sonic Visualiser: X Error: " 134 << errstr <<
" " << int(err->error_code)
135 <<
"\nin major opcode: " 136 << int(err->request_code) << endl;
145 PaneStack::Options paneStackOptions) :
147 m_paneStack(nullptr),
148 m_viewManager(nullptr),
149 m_timeRulerLayer(nullptr),
150 m_audioMode(audioMode),
151 m_midiMode(midiMode),
152 m_playSource(nullptr),
153 m_recordTarget(nullptr),
154 m_playTarget(nullptr),
157 m_oscQueueStarter(nullptr),
158 m_oscScript(nullptr),
159 m_midiInput(nullptr),
160 m_recentFiles(
"RecentFiles", 20),
161 m_recentTransforms(
"RecentTransforms", 20),
162 m_documentModified(false),
163 m_openingAudioFile(false),
164 m_handlingOSC(false),
166 m_lastPlayStatusSec(0),
167 m_initialDarkBackground(false),
168 m_defaultFfwdRwdStep(2, 0),
169 m_audioRecordMode(RecordCreateAdditionalModel),
170 m_statusLabel(nullptr),
171 m_iconsVisibleInMenus(true),
172 m_menuShortcutMapper(nullptr)
174 Profiler profiler(
"MainWindowBase::MainWindowBase");
176 SVDEBUG <<
"MainWindowBase::MainWindowBase" << endl;
178 qRegisterMetaType<sv_frame_t>(
"sv_frame_t");
179 qRegisterMetaType<sv_samplerate_t>(
"sv_samplerate_t");
180 qRegisterMetaType<ModelId>(
"ModelId");
183 XSetErrorHandler(handle_x11_error);
188 connect(CommandHistory::getInstance(), SIGNAL(commandExecuted()),
193 SVDEBUG <<
"MainWindowBase: Creating view manager" << endl;
201 SVDEBUG <<
"MainWindowBase: Calculating view font size" << endl;
205 int viewFontSize = int(QApplication::font().pointSize() * 0.9);
207 settings.beginGroup(
"Preferences");
208 viewFontSize = settings.value(
"view-font-size", viewFontSize).toInt();
209 settings.setValue(
"view-font-size", viewFontSize);
212 SVDEBUG <<
"MainWindowBase: View font size is " << viewFontSize << endl;
216 Preferences::BackgroundMode mode =
217 Preferences::getInstance()->getBackgroundMode();
221 if (OSReportsDarkThemeActive()) {
228 if (mode == Preferences::BackgroundFromTheme) {
233 (mode == Preferences::DarkBackground);
257 connect(
m_paneStack, SIGNAL(dropAccepted(Pane *, QStringList)),
259 connect(
m_paneStack, SIGNAL(dropAccepted(Pane *, QString)),
264 SVDEBUG <<
"MainWindowBase: Creating play source" << endl;
271 SVDEBUG <<
"MainWindowBase: Creating record target" << endl;
282 connect(
m_playSource, SIGNAL(channelCountIncreased(
int)),
302 connect(Preferences::getInstance(),
303 SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
307 SVDEBUG <<
"MainWindowBase: Creating labeller" << endl;
309 Labeller::ValueType labellerType = Labeller::ValueFromTwoLevelCounter;
310 settings.beginGroup(
"MainWindow");
312 labellerType = (Labeller::ValueType)
313 settings.value(
"labellertype", (
int)labellerType).toInt();
314 int cycle = settings.value(
"labellercycle", 4).toInt();
322 SVDEBUG <<
"MainWindowBase: Creating MIDI input" << endl;
323 m_midiInput =
new MIDIInput(QApplication::applicationName(),
this);
326 QTimer::singleShot(1500,
this, SIGNAL(
hideSplash()));
328 SVDEBUG <<
"MainWindowBase: Constructor done" << endl;
333 SVDEBUG <<
"MainWindowBase::~MainWindowBase" << endl;
351 disconnect(
m_oscScript,
nullptr,
nullptr,
nullptr);
372 Profiles::getInstance()->dump();
378 SVDEBUG <<
"MainWindowBase: Hiding splash screen (if not hidden already)" << endl;
385 SVDEBUG <<
"MainWindowBase::finaliseMenus called" << endl;
395 QMenuBar *mb = menuBar();
406 QList<QMenu *> menus = mb->findChildren<QMenu *>
407 (QString(), Qt::FindDirectChildrenOnly);
409 foreach (QMenu *menu, menus) {
413 SVDEBUG <<
"MainWindowBase::finaliseMenus done" << endl;
419 foreach (QAction *a, menu->actions()) {
460 #if (QT_VERSION < QT_VERSION_CHECK(5, 5, 0)) 468 foreach (QAction *a, menu->actions()) {
470 if (a->isSeparator()) {
472 }
else if (a->menu()) {
476 QWidgetList ww = a->associatedWidgets();
477 bool hasButton =
false;
478 foreach (QWidget *w, ww) {
479 if (qobject_cast<QAbstractButton *>(w)) {
484 if (hasButton)
continue;
485 QKeySequence sc = a->shortcut();
491 #if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)) 494 #elif (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)) 495 if (sc.count() == 1 &&
496 (sc[0] & Qt::KeyboardModifierMask) == Qt::ShiftModifier) {
498 if (sc.count() == 1 &&
499 ((sc[0] & Qt::KeyboardModifierMask) == Qt::NoModifier ||
500 (sc[0] & Qt::KeyboardModifierMask) == Qt::ShiftModifier)) {
502 QShortcut *newSc =
new QShortcut(sc, a->parentWidget());
503 QObject::connect(newSc, SIGNAL(activated()),
517 QAction *a = qobject_cast<QAction *>(o);
518 if (a && a->isEnabled()) {
526 QScreen *screen = QApplication::primaryScreen();
527 QRect available = screen->availableGeometry();
528 QSize actual(std::min(size.width(), available.width()),
529 std::min(size.height(), available.height()));
546 QTimer *oscTimer =
new QTimer(
this);
547 connect(oscTimer, SIGNAL(timeout()),
this, SLOT(
pollOSC()));
548 oscTimer->start(2000);
551 SVDEBUG <<
"Finished setting up OSC interface" << endl;
553 SVDEBUG <<
"Finished setting up internal-only OSC queue" << endl;
591 FileFinder *ff = FileFinder::getInstance();
593 if (type == FileFinder::AnyFile) {
597 return ff->getOpenFileName(FileFinder::AnyFile,
m_sessionFile);
599 return ff->getOpenFileName(FileFinder::SessionOrAudioFile,
606 if (type == FileFinder::AudioFile) {
610 return ff->getOpenFileName(type, lastPath);
618 if (type == FileFinder::AudioFile) {
622 FileFinder *ff = FileFinder::getInstance();
623 return ff->getSaveFileName(type, lastPath);
629 FileFinder *ff = FileFinder::getInstance();
630 ff->registerLastOpenedFilePath(type, path);
637 settings.beginGroup(
"MainWindow");
638 QString templateName = settings.value(
"sessiontemplate",
"").toString();
639 if (templateName ==
"") templateName =
"default";
647 settings.beginGroup(
"MainWindow");
648 settings.setValue(
"sessiontemplate", n);
654 Pane *currentPane =
nullptr;
655 Layer *currentLayer =
nullptr;
658 if (currentPane) currentLayer = currentPane->getSelectedLayer();
660 bool havePrevPane =
false, haveNextPane =
false;
661 bool havePrevLayer =
false, haveNextLayer =
false;
664 for (
int i = 0; i <
m_paneStack->getPaneCount(); ++i) {
666 if (i > 0) havePrevPane =
true;
667 if (i < m_paneStack->getPaneCount()-1) haveNextPane =
true;
675 if (currentPane->getLayerCount() > 0) {
676 havePrevLayer =
true;
677 haveNextLayer =
true;
681 bool haveCurrentPane =
682 (currentPane !=
nullptr);
683 bool haveCurrentLayer =
685 (currentLayer !=
nullptr));
688 bool havePlayTarget =
693 bool haveCurrentEditableLayer =
695 currentLayer->isLayerEditable());
696 bool haveCurrentTimeInstantsLayer =
698 dynamic_cast<TimeInstantLayer *
>(currentLayer));
699 bool haveCurrentDurationLayer =
701 (
dynamic_cast<NoteLayer *
>(currentLayer) ||
702 dynamic_cast<FlexiNoteLayer *>(currentLayer) ||
703 dynamic_cast<RegionLayer *
>(currentLayer)));
704 bool haveCurrentColour3DPlot =
706 dynamic_cast<Colour3DPlotLayer *
>(currentLayer));
707 bool haveCurrentSpectrogram =
709 dynamic_cast<SpectrogramLayer *
>(currentLayer));
710 bool haveClipboardContents =
713 bool haveTabularLayer =
715 ModelById::isa<TabularModel>(currentLayer->getModel()));
719 emit
canZoom(haveMainModel && haveCurrentPane);
720 emit
canScroll(haveMainModel && haveCurrentPane);
721 emit
canAddLayer(haveMainModel && haveCurrentPane);
728 (haveCurrentEditableLayer ||
729 haveCurrentColour3DPlot ||
730 haveCurrentSpectrogram));
737 emit
canSelect(haveMainModel && haveCurrentPane);
738 emit
canPlay(haveMainModel && havePlayTarget);
741 emit
canPaste(haveClipboardContents);
774 bool recordDeviceFailed =
777 emit
canRecord(!recordDisabled && !recordDeviceFailed);
788 title = tr(
"%1: %2 [%3]")
789 .arg(QApplication::applicationName())
794 .arg(QApplication::applicationName())
800 .arg(QApplication::applicationName())
803 title = QApplication::applicationName();
808 title = tr(
"%1 (modified)").arg(title);
811 setWindowTitle(title);
837 QAction *action =
dynamic_cast<QAction *
>(sender());
849 QAction *action =
dynamic_cast<QAction *
>(sender());
861 QAction *action =
dynamic_cast<QAction *
>(sender());
896 ModelId prevPlaybackModel =
m_viewManager->getPlaybackModel();
906 sv_frame_t frame =
m_playSource->getCurrentBufferedFrame();
908 cerr <<
"currentPaneChanged: current frame (in ref model) = " << frame << endl;
910 View::ModelSet soloModels = p->getModels();
912 View::ModelSet sources;
913 for (ModelId modelId: sources) {
918 if (
auto model = ModelById::get(modelId)) {
919 if (!ModelById::isa<RangeSummarisableTimeValueModel>(modelId) &&
920 !model->getSourceModel().isNone()) {
921 sources.insert(model->getSourceModel());
925 for (ModelId modelId: sources) {
926 soloModels.insert(modelId);
934 ModelId newPlaybackModel;
936 for (ModelId modelId: soloModels) {
937 if (ModelById::isa<RangeSummarisableTimeValueModel>(modelId)) {
939 newPlaybackModel = modelId;
945 if (!prevPlaybackModel.isNone() && !newPlaybackModel.isNone() &&
946 prevPlaybackModel != newPlaybackModel) {
963 sv_frame_t startFrame = 0;
965 for (
int i = 0; i <
m_paneStack->getPaneCount(); ++i) {
966 sv_frame_t thisStart =
m_paneStack->getPane(i)->getModelsStartFrame();
967 if (i == 0 || thisStart < startFrame) {
968 startFrame = thisStart;
977 sv_frame_t endFrame = 0;
979 for (
int i = 0; i <
m_paneStack->getPaneCount(); ++i) {
980 sv_frame_t thisEnd =
m_paneStack->getPane(i)->getModelsEndFrame();
981 if (i == 0 || thisEnd > endFrame) {
1015 Pane *currentPane =
m_paneStack->getCurrentPane();
1016 if (!currentPane)
return;
1018 sv_frame_t startFrame, endFrame;
1020 if (currentPane->getStartFrame() < 0) {
1023 startFrame = currentPane->getStartFrame();
1026 if (currentPane->getEndFrame() > model->getEndFrame()) {
1027 endFrame = model->getEndFrame();
1029 endFrame = currentPane->getEndFrame();
1032 m_viewManager->setSelection(Selection(startFrame, endFrame));
1044 Pane *currentPane =
m_paneStack->getCurrentPane();
1045 if (!currentPane)
return;
1047 Layer *layer = currentPane->getSelectedLayer();
1053 MultiSelection::SelectionList selections =
m_viewManager->getSelections();
1055 CommandHistory::getInstance()->startCompoundOperation(tr(
"Cut"),
true);
1057 for (MultiSelection::SelectionList::iterator i = selections.begin();
1058 i != selections.end(); ++i) {
1059 layer->copy(currentPane, *i, clipboard);
1060 layer->deleteSelection(*i);
1063 CommandHistory::getInstance()->endCompoundOperation();
1069 Pane *currentPane =
m_paneStack->getCurrentPane();
1070 if (!currentPane)
return;
1072 Layer *layer = currentPane->getSelectedLayer();
1078 MultiSelection::SelectionList selections =
m_viewManager->getSelections();
1080 for (MultiSelection::SelectionList::iterator i = selections.begin();
1081 i != selections.end(); ++i) {
1082 layer->copy(currentPane, *i, clipboard);
1097 if (!clipboard.empty()) {
1098 sv_frame_t firstEventFrame = clipboard.getPoints()[0].getFrame();
1099 sv_frame_t offset = 0;
1100 if (firstEventFrame < 0) {
1101 offset = pos - firstEventFrame;
1102 }
else if (firstEventFrame < pos) {
1103 offset = pos - firstEventFrame;
1105 offset = -(firstEventFrame - pos);
1114 Pane *currentPane =
m_paneStack->getCurrentPane();
1115 if (!currentPane)
return;
1117 Layer *layer = currentPane->getSelectedLayer();
1121 bool inCompound =
false;
1123 if (!layer || !layer->isLayerEditable()) {
1125 CommandHistory::getInstance()->startCompoundOperation
1126 (tr(
"Paste"),
true);
1130 LayerFactory::LayerType type =
1131 LayerFactory::getInstance()->getLayerTypeForClipboardContents(clipboard);
1135 CommandHistory::getInstance()->endCompoundOperation();
1145 layer->paste(currentPane, clipboard, offset,
true);
1147 if (inCompound) CommandHistory::getInstance()->endCompoundOperation();
1154 m_paneStack->getCurrentPane()->getSelectedLayer()) {
1156 Layer *layer =
m_paneStack->getCurrentPane()->getSelectedLayer();
1160 if (
m_viewManager->getToolMode() == ViewManager::MeasureMode) {
1162 layer->deleteCurrentMeasureRect();
1166 MultiSelection::SelectionList selections =
1169 for (MultiSelection::SelectionList::iterator i = selections.begin();
1170 i != selections.end(); ++i) {
1171 layer->deleteSelection(*i);
1199 MultiSelection::SelectionList selections =
m_viewManager->getSelections();
1200 for (MultiSelection::SelectionList::iterator i = selections.begin();
1201 i != selections.end(); ++i) {
1202 sv_frame_t start = i->getStartFrame();
1203 sv_frame_t end = i->getEndFrame();
1219 frame = pane->alignFromReference(frame);
1221 Layer *layer =
dynamic_cast<TimeInstantLayer *
> 1222 (pane->getSelectedLayer());
1225 for (
int i = pane->getLayerCount(); i > 0; --i) {
1226 layer =
dynamic_cast<TimeInstantLayer *
>(pane->getLayer(i - 1));
1231 CommandHistory::getInstance()->startCompoundOperation
1232 (tr(
"Add Point"),
true);
1238 CommandHistory::getInstance()->endCompoundOperation();
1244 ModelId model = layer->getModel();
1245 auto sodm = ModelById::getAs<SparseOneDimensionalModel>(model);
1248 Event point(frame,
"");
1250 bool havePrevPoint =
false;
1252 ChangeEventsCommand *command =
1253 new ChangeEventsCommand(model.untyped, tr(
"Add Point"));
1259 if (sodm->getNearestEventMatching
1261 [](Event) { return true; },
1262 EventSeries::Backward,
1264 havePrevPoint =
true;
1268 m_labeller->setSampleRate(sodm->getSampleRate());
1270 Labeller::Relabelling relabelling =
m_labeller->label
1271 (point, havePrevPoint ? &prevPoint :
nullptr);
1273 if (relabelling.first == Labeller::AppliesToPreviousEvent) {
1274 command->remove(prevPoint);
1275 command->add(relabelling.second);
1277 point = relabelling.second;
1281 command->add(point);
1283 command->setName(tr(
"Add Point at %1 s")
1284 .arg(RealTime::frame2RealTime
1286 sodm->getSampleRate())
1287 .toText(
false).c_str()));
1289 Command *c = command->finish();
1291 CommandHistory::getInstance()->addCommand(c,
false);
1300 MultiSelection::SelectionList selections =
m_viewManager->getSelections();
1301 for (MultiSelection::SelectionList::iterator i = selections.begin();
1302 i != selections.end(); ++i) {
1303 sv_frame_t start = i->getStartFrame();
1304 sv_frame_t end = i->getEndFrame();
1321 sv_frame_t alignedStart = pane->alignFromReference(frame);
1322 sv_frame_t alignedEnd = pane->alignFromReference(frame + duration);
1323 if (alignedStart >= alignedEnd)
return;
1324 sv_frame_t alignedDuration = alignedEnd - alignedStart;
1326 Command *c =
nullptr;
1328 QString name = tr(
"Add Item at %1 s")
1329 .arg(RealTime::frame2RealTime
1332 .toText(
false).c_str());
1334 Layer *layer = pane->getSelectedLayer();
1337 ModelId modelId = layer->getModel();
1339 auto rm = ModelById::getAs<RegionModel>(modelId);
1341 Event point(alignedStart,
1342 rm->getValueMaximum() + 1,
1345 ChangeEventsCommand *command =
new ChangeEventsCommand
1346 (modelId.untyped, name);
1347 command->add(point);
1348 c = command->finish();
1352 CommandHistory::getInstance()->addCommand(c,
false);
1356 auto nm = ModelById::getAs<NoteModel>(modelId);
1358 Event point(alignedStart,
1359 nm->getValueMinimum(),
1363 ChangeEventsCommand *command =
new ChangeEventsCommand
1364 (modelId.untyped, name);
1365 command->add(point);
1366 c = command->finish();
1370 CommandHistory::getInstance()->addCommand(c,
false);
1381 Layer *layer =
dynamic_cast<TimeInstantLayer *
>(pane->getSelectedLayer());
1386 ModelId modelId = layer->getModel();
1388 auto sodm = ModelById::getAs<SparseOneDimensionalModel>(modelId);
1394 labeller.setSampleRate(sodm->getSampleRate());
1396 Command *c = labeller.labelAll(modelId.untyped, &ms, sodm->getAllEvents());
1397 if (c) CommandHistory::getInstance()->addCommand(c,
false);
1406 Layer *layer =
dynamic_cast<TimeInstantLayer *
>(pane->getSelectedLayer());
1411 ModelId modelId = layer->getModel();
1413 auto sodm = ModelById::getAs<SparseOneDimensionalModel>(modelId);
1419 labeller.setSampleRate(sodm->getSampleRate());
1421 Command *c = labeller.subdivide(modelId.untyped, &ms, sodm->getAllEvents(), n);
1422 if (c) CommandHistory::getInstance()->addCommand(c,
false);
1431 Layer *layer =
dynamic_cast<TimeInstantLayer *
>(pane->getSelectedLayer());
1436 ModelId modelId = layer->getModel();
1438 auto sodm = ModelById::getAs<SparseOneDimensionalModel>(modelId);
1444 labeller.setSampleRate(sodm->getSampleRate());
1446 Command *c = labeller.winnow(modelId.untyped, &ms, sodm->getAllEvents(), n);
1447 if (c) CommandHistory::getInstance()->addCommand(c,
false);
1453 ProgressDialog dialog(tr(
"Opening file or URL..."),
true, 2000,
this);
1454 connect(&dialog, SIGNAL(showing()),
this, SIGNAL(
hideSplash()));
1455 return open(FileSource(fileOrUrl, &dialog), mode);
1464 source.waitForData();
1470 QString extension = source.getExtension().toLower();
1472 bool rdf = (extension ==
"rdf" || extension ==
"n3" || extension ==
"ttl");
1474 AudioFileReaderFactory::getKnownExtensions().contains(extension);
1476 bool rdfSession =
false;
1478 RDFImporter::RDFDocumentType rdfType =
1479 RDFImporter::identifyDocumentType
1480 (QUrl::fromLocalFile(source.getLocalFilename()));
1481 if (rdfType == RDFImporter::AudioRefAndAnnotations ||
1482 rdfType == RDFImporter::AudioRef) {
1484 }
else if (rdfType == RDFImporter::NotRDF) {
1492 bool cancel =
false;
1495 }
else if (cancel) {
1503 }
else if (!canImportLayer) {
1519 }
else if (!canImportLayer) {
1524 if (ImageLayer::isImageFileSupported(source.getLocation())) {
1527 if (extension ==
"mid" || extension ==
"midi") {
1530 if (TextTest::isApparentTextDocument(source)) {
1541 }
catch (
const InsufficientDiscSpace &e) {
1544 SVCERR <<
"MainWindowBase: Caught InsufficientDiscSpace in file open" << endl;
1545 QMessageBox::critical
1546 (
this, tr(
"Not enough disc space"),
1547 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()));
1549 }
catch (
const std::bad_alloc &e) {
1552 SVCERR <<
"MainWindowBase: Caught bad_alloc in file open" << endl;
1553 QMessageBox::critical
1554 (
this, tr(
"Not enough memory"),
1555 tr(
"<b>Not enough memory</b><p>There doesn't appear to be enough memory to accommodate any necessary temporary data.</p>"));
1563 QString templateName)
1565 SVDEBUG <<
"MainWindowBase::openAudio(" << source.getLocation() <<
") with mode " << mode <<
" and template " << templateName << endl;
1567 if (templateName ==
"") {
1569 SVDEBUG <<
"(Default template is: \"" << templateName <<
"\")" << endl;
1574 if (!source.isAvailable()) {
1575 if (source.wasCancelled()) {
1584 source.waitForData();
1586 sv_samplerate_t rate = 0;
1588 SVDEBUG <<
"Checking whether to preserve incoming audio file's sample rate" 1591 if (Preferences::getInstance()->getFixedSampleRate() != 0) {
1592 rate = Preferences::getInstance()->getFixedSampleRate();
1593 SVDEBUG <<
"No: preferences specify fixed rate of " << rate << endl;
1594 }
else if (Preferences::getInstance()->getResampleOnLoad()) {
1597 SVDEBUG <<
"Preferences specify resampling additional models to match main model, but we are opening this file to replace the main model according to the open mode: therefore..." << endl;
1600 SVDEBUG <<
"No: preferences specify resampling to match main model, whose rate is currently " << rate << endl;
1606 SVDEBUG <<
"Yes, preserving incoming file rate" << endl;
1609 auto newModel = std::make_shared<ReadOnlyWaveFileModel>(source, rate);
1610 if (!newModel->isOK()) {
1612 if (source.wasCancelled()) {
1619 auto newModelId = ModelById::add(newModel);
1621 (source, newModelId, mode, templateName,
true);
1630 QString templateName,
1631 bool registerSource)
1637 settings.beginGroup(
"MainWindow");
1638 int lastMode = settings.value(
"lastaudioopenmode", 0).toBool();
1639 settings.endGroup();
1643 items << tr(
"Close the current session and start a new one")
1644 << tr(
"Replace the main audio file in this session")
1645 << tr(
"Add the audio file to this session");
1648 QString item = ListInputDialog::getItem
1649 (
this, tr(
"Select target for import"),
1650 tr(
"<b>Select a target for import</b><p>You already have an audio file loaded.<br>What would you like to do with the new audio file?"),
1651 items, lastMode, &ok);
1653 if (!ok || item.isEmpty()) {
1654 ModelById::release(newModel);
1659 for (
int i = 0; i < items.size(); ++i) {
1660 if (item == items[i]) imode = i;
1663 settings.beginGroup(
"MainWindow");
1664 settings.setValue(
"lastaudioopenmode", imode);
1665 settings.endGroup();
1680 View::ModelSet models(pane->getModels());
1699 SVDEBUG <<
"File open mode requested is something other than ReplaceSession, but we have no document at all yet, so we must use ReplaceSession mode" << endl;
1704 SVDEBUG <<
"File open mode requested is CreateAdditionalModel, but we have no main model, so switching to ReplaceSession mode" << endl;
1708 bool loadedTemplate =
false;
1717 SVDEBUG <<
"SV looking for template " << templateName << endl;
1718 if (templateName !=
"") {
1721 SVDEBUG <<
"Template load cancelled" << endl;
1726 SVDEBUG <<
"Template load succeeded" << endl;
1727 loadedTemplate =
true;
1731 if (!loadedTemplate) {
1732 SVDEBUG <<
"No template found: closing session, creating new empty document" << endl;
1737 SVDEBUG <<
"Now switching to ReplaceMainModel mode" << endl;
1741 emit
activity(tr(
"Import audio file \"%1\"").arg(source.getLocation()));
1746 if (!prevMain.isNone()) {
1750 SVDEBUG <<
"SV about to call setMainModel(" << newModel <<
"): prevMain is " << prevMain << endl;
1759 CommandHistory::getInstance()->clear();
1760 CommandHistory::getInstance()->documentSaved();
1768 if (!source.isRemote() && registerSource) {
1776 SVCERR <<
"Mode is CreateAdditionalModel" << endl;
1778 CommandHistory::getInstance()->startCompoundOperation
1779 (tr(
"Import \"%1\"").arg(source.getBasename()),
true);
1784 CommandHistory::getInstance()->addCommand(command);
1786 Pane *pane = command->
getPane();
1789 SVCERR <<
"Have time ruler, adding it" << endl;
1792 SVCERR <<
"Do not have time ruler" << endl;
1801 CommandHistory::getInstance()->endCompoundOperation();
1812 Layer *replace =
nullptr;
1814 for (
int i = 0; i < pane->getLayerCount(); ++i) {
1815 Layer *layer = pane->getLayer(i);
1816 if (dynamic_cast<WaveformLayer *>(layer)) {
1822 CommandHistory::getInstance()->startCompoundOperation
1823 (tr(
"Import \"%1\"").arg(source.getBasename()),
true);
1837 CommandHistory::getInstance()->endCompoundOperation();
1842 if (registerSource) {
1845 if (!source.isRemote() && registerSource) {
1848 source.getLocalFilename());
1863 SVDEBUG <<
"MainWindowBase::openPlaylist(" << source.getLocation() <<
")" << endl;
1865 std::set<QString> extensions;
1866 PlaylistFileReader::getSupportedExtensions(extensions);
1867 QString extension = source.getExtension().toLower();
1868 if (extensions.find(extension) == extensions.end())
return FileOpenFailed;
1871 source.waitForData();
1873 PlaylistFileReader reader(source.getLocalFilename());
1876 PlaylistFileReader::Playlist playlist = reader.load();
1878 bool someSuccess =
false;
1880 for (PlaylistFileReader::Playlist::const_iterator i = playlist.begin();
1881 i != playlist.end(); ++i) {
1883 ProgressDialog dialog(tr(
"Opening playlist..."),
true, 2000,
this);
1884 connect(&dialog, SIGNAL(showing()),
this, SIGNAL(
hideSplash()));
1904 SVDEBUG <<
"MainWindowBase::openLayer(" << source.getLocation() <<
")" << endl;
1910 cerr <<
"WARNING: MainWindowBase::openLayer: no current pane" << endl;
1916 cerr <<
"WARNING: MainWindowBase::openLayer: No main model -- hence no default sample rate available" << endl;
1921 source.waitForData();
1923 QString path = source.getLocalFilename();
1925 RDFImporter::RDFDocumentType rdfType =
1926 RDFImporter::identifyDocumentType(QUrl::fromLocalFile(path));
1930 if (rdfType != RDFImporter::NotRDF) {
1934 }
else if (source.getExtension().toLower() ==
"svl" ||
1935 (source.getExtension().toLower() ==
"xml" &&
1942 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
1943 cerr <<
"ERROR: MainWindowBase::openLayer(" 1944 << source.getLocation()
1945 <<
"): Failed to open file for reading" << endl;
1956 reader.setCurrentPane(pane);
1958 QXmlInputSource inputSource(&file);
1959 reader.parse(inputSource);
1961 if (!reader.isOK()) {
1962 cerr <<
"ERROR: MainWindowBase::openLayer(" 1963 << source.getLocation()
1964 <<
"): Failed to read XML file: " 1965 << reader.getErrorString() << endl;
1969 emit
activity(tr(
"Import layer XML file \"%1\"").arg(source.getLocation()));
1973 if (!source.isRemote()) {
1983 MIDIFileImportDialog midiDlg(
this);
1985 Model *newModelPtr = DataFileReaderFactory::loadNonCSV
1989 CSVFormatDialog *dialog =
1990 new CSVFormatDialog(
this,
1994 if (dialog->exec() == QDialog::Accepted) {
1995 newModelPtr = DataFileReaderFactory::loadCSV
1996 (path, dialog->getFormat(),
2004 SVDEBUG <<
"MainWindowBase::openLayer: Have model" << endl;
2006 emit
activity(tr(
"Import MIDI file \"%1\"").arg(source.getLocation()));
2009 ModelById::add(std::shared_ptr<Model>(newModelPtr));
2020 if (!source.isRemote()) {
2022 (FileFinder::LayerFile,
2029 }
catch (DataFileReaderFactory::Exception e) {
2030 if (e == DataFileReaderFactory::ImportCancelled) {
2042 SVDEBUG <<
"MainWindowBase::openImage(" << source.getLocation() <<
")" << endl;
2048 cerr <<
"WARNING: MainWindowBase::openImage: no current pane" << endl;
2056 bool newLayer =
false;
2058 ImageLayer *il =
dynamic_cast<ImageLayer *
>(pane->getSelectedLayer());
2060 for (
int i = pane->getLayerCount()-1; i >= 0; --i) {
2061 il =
dynamic_cast<ImageLayer *
>(pane->getLayer(i));
2066 il =
dynamic_cast<ImageLayer *
> 2074 SVCERR <<
"openImage: trying location \"" << source.getLocation() <<
"\" in image layer" << endl;
2076 if (!il->addImage(
m_viewManager->getGlobalCentreFrame(), source.getLocation())) {
2095 QStringList files = dir.entryList(QDir::Files | QDir::Readable);
2100 bool cancelled =
false;
2102 foreach (QString file, files) {
2104 FileSource source(dir.filePath(file));
2105 if (!source.isAvailable()) {
2109 if (AudioFileReaderFactory::getKnownExtensions().contains
2110 (source.getExtension().toLower())) {
2130 if (cancelled)
break;
2139 ProgressDialog dialog(tr(
"Opening session..."),
true, 2000,
this);
2140 connect(&dialog, SIGNAL(showing()),
this, SIGNAL(
hideSplash()));
2141 return openSession(FileSource(fileOrUrl, &dialog));
2147 SVDEBUG <<
"MainWindowBase::openSession(" << source.getLocation() <<
")" << endl;
2150 source.waitForData();
2152 QString sessionExt =
2153 InteractiveFileFinder::getInstance()->getApplicationSessionExtension();
2155 QString extension = source.getExtension().toLower();
2157 bool rdf = (extension ==
"rdf" || extension ==
"n3" || extension ==
"ttl");
2159 if (extension != sessionExt) {
2163 RDFImporter::RDFDocumentType rdfType =
2164 RDFImporter::identifyDocumentType
2165 (QUrl::fromLocalFile(source.getLocalFilename()));
2169 if (rdfType == RDFImporter::AudioRefAndAnnotations ||
2170 rdfType == RDFImporter::AudioRef) {
2172 }
else if (rdfType != RDFImporter::NotRDF) {
2176 }
else if (extension ==
"xml") {
2180 cerr <<
"This XML file looks like a session file, attempting to open it as a session" << endl;
2189 QXmlInputSource *inputSource =
nullptr;
2190 BZipFileDevice *bzFile =
nullptr;
2191 QFile *rawFile =
nullptr;
2193 if (extension == sessionExt) {
2194 bzFile =
new BZipFileDevice(source.getLocalFilename());
2195 if (!bzFile->open(QIODevice::ReadOnly)) {
2199 inputSource =
new QXmlInputSource(bzFile);
2201 rawFile =
new QFile(source.getLocalFilename());
2202 inputSource =
new QXmlInputSource(rawFile);
2206 if (bzFile) bzFile->close();
2228 reader.parse(*inputSource);
2230 if (!reader.isOK()) {
2231 error = tr(
"SV XML file read error:\n%1").arg(reader.getErrorString());
2234 if (bzFile) bzFile->close();
2240 bool ok = (error ==
"");
2244 emit
activity(tr(
"Import session file \"%1\"").arg(source.getLocation()));
2255 QMessageBox::warning
2257 tr(
"Incomplete session loaded"),
2258 tr(
"Some of the audio content referred to by the original session file could not be loaded.\nIf you save this session, it will be saved without any reference to that audio, and information may be lost."),
2266 CommandHistory::getInstance()->clear();
2267 CommandHistory::getInstance()->documentSaved();
2273 if (!source.isRemote()) {
2276 source.getLocalFilename());
2296 QString tfile = rf.getResourcePath(
"templates", templateName +
".svt");
2298 cerr <<
"SV loading template file " << tfile << endl;
2308 cerr <<
"MainWindowBase::openSessionTemplate(" << source.getLocation() <<
")" << endl;
2311 source.waitForData();
2313 QXmlInputSource *inputSource =
nullptr;
2314 QFile *file =
nullptr;
2316 file =
new QFile(source.getLocalFilename());
2317 inputSource =
new QXmlInputSource(file);
2340 reader.parse(*inputSource);
2342 if (!reader.isOK()) {
2343 error = tr(
"SV XML file read error:\n%1").arg(reader.getErrorString());
2349 bool ok = (error ==
"");
2353 emit
activity(tr(
"Open session template \"%1\"").arg(source.getLocation()));
2358 CommandHistory::getInstance()->clear();
2359 CommandHistory::getInstance()->documentSaved();
2374 SVDEBUG <<
"MainWindowBase::openSessionFromRDF(" << source.getLocation() <<
")" << endl;
2377 source.waitForData();
2391 CommandHistory::getInstance()->clear();
2392 CommandHistory::getInstance()->documentSaved();
2404 sv_samplerate_t rate = 0;
2406 SVDEBUG <<
"MainWindowBase::openLayersFromRDF" << endl;
2408 ProgressDialog dialog(tr(
"Importing from RDF..."),
true, 2000,
this);
2409 connect(&dialog, SIGNAL(showing()),
this, SIGNAL(
hideSplash()));
2413 }
else if (Preferences::getInstance()->getResampleOnLoad()) {
2419 RDFImporter importer
2420 (QUrl::fromLocalFile(source.getLocalFilename()).toString(), rate);
2422 if (!importer.isOK()) {
2423 if (importer.getErrorString() !=
"") {
2424 QMessageBox::critical
2425 (
this, tr(
"Failed to import RDF"),
2426 tr(
"<b>Failed to import RDF</b><p>Importing data from RDF document at \"%1\" failed: %2</p>")
2427 .arg(source.getLocation()).arg(importer.getErrorString()));
2432 std::vector<ModelId> modelIds = importer.getDataModels(&dialog);
2434 dialog.setMessage(tr(
"Importing from RDF..."));
2436 if (modelIds.empty()) {
2437 QMessageBox::critical
2438 (
this, tr(
"Failed to import RDF"),
2439 tr(
"<b>Failed to import RDF</b><p>No suitable data models found for import from RDF document at \"%1\"</p>").arg(source.getLocation()));
2443 emit
activity(tr(
"Import RDF document \"%1\"").arg(source.getLocation()));
2445 std::set<ModelId> added;
2447 for (
auto modelId: modelIds) {
2449 if (ModelById::isa<WaveFileModel>(modelId)) {
2452 Layer *layer =
nullptr;
2467 added.insert(modelId);
2469 for (
auto otherId: modelIds) {
2471 if (otherId == modelId)
continue;
2473 bool isDependent =
false;
2474 if (
auto dm = ModelById::get(otherId)) {
2475 if (dm->getSourceModel() == modelId) {
2479 if (!isDependent)
continue;
2483 if (layer->isLayerOpaque() ||
2484 dynamic_cast<Colour3DPlotLayer *
>(layer)) {
2495 }
else if (layer->getLayerColourSignificance() ==
2496 Layer::ColourHasMeaningfulValue) {
2502 bool needNewPane =
false;
2503 for (
int i = 0; i < pane->getLayerCount(); ++i) {
2504 Layer *otherLayer = pane->getLayer(i);
2506 (otherLayer->getLayerColourSignificance() ==
2507 Layer::ColourHasMeaningfulValue)) {
2520 if (pane->getLayerCount() > 4) {
2527 added.insert(otherId);
2532 for (
auto modelId : modelIds) {
2534 if (added.find(modelId) == added.end()) {
2554 void log(std::string message)
const override {
2555 SVDEBUG << message << endl;
2565 breakfastquay::AudioFactory::setLogCallback(&audioLogCallback);
2570 settings.beginGroup(
"Preferences");
2571 QString implementation = settings.value
2572 (
"audio-target",
"").toString();
2574 if (implementation !=
"") suffix =
"-" + implementation;
2575 QString recordDevice = settings.value
2576 (
"audio-record-device" + suffix,
"").toString();
2577 QString playbackDevice = settings.value
2578 (
"audio-playback-device" + suffix,
"").toString();
2579 settings.endGroup();
2581 if (implementation ==
"auto") {
2582 implementation =
"";
2585 breakfastquay::AudioFactory::Preference preference;
2586 preference.implementation = implementation.toStdString();
2587 preference.recordDevice = recordDevice.toStdString();
2588 preference.playbackDevice = playbackDevice.toStdString();
2590 SVCERR <<
"createAudioIO: Preferred implementation = \"" 2591 << preference.implementation <<
"\"" << endl;
2592 SVCERR <<
"createAudioIO: Preferred playback device = \"" 2593 << preference.playbackDevice <<
"\"" << endl;
2594 SVCERR <<
"createAudioIO: Preferred record device = \"" 2595 << preference.recordDevice <<
"\"" << endl;
2597 breakfastquay::ApplicationPlaybackSource *source =
2600 std::string errorString;
2603 m_audioIO = breakfastquay::AudioFactory::
2604 createCallbackIO(
m_recordTarget, source, preference, errorString);
2606 SVDEBUG <<
"MainWindowBase::createAudioIO: Suspending on creation" << endl;
2619 createCallbackPlayTarget(source, preference, errorString);
2621 SVDEBUG <<
"MainWindowBase::createAudioIO: Suspending on creation" << endl;
2630 QString error = errorString.c_str();
2631 QString firstBit, secondBit;
2632 if (implementation ==
"") {
2634 firstBit = tr(
"<b>No audio available</b><p>Could not open an audio device.</p>");
2636 firstBit = tr(
"<b>No audio available</b><p>Could not open audio device: %1</p>").arg(error);
2640 secondBit = tr(
"<p>Automatic audio device detection failed. Audio playback and recording will not be available during this session.</p>");
2642 secondBit = tr(
"<p>Automatic audio device detection failed. Audio playback will not be available during this session.</p>");
2645 QString driverName = breakfastquay::AudioFactory::
2646 getImplementationDescription(implementation.toStdString())
2649 firstBit = tr(
"<b>No audio available</b><p>Failed to open your preferred audio driver (\"%1\").</p>").arg(driverName);
2651 firstBit = tr(
"<b>No audio available</b><p>Failed to open your preferred audio driver (\"%1\"): %2.</p>").arg(driverName).arg(error);
2655 secondBit = tr(
"<p>Audio playback and recording will not be available during this session.</p>");
2657 secondBit = tr(
"<p>Audio playback will not be available during this session.</p>");
2660 SVDEBUG <<
"createAudioIO: ERROR: Failed to open audio device \"" 2661 << implementation <<
"\": error is: " << error << endl;
2662 QMessageBox::warning(
this, tr(
"Couldn't open audio device"),
2663 firstBit + secondBit, QMessageBox::Ok);
2694 SVCERR <<
"MainWindowBase::audioChannelCountIncreased" << endl;
2700 SVCERR <<
"MainWindowBase::audioChannelCountIncreased: we were recording already, so resuming IO now" << endl;
2712 std::shared_ptr<WaveFileModel>
2756 TempWriteFile temp(path);
2758 BZipFileDevice bzFile(temp.getTemporaryFilename());
2759 if (!bzFile.open(QIODevice::WriteOnly)) {
2760 cerr <<
"Failed to open session file \"" 2761 << temp.getTemporaryFilename()
2762 <<
"\" for writing: " 2763 << bzFile.errorString() << endl;
2767 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
2769 QTextStream out(&bzFile);
2770 out.setCodec(QTextCodec::codecForName(
"UTF-8"));
2774 QApplication::restoreOverrideCursor();
2776 if (!bzFile.isOK()) {
2777 QMessageBox::critical(
this, tr(
"Failed to write file"),
2778 tr(
"<b>Save failed</b><p>Failed to write to file \"%1\": %2")
2779 .arg(path).arg(bzFile.errorString()));
2785 temp.moveToTarget();
2788 }
catch (FileOperationFailed &f) {
2790 QMessageBox::critical(
this, tr(
"Failed to write file"),
2791 tr(
"<b>Save failed</b><p>Failed to write to file \"%1\": %2")
2792 .arg(path).arg(f.what()));
2802 TempWriteFile temp(path);
2804 QFile file(temp.getTemporaryFilename());
2805 if (!file.open(QIODevice::WriteOnly)) {
2806 cerr <<
"Failed to open session template file \"" 2807 << temp.getTemporaryFilename()
2808 <<
"\" for writing: " 2809 << file.errorString() << endl;
2813 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
2815 QTextStream out(&file);
2816 out.setCodec(QTextCodec::codecForName(
"UTF-8"));
2820 QApplication::restoreOverrideCursor();
2823 temp.moveToTarget();
2826 }
catch (FileOperationFailed &f) {
2828 QMessageBox::critical(
this, tr(
"Failed to write file"),
2829 tr(
"<b>Save failed</b><p>Failed to write to file \"%1\": %2")
2830 .arg(path).arg(f.what()));
2842 QString path, QString &error)
2844 if (QFileInfo(path).suffix() ==
"") path +=
".svl";
2846 QString suffix = QFileInfo(path).suffix().toLower();
2848 auto model = ModelById::get(layer->getExportModel(
nullptr));
2850 error = tr(
"Internal error: unknown model");
2855 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
2856 error = tr(
"Failed to open file %1 for writing").arg(path);
2858 QTextStream out(&file);
2859 out.setCodec(QTextCodec::codecForName(
"UTF-8"));
2860 out <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 2861 <<
"<!DOCTYPE sonic-visualiser>\n" 2865 model->toXml(out,
" ");
2870 layer->toXml(out,
" ");
2872 out <<
" </display>\n" 2876 return (error ==
"");
2881 MultiSelection *selectionsToWrite,
2882 QString path, QString &error)
2884 if (QFileInfo(path).suffix() ==
"") path +=
".mid";
2886 QString suffix = QFileInfo(path).suffix().toLower();
2888 auto model = ModelById::get(layer->getExportModel(
nullptr));
2890 error = tr(
"Internal error: unknown model");
2894 auto nm = ModelById::getAs<NoteModel>(layer->getModel());
2897 error = tr(
"Can't export non-note layers to MIDI");
2898 }
else if (!selectionsToWrite) {
2899 MIDIFileWriter writer(path, nm.get(), nm->getSampleRate());
2901 if (!writer.isOK()) {
2902 error = writer.getError();
2905 NoteModel temporary(nm->getSampleRate(),
2906 nm->getResolution(),
2907 nm->getValueMinimum(),
2908 nm->getValueMaximum(),
2910 temporary.setScaleUnits(nm->getScaleUnits());
2911 for (
const auto &s: selectionsToWrite->getSelections()) {
2912 EventVector ev(nm->getEventsStartingWithin
2913 (s.getStartFrame(), s.getDuration()));
2914 for (
const auto &e: ev) {
2918 MIDIFileWriter writer(path, &temporary, temporary.getSampleRate());
2920 if (!writer.isOK()) {
2921 error = writer.getError();
2925 return (error ==
"");
2930 QString path, QString &error)
2932 if (QFileInfo(path).suffix() ==
"") path +=
".ttl";
2934 QString suffix = QFileInfo(path).suffix().toLower();
2936 auto model = ModelById::get(layer->getExportModel(
nullptr));
2938 error = tr(
"Internal error: unknown model");
2942 if (!RDFExporter::canExportModel(model.get())) {
2943 error = tr(
"Sorry, cannot export this layer type to RDF (supported types are: region, note, text, time instants, time values)");
2945 RDFExporter exporter(path, model.get());
2947 if (!exporter.isOK()) {
2948 error = exporter.getError();
2952 return (error ==
"");
2957 MultiSelection *selectionsToWrite,
2959 DataExportOptions options,
2960 QString path, QString &error)
2962 if (QFileInfo(path).suffix() ==
"") path +=
".csv";
2964 QString suffix = QFileInfo(path).suffix().toLower();
2966 auto model = ModelById::get(layer->getExportModel(provider));
2968 error = tr(
"Internal error: unknown model");
2972 ProgressDialog dialog {
2973 QObject::tr(
"Exporting layer..."),
true, 500,
this,
2974 Qt::ApplicationModal
2977 CSVFileWriter writer(path, model.get(), &dialog, delimiter, options);
2979 if (selectionsToWrite) {
2980 writer.writeSelection(*selectionsToWrite);
2985 if (!writer.isOK()) {
2986 error = writer.getError();
2988 error = tr(
"Failed to export layer for an unknown reason");
2992 return (error ==
"");
2997 MultiSelection *selectionsToWrite,
2998 QString path, QString &error)
3000 if (QFileInfo(path).suffix() ==
"") path +=
".csv";
3001 QString suffix = QFileInfo(path).suffix().toLower();
3003 if (suffix ==
"xml" || suffix ==
"svl") {
3005 }
else if (suffix ==
"mid" || suffix ==
"midi") {
3007 }
else if (suffix ==
"ttl" || suffix ==
"n3") {
3011 (suffix ==
"csv" ?
"," :
"\t"),
3012 DataExportDefaults, path, error);
3019 QString indent(
" ");
3021 out <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
3022 out <<
"<!DOCTYPE sonic-visualiser>\n";
3031 out <<
"<display>\n";
3033 out << QString(
" <window width=\"%1\" height=\"%2\"/>\n")
3034 .arg(width()).arg(height());
3036 for (
int i = 0; i <
m_paneStack->getPaneCount(); ++i) {
3041 pane->toXml(out, indent);
3045 out <<
"</display>\n";
3055 cerr <<
"MainWindowBase::addPaneToStack()" << endl;
3057 CommandHistory::getInstance()->addCommand(command);
3058 Pane *pane = command->
getPane();
3065 Pane *currentPane =
m_paneStack->getCurrentPane();
3066 if (currentPane) currentPane->zoom(
true);
3072 Pane *currentPane =
m_paneStack->getCurrentPane();
3073 if (currentPane) currentPane->zoom(
false);
3079 Pane *currentPane =
m_paneStack->getCurrentPane();
3080 if (!currentPane)
return;
3085 sv_frame_t start = model->getStartFrame();
3086 sv_frame_t end = model->getEndFrame();
3088 int pixels = currentPane->width();
3090 int sw = currentPane->getVerticalScaleWidth();
3091 if (pixels > sw * 2) pixels -= sw * 2;
3093 if (pixels > 4) pixels -= 4;
3095 ZoomLevel zoomLevel = ZoomLevel::fromRatio(pixels, end - start);
3096 currentPane->setZoomLevel(zoomLevel);
3097 currentPane->setCentreFrame((start + end) / 2);
3103 Pane *currentPane =
m_paneStack->getCurrentPane();
3105 settings.beginGroup(
"MainWindow");
3106 int zoom = settings.value(
"zoom-default", 1024).toInt();
3107 settings.endGroup();
3109 currentPane->setZoomLevel(ZoomLevel(ZoomLevel::FramesPerPixel, zoom));
3116 Pane *currentPane =
m_paneStack->getCurrentPane();
3117 if (currentPane) currentPane->scroll(
false,
false);
3123 Pane *currentPane =
m_paneStack->getCurrentPane();
3124 if (currentPane) currentPane->scroll(
false,
true);
3130 Pane *currentPane =
m_paneStack->getCurrentPane();
3131 if (currentPane) currentPane->scroll(
false,
false,
false);
3137 Pane *currentPane =
m_paneStack->getCurrentPane();
3138 if (currentPane) currentPane->scroll(
true,
false);
3144 Pane *currentPane =
m_paneStack->getCurrentPane();
3145 if (currentPane) currentPane->scroll(
true,
true);
3151 Pane *currentPane =
m_paneStack->getCurrentPane();
3152 if (currentPane) currentPane->scroll(
true,
false,
false);
3164 m_viewManager->setOverlayMode(ViewManager::StandardOverlays);
3176 for (
int i = 0; i <
m_paneStack->getPaneCount(); ++i) {
3178 if (!pane)
continue;
3179 for (
int j = 0; j < pane->getLayerCount(); ++j) {
3180 Layer *layer = pane->getLayer(j);
3181 if (!dynamic_cast<TimeRulerLayer *>(layer))
continue;
3187 SVCERR <<
"WARNING: Time ruler layer was not reset to 0 before session template loaded?" << endl;
3196 bool haveRulers =
false;
3197 bool someHidden =
false;
3199 for (
int i = 0; i <
m_paneStack->getPaneCount(); ++i) {
3202 if (!pane)
continue;
3204 for (
int j = 0; j < pane->getLayerCount(); ++j) {
3206 Layer *layer = pane->getLayer(j);
3207 if (!dynamic_cast<TimeRulerLayer *>(layer))
continue;
3210 if (layer->isLayerDormant(pane)) someHidden =
true;
3216 bool show = someHidden;
3218 for (
int i = 0; i <
m_paneStack->getPaneCount(); ++i) {
3221 if (!pane)
continue;
3223 for (
int j = 0; j < pane->getLayerCount(); ++j) {
3225 Layer *layer = pane->getLayer(j);
3226 if (!dynamic_cast<TimeRulerLayer *>(layer))
continue;
3228 layer->showLayer(pane, show);
3247 if (
m_paneStack->getLayoutStyle() == PaneStack::HiddenPropertyStacksLayout) {
3248 if (Preferences::getInstance()->getPropertyBoxLayout() ==
3249 Preferences::VerticallyStacked) {
3250 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
3252 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
3255 m_paneStack->setLayoutStyle(PaneStack::HiddenPropertyStacksLayout);
3267 QList<QFrame *> frames = statusBar()->findChildren<QFrame *>();
3268 foreach (QFrame *f, frames) {
3269 f->setFrameStyle(QFrame::NoFrame);
3279 settings.beginGroup(
"MainWindow");
3280 bool sb = settings.value(
"showstatusbar",
true).toBool();
3283 statusBar()->hide();
3285 statusBar()->show();
3288 settings.setValue(
"showstatusbar", !sb);
3290 settings.endGroup();
3306 if (name ==
"Property Box Layout") {
3307 if (
m_paneStack->getLayoutStyle() != PaneStack::HiddenPropertyStacksLayout) {
3308 if (Preferences::getInstance()->getPropertyBoxLayout() ==
3309 Preferences::VerticallyStacked) {
3310 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
3312 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
3316 Preferences::BackgroundMode mode =
3317 Preferences::getInstance()->getBackgroundMode();
3318 if (mode == Preferences::BackgroundFromTheme) {
3320 }
else if (mode == Preferences::DarkBackground) {
3334 QAction *action = qobject_cast<QAction *>(sender());
3335 if (action) action->setChecked(
false);
3347 QAction *action = qobject_cast<QAction *>(sender());
3350 if (action) action->setChecked(
false);
3355 if (action) action->setChecked(
false);
3360 SVDEBUG <<
"MainWindowBase::record: upgrading from " 3361 <<
"AUDIO_PLAYBACK_NOW_RECORD_LATER to " 3362 <<
"AUDIO_PLAYBACK_AND_RECORD" << endl;
3368 SVDEBUG <<
"MainWindowBase::record: about to create audio IO" << endl;
3375 if (action) action->setChecked(
false);
3384 QMessageBox::critical
3385 (
this, tr(
"No record device available"),
3386 tr(
"<b>No record device available</b><p>Failed to find or open an audio device for recording. Only playback will be available.</p>"));
3387 if (action) action->setChecked(
false);
3400 if (action) action->setChecked(
false);
3407 SVCERR <<
"MainWindowBase::record: about to resume" << endl;
3410 WritableWaveFileModel *modelPtr =
m_recordTarget->startRecording();
3412 SVCERR <<
"ERROR: MainWindowBase::record: Recording failed" << endl;
3413 QMessageBox::critical
3414 (
this, tr(
"Recording failed"),
3415 tr(
"<b>Recording failed</b><p>Failed to switch to record mode (some internal problem?)</p>"));
3416 if (action) action->setChecked(
false);
3420 if (!modelPtr->isOK()) {
3421 SVCERR <<
"MainWindowBase::record: Model not OK, stopping and suspending" << endl;
3424 if (action) action->setChecked(
false);
3429 SVCERR <<
"MainWindowBase::record: Model is OK, continuing..." << endl;
3431 QString location = modelPtr->getLocation();
3433 auto modelId = ModelById::add(std::shared_ptr<Model>(modelPtr));
3440 bool loadedTemplate =
false;
3442 if (templateName !=
"") {
3445 SVCERR <<
"MainWindowBase::record: Session template open cancelled, stopping and suspending" << endl;
3448 ModelById::release(modelId);
3452 loadedTemplate =
true;
3456 if (!loadedTemplate) {
3462 if (!prevMain.isNone()) {
3473 CommandHistory::getInstance()->clear();
3474 CommandHistory::getInstance()->documentSaved();
3482 CommandHistory::getInstance()->startCompoundOperation
3483 (tr(
"Import Recorded Audio"),
true);
3488 CommandHistory::getInstance()->addCommand(command);
3490 Pane *pane = command->
getPane();
3502 CommandHistory::getInstance()->endCompoundOperation();
3517 sv_frame_t playbackFrame =
m_viewManager->getPlaybackFrame();
3518 sv_frame_t frame = playbackFrame + 1;
3524 if (!pane || !layer) {
3526 frame = RealTime::realTime2Frame
3534 sv_frame_t pframe = pane->alignFromReference(frame);
3536 bool success =
false;
3538 while (layer->snapToFeatureFrame(pane, pframe, resolution,
3539 Layer::SnapRight, -1)) {
3540 if (pane->alignToReference(pframe) > playbackFrame) {
3549 frame = pane->alignToReference(pframe);
3555 if (frame < 0) frame = 0;
3597 if (!layer) {
ffwd();
return; }
3603 if (pane) frame = pane->alignFromReference(frame);
3604 if (layer->snapToSimilarFeature(
m_paneStack->getCurrentPane(),
3605 frame, resolution, Layer::SnapRight)) {
3606 if (pane) frame = pane->alignToReference(frame);
3611 if (frame < 0) frame = 0;
3632 sv_frame_t playbackFrame =
m_viewManager->getPlaybackFrame();
3633 sv_frame_t frame = playbackFrame;
3634 if (frame > 0) --frame;
3644 RealTime ct = RealTime::frame2RealTime(frame, sr);
3645 ct = ct - RealTime::fromSeconds(0.15);
3646 if (ct < RealTime::zeroTime) ct = RealTime::zeroTime;
3647 frame = RealTime::realTime2Frame(ct, sr);
3650 if (!pane || !layer) {
3652 frame = RealTime::realTime2Frame
3660 sv_frame_t pframe = pane->alignFromReference(frame);
3662 bool success =
false;
3664 while (layer->snapToFeatureFrame(pane, pframe, resolution,
3665 Layer::SnapLeft, -1)) {
3666 if (pane->alignToReference(pframe) < playbackFrame ||
3676 frame = pane->alignToReference(pframe);
3682 if (frame < 0) frame = 0;
3711 if (!layer) {
rewind();
return; }
3717 if (pane) frame = pane->alignFromReference(frame);
3718 if (layer->snapToSimilarFeature(
m_paneStack->getCurrentPane(),
3719 frame, resolution, Layer::SnapLeft)) {
3720 if (pane) frame = pane->alignToReference(frame);
3725 if (frame < 0) frame = 0;
3738 if (!pane)
return nullptr;
3740 Layer *layer = pane->getSelectedLayer();
3742 if (!dynamic_cast<TimeInstantLayer *>(layer) &&
3743 !dynamic_cast<TimeValueLayer *>(layer) &&
3744 !dynamic_cast<RegionLayer *>(layer) &&
3745 !dynamic_cast<TimeRulerLayer *>(layer)) {
3749 for (
int i = pane->getLayerCount(); i > 0; --i) {
3750 Layer *l = pane->getLayer(i-1);
3751 if (dynamic_cast<TimeRulerLayer *>(l)) {
3773 SVDEBUG <<
"MainWindowBase::stop: suspending" << endl;
3789 m_prevCurrentPane(nullptr),
3804 return tr(
"Add Pane");
3850 return tr(
"Remove Pane");
3872 CommandHistory::getInstance()->startCompoundOperation
3873 (tr(
"Delete Pane"),
true);
3877 while (pane->getLayerCount() > 0) {
3878 Layer *layer = pane->getLayer(0);
3887 CommandHistory::getInstance()->addCommand(command);
3890 CommandHistory::getInstance()->endCompoundOperation();
3900 Layer *layer = pane->getSelectedLayer();
3911 Layer *layer =
nullptr;
3913 if (pane) layer = pane->getSelectedLayer();
3916 auto tabular = ModelById::getAs<TabularModel>(layer->getModel());
3921 SVDEBUG <<
"NOTE: Not a tabular model" << endl;
3933 QString title = layer->getLayerPresentationName();
3935 ModelDataTableDialog *dialog =
new ModelDataTableDialog
3936 (layer->getModel(), title,
this);
3937 dialog->setAttribute(Qt::WA_DeleteOnClose);
3953 SLOT(userScrolledToFrame(sv_frame_t)));
3958 SLOT(playbackScrolledToFrame(sv_frame_t)));
3961 SIGNAL(scrollToFrame(sv_frame_t)),
3963 SLOT(setGlobalCentreFrame(sv_frame_t)));
3966 SIGNAL(scrollToFrame(sv_frame_t)),
3968 SLOT(setPlaybackFrame(sv_frame_t)));
3976 Pane *currentPane =
m_paneStack->getCurrentPane();
3977 if (!currentPane)
return;
3979 for (
int i = 0; i <
m_paneStack->getPaneCount(); ++i) {
3994 Pane *currentPane =
m_paneStack->getCurrentPane();
3995 if (!currentPane)
return;
3997 for (
int i = 0; i <
m_paneStack->getPaneCount(); ++i) {
4012 Pane *currentPane =
m_paneStack->getCurrentPane();
4013 if (!currentPane)
return;
4015 int count = currentPane->getLayerCount();
4016 if (count == 0)
return;
4018 Layer *currentLayer = currentPane->getSelectedLayer();
4020 if (!currentLayer) {
4023 (currentPane, currentPane->getFixedOrderLayer(count-1));
4025 for (
int i = 0; i < count; ++i) {
4026 if (currentPane->getFixedOrderLayer(i) == currentLayer) {
4029 (currentPane,
nullptr);
4032 (currentPane, currentPane->getFixedOrderLayer(i-1));
4047 Pane *currentPane =
m_paneStack->getCurrentPane();
4048 if (!currentPane)
return;
4050 int count = currentPane->getLayerCount();
4051 if (count == 0)
return;
4053 Layer *currentLayer = currentPane->getSelectedLayer();
4055 if (!currentLayer) {
4058 (currentPane, currentPane->getFixedOrderLayer(0));
4060 for (
int i = 0; i < count; ++i) {
4061 if (currentPane->getFixedOrderLayer(i) == currentLayer) {
4062 if (i == currentPane->getLayerCount()-1) {
4064 (currentPane,
nullptr);
4067 (currentPane, currentPane->getFixedOrderLayer(i+1));
4084 RealTime now = RealTime::frame2RealTime
4089 RealTime then = RealTime::frame2RealTime
4094 QString remainingStr;
4096 if (then.sec > 10) {
4097 nowStr = now.toSecText().c_str();
4098 thenStr = then.toSecText().c_str();
4099 remainingStr = (then - now).toSecText().c_str();
4102 nowStr = now.toText(
true).c_str();
4103 thenStr = then.toText(
true).c_str();
4104 remainingStr = (then - now).toText(
true).c_str();
4108 .arg(nowStr).arg(thenStr).arg(remainingStr);
4116 RealTime duration = RealTime::frame2RealTime(frame, rate);
4117 QString durStr = duration.toSecText().c_str();
4130 if (!p->getFollowGlobalPan())
return;
4142 (*i)->userScrolledToFrame(frame);
4170 Profiler profiler(
"MainWindowBase::layerRemoved");
4196 ModelId modelId = layer->getModel();
4197 if (!modelId.isNone()) {
4202 for (
int i = 0; i <
m_paneStack->getPaneCount(); ++i) {
4204 if (!pane)
continue;
4205 for (
int j = 0; j < pane->getLayerCount(); ++j) {
4206 Layer *pl = pane->getLayer(j);
4208 !dynamic_cast<TimeRulerLayer *>(pl) &&
4209 (pl->getModel() == modelId)) {
4234 vi->second.erase(dialog);
4246 std::cerr <<
"\nAdding model " << model <<
" to playsource " << std::endl;
4255 auto model = ModelById::getAs<WaveFileModel>(modelId);
4256 if (model)
m_viewManager->setMainModelSampleRate(model->getSampleRate());
4266 for (
int i = 0; i <
m_paneStack->getPaneCount(); ++i) {
4273 SVDEBUG <<
"MainWindowBase::paneDeleteButtonClicked: Unknown pane " 4278 CommandHistory::getInstance()->startCompoundOperation
4279 (tr(
"Delete Pane"),
true);
4281 while (pane->getLayerCount() > 0) {
4282 Layer *layer = pane->getLayer(pane->getLayerCount() - 1);
4291 CommandHistory::getInstance()->addCommand(command);
4293 CommandHistory::getInstance()->endCompoundOperation();
4301 cerr <<
"MainWindowBase::alignmentComplete(" << alignmentModelId <<
")" << endl;
4310 SVDEBUG <<
"MainWindowBase::pollOSC: " 4311 <<
"not making nested invocations, waiting" 4321 SVDEBUG <<
"MainWindowBase::pollOSC: " 4322 <<
"waiting for audio to finish loading" 4328 if (ModelTransformerFactory::getInstance()->haveRunningTransformers()) {
4329 SVDEBUG <<
"MainWindowBase::pollOSC: " 4330 <<
"waiting for running transforms to complete" 4336 SVDEBUG <<
"MainWindowBase::pollOSC: have " 4338 <<
" messages" << endl;
4340 OSCMessage message =
m_oscQueue->readMessage();
4342 if (message.getTarget() != 0) {
4343 SVCERR <<
"MainWindowBase::pollOSC: ignoring message with target " 4344 << message.getTarget() <<
" (we are target 0)" << endl;
4349 handleOSCMessage(message);
4351 disconnect(
m_oscQueue, SIGNAL(messagesAvailable()),
4354 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents |
4355 QEventLoop::ExcludeSocketNotifiers);
4360 connect(
m_oscQueue, SIGNAL(messagesAvailable()),
4367 Pane *currentPane =
nullptr;
4395 QProcess *process =
new QProcess(
this);
4396 connect(process, SIGNAL(finished(
int)), process, SLOT(deleteLater()));
4402 process->start(
"open", args);
4406 (void)getEnvUtf8(
"ProgramFiles", pfiles);
4408 QString::fromStdString(pfiles) +
4409 QString(
"\\Internet Explorer\\IEXPLORE.EXE");
4412 process->start(command, args);
4414 if (!qgetenv(
"KDE_FULL_SESSION").isEmpty()) {
4415 args.append(
"exec");
4417 process->start(
"kfmclient", args);
4418 }
else if (!qgetenv(
"BROWSER").isEmpty()) {
4420 process->start(qgetenv(
"BROWSER"), args);
4423 process->start(
"firefox", args);
4435 QString path = d.canonicalPath();
4436 #if defined Q_OS_WIN32 4440 path = path.replace(
'/',
'\\');
4442 QProcess::execute(
"c:/windows/explorer.exe", args);
4446 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
4447 env.insert(
"LD_LIBRARY_PATH",
"");
4448 process.setProcessEnvironment(env);
4450 #
if defined Q_OS_MAC
4453 "/usr/bin/xdg-open",
4456 process.waitForFinished();
AudioCallbackRecordTarget * m_recordTarget
virtual void playSoloToggled()
void setMainModel(ModelId)
Set the main model (the source for playback sample rate, etc) to the given wave file model...
void canSelectNextPane(bool)
void canMeasureLayer(bool)
virtual void toXml(QTextStream &stream, bool asTemplate)
virtual QString getSaveFileName(FileFinder::FileType type)
void cueOSCScript(QString filename)
virtual void documentModified()
Open a MIDI device and listen for MIDI input.
virtual ~RemovePaneCommand()
virtual void registerLastOpenedFilePath(FileFinder::FileType type, QString path)
virtual bool shouldCreateNewSessionForRDFAudio(bool *)
OSCQueueStarter * m_oscQueueStarter
void unexecute() override
virtual bool exportLayerToCSV(Layer *layer, LayerGeometryProvider *provider, MultiSelection *selectionsToWrite, QString delimiter, DataExportOptions options, QString toPath, QString &error)
MIDIMode
Determine whether to open a MIDI input device.
virtual void clearSelection()
virtual void monitoringLevelsChanged(float, float)=0
QLabel * getStatusLabel() const
RecentFiles m_recentFiles
virtual void paneRightButtonMenuRequested(Pane *, QPoint point)=0
RealTime m_defaultFfwdRwdStep
virtual void zoomDefault()
virtual void previousPane()
virtual void editCurrentLayer()
virtual void rewindSimilar()
virtual void preferenceChanged(PropertyContainer::PropertyName)
virtual void insertInstantAt(sv_frame_t)
void canSelectNextLayer(bool)
virtual void showNoOverlays()
virtual void currentPaneChanged(Pane *)
The base class for the SV main window.
virtual bool saveSessionFile(QString path)
virtual void panePropertiesRightButtonMenuRequested(Pane *, QPoint point)=0
virtual void documentRestored()
breakfastquay::SystemPlaybackTarget * m_playTarget
virtual void findTimeRulerLayer()
void canExportImage(bool)
virtual void layerInAView(Layer *, bool)
virtual void winnowInstantsBy(int)
void canSelectPreviousLayer(bool)
virtual void alignmentFailed(ModelId, QString)=0
sv_frame_t getFrame() const override
Implementation of FrameTimer interface method.
virtual void sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool)=0
void canSelectPreviousPane(bool)
virtual void layerPropertiesRightButtonMenuRequested(Pane *, Layer *, QPoint point)=0
virtual void playLoopToggled()
void addNonDerivedModel(ModelId)
Add an imported model, i.e.
Layer * createMainModelLayer(LayerFactory::LayerType)
Create and return a new layer of the given type, associated with the current main model (if appropria...
virtual void contextHelpChanged(const QString &)
SVFileReader loads Sonic Visualiser XML files.
virtual void modelAdded(ModelId)
virtual void audioChannelCountIncreased(int count)
virtual void paneDropAccepted(Pane *, QStringList)=0
virtual ~AddPaneCommand()
sv_frame_t getModelsStartFrame() const
QList< QShortcut * > m_appShortcuts
void removeLayerEditDialog(Layer *)
QString getName() const override
bool m_initialDarkBackground
virtual void updateDescriptionLabel()=0
void canImportLayer(bool)
virtual void layerAdded(Layer *)
void canEditSelection(bool)
virtual bool exportLayerToMIDI(Layer *layer, MultiSelection *selectionsToWrite, QString toPath, QString &error)
virtual void deleteCurrentPane()
virtual void viewZoomLevelChanged(View *, ZoomLevel, bool)
virtual FileOpenStatus openAudio(FileSource source, AudioFileOpenMode=AskUser, QString templateName="")
virtual void scrollRight()
void canImportMoreAudio(bool)
virtual void alignmentComplete(ModelId)
virtual QString getOpenFileName(FileFinder::FileType type)
virtual FileOpenStatus openPath(QString fileOrUrl, AudioFileOpenMode=AskUser)
virtual void insertInstant()
void canSubdivideInstants(bool)
breakfastquay::SystemAudioIO * m_audioIO
void canRenameLayer(bool)
void log(std::string message) const override
Open for playback, never for recording.
ModelId getMainModel()
Get the main model (the source for playback sample rate, etc).
virtual void deleteCurrentLayer()
virtual void selectVisible()
void canChangeSessionTemplate(bool)
virtual void togglePropertyBoxes()
virtual void updateVisibleRangeDisplay(Pane *p) const =0
Open for playback when model loaded, switch to I/O if record called.
virtual void emitHideSplash()
virtual bool checkSaveModified()=0
virtual void recordDurationChanged(sv_frame_t, sv_samplerate_t)
virtual void audioOverloadPluginDisabled()=0
virtual void paneDeleteButtonClicked(Pane *)
virtual void updatePositionStatusDisplays() const =0
AudioMode
Determine what kind of audio device to open when the first model is loaded or record() is called...
QString getName() const override
virtual void oscScriptFinished()
void toXmlAsTemplate(QTextStream &, QString indent, QString extraAttributes) const
virtual void modelGenerationFailed(QString, QString)=0
ModelId getMainModelId() const
static FileType identifyXmlFile(QString path)
FileOpenStatus addOpenedAudioModel(FileSource source, ModelId model, AudioFileOpenMode mode, QString templateName, bool registerSource)
virtual void ffwdSimilar()
void canEditLayerTabular(bool)
void canDeleteCurrentPane(bool)
void removeLayerFromView(View *, Layer *)
Remove the given layer from the given view.
virtual void scrollLeft()
virtual void updateWindowTitle()
virtual void toggleStatusBar()
Layer * createEmptyLayer(LayerFactory::LayerType)
Create and return a new layer of the given type, with an appropriate empty model. ...
virtual void paneAboutToBeDeleted(Pane *)=0
virtual bool exportLayerToRDF(Layer *layer, QString toPath, QString &error)
virtual void inProgressSelectionChanged()
Layer * getSnapLayer() const
QSignalMapper * m_menuShortcutMapper
virtual void layerRemoved(Layer *)
virtual void paneAdded(Pane *)=0
QString m_myStatusMessage
virtual void connectLayerEditDialog(ModelDataTableDialog *dialog)
std::shared_ptr< WaveFileModel > getMainModel() const
virtual void showMinimalOverlays()
virtual FileOpenStatus openLayer(FileSource source)
void canClearSelection(bool)
virtual void modelRegenerationFailed(QString, QString, QString)=0
virtual void updateMenuStates()
RemovePaneCommand(MainWindowBase *mw, Pane *pane)
virtual FileOpenStatus openSessionPath(QString fileOrUrl)
void toXml(QTextStream &, QString indent, QString extraAttributes) const override
virtual ~MainWindowBase()
virtual void modelRegenerationWarning(QString, QString, QString)=0
virtual QString getDefaultSessionTemplate() const
virtual void pasteAtPlaybackPosition()
virtual void showAllOverlays()
Open for I/O as soon as model loaded or record called.
virtual void currentLayerChanged(Pane *, Layer *)
virtual void viewCentreFrameChanged(View *, sv_frame_t)
void canReplaceMainAudio(bool)
virtual void setDefaultSessionTemplate(QString)
A Sonic Visualiser document consists of a set of data models, and also the visualisation layers used ...
bool isIncomplete() const
Return true if any external files (most obviously audio) failed to be found on load, so that the document is incomplete compared to its saved description.
virtual void paneHidden(Pane *)=0
virtual void mainModelChanged(ModelId)
void addLayerToView(View *, Layer *)
Add the given layer to the given view.
virtual void playSelectionToggled()
virtual void selectToStart()
virtual FileOpenStatus openPlaylist(FileSource source, AudioFileOpenMode=AskUser)
virtual void closeSession()=0
void startOSCQueue(bool withNetworkPort)
ViewDataDialogMap m_viewDataDialogMap
virtual FileOpenStatus openLayersFromRDF(FileSource source)
virtual void globalCentreFrameChanged(sv_frame_t)
virtual void previousLayer()
sv_frame_t getModelsEndFrame() const
void setAutoAlignment(bool on)
Specify whether models added via addImportedModel should be automatically aligned against the main mo...
virtual void finaliseMenu(QMenu *)
virtual void openLocalFolder(QString path)
virtual FileOpenStatus openDirOfAudio(QString dirPath)
virtual void insertInstantsAtBoundaries()
virtual void layerAboutToBeDeleted(Layer *)
Open no audio device, ever.
virtual void recreateAudioIO()
virtual FileOpenStatus openSessionFromRDF(FileSource source)
virtual void menuActionMapperInvoked(QObject *)
virtual void toggleTimeRulers()
virtual void deleteSelected()
virtual FileOpenStatus openImage(FileSource source)
AddPaneCommand(MainWindowBase *mw)
virtual void createAudioIO()
void canExportLayer(bool)
virtual void playbackFrameChanged(sv_frame_t)
void canInsertItemAtSelection(bool)
AudioRecordMode m_audioRecordMode
virtual bool exportLayerTo(Layer *layer, LayerGeometryProvider *provider, MultiSelection *selectionsToWrite, QString toPath, QString &error)
void canInsertInstantsAtBoundaries(bool)
virtual void resizeConstrained(QSize)
virtual void openHelpUrl(QString url)
void deleteLayer(Layer *, bool force=false)
Delete the given layer, and also its associated model if no longer used by any other layer...
virtual void toggleZoomWheels()
void canInsertInstant(bool)
virtual FileOpenStatus openSessionTemplate(QString templateName)
virtual void pasteRelative(sv_frame_t offset)
virtual void selectToEnd()
virtual void finaliseMenus()
void canRenumberInstants(bool)
MainWindowBase(AudioMode audioMode, MIDIMode midiMode, PaneStack::Options paneStackOptions)
bool m_iconsVisibleInMenus
virtual bool exportLayerToSVL(Layer *layer, QString toPath, QString &error)
!! should we pull out the whole export logic into another
void canWinnowInstants(bool)
LayerDataDialogMap m_layerDataDialogMap
QString m_originalLocation
void canPlaySelection(bool)
virtual void insertItemAt(sv_frame_t, sv_frame_t)
virtual bool saveSessionTemplate(QString path)
virtual void deleteAudioIO()
virtual void insertItemAtSelection()
void canExportAudio(bool)
Layer * createImportedLayer(ModelId)
Create and return a new layer associated with the given model, and register the model as an imported ...
virtual void setupMenus()=0
virtual void renumberInstants()
virtual void rewindStart()
virtual FileOpenStatus openSession(FileSource source)
virtual void toggleCentreLine()
void canDeleteCurrentLayer(bool)
void unexecute() override
AudioCallbackPlaySource * m_playSource
virtual void subdivideInstantsBy(int)
ViewManager * m_viewManager
virtual FileOpenStatus open(FileSource source, AudioFileOpenMode=AskUser)