TagLib: Implement support for APE tags on TTA
TrueAudio will now read APE tags, and if I should start writing tags some day, will prefer creating APE tags if no tags exist. Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
parent
91da112e35
commit
0b8a659bc2
2 changed files with 105 additions and 7 deletions
|
@ -39,12 +39,14 @@
|
||||||
#include "id3v1tag.h"
|
#include "id3v1tag.h"
|
||||||
#include "id3v2tag.h"
|
#include "id3v2tag.h"
|
||||||
#include "id3v2header.h"
|
#include "id3v2header.h"
|
||||||
|
#include "apefooter.h"
|
||||||
|
#include "apetag.h"
|
||||||
|
|
||||||
using namespace TagLib;
|
using namespace TagLib;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
enum { TrueAudioID3v2Index = 0, TrueAudioID3v1Index = 1 };
|
enum { TrueAudioID3v2Index = 0, TrueAudioAPEIndex = 1, TrueAudioID3v1Index = 2 };
|
||||||
}
|
}
|
||||||
|
|
||||||
class TrueAudio::File::FilePrivate
|
class TrueAudio::File::FilePrivate
|
||||||
|
@ -55,6 +57,8 @@ public:
|
||||||
ID3v2Location(-1),
|
ID3v2Location(-1),
|
||||||
ID3v2OriginalSize(0),
|
ID3v2OriginalSize(0),
|
||||||
ID3v1Location(-1),
|
ID3v1Location(-1),
|
||||||
|
APELocation(-1),
|
||||||
|
APEOriginalSize(0),
|
||||||
properties(0) {}
|
properties(0) {}
|
||||||
|
|
||||||
~FilePrivate()
|
~FilePrivate()
|
||||||
|
@ -66,6 +70,9 @@ public:
|
||||||
long ID3v2Location;
|
long ID3v2Location;
|
||||||
long ID3v2OriginalSize;
|
long ID3v2OriginalSize;
|
||||||
|
|
||||||
|
long APELocation;
|
||||||
|
long APEOriginalSize;
|
||||||
|
|
||||||
long ID3v1Location;
|
long ID3v1Location;
|
||||||
|
|
||||||
TagUnion tag;
|
TagUnion tag;
|
||||||
|
@ -148,7 +155,10 @@ PropertyMap TrueAudio::File::setProperties(const PropertyMap &properties)
|
||||||
if(ID3v1Tag())
|
if(ID3v1Tag())
|
||||||
ID3v1Tag()->setProperties(properties);
|
ID3v1Tag()->setProperties(properties);
|
||||||
|
|
||||||
return ID3v2Tag(true)->setProperties(properties);
|
if(ID3v2Tag())
|
||||||
|
ID3v2Tag()->setProperties(properties);
|
||||||
|
|
||||||
|
return APETag(true)->setProperties(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
TrueAudio::Properties *TrueAudio::File::audioProperties() const
|
TrueAudio::Properties *TrueAudio::File::audioProperties() const
|
||||||
|
@ -180,6 +190,9 @@ bool TrueAudio::File::save()
|
||||||
const ByteVector data = ID3v2Tag()->render();
|
const ByteVector data = ID3v2Tag()->render();
|
||||||
insert(data, d->ID3v2Location, d->ID3v2OriginalSize);
|
insert(data, d->ID3v2Location, d->ID3v2OriginalSize);
|
||||||
|
|
||||||
|
if(d->APELocation >= 0)
|
||||||
|
d->APELocation += (static_cast<long>(data.size()) - d->ID3v2OriginalSize);
|
||||||
|
|
||||||
if(d->ID3v1Location >= 0)
|
if(d->ID3v1Location >= 0)
|
||||||
d->ID3v1Location += (static_cast<long>(data.size()) - d->ID3v2OriginalSize);
|
d->ID3v1Location += (static_cast<long>(data.size()) - d->ID3v2OriginalSize);
|
||||||
|
|
||||||
|
@ -192,6 +205,9 @@ bool TrueAudio::File::save()
|
||||||
if(d->ID3v2Location >= 0) {
|
if(d->ID3v2Location >= 0) {
|
||||||
removeBlock(d->ID3v2Location, d->ID3v2OriginalSize);
|
removeBlock(d->ID3v2Location, d->ID3v2OriginalSize);
|
||||||
|
|
||||||
|
if(d->APELocation >= 0)
|
||||||
|
d->APELocation -= d->ID3v2OriginalSize;
|
||||||
|
|
||||||
if(d->ID3v1Location >= 0)
|
if(d->ID3v1Location >= 0)
|
||||||
d->ID3v1Location -= d->ID3v2OriginalSize;
|
d->ID3v1Location -= d->ID3v2OriginalSize;
|
||||||
|
|
||||||
|
@ -226,6 +242,35 @@ bool TrueAudio::File::save()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(APETag() && !APETag()->isEmpty()) {
|
||||||
|
// APE tag is not empty. Update the old one or create a new one.
|
||||||
|
if(d->APELocation < 0) {
|
||||||
|
if(d->ID3v1Location >= 0)
|
||||||
|
d->APELocation = d->ID3v1Location;
|
||||||
|
else
|
||||||
|
d->APELocation = length();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ByteVector data = APETag()->render();
|
||||||
|
insert(data, d->APELocation, d->APEOriginalSize);
|
||||||
|
|
||||||
|
if(d->ID3v1Location >= 0)
|
||||||
|
d->ID3v1Location += (static_cast<long>(data.size()) - d->APEOriginalSize);
|
||||||
|
|
||||||
|
d->APEOriginalSize = data.size();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// APE tag is empty. Remove the old one.
|
||||||
|
|
||||||
|
if(d->APELocation >= 0) {
|
||||||
|
removeBlock(d->APELocation, d->APEOriginalSize);
|
||||||
|
|
||||||
|
if (d->ID3v1Location >= 0) {
|
||||||
|
d->ID3v1Location -= d->APEOriginalSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,6 +284,11 @@ ID3v2::Tag *TrueAudio::File::ID3v2Tag(bool create)
|
||||||
return d->tag.access<ID3v2::Tag>(TrueAudioID3v2Index, create);
|
return d->tag.access<ID3v2::Tag>(TrueAudioID3v2Index, create);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
APE::Tag *TrueAudio::File::APETag(bool create)
|
||||||
|
{
|
||||||
|
return d->tag.access<APE::Tag>(TrueAudioAPEIndex, create);
|
||||||
|
}
|
||||||
|
|
||||||
void TrueAudio::File::strip(int tags)
|
void TrueAudio::File::strip(int tags)
|
||||||
{
|
{
|
||||||
if(tags & ID3v1)
|
if(tags & ID3v1)
|
||||||
|
@ -247,8 +297,11 @@ void TrueAudio::File::strip(int tags)
|
||||||
if(tags & ID3v2)
|
if(tags & ID3v2)
|
||||||
d->tag.set(TrueAudioID3v2Index, 0);
|
d->tag.set(TrueAudioID3v2Index, 0);
|
||||||
|
|
||||||
|
if(tags & APE)
|
||||||
|
d->tag.set(TrueAudioAPEIndex, 0);
|
||||||
|
|
||||||
if(!ID3v1Tag())
|
if(!ID3v1Tag())
|
||||||
ID3v2Tag(true);
|
APETag(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TrueAudio::File::hasID3v1Tag() const
|
bool TrueAudio::File::hasID3v1Tag() const
|
||||||
|
@ -261,6 +314,11 @@ bool TrueAudio::File::hasID3v2Tag() const
|
||||||
return (d->ID3v2Location >= 0);
|
return (d->ID3v2Location >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TrueAudio::File::hasAPETag() const
|
||||||
|
{
|
||||||
|
return (d->APELocation >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// private members
|
// private members
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -284,7 +342,17 @@ void TrueAudio::File::read(bool readProperties)
|
||||||
d->tag.set(TrueAudioID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
|
d->tag.set(TrueAudioID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
|
||||||
|
|
||||||
if(d->ID3v1Location < 0)
|
if(d->ID3v1Location < 0)
|
||||||
ID3v2Tag(true);
|
APETag(true);
|
||||||
|
|
||||||
|
// Look for an APE tag
|
||||||
|
|
||||||
|
d->APELocation = Utils::findAPE(this, d->ID3v1Location);
|
||||||
|
|
||||||
|
if(d->APELocation >= 0) {
|
||||||
|
d->tag.set(TrueAudioAPEIndex, new APE::Tag(this, d->APELocation));
|
||||||
|
d->APEOriginalSize = APETag()->footer()->completeTagSize();
|
||||||
|
d->APELocation = d->APELocation + APE::Footer::size() - d->APEOriginalSize;
|
||||||
|
}
|
||||||
|
|
||||||
// Look for TrueAudio metadata
|
// Look for TrueAudio metadata
|
||||||
|
|
||||||
|
|
|
@ -39,13 +39,14 @@ namespace TagLib {
|
||||||
|
|
||||||
namespace ID3v2 { class Tag; class FrameFactory; }
|
namespace ID3v2 { class Tag; class FrameFactory; }
|
||||||
namespace ID3v1 { class Tag; }
|
namespace ID3v1 { class Tag; }
|
||||||
|
namespace APE { class Tag; }
|
||||||
|
|
||||||
//! An implementation of TrueAudio metadata
|
//! An implementation of TrueAudio metadata
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* This is implementation of TrueAudio metadata.
|
* This is implementation of TrueAudio metadata.
|
||||||
*
|
*
|
||||||
* This supports ID3v1 and ID3v2 tags as well as reading stream
|
* This supports ID3v1, ID3v2, and APE tags as well as reading stream
|
||||||
* properties from the file.
|
* properties from the file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -74,6 +75,8 @@ namespace TagLib {
|
||||||
ID3v1 = 0x0001,
|
ID3v1 = 0x0001,
|
||||||
//! Matches ID3v2 tags.
|
//! Matches ID3v2 tags.
|
||||||
ID3v2 = 0x0002,
|
ID3v2 = 0x0002,
|
||||||
|
//! Matches APE tags.
|
||||||
|
APE = 0x0004,
|
||||||
//! Matches all tag types.
|
//! Matches all tag types.
|
||||||
AllTags = 0xffff
|
AllTags = 0xffff
|
||||||
};
|
};
|
||||||
|
@ -141,13 +144,14 @@ namespace TagLib {
|
||||||
/*!
|
/*!
|
||||||
* Implements the unified property interface -- export function.
|
* Implements the unified property interface -- export function.
|
||||||
* If the file contains both ID3v1 and v2 tags, only ID3v2 will be
|
* If the file contains both ID3v1 and v2 tags, only ID3v2 will be
|
||||||
* converted to the PropertyMap.
|
* converted to the PropertyMap. If the file contains APE tags,
|
||||||
|
* only they will be converted to the PropertyMap.
|
||||||
*/
|
*/
|
||||||
PropertyMap properties() const;
|
PropertyMap properties() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Implements the unified property interface -- import function.
|
* Implements the unified property interface -- import function.
|
||||||
* Creates in ID3v2 tag if necessary. If an ID3v1 tag exists, it will
|
* Creates an APE tag if necessary. If an ID3v1 tag exists, it will
|
||||||
* be updated as well, within the limitations of ID3v1.
|
* be updated as well, within the limitations of ID3v1.
|
||||||
*/
|
*/
|
||||||
PropertyMap setProperties(const PropertyMap &);
|
PropertyMap setProperties(const PropertyMap &);
|
||||||
|
@ -211,6 +215,25 @@ namespace TagLib {
|
||||||
*/
|
*/
|
||||||
ID3v2::Tag *ID3v2Tag(bool create = false);
|
ID3v2::Tag *ID3v2Tag(bool create = false);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns a pointer to the APE tag of the file.
|
||||||
|
*
|
||||||
|
* If \a create is false (the default) this may return a null pointer
|
||||||
|
* if there is no valid APE tag. If \a create is true it will create
|
||||||
|
* an APE tag if one does not exist and returns a valid pointer.
|
||||||
|
*
|
||||||
|
* \note This may return a valid pointer regardless of whether or not the
|
||||||
|
* file on disk has an APE tag. Use hasAPETag() to check if the file
|
||||||
|
* on disk actually has an APE tag.
|
||||||
|
*
|
||||||
|
* \note The Tag <b>is still</b> owned by the TTA::File and should not be
|
||||||
|
* deleted by the user. It will be deleted when the file (object) is
|
||||||
|
* destroyed.
|
||||||
|
*
|
||||||
|
* \see hasAPETag()
|
||||||
|
*/
|
||||||
|
APE::Tag *APETag(bool create = false);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* This will remove the tags that match the OR-ed together TagTypes from the
|
* This will remove the tags that match the OR-ed together TagTypes from the
|
||||||
* file. By default it removes all tags.
|
* file. By default it removes all tags.
|
||||||
|
@ -235,6 +258,13 @@ namespace TagLib {
|
||||||
*/
|
*/
|
||||||
bool hasID3v2Tag() const;
|
bool hasID3v2Tag() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns whether or not the file on disk actually has an APE tag.
|
||||||
|
*
|
||||||
|
* \see APETag()
|
||||||
|
*/
|
||||||
|
bool hasAPETag() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Returns whether or not the given \a stream can be opened as a TrueAudio
|
* Returns whether or not the given \a stream can be opened as a TrueAudio
|
||||||
* file.
|
* file.
|
||||||
|
|
Loading…
Reference in a new issue