TagLib: Support reading Apple SoundCheck tags from ID3v2 and MP4

CQTexperiment
Christopher Snowhill 2022-01-22 20:20:24 -08:00
parent b54b10861b
commit 72f1168498
22 changed files with 106 additions and 6 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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)
{

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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.

View File

@ -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);

View File

@ -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);

View File

@ -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) {

View File

@ -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.

View File

@ -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();
@ -101,6 +102,25 @@
[dict setObject:[NSNumber numberWithFloat:rgAlbumPeak] forKey:@"replayGainAlbumPeak"];
[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"];