diff data/fileio/test/EncodingTest.h @ 1527:710e6250a401 zoom

Merge from default branch
author Chris Cannam
date Mon, 17 Sep 2018 13:51:14 +0100
parents 87ae75da6527
children 0773b34d987f
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/fileio/test/EncodingTest.h	Mon Sep 17 13:51:14 2018 +0100
@@ -0,0 +1,267 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    Sonic Visualiser
+    An audio file viewer and annotation editor.
+    Centre for Digital Music, Queen Mary, University of London.
+    
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.  See the file
+    COPYING included with this distribution for more information.
+*/
+
+#ifndef TEST_AUDIO_ENCODINGS_H
+#define TEST_AUDIO_ENCODINGS_H
+
+// Quick tests for filename encodings and encoding of ID3 data. Not a
+// test of audio codecs.
+
+#include "../AudioFileReaderFactory.h"
+#include "../AudioFileReader.h"
+#include "../WavFileWriter.h"
+
+#include <cmath>
+
+#include <QObject>
+#include <QtTest>
+#include <QDir>
+
+#include <iostream>
+
+using namespace std;
+
+const char utf8_name_cdp_1[] = "Caf\303\251 de Paris";
+const char utf8_name_cdp_2[] = "Caf\303\251 de \351\207\215\345\272\206";
+const char utf8_name_tsprk[] = "T\303\253mple of Sp\303\266rks";
+const char utf8_name_sprkt[] = "\343\202\271\343\203\235\343\203\274\343\202\257\343\201\256\345\257\272\351\231\242";
+
+// Mapping between filename and expected title metadata field
+static const char *mapping[][2] = {
+    { "id3v2-iso-8859-1", utf8_name_cdp_1 },
+    { "id3v2-ucs-2", utf8_name_cdp_2 },
+    { utf8_name_tsprk, utf8_name_tsprk },
+    { utf8_name_sprkt, utf8_name_sprkt },
+};
+static const int mappingCount = 4;
+
+class EncodingTest : public QObject
+{
+    Q_OBJECT
+
+private:
+    QString testDirBase;
+    QString encodingDir;
+    QString outDir;
+
+public:
+    EncodingTest(QString base) {
+        if (base == "") {
+            base = "svcore/data/fileio/test";
+        }
+        testDirBase = base;
+        encodingDir = base + "/encodings";
+        outDir = base + "/outfiles";
+    }
+
+private:
+    const char *strOf(QString s) {
+        return strdup(s.toLocal8Bit().data());
+    }
+
+    void addAudioFiles() {
+        QTest::addColumn<QString>("audiofile");
+        QStringList files = QDir(encodingDir).entryList(QDir::Files);
+        foreach (QString filename, files) {
+            QTest::newRow(strOf(filename)) << filename;
+        }
+    }
+
+private slots:
+    void init()
+    {
+        if (!QDir(encodingDir).exists()) {
+            SVCERR << "ERROR: Audio encoding file directory \"" << encodingDir << "\" does not exist" << endl;
+            QVERIFY2(QDir(encodingDir).exists(), "Audio encoding file directory not found");
+        }
+        if (!QDir(outDir).exists() && !QDir().mkpath(outDir)) {
+            SVCERR << "ERROR: Audio out directory \"" << outDir << "\" does not exist and could not be created" << endl;
+            QVERIFY2(QDir(outDir).exists(), "Audio out directory not found and could not be created");
+        }
+    }
+
+    void readAudio_data() {
+        addAudioFiles();
+    }
+
+    void readAudio() {
+
+        // Ensure that we can open all the files
+        
+        QFETCH(QString, audiofile);
+
+        AudioFileReaderFactory::Parameters params;
+        AudioFileReader *reader =
+            AudioFileReaderFactory::createReader
+            (encodingDir + "/" + audiofile, params);
+
+        QVERIFY(reader != nullptr);
+
+        delete reader;
+    }
+
+    void readMetadata_data() {
+        addAudioFiles();
+    }
+    
+    void readMetadata() {
+        
+        // All files other than WAVs should have title metadata; check
+        // that the title matches whatever is in our mapping structure
+        // defined at the top
+        
+        QFETCH(QString, audiofile);
+
+        AudioFileReaderFactory::Parameters params;
+        AudioFileReader *reader =
+            AudioFileReaderFactory::createReader
+            (encodingDir + "/" + audiofile, params);
+
+        QVERIFY(reader != nullptr);
+
+        QStringList fileAndExt = audiofile.split(".");
+        QString file = fileAndExt[0];
+        QString extension = fileAndExt[1];
+
+        if (extension == "wav") {
+
+            // Nothing
+            
+            delete reader;
+
+        } else {
+
+#if (!defined (HAVE_OGGZ) || !defined(HAVE_FISHSOUND))
+            if (extension == "ogg") {
+                QSKIP("Lack native Ogg Vorbis reader, so won't be getting metadata");
+            }
+#endif
+            
+            auto blah = reader->getInterleavedFrames(0, 10);
+            
+            QString title = reader->getTitle();
+            QVERIFY(title != QString());
+
+            delete reader;
+
+            bool found = false;
+            for (int m = 0; m < mappingCount; ++m) {
+                if (file == QString::fromUtf8(mapping[m][0])) {
+                    found = true;
+                    QString expected = QString::fromUtf8(mapping[m][1]);
+                    if (title != expected) {
+                        SVCERR << "Title does not match expected: codepoints are" << endl;
+                        SVCERR << "Title (" << title.length() << "ch): ";
+                        for (int i = 0; i < title.length(); ++i) {
+                            SVCERR << title[i].unicode() << " ";
+                        }
+                        SVCERR << endl;
+                        SVCERR << "Expected (" << expected.length() << "ch): ";
+                        for (int i = 0; i < expected.length(); ++i) {
+                            SVCERR << expected[i].unicode() << " ";
+                        }
+                        SVCERR << endl;
+                    }
+                    QCOMPARE(title, expected);
+                    break;
+                }
+            }
+
+            if (!found) {
+                // Note that this can happen legitimately on Windows,
+                // where (for annoying VCS-related reasons) the test
+                // files may have a different filename encoding from
+                // the expected UTF-16. We check this properly in
+                // readWriteAudio below, by saving out the file to a
+                // name matching the metadata
+                SVCERR << "Couldn't find filename \""
+                     << file << "\" in title mapping array" << endl;
+                QSKIP("Couldn't find filename in title mapping array");
+            }
+        }
+    }
+
+    void readWriteAudio_data() {
+        addAudioFiles();
+    }
+
+    void readWriteAudio()
+    {
+        // For those files that have title metadata (i.e. all of them
+        // except the WAVs), read the title metadata and write a wav
+        // file (of arbitrary content) whose name matches that.  Then
+        // check that we can re-read it. This is intended to exercise
+        // systems on which the original test filename is miscoded (as
+        // can happen on Windows).
+        
+        QFETCH(QString, audiofile);
+
+        QStringList fileAndExt = audiofile.split(".");
+        QString file = fileAndExt[0];
+        QString extension = fileAndExt[1];
+
+        if (extension == "wav") {
+            return;
+        }
+
+#if (!defined (HAVE_OGGZ) || !defined(HAVE_FISHSOUND))
+        if (extension == "ogg") {
+            QSKIP("Lack native Ogg Vorbis reader, so won't be getting metadata");
+        }
+#endif
+
+        AudioFileReaderFactory::Parameters params;
+        AudioFileReader *reader =
+            AudioFileReaderFactory::createReader
+            (encodingDir + "/" + audiofile, params);
+        QVERIFY(reader != nullptr);
+
+        QString title = reader->getTitle();
+        QVERIFY(title != QString());
+
+        for (int useTemporary = 0; useTemporary <= 1; ++useTemporary) {
+        
+            QString outfile = outDir + "/" + file + ".wav";
+            WavFileWriter writer(outfile,
+                                 reader->getSampleRate(),
+                                 1,
+                                 useTemporary ?
+                                 WavFileWriter::WriteToTemporary :
+                                 WavFileWriter::WriteToTarget);
+
+            QVERIFY(writer.isOK());
+
+            floatvec_t data { 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0 };
+            const float *samples = data.data();
+            bool ok = writer.writeSamples(&samples, 8);
+            QVERIFY(ok);
+
+            ok = writer.close();
+            QVERIFY(ok);
+
+            AudioFileReader *rereader =
+                AudioFileReaderFactory::createReader(outfile, params);
+            QVERIFY(rereader != nullptr);
+
+            floatvec_t readFrames = rereader->getInterleavedFrames(0, 8);
+            QCOMPARE(readFrames, data);
+
+            delete rereader;
+        }
+
+        delete reader;
+    }
+};
+
+#endif