예제 #1
0
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;
}
예제 #2
0
void ReplayGainReader::readID3v2(TagLib::ID3v2::Tag *tag)
{
    TagLib::ID3v2::UserTextIdentificationFrame* frame = 0;
    TagLib::ID3v2::FrameList frames = tag->frameList("TXXX");
    for(TagLib::ID3v2::FrameList::Iterator it = frames.begin(); it != frames.end(); ++it)
    {
        frame = dynamic_cast<TagLib::ID3v2::UserTextIdentificationFrame*>(*it);
        if(frame && frame->fieldList().size() >= 2)
        {
            TagLib::String desc = frame->description().upper();
            if (desc == "REPLAYGAIN_TRACK_GAIN")
                setValue(Qmmp::REPLAYGAIN_TRACK_GAIN, TStringToQString(frame->fieldList()[1]));
            else if (desc == "REPLAYGAIN_TRACK_PEAK")
                setValue(Qmmp::REPLAYGAIN_TRACK_PEAK, TStringToQString(frame->fieldList()[1]));
            else if (desc == "REPLAYGAIN_ALBUM_GAIN")
                setValue(Qmmp::REPLAYGAIN_ALBUM_GAIN, TStringToQString(frame->fieldList()[1]));
            else if (desc == "REPLAYGAIN_ALBUM_PEAK")
                setValue(Qmmp::REPLAYGAIN_ALBUM_PEAK, TStringToQString(frame->fieldList()[1]));
        }
    }
}
예제 #3
0
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;
}
Meta::FieldHash
ID3v2TagHelper::tags() const
{
    Meta::FieldHash data = TagHelper::tags();

    TagLib::ID3v2::FrameList list = m_tag->frameList();
    for( TagLib::ID3v2::FrameList::ConstIterator it = list.begin(); it != list.end(); ++it )
    {
        qint64 field;
        TagLib::String frameName  = TagLib::String( ( *it )->frameID() );
        if( ( field = fieldName( frameName ) ) )
        {
            if( field == Meta::valUniqueId )
            {
                TagLib::ID3v2::UniqueFileIdentifierFrame *frame =
                        dynamic_cast< TagLib::ID3v2::UniqueFileIdentifierFrame * >( *it );

                if( !frame )
                    continue;

                QString identifier = TStringToQString( TagLib::String( frame->identifier() ) );

                if( identifier.isEmpty() )
                    continue;

                if( frame->owner() == uidFieldName( UIDAFT ) && isValidUID( identifier, UIDAFT ) )
                    data.insert( Meta::valUniqueId, identifier );
                continue;
            }
            else if( field == Meta::valHasCover )
            {
                TagLib::ID3v2::AttachedPictureFrame *frame =
                        dynamic_cast< TagLib::ID3v2::AttachedPictureFrame * >( *it );

                if( !frame )
                    continue;

                if( ( frame->type() == TagLib::ID3v2::AttachedPictureFrame::FrontCover ||
                      frame->type() == TagLib::ID3v2::AttachedPictureFrame::Other ) &&
                    frame->picture().size() > MIN_COVER_SIZE ) // must be at least 1kb
                {
                    data.insert( Meta::valHasCover, true );
                }
                continue;
            }

            TagLib::ID3v2::TextIdentificationFrame *frame =
                    dynamic_cast< TagLib::ID3v2::TextIdentificationFrame * >( *it );

            if( !frame )
                continue;

            QString value = TStringToQString( frame->fieldList().toString( '\n' ) );

            if( field == Meta::valDiscNr )
            {
                int disc;
                if( ( disc = splitDiscNr( value ).first ) )
                    data.insert( field, disc );
            }
            else if( field == Meta::valBpm )
                data.insert( field, value.toFloat() );
            else
                data.insert( field, value );
        }
        else if( frameName == POPM_Frame )
        {
            TagLib::ID3v2::PopularimeterFrame *frame =
                    dynamic_cast< TagLib::ID3v2::PopularimeterFrame * >( *it );

            if( !frame )
                continue;

            if( TStringToQString( frame->email() ).isEmpty() ) // only read anonymous ratings
            {
                // FMPS tags have precedence
                if( !data.contains( Meta::valRating ) && frame->rating() != 0 )
                    data.insert( Meta::valRating, qRound( frame->rating() / 256.0 * 10.0 ) );
                if( !data.contains( Meta::valPlaycount ) && frame->counter() < 10000 )
                    data.insert( Meta::valPlaycount, frame->counter() );
            }
        }
        else if( frameName == TXXX_Frame )
        {
            TagLib::ID3v2::UserTextIdentificationFrame *frame =
                    dynamic_cast< TagLib::ID3v2::UserTextIdentificationFrame * >( *it );

            if( !frame )
                continue;

            // the value of the user text frame is stored in the
            // second and following fields.
            TagLib::StringList fields = frame->fieldList();
            if( fields.size() >= 2 )
            {
                QString value = TStringToQString( fields[1] );

                if( fields[0] == fmpsFieldName( FMPSRating ) )
                    data.insert( Meta::valRating, qRound( value.toFloat() * 10.0 ) );
                else if( fields[0] == fmpsFieldName( FMPSScore ) )
                    data.insert( Meta::valScore, value.toFloat() * 100.0 );
                else if( fields[0] == fmpsFieldName( FMPSPlayCount ) )
                    data.insert( Meta::valPlaycount, value.toFloat() );
            }
        }
    }

    return data;
}