annotate framework/SVFileReader.cpp @ 626:51ecc3e2d71c

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