SINT SoundSourceOpus::readSampleFramesStereo( SINT numberOfFrames, CSAMPLE* sampleBuffer, SINT sampleBufferSize) { DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(getSampleBufferSize(numberOfFrames, true) <= sampleBufferSize); const SINT numberOfFramesTotal = math_min( numberOfFrames, getMaxFrameIndex() - m_curFrameIndex); CSAMPLE* pSampleBuffer = sampleBuffer; SINT numberOfFramesRemaining = numberOfFramesTotal; while (0 < numberOfFramesRemaining) { int readResult = op_read_float_stereo(m_pOggOpusFile, pSampleBuffer, numberOfFramesRemaining * 2); // stereo if (0 < readResult) { m_curFrameIndex += readResult; pSampleBuffer += readResult * 2; // stereo numberOfFramesRemaining -= readResult; } else { qWarning() << "Failed to read sample data from OggOpus file:" << readResult; break; // abort } } DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(numberOfFramesTotal >= numberOfFramesRemaining); return numberOfFramesTotal - numberOfFramesRemaining; }
SINT SoundSourceOggVorbis::readSampleFrames( SINT numberOfFrames, CSAMPLE* sampleBuffer, SINT sampleBufferSize, bool readStereoSamples) { DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(getSampleBufferSize(numberOfFrames, readStereoSamples) <= sampleBufferSize); const SINT numberOfFramesTotal = math_min( numberOfFrames, getMaxFrameIndex() - m_curFrameIndex); CSAMPLE* pSampleBuffer = sampleBuffer; 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, ¤tSection); if (0 < readResult) { m_curFrameIndex += readResult; if (kChannelCountMono == getChannelCount()) { if (readStereoSamples) { for (long i = 0; i < readResult; ++i) { *pSampleBuffer++ = pcmChannels[0][i]; *pSampleBuffer++ = pcmChannels[0][i]; } } else { for (long i = 0; i < readResult; ++i) { *pSampleBuffer++ = pcmChannels[0][i]; } } } else if (readStereoSamples || (kChannelCountStereo == getChannelCount())) { for (long i = 0; i < readResult; ++i) { *pSampleBuffer++ = pcmChannels[0][i]; *pSampleBuffer++ = pcmChannels[1][i]; } } else { for (long i = 0; i < readResult; ++i) { for (SINT j = 0; j < getChannelCount(); ++j) { *pSampleBuffer++ = pcmChannels[j][i]; } } } numberOfFramesRemaining -= readResult; } else { qWarning() << "Failed to read from OggVorbis file:" << readResult; break; // abort } } DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(numberOfFramesTotal >= numberOfFramesRemaining); return numberOfFramesTotal - numberOfFramesRemaining; }
SINT AudioSource::readSampleFramesStereo( SINT numberOfFrames, CSAMPLE* sampleBuffer, SINT sampleBufferSize) { DEBUG_ASSERT(getSampleBufferSize(numberOfFrames, true) <= sampleBufferSize); switch (getChannelCount()) { case 1: // mono channel { const SINT readFrameCount = readSampleFrames( numberOfFrames, sampleBuffer); SampleUtil::doubleMonoToDualMono(sampleBuffer, readFrameCount); return readFrameCount; } case 2: // stereo channel(s) { return readSampleFrames(numberOfFrames, sampleBuffer); } default: // multiple (3 or more) channels { const SINT numberOfSamplesToRead = frames2samples(numberOfFrames); if (numberOfSamplesToRead <= sampleBufferSize) { // efficient in-place transformation const SINT readFrameCount = readSampleFrames( numberOfFrames, sampleBuffer); SampleUtil::copyMultiToStereo(sampleBuffer, sampleBuffer, readFrameCount, getChannelCount()); return readFrameCount; } else { // inefficient transformation through a temporary buffer qDebug() << "Performance warning:" << "Allocating a temporary buffer of size" << numberOfSamplesToRead << "for reading stereo samples." << "The size of the provided sample buffer is" << sampleBufferSize; SampleBuffer tempBuffer(numberOfSamplesToRead); const SINT readFrameCount = readSampleFrames( numberOfFrames, tempBuffer.data()); SampleUtil::copyMultiToStereo(sampleBuffer, tempBuffer.data(), readFrameCount, getChannelCount()); return readFrameCount; } } } }
SINT SoundSourceMp3::readSampleFrames( SINT numberOfFrames, CSAMPLE* sampleBuffer, SINT sampleBufferSize, bool readStereoSamples) { DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(getSampleBufferSize(numberOfFrames, readStereoSamples) <= sampleBufferSize); const SINT numberOfFramesTotal = math_min( numberOfFrames, getMaxFrameIndex() - m_curFrameIndex); CSAMPLE* pSampleBuffer = sampleBuffer; SINT numberOfFramesRemaining = numberOfFramesTotal; while (0 < numberOfFramesRemaining) { if (0 >= m_madSynthCount) { // When all decoded output data has been consumed... DEBUG_ASSERT(0 == m_madSynthCount); // ...decode the next MP3 frame DEBUG_ASSERT(m_madStream.buffer); DEBUG_ASSERT(m_madStream.this_frame); // WARNING: Correctly evaluating and handling the result // of mad_frame_decode() has proven to be extremely tricky. // Don't change anything at the following lines of code // unless you know what you are doing!!! unsigned char const* pMadThisFrame = m_madStream.this_frame; if (mad_frame_decode(&m_madFrame, &m_madStream)) { // Something went wrong when decoding the frame... if (MAD_ERROR_BUFLEN == m_madStream.error) { // Abort break; } if (isUnrecoverableError(m_madStream)) { qWarning() << "Unrecoverable MP3 frame decoding error:" << mad_stream_errorstr(&m_madStream); // Abort decoding break; } if (isRecoverableError(m_madStream)) { if (pMadThisFrame != m_madStream.this_frame) { // Ignore all recoverable errors (and especially // "lost synchronization" warnings) while skipping // over prefetched frames after seeking. if (pSampleBuffer) { qWarning() << "Recoverable MP3 frame decoding error:" << mad_stream_errorstr(&m_madStream); } else { // Decoded samples will simply be discarded qDebug() << "Recoverable MP3 frame decoding error while skipping:" << mad_stream_errorstr(&m_madStream); } } // Continue decoding } } if (pMadThisFrame == m_madStream.this_frame) { qDebug() << "Retry decoding MP3 frame @" << m_curFrameIndex; // Retry decoding continue; } DEBUG_ASSERT(isStreamValid(m_madStream)); #ifndef QT_NO_DEBUG_OUTPUT const SINT madFrameChannelCount = MAD_NCHANNELS(&m_madFrame.header); if (madFrameChannelCount != getChannelCount()) { qDebug() << "MP3 frame header with mismatching number of channels" << madFrameChannelCount << "<>" << getChannelCount(); } #endif // Once decoded the frame is synthesized to PCM samples mad_synth_frame(&m_madSynth, &m_madFrame); #ifndef QT_NO_DEBUG_OUTPUT const SINT madSynthSampleRate = m_madSynth.pcm.samplerate; if (madSynthSampleRate != getSamplingRate()) { qDebug() << "Reading MP3 data with different sampling rate" << madSynthSampleRate << "<>" << getSamplingRate(); } #endif m_madSynthCount = m_madSynth.pcm.length; DEBUG_ASSERT(0 < m_madSynthCount); } const SINT synthReadCount = math_min( m_madSynthCount, numberOfFramesRemaining); if (pSampleBuffer) { DEBUG_ASSERT(m_madSynthCount <= m_madSynth.pcm.length); const SINT madSynthOffset = m_madSynth.pcm.length - m_madSynthCount; DEBUG_ASSERT(madSynthOffset < m_madSynth.pcm.length); const SINT madSynthChannelCount = m_madSynth.pcm.channels; DEBUG_ASSERT(0 < madSynthChannelCount); DEBUG_ASSERT(madSynthChannelCount <= getChannelCount()); #ifndef QT_NO_DEBUG_OUTPUT if (madSynthChannelCount != getChannelCount()) { qDebug() << "Reading MP3 data with different number of channels" << madSynthChannelCount << "<>" << getChannelCount(); } #endif if (kChannelCountMono == madSynthChannelCount) { // MP3 frame contains a mono signal if (readStereoSamples || (kChannelCountStereo == getChannelCount())) { // The reader explicitly requested a stereo signal // or the AudioSource itself provides a stereo signal. // Mono -> Stereo: Copy 1st channel twice for (SINT i = 0; i < synthReadCount; ++i) { const CSAMPLE sampleValue = madScaleSampleValue( m_madSynth.pcm.samples[0][madSynthOffset + i]); *pSampleBuffer++ = sampleValue; *pSampleBuffer++ = sampleValue; } } else { // Mono -> Mono: Copy 1st channel for (SINT i = 0; i < synthReadCount; ++i) { const CSAMPLE sampleValue = madScaleSampleValue( m_madSynth.pcm.samples[0][madSynthOffset + i]); *pSampleBuffer++ = sampleValue; } } } else { // MP3 frame contains a stereo signal DEBUG_ASSERT(kChannelCountStereo == madSynthChannelCount); // If the MP3 frame contains a stereo signal then the whole // AudioSource must also provide 2 channels, because the // maximum channel count of all MP3 frames is used. DEBUG_ASSERT(kChannelCountStereo == getChannelCount()); // Stereo -> Stereo: Copy 1st + 2nd channel for (SINT i = 0; i < synthReadCount; ++i) { *pSampleBuffer++ = madScaleSampleValue( m_madSynth.pcm.samples[0][madSynthOffset + i]); *pSampleBuffer++ = madScaleSampleValue( m_madSynth.pcm.samples[1][madSynthOffset + i]); } } } // consume decoded output data m_madSynthCount -= synthReadCount; m_curFrameIndex += synthReadCount; numberOfFramesRemaining -= synthReadCount; } DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(numberOfFramesTotal >= numberOfFramesRemaining); return numberOfFramesTotal - numberOfFramesRemaining; }
SINT SoundSourceFLAC::readSampleFrames( SINT numberOfFrames, CSAMPLE* sampleBuffer, SINT sampleBufferSize, bool readStereoSamples) { DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(getSampleBufferSize(numberOfFrames, readStereoSamples) <= sampleBufferSize); const SINT numberOfFramesTotal = math_min(numberOfFrames, getMaxFrameIndex() - m_curFrameIndex); const SINT numberOfSamplesTotal = frames2samples(numberOfFramesTotal); CSAMPLE* outBuffer = sampleBuffer; SINT numberOfSamplesRemaining = numberOfSamplesTotal; 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.isEmpty()) { // 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)) { qWarning() << "Failed to decode FLAC file" << m_file.fileName(); break; // abort } // After seeking we might need to skip some samples if the decoder // complained that it has lost sync for some malformed(?) files if (curFrameIndexBeforeProcessing != m_curFrameIndex) { if (curFrameIndexBeforeProcessing > m_curFrameIndex) { qWarning() << "Trying to adjust frame index" << m_curFrameIndex << "<>" << curFrameIndexBeforeProcessing << "while decoding FLAC file" << m_file.fileName(); skipSampleFrames(curFrameIndexBeforeProcessing - m_curFrameIndex); } else { qWarning() << "Unexpected frame index" << m_curFrameIndex << "<>" << curFrameIndexBeforeProcessing << "while decoding FLAC file" << m_file.fileName(); break; // abort } } DEBUG_ASSERT(curFrameIndexBeforeProcessing == m_curFrameIndex); } if (m_sampleBuffer.isEmpty()) { break; // EOF } const SampleBuffer::ReadableChunk readableChunk( m_sampleBuffer.readFromHead(numberOfSamplesRemaining)); const SINT framesToCopy = samples2frames(readableChunk.size()); if (outBuffer) { if (readStereoSamples && (kChannelCountStereo != getChannelCount())) { if (kChannelCountMono == getChannelCount()) { SampleUtil::copyMonoToDualMono(outBuffer, readableChunk.data(), framesToCopy); } else { SampleUtil::copyMultiToStereo(outBuffer, readableChunk.data(), framesToCopy, getChannelCount()); } outBuffer += framesToCopy * kChannelCountStereo; } else { SampleUtil::copy(outBuffer, readableChunk.data(), readableChunk.size()); outBuffer += readableChunk.size(); } } m_curFrameIndex += framesToCopy; numberOfSamplesRemaining -= readableChunk.size(); } DEBUG_ASSERT(isValidFrameIndex(m_curFrameIndex)); DEBUG_ASSERT(numberOfSamplesTotal >= numberOfSamplesRemaining); return samples2frames(numberOfSamplesTotal - numberOfSamplesRemaining); }