void FileHelper::setRatingForID3v2(int rating, TagLib::ID3v2::Tag *tag) { TagLib::ID3v2::FrameList l = tag->frameListMap()["POPM"]; // If one wants to remove the existing rating if (rating == 0 && !l.isEmpty()) { tag->removeFrame(l.front()); } else { TagLib::ID3v2::PopularimeterFrame *pf = nullptr; if (l.isEmpty()) { pf = new TagLib::ID3v2::PopularimeterFrame(); tag->addFrame(pf); } else { pf = static_cast<TagLib::ID3v2::PopularimeterFrame*>(l.front()); } switch (rating) { case 1: pf->setRating(1); break; case 2: pf->setRating(64); break; case 3: pf->setRating(128); break; case 4: pf->setRating(196); break; case 5: pf->setRating(255); break; } } }
bool SoundSource::processID3v2Tag(TagLib::ID3v2::Tag* id3v2) { // Print every frame in the file. if (s_bDebugMetadata) { TagLib::ID3v2::FrameList::ConstIterator it = id3v2->frameList().begin(); for(; it != id3v2->frameList().end(); it++) { qDebug() << "ID3V2" << (*it)->frameID().data() << "-" << TStringToQString((*it)->toString()); } } TagLib::ID3v2::FrameList bpmFrame = id3v2->frameListMap()["TBPM"]; if (!bpmFrame.isEmpty()) { QString sBpm = TStringToQString(bpmFrame.front()->toString()); processBpmString("ID3v2", sBpm); } TagLib::ID3v2::FrameList keyFrame = id3v2->frameListMap()["TKEY"]; if (!keyFrame.isEmpty()) { QString sKey = TStringToQString(keyFrame.front()->toString()); setKey(sKey); } // Foobar2000-style ID3v2.3.0 tags // TODO: Check if everything is ok. TagLib::ID3v2::FrameList frames = id3v2->frameListMap()["TXXX"]; for ( TagLib::ID3v2::FrameList::Iterator it = frames.begin(); it != frames.end(); ++it ) { TagLib::ID3v2::UserTextIdentificationFrame* ReplayGainframe = dynamic_cast<TagLib::ID3v2::UserTextIdentificationFrame*>( *it ); if ( ReplayGainframe && ReplayGainframe->fieldList().size() >= 2 ) { QString desc = TStringToQString( ReplayGainframe->description() ).toLower(); if ( desc == "replaygain_album_gain" ){ QString sReplayGain = TStringToQString( ReplayGainframe->fieldList()[1]); parseReplayGainString(sReplayGain); } if ( desc == "replaygain_track_gain" ){ QString sReplayGain = TStringToQString( ReplayGainframe->fieldList()[1]); parseReplayGainString(sReplayGain); } } } TagLib::ID3v2::FrameList composerFrame = id3v2->frameListMap()["TCOM"]; if (!composerFrame.isEmpty()) { QString sComposer = TStringToQString(composerFrame.front()->toString()); setComposer(sComposer); } return true; }
void mttFile::checkEncodings( void ) { fileref = new TagLib::FileRef( QFile::encodeName( fname ).constData() ); if ( isMpeg() ) { TagLib::MPEG::File *f = dynamic_cast<TagLib::MPEG::File *>(fileref->file()); if ( f->ID3v2Tag() ) { TagLib::ID3v2::FrameList l = f->ID3v2Tag()->frameListMap()["TALB"]; if ( !l.isEmpty() ) { TagLib::ID3v2::TextIdentificationFrame *tf = dynamic_cast<TagLib::ID3v2::TextIdentificationFrame *>(l.front()); if ( tf && tf->textEncoding() != TagLib::String::UTF8 ) tf->setTextEncoding( TagLib::String::UTF8 ); } l = f->ID3v2Tag()->frameListMap()["TIT2"]; if ( !l.isEmpty() ) { TagLib::ID3v2::TextIdentificationFrame *tf = dynamic_cast<TagLib::ID3v2::TextIdentificationFrame *>(l.front()); if ( tf && tf->textEncoding() != TagLib::String::UTF8 ) tf->setTextEncoding( TagLib::String::UTF8 ); } l = f->ID3v2Tag()->frameListMap()["TPE1"]; if ( !l.isEmpty() ) { TagLib::ID3v2::TextIdentificationFrame *tf = dynamic_cast<TagLib::ID3v2::TextIdentificationFrame *>(l.front()); if ( tf && tf->textEncoding() != TagLib::String::UTF8 ) tf->setTextEncoding( TagLib::String::UTF8 ); } l = f->ID3v2Tag()->frameListMap()["TCON"]; if ( !l.isEmpty() ) { TagLib::ID3v2::TextIdentificationFrame *tf = dynamic_cast<TagLib::ID3v2::TextIdentificationFrame *>(l.front()); if ( tf && tf->textEncoding() != TagLib::String::UTF8 ) tf->setTextEncoding( TagLib::String::UTF8 ); } l = f->ID3v2Tag()->frameListMap()["COMM"]; if ( !l.isEmpty() ) { TagLib::ID3v2::TextIdentificationFrame *tf = dynamic_cast<TagLib::ID3v2::TextIdentificationFrame *>(l.front()); if ( tf && tf->textEncoding() != TagLib::String::UTF8 ) tf->setTextEncoding( TagLib::String::UTF8 ); } } } delete fileref; fileref = NULL; }
int FileHelper::ratingForID3v2(TagLib::ID3v2::Tag *tag) const { int r = -1; TagLib::ID3v2::FrameList l = tag->frameListMap()["POPM"]; if (l.isEmpty()) { return r; } if (TagLib::ID3v2::PopularimeterFrame *pf = static_cast<TagLib::ID3v2::PopularimeterFrame*>(l.front())) { switch (pf->rating()) { case 1: r = 1; break; case 64: r = 2; break; case 128: r = 3; break; case 196: r = 4; break; case 255: r = 5; break; } } return r; }
bool CTagBase::exportImage(const wchar_t* s) { if (!s) return false; if (_tagFile) { //get picture TagLib::MPEG::File *f = (TagLib::MPEG::File *)_tagFile.get(); if (!f->hasID3v2Tag() || f->ID3v2Tag()->isEmpty()) return false; /* TagLib::ID3v2::FrameList::ConstIterator it = f->ID3v2Tag()->frameList().begin(); for (; it != f->ID3v2Tag()->frameList().end(); it++) { if ((*it)->frameID().operator == (TagLib::ByteVector("APIC"))) { HANDLE hFile = CreateFile(s, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) return false; int nWriteBytes = 0; size_t size = (*it)->size(); ::WriteFile(hFile, (*it)->render().data(), (*it)->size(), (LPDWORD)&nWriteBytes, NULL); ::CloseHandle(hFile); if (nWriteBytes != size) return false; return true; } }*/ if (f->ID3v2Tag()->frameListMap().size() == 0) return false; if (f->ID3v2Tag()->frameListMap().find("APIC") == f->ID3v2Tag()->frameListMap().end()) return false; TagLib::ID3v2::FrameList Flist = f->ID3v2Tag()->frameListMap()["APIC"]; if (Flist.isEmpty()) return false; TagLib::ID3v2::AttachedPictureFrame *p = static_cast<TagLib::ID3v2::AttachedPictureFrame *>(Flist.front()); size_t size = p->picture().size(); CString strPicType = p->mimeType().toCString(true); int nPos = strPicType.Find('/'); CString strTemp = strPicType.Right(strPicType.GetLength() - nPos - 1); //CString strPicPath = s; //if (strTemp == _T("png")) // strPicPath.Append(_T(".png")); //else // strPicPath.Append(_T(".jpg")); HANDLE hFile = CreateFile(s, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) return false; int nWriteBytes = 0; ::WriteFile(hFile, p->picture().data(), size, (LPDWORD)&nWriteBytes, NULL); ::CloseHandle(hFile); if (nWriteBytes != size) return false; return true; } return false; }
void FileHelper::setFlacAttribute(const std::string &attribute, const QString &value) { if (TagLib::FLAC::File *flacFile = static_cast<TagLib::FLAC::File*>(_file)) { if (flacFile->hasID3v2Tag()) { TagLib::ID3v2::Tag *tag = flacFile->ID3v2Tag(); QString key = this->convertKeyToID3v2Key(attribute.data()); TagLib::ID3v2::FrameList l = tag->frameListMap()[key.toStdString().data()]; if (!l.isEmpty()) { tag->removeFrame(l.front()); } TagLib::ID3v2::TextIdentificationFrame *tif = new TagLib::ID3v2::TextIdentificationFrame(TagLib::ByteVector("ARTISTALBUM")); tif->setText(value.toStdString().data()); tag->addFrame(tif); } else if (flacFile->hasID3v1Tag()) { qDebug() << Q_FUNC_INFO << "Not implemented (FLAC ID3v1)"; } else if (flacFile->hasXiphComment()) { TagLib::Ogg::XiphComment *xiph = flacFile->xiphComment(); if (value.isEmpty()) { xiph->removeField(attribute.data()); } else { xiph->addField(attribute.data(), value.toStdString().data()); } } } }
void loadCover(Tune *tune, TagLib::File *file) { if (!searchLocalCover(tune)) { auto mpeg = dynamic_cast<TagLib::MPEG::File*>(file); if(mpeg) { TagLib::ID3v2::Tag* tag2 = mpeg->ID3v2Tag(); if(tag2) { TagLib::ID3v2::FrameList frameList = tag2->frameList("APIC"); if(!frameList.isEmpty()) { for(unsigned int i = 0; i < frameList.size(); ++i) { auto *coverImg = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame *>(frameList[i]); if(coverImg) { QImage cover; if(cover.loadFromData(reinterpret_cast<const uchar*>(coverImg->picture().data()), coverImg->picture().size())) { tune->setCover(cover); break; } } } } } } } }
QString FileHelper::extractFlacFeature(const QString &featureToExtract) const { QString feature; if (TagLib::FLAC::File *flacFile = static_cast<TagLib::FLAC::File*>(_file)) { if (flacFile->ID3v2Tag()) { QString key = this->convertKeyToID3v2Key(featureToExtract); TagLib::ID3v2::FrameList l = flacFile->ID3v2Tag()->frameListMap()[key.toStdString().data()]; // Fallback to the generic map in case we didn't find the matching key if (l.isEmpty()) { TagLib::StringList list = flacFile->properties()[featureToExtract.toStdString()]; if (!list.isEmpty()) { feature = list.front().toCString(true); } } else { feature = QString(l.front()->toString().toCString(true)); } } else if (flacFile->ID3v1Tag()) { qDebug() << Q_FUNC_INFO << "Not yet implemented for ID3v1Tag FLAC file"; } else if (flacFile->xiphComment()) { const TagLib::Ogg::FieldListMap map = flacFile->xiphComment()->fieldListMap(); if (!map[featureToExtract.toStdString().data()].isEmpty()) { feature = QString(map[featureToExtract.toStdString().data()].front().toCString(true)); } } } return feature; }
void AudioTagger::addID3v2Tag(TagLib::ID3v2::Tag* id3v2) { if (!id3v2) return; TagLib::ID3v2::FrameList bpmFrame = id3v2->frameListMap()["TBPM"]; if (!bpmFrame.isEmpty()) { bpmFrame.front()->setText(m_bpm.toStdString()); } else { // add new frame TextIdentificationFrame which is responsible for TKEY and TBPM // see http://developer.kde.org/~wheeler/taglib/api/classTagLib_1_1ID3v2_1_1TextIdentificationFrame.html TagLib::ID3v2::TextIdentificationFrame* newFrame = new TagLib::ID3v2::TextIdentificationFrame("TBPM", TagLib::String::Latin1); newFrame->setText(m_bpm.toStdString()); id3v2->addFrame(newFrame); } TagLib::ID3v2::FrameList keyFrame = id3v2->frameListMap()["TKEY"]; if (!keyFrame.isEmpty()) { keyFrame.front()->setText(m_key.toStdString()); } else { //add new frame TagLib::ID3v2::TextIdentificationFrame* newFrame = new TagLib::ID3v2::TextIdentificationFrame("TKEY", TagLib::String::Latin1); newFrame->setText(m_key.toStdString()); id3v2->addFrame(newFrame); } TagLib::ID3v2::FrameList composerFrame = id3v2->frameListMap()["TCOM"]; if (!composerFrame.isEmpty()) { composerFrame.front()->setText(m_composer.toStdString()); } else { //add new frame TagLib::ID3v2::TextIdentificationFrame* newFrame = new TagLib::ID3v2::TextIdentificationFrame( "TCOM", TagLib::String::Latin1); newFrame->setText(m_composer.toStdString()); id3v2->addFrame(newFrame); } }
QString FileHelper::extractMpegFeature(const QString &featureToExtract) const { QString feature; if (TagLib::MPEG::File *mpegFile = static_cast<TagLib::MPEG::File*>(_file)) { if (mpegFile->hasID3v2Tag()) { TagLib::ID3v2::FrameList l = mpegFile->ID3v2Tag()->frameListMap()[featureToExtract.toStdString().data()]; if (!l.isEmpty()) { feature = QString(l.front()->toString().toCString(true)); } } } return feature; }
TagLib::Tag *mttFile::getTag( bool create ) { if ( tag == NULL ) { fileref = new TagLib::FileRef( QFile::encodeName( fname ).constData() ); if ( fileref ) { if ( ismpeg ) { TagLib::MPEG::File *f = dynamic_cast<TagLib::MPEG::File *>(fileref->file()); tag = new TagLib::ID3v2::Tag(); if ( f->ID3v2Tag( create ) != NULL ) { TagLib::Tag::duplicate( dynamic_cast<TagLib::Tag *>( f->ID3v2Tag( create ) ), tag, true ); // Read extra mp3 tags int i; for ( i = 0; i < EF_NUM; i++ ) { TagLib::ID3v2::FrameList l = f->ID3v2Tag()->frameListMap()[extraFrames[i][0]]; if ( !l.isEmpty() ) { mp3eframes += extraFrames[i][0]; mp3eframes += TStringToQString( l.front()->toString() ); } } } delete fileref; fileref = NULL; return tag; } else { // If the file is ogg or flac tag = new TagLib::Ogg::XiphComment(); if ( fileref->tag() ) // If a tag already exists TagLib::Tag::duplicate( fileref->tag(), tag, true ); delete fileref; fileref = NULL; return tag; } } else { //qDebug( "fileref = NULL" ); return NULL; } delete fileref; fileref = NULL; } else return tag; }
void FileHelper::setArtistAlbum(const QString &artistAlbum) { switch (_fileType) { case EXT_FLAC: { this->setFlacAttribute("ALBUMARTIST", artistAlbum); break; } case EXT_MP4:{ TagLib::StringList l; l.append(artistAlbum.toStdString().data()); TagLib::MP4::Item item(l); this->setMp4Attribute("aART", item); break; } case EXT_MPC: //mpcFile = static_cast<MPC::File*>(f); qDebug() << Q_FUNC_INFO << "Not implemented for MPC"; break; case EXT_MP3:{ TagLib::MPEG::File *mpegFile = static_cast<TagLib::MPEG::File*>(_file); if (mpegFile->hasID3v2Tag()) { TagLib::ID3v2::Tag *tag = mpegFile->ID3v2Tag(); QString convertedKey = this->convertKeyToID3v2Key("ARTISTALBUM"); TagLib::ID3v2::FrameList l = tag->frameListMap()[convertedKey.toStdString().data()]; if (!l.isEmpty()) { tag->removeFrame(l.front()); } TagLib::ID3v2::TextIdentificationFrame *tif = new TagLib::ID3v2::TextIdentificationFrame(TagLib::ByteVector(convertedKey.toStdString().data())); tif->setText(artistAlbum.toStdString().data()); tag->addFrame(tif); } else if (mpegFile->hasID3v1Tag()) { qDebug() << Q_FUNC_INFO << "Not implemented for ID3v1Tag"; } break; } case EXT_OGG: { TagLib::Ogg::XiphComment *xiphComment = static_cast<TagLib::Ogg::XiphComment*>(_file->tag()); if (xiphComment) { xiphComment->addField("ALBUMARTIST", artistAlbum.toStdString().data()); } else { qDebug() << Q_FUNC_INFO << "Not implemented for this OGG file"; } break; } default: qDebug() << Q_FUNC_INFO << "Not implemented for this type of file"; break; } }
QString extractMBIDFromFile(TagLib::MPEG::File *file) { TagLib::ID3v2::Tag *tag = file->ID3v2Tag(); TagLib::ID3v2::FrameList ufid = tag->frameListMap()["UFID"]; if (!ufid.isEmpty()) { for (TagLib::ID3v2::FrameList::Iterator i = ufid.begin(); i != ufid.end(); i++) { TagLib::ID3v2::UniqueFileIdentifierFrame *frame = dynamic_cast<TagLib::ID3v2::UniqueFileIdentifierFrame *>(*i); if (frame && frame->owner() == "http://musicbrainz.org") { TagLib::ByteVector id = frame->identifier(); return QString::fromAscii(id.data(), id.size()); } } } return QString(); }
bool CoverUtils::coverFromMPEGTags(TagLib::ID3v2::Tag *tag, Album *album) { if (!tag) return false; TagLib::ID3v2::FrameList list = tag->frameList("APIC"); if (list.isEmpty()) return false; TagLib::ID3v2::AttachedPictureFrame *frame = static_cast<TagLib::ID3v2::AttachedPictureFrame *>(list.front()); if (!frame) return false; const int frameSize = frame->picture().size(); if (frameSize <= 0) return false; QImage image; image.loadFromData((const uchar *) frame->picture().data(), frame->picture().size()); if (!isAcceptableImage(image)) return false; return saveImage(image, album); }
/*! * \copydoc MetaIO::write() */ bool MetaIOID3::write(Metadata* mdata) { TagLib::MPEG::File *mpegfile = OpenFile(mdata->Filename()); if (!mpegfile) return false; TagLib::ID3v2::Tag *tag = mpegfile->ID3v2Tag(); if (!tag) { delete mpegfile; return false; } WriteGenericMetadata(tag, mdata); // MythTV rating and playcount, stored in POPM frame writeRating(tag, mdata->Rating()); writePlayCount(tag, mdata->PlayCount()); // MusicBrainz ID UserTextIdentificationFrame *musicbrainz = NULL; musicbrainz = find(tag, "MusicBrainz Album Artist Id"); if (mdata->Compilation()) { if (!musicbrainz) { musicbrainz = new UserTextIdentificationFrame(TagLib::String::UTF8); tag->addFrame(musicbrainz); musicbrainz->setDescription("MusicBrainz Album Artist Id"); } musicbrainz->setText(MYTH_MUSICBRAINZ_ALBUMARTIST_UUID); } else if (musicbrainz) tag->removeFrame(musicbrainz); // Compilation Artist Frame (TPE4/2) if (!mdata->CompilationArtist().isEmpty()) { TextIdentificationFrame *tpe4frame = NULL; TagLib::ID3v2::FrameList tpelist = tag->frameListMap()["TPE4"]; if (!tpelist.isEmpty()) tpe4frame = (TextIdentificationFrame *)tpelist.front(); if (!tpe4frame) { tpe4frame = new TextIdentificationFrame(TagLib::ByteVector("TPE4"), TagLib::String::UTF8); tag->addFrame(tpe4frame); } tpe4frame->setText(QStringToTString(mdata->CompilationArtist())); TextIdentificationFrame *tpe2frame = NULL; tpelist = tag->frameListMap()["TPE2"]; if (!tpelist.isEmpty()) tpe2frame = (TextIdentificationFrame *)tpelist.front(); if (!tpe2frame) { tpe2frame = new TextIdentificationFrame(TagLib::ByteVector("TPE2"), TagLib::String::UTF8); tag->addFrame(tpe2frame); } tpe2frame->setText(QStringToTString(mdata->CompilationArtist())); } bool result = mpegfile->save(); delete mpegfile; return result; }
/*! * \copydoc MetaIO::read() */ Metadata *MetaIOID3::read(QString filename) { TagLib::MPEG::File *mpegfile = OpenFile(filename); if (!mpegfile) return NULL; TagLib::ID3v2::Tag *tag = mpegfile->ID3v2Tag(); if (!tag) { delete mpegfile; return NULL; } // if there is no ID3v2 tag, try to read the ID3v1 tag and copy it to the ID3v2 tag structure if (tag->isEmpty()) { TagLib::ID3v1::Tag *tag_v1 = mpegfile->ID3v1Tag(); if (!tag_v1) { delete mpegfile; return NULL; } if (!tag_v1->isEmpty()) { tag->setTitle(tag_v1->title()); tag->setArtist(tag_v1->artist()); tag->setAlbum(tag_v1->album()); tag->setTrack(tag_v1->track()); tag->setYear(tag_v1->year()); tag->setGenre(tag_v1->genre()); } } Metadata *metadata = new Metadata(filename); ReadGenericMetadata(tag, metadata); bool compilation = false; // Compilation Artist (TPE4 Remix) or fallback to (TPE2 Band) // N.B. The existance of a either frame is NOT an indication that this // is a compilation, but if it is then one of them will probably hold // the compilation artist. TextIdentificationFrame *tpeframe = NULL; TagLib::ID3v2::FrameList tpelist = tag->frameListMap()["TPE4"]; if (tpelist.isEmpty() || tpelist.front()->toString().isEmpty()) tpelist = tag->frameListMap()["TPE2"]; if (!tpelist.isEmpty()) tpeframe = (TextIdentificationFrame *)tpelist.front(); if (tpeframe && !tpeframe->toString().isEmpty()) { QString compilation_artist = TStringToQString(tpeframe->toString()) .trimmed(); metadata->setCompilationArtist(compilation_artist); } // MythTV rating and playcount, stored in POPM frame PopularimeterFrame *popm = findPOPM(tag, email); if (!popm) { if (!tag->frameListMap()["POPM"].isEmpty()) popm = dynamic_cast<PopularimeterFrame *> (tag->frameListMap()["POPM"].front()); } if (popm) { int rating = popm->rating(); rating = static_cast<int>(((static_cast<float>(rating)/255.0) * 10.0) + 0.5); metadata->setRating(rating); metadata->setPlaycount(popm->counter()); } // Look for MusicBrainz Album+Artist ID in TXXX Frame UserTextIdentificationFrame *musicbrainz = find(tag, "MusicBrainz Album Artist Id"); if (musicbrainz) { // If the MusicBrainz ID is the special "Various Artists" ID // then compilation is TRUE if (!compilation && !musicbrainz->fieldList().isEmpty()) compilation = (MYTH_MUSICBRAINZ_ALBUMARTIST_UUID == TStringToQString(musicbrainz->fieldList().front())); } // TLEN - Ignored intentionally, some encoders write bad values // e.g. Lame under certain circumstances will always write a length of // 27 hours metadata->setCompilation(compilation); TagLib::FileRef *fileref = new TagLib::FileRef(mpegfile); metadata->setLength(getTrackLength(fileref)); // FileRef takes ownership of mpegfile, and is responsible for it's // deletion. Messy. delete fileref; return metadata; }
static Meta::ReplayGainTagMap readID3v2Tags( TagLib::ID3v2::Tag *tag ) { Meta::ReplayGainTagMap map; { // ID3v2.4.0 native replay gain tag support (as written by Quod Libet, for example). TagLib::ID3v2::FrameList frames = tag->frameListMap()["RVA2"]; frames.append(tag->frameListMap()["XRVA"]); if ( !frames.isEmpty() ) { for ( unsigned int i = 0; i < frames.size(); ++i ) { // we have to parse this frame ourselves // ID3v2 frame header is 10 bytes, so skip that TagLib::ByteVector data = frames[i]->render().mid( 10 ); unsigned int offset = 0; QString desc( data.data() ); offset += desc.count() + 1; unsigned int channel = data.mid( offset, 1 ).toUInt( true ); // channel 1 is the main volume - the only one we care about if ( channel == 1 ) { ++offset; qint16 adjustment512 = data.mid( offset, 2 ).toShort( true ); qreal adjustment = ( (qreal)adjustment512 ) / 512.0; offset += 2; unsigned int peakBits = data.mid( offset, 1 ).toUInt( true ); ++offset; bool ok = false; qreal peak = readRVA2PeakValue( data.mid( offset ), peakBits, &ok ); if ( ok ) { if ( desc.toLower() == "album" ) { map[Meta::ReplayGain_Album_Gain] = adjustment; map[Meta::ReplayGain_Album_Peak] = peakToDecibels( peak ); } else if ( desc.toLower() == "track" || !map.contains( Meta::ReplayGain_Track_Gain ) ) { map[Meta::ReplayGain_Track_Gain] = adjustment; map[Meta::ReplayGain_Track_Peak] = peakToDecibels( peak ); } } } } if ( !map.isEmpty() ) return map; } } { // Foobar2000-style ID3v2.3.0 tags TagLib::ID3v2::FrameList frames = tag->frameListMap()["TXXX"]; for ( TagLib::ID3v2::FrameList::Iterator it = frames.begin(); it != frames.end(); ++it ) { TagLib::ID3v2::UserTextIdentificationFrame* frame = dynamic_cast<TagLib::ID3v2::UserTextIdentificationFrame*>( *it ); if ( frame && frame->fieldList().size() >= 2 ) { QString desc = TStringToQString( frame->description() ).toLower(); if ( desc == "replaygain_album_gain" ) maybeAddGain( frame->fieldList()[1], Meta::ReplayGain_Album_Gain, &map ); if ( desc == "replaygain_album_peak" ) maybeAddPeak( frame->fieldList()[1], Meta::ReplayGain_Album_Peak, &map ); if ( desc == "replaygain_track_gain" ) maybeAddGain( frame->fieldList()[1], Meta::ReplayGain_Track_Gain, &map ); if ( desc == "replaygain_track_peak" ) maybeAddPeak( frame->fieldList()[1], Meta::ReplayGain_Track_Peak, &map ); } } } return map; }
//Adds dir & its contents to the library void libraryDialog::addDir2Lib(QDir dir) { dir.setFilter(QDir::Files | QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot); QDirIterator di(dir, QDirIterator::Subdirectories); while(di.hasNext()) { di.next(); QString fpath = di.filePath(); QFileInfo f = di.fileInfo(); if(isAudioFile(f))//Add this song to the database { wchar_t wname[250]; //TODO: Dynamic. Need to figure out wchar length from QStr length wname[fpath.toWCharArray(wname)] = 0; TagLib::FileName fname(wname); //We'll store tag information in these: QMap<QString, QString> stmap; QMap<QString, int> itmap; TagLib::File* file = NULL; //MP3 Means we can check for additional info in ID3v2 tags if(f.suffix() == "mp3") { TagLib::MPEG::File* fr = new TagLib::MPEG::File(fname, true, TagLib::AudioProperties::ReadStyle::Fast); if(fr->ID3v2Tag()) { //Somehow this means album artist / band. http://www.id3.org/id3v2.4.0-frames TagLib::ID3v2::FrameList l = fr->ID3v2Tag()->frameList("TPE2"); if(!l.isEmpty()) stmap["albumartist"] = l.front()->toString().toCString(); } file = dynamic_cast<TagLib::File*>(fr); } if(file == NULL) { qDebug() << "ERR: " + fpath; continue; //TODO: Error out here } //Try to get audio properties TagLib::AudioProperties* ap = file->audioProperties(); TagLib::Tag* genTag = file->tag(); stmap["name"] = genTag->title().toCString(); stmap["genre"] = genTag->genre().toCString(); itmap["year"] = genTag->year(); itmap["tracknum"] = genTag->track(); stmap["album"] = genTag->album().toCString(); stmap["artist"] = genTag->artist().toCString(); if(ap != NULL) itmap["length"] = ap->length(); stmap["path"] = fpath; //Add collected info to db DBItem s; s.strVals = stmap; s.intVals = itmap; myparent->dbi->addSong(s); delete file; } else if(f.isDir()) ui.curDirLbl->setText(fpath); //if(top) //If we're the top level of recursion update prog bar // ui.progressBar->setValue(di./siz * 100); qApp->processEvents(); } }
/*! * \copydoc MetaIO::read() */ Metadata *MetaIOID3::read(const QString &filename) { if (!OpenFile(filename)) return NULL; TagLib::ID3v2::Tag *tag = GetID3v2Tag(true); // Create tag if none are found // if there is no ID3v2 tag, try to read the ID3v1 tag and copy it to // the ID3v2 tag structure if (tag->isEmpty()) { TagLib::ID3v1::Tag *tag_v1 = GetID3v1Tag(); if (!tag_v1) return NULL; if (!tag_v1->isEmpty()) { tag->setTitle(tag_v1->title()); tag->setArtist(tag_v1->artist()); tag->setAlbum(tag_v1->album()); tag->setTrack(tag_v1->track()); tag->setYear(tag_v1->year()); tag->setGenre(tag_v1->genre()); } } Metadata *metadata = new Metadata(filename); ReadGenericMetadata(tag, metadata); bool compilation = false; // Compilation Artist (TPE4 Remix) or fallback to (TPE2 Band) // N.B. The existance of a either frame is NOT an indication that this // is a compilation, but if it is then one of them will probably hold // the compilation artist. TextIdentificationFrame *tpeframe = NULL; TagLib::ID3v2::FrameList tpelist = tag->frameListMap()["TPE4"]; if (tpelist.isEmpty() || tpelist.front()->toString().isEmpty()) tpelist = tag->frameListMap()["TPE2"]; if (!tpelist.isEmpty()) tpeframe = (TextIdentificationFrame *)tpelist.front(); if (tpeframe && !tpeframe->toString().isEmpty()) { QString compilation_artist = TStringToQString(tpeframe->toString()) .trimmed(); metadata->setCompilationArtist(compilation_artist); } // MythTV rating and playcount, stored in POPM frame PopularimeterFrame *popm = findPOPM(tag, email); if (!popm) { if (!tag->frameListMap()["POPM"].isEmpty()) popm = dynamic_cast<PopularimeterFrame *> (tag->frameListMap()["POPM"].front()); } if (popm) { int rating = popm->rating(); rating = static_cast<int>(((static_cast<float>(rating)/255.0) * 10.0) + 0.5); metadata->setRating(rating); metadata->setPlaycount(popm->counter()); } // Look for MusicBrainz Album+Artist ID in TXXX Frame UserTextIdentificationFrame *musicbrainz = find(tag, "MusicBrainz Album Artist Id"); if (musicbrainz) { // If the MusicBrainz ID is the special "Various Artists" ID // then compilation is TRUE if (!compilation && !musicbrainz->fieldList().isEmpty()) compilation = (MYTH_MUSICBRAINZ_ALBUMARTIST_UUID == TStringToQString(musicbrainz->fieldList().front())); } // TLEN - Ignored intentionally, some encoders write bad values // e.g. Lame under certain circumstances will always write a length of // 27 hours // Length if (!tag->frameListMap()["TLEN"].isEmpty()) { int length = tag->frameListMap()["TLEN"].front()->toString().toInt(); LOG(VB_FILE, LOG_DEBUG, QString("MetaIOID3::read: Length for '%1' from tag is '%2'\n").arg(filename).arg(length)); } metadata->setCompilation(compilation); metadata->setLength(getTrackLength(m_file)); // The number of tracks on the album, if supplied if (!tag->frameListMap()["TRCK"].isEmpty()) { QString trackFrame = TStringToQString( tag->frameListMap()["TRCK"].front()->toString()) .trimmed(); int trackCount = trackFrame.section('/', -1).toInt(); if (trackCount > 0) metadata->setTrackCount(trackCount); } LOG(VB_FILE, LOG_DEBUG, QString("MetaIOID3::read: Length for '%1' from properties is '%2'\n").arg(filename).arg(metadata->Length())); return metadata; }
/*! * \copydoc MetaIO::write() */ bool MetaIOID3::write(const QString &filename, MusicMetadata* mdata) { if (filename.isEmpty()) return false; if (!OpenFile(filename, true)) return false; TagLib::ID3v2::Tag *tag = GetID3v2Tag(); if (!tag) return false; WriteGenericMetadata(tag, mdata); // MythTV rating and playcount, stored in POPM frame writeRating(tag, mdata->Rating()); writePlayCount(tag, mdata->PlayCount()); writeLastPlay(tag, mdata->LastPlay()); // MusicBrainz ID UserTextIdentificationFrame *musicbrainz = nullptr; musicbrainz = find(tag, "MusicBrainz Album Artist Id"); if (mdata->Compilation()) { if (!musicbrainz) { musicbrainz = new UserTextIdentificationFrame(TagLib::String::UTF8); tag->addFrame(musicbrainz); musicbrainz->setDescription("MusicBrainz Album Artist Id"); } musicbrainz->setText(MYTH_MUSICBRAINZ_ALBUMARTIST_UUID); } else if (musicbrainz) tag->removeFrame(musicbrainz); // Compilation Artist Frame (TPE4/2) if (!mdata->CompilationArtist().isEmpty()) { TextIdentificationFrame *tpe4frame = nullptr; TagLib::ID3v2::FrameList tpelist = tag->frameListMap()["TPE4"]; if (!tpelist.isEmpty()) tpe4frame = (TextIdentificationFrame *)tpelist.front(); if (!tpe4frame) { tpe4frame = new TextIdentificationFrame(TagLib::ByteVector("TPE4"), TagLib::String::UTF8); tag->addFrame(tpe4frame); } tpe4frame->setText(QStringToTString(mdata->CompilationArtist())); TextIdentificationFrame *tpe2frame = nullptr; tpelist = tag->frameListMap()["TPE2"]; if (!tpelist.isEmpty()) tpe2frame = (TextIdentificationFrame *)tpelist.front(); if (!tpe2frame) { tpe2frame = new TextIdentificationFrame(TagLib::ByteVector("TPE2"), TagLib::String::UTF8); tag->addFrame(tpe2frame); } tpe2frame->setText(QStringToTString(mdata->CompilationArtist())); } if (!SaveFile()) return false; return true; }
QString TagLibMetadata::getKey() const{ if(f == NULL || !f->isValid()) return ""; TagLib::MPEG::File* fileTestMpeg = dynamic_cast<TagLib::MPEG::File*>(f); if(fileTestMpeg != NULL){ TagLib::ID3v2::Tag* tagTestId3v2 = fileTestMpeg->ID3v2Tag(); if(tagTestId3v2 != NULL){ TagLib::ID3v2::FrameList l = tagTestId3v2->frameListMap()["TKEY"]; if(!l.isEmpty()){ TagLib::String out = l.front()->toString(); return QString::fromUtf8((out.toCString())); } return ""; } TagLib::ID3v1::Tag* tagTestId3v1 = fileTestMpeg->ID3v1Tag(); if(tagTestId3v1 != NULL){ #ifdef Q_OS_WIN qDebug("ID3v1 does not support the Key tag"); #else qDebug("ID3v1 does not support the Key tag (%s)",f->name()); #endif return "N/A"; } } TagLib::RIFF::AIFF::File* fileTestAiff = dynamic_cast<TagLib::RIFF::AIFF::File*>(f); if(fileTestAiff != NULL){ TagLib::ID3v2::Tag* tagTestId3v2 = fileTestAiff->tag(); if(tagTestId3v2 != NULL){ TagLib::ID3v2::FrameList l = tagTestId3v2->frameListMap()["TKEY"]; if(!l.isEmpty()){ TagLib::String out = l.front()->toString(); return QString::fromUtf8((out.toCString())); } return ""; } } TagLib::RIFF::WAV::File* fileTestWav = dynamic_cast<TagLib::RIFF::WAV::File*>(f); if(fileTestWav != NULL){ TagLib::ID3v2::Tag* tagTestId3v2 = fileTestWav->tag(); if(tagTestId3v2 != NULL){ TagLib::ID3v2::FrameList l = tagTestId3v2->frameListMap()["TKEY"]; if(!l.isEmpty()){ TagLib::String out = l.front()->toString(); return QString::fromUtf8((out.toCString())); } return ""; } } TagLib::MP4::Tag* tagTestMp4 = dynamic_cast<TagLib::MP4::Tag*>(f->tag()); if(tagTestMp4 != NULL){ #ifdef Q_OS_WIN qDebug("iTunes metadata does not support the Key tag"); #else qDebug("iTunes metadata does not support the Key tag (%s)",f->name()); #endif return "N/A"; } TagLib::ASF::Tag* tagTestAsf = dynamic_cast<TagLib::ASF::Tag*>(f->tag()); if(tagTestAsf != NULL){ TagLib::ASF::AttributeList l = tagTestAsf->attributeListMap()["WM/InitialKey"]; if(!l.isEmpty()){ TagLib::String out = l.front().toString(); return QString::fromUtf8((out.toCString())); } return ""; } TagLib::APE::Tag* tagTestApe = dynamic_cast<TagLib::APE::Tag*>(f->tag()); if(tagTestApe != NULL){ #ifdef Q_OS_WIN qDebug("APE metadata does not support the Key tag"); #else qDebug("APE metadata does not support the Key tag (%s)",f->name()); #endif return "N/A"; } #ifdef Q_OS_WIN qDebug("Key tag read failed all tests"); #else qDebug("Key tag read failed all tests on %s",f->name()); #endif return "N/A"; }
/*! * \copydoc MetaIO::read() */ MusicMetadata *MetaIOID3::read(const QString &filename) { if (!OpenFile(filename)) return nullptr; TagLib::ID3v2::Tag *tag = GetID3v2Tag(true); // Create tag if none are found // if there is no ID3v2 tag, try to read the ID3v1 tag and copy it to // the ID3v2 tag structure if (tag->isEmpty()) { TagLib::ID3v1::Tag *tag_v1 = GetID3v1Tag(); if (!tag_v1) return nullptr; if (!tag_v1->isEmpty()) { tag->setTitle(tag_v1->title()); tag->setArtist(tag_v1->artist()); tag->setAlbum(tag_v1->album()); tag->setTrack(tag_v1->track()); tag->setYear(tag_v1->year()); tag->setGenre(tag_v1->genre()); } } MusicMetadata *metadata = new MusicMetadata(filename); ReadGenericMetadata(tag, metadata); bool compilation = false; // Compilation Artist (TPE4 Remix) or fallback to (TPE2 Band) // N.B. The existance of a either frame is NOT an indication that this // is a compilation, but if it is then one of them will probably hold // the compilation artist. TextIdentificationFrame *tpeframe = nullptr; TagLib::ID3v2::FrameList tpelist = tag->frameListMap()["TPE4"]; if (tpelist.isEmpty() || tpelist.front()->toString().isEmpty()) tpelist = tag->frameListMap()["TPE2"]; if (!tpelist.isEmpty()) tpeframe = (TextIdentificationFrame *)tpelist.front(); if (tpeframe && !tpeframe->toString().isEmpty()) { QString compilation_artist = TStringToQString(tpeframe->toString()) .trimmed(); metadata->setCompilationArtist(compilation_artist); } // Rating and playcount, stored in POPM frame PopularimeterFrame *popm = findPOPM(tag, ""); // Global (all apps) tag // If no 'global' tag exists, look for the MythTV specific one if (!popm) { popm = findPOPM(tag, email); } // Fallback to using any POPM tag we can find if (!popm) { if (!tag->frameListMap()["POPM"].isEmpty()) popm = dynamic_cast<PopularimeterFrame *> (tag->frameListMap()["POPM"].front()); } if (popm) { int rating = popm->rating(); rating = lroundf(static_cast<float>(rating) / 255.0f * 10.0f); metadata->setRating(rating); metadata->setPlaycount(popm->counter()); } // Look for MusicBrainz Album+Artist ID in TXXX Frame UserTextIdentificationFrame *musicbrainz = find(tag, "MusicBrainz Album Artist Id"); if (musicbrainz) { // If the MusicBrainz ID is the special "Various Artists" ID // then compilation is TRUE if (!compilation && !musicbrainz->fieldList().isEmpty()) { TagLib::StringList l = musicbrainz->fieldList(); for (TagLib::StringList::ConstIterator it = l.begin(); it != l.end(); it++) { QString ID = TStringToQString((*it)); if (ID == MYTH_MUSICBRAINZ_ALBUMARTIST_UUID) { compilation = true; break; } } } } // TLEN - Ignored intentionally, some encoders write bad values // e.g. Lame under certain circumstances will always write a length of // 27 hours // Length if (!tag->frameListMap()["TLEN"].isEmpty()) { int length = tag->frameListMap()["TLEN"].front()->toString().toInt(); LOG(VB_FILE, LOG_DEBUG, QString("MetaIOID3::read: Length for '%1' from tag is '%2'\n").arg(filename).arg(length)); } metadata->setCompilation(compilation); metadata->setLength(getTrackLength(m_file)); // The number of tracks on the album, if supplied if (!tag->frameListMap()["TRCK"].isEmpty()) { QString trackFrame = TStringToQString( tag->frameListMap()["TRCK"].front()->toString()) .trimmed(); int trackCount = trackFrame.section('/', -1).toInt(); if (trackCount > 0) metadata->setTrackCount(trackCount); } LOG(VB_FILE, LOG_DEBUG, QString("MetaIOID3::read: Length for '%1' from properties is '%2'\n").arg(filename).arg(metadata->Length())); // Look for MythTVLastPlayed in TXXX Frame UserTextIdentificationFrame *lastplayed = find(tag, "MythTVLastPlayed"); if (lastplayed) { QString lastPlayStr = TStringToQString(lastplayed->toString()); metadata->setLastPlay(QDateTime::fromString(lastPlayStr, Qt::ISODate)); } // Part of a set if (!tag->frameListMap()["TPOS"].isEmpty()) { QString pos = TStringToQString( tag->frameListMap()["TPOS"].front()->toString()).trimmed(); int discNumber = pos.section('/', 0, 0).toInt(); int discCount = pos.section('/', -1).toInt(); if (discNumber > 0) metadata->setDiscNumber(discNumber); if (discCount > 0) metadata->setDiscCount(discCount); } return metadata; }
QString TagLibMetadata::getGrouping() const{ if(f == NULL || !f->isValid()) return ""; TagLib::MPEG::File* fileTestMpeg = dynamic_cast<TagLib::MPEG::File*>(f); if(fileTestMpeg != NULL){ TagLib::ID3v2::Tag* tagTestId3v2 = fileTestMpeg->ID3v2Tag(); if(tagTestId3v2 != NULL){ TagLib::ID3v2::FrameList l = tagTestId3v2->frameListMap()["TIT1"]; if(!l.isEmpty()){ TagLib::String out = l.front()->toString(); return QString::fromUtf8((out.toCString())); } return ""; } TagLib::ID3v1::Tag* tagTestId3v1 = fileTestMpeg->ID3v1Tag(); if(tagTestId3v1 != NULL){ #ifdef Q_OS_WIN qDebug("ID3v1 does not support the Grouping tag"); #else qDebug("ID3v1 does not support the Grouping tag (%s)",f->name()); #endif return "N/A"; } } TagLib::RIFF::AIFF::File* fileTestAiff = dynamic_cast<TagLib::RIFF::AIFF::File*>(f); if(fileTestAiff != NULL){ TagLib::ID3v2::Tag* tagTestId3v2 = fileTestAiff->tag(); if(tagTestId3v2 != NULL){ TagLib::ID3v2::FrameList l = tagTestId3v2->frameListMap()["TIT1"]; if(!l.isEmpty()){ TagLib::String out = l.front()->toString(); return QString::fromUtf8((out.toCString())); } return ""; } } TagLib::RIFF::WAV::File* fileTestWav = dynamic_cast<TagLib::RIFF::WAV::File*>(f); if(fileTestWav != NULL){ TagLib::ID3v2::Tag* tagTestId3v2 = fileTestWav->tag(); if(tagTestId3v2 != NULL){ TagLib::ID3v2::FrameList l = tagTestId3v2->frameListMap()["TIT1"]; if(!l.isEmpty()){ TagLib::String out = l.front()->toString(); return QString::fromUtf8((out.toCString())); } return ""; } } TagLib::MP4::Tag* tagTestMp4 = dynamic_cast<TagLib::MP4::Tag*>(f->tag()); if(tagTestMp4 != NULL){ TagLib::MP4::Item m = tagTestMp4->itemListMap()["\251grp"]; if(m.isValid()){ TagLib::String out = m.toStringList().front(); return QString::fromUtf8((out.toCString())); } return ""; } TagLib::ASF::Tag* tagTestAsf = dynamic_cast<TagLib::ASF::Tag*>(f->tag()); if(tagTestAsf != NULL){ TagLib::ASF::AttributeList l = tagTestAsf->attributeListMap()["WM/ContentGroupDescription"]; if(!l.isEmpty()){ TagLib::String out = l.front().toString(); return QString::fromUtf8((out.toCString())); } return ""; } TagLib::APE::Tag* tagTestApe = dynamic_cast<TagLib::APE::Tag*>(f->tag()); if(tagTestApe != NULL){ TagLib::APE::Item m = tagTestApe->itemListMap()["Grouping"]; if(!m.isEmpty()){ TagLib::String out = m.toStringList().front(); return QString::fromUtf8((out.toCString())); } return ""; } #ifdef Q_OS_WIN qDebug("Grouping tag read failed all tests"); #else qDebug("Grouping tag read failed all tests on %s",f->name()); #endif return "N/A"; }