TagLib: Support reading Apple SoundCheck tags from ID3v2 and MP4
parent
b54b10861b
commit
72f1168498
|
@ -216,6 +216,11 @@ float APE::Tag::rgTrackPeak() const
|
||||||
return d->itemListMap["REPLAYGAIN_TRACK_PEAK"].toString().toFloat();
|
return d->itemListMap["REPLAYGAIN_TRACK_PEAK"].toString().toFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String APE::Tag::soundcheck() const
|
||||||
|
{
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
void APE::Tag::setTitle(const String &s)
|
void APE::Tag::setTitle(const String &s)
|
||||||
{
|
{
|
||||||
addValue("TITLE", s, true);
|
addValue("TITLE", s, true);
|
||||||
|
|
|
@ -101,6 +101,7 @@ namespace TagLib {
|
||||||
virtual float rgAlbumPeak() const;
|
virtual float rgAlbumPeak() const;
|
||||||
virtual float rgTrackGain() const;
|
virtual float rgTrackGain() const;
|
||||||
virtual float rgTrackPeak() const;
|
virtual float rgTrackPeak() const;
|
||||||
|
virtual String soundcheck() const;
|
||||||
|
|
||||||
virtual void setTitle(const String &s);
|
virtual void setTitle(const String &s);
|
||||||
virtual void setAlbumArtist(const String &s);
|
virtual void setAlbumArtist(const String &s);
|
||||||
|
|
|
@ -154,6 +154,11 @@ float ASF::Tag::rgTrackPeak() const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String ASF::Tag::soundcheck() const
|
||||||
|
{
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
void ASF::Tag::setTitle(const String &value)
|
void ASF::Tag::setTitle(const String &value)
|
||||||
{
|
{
|
||||||
d->title = value;
|
d->title = value;
|
||||||
|
|
|
@ -110,6 +110,7 @@ namespace TagLib {
|
||||||
virtual float rgAlbumPeak() const;
|
virtual float rgAlbumPeak() const;
|
||||||
virtual float rgTrackGain() const;
|
virtual float rgTrackGain() const;
|
||||||
virtual float rgTrackPeak() const;
|
virtual float rgTrackPeak() const;
|
||||||
|
virtual String soundcheck() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Sets the title to \a s.
|
* Sets the title to \a s.
|
||||||
|
|
|
@ -124,6 +124,11 @@ float Mod::Tag::rgTrackPeak() const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String Mod::Tag::soundcheck() const
|
||||||
|
{
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
String Mod::Tag::trackerName() const
|
String Mod::Tag::trackerName() const
|
||||||
{
|
{
|
||||||
return d->trackerName;
|
return d->trackerName;
|
||||||
|
|
|
@ -124,6 +124,11 @@ namespace TagLib {
|
||||||
*/
|
*/
|
||||||
virtual float rgTrackPeak() const;
|
virtual float rgTrackPeak() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Not supported by module files. Therefore always returns empty.
|
||||||
|
*/
|
||||||
|
virtual String soundcheck() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Returns the name of the tracker used to create/edit the module file.
|
* Returns the name of the tracker used to create/edit the module file.
|
||||||
* Only XM files store this tag to the file as such, for other formats
|
* Only XM files store this tag to the file as such, for other formats
|
||||||
|
|
|
@ -834,6 +834,14 @@ MP4::Tag::rgTrackPeak() const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String
|
||||||
|
MP4::Tag::soundcheck() const
|
||||||
|
{
|
||||||
|
if (d->items.contains("----:com.apple.iTunes:iTunNORM"))
|
||||||
|
return d->items["----:com.apple.iTunes:iTunNORM"].toStringList()[0];
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MP4::Tag::setTitle(const String &value)
|
MP4::Tag::setTitle(const String &value)
|
||||||
{
|
{
|
||||||
|
|
|
@ -67,6 +67,7 @@ namespace TagLib {
|
||||||
virtual float rgAlbumPeak() const;
|
virtual float rgAlbumPeak() const;
|
||||||
virtual float rgTrackGain() const;
|
virtual float rgTrackGain() const;
|
||||||
virtual float rgTrackPeak() const;
|
virtual float rgTrackPeak() const;
|
||||||
|
virtual String soundcheck() const;
|
||||||
|
|
||||||
virtual void setTitle(const String &value);
|
virtual void setTitle(const String &value);
|
||||||
virtual void setAlbumArtist(const String &value);
|
virtual void setAlbumArtist(const String &value);
|
||||||
|
|
|
@ -197,6 +197,11 @@ float ID3v1::Tag::rgTrackPeak() const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String ID3v1::Tag::soundcheck() const
|
||||||
|
{
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
void ID3v1::Tag::setTitle(const String &s)
|
void ID3v1::Tag::setTitle(const String &s)
|
||||||
{
|
{
|
||||||
d->title = s;
|
d->title = s;
|
||||||
|
|
|
@ -149,6 +149,7 @@ namespace TagLib {
|
||||||
virtual float rgAlbumPeak() const;
|
virtual float rgAlbumPeak() const;
|
||||||
virtual float rgTrackGain() const;
|
virtual float rgTrackGain() const;
|
||||||
virtual float rgTrackPeak() const;
|
virtual float rgTrackPeak() const;
|
||||||
|
virtual String soundcheck() const;
|
||||||
|
|
||||||
virtual void setTitle(const String &s);
|
virtual void setTitle(const String &s);
|
||||||
virtual void setAlbumArtist(const String &s);
|
virtual void setAlbumArtist(const String &s);
|
||||||
|
|
|
@ -312,6 +312,24 @@ float ID3v2::Tag::rgTrackPeak() const
|
||||||
return rg("replaygain_track_peak");
|
return rg("replaygain_track_peak");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String ID3v2::Tag::soundcheck() const
|
||||||
|
{
|
||||||
|
const FrameList &comments = d->frameListMap["COMM"];
|
||||||
|
|
||||||
|
if(comments.isEmpty())
|
||||||
|
return String();
|
||||||
|
|
||||||
|
for(FrameList::ConstIterator it = comments.begin(); it != comments.end(); ++it)
|
||||||
|
{
|
||||||
|
CommentsFrame *frame = dynamic_cast<CommentsFrame *>(*it);
|
||||||
|
|
||||||
|
if(frame && frame->description() == "iTunNORM")
|
||||||
|
return (*it)->toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
void ID3v2::Tag::setTitle(const String &s)
|
void ID3v2::Tag::setTitle(const String &s)
|
||||||
{
|
{
|
||||||
setTextFrame("TIT2", s);
|
setTextFrame("TIT2", s);
|
||||||
|
|
|
@ -173,6 +173,7 @@ namespace TagLib {
|
||||||
virtual float rgAlbumPeak() const;
|
virtual float rgAlbumPeak() const;
|
||||||
virtual float rgTrackGain() const;
|
virtual float rgTrackGain() const;
|
||||||
virtual float rgTrackPeak() const;
|
virtual float rgTrackPeak() const;
|
||||||
|
virtual String soundcheck() const;
|
||||||
|
|
||||||
virtual void setTitle(const String &s);
|
virtual void setTitle(const String &s);
|
||||||
virtual void setAlbumArtist(const String &s);
|
virtual void setAlbumArtist(const String &s);
|
||||||
|
|
|
@ -196,6 +196,11 @@ float Ogg::XiphComment::rgTrackPeak() const
|
||||||
return d->fieldListMap["REPLAYGAIN_TRACK_PEAK"].front().toFloat();
|
return d->fieldListMap["REPLAYGAIN_TRACK_PEAK"].front().toFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String Ogg::XiphComment::soundcheck() const
|
||||||
|
{
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
void Ogg::XiphComment::setTitle(const String &s)
|
void Ogg::XiphComment::setTitle(const String &s)
|
||||||
{
|
{
|
||||||
addField("TITLE", s);
|
addField("TITLE", s);
|
||||||
|
|
|
@ -94,6 +94,7 @@ namespace TagLib {
|
||||||
virtual float rgAlbumPeak() const;
|
virtual float rgAlbumPeak() const;
|
||||||
virtual float rgTrackGain() const;
|
virtual float rgTrackGain() const;
|
||||||
virtual float rgTrackPeak() const;
|
virtual float rgTrackPeak() const;
|
||||||
|
virtual String soundcheck() const;
|
||||||
|
|
||||||
virtual void setTitle(const String &s);
|
virtual void setTitle(const String &s);
|
||||||
virtual void setAlbumArtist(const String &s);
|
virtual void setAlbumArtist(const String &s);
|
||||||
|
|
|
@ -158,6 +158,11 @@ float RIFF::Info::Tag::rgTrackPeak() const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String RIFF::Info::Tag::soundcheck() const
|
||||||
|
{
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
void RIFF::Info::Tag::setTitle(const String &s)
|
void RIFF::Info::Tag::setTitle(const String &s)
|
||||||
{
|
{
|
||||||
setFieldText("INAM", s);
|
setFieldText("INAM", s);
|
||||||
|
|
|
@ -116,6 +116,7 @@ namespace TagLib {
|
||||||
virtual float rgAlbumPeak() const;
|
virtual float rgAlbumPeak() const;
|
||||||
virtual float rgTrackGain() const;
|
virtual float rgTrackGain() const;
|
||||||
virtual float rgTrackPeak() const;
|
virtual float rgTrackPeak() const;
|
||||||
|
virtual String soundcheck() const;
|
||||||
|
|
||||||
virtual void setTitle(const String &s);
|
virtual void setTitle(const String &s);
|
||||||
virtual void setAlbumArtist(const String &s);
|
virtual void setAlbumArtist(const String &s);
|
||||||
|
|
|
@ -161,6 +161,12 @@ namespace TagLib {
|
||||||
*/
|
*/
|
||||||
virtual float rgTrackPeak() const = 0;
|
virtual float rgTrackPeak() const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the Apple SoundCheck tag; if there is tag set, this will
|
||||||
|
* return empty.
|
||||||
|
*/
|
||||||
|
virtual String soundcheck() const = 0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Sets the title to \a s. If \a s is String::null then this value will be
|
* Sets the title to \a s. If \a s is String::null then this value will be
|
||||||
* cleared.
|
* cleared.
|
||||||
|
|
|
@ -243,6 +243,11 @@ float TagUnion::rgTrackPeak() const
|
||||||
floatUnion(rgTrackPeak);
|
floatUnion(rgTrackPeak);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String TagUnion::soundcheck() const
|
||||||
|
{
|
||||||
|
stringUnion(soundcheck);
|
||||||
|
}
|
||||||
|
|
||||||
void TagUnion::setTitle(const String &s)
|
void TagUnion::setTitle(const String &s)
|
||||||
{
|
{
|
||||||
setUnion(Title, s);
|
setUnion(Title, s);
|
||||||
|
|
|
@ -73,6 +73,7 @@ namespace TagLib {
|
||||||
virtual float rgAlbumPeak() const;
|
virtual float rgAlbumPeak() const;
|
||||||
virtual float rgTrackGain() const;
|
virtual float rgTrackGain() const;
|
||||||
virtual float rgTrackPeak() const;
|
virtual float rgTrackPeak() const;
|
||||||
|
virtual String soundcheck() const;
|
||||||
|
|
||||||
virtual void setTitle(const String &s);
|
virtual void setTitle(const String &s);
|
||||||
virtual void setAlbumArtist(const String &s);
|
virtual void setAlbumArtist(const String &s);
|
||||||
|
|
|
@ -494,17 +494,17 @@ ByteVector String::data(Type t) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int String::toInt() const
|
int String::toInt(unsigned int base) const
|
||||||
{
|
{
|
||||||
return toInt(0);
|
return toInt(0, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
int String::toInt(bool *ok) const
|
int String::toInt(bool *ok, unsigned int base) const
|
||||||
{
|
{
|
||||||
const wchar_t *begin = d->data.c_str();
|
const wchar_t *begin = d->data.c_str();
|
||||||
wchar_t *end;
|
wchar_t *end;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
const long value = ::wcstol(begin, &end, 10);
|
const long value = ::wcstol(begin, &end, base);
|
||||||
|
|
||||||
// Has wcstol() consumed the entire string and not overflowed?
|
// Has wcstol() consumed the entire string and not overflowed?
|
||||||
if(ok) {
|
if(ok) {
|
||||||
|
|
|
@ -361,7 +361,7 @@ namespace TagLib {
|
||||||
* string does not represent a number.
|
* string does not represent a number.
|
||||||
*/
|
*/
|
||||||
// BIC: merge with the method below
|
// BIC: merge with the method below
|
||||||
int toInt() const;
|
int toInt(unsigned int base = 10) const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Convert the string to an integer.
|
* Convert the string to an integer.
|
||||||
|
@ -370,7 +370,7 @@ namespace TagLib {
|
||||||
* true and returns the integer. Otherwise it sets \a *ok to false
|
* true and returns the integer. Otherwise it sets \a *ok to false
|
||||||
* and the result is undefined.
|
* and the result is undefined.
|
||||||
*/
|
*/
|
||||||
int toInt(bool *ok) const;
|
int toInt(bool *ok, unsigned int base = 10) const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Convert the string to a float.
|
* Convert the string to a float.
|
||||||
|
|
|
@ -75,6 +75,7 @@
|
||||||
int year, track, disc;
|
int year, track, disc;
|
||||||
float rgAlbumGain, rgAlbumPeak, rgTrackGain, rgTrackPeak;
|
float rgAlbumGain, rgAlbumPeak, rgTrackGain, rgTrackPeak;
|
||||||
TagLib::String cuesheet;
|
TagLib::String cuesheet;
|
||||||
|
TagLib::String soundcheck;
|
||||||
|
|
||||||
artist = tag->artist();
|
artist = tag->artist();
|
||||||
albumartist = tag->albumartist();
|
albumartist = tag->albumartist();
|
||||||
|
@ -102,6 +103,25 @@
|
||||||
[dict setObject:[NSNumber numberWithFloat:rgTrackGain] forKey:@"replayGainTrackGain"];
|
[dict setObject:[NSNumber numberWithFloat:rgTrackGain] forKey:@"replayGainTrackGain"];
|
||||||
[dict setObject:[NSNumber numberWithFloat:rgTrackPeak] forKey:@"replayGainTrackPeak"];
|
[dict setObject:[NSNumber numberWithFloat:rgTrackPeak] forKey:@"replayGainTrackPeak"];
|
||||||
|
|
||||||
|
soundcheck = tag->soundcheck();
|
||||||
|
if (!soundcheck.isEmpty()) {
|
||||||
|
TagLib::StringList tag = soundcheck.split(" ");
|
||||||
|
TagLib::StringList wantedTag;
|
||||||
|
for (int i = 0, count = tag.size(); i < count; i++)
|
||||||
|
{
|
||||||
|
if (tag[i].length() == 8)
|
||||||
|
wantedTag.append(tag[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wantedTag.size() >= 10) {
|
||||||
|
float volume1 = - log10( (double)((uint32_t)wantedTag[0].toInt(16)) / 1000 ) * 10;
|
||||||
|
float volume2 = - log10( (double)((uint32_t)wantedTag[1].toInt(16)) / 1000 ) * 10;
|
||||||
|
float volumeToUse = MIN(volume1, volume2);
|
||||||
|
float volumeScale = pow( 10, volumeToUse / 20 );
|
||||||
|
[dict setObject:[NSNumber numberWithFloat:volumeScale] forKey:@"volume"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!artist.isEmpty())
|
if (!artist.isEmpty())
|
||||||
[dict setObject:[NSString stringWithUTF8String:artist.toCString(true)] forKey:@"artist"];
|
[dict setObject:[NSString stringWithUTF8String:artist.toCString(true)] forKey:@"artist"];
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue