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>CQTexperiment
parent
91da112e35
commit
0b8a659bc2
|
@ -39,12 +39,14 @@
|
|||
#include "id3v1tag.h"
|
||||
#include "id3v2tag.h"
|
||||
#include "id3v2header.h"
|
||||
#include "apefooter.h"
|
||||
#include "apetag.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace
|
||||
{
|
||||
enum { TrueAudioID3v2Index = 0, TrueAudioID3v1Index = 1 };
|
||||
enum { TrueAudioID3v2Index = 0, TrueAudioAPEIndex = 1, TrueAudioID3v1Index = 2 };
|
||||
}
|
||||
|
||||
class TrueAudio::File::FilePrivate
|
||||
|
@ -55,6 +57,8 @@ public:
|
|||
ID3v2Location(-1),
|
||||
ID3v2OriginalSize(0),
|
||||
ID3v1Location(-1),
|
||||
APELocation(-1),
|
||||
APEOriginalSize(0),
|
||||
properties(0) {}
|
||||
|
||||
~FilePrivate()
|
||||
|
@ -66,6 +70,9 @@ public:
|
|||
long ID3v2Location;
|
||||
long ID3v2OriginalSize;
|
||||
|
||||
long APELocation;
|
||||
long APEOriginalSize;
|
||||
|
||||
long ID3v1Location;
|
||||
|
||||
TagUnion tag;
|
||||
|
@ -148,7 +155,10 @@ PropertyMap TrueAudio::File::setProperties(const PropertyMap &properties)
|
|||
if(ID3v1Tag())
|
||||
ID3v1Tag()->setProperties(properties);
|
||||
|
||||
return ID3v2Tag(true)->setProperties(properties);
|
||||
if(ID3v2Tag())
|
||||
ID3v2Tag()->setProperties(properties);
|
||||
|
||||
return APETag(true)->setProperties(properties);
|
||||
}
|
||||
|
||||
TrueAudio::Properties *TrueAudio::File::audioProperties() const
|
||||
|
@ -180,6 +190,9 @@ bool TrueAudio::File::save()
|
|||
const ByteVector data = ID3v2Tag()->render();
|
||||
insert(data, d->ID3v2Location, d->ID3v2OriginalSize);
|
||||
|
||||
if(d->APELocation >= 0)
|
||||
d->APELocation += (static_cast<long>(data.size()) - d->ID3v2OriginalSize);
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->ID3v1Location += (static_cast<long>(data.size()) - d->ID3v2OriginalSize);
|
||||
|
||||
|
@ -192,6 +205,9 @@ bool TrueAudio::File::save()
|
|||
if(d->ID3v2Location >= 0) {
|
||||
removeBlock(d->ID3v2Location, d->ID3v2OriginalSize);
|
||||
|
||||
if(d->APELocation >= 0)
|
||||
d->APELocation -= d->ID3v2OriginalSize;
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -239,6 +284,11 @@ ID3v2::Tag *TrueAudio::File::ID3v2Tag(bool 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)
|
||||
{
|
||||
if(tags & ID3v1)
|
||||
|
@ -247,8 +297,11 @@ void TrueAudio::File::strip(int tags)
|
|||
if(tags & ID3v2)
|
||||
d->tag.set(TrueAudioID3v2Index, 0);
|
||||
|
||||
if(tags & APE)
|
||||
d->tag.set(TrueAudioAPEIndex, 0);
|
||||
|
||||
if(!ID3v1Tag())
|
||||
ID3v2Tag(true);
|
||||
APETag(true);
|
||||
}
|
||||
|
||||
bool TrueAudio::File::hasID3v1Tag() const
|
||||
|
@ -261,6 +314,11 @@ bool TrueAudio::File::hasID3v2Tag() const
|
|||
return (d->ID3v2Location >= 0);
|
||||
}
|
||||
|
||||
bool TrueAudio::File::hasAPETag() const
|
||||
{
|
||||
return (d->APELocation >= 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -284,7 +342,17 @@ void TrueAudio::File::read(bool readProperties)
|
|||
d->tag.set(TrueAudioID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -39,13 +39,14 @@ namespace TagLib {
|
|||
|
||||
namespace ID3v2 { class Tag; class FrameFactory; }
|
||||
namespace ID3v1 { class Tag; }
|
||||
namespace APE { class Tag; }
|
||||
|
||||
//! An 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.
|
||||
*/
|
||||
|
||||
|
@ -74,6 +75,8 @@ namespace TagLib {
|
|||
ID3v1 = 0x0001,
|
||||
//! Matches ID3v2 tags.
|
||||
ID3v2 = 0x0002,
|
||||
//! Matches APE tags.
|
||||
APE = 0x0004,
|
||||
//! Matches all tag types.
|
||||
AllTags = 0xffff
|
||||
};
|
||||
|
@ -141,13 +144,14 @@ namespace TagLib {
|
|||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
* 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;
|
||||
|
||||
/*!
|
||||
* 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.
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
@ -211,6 +215,25 @@ namespace TagLib {
|
|||
*/
|
||||
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
|
||||
* file. By default it removes all tags.
|
||||
|
@ -235,6 +258,13 @@ namespace TagLib {
|
|||
*/
|
||||
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
|
||||
* file.
|
||||
|
|
Loading…
Reference in New Issue