annotate data/fileio/CSVFileReader.cpp @ 1518:9c09a3f05139 import-audio-data

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