annotate data/fileio/CSVFileReader.cpp @ 1491:1dc64d3d323c import-audio-data

Support progress reporter for data file loads
author Chris Cannam
date Fri, 29 Jun 2018 13:44:53 +0100
parents 9ab8e5ec4731
children 6989d6215640
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@1491 53 m_progress(0),
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@1491 87 m_progress(0),
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@148 232 while (!in.atEnd()) {
Chris@148 233
Chris@283 234 // QTextStream's readLine doesn't cope with old-style Mac
Chris@283 235 // CR-only line endings. Why did they bother making the class
Chris@283 236 // cope with more than one sort of line ending, if it still
Chris@283 237 // can't be configured to cope with all the common sorts?
Chris@148 238
Chris@283 239 // For the time being we'll deal with this case (which is
Chris@283 240 // relatively uncommon for us, but still necessary to handle)
Chris@283 241 // by reading the entire file using a single readLine, and
Chris@283 242 // splitting it. For CR and CR/LF line endings this will just
Chris@283 243 // read a line at a time, and that's obviously OK.
Chris@148 244
Chris@283 245 QString chunk = in.readLine();
Chris@283 246 QStringList lines = chunk.split('\r', QString::SkipEmptyParts);
Chris@1491 247
Chris@1491 248 m_readCount += chunk.size() + 1;
Chris@1491 249
Chris@1491 250 if (m_reporter) {
Chris@1491 251 if (m_reporter->wasCancelled()) {
Chris@1491 252 break;
Chris@1491 253 }
Chris@1491 254 int progress;
Chris@1491 255 if (m_fileSize > 0) {
Chris@1491 256 progress = int((double(m_readCount) / double(m_fileSize))
Chris@1491 257 * 100.0);
Chris@1491 258 } else {
Chris@1491 259 progress = int(m_readCount / 10000);
Chris@1491 260 }
Chris@1491 261 if (progress != m_progress) {
Chris@1491 262 m_reporter->setProgress(progress);
Chris@1491 263 m_progress = progress;
Chris@1491 264 }
Chris@1491 265 }
Chris@283 266
Chris@897 267 for (int li = 0; li < lines.size(); ++li) {
Chris@148 268
Chris@283 269 QString line = lines[li];
Chris@1009 270
Chris@283 271 if (line.startsWith("#")) continue;
Chris@283 272
Chris@631 273 QStringList list = StringBits::split(line, separator, allowQuoting);
Chris@283 274 if (!model) {
Chris@283 275
Chris@283 276 switch (modelType) {
Chris@283 277
Chris@392 278 case CSVFormat::OneDimensionalModel:
Chris@283 279 model1 = new SparseOneDimensionalModel(sampleRate, windowSize);
Chris@283 280 model = model1;
Chris@283 281 break;
Chris@1429 282
Chris@392 283 case CSVFormat::TwoDimensionalModel:
Chris@283 284 model2 = new SparseTimeValueModel(sampleRate, windowSize, false);
Chris@283 285 model = model2;
Chris@283 286 break;
Chris@1429 287
Chris@628 288 case CSVFormat::TwoDimensionalModelWithDuration:
Chris@628 289 model2a = new RegionModel(sampleRate, windowSize, false);
Chris@628 290 model = model2a;
Chris@628 291 break;
Chris@1429 292
Chris@897 293 case CSVFormat::TwoDimensionalModelWithDurationAndPitch:
Chris@897 294 model2b = new NoteModel(sampleRate, windowSize, false);
Chris@897 295 model = model2b;
Chris@897 296 break;
Chris@1429 297
Chris@392 298 case CSVFormat::ThreeDimensionalModel:
Chris@535 299 model3 = new EditableDenseThreeDimensionalModel
Chris@535 300 (sampleRate,
Chris@535 301 windowSize,
Chris@676 302 valueColumns,
Chris@535 303 EditableDenseThreeDimensionalModel::NoCompression);
Chris@283 304 model = model3;
Chris@283 305 break;
Chris@1488 306
Chris@1488 307 case CSVFormat::WaveFileModel:
Chris@1488 308 modelW = new WritableWaveFileModel
Chris@1488 309 (sampleRate, valueColumns);
Chris@1488 310 model = modelW;
Chris@1488 311 break;
Chris@283 312 }
Chris@1030 313
Chris@1030 314 if (model) {
Chris@1030 315 if (m_filename != "") {
Chris@1030 316 model->setObjectName(m_filename);
Chris@1030 317 }
Chris@1030 318 }
Chris@283 319 }
Chris@148 320
Chris@631 321 float value = 0.f;
Chris@897 322 float pitch = 0.f;
Chris@631 323 QString label = "";
Chris@148 324
Chris@631 325 duration = 0.f;
Chris@631 326 haveEndTime = false;
Chris@628 327
Chris@283 328 for (int i = 0; i < list.size(); ++i) {
Chris@148 329
Chris@631 330 QString s = list[i];
Chris@631 331
Chris@631 332 CSVFormat::ColumnPurpose purpose = m_format.getColumnPurpose(i);
Chris@631 333
Chris@631 334 switch (purpose) {
Chris@631 335
Chris@631 336 case CSVFormat::ColumnUnknown:
Chris@631 337 break;
Chris@631 338
Chris@631 339 case CSVFormat::ColumnStartTime:
Chris@631 340 frameNo = convertTimeValue(s, lineno, sampleRate, windowSize);
Chris@631 341 break;
Chris@631 342
Chris@631 343 case CSVFormat::ColumnEndTime:
Chris@631 344 endFrame = convertTimeValue(s, lineno, sampleRate, windowSize);
Chris@631 345 haveEndTime = true;
Chris@631 346 break;
Chris@631 347
Chris@631 348 case CSVFormat::ColumnDuration:
Chris@631 349 duration = convertTimeValue(s, lineno, sampleRate, windowSize);
Chris@631 350 break;
Chris@631 351
Chris@631 352 case CSVFormat::ColumnValue:
Chris@631 353 value = s.toFloat();
Chris@631 354 haveAnyValue = true;
Chris@631 355 break;
Chris@631 356
Chris@897 357 case CSVFormat::ColumnPitch:
Chris@897 358 pitch = s.toFloat();
Chris@897 359 if (pitch < 0.f || pitch > 127.f) {
Chris@897 360 pitchLooksLikeMIDI = false;
Chris@897 361 }
Chris@897 362 break;
Chris@897 363
Chris@631 364 case CSVFormat::ColumnLabel:
Chris@631 365 label = s;
Chris@631 366 break;
Chris@283 367 }
Chris@631 368 }
Chris@148 369
Chris@1113 370 ++labelCountMap[label];
Chris@1113 371
Chris@631 372 if (haveEndTime) { // ... calculate duration now all cols read
Chris@631 373 if (endFrame > frameNo) {
Chris@631 374 duration = endFrame - frameNo;
Chris@628 375 }
Chris@283 376 }
Chris@148 377
Chris@392 378 if (modelType == CSVFormat::OneDimensionalModel) {
Chris@1429 379
Chris@631 380 SparseOneDimensionalModel::Point point(frameNo, label);
Chris@283 381 model1->addPoint(point);
Chris@148 382
Chris@392 383 } else if (modelType == CSVFormat::TwoDimensionalModel) {
Chris@148 384
Chris@631 385 SparseTimeValueModel::Point point(frameNo, value, label);
Chris@283 386 model2->addPoint(point);
Chris@148 387
Chris@628 388 } else if (modelType == CSVFormat::TwoDimensionalModelWithDuration) {
Chris@628 389
Chris@631 390 RegionModel::Point point(frameNo, value, duration, label);
Chris@628 391 model2a->addPoint(point);
Chris@628 392
Chris@897 393 } else if (modelType == CSVFormat::TwoDimensionalModelWithDurationAndPitch) {
Chris@897 394
Chris@897 395 float level = ((value >= 0.f && value <= 1.f) ? value : 1.f);
Chris@897 396 NoteModel::Point point(frameNo, pitch, duration, level, label);
Chris@897 397 model2b->addPoint(point);
Chris@897 398
Chris@392 399 } else if (modelType == CSVFormat::ThreeDimensionalModel) {
Chris@148 400
Chris@283 401 DenseThreeDimensionalModel::Column values;
Chris@148 402
Chris@631 403 for (int i = 0; i < list.size(); ++i) {
Chris@148 404
Chris@676 405 if (m_format.getColumnPurpose(i) != CSVFormat::ColumnValue) {
Chris@676 406 continue;
Chris@676 407 }
Chris@676 408
Chris@283 409 bool ok = false;
Chris@283 410 float value = list[i].toFloat(&ok);
Chris@611 411
Chris@676 412 values.push_back(value);
Chris@1429 413
Chris@631 414 if (firstEverValue || value < min) min = value;
Chris@631 415 if (firstEverValue || value > max) max = value;
Chris@676 416
Chris@631 417 if (firstEverValue) {
Chris@611 418 startFrame = frameNo;
Chris@611 419 model3->setStartFrame(startFrame);
Chris@611 420 } else if (lineno == 1 &&
Chris@611 421 timingType == CSVFormat::ExplicitTiming) {
Chris@1038 422 model3->setResolution(int(frameNo - startFrame));
Chris@611 423 }
Chris@631 424
Chris@631 425 firstEverValue = false;
Chris@148 426
Chris@283 427 if (!ok) {
Chris@283 428 if (warnings < warnLimit) {
Chris@1428 429 SVCERR << "WARNING: CSVFileReader::load: "
Chris@390 430 << "Non-numeric value \""
Chris@844 431 << list[i]
Chris@491 432 << "\" in data line " << lineno+1
Chris@843 433 << ":" << endl;
Chris@1428 434 SVCERR << line << endl;
Chris@283 435 ++warnings;
Chris@283 436 } else if (warnings == warnLimit) {
Chris@1428 437 // SVCERR << "WARNING: Too many warnings" << endl;
Chris@283 438 }
Chris@283 439 }
Chris@283 440 }
Chris@1429 441
Chris@690 442 // SVDEBUG << "Setting bin values for count " << lineno << ", frame "
Chris@687 443 // << frameNo << ", time " << RealTime::frame2RealTime(frameNo, sampleRate) << endl;
Chris@148 444
Chris@611 445 model3->setColumn(lineno, values);
Chris@1488 446
Chris@1488 447 } else if (modelType == CSVFormat::WaveFileModel) {
Chris@1488 448
Chris@1488 449 int channels = modelW->getChannelCount();
Chris@1488 450
Chris@1488 451 float **samples =
Chris@1488 452 breakfastquay::allocate_and_zero_channels<float>
Chris@1488 453 (channels, 1);
Chris@1490 454
Chris@1490 455 int channel = 0;
Chris@1488 456
Chris@1490 457 for (int i = 0; i < list.size() && channel < channels; ++i) {
Chris@1488 458
Chris@1490 459 if (m_format.getColumnPurpose(i) !=
Chris@1490 460 CSVFormat::ColumnValue) {
Chris@1488 461 continue;
Chris@1488 462 }
Chris@1488 463
Chris@1488 464 bool ok = false;
Chris@1488 465 float value = list[i].toFloat(&ok);
Chris@1488 466
Chris@1490 467 samples[channel][0] = value;
Chris@1490 468
Chris@1490 469 ++channel;
Chris@1488 470 }
Chris@1488 471
Chris@1488 472 bool ok = modelW->addSamples(samples, 1);
Chris@1488 473
Chris@1488 474 breakfastquay::deallocate_channels(samples, channels);
Chris@1488 475
Chris@1488 476 if (!ok) {
Chris@1488 477 if (warnings < warnLimit) {
Chris@1488 478 SVCERR << "WARNING: CSVFileReader::load: "
Chris@1488 479 << "Unable to add sample to wave-file model"
Chris@1488 480 << endl;
Chris@1488 481 SVCERR << line << endl;
Chris@1488 482 ++warnings;
Chris@1488 483 }
Chris@1488 484 }
Chris@283 485 }
Chris@1488 486
Chris@283 487 ++lineno;
Chris@392 488 if (timingType == CSVFormat::ImplicitTiming ||
Chris@283 489 list.size() == 0) {
Chris@283 490 frameNo += windowSize;
Chris@283 491 }
Chris@283 492 }
Chris@148 493 }
Chris@148 494
Chris@631 495 if (!haveAnyValue) {
Chris@631 496 if (model2a) {
Chris@631 497 // assign values for regions based on label frequency; we
Chris@631 498 // have this in our labelCountMap, sort of
Chris@631 499
Chris@1113 500 map<int, map<QString, float> > countLabelValueMap;
Chris@1113 501 for (map<QString, int>::iterator i = labelCountMap.begin();
Chris@631 502 i != labelCountMap.end(); ++i) {
Chris@1113 503 countLabelValueMap[i->second][i->first] = -1.f;
Chris@631 504 }
Chris@631 505
Chris@631 506 float v = 0.f;
Chris@1113 507 for (map<int, map<QString, float> >::iterator i =
Chris@631 508 countLabelValueMap.end(); i != countLabelValueMap.begin(); ) {
Chris@631 509 --i;
Chris@1428 510 SVCERR << "count -> " << i->first << endl;
Chris@1113 511 for (map<QString, float>::iterator j = i->second.begin();
Chris@631 512 j != i->second.end(); ++j) {
Chris@631 513 j->second = v;
Chris@1428 514 SVCERR << "label -> " << j->first << ", value " << v << endl;
Chris@631 515 v = v + 1.f;
Chris@631 516 }
Chris@631 517 }
Chris@631 518
Chris@1113 519 map<RegionModel::Point, RegionModel::Point,
Chris@631 520 RegionModel::Point::Comparator> pointMap;
Chris@631 521 for (RegionModel::PointList::const_iterator i =
Chris@631 522 model2a->getPoints().begin();
Chris@631 523 i != model2a->getPoints().end(); ++i) {
Chris@631 524 RegionModel::Point p(*i);
Chris@1113 525 int count = labelCountMap[p.label];
Chris@1113 526 v = countLabelValueMap[count][p.label];
Chris@1428 527 // SVCERR << "mapping from label \"" << p.label << "\" (count " << count << ") to value " << v << endl;
Chris@631 528 RegionModel::Point pp(p.frame, v, p.duration, p.label);
Chris@631 529 pointMap[p] = pp;
Chris@631 530 }
Chris@631 531
Chris@1113 532 for (map<RegionModel::Point, RegionModel::Point>::iterator i =
Chris@631 533 pointMap.begin(); i != pointMap.end(); ++i) {
Chris@1113 534 // There could be duplicate regions; if so replace
Chris@1113 535 // them all -- but we need to check we're not
Chris@1113 536 // replacing a region by itself (or else this will
Chris@1113 537 // never terminate)
Chris@1113 538 if (i->first.value == i->second.value) {
Chris@1113 539 continue;
Chris@1113 540 }
Chris@1113 541 while (model2a->containsPoint(i->first)) {
Chris@1113 542 model2a->deletePoint(i->first);
Chris@1113 543 model2a->addPoint(i->second);
Chris@1113 544 }
Chris@631 545 }
Chris@631 546 }
Chris@631 547 }
Chris@631 548
Chris@897 549 if (model2b) {
Chris@897 550 if (pitchLooksLikeMIDI) {
Chris@897 551 model2b->setScaleUnits("MIDI Pitch");
Chris@897 552 } else {
Chris@897 553 model2b->setScaleUnits("Hz");
Chris@897 554 }
Chris@897 555 }
Chris@897 556
Chris@961 557 if (model3) {
Chris@1429 558 model3->setMinimumLevel(min);
Chris@1429 559 model3->setMaximumLevel(max);
Chris@148 560 }
Chris@148 561
Chris@1489 562 if (modelW) {
Chris@1489 563 modelW->writeComplete();
Chris@1489 564 }
Chris@1489 565
Chris@148 566 return model;
Chris@148 567 }
Chris@148 568