642ab87dce35 — Chris Cannam 10 years ago
Merge
3 files changed, 119 insertions(+), 18 deletions(-)

M src/AudioReadStream.cpp
M src/AudioReadStream.h
M src/test/TestAudioStreamRead.h
M src/AudioReadStream.cpp +7 -0
@@ 45,6 45,13 @@ AudioReadStream::setRetrievalSampleRate(
 }
 
 size_t
+AudioReadStream::getRetrievalSampleRate() const
+{
+    if (m_retrievalRate == 0) return m_sampleRate;
+    else return m_retrievalRate;
+}
+
+size_t
 AudioReadStream::getInterleavedFrames(size_t count, float *frames)
 {
     if (m_retrievalRate == 0 ||

          
M src/AudioReadStream.h +2 -1
@@ 35,9 35,10 @@ public:
     virtual QString getError() const { return ""; }
 
     size_t getChannelCount() const { return m_channelCount; }
-    size_t getSampleRate() const { return m_sampleRate; }
+    size_t getSampleRate() const { return m_sampleRate; } // source stream rate
     
     void setRetrievalSampleRate(size_t);
+    size_t getRetrievalSampleRate() const;
 
     /**
      * Retrieve \count frames of audio data (that is, \count *

          
M src/test/TestAudioStreamRead.h +110 -17
@@ 52,43 52,136 @@ private slots:
     void read()
     {
         QFETCH(QString, audiofile);
+
+        std::cerr << "\n\n*** audiofile = " << audiofile << "\n\n" << std::endl;
+
         try {
 
+            int readRate = 48000;
+
             AudioReadStream *stream =
                 AudioReadStreamFactory::createReadStream
                 (audioDir + "/" + audiofile);
 
-            stream->setRetrievalSampleRate(48000);
+            stream->setRetrievalSampleRate(readRate);
             int channels = stream->getChannelCount();
-            AudioStreamTestData tdata(48000, channels);
+            AudioStreamTestData tdata(readRate, channels);
+
+            QStringList fileAndExt = audiofile.split(".");
+            QStringList bits = fileAndExt[0].split("-");
+            QString extension = fileAndExt[1];
+            int nominalRate = bits[0].toInt();
+            int nominalChannels = bits[1].toInt();
+            int nominalDepth = 16;
+            if (bits.length() > 2) nominalDepth = bits[2].toInt();
+
+            QCOMPARE(channels, nominalChannels);
+
+            QCOMPARE((int)stream->getSampleRate(), nominalRate);
+            QCOMPARE((int)stream->getRetrievalSampleRate(), readRate);
 
             float *reference = tdata.getInterleavedData();
-            int refsize = tdata.getFrameCount() * channels;
+            int refFrames = tdata.getFrameCount();
+            
+            // The reader should give us exactly the expected number of
+            // frames, except for mp3/aac files. We ask for quite a lot
+            // more, though, so we can (a) check that we only get the
+            // expected number back (if this is not mp3/aac) or (b) take
+            // into account silence at beginning and end (if it is).
+            int testFrames = refFrames + 5000;
+            int testsize = testFrames * channels;
+            
+            float *test = new float[testsize];
+	
+            int read = stream->getInterleavedFrames(testFrames, test);
 
-            float *test = new float[refsize];
+            if (extension == "mp3" || extension == "aac" || extension == "m4a") {
+                // mp3s and aacs can have silence at start and end
+                QVERIFY(read >= refFrames);
+            } else {
+                QCOMPARE(read, refFrames);
+            }
+
+            // Our limits are pretty relaxed -- we're not testing decoder
+            // or resampler quality here, just whether the results are
+            // plainly wrong (e.g. at wrong samplerate or with an offset)
+
+            float limit = 0.01;
+            float edgeLimit = limit * 10; // in first or final edgeSize frames
+            int edgeSize = 100; 
 
-            // The stream should give us exactly the expected number
-            // of frames -- so we ask for one more, just to check we
-            // don't get it!
-            int read = stream->getInterleavedFrames
-                (tdata.getFrameCount() + 1, test);
-            
-            QCOMPARE(read, tdata.getFrameCount());
-            
+            if (nominalDepth < 16) {
+                limit = 0.02;
+            }
+            if (extension == "ogg" || extension == "mp3" ||
+                extension == "aac" || extension == "m4a") {
+                limit = 0.2;
+                edgeLimit = limit * 3;
+            }
+
+            // And we ignore completely the last few frames when upsampling
+            int discard = 1 + readRate / nominalRate;
+
+            int offset = 0;
+
+            if (extension == "aac" || extension == "m4a") {
+                // our m4a file appears to have a fixed offset of 1024 (at
+                // file sample rate)
+                offset = (1024 / float(nominalRate)) * readRate;
+            }
+
+            if (extension == "mp3") {
+                // while mp3s appear to vary
+                for (int i = 0; i < read; ++i) {
+                    bool any = false;
+                    float thresh = 0.01;
+                    for (int c = 0; c < channels; ++c) {
+                        if (fabsf(test[i * channels + c]) > thresh) {
+                            any = true;
+                            break;
+                        }
+                    }
+                    if (any) {
+                        offset = i;
+                        break;
+                    }
+                }
+            }
+
             for (int c = 0; c < channels; ++c) {
                 float maxdiff = 0.f;
+                int maxAt = 0;
                 float totdiff = 0.f;
-                for (int i = 0; i < read; ++i) {
-                    float diff = fabsf(test[i * channels + c] -
+                for (int i = 0; i < read - offset - discard && i < refFrames; ++i) {
+                    float diff = fabsf(test[(i + offset) * channels + c] -
                                        reference[i * channels + c]);
                     totdiff += diff;
-                    if (diff > maxdiff) maxdiff = diff;
+                    // in edge areas, record this only if it exceeds edgeLimit
+                    if (i < edgeSize || i + edgeSize >= read - offset) {
+                        if (diff > edgeLimit) {
+                            maxdiff = diff;
+                            maxAt = i;
+                        }
+                    } else {
+                        if (diff > maxdiff) {
+                            maxdiff = diff;
+                            maxAt = i;
+                        }
+                    }
                 }
                 float meandiff = totdiff / read;
-                std::cerr << "meandiff on channel " << c << ": " << meandiff << std::endl;
-                std::cerr << "maxdiff on channel " << c << ": " << maxdiff << std::endl;
+                if (meandiff >= limit) {
+                    std::cerr << "ERROR: for audiofile " << audiofile << ": mean diff = " << meandiff << " for channel " << c << std::endl;
+                    QVERIFY(meandiff < limit);
+                }
+                if (maxdiff >= limit) {
+                    std::cerr << "ERROR: for audiofile " << audiofile << ": max diff = " << maxdiff << " at frame " << maxAt << " of " << read << " on channel " << c << " (mean diff = " << meandiff << ")" << std::endl;
+                    QVERIFY(maxdiff < limit);
+                }
             }
 
+            delete[] test;
+
         } catch (UnknownFileType &t) {
             QSKIP(strOf(QString("File format for \"%1\" not supported, skipping").arg(audiofile)), SkipSingle);
         }