示例#1
0
ReadableSampleFrames SoundSourceFLAC::readSampleFramesClamped(
        WritableSampleFrames writableSampleFrames) {
    const SINT firstFrameIndex = writableSampleFrames.frameIndexRange().start();

    if (m_curFrameIndex != firstFrameIndex) {
        // Seek to the new position
        SINT seekFrameIndex = firstFrameIndex;
        int retryCount = 0;
        // NOTE(uklotzde): This loop avoids unnecessary seek operations.
        // If the file is decoded from the beginning to the end during
        // continuous playback no seek operations are necessary. This
        // may hide rare seek errors that we have observed in some "flaky"
        // FLAC files. The retry strategy implemented by this loop tries
        // to solve these issues when randomly seeking through such a file.
        while ((seekFrameIndex != m_curFrameIndex) &&
                (retryCount <= kSeekErrorMaxRetryCount)) {
            // Discard decoded sample data before seeking
            m_sampleBuffer.clear();
            invalidateCurFrameIndex();
            if (FLAC__stream_decoder_seek_absolute(m_decoder, seekFrameIndex)) {
                // Success: Set the new position
                m_curFrameIndex = seekFrameIndex;
                DEBUG_ASSERT(FLAC__STREAM_DECODER_SEEK_ERROR != FLAC__stream_decoder_get_state(m_decoder));
            } else {
                // Failure
                kLogger.warning()
                        << "Seek error at" << seekFrameIndex
                        << "in file" << m_file.fileName();
                if (FLAC__STREAM_DECODER_SEEK_ERROR == FLAC__stream_decoder_get_state(m_decoder)) {
                    // Flush the input stream of the decoder according to the
                    // documentation of FLAC__stream_decoder_seek_absolute()
                    if (!FLAC__stream_decoder_flush(m_decoder)) {
                        kLogger.warning()
                                << "Failed to flush input buffer of the FLAC decoder after seek failure"
                                << "in file" << m_file.fileName();
                        invalidateCurFrameIndex();
                        // ...and abort
                        return ReadableSampleFrames(
                                IndexRange::between(
                                        m_curFrameIndex,
                                        m_curFrameIndex));
                    }
                }
                if (frameIndexMin() < seekFrameIndex) {
                    // The next seek position should start at a preceding sample block.
                    // By subtracting max. blocksize from the current seek position it
                    // is guaranteed that the targeted sample blocks of subsequent seek
                    // operations will differ.
                    DEBUG_ASSERT(0 < m_maxBlocksize);
                    seekFrameIndex -= m_maxBlocksize;
                    if (seekFrameIndex < frameIndexMin()) {
                        seekFrameIndex = frameIndexMin();
                    }
                } else {
                    // We have already reached the beginning of the file
                    // and cannot move the seek position backwards any
                    // further!
                    break; // exit loop
                }
            }
        }

        // Decoding starts before the actual target position
        DEBUG_ASSERT(m_curFrameIndex <= firstFrameIndex);
        const auto precedingFrames =
                IndexRange::between(m_curFrameIndex, firstFrameIndex);
        if (!precedingFrames.empty() &&
                (precedingFrames != readSampleFramesClamped(WritableSampleFrames(precedingFrames)).frameIndexRange())) {
            kLogger.warning()
                    << "Failed to skip preceding frames"
                    << precedingFrames;
            // Abort
            return ReadableSampleFrames(
                    IndexRange::between(
                            m_curFrameIndex,
                            m_curFrameIndex));
        }
    }
    DEBUG_ASSERT(m_curFrameIndex == firstFrameIndex);

    const SINT numberOfSamplesTotal = frames2samples(writableSampleFrames.frameLength());

    SINT numberOfSamplesRemaining = numberOfSamplesTotal;
    SINT outputSampleOffset = 0;
    while (0 < numberOfSamplesRemaining) {
        // If our buffer from libflac is empty (either because we explicitly cleared
        // it or because we've simply used all the samples), ask for a new buffer
        if (m_sampleBuffer.empty()) {
            // Save the current frame index
            const SINT curFrameIndexBeforeProcessing = m_curFrameIndex;
            // Documentation of FLAC__stream_decoder_process_single():
            // "Depending on what was decoded, the metadata or write callback
            // will be called with the decoded metadata block or audio frame."
            // See also: https://xiph.org/flac/api/group__flac__stream__decoder.html#ga9d6df4a39892c05955122cf7f987f856
            if (!FLAC__stream_decoder_process_single(m_decoder)) {
                kLogger.warning()
                        << "Failed to decode FLAC file"
                        << m_file.fileName();
                break; // abort
            }
            // After decoding we might first need to skip some samples if the
            // decoder complained that it has lost sync for some malformed(?)
            // files
            if (m_curFrameIndex != curFrameIndexBeforeProcessing) {
                if (m_curFrameIndex < curFrameIndexBeforeProcessing) {
                    kLogger.warning()
                            << "Trying to adjust frame index"
                            << m_curFrameIndex << "<" << curFrameIndexBeforeProcessing
                            << "while decoding FLAC file"
                            << m_file.fileName();
                    const auto skipFrames =
                            IndexRange::between(m_curFrameIndex, curFrameIndexBeforeProcessing);
                    if (skipFrames != readSampleFramesClamped(WritableSampleFrames(skipFrames)).frameIndexRange()) {
                        kLogger.warning()
                                << "Failed to skip sample frames"
                                << skipFrames
                                << "while decoding FLAC file"
                                << m_file.fileName();
                        break; // abort
                    }
                } else {
                    kLogger.warning()
                            << "Unexpected frame index"
                            << m_curFrameIndex << ">" << curFrameIndexBeforeProcessing
                            << "while decoding FLAC file"
                            << m_file.fileName();
                    break; // abort
                }
            }
            DEBUG_ASSERT(curFrameIndexBeforeProcessing == m_curFrameIndex);
        }
        if (m_sampleBuffer.empty()) {
            break; // EOF
        }

        const SINT numberOfSamplesRead =
                std::min(m_sampleBuffer.readableLength(), numberOfSamplesRemaining);
        const SampleBuffer::ReadableSlice readableSlice(
                m_sampleBuffer.shrinkForReading(numberOfSamplesRead));
        DEBUG_ASSERT(readableSlice.length() == numberOfSamplesRead);
        if (writableSampleFrames.writableData()) {
            SampleUtil::copy(
                    writableSampleFrames.writableData(outputSampleOffset),
                    readableSlice.data(),
                    readableSlice.length());
            outputSampleOffset += numberOfSamplesRead;
        }
        m_curFrameIndex += samples2frames(numberOfSamplesRead);
        numberOfSamplesRemaining -= numberOfSamplesRead;
    }

    DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex));
    DEBUG_ASSERT(numberOfSamplesTotal >= numberOfSamplesRemaining);
    const SINT numberOfSamples = numberOfSamplesTotal - numberOfSamplesRemaining;
    return ReadableSampleFrames(
            IndexRange::forward(firstFrameIndex, samples2frames(numberOfSamples)),
            SampleBuffer::ReadableSlice(
                    writableSampleFrames.writableData(),
                    std::min(writableSampleFrames.writableLength(), numberOfSamples)));
}
示例#2
0
ReadableSampleFrames SoundSourceOggVorbis::readSampleFramesClamped(
        WritableSampleFrames writableSampleFrames) {

    const SINT firstFrameIndex = writableSampleFrames.frameIndexRange().start();

    if (m_curFrameIndex != firstFrameIndex) {
        const int seekResult = ov_pcm_seek(&m_vf, firstFrameIndex);
        if (seekResult == 0) {
            m_curFrameIndex = firstFrameIndex;
        } else {
            kLogger.warning() << "Failed to seek file:" << seekResult;
            const ogg_int64_t pcmOffset = ov_pcm_tell(&m_vf);
            if (0 <= pcmOffset) {
                m_curFrameIndex = pcmOffset;
            } else {
                // Reset to EOF
                m_curFrameIndex = frameIndexMax();
            }
            // Abort
            return ReadableSampleFrames(
                    IndexRange::between(
                            m_curFrameIndex,
                            m_curFrameIndex));
        }
    }
    DEBUG_ASSERT(m_curFrameIndex == firstFrameIndex);

    const SINT numberOfFramesTotal = writableSampleFrames.frameLength();

    CSAMPLE* pSampleBuffer = writableSampleFrames.writableData();
    SINT numberOfFramesRemaining = numberOfFramesTotal;
    while (0 < numberOfFramesRemaining) {
        float** pcmChannels;
        int currentSection;
        // Use 'long' here, because ov_read_float() returns this type.
        // This is an exception from the rule not to any types with
        // differing sizes on different platforms.
        // https://bugs.launchpad.net/mixxx/+bug/1094143
        const long readResult = ov_read_float(&m_vf, &pcmChannels,
                numberOfFramesRemaining, &currentSection);
        if (0 < readResult) {
            m_curFrameIndex += readResult;
            if (pSampleBuffer) {
                switch (channelCount()) {
                case 1:
                    for (long i = 0; i < readResult; ++i) {
                        *pSampleBuffer++ = pcmChannels[0][i];
                    }
                    break;
                case 2:
                    for (long i = 0; i < readResult; ++i) {
                        *pSampleBuffer++ = pcmChannels[0][i];
                        *pSampleBuffer++ = pcmChannels[1][i];
                    }
                    break;
                default:
                    for (long i = 0; i < readResult; ++i) {
                        for (SINT j = 0; j < channelCount(); ++j) {
                            *pSampleBuffer++ = pcmChannels[j][i];
                        }
                    }
                }
            }
            numberOfFramesRemaining -= readResult;
        } else {
            kLogger.warning() << "Failed to read from file:" << readResult;
            break; // abort
        }
    }

    DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex));
    DEBUG_ASSERT(numberOfFramesTotal >= numberOfFramesRemaining);
    const SINT numberOfFrames = numberOfFramesTotal - numberOfFramesRemaining;
    return ReadableSampleFrames(
            IndexRange::forward(firstFrameIndex, numberOfFrames),
            SampleBuffer::ReadableSlice(
                    writableSampleFrames.writableData(),
                    std::min(writableSampleFrames.writableLength(), frames2samples(numberOfFrames))));
}