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();
|
||||
}
|
||||
|
||||
String APE::Tag::soundcheck() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
void APE::Tag::setTitle(const String &s)
|
||||
{
|
||||
addValue("TITLE", s, true);
|
||||
|
|
|
@ -101,6 +101,7 @@ namespace TagLib {
|
|||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() const;
|
||||
virtual String soundcheck() const;
|
||||
|
||||
virtual void setTitle(const String &s);
|
||||
virtual void setAlbumArtist(const String &s);
|
||||
|
|
|
@ -154,6 +154,11 @@ float ASF::Tag::rgTrackPeak() const
|
|||
return 0;
|
||||
}
|
||||
|
||||
String ASF::Tag::soundcheck() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
void ASF::Tag::setTitle(const String &value)
|
||||
{
|
||||
d->title = value;
|
||||
|
|
|
@ -110,6 +110,7 @@ namespace TagLib {
|
|||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() const;
|
||||
virtual String soundcheck() const;
|
||||
|
||||
/*!
|
||||
* Sets the title to \a s.
|
||||
|
|
|
@ -124,6 +124,11 @@ float Mod::Tag::rgTrackPeak() const
|
|||
return 0;
|
||||
}
|
||||
|
||||
String Mod::Tag::soundcheck() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
String Mod::Tag::trackerName() const
|
||||
{
|
||||
return d->trackerName;
|
||||
|
|
|
@ -124,6 +124,11 @@ namespace TagLib {
|
|||
*/
|
||||
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.
|
||||
* Only XM files store this tag to the file as such, for other formats
|
||||
|
|
|
@ -834,6 +834,14 @@ MP4::Tag::rgTrackPeak() const
|
|||
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
|
||||
MP4::Tag::setTitle(const String &value)
|
||||
{
|
||||
|
|
|
@ -67,6 +67,7 @@ namespace TagLib {
|
|||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() const;
|
||||
virtual String soundcheck() const;
|
||||
|
||||
virtual void setTitle(const String &value);
|
||||
virtual void setAlbumArtist(const String &value);
|
||||
|
|
|
@ -197,6 +197,11 @@ float ID3v1::Tag::rgTrackPeak() const
|
|||
return 0;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::soundcheck() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setTitle(const String &s)
|
||||
{
|
||||
d->title = s;
|
||||
|
|
|
@ -149,6 +149,7 @@ namespace TagLib {
|
|||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() const;
|
||||
virtual String soundcheck() const;
|
||||
|
||||
virtual void setTitle(const String &s);
|
||||
virtual void setAlbumArtist(const String &s);
|
||||
|
|
|
@ -312,6 +312,24 @@ float ID3v2::Tag::rgTrackPeak() const
|
|||
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)
|
||||
{
|
||||
setTextFrame("TIT2", s);
|
||||
|
|
|
@ -173,6 +173,7 @@ namespace TagLib {
|
|||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() const;
|
||||
virtual String soundcheck() const;
|
||||
|
||||
virtual void setTitle(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();
|
||||
}
|
||||
|
||||
String Ogg::XiphComment::soundcheck() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
void Ogg::XiphComment::setTitle(const String &s)
|
||||
{
|
||||
addField("TITLE", s);
|
||||
|
|
|
@ -94,6 +94,7 @@ namespace TagLib {
|
|||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() const;
|
||||
virtual String soundcheck() const;
|
||||
|
||||
virtual void setTitle(const String &s);
|
||||
virtual void setAlbumArtist(const String &s);
|
||||
|
|
|
@ -158,6 +158,11 @@ float RIFF::Info::Tag::rgTrackPeak() const
|
|||
return 0;
|
||||
}
|
||||
|
||||
String RIFF::Info::Tag::soundcheck() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
void RIFF::Info::Tag::setTitle(const String &s)
|
||||
{
|
||||
setFieldText("INAM", s);
|
||||
|
|
|
@ -116,6 +116,7 @@ namespace TagLib {
|
|||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() const;
|
||||
virtual String soundcheck() const;
|
||||
|
||||
virtual void setTitle(const String &s);
|
||||
virtual void setAlbumArtist(const String &s);
|
||||
|
|
|
@ -161,6 +161,12 @@ namespace TagLib {
|
|||
*/
|
||||
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
|
||||
* cleared.
|
||||
|
|
|
@ -243,6 +243,11 @@ float TagUnion::rgTrackPeak() const
|
|||
floatUnion(rgTrackPeak);
|
||||
}
|
||||
|
||||
String TagUnion::soundcheck() const
|
||||
{
|
||||
stringUnion(soundcheck);
|
||||
}
|
||||
|
||||
void TagUnion::setTitle(const String &s)
|
||||
{
|
||||
setUnion(Title, s);
|
||||
|
|
|
@ -73,6 +73,7 @@ namespace TagLib {
|
|||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() const;
|
||||
virtual String soundcheck() const;
|
||||
|
||||
virtual void setTitle(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();
|
||||
wchar_t *end;
|
||||
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?
|
||||
if(ok) {
|
||||
|
|
|
@ -361,7 +361,7 @@ namespace TagLib {
|
|||
* string does not represent a number.
|
||||
*/
|
||||
// BIC: merge with the method below
|
||||
int toInt() const;
|
||||
int toInt(unsigned int base = 10) const;
|
||||
|
||||
/*!
|
||||
* Convert the string to an integer.
|
||||
|
@ -370,7 +370,7 @@ namespace TagLib {
|
|||
* true and returns the integer. Otherwise it sets \a *ok to false
|
||||
* 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.
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
int year, track, disc;
|
||||
float rgAlbumGain, rgAlbumPeak, rgTrackGain, rgTrackPeak;
|
||||
TagLib::String cuesheet;
|
||||
TagLib::String soundcheck;
|
||||
|
||||
artist = tag->artist();
|
||||
albumartist = tag->albumartist();
|
||||
|
@ -102,6 +103,25 @@
|
|||
[dict setObject:[NSNumber numberWithFloat:rgTrackGain] forKey:@"replayGainTrackGain"];
|
||||
[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())
|
||||
[dict setObject:[NSString stringWithUTF8String:artist.toCString(true)] forKey:@"artist"];
|
||||
|
||||
|
|
Loading…
Reference in New Issue