annotate data/fileio/test/AudioFileReaderTest.h @ 1833:21c792334c2e sensible-delimited-data-strings

Rewrite all the DelimitedDataString stuff so as to return vectors of individual cell strings rather than having the classes add the delimiters themselves. Rename accordingly to names based on StringExport. Take advantage of this in the CSV writer code so as to properly quote cells that contain delimiter characters.
author Chris Cannam
date Fri, 03 Apr 2020 17:11:05 +0100
parents 83cb6e9d769b
children
rev   line source
Chris@756 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@756 2
Chris@756 3 /*
Chris@756 4 Sonic Visualiser
Chris@756 5 An audio file viewer and annotation editor.
Chris@756 6 Centre for Digital Music, Queen Mary, University of London.
Chris@756 7 This file copyright 2013 Chris Cannam.
Chris@756 8
Chris@756 9 This program is free software; you can redistribute it and/or
Chris@756 10 modify it under the terms of the GNU General Public License as
Chris@756 11 published by the Free Software Foundation; either version 2 of the
Chris@756 12 License, or (at your option) any later version. See the file
Chris@756 13 COPYING included with this distribution for more information.
Chris@756 14 */
Chris@756 15
Chris@756 16 #ifndef TEST_AUDIO_FILE_READER_H
Chris@756 17 #define TEST_AUDIO_FILE_READER_H
Chris@756 18
Chris@756 19 #include "../AudioFileReaderFactory.h"
Chris@756 20 #include "../AudioFileReader.h"
Chris@1313 21 #include "../WavFileWriter.h"
Chris@756 22
Chris@756 23 #include "AudioTestData.h"
Chris@1698 24 #include "UnsupportedFormat.h"
Chris@756 25
Chris@756 26 #include <cmath>
Chris@756 27
Chris@756 28 #include <QObject>
Chris@756 29 #include <QtTest>
Chris@756 30 #include <QDir>
Chris@756 31
Chris@756 32 #include <iostream>
Chris@756 33
Chris@756 34 using namespace std;
Chris@756 35
Chris@756 36 class AudioFileReaderTest : public QObject
Chris@756 37 {
Chris@756 38 Q_OBJECT
Chris@756 39
Chris@1346 40 private:
Chris@1346 41 QString testDirBase;
Chris@1346 42 QString audioDir;
Chris@1346 43 QString diffDir;
Chris@1346 44
Chris@1346 45 public:
Chris@1346 46 AudioFileReaderTest(QString base) {
Chris@1346 47 if (base == "") {
Chris@1346 48 base = "svcore/data/fileio/test";
Chris@1346 49 }
Chris@1346 50 testDirBase = base;
Chris@1359 51 audioDir = base + "/audio";
Chris@1346 52 diffDir = base + "/diffs";
Chris@1346 53 }
Chris@1346 54
Chris@1346 55 private:
Chris@756 56 const char *strOf(QString s) {
Chris@756 57 return strdup(s.toLocal8Bit().data());
Chris@756 58 }
Chris@756 59
Chris@1313 60 void getFileMetadata(QString filename,
Chris@1313 61 QString &extension,
Chris@1313 62 sv_samplerate_t &rate,
Chris@1313 63 int &channels,
Chris@1313 64 int &bitdepth) {
Chris@1313 65
Chris@1313 66 QStringList fileAndExt = filename.split(".");
Chris@1313 67 QStringList bits = fileAndExt[0].split("-");
Chris@1313 68
Chris@1313 69 extension = fileAndExt[1];
Chris@1313 70 rate = bits[0].toInt();
Chris@1313 71 channels = bits[1].toInt();
Chris@1313 72 bitdepth = 16;
Chris@1313 73 if (bits.length() > 2) {
Chris@1313 74 bitdepth = bits[2].toInt();
Chris@1313 75 }
Chris@1313 76 }
Chris@1698 77
cannam@1315 78 void getExpectedThresholds(QString format,
cannam@1315 79 QString filename,
Chris@1313 80 bool resampled,
Chris@1313 81 bool gapless,
Chris@1313 82 bool normalised,
Chris@1313 83 double &maxLimit,
Chris@1313 84 double &rmsLimit) {
Chris@1313 85
Chris@1313 86 QString extension;
Chris@1313 87 sv_samplerate_t fileRate;
Chris@1313 88 int channels;
Chris@1313 89 int bitdepth;
Chris@1313 90 getFileMetadata(filename, extension, fileRate, channels, bitdepth);
Chris@1313 91
Chris@1313 92 if (normalised) {
Chris@1313 93
cannam@1315 94 if (format == "ogg") {
Chris@1313 95
Chris@1313 96 // Our ogg is not especially high quality and is
Chris@1313 97 // actually further from the original if normalised
Chris@1313 98
Chris@1313 99 maxLimit = 0.1;
Chris@1313 100 rmsLimit = 0.03;
Chris@1313 101
Chris@1598 102 } else if (format == "opus") {
Chris@1598 103
Chris@1598 104 maxLimit = 0.06;
Chris@1598 105 rmsLimit = 0.015;
Chris@1598 106
cannam@1315 107 } else if (format == "aac") {
Chris@1313 108
cannam@1315 109 // Terrible performance for this test, load of spill
cannam@1315 110 // from one channel to the other. I guess they know
cannam@1315 111 // what they're doing, it's perceptual after all, but
cannam@1315 112 // it does make this check a bit superfluous, you
cannam@1315 113 // could probably pass it with a signal that sounds
cannam@1315 114 // nothing like the original
cannam@1315 115 maxLimit = 0.2;
cannam@1314 116 rmsLimit = 0.1;
Chris@1313 117
Chris@1603 118 } else if (format == "wma") {
Chris@1603 119
Chris@1603 120 maxLimit = 0.05;
Chris@1603 121 rmsLimit = 0.01;
Chris@1603 122
cannam@1315 123 } else if (format == "mp3") {
Chris@1313 124
Chris@1313 125 if (resampled && !gapless) {
Chris@1313 126
Chris@1313 127 // We expect worse figures here, because the
Chris@1313 128 // combination of uncompensated encoder delay +
Chris@1313 129 // resampling results in a fractional delay which
Chris@1313 130 // means the decoded signal is slightly out of
Chris@1313 131 // phase compared to the test signal
Chris@1313 132
Chris@1313 133 maxLimit = 0.1;
Chris@1313 134 rmsLimit = 0.05;
Chris@1313 135
Chris@1313 136 } else {
Chris@1313 137
Chris@1313 138 maxLimit = 0.05;
Chris@1313 139 rmsLimit = 0.01;
Chris@1313 140 }
Chris@1313 141
Chris@1313 142 } else {
Chris@1313 143
cannam@1315 144 // lossless formats (wav, aiff, flac, apple_lossless)
Chris@1313 145
Chris@1313 146 if (bitdepth >= 16 && !resampled) {
Chris@1313 147 maxLimit = 1e-3;
Chris@1313 148 rmsLimit = 3e-4;
Chris@1313 149 } else {
Chris@1313 150 maxLimit = 0.01;
Chris@1313 151 rmsLimit = 5e-3;
Chris@1313 152 }
Chris@1313 153 }
Chris@1313 154
Chris@1313 155 } else { // !normalised
Chris@1313 156
cannam@1315 157 if (format == "ogg") {
Chris@1313 158
Chris@1313 159 maxLimit = 0.06;
Chris@1313 160 rmsLimit = 0.03;
Chris@1313 161
Chris@1598 162 } else if (format == "opus") {
Chris@1598 163
Chris@1598 164 maxLimit = 0.06;
Chris@1598 165 rmsLimit = 0.015;
Chris@1598 166
cannam@1315 167 } else if (format == "aac") {
Chris@1313 168
Chris@1603 169 maxLimit = 0.2;
cannam@1315 170 rmsLimit = 0.1;
Chris@1313 171
Chris@1603 172 } else if (format == "wma") {
Chris@1603 173
Chris@1603 174 maxLimit = 0.05;
Chris@1603 175 rmsLimit = 0.01;
Chris@1603 176
cannam@1315 177 } else if (format == "mp3") {
Chris@1313 178
Chris@1313 179 // all mp3 figures are worse when not normalising
Chris@1313 180 maxLimit = 0.1;
Chris@1313 181 rmsLimit = 0.05;
Chris@1313 182
Chris@1313 183 } else {
Chris@1313 184
cannam@1315 185 // lossless formats (wav, aiff, flac, apple_lossless)
Chris@1313 186
Chris@1313 187 if (bitdepth >= 16 && !resampled) {
Chris@1313 188 maxLimit = 1e-3;
Chris@1313 189 rmsLimit = 3e-4;
Chris@1313 190 } else {
Chris@1313 191 maxLimit = 0.02;
Chris@1313 192 rmsLimit = 0.01;
Chris@1313 193 }
Chris@1313 194 }
Chris@1313 195 }
Chris@1313 196 }
Chris@1313 197
cannam@1315 198 QString testName(QString format, QString filename, int rate, bool norm, bool gapless) {
cannam@1315 199 return QString("%1/%2 at %3%4%5")
cannam@1315 200 .arg(format)
Chris@1313 201 .arg(filename)
Chris@1313 202 .arg(rate)
Chris@1313 203 .arg(norm ? " normalised": "")
Chris@1313 204 .arg(gapless ? "" : " non-gapless");
Chris@1313 205 }
Chris@1313 206
Chris@756 207 private slots:
Chris@756 208 void init()
Chris@756 209 {
Chris@756 210 if (!QDir(audioDir).exists()) {
Chris@1346 211 QString cwd = QDir::currentPath();
Chris@1428 212 SVCERR << "ERROR: Audio test file directory \"" << audioDir << "\" does not exist (cwd = " << cwd << ")" << endl;
Chris@756 213 QVERIFY2(QDir(audioDir).exists(), "Audio test file directory not found");
Chris@756 214 }
Chris@1313 215 if (!QDir(diffDir).exists() && !QDir().mkpath(diffDir)) {
Chris@1428 216 SVCERR << "ERROR: Audio diff directory \"" << diffDir << "\" does not exist and could not be created" << endl;
Chris@1313 217 QVERIFY2(QDir(diffDir).exists(), "Audio diff directory not found and could not be created");
Chris@1313 218 }
Chris@756 219 }
Chris@756 220
Chris@756 221 void read_data()
Chris@756 222 {
cannam@1315 223 QTest::addColumn<QString>("format");
Chris@756 224 QTest::addColumn<QString>("audiofile");
Chris@1313 225 QTest::addColumn<int>("rate");
Chris@1313 226 QTest::addColumn<bool>("normalised");
Chris@1313 227 QTest::addColumn<bool>("gapless");
cannam@1315 228 QStringList dirs = QDir(audioDir).entryList(QDir::Dirs |
cannam@1315 229 QDir::NoDotAndDotDot);
cannam@1315 230 for (QString format: dirs) {
cannam@1315 231 QStringList files = QDir(QDir(audioDir).filePath(format))
cannam@1315 232 .entryList(QDir::Files);
cannam@1315 233 int readRates[] = { 44100, 48000 };
cannam@1315 234 bool norms[] = { false, true };
cannam@1315 235 bool gaplesses[] = { true, false };
cannam@1315 236 foreach (QString filename, files) {
cannam@1315 237 for (int rate: readRates) {
cannam@1315 238 for (bool norm: norms) {
cannam@1315 239 for (bool gapless: gaplesses) {
Chris@1313 240
Chris@1603 241 #ifdef Q_OS_WIN
Chris@1603 242 if (format == "aac") {
Chris@1603 243 if (gapless) {
Chris@1603 244 // Apparently no support for AAC
Chris@1603 245 // encoder delay compensation in
Chris@1603 246 // MediaFoundation, so these tests
Chris@1603 247 // are only available non-gapless
Chris@1603 248 continue;
Chris@1603 249 }
Chris@1603 250 } else if (format != "mp3") {
Chris@1603 251 if (!gapless) {
Chris@1603 252 // All other formats but mp3 are
Chris@1603 253 // intrinsically gapless, so we
Chris@1603 254 // can skip the non-gapless option
Chris@1603 255 continue;
Chris@1603 256 }
cannam@1315 257 }
Chris@1603 258 #else
Chris@1603 259 if (format != "mp3") {
Chris@1603 260 if (!gapless) {
Chris@1603 261 // All other formats but mp3 are
Chris@1603 262 // intrinsically gapless
Chris@1603 263 // everywhere except for Windows
Chris@1603 264 // (see above), so we can skip the
Chris@1603 265 // non-gapless option
Chris@1603 266 continue;
Chris@1603 267 }
Chris@1603 268 }
Chris@1603 269 #endif
cannam@1315 270
cannam@1315 271 QString desc = testName
cannam@1315 272 (format, filename, rate, norm, gapless);
cannam@1315 273
cannam@1315 274 QTest::newRow(strOf(desc))
cannam@1315 275 << format << filename << rate << norm << gapless;
Chris@1313 276 }
Chris@1313 277 }
Chris@1313 278 }
Chris@1313 279 }
Chris@756 280 }
Chris@756 281 }
Chris@756 282
Chris@756 283 void read()
Chris@756 284 {
cannam@1315 285 QFETCH(QString, format);
Chris@756 286 QFETCH(QString, audiofile);
Chris@1313 287 QFETCH(int, rate);
Chris@1313 288 QFETCH(bool, normalised);
Chris@1313 289 QFETCH(bool, gapless);
Chris@756 290
Chris@1313 291 sv_samplerate_t readRate(rate);
Chris@1313 292
cannam@1315 293 // cerr << "\naudiofile = " << audiofile << endl;
Chris@1313 294
Chris@1313 295 AudioFileReaderFactory::Parameters params;
Chris@1313 296 params.targetRate = readRate;
Chris@1313 297 params.normalisation = (normalised ?
Chris@1313 298 AudioFileReaderFactory::Normalisation::Peak :
Chris@1313 299 AudioFileReaderFactory::Normalisation::None);
Chris@1313 300 params.gaplessMode = (gapless ?
Chris@1313 301 AudioFileReaderFactory::GaplessMode::Gapless :
Chris@1313 302 AudioFileReaderFactory::GaplessMode::Gappy);
Chris@757 303
Chris@1429 304 AudioFileReader *reader =
Chris@1429 305 AudioFileReaderFactory::createReader
Chris@1429 306 (audioDir + "/" + format + "/" + audiofile, params);
Chris@1313 307
Chris@1429 308 if (!reader) {
Chris@1714 309 if (UnsupportedFormat::isLegitimatelyUnsupported(format)) {
Chris@820 310 #if ( QT_VERSION >= 0x050000 )
Chris@1698 311 QSKIP("Unsupported file, skipping");
Chris@820 312 #else
Chris@1698 313 QSKIP("Unsupported file, skipping", SkipSingle);
Chris@820 314 #endif
Chris@1698 315 }
Chris@1429 316 }
Chris@756 317
cannam@1700 318 QVERIFY(reader != nullptr);
cannam@1700 319
Chris@1313 320 QString extension;
Chris@1313 321 sv_samplerate_t fileRate;
Chris@1313 322 int channels;
Chris@1313 323 int fileBitdepth;
Chris@1313 324 getFileMetadata(audiofile, extension, fileRate, channels, fileBitdepth);
Chris@1313 325
Chris@1313 326 QCOMPARE((int)reader->getChannelCount(), channels);
Chris@1313 327 QCOMPARE(reader->getNativeRate(), fileRate);
Chris@1040 328 QCOMPARE(reader->getSampleRate(), readRate);
Chris@757 329
Chris@1429 330 AudioTestData tdata(readRate, channels);
Chris@1429 331
Chris@1429 332 float *reference = tdata.getInterleavedData();
Chris@1040 333 sv_frame_t refFrames = tdata.getFrameCount();
Chris@1429 334
Chris@1429 335 // The reader should give us exactly the expected number of
Chris@1429 336 // frames, except for mp3/aac files. We ask for quite a lot
Chris@1429 337 // more, though, so we can (a) check that we only get the
Chris@1429 338 // expected number back (if this is not mp3/aac) or (b) take
Chris@1429 339 // into account silence at beginning and end (if it is).
Chris@1429 340 floatvec_t test = reader->getInterleavedFrames(0, refFrames + 5000);
Chris@1402 341
Chris@1402 342 delete reader;
Chris@1402 343 reader = 0;
Chris@1402 344
Chris@1429 345 sv_frame_t read = test.size() / channels;
Chris@756 346
Chris@1313 347 bool perceptual = (extension == "mp3" ||
Chris@1313 348 extension == "aac" ||
Chris@1598 349 extension == "m4a" ||
Chris@1603 350 extension == "wma" ||
Chris@1598 351 extension == "opus");
Chris@1313 352
Chris@1313 353 if (perceptual && !gapless) {
Chris@1313 354 // allow silence at start and end
Chris@759 355 QVERIFY(read >= refFrames);
Chris@757 356 } else {
Chris@759 357 QCOMPARE(read, refFrames);
Chris@757 358 }
Chris@757 359
Chris@1313 360 bool resampled = readRate != fileRate;
Chris@1313 361 double maxLimit, rmsLimit;
cannam@1315 362 getExpectedThresholds(format,
cannam@1315 363 audiofile,
Chris@1313 364 resampled,
Chris@1313 365 gapless,
Chris@1313 366 normalised,
Chris@1313 367 maxLimit, rmsLimit);
Chris@1313 368
Chris@1313 369 double edgeLimit = maxLimit * 3; // in first or final edgeSize frames
Chris@1313 370 if (resampled && edgeLimit < 0.1) edgeLimit = 0.1;
Chris@759 371 int edgeSize = 100;
Chris@759 372
Chris@759 373 // And we ignore completely the last few frames when upsampling
Chris@1313 374 int discard = 1 + int(round(readRate / fileRate));
Chris@759 375
Chris@759 376 int offset = 0;
Chris@759 377
Chris@1313 378 if (perceptual) {
Chris@759 379
cannam@1314 380 // Look for an initial offset.
cannam@1314 381 //
cannam@1314 382 // We know the first channel has a sinusoid in it. It
cannam@1314 383 // should have a peak at 0.4ms (see AudioTestData.h) but
cannam@1314 384 // that might have been clipped, which would make it
cannam@1314 385 // imprecise. We can tell if it's clipped, though, as
cannam@1314 386 // there will be samples having exactly identical
cannam@1314 387 // values. So what we look for is the peak if it's not
cannam@1314 388 // clipped and, if it is, the first zero crossing after
cannam@1314 389 // the peak, which should be at 0.8ms.
cannam@1314 390
Chris@1296 391 int expectedPeak = int(0.0004 * readRate);
cannam@1314 392 int expectedZC = int(0.0008 * readRate);
cannam@1314 393 bool foundPeak = false;
cannam@1314 394 for (int i = 1; i+1 < read; ++i) {
cannam@1314 395 float prevSample = test[(i-1) * channels];
cannam@1314 396 float thisSample = test[i * channels];
cannam@1314 397 float nextSample = test[(i+1) * channels];
cannam@1314 398 if (thisSample > 0.8 && nextSample < thisSample) {
cannam@1314 399 foundPeak = true;
cannam@1314 400 if (thisSample > prevSample) {
cannam@1314 401 // not clipped
cannam@1314 402 offset = i - expectedPeak - 1;
cannam@1314 403 break;
cannam@1314 404 }
cannam@1314 405 }
cannam@1314 406 if (foundPeak && (thisSample >= 0.0 && nextSample < 0.0)) {
cannam@1315 407 // cerr << "thisSample = " << thisSample << ", nextSample = "
cannam@1315 408 // << nextSample << endl;
cannam@1314 409 offset = i - expectedZC - 1;
Chris@759 410 break;
Chris@759 411 }
Chris@759 412 }
Chris@1313 413
cannam@1315 414 // int fileRateEquivalent = int((offset / readRate) * fileRate);
cannam@1315 415 // std::cerr << "offset = " << offset << std::endl;
cannam@1315 416 // std::cerr << "at file rate would be " << fileRateEquivalent << std::endl;
Chris@1313 417
Chris@1313 418 // Previously our m4a test file had a fixed offset of 1024
Chris@1313 419 // at the file sample rate -- this may be because it was
Chris@1313 420 // produced by FAAC which did not write in the delay as
Chris@1313 421 // metadata? We now have an m4a produced by Core Audio
Chris@1313 422 // which gives a 0 offset. What to do...
Chris@1313 423
Chris@1313 424 // Anyway, mp3s should have 0 offset in gapless mode and
Chris@1313 425 // "something else" otherwise.
Chris@1313 426
Chris@1313 427 if (gapless) {
Chris@1603 428 if (format == "aac"
Chris@1603 429 #ifdef Q_OS_WIN
Chris@1603 430 || (format == "mp3" && (readRate != fileRate))
Chris@1603 431 #endif
Chris@1603 432 ) {
cannam@1315 433 // ouch!
cannam@1315 434 if (offset == -1) offset = 0;
cannam@1315 435 }
Chris@1313 436 QCOMPARE(offset, 0);
Chris@1313 437 }
Chris@759 438 }
Chris@756 439
cannam@1315 440 {
cannam@1315 441 // Write the diff file now, so that it's already been written
cannam@1315 442 // even if the comparison fails. We aren't checking anything
cannam@1315 443 // here except as necessary to avoid buffer overruns etc
cannam@1315 444
cannam@1315 445 QString diffFile =
cannam@1315 446 testName(format, audiofile, rate, normalised, gapless);
cannam@1315 447 diffFile.replace("/", "_");
cannam@1315 448 diffFile.replace(".", "_");
cannam@1315 449 diffFile.replace(" ", "_");
cannam@1315 450 diffFile += ".wav";
cannam@1315 451 diffFile = QDir(diffDir).filePath(diffFile);
cannam@1315 452 WavFileWriter diffWriter(diffFile, readRate, channels,
Chris@1359 453 WavFileWriter::WriteToTemporary);
cannam@1315 454 QVERIFY(diffWriter.isOK());
cannam@1315 455
cannam@1315 456 vector<vector<float>> diffs(channels);
cannam@1315 457 for (int c = 0; c < channels; ++c) {
cannam@1315 458 for (int i = 0; i < refFrames; ++i) {
cannam@1315 459 int ix = i + offset;
cannam@1315 460 if (ix < read) {
cannam@1315 461 float signeddiff =
cannam@1315 462 test[ix * channels + c] -
cannam@1315 463 reference[i * channels + c];
cannam@1315 464 diffs[c].push_back(signeddiff);
cannam@1315 465 }
cannam@1315 466 }
cannam@1315 467 }
cannam@1315 468 float **ptrs = new float*[channels];
cannam@1315 469 for (int c = 0; c < channels; ++c) {
cannam@1315 470 ptrs[c] = diffs[c].data();
cannam@1315 471 }
cannam@1315 472 diffWriter.writeSamples(ptrs, refFrames);
cannam@1315 473 delete[] ptrs;
cannam@1315 474 }
Chris@1313 475
Chris@1346 476 for (int c = 0; c < channels; ++c) {
Chris@1313 477
Chris@1313 478 double maxDiff = 0.0;
Chris@1313 479 double totalDiff = 0.0;
Chris@1313 480 double totalSqrDiff = 0.0;
Chris@1346 481 int maxIndex = 0;
Chris@1313 482
Chris@1346 483 for (int i = 0; i < refFrames; ++i) {
Chris@1296 484 int ix = i + offset;
Chris@1296 485 if (ix >= read) {
Chris@1428 486 SVCERR << "ERROR: audiofile " << audiofile << " reads truncated (read-rate reference frames " << i << " onward, of " << refFrames << ", are lost)" << endl;
Chris@1296 487 QVERIFY(ix < read);
Chris@1296 488 }
Chris@1313 489
Chris@1296 490 if (ix + discard >= read) {
Chris@1296 491 // we forgive the very edge samples when
Chris@1296 492 // resampling (discard > 0)
Chris@1296 493 continue;
Chris@1296 494 }
Chris@1313 495
Chris@1346 496 double diff = fabs(test[ix * channels + c] -
cannam@1315 497 reference[i * channels + c]);
Chris@1313 498
Chris@1346 499 totalDiff += diff;
Chris@1313 500 totalSqrDiff += diff * diff;
Chris@1313 501
Chris@757 502 // in edge areas, record this only if it exceeds edgeLimit
Chris@1313 503 if (i < edgeSize || i + edgeSize >= refFrames) {
Chris@1313 504 if (diff > edgeLimit && diff > maxDiff) {
Chris@1313 505 maxDiff = diff;
Chris@1313 506 maxIndex = i;
Chris@757 507 }
Chris@757 508 } else {
Chris@1313 509 if (diff > maxDiff) {
Chris@1313 510 maxDiff = diff;
Chris@1313 511 maxIndex = i;
Chris@757 512 }
Chris@1346 513 }
Chris@1346 514 }
Chris@1313 515
Chris@1346 516 double meanDiff = totalDiff / double(refFrames);
Chris@1313 517 double rmsDiff = sqrt(totalSqrDiff / double(refFrames));
cannam@1308 518
cannam@1314 519 /*
Chris@1346 520 cerr << "channel " << c << ": mean diff " << meanDiff << endl;
Chris@1429 521 cerr << "channel " << c << ": rms diff " << rmsDiff << endl;
Chris@1429 522 cerr << "channel " << c << ": max diff " << maxDiff << " at " << maxIndex << endl;
cannam@1314 523 */
Chris@1313 524 if (rmsDiff >= rmsLimit) {
Chris@1428 525 SVCERR << "ERROR: for audiofile " << audiofile << ": RMS diff = " << rmsDiff << " for channel " << c << " (limit = " << rmsLimit << ")" << endl;
Chris@1313 526 QVERIFY(rmsDiff < rmsLimit);
Chris@1313 527 }
Chris@1346 528 if (maxDiff >= maxLimit) {
Chris@1428 529 SVCERR << "ERROR: for audiofile " << audiofile << ": max diff = " << maxDiff << " at frame " << maxIndex << " of " << read << " on channel " << c << " (limit = " << maxLimit << ", edge limit = " << edgeLimit << ", mean diff = " << meanDiff << ", rms = " << rmsDiff << ")" << endl;
Chris@1346 530 QVERIFY(maxDiff < maxLimit);
Chris@1346 531 }
Chris@1313 532
Chris@1313 533 // and check for spurious material at end
Chris@1313 534
Chris@1309 535 for (sv_frame_t i = refFrames; i + offset < read; ++i) {
Chris@1309 536 sv_frame_t ix = i + offset;
Chris@1323 537 float quiet = 0.1f; //!!! allow some ringing - but let's come back to this, it should tail off
cannam@1308 538 float mag = fabsf(test[ix * channels + c]);
cannam@1308 539 if (mag > quiet) {
Chris@1428 540 SVCERR << "ERROR: audiofile " << audiofile << " contains spurious data after end of reference (found sample " << test[ix * channels + c] << " at index " << ix << " of channel " << c << " after reference+offset ended at " << refFrames+offset << ")" << endl;
cannam@1308 541 QVERIFY(mag < quiet);
cannam@1308 542 }
cannam@1308 543 }
Chris@1429 544 }
Chris@756 545 }
Chris@756 546 };
Chris@756 547
Chris@756 548 #endif