annotate data/fileio/CSVFileReader.cpp @ 1509:3299b42d8bdd import-audio-data

Don't try to continue after what should have been a terminal problem
author Chris Cannam
date Wed, 05 Sep 2018 11:56:39 +0100
parents b837ccdd4946
children 925d205c39b4
rev   line source
Chris@148 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@148 2
Chris@148 3 /*
Chris@148 4 Sonic Visualiser
Chris@148 5 An audio file viewer and annotation editor.
Chris@148 6 Centre for Digital Music, Queen Mary, University of London.
Chris@148 7 This file copyright 2006 Chris Cannam.
Chris@148 8
Chris@148 9 This program is free software; you can redistribute it and/or
Chris@148 10 modify it under the terms of the GNU General Public License as
Chris@148 11 published by the Free Software Foundation; either version 2 of the
Chris@148 12 License, or (at your option) any later version. See the file
Chris@148 13 COPYING included with this distribution for more information.
Chris@148 14 */
Chris@148 15
Chris@148 16 #include "CSVFileReader.h"
Chris@148 17
Chris@150 18 #include "model/Model.h"
Chris@148 19 #include "base/RealTime.h"
Chris@631 20 #include "base/StringBits.h"
Chris@1491 21 #include "base/ProgressReporter.h"
Chris@148 22 #include "model/SparseOneDimensionalModel.h"
Chris@148 23 #include "model/SparseTimeValueModel.h"
Chris@152 24 #include "model/EditableDenseThreeDimensionalModel.h"
Chris@628 25 #include "model/RegionModel.h"
Chris@897 26 #include "model/NoteModel.h"
Chris@1488 27 #include "model/WritableWaveFileModel.h"
Chris@308 28 #include "DataFileReaderFactory.h"
Chris@148 29
Chris@148 30 #include <QFile>
Chris@1030 31 #include <QFileInfo>
Chris@148 32 #include <QString>
Chris@148 33 #include <QRegExp>
Chris@148 34 #include <QStringList>
Chris@148 35 #include <QTextStream>
Chris@148 36
Chris@148 37 #include <iostream>
Chris@628 38 #include <map>
Chris@1428 39 #include <string>
Chris@148 40
Chris@1113 41 using namespace std;
Chris@1113 42
Chris@392 43 CSVFileReader::CSVFileReader(QString path, CSVFormat format,
Chris@1491 44 sv_samplerate_t mainModelSampleRate,
Chris@1491 45 ProgressReporter *reporter) :
Chris@392 46 m_format(format),
Chris@1009 47 m_device(0),
Chris@1009 48 m_ownDevice(true),
Chris@631 49 m_warnings(0),
Chris@1491 50 m_mainModelSampleRate(mainModelSampleRate),
Chris@1491 51 m_fileSize(0),
Chris@1491 52 m_readCount(0),
Chris@1492 53 m_progress(-1),
Chris@1491 54 m_reporter(reporter)
Chris@148 55 {
Chris@1009 56 QFile *file = new QFile(path);
Chris@148 57 bool good = false;
Chris@148 58
Chris@1009 59 if (!file->exists()) {
Chris@1429 60 m_error = QFile::tr("File \"%1\" does not exist").arg(path);
Chris@1009 61 } else if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) {
Chris@1429 62 m_error = QFile::tr("Failed to open file \"%1\"").arg(path);
Chris@148 63 } else {
Chris@1429 64 good = true;
Chris@148 65 }
Chris@148 66
Chris@1009 67 if (good) {
Chris@1009 68 m_device = file;
Chris@1030 69 m_filename = QFileInfo(path).fileName();
Chris@1491 70 m_fileSize = file->size();
Chris@1491 71 if (m_reporter) m_reporter->setDefinite(true);
Chris@1009 72 } else {
Chris@1429 73 delete file;
Chris@148 74 }
Chris@148 75 }
Chris@148 76
Chris@1009 77 CSVFileReader::CSVFileReader(QIODevice *device, CSVFormat format,
Chris@1491 78 sv_samplerate_t mainModelSampleRate,
Chris@1491 79 ProgressReporter *reporter) :
Chris@1009 80 m_format(format),
Chris@1009 81 m_device(device),
Chris@1009 82 m_ownDevice(false),
Chris@1009 83 m_warnings(0),
Chris@1491 84 m_mainModelSampleRate(mainModelSampleRate),
Chris@1491 85 m_fileSize(0),
Chris@1491 86 m_readCount(0),
Chris@1492 87 m_progress(-1),
Chris@1491 88 m_reporter(reporter)
Chris@1009 89 {
Chris@1491 90 if (m_reporter) m_reporter->setDefinite(false);
Chris@1009 91 }
Chris@1009 92
Chris@148 93 CSVFileReader::~CSVFileReader()
Chris@148 94 {
Chris@1009 95 SVDEBUG << "CSVFileReader::~CSVFileReader: device is " << m_device << endl;
Chris@148 96
Chris@1009 97 if (m_device && m_ownDevice) {
Chris@1009 98 SVDEBUG << "CSVFileReader::CSVFileReader: Closing device" << endl;
Chris@1009 99 m_device->close();
Chris@1009 100 delete m_device;
Chris@148 101 }
Chris@148 102 }
Chris@148 103
Chris@148 104 bool
Chris@148 105 CSVFileReader::isOK() const
Chris@148 106 {
Chris@1009 107 return (m_device != 0);
Chris@148 108 }
Chris@148 109
Chris@148 110 QString
Chris@148 111 CSVFileReader::getError() const
Chris@148 112 {
Chris@148 113 return m_error;
Chris@148 114 }
Chris@148 115
Chris@1038 116 sv_frame_t
Chris@1047 117 CSVFileReader::convertTimeValue(QString s, int lineno,
Chris@1047 118 sv_samplerate_t sampleRate,
Chris@929 119 int windowSize) const
Chris@631 120 {
Chris@631 121 QRegExp nonNumericRx("[^0-9eE.,+-]");
Chris@897 122 int warnLimit = 10;
Chris@631 123
Chris@631 124 CSVFormat::TimeUnits timeUnits = m_format.getTimeUnits();
Chris@631 125
Chris@1038 126 sv_frame_t calculatedFrame = 0;
Chris@631 127
Chris@631 128 bool ok = false;
Chris@631 129 QString numeric = s;
Chris@631 130 numeric.remove(nonNumericRx);
Chris@631 131
Chris@631 132 if (timeUnits == CSVFormat::TimeSeconds) {
Chris@631 133
Chris@631 134 double time = numeric.toDouble(&ok);
Chris@631 135 if (!ok) time = StringBits::stringToDoubleLocaleFree(numeric, &ok);
Chris@1038 136 calculatedFrame = sv_frame_t(time * sampleRate + 0.5);
Chris@990 137
Chris@990 138 } else if (timeUnits == CSVFormat::TimeMilliseconds) {
Chris@990 139
Chris@990 140 double time = numeric.toDouble(&ok);
Chris@990 141 if (!ok) time = StringBits::stringToDoubleLocaleFree(numeric, &ok);
Chris@1038 142 calculatedFrame = sv_frame_t((time / 1000.0) * sampleRate + 0.5);
Chris@631 143
Chris@631 144 } else {
Chris@631 145
Chris@631 146 long n = numeric.toLong(&ok);
Chris@631 147 if (n >= 0) calculatedFrame = n;
Chris@631 148
Chris@631 149 if (timeUnits == CSVFormat::TimeWindows) {
Chris@631 150 calculatedFrame *= windowSize;
Chris@631 151 }
Chris@631 152 }
Chris@631 153
Chris@631 154 if (!ok) {
Chris@631 155 if (m_warnings < warnLimit) {
Chris@1428 156 SVCERR << "WARNING: CSVFileReader::load: "
Chris@844 157 << "Bad time format (\"" << s
Chris@631 158 << "\") in data line "
Chris@843 159 << lineno+1 << endl;
Chris@631 160 } else if (m_warnings == warnLimit) {
Chris@1428 161 SVCERR << "WARNING: Too many warnings" << endl;
Chris@631 162 }
Chris@631 163 ++m_warnings;
Chris@631 164 }
Chris@631 165
Chris@631 166 return calculatedFrame;
Chris@631 167 }
Chris@631 168
Chris@148 169 Model *
Chris@148 170 CSVFileReader::load() const
Chris@148 171 {
Chris@1009 172 if (!m_device) return 0;
Chris@148 173
Chris@628 174 CSVFormat::ModelType modelType = m_format.getModelType();
Chris@392 175 CSVFormat::TimingType timingType = m_format.getTimingType();
Chris@628 176 CSVFormat::TimeUnits timeUnits = m_format.getTimeUnits();
Chris@1047 177 sv_samplerate_t sampleRate = m_format.getSampleRate();
Chris@929 178 int windowSize = m_format.getWindowSize();
Chris@631 179 QChar separator = m_format.getSeparator();
Chris@631 180 bool allowQuoting = m_format.getAllowQuoting();
Chris@148 181
Chris@392 182 if (timingType == CSVFormat::ExplicitTiming) {
Chris@611 183 if (modelType == CSVFormat::ThreeDimensionalModel) {
Chris@611 184 // This will be overridden later if more than one line
Chris@611 185 // appears in our file, but we want to choose a default
Chris@611 186 // that's likely to be visible
Chris@611 187 windowSize = 1024;
Chris@611 188 } else {
Chris@611 189 windowSize = 1;
Chris@611 190 }
Chris@1429 191 if (timeUnits == CSVFormat::TimeSeconds ||
Chris@990 192 timeUnits == CSVFormat::TimeMilliseconds) {
Chris@1429 193 sampleRate = m_mainModelSampleRate;
Chris@1429 194 }
Chris@148 195 }
Chris@148 196
Chris@148 197 SparseOneDimensionalModel *model1 = 0;
Chris@148 198 SparseTimeValueModel *model2 = 0;
Chris@628 199 RegionModel *model2a = 0;
Chris@897 200 NoteModel *model2b = 0;
Chris@152 201 EditableDenseThreeDimensionalModel *model3 = 0;
Chris@1488 202 WritableWaveFileModel *modelW = 0;
Chris@148 203 Model *model = 0;
Chris@148 204
Chris@1009 205 QTextStream in(m_device);
Chris@148 206
Chris@148 207 unsigned int warnings = 0, warnLimit = 10;
Chris@148 208 unsigned int lineno = 0;
Chris@148 209
Chris@148 210 float min = 0.0, max = 0.0;
Chris@148 211
Chris@1038 212 sv_frame_t frameNo = 0;
Chris@1038 213 sv_frame_t duration = 0;
Chris@1038 214 sv_frame_t endFrame = 0;
Chris@631 215
Chris@631 216 bool haveAnyValue = false;
Chris@631 217 bool haveEndTime = false;
Chris@897 218 bool pitchLooksLikeMIDI = true;
Chris@631 219
Chris@1038 220 sv_frame_t startFrame = 0; // for calculation of dense model resolution
Chris@631 221 bool firstEverValue = true;
Chris@148 222
Chris@1113 223 map<QString, int> labelCountMap;
Chris@631 224
Chris@676 225 int valueColumns = 0;
Chris@676 226 for (int i = 0; i < m_format.getColumnCount(); ++i) {
Chris@676 227 if (m_format.getColumnPurpose(i) == CSVFormat::ColumnValue) {
Chris@676 228 ++valueColumns;
Chris@676 229 }
Chris@676 230 }
Chris@676 231
Chris@1509 232 bool abandoned = false;
Chris@1509 233
Chris@1509 234 while (!in.atEnd() && !abandoned) {
Chris@148 235
Chris@283 236 // QTextStream's readLine doesn't cope with old-style Mac
Chris@283 237 // CR-only line endings. Why did they bother making the class
Chris@283 238 // cope with more than one sort of line ending, if it still
Chris@283 239 // can't be configured to cope with all the common sorts?
Chris@148 240
Chris@283 241 // For the time being we'll deal with this case (which is
Chris@283 242 // relatively uncommon for us, but still necessary to handle)
Chris@283 243 // by reading the entire file using a single readLine, and
Chris@283 244 // splitting it. For CR and CR/LF line endings this will just
Chris@283 245 // read a line at a time, and that's obviously OK.
Chris@148 246
Chris@283 247 QString chunk = in.readLine();
Chris@283 248 QStringList lines = chunk.split('\r', QString::SkipEmptyParts);
Chris@1491 249
Chris@1491 250 m_readCount += chunk.size() + 1;
Chris@1491 251
Chris@1491 252 if (m_reporter) {
Chris@1491 253 if (m_reporter->wasCancelled()) {
Chris@1509 254 abandoned = true;
Chris@1491 255 break;
Chris@1491 256 }
Chris@1491 257 int progress;
Chris@1491 258 if (m_fileSize > 0) {
Chris@1491 259 progress = int((double(m_readCount) / double(m_fileSize))
Chris@1491 260 * 100.0);
Chris@1491 261 } else {
Chris@1491 262 progress = int(m_readCount / 10000);
Chris@1491 263 }
Chris@1491 264 if (progress != m_progress) {
Chris@1491 265 m_reporter->setProgress(progress);
Chris@1491 266 m_progress = progress;
Chris@1491 267 }
Chris@1491 268 }
Chris@283 269
Chris@897 270 for (int li = 0; li < lines.size(); ++li) {
Chris@148 271
Chris@283 272 QString line = lines[li];
Chris@1009 273
Chris@283 274 if (line.startsWith("#")) continue;
Chris@283 275
Chris@631 276 QStringList list = StringBits::split(line, separator, allowQuoting);
Chris@283 277 if (!model) {
Chris@283 278
Chris@283 279 switch (modelType) {
Chris@283 280
Chris@392 281 case CSVFormat::OneDimensionalModel:
Chris@283 282 model1 = new SparseOneDimensionalModel(sampleRate, windowSize);
Chris@283 283 model = model1;
Chris@283 284 break;
Chris@1429 285
Chris@392 286 case CSVFormat::TwoDimensionalModel:
Chris@283 287 model2 = new SparseTimeValueModel(sampleRate, windowSize, false);
Chris@283 288 model = model2;
Chris@283 289 break;
Chris@1429 290
Chris@628 291 case CSVFormat::TwoDimensionalModelWithDuration:
Chris@628 292 model2a = new RegionModel(sampleRate, windowSize, false);
Chris@628 293 model = model2a;
Chris@628 294 break;
Chris@1429 295
Chris@897 296 case CSVFormat::TwoDimensionalModelWithDurationAndPitch:
Chris@897 297 model2b = new NoteModel(sampleRate, windowSize, false);
Chris@897 298 model = model2b;
Chris@897 299 break;
Chris@1429 300
Chris@392 301 case CSVFormat::ThreeDimensionalModel:
Chris@535 302 model3 = new EditableDenseThreeDimensionalModel
Chris@535 303 (sampleRate,
Chris@535 304 windowSize,
Chris@676 305 valueColumns,
Chris@535 306 EditableDenseThreeDimensionalModel::NoCompression);
Chris@283 307 model = model3;
Chris@283 308 break;
Chris@1488 309
Chris@1488 310 case CSVFormat::WaveFileModel:
Chris@1488 311 modelW = new WritableWaveFileModel
Chris@1488 312 (sampleRate, valueColumns);
Chris@1488 313 model = modelW;
Chris@1488 314 break;
Chris@283 315 }
Chris@1030 316
Chris@1508 317 if (model && model->isOK()) {
Chris@1030 318 if (m_filename != "") {
Chris@1030 319 model->setObjectName(m_filename);
Chris@1030 320 }
Chris@1030 321 }
Chris@283 322 }
Chris@148 323
Chris@1508 324 if (!model || !model->isOK()) {
Chris@1508 325 SVCERR << "Failed to create model to load CSV file into"
Chris@1508 326 << endl;
Chris@1508 327 if (model) {
Chris@1508 328 delete model;
Chris@1508 329 model = 0;
Chris@1508 330 model1 = 0; model2 = 0; model2a = 0; model2b = 0;
Chris@1508 331 model3 = 0; modelW = 0;
Chris@1508 332 }
Chris@1509 333 abandoned = true;
Chris@1508 334 break;
Chris@1508 335 }
Chris@1508 336
Chris@631 337 float value = 0.f;
Chris@897 338 float pitch = 0.f;
Chris@631 339 QString label = "";
Chris@148 340
Chris@631 341 duration = 0.f;
Chris@631 342 haveEndTime = false;
Chris@628 343
Chris@283 344 for (int i = 0; i < list.size(); ++i) {
Chris@148 345
Chris@631 346 QString s = list[i];
Chris@631 347
Chris@631 348 CSVFormat::ColumnPurpose purpose = m_format.getColumnPurpose(i);
Chris@631 349
Chris@631 350 switch (purpose) {
Chris@631 351
Chris@631 352 case CSVFormat::ColumnUnknown:
Chris@631 353 break;
Chris@631 354
Chris@631 355 case CSVFormat::ColumnStartTime:
Chris@631 356 frameNo = convertTimeValue(s, lineno, sampleRate, windowSize);
Chris@631 357 break;
Chris@631 358
Chris@631 359 case CSVFormat::ColumnEndTime:
Chris@631 360 endFrame = convertTimeValue(s, lineno, sampleRate, windowSize);
Chris@631 361 haveEndTime = true;
Chris@631 362 break;
Chris@631 363
Chris@631 364 case CSVFormat::ColumnDuration:
Chris@631 365 duration = convertTimeValue(s, lineno, sampleRate, windowSize);
Chris@631 366 break;
Chris@631 367
Chris@631 368 case CSVFormat::ColumnValue:
Chris@631 369 value = s.toFloat();
Chris@631 370 haveAnyValue = true;
Chris@631 371 break;
Chris@631 372
Chris@897 373 case CSVFormat::ColumnPitch:
Chris@897 374 pitch = s.toFloat();
Chris@897 375 if (pitch < 0.f || pitch > 127.f) {
Chris@897 376 pitchLooksLikeMIDI = false;
Chris@897 377 }
Chris@897 378 break;
Chris@897 379
Chris@631 380 case CSVFormat::ColumnLabel:
Chris@631 381 label = s;
Chris@631 382 break;
Chris@283 383 }
Chris@631 384 }
Chris@148 385
Chris@1113 386 ++labelCountMap[label];
Chris@1113 387
Chris@631 388 if (haveEndTime) { // ... calculate duration now all cols read
Chris@631 389 if (endFrame > frameNo) {
Chris@631 390 duration = endFrame - frameNo;
Chris@628 391 }
Chris@283 392 }
Chris@148 393
Chris@392 394 if (modelType == CSVFormat::OneDimensionalModel) {
Chris@1429 395
Chris@631 396 SparseOneDimensionalModel::Point point(frameNo, label);
Chris@283 397 model1->addPoint(point);
Chris@148 398
Chris@392 399 } else if (modelType == CSVFormat::TwoDimensionalModel) {
Chris@148 400
Chris@631 401 SparseTimeValueModel::Point point(frameNo, value, label);
Chris@283 402 model2->addPoint(point);
Chris@148 403
Chris@628 404 } else if (modelType == CSVFormat::TwoDimensionalModelWithDuration) {
Chris@628 405
Chris@631 406 RegionModel::Point point(frameNo, value, duration, label);
Chris@628 407 model2a->addPoint(point);
Chris@628 408
Chris@897 409 } else if (modelType == CSVFormat::TwoDimensionalModelWithDurationAndPitch) {
Chris@897 410
Chris@897 411 float level = ((value >= 0.f && value <= 1.f) ? value : 1.f);
Chris@897 412 NoteModel::Point point(frameNo, pitch, duration, level, label);
Chris@897 413 model2b->addPoint(point);
Chris@897 414
Chris@392 415 } else if (modelType == CSVFormat::ThreeDimensionalModel) {
Chris@148 416
Chris@283 417 DenseThreeDimensionalModel::Column values;
Chris@148 418
Chris@631 419 for (int i = 0; i < list.size(); ++i) {
Chris@148 420
Chris@676 421 if (m_format.getColumnPurpose(i) != CSVFormat::ColumnValue) {
Chris@676 422 continue;
Chris@676 423 }
Chris@676 424
Chris@283 425 bool ok = false;
Chris@283 426 float value = list[i].toFloat(&ok);
Chris@611 427
Chris@676 428 values.push_back(value);
Chris@1429 429
Chris@631 430 if (firstEverValue || value < min) min = value;
Chris@631 431 if (firstEverValue || value > max) max = value;
Chris@676 432
Chris@631 433 if (firstEverValue) {
Chris@611 434 startFrame = frameNo;
Chris@611 435 model3->setStartFrame(startFrame);
Chris@611 436 } else if (lineno == 1 &&
Chris@611 437 timingType == CSVFormat::ExplicitTiming) {
Chris@1038 438 model3->setResolution(int(frameNo - startFrame));
Chris@611 439 }
Chris@631 440
Chris@631 441 firstEverValue = false;
Chris@148 442
Chris@283 443 if (!ok) {
Chris@283 444 if (warnings < warnLimit) {
Chris@1428 445 SVCERR << "WARNING: CSVFileReader::load: "
Chris@390 446 << "Non-numeric value \""
Chris@844 447 << list[i]
Chris@491 448 << "\" in data line " << lineno+1
Chris@843 449 << ":" << endl;
Chris@1428 450 SVCERR << line << endl;
Chris@283 451 ++warnings;
Chris@283 452 } else if (warnings == warnLimit) {
Chris@1428 453 // SVCERR << "WARNING: Too many warnings" << endl;
Chris@283 454 }
Chris@283 455 }
Chris@283 456 }
Chris@1429 457
Chris@690 458 // SVDEBUG << "Setting bin values for count " << lineno << ", frame "
Chris@687 459 // << frameNo << ", time " << RealTime::frame2RealTime(frameNo, sampleRate) << endl;
Chris@148 460
Chris@611 461 model3->setColumn(lineno, values);
Chris@1488 462
Chris@1488 463 } else if (modelType == CSVFormat::WaveFileModel) {
Chris@1488 464
Chris@1488 465 int channels = modelW->getChannelCount();
Chris@1488 466
Chris@1488 467 float **samples =
Chris@1488 468 breakfastquay::allocate_and_zero_channels<float>
Chris@1488 469 (channels, 1);
Chris@1490 470
Chris@1490 471 int channel = 0;
Chris@1488 472
Chris@1490 473 for (int i = 0; i < list.size() && channel < channels; ++i) {
Chris@1488 474
Chris@1490 475 if (m_format.getColumnPurpose(i) !=
Chris@1490 476 CSVFormat::ColumnValue) {
Chris@1488 477 continue;
Chris@1488 478 }
Chris@1488 479
Chris@1488 480 bool ok = false;
Chris@1488 481 float value = list[i].toFloat(&ok);
Chris@1488 482
Chris@1490 483 samples[channel][0] = value;
Chris@1490 484
Chris@1490 485 ++channel;
Chris@1488 486 }
Chris@1488 487
Chris@1488 488 bool ok = modelW->addSamples(samples, 1);
Chris@1488 489
Chris@1488 490 breakfastquay::deallocate_channels(samples, channels);
Chris@1488 491
Chris@1488 492 if (!ok) {
Chris@1488 493 if (warnings < warnLimit) {
Chris@1488 494 SVCERR << "WARNING: CSVFileReader::load: "
Chris@1488 495 << "Unable to add sample to wave-file model"
Chris@1488 496 << endl;
Chris@1488 497 SVCERR << line << endl;
Chris@1488 498 ++warnings;
Chris@1488 499 }
Chris@1488 500 }
Chris@283 501 }
Chris@1488 502
Chris@283 503 ++lineno;
Chris@392 504 if (timingType == CSVFormat::ImplicitTiming ||
Chris@283 505 list.size() == 0) {
Chris@283 506 frameNo += windowSize;
Chris@283 507 }
Chris@283 508 }
Chris@148 509 }
Chris@148 510
Chris@631 511 if (!haveAnyValue) {
Chris@631 512 if (model2a) {
Chris@631 513 // assign values for regions based on label frequency; we
Chris@631 514 // have this in our labelCountMap, sort of
Chris@631 515
Chris@1113 516 map<int, map<QString, float> > countLabelValueMap;
Chris@1113 517 for (map<QString, int>::iterator i = labelCountMap.begin();
Chris@631 518 i != labelCountMap.end(); ++i) {
Chris@1113 519 countLabelValueMap[i->second][i->first] = -1.f;
Chris@631 520 }
Chris@631 521
Chris@631 522 float v = 0.f;
Chris@1113 523 for (map<int, map<QString, float> >::iterator i =
Chris@631 524 countLabelValueMap.end(); i != countLabelValueMap.begin(); ) {
Chris@631 525 --i;
Chris@1428 526 SVCERR << "count -> " << i->first << endl;
Chris@1113 527 for (map<QString, float>::iterator j = i->second.begin();
Chris@631 528 j != i->second.end(); ++j) {
Chris@631 529 j->second = v;
Chris@1428 530 SVCERR << "label -> " << j->first << ", value " << v << endl;
Chris@631 531 v = v + 1.f;
Chris@631 532 }
Chris@631 533 }
Chris@631 534
Chris@1113 535 map<RegionModel::Point, RegionModel::Point,
Chris@631 536 RegionModel::Point::Comparator> pointMap;
Chris@631 537 for (RegionModel::PointList::const_iterator i =
Chris@631 538 model2a->getPoints().begin();
Chris@631 539 i != model2a->getPoints().end(); ++i) {
Chris@631 540 RegionModel::Point p(*i);
Chris@1113 541 int count = labelCountMap[p.label];
Chris@1113 542 v = countLabelValueMap[count][p.label];
Chris@1428 543 // SVCERR << "mapping from label \"" << p.label << "\" (count " << count << ") to value " << v << endl;
Chris@631 544 RegionModel::Point pp(p.frame, v, p.duration, p.label);
Chris@631 545 pointMap[p] = pp;
Chris@631 546 }
Chris@631 547
Chris@1113 548 for (map<RegionModel::Point, RegionModel::Point>::iterator i =
Chris@631 549 pointMap.begin(); i != pointMap.end(); ++i) {
Chris@1113 550 // There could be duplicate regions; if so replace
Chris@1113 551 // them all -- but we need to check we're not
Chris@1113 552 // replacing a region by itself (or else this will
Chris@1113 553 // never terminate)
Chris@1113 554 if (i->first.value == i->second.value) {
Chris@1113 555 continue;
Chris@1113 556 }
Chris@1113 557 while (model2a->containsPoint(i->first)) {
Chris@1113 558 model2a->deletePoint(i->first);
Chris@1113 559 model2a->addPoint(i->second);
Chris@1113 560 }
Chris@631 561 }
Chris@631 562 }
Chris@631 563 }
Chris@631 564
Chris@897 565 if (model2b) {
Chris@897 566 if (pitchLooksLikeMIDI) {
Chris@897 567 model2b->setScaleUnits("MIDI Pitch");
Chris@897 568 } else {
Chris@897 569 model2b->setScaleUnits("Hz");
Chris@897 570 }
Chris@897 571 }
Chris@897 572
Chris@961 573 if (model3) {
Chris@1429 574 model3->setMinimumLevel(min);
Chris@1429 575 model3->setMaximumLevel(max);
Chris@148 576 }
Chris@148 577
Chris@1489 578 if (modelW) {
Chris@1493 579 modelW->updateModel();
Chris@1489 580 modelW->writeComplete();
Chris@1489 581 }
Chris@1489 582
Chris@148 583 return model;
Chris@148 584 }
Chris@148 585