* Exposed FLAC MD5 signature of the uncompressed audio stream via
FLAC::Properties::signature(). (BUG:160172)
* Added function ByteVector::toHex() for hex-encoding of byte vectors.
+ * WavPack reader now tries to get the audio length by finding the final
+ block, if the header doesn't have the information. (BUG:258016)
TagLib 1.6.3 (Apr 17, 2010)
===========================
if(readProperties) {
seek(0);
- d->properties = new Properties(readBlock(WavPack::HeaderSize),
- length() - d->APESize);
+ d->properties = new Properties(this, length() - d->APESize);
}
}
sampleRate(0),
channels(0),
version(0),
- bitsPerSample(0) {}
+ bitsPerSample(0),
+ file(0) {}
ByteVector data;
long streamLength;
int channels;
int version;
int bitsPerSample;
+ File *file;
};
////////////////////////////////////////////////////////////////////////////////
read();
}
+WavPack::Properties::Properties(File *file, long streamLength, ReadStyle style) : AudioProperties(style)
+{
+ ByteVector data = file->readBlock(32);
+ d = new PropertiesPrivate(data, streamLength, style);
+ d->file = file;
+ read();
+}
+
WavPack::Properties::~Properties()
{
delete d;
#define SRATE_LSB 23
#define SRATE_MASK (0xfL << SRATE_LSB)
+#define MIN_STREAM_VERS 0x402
+#define MAX_STREAM_VERS 0x410
+
+#define FINAL_BLOCK 0x1000
+
void WavPack::Properties::read()
{
if(!d->data.startsWith("wvpk"))
return;
d->version = d->data.mid(8, 2).toShort(false);
+ if(d->version < MIN_STREAM_VERS || d->version > MAX_STREAM_VERS)
+ return;
unsigned int flags = d->data.mid(24, 4).toUInt(false);
d->bitsPerSample = ((flags & BYTES_STORED) + 1) * 8 -
d->channels = (flags & MONO_FLAG) ? 1 : 2;
unsigned int samples = d->data.mid(12, 4).toUInt(false);
- if (samples == ~0u) {
- samples = 0;
+ if(samples == ~0u) {
+ if(d->file && d->style != Fast) {
+ samples = seekFinalIndex();
+ }
+ else {
+ samples = 0;
+ }
}
d->length = d->sampleRate > 0 ? (samples + (d->sampleRate / 2)) / d->sampleRate : 0;
d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0;
}
+unsigned int WavPack::Properties::seekFinalIndex()
+{
+ ByteVector blockID("wvpk", 4);
+
+ long offset = d->streamLength;
+ while(offset > 0) {
+ offset = d->file->rfind(blockID, offset);
+ if(offset == -1)
+ return 0;
+ d->file->seek(offset);
+ ByteVector data = d->file->readBlock(32);
+ if(data.size() != 32)
+ return 0;
+ int version = data.mid(8, 2).toShort(false);
+ if(version < MIN_STREAM_VERS || version > MAX_STREAM_VERS)
+ continue;
+ unsigned int flags = data.mid(24, 4).toUInt(false);
+ if(!(flags & FINAL_BLOCK))
+ return 0;
+ unsigned int blockIndex = data.mid(16, 4).toUInt(false);
+ unsigned int blockSamples = data.mid(20, 4).toUInt(false);
+ return blockIndex + blockSamples;
+ }
+
+ return 0;
+}
+
/*!
* Create an instance of WavPack::Properties with the data read from the
* ByteVector \a data.
+ *
+ * \deprecated This constructor will be dropped in favor of the one below
+ * in a future version.
*/
Properties(const ByteVector &data, long streamLength, ReadStyle style = Average);
+ /*!
+ * Create an instance of WavPack::Properties.
+ */
+ // BIC: merge with the above constructor
+ Properties(File *file, long streamLength, ReadStyle style = Average);
+
/*!
* Destroys this WavPack::Properties instance.
*/
Properties &operator=(const Properties &);
void read();
+ unsigned int seekFinalIndex();
class PropertiesPrivate;
PropertiesPrivate *d;
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg/vorbis
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg/flac
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/flac
+ ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/wavpack
)
SET(test_runner_SRCS
test_ape.cpp
test_apetag.cpp
test_wav.cpp
+ test_wavpack.cpp
)
IF(WITH_MP4)
SET(test_runner_SRCS ${test_runner_SRCS}
-I$(top_srcdir)/taglib/flac \
-I$(top_srcdir)/taglib/riff \
-I$(top_srcdir)/taglib/riff/aiff \
- -I$(top_srcdir)/taglib/mpeg/id3v2/frames
+ -I$(top_srcdir)/taglib/mpeg/id3v2/frames \
+ -I$(top_srcdir)/taglib/wavpack
test_runner_SOURCES = \
main.cpp \
test_aiff.cpp \
test_ogg.cpp \
test_oggflac.cpp \
- test_flac.cpp
+ test_flac.cpp \
+ test_wavpack.cpp
if build_tests
TESTS = test_runner
--- /dev/null
+#include <cppunit/extensions/HelperMacros.h>
+#include <string>
+#include <stdio.h>
+#include <tag.h>
+#include <tbytevectorlist.h>
+#include <wavpackfile.h>
+#include "utils.h"
+
+using namespace std;
+using namespace TagLib;
+
+class TestWavPack : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(TestWavPack);
+ CPPUNIT_TEST(testLengthScan);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+
+ void testLengthScan()
+ {
+ WavPack::File f("data/no_length.wv");
+ CPPUNIT_ASSERT_EQUAL(4, f.audioProperties()->length());
+ }
+
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TestWavPack);