Beispiel #1
0
// checks the streams for issues (missing ID3V2, Unknown streams, inconsistencies, ...)
void Mp3Handler::analyze(const QualThresholds& qualThresholds)
{
    NoteColl& notes (m_notes); // for MP3_NOTE()

    for (int i = 0, n = cSize(m_vpAllStreams); i < n; ++i)
    {
        DataStream* pDs (m_vpAllStreams[i]);
        {
            Id3V230Stream* p (dynamic_cast<Id3V230Stream*>(pDs));
            if (0 != p)
            {
                if (0 == m_pId3V230Stream)
                    m_pId3V230Stream = p;
                else
                    MP3_NOTE (p->getPos(), twoId3V230);
            }
        }

        {
            Id3V240Stream* p (dynamic_cast<Id3V240Stream*>(pDs));
            if (0 != p)
            {
                if (0 == m_pId3V240Stream)
                    m_pId3V240Stream = p;
                else
                    MP3_NOTE (p->getPos(), twoId3V240);
            }
        }

        {
            Id3V1Stream* p (dynamic_cast<Id3V1Stream*>(pDs));
            if (0 != p)
            {
                if (0 == m_pId3V1Stream)
                    m_pId3V1Stream = p;
                else
                    MP3_NOTE (p->getPos(), twoId3V1);
            }
        }

        {
            LameStream* p (dynamic_cast<LameStream*>(pDs));
            if (0 != p)
            {
                if (0 == m_pLameStream)
                    m_pLameStream = p;
                else
                    MP3_NOTE (p->getPos(), twoLame);
            }
        }

        {
            XingStreamBase* p (dynamic_cast<XingStreamBase*>(pDs));
            if (0 != p)
            {
                if (0 == m_pXingStream)
                {
                    m_pXingStream = p;
                    if (i < n - 2 && p->isBrokenByMp3Fixer(m_vpAllStreams[i + 1], m_vpAllStreams[i + 2]))
                    {
                        MP3_NOTE (p->getPos(), xingAddedByMp3Fixer);
                    }
                    if (i < n - 1)
                    {
                        MpegStream* q (dynamic_cast<MpegStream*>(m_vpAllStreams[i + 1]));
                        if (0 != q && p->getFrameCount() != q->getFrameCount())
                        {
                            MP3_NOTE (p->getPos(), xingFrameCountMismatch);
                        }
                    }
                }
                else
                    MP3_NOTE (p->getPos(), twoXing);
            }
        }

        {
            VbriStream* p (dynamic_cast<VbriStream*>(pDs));
            if (0 != p)
            {
                if (0 == m_pVbriStream)
                    m_pVbriStream = p;
                else
                    MP3_NOTE (p->getPos(), twoVbri);
            }
        }

        {
            MpegStream* p (dynamic_cast<MpegStream*>(pDs));
            if (0 != p)
            {
                if (0 == m_pMpegStream)
                    m_pMpegStream = p;
                else
                    MP3_NOTE (p->getPos(), twoAudio);

                //const MpegFrame& frm (p->getFirstFrame());
                if (p->isVbr())
                {
                    switch (p->getChannelMode())
                    {   // ttt2 should be possible that changing qual thresholds in config triggers notes being added / removed
                    case MpegFrame::STEREO:
                        if (p->getBitrate() < qualThresholds.m_nStereoVbr) {
                            MP3_NOTE (p->getPos(), lowQualAudio);
                        }
                        break;
                    case MpegFrame::JOINT_STEREO:
                        if (p->getBitrate() < qualThresholds.m_nJointStereoVbr) {
                            MP3_NOTE (p->getPos(), lowQualAudio);
                        }
                        break;
                    case MpegFrame::DUAL_CHANNEL:
                        if (p->getBitrate() < qualThresholds.m_nDoubleChannelVbr) {
                            MP3_NOTE (p->getPos(), lowQualAudio);
                        }
                        break;
                    case MpegFrame::SINGLE_CHANNEL:
                        if (p->getBitrate() < qualThresholds.m_nDoubleChannelVbr / 2) {
                            MP3_NOTE (p->getPos(), lowQualAudio);
                        }
                        break;
                    }
                }
                else
                {
                    switch (p->getChannelMode())
                    {
                    case MpegFrame::STEREO:
                        if (p->getBitrate() < qualThresholds.m_nStereoCbr) {
                            MP3_NOTE (p->getPos(), lowQualAudio);
                        }
                        break;
                    case MpegFrame::JOINT_STEREO:
                        if (p->getBitrate() < qualThresholds.m_nJointStereoCbr) {
                            MP3_NOTE (p->getPos(), lowQualAudio);
                        }
                        break;
                    case MpegFrame::DUAL_CHANNEL:
                        if (p->getBitrate() < qualThresholds.m_nDoubleChannelCbr) {
                            MP3_NOTE (p->getPos(), lowQualAudio);
                        }
                        break;
                    case MpegFrame::SINGLE_CHANNEL:
                        if (p->getBitrate() < qualThresholds.m_nDoubleChannelCbr / 2) {
                            MP3_NOTE (p->getPos(), lowQualAudio);
                        }
                        break;
                    }
                }
            }
        }

        {
            ApeStream* p (dynamic_cast<ApeStream*>(pDs));
            if (0 != p)
            {
                if (0 == m_pApeStream)
                    m_pApeStream = p;
                else
                    MP3_NOTE (p->getPos(), twoApe);
            }
        }

        {
            LyricsStream* p (dynamic_cast<LyricsStream*>(pDs));
            if (0 != p)
            {
                if (0 == m_pLyricsStream)
                    m_pLyricsStream = p;
                else
                    MP3_NOTE (p->getPos(), twoLyr);
            }
        }

        {
            NullDataStream* p (dynamic_cast<NullDataStream*>(pDs));
            if (0 != p)
            {
                m_vpNullStreams.push_back(p);
            }
        }

        {
            UnknownDataStream* p (dynamic_cast<UnknownDataStream*>(pDs));
            if (0 != p)
            {
                m_vpUnknownStreams.push_back(p);
            }
        }

        {
            BrokenDataStream* p (dynamic_cast<BrokenDataStream*>(pDs));
            if (0 != p)
            {
                m_vpBrokenStreams.push_back(p);
            }
        }

        {
            UnsupportedDataStream* p (dynamic_cast<UnsupportedDataStream*>(pDs));
            if (0 != p)
            {
                m_vpUnsupportedStreams.push_back(p);
            }
        }

        {
            TruncatedMpegDataStream* p (dynamic_cast<TruncatedMpegDataStream*>(pDs));
            if (0 != p)
            {
                m_vpTruncatedMpegStreams.push_back(p);
            }
        }
    }

    if (0 == m_pMpegStream) {
        MP3_NOTE (-1, noAudio);
    }
    if (0 == m_pId3V230Stream) {
        MP3_NOTE (-1, noId3V230);
    }
    if (0 != m_pId3V230Stream && 0 != m_pId3V240Stream) {
        MP3_NOTE (m_pId3V240Stream->getPos(), bothId3V230_V240);
    }
    if (0 != m_pVbriStream) {
        MP3_NOTE (m_pVbriStream->getPos(), vbriFound);
    }
    //if (0 != m_pLyricsStream) { MP3_NOTE (m_pLyricsStream->getPos(), lyricsNotSupported); }
    if (0 != m_pId3V1Stream && 0 == m_pId3V230Stream && 0 == m_pId3V240Stream && 0 == m_pApeStream) {
        MP3_NOTE (m_pId3V1Stream->getPos(), onlyId3V1);
    }
    if (0 == m_pId3V1Stream && 0 == m_pId3V230Stream && 0 == m_pId3V240Stream && 0 == m_pApeStream) {
        MP3_NOTE (-1, noInfoTag);
    }
    if (!m_vpNullStreams.empty()) {
        MP3_NOTE (m_vpNullStreams[0]->getPos(), foundNull);
    }
    if (0 != m_pVbriStream && 0 != m_pXingStream) {
        MP3_NOTE (m_pVbriStream->getPos(), foundVbriAndXing);
    }
    if (0 != m_pXingStream && 0 != m_pMpegStream && m_pXingStream->getIndex() != m_pMpegStream->getIndex() - 1) {
        MP3_NOTE (m_pXingStream->getPos(), xingNotBeforeAudio);
    }

    if (0 != m_pXingStream && 0 != m_pMpegStream && !m_pXingStream->matchesStructure(*m_pMpegStream)) {
        MP3_NOTE (m_pXingStream->getPos(), incompatXing);
    }
    if (0 != m_pId3V1Stream && 0 != m_pMpegStream && m_pId3V1Stream->getIndex() < m_pMpegStream->getIndex()) {
        MP3_NOTE (m_pId3V1Stream->getPos(), id3v1BeforeAudio);
    }
    if (0 != m_pId3V230Stream && 0 != m_pId3V230Stream->getIndex()) {
        MP3_NOTE (m_pId3V230Stream->getPos(), id3v230AfterAudio);
    }
    if (0 == m_pXingStream && 0 != m_pMpegStream && m_pMpegStream->isVbr()) {
        MP3_NOTE (m_pMpegStream->getPos(), missingXing);
    }
    if (0 != m_pMpegStream && m_pMpegStream->isVbr() && (MpegFrame::MPEG1 != m_pMpegStream->getFirstFrame().getVersion() || MpegFrame::LAYER3 != m_pMpegStream->getFirstFrame().getLayer())) {
        MP3_NOTE (m_pMpegStream->getPos(), vbrUsedForNonMpg1L3);
    }
    if (
        (0 != m_pMpegStream) &&
        (0 == m_pApeStream || !m_pApeStream->hasMp3Gain()) &&
        (0 == m_pId3V230Stream || !m_pId3V230Stream->hasReplayGain()) &&
        (0 == m_pId3V240Stream || !m_pId3V240Stream->hasReplayGain())) //ttt2 not quite OK when mutliple ID3V2 streams are found
    {
        MP3_NOTE (m_pMpegStream->getPos(), noMp3Gain);
    }

    if (!m_vpBrokenStreams.empty())
    {
        if (1 == cSize(m_vpBrokenStreams) && m_vpBrokenStreams.back() == m_vpAllStreams.back())
        {
            MP3_NOTE (m_vpBrokenStreams.back()->getPos(), brokenAtTheEnd);
        }
        else
        {
            MP3_NOTE (m_vpBrokenStreams.back()->getPos(), brokenInTheMiddle);
        }
    }

    if (!m_vpUnknownStreams.empty())
    {
        if (1 == cSize(m_vpUnknownStreams) && m_vpUnknownStreams.back() == m_vpAllStreams.back())
        {
            MP3_NOTE (m_vpUnknownStreams.back()->getPos(), unknownAtTheEnd);
        }
        else
        {
            MP3_NOTE (m_vpUnknownStreams.back()->getPos(), unknownInTheMiddle);
        }
    }

    if (!m_vpUnsupportedStreams.empty())
    {
        MP3_NOTE (m_vpUnsupportedStreams.back()->getPos(), unsupportedFound);
    }

    if (!m_vpTruncatedMpegStreams.empty())
    {
        if (1 == cSize(m_vpTruncatedMpegStreams) && m_vpTruncatedMpegStreams.back() == m_vpAllStreams.back())
        {
            MP3_NOTE (m_vpTruncatedMpegStreams.back()->getPos(), truncAudioWithWholeFile);
        }
        else
        {
            MP3_NOTE (m_vpTruncatedMpegStreams.back()->getPos(), truncAudio);
        }
    }

    m_notes.sort();
    //sort(m_notes.begin(), m_notes.end(), notePtrCmp);
}