SVFileReader.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006 Chris Cannam and QMUL.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #include "SVFileReader.h"
17 
18 #include "layer/Layer.h"
19 #include "view/View.h"
20 #include "base/PlayParameters.h"
21 #include "base/PlayParameterRepository.h"
22 #include "base/Preferences.h"
23 
24 #include "data/fileio/AudioFileReaderFactory.h"
25 #include "data/fileio/FileSource.h"
26 
27 #include "data/fileio/FileFinder.h"
28 
29 #include "data/model/ReadOnlyWaveFileModel.h"
30 #include "data/model/EditableDenseThreeDimensionalModel.h"
31 #include "data/model/SparseOneDimensionalModel.h"
32 #include "data/model/SparseTimeValueModel.h"
33 #include "data/model/NoteModel.h"
34 #include "data/model/RegionModel.h"
35 #include "data/model/TextModel.h"
36 #include "data/model/ImageModel.h"
37 #include "data/model/BoxModel.h"
38 #include "data/model/AlignmentModel.h"
39 #include "data/model/AggregateWaveModel.h"
40 
41 #include "transform/TransformFactory.h"
42 
43 #include "view/Pane.h"
44 
45 #include "widgets/ProgressDialog.h"
46 
47 #include "Document.h"
48 
49 #include <QString>
50 #include <QMessageBox>
51 #include <QFileDialog>
52 
53 #include <iostream>
54 
56  SVFileReaderPaneCallback &callback,
57  QString location) :
58  m_document(document),
59  m_paneCallback(callback),
60  m_location(location),
61  m_currentPane(nullptr),
62  m_currentDataset(XmlExportable::NO_ID),
63  m_currentLayer(nullptr),
64  m_pendingDerivedModel(XmlExportable::NO_ID),
65  m_currentTransformChannel(0),
66  m_currentTransformIsNewStyle(true),
67  m_datasetSeparator(" "),
68  m_inRow(false),
69  m_inLayer(false),
70  m_inView(false),
71  m_inData(false),
72  m_inSelections(false),
73  m_rowNumber(0),
74  m_ok(false)
75 {
76 }
77 
78 void
79 SVFileReader::parse(const QString &xmlData)
80 {
81  QXmlInputSource inputSource;
82  inputSource.setData(xmlData);
83  parse(inputSource);
84 }
85 
86 void
87 SVFileReader::parse(QXmlInputSource &inputSource)
88 {
89  QXmlSimpleReader reader;
90  reader.setContentHandler(this);
91  reader.setErrorHandler(this);
92  m_ok = reader.parse(inputSource);
93 }
94 
95 bool
97 {
98  return m_ok;
99 }
100 
102 {
103  if (!m_awaitingDatasets.empty()) {
104  SVCERR << "WARNING: SV-XML: File ended with "
105  << m_awaitingDatasets.size() << " unfilled model dataset(s)"
106  << endl;
107  }
108 
109  std::set<ModelId> unaddedModels;
110 
111  for (auto i: m_models) {
112  if (m_addedModels.find(i.second) == m_addedModels.end()) {
113  unaddedModels.insert(i.second);
114  }
115  }
116 
117  if (!unaddedModels.empty()) {
118  SVCERR << "WARNING: SV-XML: File contained "
119  << unaddedModels.size() << " unused models"
120  << endl;
121  for (auto m: unaddedModels) {
122  ModelById::release(m);
123  }
124  }
125 
126  if (!m_paths.empty()) {
127  SVCERR << "WARNING: SV-XML: File contained "
128  << m_paths.size() << " unused paths"
129  << endl;
130  for (auto p: m_paths) {
131  delete p.second;
132  }
133  }
134 }
135 
136 bool
137 SVFileReader::startElement(const QString &, const QString &,
138  const QString &qName,
139  const QXmlAttributes &attributes)
140 {
141  QString name = qName.toLower();
142 
143  bool ok = false;
144 
145  // Valid element names:
146  //
147  // sv
148  // data
149  // dataset
150  // display
151  // derivation
152  // playparameters
153  // layer
154  // model
155  // point
156  // row
157  // view
158  // window
159  // plugin
160  // transform
161  // selections
162  // selection
163  // measurement
164 
165  if (name == "sv") {
166 
167  // nothing needed
168  ok = true;
169 
170  } else if (name == "data") {
171 
172  // nothing needed
173  m_inData = true;
174  ok = true;
175 
176  } else if (name == "display") {
177 
178  // nothing needed
179  ok = true;
180 
181  } else if (name == "window") {
182 
183  ok = readWindow(attributes);
184 
185  } else if (name == "model") {
186 
187  ok = readModel(attributes);
188 
189  } else if (name == "dataset") {
190 
191  ok = readDatasetStart(attributes);
192 
193  } else if (name == "bin") {
194 
195  ok = addBinToDataset(attributes);
196 
197  } else if (name == "point") {
198 
199  ok = addPointToDataset(attributes);
200 
201  } else if (name == "row") {
202 
203  ok = addRowToDataset(attributes);
204 
205  } else if (name == "layer") {
206 
207  addUnaddedModels(); // all models must be specified before first layer
208  ok = readLayer(attributes);
209 
210  } else if (name == "view") {
211 
212  m_inView = true;
213  ok = readView(attributes);
214 
215  } else if (name == "derivation") {
216 
217  makeAggregateModels(); // must be done before derivations that use them
218  ok = readDerivation(attributes);
219 
220  } else if (name == "playparameters") {
221 
222  ok = readPlayParameters(attributes);
223 
224  } else if (name == "plugin") {
225 
226  ok = readPlugin(attributes);
227 
228  } else if (name == "selections") {
229 
230  m_inSelections = true;
231  ok = true;
232 
233  } else if (name == "selection") {
234 
235  ok = readSelection(attributes);
236 
237  } else if (name == "measurement") {
238 
239  ok = readMeasurement(attributes);
240 
241  } else if (name == "transform") {
242 
243  ok = readTransform(attributes);
244 
245  } else if (name == "parameter") {
246 
247  ok = readParameter(attributes);
248 
249  } else {
250  SVCERR << "WARNING: SV-XML: Unexpected element \""
251  << name << "\"" << endl;
252  }
253 
254  if (!ok) {
255  SVCERR << "WARNING: SV-XML: Failed to completely process element \""
256  << name << "\"" << endl;
257  }
258 
259  return true;
260 }
261 
262 bool
263 SVFileReader::characters(const QString &text)
264 {
265  bool ok = false;
266 
267  if (m_inRow) {
268  ok = readRowData(text);
269  if (!ok) {
270  SVCERR << "WARNING: SV-XML: Failed to read row data content for row " << m_rowNumber << endl;
271  }
272  }
273 
274  return true;
275 }
276 
277 bool
278 SVFileReader::endElement(const QString &, const QString &,
279  const QString &qName)
280 {
281  QString name = qName.toLower();
282 
283  if (name == "dataset") {
284 
285  if (m_currentDataset != XmlExportable::NO_ID) {
286 
287  bool foundInAwaiting = false;
288 
289  for (auto i: m_awaitingDatasets) {
290  if (i.second == m_currentDataset) {
291  m_awaitingDatasets.erase(i.first);
292  foundInAwaiting = true;
293  break;
294  }
295  }
296 
297  if (!foundInAwaiting) {
298  SVCERR << "WARNING: SV-XML: Dataset precedes model, or no model uses dataset" << endl;
299  }
300  }
301 
302  m_currentDataset = XmlExportable::NO_ID;
303 
304  } else if (name == "data") {
305 
307  m_inData = false;
308 
309  } else if (name == "derivation") {
310 
311  if (m_currentDerivedModel.isNone()) {
312  if (m_pendingDerivedModel == XmlExportable::NO_ID) {
313  SVCERR << "WARNING: SV-XML: No valid output model id "
314  << "for derivation" << endl;
315  } else if (haveModel(m_pendingDerivedModel)) {
316  SVCERR << "WARNING: SV-XML: Derivation has existing model "
318  << " as target, not regenerating" << endl;
319  } else {
320  QString message;
324  ModelTransformer::Input(m_currentTransformSource,
326  message);
327  if (m_currentDerivedModel.isNone()) {
328  emit modelRegenerationFailed(tr("(derived model in SV-XML)"),
329  m_currentTransform.getIdentifier(),
330  message);
331  } else if (message != "") {
332  emit modelRegenerationWarning(tr("(derived model in SV-XML)"),
333  m_currentTransform.getIdentifier(),
334  message);
335  }
336  }
337  } else {
340  ModelTransformer::Input(m_currentTransformSource,
343  }
344 
347  m_pendingDerivedModel = XmlExportable::NO_ID;
349  m_currentTransform = Transform();
351 
352  } else if (name == "row") {
353  m_inRow = false;
354  } else if (name == "layer") {
355  m_inLayer = false;
356  } else if (name == "view") {
357  m_inView = false;
358  } else if (name == "selections") {
359  m_inSelections = false;
360  } else if (name == "playparameters") {
362  }
363 
364  return true;
365 }
366 
367 bool
368 SVFileReader::error(const QXmlParseException &exception)
369 {
370  m_errorString =
371  QString("ERROR: SV-XML: %1 at line %2, column %3")
372  .arg(exception.message())
373  .arg(exception.lineNumber())
374  .arg(exception.columnNumber());
375  SVCERR << m_errorString << endl;
376  return QXmlDefaultHandler::error(exception);
377 }
378 
379 bool
380 SVFileReader::fatalError(const QXmlParseException &exception)
381 {
382  m_errorString =
383  QString("FATAL ERROR: SV-XML: %1 at line %2, column %3")
384  .arg(exception.message())
385  .arg(exception.lineNumber())
386  .arg(exception.columnNumber());
387  SVCERR << m_errorString << endl;
388  return QXmlDefaultHandler::fatalError(exception);
389 }
390 
391 
392 #define READ_MANDATORY(TYPE, NAME, CONVERSION) \
393  TYPE NAME = attributes.value(#NAME).trimmed().CONVERSION(&ok); \
394  if (!ok) { \
395  SVCERR << "WARNING: SV-XML: Missing or invalid mandatory " #TYPE " attribute \"" #NAME "\"" << endl; \
396  return false; \
397  }
398 
399 bool
400 SVFileReader::readWindow(const QXmlAttributes &)
401 {
402  // The window element contains window dimensions, which we used to
403  // read and size the window accordingly. This was a Bad Idea [tm]
404  // and we now do nothing instead. See #1769 Loading window
405  // dimensions from session file is a really bad idea
406  return true;
407 }
408 
409 void
411 {
412  std::map<ExportId, PendingAggregateRec> stillPending;
413 
414  for (auto p: m_pendingAggregates) {
415 
416  int id = p.first;
417  const PendingAggregateRec &rec = p.second;
418  bool skip = false;
419 
420  AggregateWaveModel::ChannelSpecList specs;
421  for (ExportId componentId: rec.components) {
422  bool found = false;
423  if (m_models.find(componentId) != m_models.end()) {
424  ModelId modelId = m_models[componentId];
425  auto rs = ModelById::getAs<RangeSummarisableTimeValueModel>
426  (modelId);
427  if (rs) {
428  specs.push_back(AggregateWaveModel::ModelChannelSpec
429  (modelId, -1));
430  found = true;
431  } else {
432  SVDEBUG << "SVFileReader::makeAggregateModels: "
433  << "Component model id " << componentId
434  << "in aggregate model id " << id
435  << "does not appear to be convertible to "
436  << "RangeSummarisableTimeValueModel"
437  << endl;
438  }
439  }
440  if (!found) {
441  SVDEBUG << "SVFileReader::makeAggregateModels: "
442  << "Unknown component model id "
443  << componentId << " in aggregate model id " << id
444  << ", hoping we won't be needing it just yet"
445  << endl;
446  skip = true;
447  }
448  }
449 
450  if (skip) {
451  stillPending[id] = rec;
452  } else {
453  auto model = std::make_shared<AggregateWaveModel>(specs);
454  model->setObjectName(rec.name);
455  m_models[id] = ModelById::add(model);
456 
457  SVDEBUG << "SVFileReader::makeAggregateModels: created aggregate "
458  << "model id " << id << " with " << specs.size()
459  << " components" << endl;
460  }
461  }
462 
463  m_pendingAggregates = stillPending;
464 }
465 
466 void
468 {
470 
471  for (auto i: m_models) {
472 
473  ModelId modelId = i.second;
474 
475  if (m_addedModels.find(modelId) != m_addedModels.end()) {
476  // already added this one
477  continue;
478  }
479 
480  m_document->addNonDerivedModel(modelId);
481 
482  // make a note of all models that have been added to the
483  // document, so they don't get released by our own destructor
484  m_addedModels.insert(modelId);
485  }
486 }
487 
488 bool
489 SVFileReader::readModel(const QXmlAttributes &attributes)
490 {
491  bool ok = false;
492 
493  READ_MANDATORY(int, id, toInt);
494 
495  if (haveModel(id)) {
496  SVCERR << "WARNING: SV-XML: Ignoring duplicate model id " << id
497  << endl;
498  return false;
499  }
500 
501  QString name = attributes.value("name");
502 
503  SVDEBUG << "SVFileReader::readModel: model name \"" << name << "\"" << endl;
504 
505  READ_MANDATORY(double, sampleRate, toDouble);
506 
507  QString type = attributes.value("type").trimmed();
508  bool isMainModel = (attributes.value("mainModel").trimmed() == "true");
509 
510  if (type == "wavefile") {
511 
512  WaveFileModel *model = nullptr;
513  FileFinder *ff = FileFinder::getInstance();
514  QString originalPath = attributes.value("file");
515  QString path = ff->find(FileFinder::AudioFile,
516  originalPath, m_location);
517 
518  SVDEBUG << "Wave file originalPath = " << originalPath << ", path = "
519  << path << endl;
520 
521  ProgressDialog dialog(tr("Opening file or URL..."), true, 2000);
522  FileSource file(path, &dialog);
523  file.waitForStatus();
524 
525  if (!file.isOK()) {
526  SVCERR << "SVFileReader::readModel: Failed to retrieve file \"" << path << "\" for wave file model: " << file.getErrorString() << endl;
527  } else if (!file.isAvailable()) {
528  SVCERR << "SVFileReader::readModel: Failed to retrieve file \"" << path << "\" for wave file model: Source unavailable" << endl;
529  } else {
530 
531  file.waitForData();
532 
533  sv_samplerate_t rate = sampleRate;
534 
535  if (Preferences::getInstance()->getFixedSampleRate() != 0) {
536  rate = Preferences::getInstance()->getFixedSampleRate();
537  } else if (rate == 0 &&
538  !isMainModel &&
539  Preferences::getInstance()->getResampleOnLoad()) {
540  auto mm = ModelById::getAs<WaveFileModel>
542  if (mm) rate = mm->getSampleRate();
543  }
544 
545  model = new ReadOnlyWaveFileModel(file, rate);
546  if (!model->isOK()) {
547  delete model;
548  model = nullptr;
549  }
550  }
551 
552  if (!model) {
553  m_document->setIncomplete(true);
554  return false;
555  }
556 
557  model->setObjectName(name);
558 
559  ModelId modelId = ModelById::add(std::shared_ptr<Model>(model));
560  m_models[id] = modelId;
561 
562  if (isMainModel) {
563  m_document->setMainModel(modelId);
564  m_addedModels.insert(modelId);
565  }
566  // Derived models will be added when their derivation
567  // is found.
568 
569  return true;
570 
571  } else if (type == "aggregatewave") {
572 
573  QString components = attributes.value("components");
574  QStringList componentIdStrings = components.split(",");
575  std::vector<int> componentIds;
576  for (auto cidStr: componentIdStrings) {
577  bool ok = false;
578  int cid = cidStr.toInt(&ok);
579  if (!ok) {
580  SVCERR << "SVFileReader::readModel: Failed to convert component model id from part \"" << cidStr << "\" in \"" << components << "\"" << endl;
581  } else {
582  componentIds.push_back(cid);
583  }
584  }
585  PendingAggregateRec rec { name, sampleRate, componentIds };
586  m_pendingAggregates[id] = rec;
587 
588  // The aggregate model will be constructed from its pending
589  // record in makeAggregateModels; it can't happen here because
590  // the component models might not all have been observed yet
591  // (an unfortunate accident of the way the file is written)
592 
593  return true;
594 
595  } else if (type == "dense") {
596 
597  READ_MANDATORY(int, dimensions, toInt);
598 
599  // Currently the only dense model we support here is the dense
600  // 3d model. Dense time-value models are always file-backed
601  // waveform data, at this point, and they come in as wavefile
602  // models.
603 
604  if (dimensions == 3) {
605 
606  READ_MANDATORY(int, windowSize, toInt);
607  READ_MANDATORY(int, yBinCount, toInt);
608 
609  auto model = std::make_shared<EditableDenseThreeDimensionalModel>
610  (sampleRate, windowSize, yBinCount);
611 
612  model->setObjectName(name);
613  m_models[id] = ModelById::add(model);
614 
615  float minimum = attributes.value("minimum").trimmed().toFloat(&ok);
616  if (ok) model->setMinimumLevel(minimum);
617 
618  float maximum = attributes.value("maximum").trimmed().toFloat(&ok);
619  if (ok) model->setMaximumLevel(maximum);
620 
621  int dataset = attributes.value("dataset").trimmed().toInt(&ok);
622  if (ok) m_awaitingDatasets[dataset] = id;
623 
624  int startFrame = attributes.value("startFrame").trimmed().toInt(&ok);
625  if (ok) model->setStartFrame(startFrame);
626 
627  return true;
628 
629  } else {
630 
631  SVCERR << "WARNING: SV-XML: Unexpected dense model dimension ("
632  << dimensions << ")" << endl;
633  }
634  } else if (type == "sparse") {
635 
636  READ_MANDATORY(int, dimensions, toInt);
637 
638  if (dimensions == 1) {
639 
640  READ_MANDATORY(int, resolution, toInt);
641 
642  if (attributes.value("subtype") == "image") {
643 
644  bool notifyOnAdd = (attributes.value("notifyOnAdd") == "true");
645  auto model = std::make_shared<ImageModel>
646  (sampleRate, resolution, notifyOnAdd);
647  model->setObjectName(name);
648  m_models[id] = ModelById::add(model);
649 
650  } else {
651 
652  auto model = std::make_shared<SparseOneDimensionalModel>
653  (sampleRate, resolution);
654  model->setObjectName(name);
655  m_models[id] = ModelById::add(model);
656  }
657 
658  int dataset = attributes.value("dataset").trimmed().toInt(&ok);
659  if (ok) m_awaitingDatasets[dataset] = id;
660 
661  return true;
662 
663  } else if (dimensions == 2 || dimensions == 3) {
664 
665  READ_MANDATORY(int, resolution, toInt);
666 
667  bool haveMinMax = true;
668  float minimum = attributes.value("minimum").trimmed().toFloat(&ok);
669  if (!ok) haveMinMax = false;
670  float maximum = attributes.value("maximum").trimmed().toFloat(&ok);
671  if (!ok) haveMinMax = false;
672 
673  float valueQuantization =
674  attributes.value("valueQuantization").trimmed().toFloat(&ok);
675 
676  bool notifyOnAdd = (attributes.value("notifyOnAdd") == "true");
677 
678  QString units = attributes.value("units");
679 
680  if (dimensions == 2) {
681  if (attributes.value("subtype") == "text") {
682  auto model = std::make_shared<TextModel>
683  (sampleRate, resolution, notifyOnAdd);
684  model->setObjectName(name);
685  m_models[id] = ModelById::add(model);
686  } else if (attributes.value("subtype") == "path") {
687  // Paths are no longer actually models
688  Path *path = new Path(sampleRate, resolution);
689  m_paths[id] = path;
690  } else if (attributes.value("subtype") == "box" ||
691  attributes.value("subtype") == "timefrequencybox") {
692  auto model = std::make_shared<BoxModel>
693  (sampleRate, resolution, notifyOnAdd);
694  model->setScaleUnits(units);
695  model->setObjectName(name);
696  m_models[id] = ModelById::add(model);
697  } else {
698  std::shared_ptr<SparseTimeValueModel> model;
699  if (haveMinMax) {
700  model = std::make_shared<SparseTimeValueModel>
701  (sampleRate, resolution, minimum, maximum,
702  notifyOnAdd);
703  } else {
704  model = std::make_shared<SparseTimeValueModel>
705  (sampleRate, resolution, notifyOnAdd);
706  }
707  model->setScaleUnits(units);
708  model->setObjectName(name);
709  m_models[id] = ModelById::add(model);
710  }
711  } else {
712  if (attributes.value("subtype") == "region") {
713  std::shared_ptr<RegionModel> model;
714  if (haveMinMax) {
715  model = std::make_shared<RegionModel>
716  (sampleRate, resolution, minimum, maximum,
717  notifyOnAdd);
718  } else {
719  model = std::make_shared<RegionModel>
720  (sampleRate, resolution, notifyOnAdd);
721  }
722  model->setValueQuantization(valueQuantization);
723  model->setScaleUnits(units);
724  model->setObjectName(name);
725  m_models[id] = ModelById::add(model);
726  } else if (attributes.value("subtype") == "flexinote") {
727  std::shared_ptr<NoteModel> model;
728  if (haveMinMax) {
729  model = std::make_shared<NoteModel>
730  (sampleRate, resolution, minimum, maximum,
731  notifyOnAdd,
732  NoteModel::FLEXI_NOTE);
733  } else {
734  model = std::make_shared<NoteModel>
735  (sampleRate, resolution, notifyOnAdd,
736  NoteModel::FLEXI_NOTE);
737  }
738  model->setValueQuantization(valueQuantization);
739  model->setScaleUnits(units);
740  model->setObjectName(name);
741  m_models[id] = ModelById::add(model);
742  } else {
743  // note models written out by SV 1.3 and earlier
744  // have no subtype, so we can't test that
745  std::shared_ptr<NoteModel> model;
746  if (haveMinMax) {
747  model = std::make_shared<NoteModel>
748  (sampleRate, resolution, minimum, maximum, notifyOnAdd);
749  } else {
750  model = std::make_shared<NoteModel>
751  (sampleRate, resolution, notifyOnAdd);
752  }
753  model->setValueQuantization(valueQuantization);
754  model->setScaleUnits(units);
755  model->setObjectName(name);
756  m_models[id] = ModelById::add(model);
757  }
758  }
759 
760  int dataset = attributes.value("dataset").trimmed().toInt(&ok);
761  if (ok) m_awaitingDatasets[dataset] = id;
762 
763  return true;
764 
765  } else {
766 
767  SVCERR << "WARNING: SV-XML: Unexpected sparse model dimension ("
768  << dimensions << ")" << endl;
769  }
770 
771  } else if (type == "alignment") {
772 
773  READ_MANDATORY(int, reference, toInt);
774  READ_MANDATORY(int, aligned, toInt);
775  READ_MANDATORY(int, path, toInt);
776 
777  ModelId refModel, alignedModel;
778  Path *pathPtr = nullptr;
779 
780  if (m_models.find(reference) != m_models.end()) {
781  refModel = m_models[reference];
782  } else {
783  SVCERR << "WARNING: SV-XML: Unknown reference model id "
784  << reference << " in alignment model id " << id
785  << endl;
786  }
787 
788  if (m_models.find(aligned) != m_models.end()) {
789  alignedModel = m_models[aligned];
790  } else {
791  SVCERR << "WARNING: SV-XML: Unknown aligned model id "
792  << aligned << " in alignment model id " << id
793  << endl;
794  }
795 
796  if (m_paths.find(path) != m_paths.end()) {
797  pathPtr = m_paths[path];
798  } else {
799  SVCERR << "WARNING: SV-XML: Unknown path id "
800  << path << " in alignment model id " << id
801  << endl;
802  }
803 
804  if (!refModel.isNone() && !alignedModel.isNone() && pathPtr) {
805  auto model = std::make_shared<AlignmentModel>
806  (refModel, alignedModel, ModelId());
807  model->setPath(*pathPtr);
808  model->setObjectName(name);
809  m_models[id] = ModelById::add(model);
810  if (auto am = ModelById::get(alignedModel)) {
811  am->setAlignment(m_models[id]);
812  }
813  return true;
814  }
815 
816  if (pathPtr) {
817  delete pathPtr;
818  m_paths.erase(path);
819  }
820 
821  } else {
822 
823  SVCERR << "WARNING: SV-XML: Unexpected model type \""
824  << type << "\" for model id " << id << endl;
825  }
826 
827  return false;
828 }
829 
830 bool
831 SVFileReader::readView(const QXmlAttributes &attributes)
832 {
833  QString type = attributes.value("type");
834  m_currentPane = nullptr;
835 
836  if (type != "pane") {
837  SVCERR << "WARNING: SV-XML: Unexpected view type \""
838  << type << "\"" << endl;
839  return false;
840  }
841 
843 
844  SVDEBUG << "SVFileReader::addPane: pane is " << m_currentPane << endl;
845 
846  if (!m_currentPane) {
847  SVCERR << "WARNING: SV-XML: Internal error: Failed to add pane!"
848  << endl;
849  return false;
850  }
851 
852  bool ok = false;
853 
854  View *view = m_currentPane;
855 
856  // The view properties first
857 
858  READ_MANDATORY(int, centre, toInt);
859  READ_MANDATORY(int, zoom, toInt);
860  READ_MANDATORY(int, followPan, toInt);
861  READ_MANDATORY(int, followZoom, toInt);
862  QString tracking = attributes.value("tracking");
863 
864  ZoomLevel zoomLevel;
865  int deepZoom = attributes.value("deepZoom").trimmed().toInt(&ok);
866  if (ok && zoom == 1 && deepZoom > 1) {
867  zoomLevel = { ZoomLevel::PixelsPerFrame, deepZoom };
868  } else {
869  zoomLevel = { ZoomLevel::FramesPerPixel, zoom };
870  }
871 
872  // Specify the follow modes before we set the actual values
873  view->setFollowGlobalPan(followPan);
874  view->setFollowGlobalZoom(followZoom);
875  view->setPlaybackFollow(tracking == "scroll" ? PlaybackScrollContinuous :
876  tracking == "page" ? PlaybackScrollPageWithCentre :
877  tracking == "daw" ? PlaybackScrollPage
878  : PlaybackIgnore);
879 
880  // Then set these values
881  view->setCentreFrame(centre);
882  view->setZoomLevel(zoomLevel);
883 
884  // And pane properties
885  READ_MANDATORY(int, centreLineVisible, toInt);
886  m_currentPane->setCentreLineVisible(centreLineVisible);
887 
888  int height = attributes.value("height").toInt(&ok);
889  if (ok) {
890  m_currentPane->resize(m_currentPane->width(), height);
891  }
892 
893  return true;
894 }
895 
896 bool
897 SVFileReader::readLayer(const QXmlAttributes &attributes)
898 {
899  QString type = attributes.value("type");
900 
901  int id;
902  bool ok = false;
903  id = attributes.value("id").trimmed().toInt(&ok);
904 
905  if (!ok) {
906  SVCERR << "WARNING: SV-XML: No layer id for layer of type \""
907  << type
908  << "\"" << endl;
909  return false;
910  }
911 
912  Layer *layer = nullptr;
913  bool isNewLayer = false;
914 
915  // Layers are expected to be defined in layer elements in the data
916  // section, and referred to in layer elements in the view
917  // sections. So if we're in the data section, we expect this
918  // layer not to exist already; if we're in the view section, we
919  // expect it to exist.
920 
921  if (m_inData) {
922 
923  if (m_layers.find(id) != m_layers.end()) {
924  SVCERR << "WARNING: SV-XML: Ignoring duplicate layer id " << id
925  << " in data section" << endl;
926  return false;
927  }
928 
929  layer = m_layers[id] = m_document->createLayer
930  (LayerFactory::getInstance()->getLayerTypeForName(type));
931 
932  if (layer) {
933  m_layers[id] = layer;
934  isNewLayer = true;
935  }
936 
937  } else {
938 
939  if (!m_currentPane) {
940  SVCERR << "WARNING: SV-XML: No current pane for layer " << id
941  << " in view section" << endl;
942  return false;
943  }
944 
945  if (m_layers.find(id) != m_layers.end()) {
946 
947  layer = m_layers[id];
948 
949  } else {
950  SVCERR << "WARNING: SV-XML: Layer id " << id
951  << " in view section has not been defined -- defining it here"
952  << endl;
953 
954  layer = m_document->createLayer
955  (LayerFactory::getInstance()->getLayerTypeForName(type));
956 
957  if (layer) {
958  m_layers[id] = layer;
959  isNewLayer = true;
960  }
961  }
962  }
963 
964  if (!layer) {
965  SVCERR << "WARNING: SV-XML: Failed to add layer of type \""
966  << type
967  << "\"" << endl;
968  return false;
969  }
970 
971  if (isNewLayer) {
972 
973  QString name = attributes.value("name");
974  layer->setObjectName(name);
975 
976  QString presentationName = attributes.value("presentationName");
977  layer->setPresentationName(presentationName);
978 
979  int modelId;
980  bool modelOk = false;
981  modelId = attributes.value("model").trimmed().toInt(&modelOk);
982 
983  if (modelOk) {
984  if (haveModel(modelId)) {
985  m_document->setModel(layer, m_models[modelId]);
986  } else {
987  SVCERR << "WARNING: SV-XML: Unknown model id " << modelId
988  << " in layer definition" << endl;
989  if (!layer->canExistWithoutModel()) {
990  // Don't add a layer with an unknown model id
991  // unless it explicitly supports this state
992  m_document->deleteLayer(layer);
993  m_layers[id] = layer = nullptr;
994  return false;
995  }
996  }
997  }
998 
999  if (layer) layer->setProperties(attributes);
1000  }
1001 
1002  if (!m_inData && m_currentPane && layer) {
1003 
1004  QString visible = attributes.value("visible");
1005  bool dormant = (visible == "false");
1006 
1007  // We need to do this both before and after adding the layer
1008  // to the view -- we need it to be dormant if appropriate
1009  // before it's actually added to the view so that any property
1010  // box gets the right state when it's added, but the add layer
1011  // command sets dormant to false because it assumes it may be
1012  // restoring a previously dormant layer, so we need to set it
1013  // again afterwards too. Hm
1014  layer->setLayerDormant(m_currentPane, dormant);
1015 
1017 
1018  layer->setLayerDormant(m_currentPane, dormant);
1019  }
1020 
1021  m_currentLayer = layer;
1022  m_inLayer = (layer != nullptr);
1023 
1024  return true;
1025 }
1026 
1027 bool
1028 SVFileReader::readDatasetStart(const QXmlAttributes &attributes)
1029 {
1030  bool ok = false;
1031 
1032  READ_MANDATORY(int, id, toInt);
1033  READ_MANDATORY(int, dimensions, toInt);
1034 
1035  if (m_awaitingDatasets.find(id) == m_awaitingDatasets.end()) {
1036  SVCERR << "WARNING: SV-XML: Unwanted dataset " << id << endl;
1037  return false;
1038  }
1039 
1040  int awaitingId = m_awaitingDatasets[id];
1041 
1042  ModelId modelId;
1043  Path *path = nullptr;
1044 
1045  if (haveModel(awaitingId)) {
1046  modelId = m_models[awaitingId];
1047  } else if (m_paths.find(awaitingId) != m_paths.end()) {
1048  path = m_paths[awaitingId];
1049  } else {
1050  SVCERR << "WARNING: SV-XML: Internal error: Unknown model or path "
1051  << modelId << " awaiting dataset " << id << endl;
1052  return false;
1053  }
1054 
1055  bool good = false;
1056 
1057  switch (dimensions) {
1058  case 1:
1059  good =
1060  (ModelById::isa<SparseOneDimensionalModel>(modelId) ||
1061  ModelById::isa<ImageModel>(modelId));
1062  break;
1063 
1064  case 2:
1065  good =
1066  (ModelById::isa<SparseTimeValueModel>(modelId) ||
1067  ModelById::isa<TextModel>(modelId) ||
1068  ModelById::isa<BoxModel>(modelId) ||
1069  path);
1070  break;
1071 
1072  case 3:
1073  if (ModelById::isa<EditableDenseThreeDimensionalModel>(modelId)) {
1074  good = true;
1075  m_datasetSeparator = attributes.value("separator");
1076  } else {
1077  good =
1078  (ModelById::isa<NoteModel>(modelId) ||
1079  ModelById::isa<RegionModel>(modelId));
1080  }
1081  break;
1082  }
1083 
1084  if (!good) {
1085  SVCERR << "WARNING: SV-XML: Model id " << modelId << " has wrong number of dimensions or inappropriate type for " << dimensions << "-D dataset " << id << endl;
1086  m_currentDataset = XmlExportable::NO_ID;
1087  return false;
1088  }
1089 
1090  m_currentDataset = awaitingId;
1091  return true;
1092 }
1093 
1094 bool
1095 SVFileReader::addPointToDataset(const QXmlAttributes &attributes)
1096 {
1097  bool ok = false;
1098 
1099  READ_MANDATORY(int, frame, toInt);
1100 
1101  if (m_paths.find(m_currentDataset) != m_paths.end()) {
1102  Path *path = m_paths[m_currentDataset];
1103  int mapframe = attributes.value("mapframe").trimmed().toInt(&ok);
1104  path->add(PathPoint(frame, mapframe));
1105  return ok;
1106  }
1107 
1108  if (!haveModel(m_currentDataset)) {
1109  SVCERR << "WARNING: SV-XML: Point element found in non-point dataset"
1110  << endl;
1111  return false;
1112  }
1113 
1114  ModelId modelId = m_models[m_currentDataset];
1115 
1116  if (auto sodm = ModelById::getAs<SparseOneDimensionalModel>(modelId)) {
1117  QString label = attributes.value("label");
1118  sodm->add(Event(frame, label));
1119  return true;
1120  }
1121 
1122  if (auto stvm = ModelById::getAs<SparseTimeValueModel>(modelId)) {
1123  float value = attributes.value("value").trimmed().toFloat(&ok);
1124  QString label = attributes.value("label");
1125  stvm->add(Event(frame, value, label));
1126  return ok;
1127  }
1128 
1129  if (auto nm = ModelById::getAs<NoteModel>(modelId)) {
1130  float value = attributes.value("value").trimmed().toFloat(&ok);
1131  int duration = attributes.value("duration").trimmed().toInt(&ok);
1132  QString label = attributes.value("label");
1133  float level = attributes.value("level").trimmed().toFloat(&ok);
1134  if (!ok) { // level is optional
1135  level = 1.f;
1136  ok = true;
1137  }
1138  nm->add(Event(frame, value, duration, level, label));
1139  return ok;
1140  }
1141 
1142  if (auto rm = ModelById::getAs<RegionModel>(modelId)) {
1143  float value = attributes.value("value").trimmed().toFloat(&ok);
1144  int duration = attributes.value("duration").trimmed().toInt(&ok);
1145  QString label = attributes.value("label");
1146  rm->add(Event(frame, value, duration, label));
1147  return ok;
1148  }
1149 
1150  if (auto tm = ModelById::getAs<TextModel>(modelId)) {
1151  float height = attributes.value("height").trimmed().toFloat(&ok);
1152  QString label = attributes.value("label");
1153  tm->add(Event(frame, height, label));
1154  return ok;
1155  }
1156 
1157  if (auto bm = ModelById::getAs<BoxModel>(modelId)) {
1158  float value = attributes.value("value").trimmed().toFloat(&ok);
1159  if (!ok) {
1160  value = attributes.value("frequency").trimmed().toFloat(&ok);
1161  if (bm->getScaleUnits() == "") {
1162  bm->setScaleUnits("Hz");
1163  }
1164  }
1165  float extent = attributes.value("extent").trimmed().toFloat(&ok);
1166  int duration = attributes.value("duration").trimmed().toInt(&ok);
1167  QString label = attributes.value("label");
1168  bm->add(Event(frame, value, duration, extent, label));
1169  return ok;
1170  }
1171 
1172  if (auto im = ModelById::getAs<ImageModel>(modelId)) {
1173  QString image = attributes.value("image");
1174  QString label = attributes.value("label");
1175  im->add(Event(frame).withURI(image).withLabel(label));
1176  return ok;
1177  }
1178 
1179  SVCERR << "WARNING: SV-XML: Point element found in non-point dataset"
1180  << endl;
1181 
1182  return false;
1183 }
1184 
1185 bool
1186 SVFileReader::addBinToDataset(const QXmlAttributes &attributes)
1187 {
1188  if (!haveModel(m_currentDataset)) {
1189  SVCERR << "WARNING: SV-XML: Bin definition found in incompatible dataset"
1190  << endl;
1191  return false;
1192  }
1193 
1194  ModelId modelId = m_models[m_currentDataset];
1195 
1196  if (auto dtdm = ModelById::getAs<EditableDenseThreeDimensionalModel>
1197  (modelId)) {
1198 
1199  bool ok = false;
1200  int n = attributes.value("number").trimmed().toInt(&ok);
1201  if (!ok) {
1202  SVCERR << "WARNING: SV-XML: Missing or invalid bin number"
1203  << endl;
1204  return false;
1205  }
1206 
1207  QString name = attributes.value("name");
1208  dtdm->setBinName(n, name);
1209  return true;
1210  }
1211 
1212  SVCERR << "WARNING: SV-XML: Bin definition found in incompatible dataset"
1213  << endl;
1214 
1215  return false;
1216 }
1217 
1218 
1219 bool
1220 SVFileReader::addRowToDataset(const QXmlAttributes &attributes)
1221 {
1222  m_inRow = false;
1223 
1224  bool ok = false;
1225  m_rowNumber = attributes.value("n").trimmed().toInt(&ok);
1226  if (!ok) {
1227  SVCERR << "WARNING: SV-XML: Missing or invalid row number"
1228  << endl;
1229  return false;
1230  }
1231 
1232  m_inRow = true;
1233 
1234 // SVCERR << "SV-XML: In row " << m_rowNumber << endl;
1235 
1236  return true;
1237 }
1238 
1239 bool
1240 SVFileReader::readRowData(const QString &text)
1241 {
1242  if (!haveModel(m_currentDataset)) {
1243  SVCERR << "WARNING: SV-XML: Row data found in non-row dataset" << endl;
1244  return false;
1245  }
1246 
1247  ModelId modelId = m_models[m_currentDataset];
1248  bool warned = false;
1249 
1250  if (auto dtdm = ModelById::getAs<EditableDenseThreeDimensionalModel>
1251  (modelId)) {
1252 
1253  QStringList data = text.split(m_datasetSeparator);
1254 
1255  DenseThreeDimensionalModel::Column values;
1256 
1257  for (QStringList::iterator i = data.begin(); i != data.end(); ++i) {
1258 
1259  if (int(values.size()) == dtdm->getHeight()) {
1260  if (!warned) {
1261  SVCERR << "WARNING: SV-XML: Too many y-bins in 3-D dataset row "
1262  << m_rowNumber << endl;
1263  warned = true;
1264  }
1265  }
1266 
1267  bool ok;
1268  float value = i->toFloat(&ok);
1269  if (!ok) {
1270  SVCERR << "WARNING: SV-XML: Bad floating-point value "
1271  << i->toLocal8Bit().data()
1272  << " in row data" << endl;
1273  } else {
1274  values.push_back(value);
1275  }
1276  }
1277 
1278  dtdm->setColumn(m_rowNumber, values);
1279  return true;
1280  }
1281 
1282  SVCERR << "WARNING: SV-XML: Row data found in non-row dataset" << endl;
1283  return false;
1284 }
1285 
1286 bool
1287 SVFileReader::readDerivation(const QXmlAttributes &attributes)
1288 {
1289  int modelExportId = 0;
1290  bool modelOk = false;
1291  modelExportId = attributes.value("model").trimmed().toInt(&modelOk);
1292 
1293  if (!modelOk) {
1294  SVCERR << "WARNING: SV-XML: No model id specified for derivation" << endl;
1295  return false;
1296  }
1297 
1298  if (haveModel(modelExportId)) {
1299  m_currentDerivedModel = m_models[modelExportId];
1300  } else {
1301  // we'll regenerate the model when the derivation element ends
1302  m_currentDerivedModel = {};
1303  }
1304 
1305  m_pendingDerivedModel = modelExportId;
1306 
1307  int sourceId = 0;
1308  bool sourceOk = false;
1309  sourceId = attributes.value("source").trimmed().toInt(&sourceOk);
1310 
1311  if (sourceOk && haveModel(sourceId)) {
1312  m_currentTransformSource = m_models[sourceId];
1313  } else {
1314  SVDEBUG << "NOTE: SV-XML: Can't find a model with id " << sourceId
1315  << " for derivation source, falling back to main model" << endl;
1317  }
1318 
1319  m_currentTransform = Transform();
1320 
1321  bool ok = false;
1322  int channel = attributes.value("channel").trimmed().toInt(&ok);
1323  if (ok) m_currentTransformChannel = channel;
1324  else m_currentTransformChannel = -1;
1325 
1326  QString type = attributes.value("type");
1327 
1328  if (type == "transform") {
1330  return true;
1331  } else {
1333  SVDEBUG << "NOTE: SV-XML: Reading old-style derivation element"
1334  << endl;
1335  }
1336 
1337  QString transformId = attributes.value("transform");
1338 
1339  m_currentTransform.setIdentifier(transformId);
1340 
1341  int stepSize = attributes.value("stepSize").trimmed().toInt(&ok);
1342  if (ok) m_currentTransform.setStepSize(stepSize);
1343 
1344  int blockSize = attributes.value("blockSize").trimmed().toInt(&ok);
1345  if (ok) m_currentTransform.setBlockSize(blockSize);
1346 
1347  int windowType = attributes.value("windowType").trimmed().toInt(&ok);
1348  if (ok) m_currentTransform.setWindowType(WindowType(windowType));
1349 
1350  auto currentTransformSourceModel = ModelById::get(m_currentTransformSource);
1351  if (!currentTransformSourceModel) return true;
1352 
1353  sv_samplerate_t sampleRate = currentTransformSourceModel->getSampleRate();
1354 
1355  QString startFrameStr = attributes.value("startFrame");
1356  QString durationStr = attributes.value("duration");
1357 
1358  int startFrame = 0;
1359  int duration = 0;
1360 
1361  if (startFrameStr != "") {
1362  startFrame = startFrameStr.trimmed().toInt(&ok);
1363  if (!ok) startFrame = 0;
1364  }
1365  if (durationStr != "") {
1366  duration = durationStr.trimmed().toInt(&ok);
1367  if (!ok) duration = 0;
1368  }
1369 
1370  m_currentTransform.setStartTime
1371  (RealTime::frame2RealTime(startFrame, sampleRate));
1372 
1373  m_currentTransform.setDuration
1374  (RealTime::frame2RealTime(duration, sampleRate));
1375 
1376  return true;
1377 }
1378 
1379 bool
1380 SVFileReader::readPlayParameters(const QXmlAttributes &attributes)
1381 {
1383 
1384  int modelExportId = 0;
1385  bool modelOk = false;
1386  modelExportId = attributes.value("model").trimmed().toInt(&modelOk);
1387 
1388  if (!modelOk) {
1389  SVCERR << "WARNING: SV-XML: No model id specified for play parameters" << endl;
1390  return false;
1391  }
1392 
1393  if (haveModel(modelExportId)) {
1394 
1395  bool ok = false;
1396 
1397  auto parameters = PlayParameterRepository::getInstance()->
1398  getPlayParameters(m_models[modelExportId].untyped);
1399 
1400  if (!parameters) {
1401  SVCERR << "WARNING: SV-XML: Play parameters for model "
1402  << modelExportId
1403  << " not found - has model been added to document?"
1404  << endl;
1405  return false;
1406  }
1407 
1408  bool muted = (attributes.value("mute").trimmed() == "true");
1409  parameters->setPlayMuted(muted);
1410 
1411  float pan = attributes.value("pan").toFloat(&ok);
1412  if (ok) parameters->setPlayPan(pan);
1413 
1414  float gain = attributes.value("gain").toFloat(&ok);
1415  if (ok) parameters->setPlayGain(gain);
1416 
1417  QString clipId = attributes.value("clipId");
1418  if (clipId != "") parameters->setPlayClipId(clipId);
1419 
1420  m_currentPlayParameters = parameters;
1421 
1422 // SVCERR << "Current play parameters for model: " << m_models[modelExportId] << ": " << m_currentPlayParameters << endl;
1423 
1424  } else {
1425 
1426  SVCERR << "WARNING: SV-XML: Unknown model " << modelExportId
1427  << " for play parameters" << endl;
1428  return false;
1429  }
1430 
1431  return true;
1432 }
1433 
1434 bool
1435 SVFileReader::readPlugin(const QXmlAttributes &attributes)
1436 {
1437  if (m_pendingDerivedModel != XmlExportable::NO_ID) {
1438  return readPluginForTransform(attributes);
1439  } else if (m_currentPlayParameters) {
1440  return readPluginForPlayback(attributes);
1441  } else {
1442  SVCERR << "WARNING: SV-XML: Plugin found outside derivation or play parameters" << endl;
1443  return false;
1444  }
1445 }
1446 
1447 bool
1448 SVFileReader::readPluginForTransform(const QXmlAttributes &attributes)
1449 {
1451  // Not needed, we have the transform element instead
1452  return true;
1453  }
1454 
1455  QString configurationXml = "<plugin";
1456 
1457  for (int i = 0; i < attributes.length(); ++i) {
1458  configurationXml += QString(" %1=\"%2\"")
1459  .arg(attributes.qName(i))
1460  .arg(XmlExportable::encodeEntities(attributes.value(i)));
1461  }
1462 
1463  configurationXml += "/>";
1464 
1465  TransformFactory::getInstance()->
1466  setParametersFromPluginConfigurationXml(m_currentTransform,
1467  configurationXml);
1468  return true;
1469 }
1470 
1471 bool
1472 SVFileReader::readPluginForPlayback(const QXmlAttributes &attributes)
1473 {
1474  // Obsolete but supported for compatibility
1475 
1476  QString ident = attributes.value("identifier");
1477  if (ident == "sample_player") {
1478  QString clipId = attributes.value("program");
1479  if (clipId != "") m_currentPlayParameters->setPlayClipId(clipId);
1480  }
1481 
1482  return true;
1483 }
1484 
1485 bool
1486 SVFileReader::readTransform(const QXmlAttributes &attributes)
1487 {
1488  if (m_pendingDerivedModel == XmlExportable::NO_ID) {
1489  SVCERR << "WARNING: SV-XML: Transform found outside derivation" << endl;
1490  return false;
1491  }
1492 
1493  m_currentTransform = Transform();
1494  m_currentTransform.setFromXmlAttributes(attributes);
1495  return true;
1496 }
1497 
1498 bool
1499 SVFileReader::readParameter(const QXmlAttributes &attributes)
1500 {
1501  if (m_pendingDerivedModel == XmlExportable::NO_ID) {
1502  SVCERR << "WARNING: SV-XML: Parameter found outside derivation" << endl;
1503  return false;
1504  }
1505 
1506  QString name = attributes.value("name");
1507  if (name == "") {
1508  SVCERR << "WARNING: SV-XML: Ignoring nameless transform parameter"
1509  << endl;
1510  return false;
1511  }
1512 
1513  float value = attributes.value("value").trimmed().toFloat();
1514 
1515  m_currentTransform.setParameter(name, value);
1516  return true;
1517 }
1518 
1519 bool
1520 SVFileReader::readSelection(const QXmlAttributes &attributes)
1521 {
1522  bool ok;
1523 
1524  READ_MANDATORY(int, start, toInt);
1525  READ_MANDATORY(int, end, toInt);
1526 
1527  m_paneCallback.addSelection(start, end);
1528 
1529  return true;
1530 }
1531 
1532 bool
1533 SVFileReader::readMeasurement(const QXmlAttributes &attributes)
1534 {
1535  SVDEBUG << "SVFileReader::readMeasurement: inLayer "
1536  << m_inLayer << ", layer " << m_currentLayer << endl;
1537 
1538  if (!m_inLayer) {
1539  SVCERR << "WARNING: SV-XML: Measurement found outside layer" << endl;
1540  return false;
1541  }
1542 
1543  m_currentLayer->addMeasurementRect(attributes);
1544  return true;
1545 }
1546 
1548 {
1549 }
1550 
1551 
1552 class SVFileIdentifier : public QXmlDefaultHandler
1553 {
1554 public:
1556  m_inSv(false),
1557  m_inData(false),
1558  m_type(SVFileReader::UnknownFileType)
1559  { }
1560  ~SVFileIdentifier() override { }
1561 
1562  void parse(QXmlInputSource &source) {
1563  QXmlSimpleReader reader;
1564  reader.setContentHandler(this);
1565  reader.setErrorHandler(this);
1566  reader.parse(source);
1567  }
1568 
1569  SVFileReader::FileType getType() const { return m_type; }
1570 
1571  bool startElement(const QString &,
1572  const QString &,
1573  const QString &qName,
1574  const QXmlAttributes& atts) override
1575  {
1576  QString name = qName.toLower();
1577 
1578  // SV session files have an sv element containing a data
1579  // element containing a model element with mainModel="true".
1580 
1581  // If the sv element is present but the rest does not satisfy,
1582  // then it's (probably) an SV layer file.
1583 
1584  // Otherwise, it's of unknown type.
1585 
1586  if (name == "sv") {
1587  m_inSv = true;
1588  if (m_type == SVFileReader::UnknownFileType) {
1589  m_type = SVFileReader::SVLayerFile;
1590  }
1591  return true;
1592  } else if (name == "data") {
1593  if (!m_inSv) return true;
1594  m_inData = true;
1595  } else if (name == "model") {
1596  if (!m_inData) return true;
1597  if (atts.value("mainModel").trimmed() == "true") {
1598  if (m_type == SVFileReader::SVLayerFile) {
1599  m_type = SVFileReader::SVSessionFile;
1600  return false; // done
1601  }
1602  }
1603  }
1604  return true;
1605  }
1606 
1607  bool endElement(const QString &,
1608  const QString &,
1609  const QString &qName) override
1610  {
1611  QString name = qName.toLower();
1612 
1613  if (name == "sv") {
1614  if (m_inSv) {
1615  m_inSv = false;
1616  return false; // done
1617  }
1618  } else if (name == "data") {
1619  if (m_inData) {
1620  m_inData = false;
1621  return false; // also done, nothing after the first
1622  // data element is of use here
1623  }
1624  }
1625  return true;
1626  }
1627 
1628 private:
1629  bool m_inSv;
1630  bool m_inData;
1632 };
1633 
1634 
1637 {
1638  QFile file(path);
1639  SVFileIdentifier identifier;
1640  QXmlInputSource source(&file);
1641  identifier.parse(source);
1642  return identifier.getType();
1643 }
1644 
1645 
1646 
bool readView(const QXmlAttributes &)
void setMainModel(ModelId)
Set the main model (the source for playback sample rate, etc) to the given wave file model...
Definition: Document.cpp:421
virtual void addSelection(sv_frame_t start, sv_frame_t end)=0
Transform m_currentTransform
Definition: SVFileReader.h:286
bool fatalError(const QXmlParseException &exception) override
std::map< ExportId, PendingAggregateRec > m_pendingAggregates
Definition: SVFileReader.h:267
bool haveModel(ExportId id)
Definition: SVFileReader.h:249
SVFileReaderPaneCallback & m_paneCallback
Definition: SVFileReader.h:260
SVFileReader::FileType m_type
XmlExportable::ExportId ExportId
Definition: SVFileReader.h:247
bool readPlugin(const QXmlAttributes &)
ModelId m_currentDerivedModel
Definition: SVFileReader.h:283
std::map< ExportId, ExportId > m_awaitingDatasets
Definition: SVFileReader.h:275
void addUnaddedModels()
bool readSelection(const QXmlAttributes &)
bool startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts) override
bool addPointToDataset(const QXmlAttributes &)
bool addRowToDataset(const QXmlAttributes &)
ModelId m_currentTransformSource
Definition: SVFileReader.h:287
ExportId m_pendingDerivedModel
Definition: SVFileReader.h:284
QString m_datasetSeparator
Definition: SVFileReader.h:290
void addNonDerivedModel(ModelId)
Add an imported model, i.e.
Definition: Document.cpp:645
QString m_location
Definition: SVFileReader.h:261
SVFileReader loads Sonic Visualiser XML files.
Definition: SVFileReader.h:166
bool readDerivation(const QXmlAttributes &)
Layer * createLayer(LayerFactory::LayerType)
Create and return a new layer of the given type, associated with no model.
Definition: Document.cpp:118
Layer * m_currentLayer
Definition: SVFileReader.h:282
bool readMeasurement(const QXmlAttributes &)
bool readDatasetStart(const QXmlAttributes &)
bool error(const QXmlParseException &exception) override
void parse(QXmlInputSource &source)
ModelId getMainModel()
Get the main model (the source for playback sample rate, etc).
Definition: Document.h:195
SVFileReader(Document *document, SVFileReaderPaneCallback &callback, QString location="")
bool m_inSelections
Definition: SVFileReader.h:295
bool readWindow(const QXmlAttributes &)
~SVFileIdentifier() override
Pane * m_currentPane
Definition: SVFileReader.h:262
static FileType identifyXmlFile(QString path)
QString m_errorString
Definition: SVFileReader.h:297
#define READ_MANDATORY(TYPE, NAME, CONVERSION)
bool readPluginForTransform(const QXmlAttributes &)
bool addBinToDataset(const QXmlAttributes &)
Document * m_document
Definition: SVFileReader.h:259
std::map< ExportId, Layer * > m_layers
Definition: SVFileReader.h:263
virtual Pane * addPane()=0
void modelRegenerationWarning(QString layerName, QString transformName, QString message)
bool m_currentTransformIsNewStyle
Definition: SVFileReader.h:289
ExportId m_currentDataset
Definition: SVFileReader.h:280
bool readLayer(const QXmlAttributes &)
A Sonic Visualiser document consists of a set of data models, and also the visualisation layers used ...
Definition: Document.h:71
void modelRegenerationFailed(QString layerName, QString transformName, QString message)
bool startElement(const QString &, const QString &, const QString &qName, const QXmlAttributes &atts) override
SVFileReader::FileType getType() const
std::set< ModelId > m_addedModels
Definition: SVFileReader.h:266
std::shared_ptr< PlayParameters > m_currentPlayParameters
Definition: SVFileReader.h:285
void addLayerToView(View *, Layer *)
Add the given layer to the given view.
Definition: Document.cpp:993
bool readTransform(const QXmlAttributes &)
void makeAggregateModels()
bool characters(const QString &) override
void setModel(Layer *, ModelId)
Associate the given model with the given layer.
Definition: Document.cpp:951
bool readModel(const QXmlAttributes &)
std::vector< ExportId > components
Definition: SVFileReader.h:256
std::map< ExportId, Path * > m_paths
Definition: SVFileReader.h:265
bool readParameter(const QXmlAttributes &)
void parse(const QString &xmlData)
bool readPlayParameters(const QXmlAttributes &)
bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName) override
virtual ~SVFileReader()
void setIncomplete(bool i)
Definition: Document.h:309
bool readRowData(const QString &)
void addAlreadyDerivedModel(const Transform &transform, const ModelTransformer::Input &input, ModelId outputModelToAdd)
Add a derived model associated with the given transform.
Definition: Document.cpp:604
bool readPluginForPlayback(const QXmlAttributes &)
void deleteLayer(Layer *, bool force=false)
Delete the given layer, and also its associated model if no longer used by any other layer...
Definition: Document.cpp:889
ModelId addDerivedModel(const Transform &transform, const ModelTransformer::Input &input, QString &returnedMessage)
Add a derived model associated with the given transform, running the transform and returning the resu...
Definition: Document.cpp:733
int m_currentTransformChannel
Definition: SVFileReader.h:288
std::map< ExportId, ModelId > m_models
Definition: SVFileReader.h:264
bool endElement(const QString &, const QString &, const QString &qName) override