mirror of
https://github.com/taglib/taglib.git
synced 2025-05-25 12:10:26 -04:00
Add Shorten (SHN) support (#1257)
* Add Shorten (SHN) support * Add `<cmath>` include and use `std::log2` * Use `uintptr_t` for buffer size calculations * Work around `byteSwap` not using fixed width types * Remove four-character codes * Attempt to fix `static_assert` * Revert previous commit * Update `read_uint`* functions * Use ByteVector for byte swaps * Use different ByteVector ctor * Rework variable-length input to use ByteVector * Rename some variables * Naming and formatting cleanup * Add basic Shorten tests * Rename a constant * Rename `internalFileType` to `fileType` * Add documentation on `fileType` meaning * Add DO_NOT_DOCUMENT guard * Fix shadowVariable issues reported by cppcheck cppcheck --enable=all --inline-suppr \ --suppress=noExplicitConstructor --suppress=unusedFunction \ --suppress=missingIncludeSystem --project=compile_commands.json * Formatting cleanup * More explicit types Reason for these changes: getRiceGolombCode(k, uInt32CodeSize) was called with int k for uint32_t& argument. There was also a warning from MSVC for line 299: warning C4267: 'argument': conversion from 'size_t' to 'int' * Additional explicit types * Rename `SHN` namespace to `Shorten` Also rename files to match --------- Co-authored-by: Urs Fleisch <ufleisch@users.sourceforge.net>
This commit is contained in:
parent
c1c60ebeea
commit
648f5e5882
@ -25,6 +25,7 @@ include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg/opus
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/dsf
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/dsdiff
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/shorten
|
||||
)
|
||||
|
||||
set(tag_c_HDRS tag_c.h)
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "opusfile.h"
|
||||
#include "dsffile.h"
|
||||
#include "dsdifffile.h"
|
||||
#include "shortenfile.h"
|
||||
#include "tag.h"
|
||||
#include "id3v2framefactory.h"
|
||||
|
||||
@ -190,6 +191,9 @@ TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type)
|
||||
case TagLib_File_DSDIFF:
|
||||
file = new DSDIFF::File(filename);
|
||||
break;
|
||||
case TagLib_File_SHORTEN:
|
||||
file = new Shorten::File(filename);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -130,7 +130,8 @@ typedef enum {
|
||||
TagLib_File_XM,
|
||||
TagLib_File_Opus,
|
||||
TagLib_File_DSF,
|
||||
TagLib_File_DSDIFF
|
||||
TagLib_File_DSDIFF,
|
||||
TagLib_File_SHORTEN
|
||||
} TagLib_File_Type;
|
||||
|
||||
/*!
|
||||
|
@ -26,6 +26,7 @@ include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/xm
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/dsf
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/dsdiff
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shorten
|
||||
)
|
||||
|
||||
set(tag_HDRS
|
||||
@ -141,6 +142,9 @@ set(tag_HDRS
|
||||
dsdiff/dsdifffile.h
|
||||
dsdiff/dsdiffproperties.h
|
||||
dsdiff/dsdiffdiintag.h
|
||||
shorten/shortenfile.h
|
||||
shorten/shortenproperties.h
|
||||
shorten/shortentag.h
|
||||
)
|
||||
|
||||
set(mpeg_SRCS
|
||||
@ -308,6 +312,12 @@ set(dsdiff_SRCS
|
||||
dsdiff/dsdiffdiintag.cpp
|
||||
)
|
||||
|
||||
set(shorten_SRCS
|
||||
shorten/shortenfile.cpp
|
||||
shorten/shortenproperties.cpp
|
||||
shorten/shortentag.cpp
|
||||
)
|
||||
|
||||
set(toolkit_SRCS
|
||||
toolkit/tstring.cpp
|
||||
toolkit/tstringlist.cpp
|
||||
@ -331,7 +341,7 @@ set(tag_LIB_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} ${opus_SRCS}
|
||||
${dsf_SRCS} ${dsdiff_SRCS}
|
||||
${dsf_SRCS} ${dsdiff_SRCS} ${shorten_SRCS}
|
||||
tag.cpp
|
||||
tagunion.cpp
|
||||
fileref.cpp
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include "xmfile.h"
|
||||
#include "dsffile.h"
|
||||
#include "dsdifffile.h"
|
||||
#include "shortenfile.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
@ -180,6 +181,8 @@ namespace
|
||||
file = new DSF::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||
else if(ext == "DFF" || ext == "DSDIFF")
|
||||
file = new DSDIFF::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||
else if(ext == "SHN")
|
||||
file = new Shorten::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||
|
||||
// if file is not valid, leave it to content-based detection.
|
||||
|
||||
@ -231,6 +234,8 @@ namespace
|
||||
file = new DSF::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||
else if(DSDIFF::File::isSupported(stream))
|
||||
file = new DSDIFF::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||
else if(Shorten::File::isSupported(stream))
|
||||
file = new Shorten::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||
|
||||
// isSupported() only does a quick check, so double check the file here.
|
||||
|
||||
@ -436,6 +441,7 @@ StringList FileRef::defaultFileExtensions()
|
||||
l.append("dsf");
|
||||
l.append("dff");
|
||||
l.append("dsdiff"); // alias for "dff"
|
||||
l.append("shn");
|
||||
|
||||
return l;
|
||||
}
|
||||
|
542
taglib/shorten/shortenfile.cpp
Normal file
542
taglib/shorten/shortenfile.cpp
Normal file
@ -0,0 +1,542 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2020-2024 Stephen F. Booth
|
||||
email : me@sbooth.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 "shortenfile.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "shortenutils.h"
|
||||
|
||||
#include "tdebug.h"
|
||||
#include "tutils.h"
|
||||
#include "tagutils.h"
|
||||
#include "tpropertymap.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace {
|
||||
|
||||
// MARK: Constants
|
||||
|
||||
constexpr int minSupportedVersion = 1;
|
||||
constexpr int maxSupportedVersion = 3;
|
||||
|
||||
// Possible values of k
|
||||
constexpr int32_t channelCountCodeSize = 0;
|
||||
constexpr int32_t functionCodeSize = 2;
|
||||
constexpr int32_t verbatimChunkSizeCodeSize = 5;
|
||||
constexpr int32_t verbatimByteCodeSize = 8;
|
||||
constexpr int32_t uInt32CodeSize = 2;
|
||||
constexpr int32_t skipBytesCodeSize = 1;
|
||||
constexpr int32_t lpcqCodeSize = 2;
|
||||
constexpr int32_t extraByteCodeSize = 7;
|
||||
constexpr int32_t fileTypeCodeSize = 4;
|
||||
|
||||
constexpr int32_t functionVerbatim = 9;
|
||||
|
||||
constexpr int32_t canonicalHeaderSize = 44;
|
||||
constexpr int32_t verbatimChunkMaxSize = 256;
|
||||
|
||||
constexpr uint32_t maxChannelCount = 8;
|
||||
|
||||
constexpr uint32_t defaultBlockSize = 256;
|
||||
constexpr uint32_t maxBlockSize = 65535;
|
||||
|
||||
constexpr int waveFormatPCMTag = 0x0001;
|
||||
|
||||
// MARK: Variable-Length Input
|
||||
|
||||
//! Variable-length input using Golomb-Rice coding.
|
||||
class VariableLengthInput {
|
||||
public:
|
||||
//! Creates a new \c VariableLengthInput object.
|
||||
VariableLengthInput(File *file) : file(file) {}
|
||||
|
||||
~VariableLengthInput() = default;
|
||||
|
||||
VariableLengthInput() = delete;
|
||||
VariableLengthInput(const VariableLengthInput &) = delete;
|
||||
VariableLengthInput(VariableLengthInput &&) = delete;
|
||||
VariableLengthInput &operator=(const VariableLengthInput &) = delete;
|
||||
VariableLengthInput &operator=(VariableLengthInput &&) = delete;
|
||||
|
||||
bool getRiceGolombCode(int32_t &i32, int k);
|
||||
bool getUInt(uint32_t &ui32, int version, int32_t k);
|
||||
|
||||
private:
|
||||
//! Refills \c bitBuffer with a single \c uint32_t from \c buffer,
|
||||
//! refilling \c buffer if necessary.
|
||||
bool refillBitBuffer();
|
||||
|
||||
//! Input stream
|
||||
File *file { nullptr };
|
||||
//! Byte buffer
|
||||
ByteVector buffer;
|
||||
//! Current position in buffer
|
||||
unsigned int bufferPosition { 0 };
|
||||
//! Bit buffer
|
||||
uint32_t bitBuffer { 0 };
|
||||
//! Bits available in \c bitBuffer, 0..32
|
||||
int bitsAvailable { 0 };
|
||||
};
|
||||
|
||||
bool VariableLengthInput::getRiceGolombCode(int32_t &i32, int32_t k)
|
||||
{
|
||||
static constexpr uint32_t sMaskTable[] = {
|
||||
0x0,
|
||||
0x1, 0x3, 0x7, 0xf,
|
||||
0x1f, 0x3f, 0x7f, 0xff,
|
||||
0x1ff, 0x3ff, 0x7ff, 0xfff,
|
||||
0x1fff, 0x3fff, 0x7fff, 0xffff,
|
||||
0x1ffff, 0x3ffff, 0x7ffff, 0xfffff,
|
||||
0x1fffff, 0x3fffff, 0x7fffff, 0xffffff,
|
||||
0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff,
|
||||
0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff
|
||||
};
|
||||
|
||||
if(bitsAvailable == 0 && !refillBitBuffer())
|
||||
return false;
|
||||
|
||||
int32_t result;
|
||||
for(result = 0; !(bitBuffer & (1L << --bitsAvailable)); ++result) {
|
||||
if(bitsAvailable == 0 && !refillBitBuffer())
|
||||
return false;
|
||||
}
|
||||
|
||||
while(k != 0) {
|
||||
if(bitsAvailable >= k) {
|
||||
result = (result << k) | static_cast<int32_t>(
|
||||
(bitBuffer >> (bitsAvailable - k)) & sMaskTable[k]);
|
||||
bitsAvailable -= k;
|
||||
k = 0;
|
||||
}
|
||||
else {
|
||||
result = (result << bitsAvailable) | static_cast<int32_t>(
|
||||
bitBuffer & sMaskTable[bitsAvailable]);
|
||||
k -= bitsAvailable;
|
||||
if(!refillBitBuffer())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
i32 = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VariableLengthInput::getUInt(uint32_t &ui32, int version, int32_t k)
|
||||
{
|
||||
if(version > 0 && !getRiceGolombCode(k, uInt32CodeSize))
|
||||
return false;
|
||||
|
||||
int32_t i32;
|
||||
if(!getRiceGolombCode(i32, k))
|
||||
return false;
|
||||
ui32 = static_cast<uint32_t>(i32);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VariableLengthInput::refillBitBuffer()
|
||||
{
|
||||
if(buffer.size() - bufferPosition < 4) {
|
||||
static constexpr size_t bufferSize = 512;
|
||||
auto block = file->readBlock(bufferSize);
|
||||
if(block.size() < 4)
|
||||
return false;
|
||||
buffer = block;
|
||||
bufferPosition = 0;
|
||||
}
|
||||
|
||||
bitBuffer = buffer.toUInt(bufferPosition, true);
|
||||
bufferPosition += 4;
|
||||
bitsAvailable = 32;
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class Shorten::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate() = default;
|
||||
~FilePrivate() = default;
|
||||
|
||||
FilePrivate(const FilePrivate &) = delete;
|
||||
FilePrivate &operator=(const FilePrivate &) = delete;
|
||||
|
||||
std::unique_ptr<Properties> properties;
|
||||
std::unique_ptr<Tag> tag;
|
||||
};
|
||||
|
||||
bool Shorten::File::isSupported(IOStream *stream)
|
||||
{
|
||||
// A Shorten file has to start with "ajkg"
|
||||
const ByteVector id = Utils::readHeader(stream, 4, false);
|
||||
return id.startsWith("ajkg");
|
||||
}
|
||||
|
||||
Shorten::File::File(FileName file, bool readProperties,
|
||||
AudioProperties::ReadStyle propertiesStyle) :
|
||||
TagLib::File(file),
|
||||
d(std::make_unique<FilePrivate>())
|
||||
{
|
||||
if(isOpen())
|
||||
read(propertiesStyle);
|
||||
}
|
||||
|
||||
Shorten::File::File(IOStream *stream, bool readProperties,
|
||||
AudioProperties::ReadStyle propertiesStyle) :
|
||||
TagLib::File(stream),
|
||||
d(std::make_unique<FilePrivate>())
|
||||
{
|
||||
if(isOpen())
|
||||
read(propertiesStyle);
|
||||
}
|
||||
|
||||
Shorten::File::~File() = default;
|
||||
|
||||
Shorten::Tag *Shorten::File::tag() const
|
||||
{
|
||||
return d->tag.get();
|
||||
}
|
||||
|
||||
PropertyMap Shorten::File::properties() const
|
||||
{
|
||||
return d->tag->properties();
|
||||
}
|
||||
|
||||
PropertyMap Shorten::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
return d->tag->setProperties(properties);
|
||||
}
|
||||
|
||||
Shorten::Properties *Shorten::File::audioProperties() const
|
||||
{
|
||||
return d->properties.get();
|
||||
}
|
||||
|
||||
bool Shorten::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("Shorten::File::save() - Cannot save to a read only file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
debug("Shorten::File::save() - Saving not supported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
void Shorten::File::read(AudioProperties::ReadStyle propertiesStyle)
|
||||
{
|
||||
if(!isOpen())
|
||||
return;
|
||||
|
||||
// Read magic number
|
||||
auto magic = readBlock(4);
|
||||
if(magic != "ajkg") {
|
||||
debug("Shorten::File::read() -- Not a Shorten file.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
PropertyValues props{};
|
||||
|
||||
// Read file version
|
||||
int version = readBlock(1).toUInt();
|
||||
if(version < minSupportedVersion || version > maxSupportedVersion) {
|
||||
debug("Shorten::File::read() -- Unsupported version.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
props.version = version;
|
||||
|
||||
// Set up variable length input
|
||||
VariableLengthInput input(this);
|
||||
|
||||
// Read file type
|
||||
uint32_t fileType;
|
||||
if(!input.getUInt(fileType, version, fileTypeCodeSize)) {
|
||||
debug("Shorten::File::read() -- Unable to read file type.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
props.fileType = static_cast<int>(fileType);
|
||||
|
||||
// Read number of channels
|
||||
uint32_t channelCount = 0;
|
||||
if(!input.getUInt(channelCount, version, channelCountCodeSize) ||
|
||||
channelCount == 0 || channelCount > maxChannelCount) {
|
||||
debug("Shorten::File::read() -- Invalid or unsupported channel count.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
props.channelCount = static_cast<int>(channelCount);
|
||||
|
||||
// Read block size if version > 0
|
||||
if(version > 0) {
|
||||
uint32_t blockSize = 0;
|
||||
if(!input.getUInt(blockSize, version,
|
||||
static_cast<int32_t>(std::log2(defaultBlockSize))) ||
|
||||
blockSize == 0 || blockSize > maxBlockSize) {
|
||||
debug("Shorten::File::read() -- Invalid or unsupported block size.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t maxnlpc = 0;
|
||||
if(!input.getUInt(maxnlpc, version, lpcqCodeSize) /*|| maxnlpc > 1024*/) {
|
||||
debug("Shorten::File::read() -- Invalid maximum nlpc.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t nmean = 0;
|
||||
if(!input.getUInt(nmean, version, 0) /*|| nmean > 32768*/) {
|
||||
debug("Shorten::File::read() -- Invalid nmean.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t skipCount;
|
||||
if(!input.getUInt(skipCount, version, skipBytesCodeSize)) {
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < skipCount; ++i) {
|
||||
uint32_t dummy;
|
||||
if(!input.getUInt(dummy, version, extraByteCodeSize)) {
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the WAVE or AIFF header in the verbatim section
|
||||
|
||||
int32_t function;
|
||||
if(!input.getRiceGolombCode(function, functionCodeSize) ||
|
||||
function != functionVerbatim) {
|
||||
debug("Shorten::File::read() -- Missing initial verbatim section.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t header_size;
|
||||
if(!input.getRiceGolombCode(header_size, verbatimChunkSizeCodeSize) ||
|
||||
header_size < canonicalHeaderSize || header_size > verbatimChunkMaxSize) {
|
||||
debug("Shorten::File::read() -- Incorrect header size.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
ByteVector header(header_size, 0);
|
||||
|
||||
auto it = header.begin();
|
||||
for(int32_t i = 0; i < header_size; ++i) {
|
||||
int32_t byte;
|
||||
if(!input.getRiceGolombCode(byte, verbatimByteCodeSize)) {
|
||||
debug("Shorten::File::read() -- Unable to read header.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
*it++ = static_cast<uint8_t>(byte);
|
||||
}
|
||||
|
||||
// header is at least canonicalHeaderSize (44) bytes in size
|
||||
|
||||
auto chunkID = header.toUInt(0, true);
|
||||
// auto chunkSize = header.toUInt(4, true);
|
||||
|
||||
const auto chunkData = ByteVector(header, 8, header.size() - 8);
|
||||
|
||||
// WAVE
|
||||
if(chunkID == 0x52494646 /*'RIFF'*/) {
|
||||
unsigned int offset = 0;
|
||||
|
||||
chunkID = chunkData.toUInt(offset, true);
|
||||
offset += 4;
|
||||
if(chunkID != 0x57415645 /*'WAVE'*/) {
|
||||
debug("Shorten::File::read() -- Missing 'WAVE' in 'RIFF' chunk.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
auto sawFormatChunk = false;
|
||||
uint32_t dataChunkSize = 0;
|
||||
uint16_t blockAlign = 0;
|
||||
|
||||
while(offset < chunkData.size()) {
|
||||
chunkID = chunkData.toUInt(offset, true);
|
||||
offset += 4;
|
||||
|
||||
auto chunkSize = chunkData.toUInt(offset, false);
|
||||
offset += 4;
|
||||
|
||||
switch(chunkID) {
|
||||
case 0x666d7420 /*'fmt '*/:
|
||||
{
|
||||
if(chunkSize < 16) {
|
||||
debug("Shorten::File::read() -- 'fmt ' chunk is too small.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
int formatTag = chunkData.toUShort(offset, false);
|
||||
offset += 2;
|
||||
if(formatTag != waveFormatPCMTag) {
|
||||
debug("Shorten::File::read() -- Unsupported WAVE format tag.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
int fmtChannelCount = chunkData.toUShort(offset, false);
|
||||
offset += 2;
|
||||
if(props.channelCount != fmtChannelCount)
|
||||
debug("Shorten::File::read() -- Channel count mismatch between Shorten and 'fmt ' chunk.");
|
||||
|
||||
props.sampleRate = static_cast<int>(chunkData.toUInt(offset, false));
|
||||
offset += 4;
|
||||
|
||||
// Skip average bytes per second
|
||||
offset += 4;
|
||||
|
||||
blockAlign = chunkData.toUShort(offset, false);
|
||||
offset += 2;
|
||||
|
||||
props.bitsPerSample = static_cast<int>(chunkData.toUShort(offset, false));
|
||||
offset += 2;
|
||||
|
||||
sawFormatChunk = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x64617461 /*'data'*/:
|
||||
dataChunkSize = chunkSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!sawFormatChunk) {
|
||||
debug("Shorten::File::read() -- Missing 'fmt ' chunk.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if(dataChunkSize && blockAlign)
|
||||
props.sampleFrames = static_cast<unsigned long>(dataChunkSize / blockAlign);
|
||||
}
|
||||
// AIFF
|
||||
else if(chunkID == 0x464f524d /*'FORM'*/) {
|
||||
unsigned int offset = 0;
|
||||
|
||||
chunkID = chunkData.toUInt(offset, true);
|
||||
offset += 4;
|
||||
if(chunkID != 0x41494646 /*'AIFF'*/ && chunkID != 0x41494643 /*'AIFC'*/) {
|
||||
debug("Shorten::File::read() -- Missing 'AIFF' or 'AIFC' in 'FORM' chunk.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// if(chunkID == 0x41494643 /*'AIFC'*/)
|
||||
// props.big_endian = true;
|
||||
|
||||
auto sawCommonChunk = false;
|
||||
while(offset < chunkData.size()) {
|
||||
chunkID = chunkData.toUInt(offset, true);
|
||||
offset += 4;
|
||||
|
||||
auto chunkSize = chunkData.toUInt(offset, true);
|
||||
offset += 4;
|
||||
|
||||
// All chunks must have an even length but the pad byte is not included in chunkSize
|
||||
chunkSize += (chunkSize & 1);
|
||||
|
||||
switch(chunkID) {
|
||||
case 0x434f4d4d /*'COMM'*/:
|
||||
{
|
||||
if(chunkSize < 18) {
|
||||
debug("Shorten::File::read() -- 'COMM' chunk is too small.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
int commChannelCount = chunkData.toUShort(offset, true);
|
||||
offset += 2;
|
||||
if(props.channelCount != commChannelCount)
|
||||
debug("Shorten::File::read() -- Channel count mismatch between Shorten and 'COMM' chunk.");
|
||||
|
||||
props.sampleFrames = static_cast<unsigned long>(chunkData.toUInt(offset, true));
|
||||
offset += 4;
|
||||
|
||||
props.bitsPerSample = static_cast<int>(chunkData.toUShort(offset, true));
|
||||
offset += 2;
|
||||
|
||||
// sample rate is IEEE 754 80-bit extended float
|
||||
// (16-bit exponent, 1-bit integer part, 63-bit fraction)
|
||||
auto exp = static_cast<int16_t>(chunkData.toUShort(offset, true)) - 16383 - 63;
|
||||
offset += 2;
|
||||
if(exp < -63 || exp > 63) {
|
||||
debug("Shorten::File::read() -- exp out of range.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
auto frac = chunkData.toULongLong(offset, true);
|
||||
offset += 8;
|
||||
if(exp >= 0)
|
||||
props.sampleRate = static_cast<int>(frac << exp);
|
||||
else
|
||||
props.sampleRate = static_cast<int>(
|
||||
(frac + (static_cast<uint64_t>(1) << (-exp - 1))) >> -exp);
|
||||
|
||||
sawCommonChunk = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip all other chunks
|
||||
default:
|
||||
offset += chunkSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!sawCommonChunk) {
|
||||
debug("Shorten::File::read() -- Missing 'COMM' chunk");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
debug("Shorten::File::read() -- Unsupported data format.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
d->tag = std::make_unique<Tag>();
|
||||
d->properties = std::make_unique<Properties>(&props, propertiesStyle);
|
||||
}
|
140
taglib/shorten/shortenfile.h
Normal file
140
taglib/shorten/shortenfile.h
Normal file
@ -0,0 +1,140 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2020-2024 Stephen F. Booth
|
||||
email : me@sbooth.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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_SHORTENFILE_H
|
||||
#define TAGLIB_SHORTENFILE_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "tfile.h"
|
||||
|
||||
#include "shortenproperties.h"
|
||||
#include "shortentag.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
//! An implementation of Shorten metadata
|
||||
|
||||
/*!
|
||||
* This is an implementation of Shorten metadata.
|
||||
*/
|
||||
|
||||
namespace Shorten {
|
||||
|
||||
//! An implementation of \c TagLib::File with Shorten specific methods
|
||||
|
||||
/*!
|
||||
* This implements and provides an interface for Shorten files to the
|
||||
* \c TagLib::Tag and \c TagLib::AudioProperties interfaces by way of implementing
|
||||
* the abstract \c TagLib::File API as well as providing some additional
|
||||
* information specific to Shorten files.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT File : public TagLib::File {
|
||||
public:
|
||||
/*!
|
||||
* Constructs a Shorten file from \a file.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored. The audio properties are always
|
||||
* read.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
AudioProperties::ReadStyle propertiesStyle =
|
||||
AudioProperties::Average);
|
||||
|
||||
/*!
|
||||
* Constructs a Shorten file from \a stream.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored. The audio properties are always
|
||||
* read.
|
||||
*
|
||||
* \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,
|
||||
AudioProperties::ReadStyle propertiesStyle =
|
||||
AudioProperties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
~File() override;
|
||||
|
||||
File(const File &) = delete;
|
||||
File &operator=(const File &) = delete;
|
||||
|
||||
/*!
|
||||
* Returns the \c Shorten::Tag for this file.
|
||||
*
|
||||
* \note While the returned \c Tag instance is non-null Shorten tags are not supported.
|
||||
*/
|
||||
Tag *tag() const override;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
*/
|
||||
PropertyMap properties() const override;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &) override;
|
||||
|
||||
/*!
|
||||
* Returns the \c Shorten::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
Properties *audioProperties() const override;
|
||||
|
||||
/*!
|
||||
* Save the file.
|
||||
*
|
||||
* \note Saving Shorten tags is not supported.
|
||||
*/
|
||||
bool save() override;
|
||||
|
||||
/*!
|
||||
* Returns whether or not the given \a stream can be opened as a Shorten
|
||||
* file.
|
||||
*
|
||||
* \note This method is designed to do a quick check. The result may
|
||||
* not necessarily be correct.
|
||||
*/
|
||||
static bool isSupported(IOStream *stream);
|
||||
|
||||
private:
|
||||
void read(AudioProperties::ReadStyle propertiesStyle);
|
||||
|
||||
class FilePrivate;
|
||||
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
|
||||
std::unique_ptr<FilePrivate> d;
|
||||
};
|
||||
} // namespace Shorten
|
||||
} // namespace TagLib
|
||||
|
||||
#endif
|
112
taglib/shorten/shortenproperties.cpp
Normal file
112
taglib/shorten/shortenproperties.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2020-2024 Stephen F. Booth
|
||||
email : me@sbooth.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 "shortenproperties.h"
|
||||
|
||||
#include "shortenutils.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class Shorten::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate() = default;
|
||||
~PropertiesPrivate() = default;
|
||||
|
||||
PropertiesPrivate(const PropertiesPrivate &) = delete;
|
||||
PropertiesPrivate &operator=(const PropertiesPrivate &) = delete;
|
||||
|
||||
int version { 0 };
|
||||
int fileType { 0 };
|
||||
int channelCount { 0 };
|
||||
int sampleRate { 0 };
|
||||
int bitsPerSample { 0 };
|
||||
unsigned long sampleFrames { 0 };
|
||||
|
||||
// Computed
|
||||
int bitrate { 0 };
|
||||
int length { 0 };
|
||||
};
|
||||
|
||||
Shorten::Properties::Properties(const PropertyValues *values, ReadStyle style) :
|
||||
AudioProperties(style),
|
||||
d(std::make_unique<PropertiesPrivate>())
|
||||
{
|
||||
if(values) {
|
||||
d->version = values->version;
|
||||
d->fileType = values->fileType;
|
||||
d->channelCount = values->channelCount;
|
||||
d->sampleRate = values->sampleRate;
|
||||
d->bitsPerSample = values->bitsPerSample;
|
||||
d->sampleFrames = values->sampleFrames;
|
||||
|
||||
d->bitrate = static_cast<int>(d->sampleRate * d->bitsPerSample * d->channelCount / 1000.0 + 0.5);
|
||||
if(d->sampleRate > 0)
|
||||
d->length = static_cast<int>(d->sampleFrames * 1000.0 / d->sampleRate + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
Shorten::Properties::~Properties() = default;
|
||||
|
||||
int Shorten::Properties::lengthInMilliseconds() const
|
||||
{
|
||||
return d->length;
|
||||
}
|
||||
|
||||
int Shorten::Properties::bitrate() const
|
||||
{
|
||||
return d->bitrate;
|
||||
}
|
||||
|
||||
int Shorten::Properties::sampleRate() const
|
||||
{
|
||||
return d->sampleRate;
|
||||
}
|
||||
|
||||
int Shorten::Properties::channels() const
|
||||
{
|
||||
return d->channelCount;
|
||||
}
|
||||
|
||||
int Shorten::Properties::shortenVersion() const
|
||||
{
|
||||
return d->version;
|
||||
}
|
||||
|
||||
int Shorten::Properties::fileType() const
|
||||
{
|
||||
return d->fileType;
|
||||
}
|
||||
|
||||
int Shorten::Properties::bitsPerSample() const
|
||||
{
|
||||
return d->bitsPerSample;
|
||||
}
|
||||
|
||||
unsigned long Shorten::Properties::sampleFrames() const
|
||||
{
|
||||
return d->sampleFrames;
|
||||
}
|
74
taglib/shorten/shortenproperties.h
Normal file
74
taglib/shorten/shortenproperties.h
Normal file
@ -0,0 +1,74 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2020-2024 Stephen F. Booth
|
||||
email : me@sbooth.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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_SHORTENPROPERTIES_H
|
||||
#define TAGLIB_SHORTENPROPERTIES_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "audioproperties.h"
|
||||
|
||||
namespace TagLib {
|
||||
namespace Shorten {
|
||||
|
||||
struct PropertyValues;
|
||||
|
||||
//! An implementation of audio properties for Shorten
|
||||
class TAGLIB_EXPORT Properties : public AudioProperties {
|
||||
public:
|
||||
Properties(const PropertyValues *values, ReadStyle style = Average);
|
||||
~Properties() override;
|
||||
|
||||
Properties(const Properties &) = delete;
|
||||
Properties &operator=(const Properties &) = delete;
|
||||
|
||||
int lengthInMilliseconds() const override;
|
||||
int bitrate() const override;
|
||||
int sampleRate() const override;
|
||||
int channels() const override;
|
||||
|
||||
//! Returns the Shorten file version (1-3).
|
||||
int shortenVersion() const;
|
||||
//! Returns the file type (0-9).
|
||||
//! 0 = 8-bit µ-law,
|
||||
//! 1 = signed 8-bit PCM, 2 = unsigned 8-bit PCM,
|
||||
//! 3 = signed big-endian 16-bit PCM, 4 = unsigned big-endian 16-bit PCM,
|
||||
//! 5 = signed little-endian 16-bit PCM, 6 = unsigned little-endian 16-bit PCM,
|
||||
//! 7 = 8-bit ITU-T G.711 µ-law, 8 = 8-bit µ-law,
|
||||
//! 9 = 8-bit A-law, 10 = 8-bit ITU-T G.711 A-law
|
||||
int fileType() const;
|
||||
int bitsPerSample() const;
|
||||
unsigned long sampleFrames() const;
|
||||
|
||||
private:
|
||||
class PropertiesPrivate;
|
||||
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
|
||||
std::unique_ptr<PropertiesPrivate> d;
|
||||
};
|
||||
} // namespace Shorten
|
||||
} // namespace TagLib
|
||||
|
||||
#endif
|
114
taglib/shorten/shortentag.cpp
Normal file
114
taglib/shorten/shortentag.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2020-2024 Stephen F. Booth
|
||||
email : me@sbooth.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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 "shortentag.h"
|
||||
|
||||
#include "tpropertymap.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class Shorten::Tag::TagPrivate
|
||||
{
|
||||
};
|
||||
|
||||
Shorten::Tag::Tag() :
|
||||
d(std::make_unique<TagPrivate>())
|
||||
{
|
||||
}
|
||||
|
||||
Shorten::Tag::~Tag() = default;
|
||||
|
||||
String Shorten::Tag::title() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
String Shorten::Tag::artist() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
String Shorten::Tag::album() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
String Shorten::Tag::comment() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
String Shorten::Tag::genre() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
unsigned int Shorten::Tag::year() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int Shorten::Tag::track() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Shorten::Tag::setTitle(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void Shorten::Tag::setArtist(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void Shorten::Tag::setAlbum(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void Shorten::Tag::setComment(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void Shorten::Tag::setGenre(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void Shorten::Tag::setYear(unsigned int)
|
||||
{
|
||||
}
|
||||
|
||||
void Shorten::Tag::setTrack(unsigned int)
|
||||
{
|
||||
}
|
||||
|
||||
PropertyMap Shorten::Tag::properties() const
|
||||
{
|
||||
return PropertyMap{};
|
||||
}
|
||||
|
||||
PropertyMap Shorten::Tag::setProperties(const PropertyMap &origProps)
|
||||
{
|
||||
return PropertyMap{origProps};
|
||||
}
|
139
taglib/shorten/shortentag.h
Normal file
139
taglib/shorten/shortentag.h
Normal file
@ -0,0 +1,139 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2020-2024 Stephen F. Booth
|
||||
email : me@sbooth.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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_SHORTENTAG_H
|
||||
#define TAGLIB_SHORTENTAG_H
|
||||
|
||||
#include "tag.h"
|
||||
|
||||
namespace TagLib {
|
||||
namespace Shorten {
|
||||
|
||||
//! A Shorten file tag implementation
|
||||
|
||||
/*!
|
||||
* Tags for Shorten files.
|
||||
*
|
||||
* This is a stub class; Shorten files do not support tags.
|
||||
*/
|
||||
class TAGLIB_EXPORT Tag : public TagLib::Tag
|
||||
{
|
||||
public:
|
||||
Tag();
|
||||
~Tag() override;
|
||||
|
||||
Tag(const Tag &) = delete;
|
||||
Tag &operator=(const Tag &) = delete;
|
||||
|
||||
/*!
|
||||
* Not supported by Shorten files. Therefore always returns an empty string.
|
||||
*/
|
||||
String title() const override;
|
||||
|
||||
/*!
|
||||
* Not supported by Shorten files. Therefore always returns an empty string.
|
||||
*/
|
||||
String artist() const override;
|
||||
|
||||
/*!
|
||||
* Not supported by Shorten files. Therefore always returns an empty string.
|
||||
*/
|
||||
String album() const override;
|
||||
|
||||
/*!
|
||||
* Not supported by Shorten files. Therefore always returns an empty string.
|
||||
*/
|
||||
String comment() const override;
|
||||
|
||||
/*!
|
||||
* Not supported by Shorten files. Therefore always returns an empty string.
|
||||
*/
|
||||
String genre() const override;
|
||||
|
||||
/*!
|
||||
* Not supported by Shorten files. Therefore always returns 0.
|
||||
*/
|
||||
unsigned int year() const override;
|
||||
|
||||
/*!
|
||||
* Not supported by Shorten files. Therefore always returns 0.
|
||||
*/
|
||||
unsigned int track() const override;
|
||||
|
||||
/*!
|
||||
* Not supported by Shorten files and therefore ignored.
|
||||
*/
|
||||
void setTitle(const String &title) override;
|
||||
|
||||
/*!
|
||||
* Not supported by Shorten files and therefore ignored.
|
||||
*/
|
||||
void setArtist(const String &artist) override;
|
||||
|
||||
/*!
|
||||
* Not supported by Shorten files and therefore ignored.
|
||||
*/
|
||||
void setAlbum(const String &album) override;
|
||||
|
||||
/*!
|
||||
* Not supported by Shorten files and therefore ignored.
|
||||
*/
|
||||
void setComment(const String &comment) override;
|
||||
|
||||
/*!
|
||||
* Not supported by Shorten files and therefore ignored.
|
||||
*/
|
||||
void setGenre(const String &genre) override;
|
||||
|
||||
/*!
|
||||
* Not supported by Shorten files and therefore ignored.
|
||||
*/
|
||||
void setYear(unsigned int year) override;
|
||||
|
||||
/*!
|
||||
* Not supported by Shorten files and therefore ignored.
|
||||
*/
|
||||
void setTrack(unsigned int track) override;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
*/
|
||||
PropertyMap properties() const override;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &) override;
|
||||
|
||||
private:
|
||||
class TagPrivate;
|
||||
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
|
||||
std::unique_ptr<TagPrivate> d;
|
||||
};
|
||||
|
||||
} // namespace Shorten
|
||||
} // namespace TagLib
|
||||
|
||||
#endif
|
51
taglib/shorten/shortenutils.h
Normal file
51
taglib/shorten/shortenutils.h
Normal file
@ -0,0 +1,51 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2020-2024 Stephen F. Booth
|
||||
email : me@sbooth.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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_SHORTENUTILS_H
|
||||
#define TAGLIB_SHORTENUTILS_H
|
||||
|
||||
// THIS FILE IS NOT A PART OF THE TAGLIB API
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header
|
||||
|
||||
namespace TagLib {
|
||||
namespace Shorten {
|
||||
|
||||
/// Values shared with \c Shorten::Properties by \c Shorten::File
|
||||
struct PropertyValues
|
||||
{
|
||||
int version { 0 };
|
||||
int fileType { 0 };
|
||||
int channelCount { 0 };
|
||||
int sampleRate { 0 };
|
||||
int bitsPerSample { 0 };
|
||||
unsigned long sampleFrames { 0 };
|
||||
};
|
||||
} // namespace Shorten
|
||||
} // namespace TagLib
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -27,6 +27,7 @@ INCLUDE_DIRECTORIES(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/xm
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/dsf
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/dsdiff
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/shorten
|
||||
)
|
||||
|
||||
SET(test_runner_SRCS
|
||||
@ -74,6 +75,7 @@ SET(test_runner_SRCS
|
||||
test_speex.cpp
|
||||
test_dsf.cpp
|
||||
test_dsdiff.cpp
|
||||
test_shorten.cpp
|
||||
test_sizes.cpp
|
||||
test_versionnumber.cpp
|
||||
)
|
||||
|
12
tests/data/2sec-silence.shn
Normal file
12
tests/data/2sec-silence.shn
Normal file
File diff suppressed because one or more lines are too long
@ -385,6 +385,7 @@ public:
|
||||
CPPUNIT_ASSERT(extensions.contains("dsf"));
|
||||
CPPUNIT_ASSERT(extensions.contains("dff"));
|
||||
CPPUNIT_ASSERT(extensions.contains("dsdiff"));
|
||||
CPPUNIT_ASSERT(extensions.contains("shn"));
|
||||
}
|
||||
|
||||
void testFileResolver()
|
||||
|
44
tests/test_shorten.cpp
Normal file
44
tests/test_shorten.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
|
||||
#include "tbytevectorlist.h"
|
||||
#include "tpropertymap.h"
|
||||
#include "tag.h"
|
||||
#include "shortenfile.h"
|
||||
#include "plainfile.h"
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include "utils.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace TagLib;
|
||||
|
||||
class TestShorten : public CppUnit::TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE(TestShorten);
|
||||
CPPUNIT_TEST(testBasic);
|
||||
CPPUNIT_TEST(testTags);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
|
||||
void testBasic()
|
||||
{
|
||||
Shorten::File f(TEST_FILE_PATH_C("2sec-silence.shn"));
|
||||
CPPUNIT_ASSERT(f.audioProperties());
|
||||
CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->lengthInSeconds());
|
||||
CPPUNIT_ASSERT_EQUAL(2000, f.audioProperties()->lengthInMilliseconds());
|
||||
CPPUNIT_ASSERT_EQUAL(1411, f.audioProperties()->bitrate());
|
||||
CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels());
|
||||
CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate());
|
||||
CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->shortenVersion());
|
||||
CPPUNIT_ASSERT_EQUAL(5, f.audioProperties()->fileType());
|
||||
CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample());
|
||||
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned long>(88200), f.audioProperties()->sampleFrames());
|
||||
}
|
||||
|
||||
void testTags()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestShorten);
|
@ -92,6 +92,9 @@
|
||||
#include "rifffile.h"
|
||||
#include "s3mfile.h"
|
||||
#include "s3mproperties.h"
|
||||
#include "shortenfile.h"
|
||||
#include "shortenproperties.h"
|
||||
#include "shortentag.h"
|
||||
#include "speexfile.h"
|
||||
#include "speexproperties.h"
|
||||
#include "synchronizedlyricsframe.h"
|
||||
@ -245,6 +248,9 @@ public:
|
||||
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::RIFF::WAV::Properties));
|
||||
CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::S3M::File));
|
||||
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::S3M::Properties));
|
||||
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Shorten::File));
|
||||
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Shorten::Properties));
|
||||
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Shorten::Tag));
|
||||
CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::String));
|
||||
CPPUNIT_ASSERT_EQUAL(classSize(2, false), sizeof(TagLib::StringList));
|
||||
CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::Tag));
|
||||
|
Loading…
Reference in New Issue
Block a user