/** * Get the various artist information form a tag. * * @param filetype the type-id for the file that is being processed * @param tagtype the tag-type to use (if more than one are used per filetype) * @param tag the tag-data from taglib * * @return a proper multi-artist data field or a NULL pointer. * @sideeffects none */ const char * taggit_tag_va(enum file_type filetype, int tagtype, TagLib_Tag *tag) { /* * At this point, we already figured out the file type *and* decided which * tag to read from the file. `filetype' and `tagtype' give us hints into * the right direction. We *must* follow these hints or things will blow * up. */ TagLib::APE::Tag *ape; TagLib::ID3v2::Tag *v2; TagLib::Ogg::XiphComment *ogg; const char *ret; ret = (const char *)NULL; switch (filetype) { case FT_MPEG: if (tagtype & MP3_ID3V2) { /** * @TODO Add support for TCMP (and maybe TCP) frames. * It's probably best to only check for those if TPE2 is empty, * because otherwise we already consider the track part of a * compilation. */ v2 = reinterpret_cast<TagLib::ID3v2::Tag *>(tag); if (v2->frameListMap()["TPE2"].isEmpty()) break; ret = xstrdup( v2->frameListMap()["TPE2"].front()->toString().toCString()); } else if (tagtype & MP3_APE) { ape = reinterpret_cast<TagLib::APE::Tag *>(tag); if (ape->itemListMap()["ALBUMARTIST"].isEmpty()) break; ret = xstrdup( ape->itemListMap()["ALBUMARTIST"].toString().toCString()); } /* Don't care about ID3v1 */ break; case FT_OGGVORBIS: /* @FALLTHROUGH@ */ case FT_OGGFLAC: /* ogg* files share the same tag format */ ogg = reinterpret_cast<TagLib::Ogg::XiphComment *>(tag); if (ogg->fieldListMap()["ALBUMARTIST"].isEmpty()) break; ret = xstrdup( ogg->fieldListMap()["ALBUMARTIST"].toString().toCString()); break; case FT_FLAC: /* AFAIK, there is no native FLAC tag format */ break; default: break; } return ret; }
/*! * \copydoc MetaIO::read() */ Metadata* MetaIOFLACVorbis::read(QString filename) { TagLib::FLAC::File *flacfile = OpenFile(filename); if (!flacfile) return NULL; TagLib::Ogg::XiphComment *tag = flacfile->xiphComment(); if (!tag) { delete flacfile; return NULL; } Metadata *metadata = new Metadata(filename); ReadGenericMetadata(tag, metadata); bool compilation = false; if (tag->contains("COMPILATION_ARTIST")) { QString compilation_artist = TStringToQString( tag->fieldListMap()["COMPILATION_ARTIST"].toString()).trimmed(); if (compilation_artist != metadata->Artist()) { metadata->setCompilationArtist(compilation_artist); compilation = true; } } if (!compilation && tag->contains("MUSICBRAINZ_ALBUMARTISTID")) { QString musicbrainzcode = TStringToQString( tag->fieldListMap()["MUSICBRAINZ_ALBUMARTISTID"].toString()).trimmed(); if (musicbrainzcode == MYTH_MUSICBRAINZ_ALBUMARTIST_UUID) compilation = true; } metadata->setCompilation(compilation); if (metadata->Length() <= 0) { TagLib::FileRef *fileref = new TagLib::FileRef(flacfile); metadata->setLength(getTrackLength(fileref)); // FileRef takes ownership of flacfile, and is responsible for it's // deletion. Messy. delete fileref; } else delete flacfile; return metadata; }
/*! * \copydoc MetaIO::read() */ Metadata* MetaIOOggVorbis::read(const QString &filename) { TagLib::Ogg::Vorbis::File *oggfile = OpenFile(filename); if (!oggfile) return NULL; TagLib::Ogg::XiphComment *tag = oggfile->tag(); if (!tag) { delete oggfile; return NULL; } Metadata *metadata = new Metadata(filename); ReadGenericMetadata(tag, metadata); bool compilation = false; if (tag->contains("COMPILATION_ARTIST")) { QString compilation_artist = TStringToQString( tag->fieldListMap()["COMPILATION_ARTIST"].toString()).trimmed(); if (compilation_artist != metadata->Artist()) { metadata->setCompilationArtist(compilation_artist); compilation = true; } } if (!compilation && tag->contains("MUSICBRAINZ_ALBUMARTISTID")) { QString musicbrainzcode = TStringToQString( tag->fieldListMap()["MUSICBRAINZ_ALBUMARTISTID"].toString()).trimmed(); if (musicbrainzcode == MYTH_MUSICBRAINZ_ALBUMARTIST_UUID) compilation = true; } metadata->setCompilation(compilation); if (metadata->Length() <= 0) metadata->setLength(getTrackLength(oggfile)); else delete oggfile; return metadata; }
/*! * \copydoc MetaIO::write() */ bool MetaIOFLACVorbis::write(Metadata* mdata) { if (!mdata) return false; TagLib::FLAC::File *flacfile = OpenFile(mdata->Filename()); if (!flacfile) return false; TagLib::Ogg::XiphComment *tag = flacfile->xiphComment(); if (!tag) { delete flacfile; return false; } WriteGenericMetadata(tag, mdata); // Compilation if (mdata->Compilation()) { tag->addField("MUSICBRAINZ_ALBUMARTISTID", MYTH_MUSICBRAINZ_ALBUMARTIST_UUID, true); tag->addField("COMPILATION_ARTIST", QStringToTString(mdata->CompilationArtist()), true); } else { // Don't remove the musicbrainz field unless it indicated a compilation if (tag->contains("MUSICBRAINZ_ALBUMARTISTID") && (tag->fieldListMap()["MUSICBRAINZ_ALBUMARTISTID"].toString() == MYTH_MUSICBRAINZ_ALBUMARTIST_UUID)) { tag->removeField("MUSICBRAINZ_ALBUMARTISTID"); } tag->removeField("COMPILATION_ARTIST"); } bool result = flacfile->save(); if (flacfile) delete flacfile; return (result); }
QPixmap VorbisMetaDataModel::cover() { TagLib::Ogg::Vorbis::File file(m_path.toLocal8Bit().constData()); TagLib::Ogg::XiphComment *tag = file.tag(); if(!tag) return QPixmap(); TagLib::StringList list = tag->fieldListMap()["METADATA_BLOCK_PICTURE"]; if(list.isEmpty()) return QPixmap(); for(uint i = 0; i < list.size(); ++i) { TagLib::String value = list[i]; QByteArray block = QByteArray::fromBase64(TStringToQString_qt4(value).toAscii()); if(block.size() < 32) continue; qint64 pos = 0; if(readPictureBlockField(block, pos) != 3) //picture type, use front cover only continue; pos += 4; int mimeLength = readPictureBlockField(block, pos); //mime type length pos += 4; pos += mimeLength; //skip mime type int descLength = readPictureBlockField(block, pos); //description length pos += 4; pos += descLength; //skip description pos += 4; //width pos += 4; //height pos += 4; //color depth pos += 4; //the number of colors used int length = readPictureBlockField(block, pos); //picture size pos += 4; QPixmap cover; cover.loadFromData(block.mid(pos, length)); //read binary picture data return cover; } return QPixmap(); }
int main(int argc, char *argv[]) { for(int i = 1; i < argc; i++) { cout << "******************** \"" << argv[i] << "\" ********************" << endl; TagLib::FileRef f(argv[i]); if(!f.isNull() && f.tag()) { TagLib::Tag *tag = f.tag(); cout << "-- TAG --" << endl; cout << "title - \"" << tag->title() << "\"" << endl; cout << "artist - \"" << tag->artist() << "\"" << endl; cout << "album artist - \"" << tag->albumArtist() << "\"" << endl; cout << "album - \"" << tag->album() << "\"" << endl; cout << "year - \"" << tag->year() << "\"" << endl; cout << "comment - \"" << tag->comment() << "\"" << endl; cout << "track - \"" << tag->track() << "\"" << endl; cout << "genre - \"" << tag->genre() << "\"" << endl; cout << "grouping - \"" << tag->grouping() << "\"" << endl; TagLib::Ogg::XiphComment *comment = NULL; TagLib::FLAC::File *flac = dynamic_cast<TagLib::FLAC::File *>(f.file()); if (flac) { cout << "flac:" << endl; cout << "id3v1 - \"" << flac->ID3v1Tag() << "\"" << endl; cout << "id3v2 - \"" << flac->ID3v2Tag() << "\"" << endl; cout << "xiph - \"" << flac->xiphComment() << "\"" << endl; comment = flac->xiphComment(); } if (!comment) { comment = dynamic_cast<TagLib::Ogg::XiphComment *>(tag); } if (comment) { TagLib::Ogg::FieldListMap fields = comment->fieldListMap(); for(TagLib::Ogg::FieldListMap::ConstIterator it = fields.begin(), end = fields.end(); it != end; it++) { if (!it->second.isEmpty()) cout << "xiph:" << it->first << " \"" << it->second[0].substr(0,3) << "\"" << endl; } } cout << "pictures- \"" << f.file()->pictures().size() << "\"" << endl; TagLib::File::PictureList l = f.file()->pictures(); for (TagLib::File::_PictureList::ConstIterator i = l.begin(), end = l.end(); i != end; i++) { cout << "\t" << (*i)->typeName() << ' ' << (*i)->mimeType() << ' ' << (*i)->base64data().size() << endl; } cout << "pictures- \"" << tag->pictures().size() << "\"" << endl; } if(!f.isNull() && f.audioProperties()) { TagLib::AudioProperties *properties = f.audioProperties(); int seconds = properties->length() % 60; int minutes = (properties->length() - seconds) / 60; cout << "-- AUDIO --" << endl; cout << "bitrate - " << properties->bitrate() << endl; cout << "sample rate - " << properties->sampleRate() << endl; cout << "channels - " << properties->channels() << endl; cout << "length - " << minutes << ":" << formatSeconds(seconds) << endl; } } return 0; }