annotate data/fileio/test/AudioFileReaderTest.h @ 1728:a47a23c824ac

Merge
author Chris Cannam
date Wed, 22 May 2019 15:37:44 +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