]> granicus.if.org Git - taglib/commitdiff
Add support for Ogg Opus
authorLukáš Lalinský <lalinsky@gmail.com>
Sat, 13 Oct 2012 06:55:23 +0000 (08:55 +0200)
committerLukáš Lalinský <lalinsky@gmail.com>
Sat, 13 Oct 2012 06:55:23 +0000 (08:55 +0200)
NEWS
taglib/CMakeLists.txt
taglib/fileref.cpp
taglib/ogg/opus/opusfile.cpp [new file with mode: 0644]
taglib/ogg/opus/opusfile.h [new file with mode: 0644]
taglib/ogg/opus/opusproperties.cpp [new file with mode: 0644]
taglib/ogg/opus/opusproperties.h [new file with mode: 0644]
taglib/toolkit/tfile.cpp
tests/CMakeLists.txt
tests/data/correctness_gain_silent_output.opus [new file with mode: 0644]
tests/test_opus.cpp [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 548e9baf5a3c6f021447009c31211f9886db9b1c..9432865a5cd8e76376f8c1f71af4653657164d56 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
 TagLib 1.9 (In Development)
 ==========================
 
+ * Added support for the Ogg Opus file format.
  * Added support for INFO tags in WAV files.
  * Changed FileStream to use Windows file API.
  * Included taglib-config.cmd script for Windows.
index ebb9165d9faded53e0140335f514df8eaad715aa..72712ca2ad915bdf8d90534ea3c06102b01fa4a7 100644 (file)
@@ -10,6 +10,7 @@ include_directories(
   ${CMAKE_CURRENT_SOURCE_DIR}/mp4
   ${CMAKE_CURRENT_SOURCE_DIR}/ogg/vorbis
   ${CMAKE_CURRENT_SOURCE_DIR}/ogg/speex
+  ${CMAKE_CURRENT_SOURCE_DIR}/ogg/opus
   ${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v2
   ${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v2/frames
   ${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v1
@@ -83,6 +84,8 @@ set(tag_HDRS
   ogg/flac/oggflacfile.h
   ogg/speex/speexfile.h
   ogg/speex/speexproperties.h
+  ogg/opus/opusfile.h
+  ogg/opus/opusproperties.h
   flac/flacfile.h
   flac/flacpicture.h
   flac/flacproperties.h
@@ -220,6 +223,11 @@ set(speex_SRCS
   ogg/speex/speexproperties.cpp
 )
 
+set(opus_SRCS
+  ogg/opus/opusfile.cpp
+  ogg/opus/opusproperties.cpp
+)
+
 set(trueaudio_SRCS
   trueaudio/trueaudiofile.cpp
   trueaudio/trueaudioproperties.cpp
@@ -288,7 +296,7 @@ set(tag_LIB_SRCS
   ${mpeg_SRCS} ${id3v1_SRCS} ${id3v2_SRCS} ${frames_SRCS} ${ogg_SRCS}
   ${vorbis_SRCS} ${oggflacs_SRCS} ${mpc_SRCS} ${ape_SRCS} ${toolkit_SRCS} ${flacs_SRCS}
   ${wavpack_SRCS} ${speex_SRCS} ${trueaudio_SRCS} ${riff_SRCS} ${aiff_SRCS} ${wav_SRCS}
-  ${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS}
+  ${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS} ${opus_SRCS}
   tag.cpp
   tagunion.cpp
   fileref.cpp
index 5c42ed4c1e6527603fb9547a0239fe9ec2c6b946..859f3155bd72993f824e5f6e46db320086d8c11a 100644 (file)
@@ -45,6 +45,7 @@
 #include "mp4file.h"
 #include "wavpackfile.h"
 #include "speexfile.h"
+#include "opusfile.h"
 #include "trueaudiofile.h"
 #include "aifffile.h"
 #include "wavfile.h"
@@ -252,6 +253,8 @@ File *FileRef::create(FileName fileName, bool readAudioProperties,
       return new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle);
     if(ext == "SPX")
       return new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle);
+    if(ext == "OPUS")
+      return new Ogg::Opus::File(fileName, readAudioProperties, audioPropertiesStyle);
     if(ext == "TTA")
       return new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle);
     if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2")
diff --git a/taglib/ogg/opus/opusfile.cpp b/taglib/ogg/opus/opusfile.cpp
new file mode 100644 (file)
index 0000000..836f89c
--- /dev/null
@@ -0,0 +1,128 @@
+/***************************************************************************
+    copyright            : (C) 2012 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+
+    copyright            : (C) 2002 - 2008 by Scott Wheeler
+    email                : wheeler@kde.org
+                           (original Vorbis implementation)
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA         *
+ *   02110-1301  USA                                                       *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#include <bitset>
+
+#include <tstring.h>
+#include <tdebug.h>
+
+#include "opusfile.h"
+
+using namespace TagLib;
+using namespace TagLib::Ogg;
+
+class Opus::File::FilePrivate
+{
+public:
+  FilePrivate() :
+    comment(0),
+    properties(0) {}
+
+  ~FilePrivate()
+  {
+    delete comment;
+    delete properties;
+  }
+
+  Ogg::XiphComment *comment;
+  Properties *properties;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// public members
+////////////////////////////////////////////////////////////////////////////////
+
+Opus::File::File(FileName file, bool readProperties,
+                   Properties::ReadStyle propertiesStyle) : Ogg::File(file)
+{
+  d = new FilePrivate;
+  read(readProperties, propertiesStyle);
+}
+
+Opus::File::File(IOStream *stream, bool readProperties,
+                   Properties::ReadStyle propertiesStyle) : Ogg::File(stream)
+{
+  d = new FilePrivate;
+  read(readProperties, propertiesStyle);
+}
+
+Opus::File::~File()
+{
+  delete d;
+}
+
+Ogg::XiphComment *Opus::File::tag() const
+{
+  return d->comment;
+}
+
+Opus::Properties *Opus::File::audioProperties() const
+{
+  return d->properties;
+}
+
+bool Opus::File::save()
+{
+  if(!d->comment)
+    d->comment = new Ogg::XiphComment;
+
+  setPacket(1, ByteVector("OpusTags", 8) + d->comment->render(false));
+
+  return Ogg::File::save();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// private members
+////////////////////////////////////////////////////////////////////////////////
+
+void Opus::File::read(bool readProperties, Properties::ReadStyle propertiesStyle)
+{
+  ByteVector opusHeaderData = packet(0);
+
+  if(!opusHeaderData.startsWith("OpusHead")) {
+    setValid(false);
+    debug("Opus::File::read() -- invalid Opus identification header");
+    return;
+  }
+
+  ByteVector commentHeaderData = packet(1);
+
+  if(!commentHeaderData.startsWith("OpusTags")) {
+    setValid(false);
+    debug("Opus::File::read() -- invalid Opus tags header");
+    return;
+  }
+
+  debug("starts with OpusTags");
+
+  d->comment = new Ogg::XiphComment(commentHeaderData.mid(8));
+
+  if(readProperties)
+    d->properties = new Properties(this, propertiesStyle);
+}
diff --git a/taglib/ogg/opus/opusfile.h b/taglib/ogg/opus/opusfile.h
new file mode 100644 (file)
index 0000000..73375af
--- /dev/null
@@ -0,0 +1,110 @@
+/***************************************************************************
+    copyright            : (C) 2012 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+
+    copyright            : (C) 2002 - 2008 by Scott Wheeler
+    email                : wheeler@kde.org
+                           (original Vorbis implementation)
+***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA         *
+ *   02110-1301  USA                                                       *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_OPUSFILE_H
+#define TAGLIB_OPUSFILE_H
+
+#include "oggfile.h"
+#include "xiphcomment.h"
+
+#include "opusproperties.h"
+
+namespace TagLib {
+
+  namespace Ogg {
+
+    //! A namespace containing classes for Opus metadata
+
+    namespace Opus {
+
+      //! An implementation of Ogg::File with Opus specific methods
+
+      /*!
+       * This is the central class in the Ogg Opus metadata processing collection
+       * of classes.  It's built upon Ogg::File which handles processing of the Ogg
+       * logical bitstream and breaking it down into pages which are handled by
+       * the codec implementations, in this case Opus specifically.
+       */
+
+      class TAGLIB_EXPORT File : public Ogg::File
+      {
+      public:
+        /*!
+         * Contructs a Opus file from \a file.  If \a readProperties is true the
+         * file's audio properties will also be read using \a propertiesStyle.  If
+         * false, \a propertiesStyle is ignored.
+         */
+        File(FileName file, bool readProperties = true,
+             Properties::ReadStyle propertiesStyle = Properties::Average);
+
+        /*!
+         * Contructs a Opus file from \a file.  If \a readProperties is true the
+         * file's audio properties will also be read using \a propertiesStyle.  If
+         * false, \a propertiesStyle is ignored.
+         *
+         * \note TagLib will *not* take ownership of the stream, the caller is
+         * responsible for deleting it after the File object.
+         */
+        File(IOStream *stream, bool readProperties = true,
+             Properties::ReadStyle propertiesStyle = Properties::Average);
+
+        /*!
+         * Destroys this instance of the File.
+         */
+        virtual ~File();
+
+        /*!
+         * Returns the XiphComment for this file.  XiphComment implements the tag
+         * interface, so this serves as the reimplementation of
+         * TagLib::File::tag().
+         */
+        virtual Ogg::XiphComment *tag() const;
+
+        /*!
+         * Returns the Opus::Properties for this file.  If no audio properties
+         * were read then this will return a null pointer.
+         */
+        virtual Properties *audioProperties() const;
+
+        virtual bool save();
+
+      private:
+        File(const File &);
+        File &operator=(const File &);
+
+        void read(bool readProperties, Properties::ReadStyle propertiesStyle);
+
+        class FilePrivate;
+        FilePrivate *d;
+      };
+    }
+  }
+}
+
+#endif
diff --git a/taglib/ogg/opus/opusproperties.cpp b/taglib/ogg/opus/opusproperties.cpp
new file mode 100644 (file)
index 0000000..70679d4
--- /dev/null
@@ -0,0 +1,161 @@
+/***************************************************************************
+    copyright            : (C) 2012 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+
+    copyright            : (C) 2002 - 2008 by Scott Wheeler
+    email                : wheeler@kde.org
+                           (original Vorbis implementation)
+ ***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA         *
+ *   02110-1301  USA                                                       *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#include <tstring.h>
+#include <tdebug.h>
+
+#include <oggpageheader.h>
+
+#include "opusproperties.h"
+#include "opusfile.h"
+
+using namespace TagLib;
+using namespace TagLib::Ogg;
+
+class Opus::Properties::PropertiesPrivate
+{
+public:
+  PropertiesPrivate(File *f, ReadStyle s) :
+    file(f),
+    style(s),
+    length(0),
+    inputSampleRate(0),
+    channels(0),
+    opusVersion(0) {}
+
+  File *file;
+  ReadStyle style;
+  int length;
+  int inputSampleRate;
+  int channels;
+  int opusVersion;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// public members
+////////////////////////////////////////////////////////////////////////////////
+
+Opus::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style)
+{
+  d = new PropertiesPrivate(file, style);
+  read();
+}
+
+Opus::Properties::~Properties()
+{
+  delete d;
+}
+
+int Opus::Properties::length() const
+{
+  return d->length;
+}
+
+int Opus::Properties::bitrate() const
+{
+  return 0;
+}
+
+int Opus::Properties::sampleRate() const
+{
+  // Opus can decode any stream at a sample rate of 8, 12, 16, 24, or 48 kHz,
+  // so there is no single sample rate. Let's assume it's the highest
+  // possible.
+  return 48000;
+}
+
+int Opus::Properties::channels() const
+{
+  return d->channels;
+}
+
+int Opus::Properties::inputSampleRate() const
+{
+  return d->inputSampleRate;
+}
+
+int Opus::Properties::opusVersion() const
+{
+  return d->opusVersion;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// private members
+////////////////////////////////////////////////////////////////////////////////
+
+void Opus::Properties::read()
+{
+  // Get the identification header from the Ogg implementation.
+
+  // http://tools.ietf.org/html/draft-terriberry-oggopus-01#section-5.1
+
+  ByteVector data = d->file->packet(0);
+
+  // *Magic Signature*
+  int pos = 8;
+
+  // *Version* (8 bits, unsigned)
+  d->opusVersion = uchar(data.at(pos));
+  pos += 1;
+
+  // *Output Channel Count* 'C' (8 bits, unsigned)
+  d->channels = uchar(data.at(pos));
+  pos += 1;
+
+  // *Pre-skip* (16 bits, unsigned, little endian)
+  ushort preSkip = data.mid(pos, 2).toUShort(false);
+  pos += 2;
+
+  // *Input Sample Rate* (32 bits, unsigned, little endian)
+  d->inputSampleRate = data.mid(pos, 4).toUInt(false);
+  pos += 4;
+
+  // *Output Gain* (16 bits, signed, little endian)
+  pos += 2;
+
+  // *Channel Mapping Family* (8 bits, unsigned)
+  pos += 1;
+
+  const Ogg::PageHeader *first = d->file->firstPageHeader();
+  const Ogg::PageHeader *last = d->file->lastPageHeader();
+
+  if(first && last) {
+    long long start = first->absoluteGranularPosition();
+    long long end = last->absoluteGranularPosition();
+
+    if(start >= 0 && end >= 0)
+      d->length = (int) ((end - start - preSkip) / 48000);
+    else {
+      debug("Opus::Properties::read() -- The PCM values for the start or "
+            "end of this file was incorrect.");
+    }
+  }
+  else
+    debug("Opus::Properties::read() -- Could not find valid first and last Ogg pages.");
+}
diff --git a/taglib/ogg/opus/opusproperties.h b/taglib/ogg/opus/opusproperties.h
new file mode 100644 (file)
index 0000000..946f167
--- /dev/null
@@ -0,0 +1,96 @@
+/***************************************************************************
+    copyright            : (C) 2012 by Lukáš Lalinský
+    email                : lalinsky@gmail.com
+
+    copyright            : (C) 2002 - 2008 by Scott Wheeler
+    email                : wheeler@kde.org
+                           (original Vorbis implementation)
+***************************************************************************/
+
+/***************************************************************************
+ *   This library is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU Lesser General Public License version   *
+ *   2.1 as published by the Free Software Foundation.                     *
+ *                                                                         *
+ *   This library is distributed in the hope that it will be useful, but   *
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
+ *   Lesser General Public License for more details.                       *
+ *                                                                         *
+ *   You should have received a copy of the GNU Lesser General Public      *
+ *   License along with this library; if not, write to the Free Software   *
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA         *
+ *   02110-1301  USA                                                       *
+ *                                                                         *
+ *   Alternatively, this file is available under the Mozilla Public        *
+ *   License Version 1.1.  You may obtain a copy of the License at         *
+ *   http://www.mozilla.org/MPL/                                           *
+ ***************************************************************************/
+
+#ifndef TAGLIB_OPUSPROPERTIES_H
+#define TAGLIB_OPUSPROPERTIES_H
+
+#include "audioproperties.h"
+
+namespace TagLib {
+
+  namespace Ogg {
+
+    namespace Opus {
+
+      class File;
+
+      //! An implementation of audio property reading for Ogg Opus
+
+      /*!
+       * This reads the data from an Ogg Opus stream found in the AudioProperties
+       * API.
+       */
+
+      class TAGLIB_EXPORT Properties : public AudioProperties
+      {
+      public:
+        /*!
+         * Create an instance of Opus::Properties with the data read from the
+         * Opus::File \a file.
+         */
+        Properties(File *file, ReadStyle style = Average);
+
+        /*!
+         * Destroys this Opus::Properties instance.
+         */
+        virtual ~Properties();
+
+        // Reimplementations.
+
+        virtual int length() const;
+        virtual int bitrate() const;
+        virtual int sampleRate() const;
+        virtual int channels() const;
+
+        /*!
+         * The Opus codec supports decoding at multiple sample rates, there is no
+         * single sample rate of the encoded stream. This returns the sample rate
+         * of the original audio stream.
+         */
+        int inputSampleRate() const;
+
+        /*!
+         * Returns the Opus version, currently "0" (as specified by the spec).
+         */
+        int opusVersion() const;
+
+      private:
+        Properties(const Properties &);
+        Properties &operator=(const Properties &);
+
+        void read();
+
+        class PropertiesPrivate;
+        PropertiesPrivate *d;
+      };
+    }
+  }
+}
+
+#endif
index d0a6116fbed6272efe31cd301d280de4585885dc..8d7ccdc95279e17ce775f05bb11e6c22fa681f39 100644 (file)
@@ -60,6 +60,7 @@
 #include "mp4file.h"
 #include "wavpackfile.h"
 #include "speexfile.h"
+#include "opusfile.h"
 #include "trueaudiofile.h"
 #include "aifffile.h"
 #include "wavfile.h"
@@ -135,6 +136,8 @@ PropertyMap File::properties() const
     return dynamic_cast<const Ogg::FLAC::File* >(this)->properties();
   if(dynamic_cast<const Ogg::Speex::File* >(this))
     return dynamic_cast<const Ogg::Speex::File* >(this)->properties();
+  if(dynamic_cast<const Ogg::Opus::File* >(this))
+    return dynamic_cast<const Ogg::Opus::File* >(this)->properties();
   if(dynamic_cast<const Ogg::Vorbis::File* >(this))
     return dynamic_cast<const Ogg::Vorbis::File* >(this)->properties();
   if(dynamic_cast<const RIFF::AIFF::File* >(this))
@@ -174,6 +177,8 @@ void File::removeUnsupportedProperties(const StringList &properties)
     dynamic_cast<Ogg::FLAC::File* >(this)->removeUnsupportedProperties(properties);
   else if(dynamic_cast<Ogg::Speex::File* >(this))
     dynamic_cast<Ogg::Speex::File* >(this)->removeUnsupportedProperties(properties);
+  else if(dynamic_cast<Ogg::Opus::File* >(this))
+    dynamic_cast<Ogg::Opus::File* >(this)->removeUnsupportedProperties(properties);
   else if(dynamic_cast<Ogg::Vorbis::File* >(this))
     dynamic_cast<Ogg::Vorbis::File* >(this)->removeUnsupportedProperties(properties);
   else if(dynamic_cast<RIFF::AIFF::File* >(this))
@@ -210,6 +215,8 @@ PropertyMap File::setProperties(const PropertyMap &properties)
     return dynamic_cast<Ogg::FLAC::File* >(this)->setProperties(properties);
   else if(dynamic_cast<Ogg::Speex::File* >(this))
     return dynamic_cast<Ogg::Speex::File* >(this)->setProperties(properties);
+  else if(dynamic_cast<Ogg::Opus::File* >(this))
+    return dynamic_cast<Ogg::Opus::File* >(this)->setProperties(properties);
   else if(dynamic_cast<Ogg::Vorbis::File* >(this))
     return dynamic_cast<Ogg::Vorbis::File* >(this)->setProperties(properties);
   else if(dynamic_cast<RIFF::AIFF::File* >(this))
index f51e7bfa20f55b8c8b4888b4037dd2e547f631cc..4e428af81f643c18a463015774bda9758473e261 100644 (file)
@@ -16,6 +16,8 @@ INCLUDE_DIRECTORIES(
   ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg
   ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg/vorbis
   ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg/flac
+  ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg/speex
+  ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg/opus
   ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/flac
   ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/wavpack
   ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mod
@@ -60,6 +62,7 @@ SET(test_runner_SRCS
   test_it.cpp
   test_xm.cpp
   test_mpc.cpp
+  test_opus.cpp
 )
 
 INCLUDE_DIRECTORIES(${CPPUNIT_INCLUDE_DIR})
diff --git a/tests/data/correctness_gain_silent_output.opus b/tests/data/correctness_gain_silent_output.opus
new file mode 100644 (file)
index 0000000..00972c4
Binary files /dev/null and b/tests/data/correctness_gain_silent_output.opus differ
diff --git a/tests/test_opus.cpp b/tests/test_opus.cpp
new file mode 100644 (file)
index 0000000..35ee3b3
--- /dev/null
@@ -0,0 +1,61 @@
+#include <cppunit/extensions/HelperMacros.h>
+#include <string>
+#include <stdio.h>
+#include <tag.h>
+#include <tbytevectorlist.h>
+#include <opusfile.h>
+#include "utils.h"
+
+using namespace std;
+using namespace TagLib;
+
+class TestOpus : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE(TestOpus);
+  CPPUNIT_TEST(testProperties);
+  CPPUNIT_TEST(testReadComments);
+  CPPUNIT_TEST(testWriteComments);
+  CPPUNIT_TEST_SUITE_END();
+
+public:
+
+  void testProperties()
+  {
+    Ogg::Opus::File f(TEST_FILE_PATH_C("correctness_gain_silent_output.opus"));
+    CPPUNIT_ASSERT_EQUAL(7, f.audioProperties()->length());
+    CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate());
+    CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channels());
+    CPPUNIT_ASSERT_EQUAL(48000, f.audioProperties()->sampleRate());
+    CPPUNIT_ASSERT_EQUAL(48000, ((Ogg::Opus::Properties *)f.audioProperties())->inputSampleRate());
+  }
+
+  void testReadComments()
+  {
+    Ogg::Opus::File f(TEST_FILE_PATH_C("correctness_gain_silent_output.opus"));
+    CPPUNIT_ASSERT_EQUAL(StringList("Xiph.Org Opus testvectormaker"), f.tag()->fieldListMap()["ENCODER"]);
+    CPPUNIT_ASSERT(f.tag()->fieldListMap().contains("TESTDESCRIPTION"));
+    CPPUNIT_ASSERT(!f.tag()->fieldListMap().contains("ARTIST"));
+    CPPUNIT_ASSERT_EQUAL(String("libopus 0.9.11-66-g64c2dd7"), f.tag()->vendorID());
+  }
+
+  void testWriteComments()
+  {
+    ScopedFileCopy copy("correctness_gain_silent_output", ".opus");
+    string filename = copy.fileName();
+
+    Ogg::Opus::File *f = new Ogg::Opus::File(filename.c_str());
+    f->tag()->setArtist("Your Tester");
+    f->save();
+    delete f;
+
+    f = new Ogg::Opus::File(filename.c_str());
+    CPPUNIT_ASSERT_EQUAL(StringList("Xiph.Org Opus testvectormaker"), f->tag()->fieldListMap()["ENCODER"]);
+    CPPUNIT_ASSERT(f->tag()->fieldListMap().contains("TESTDESCRIPTION"));
+    CPPUNIT_ASSERT_EQUAL(StringList("Your Tester"), f->tag()->fieldListMap()["ARTIST"]);
+    CPPUNIT_ASSERT_EQUAL(String("libopus 0.9.11-66-g64c2dd7"), f->tag()->vendorID());
+    delete f;
+  }
+
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TestOpus);