/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $URL$ * $Id$ * */ #include "sound/flac.h" #ifdef USE_FLAC #include "common/debug.h" #include "common/stream.h" #include "common/util.h" #include "sound/audiostream.h" #include "sound/audiocd.h" #define FLAC__NO_DLL // that MS-magic gave me headaches - just link the library you like #include // check if we have FLAC >= 1.1.3; LEGACY_FLAC code can be removed once FLAC-1.1.3 propagates everywhere #if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT < 8 #define LEGACY_FLAC #else #undef LEGACY_FLAC #endif #ifdef LEGACY_FLAC // Before FLAC 1.1.3, we needed to use the stream decoder API. #include typedef uint FLAC_size_t; #else // With FLAC 1.1.3, the stream decoder API was merged into the regular // stream API. In order to stay compatible with older FLAC versions, we // simply add some typedefs and #ifdefs to map between the old and new API. // We use the typedefs (instead of only #defines) in order to somewhat // improve the readability of the code. #include typedef size_t FLAC_size_t; // Add aliases for the old names typedef FLAC__StreamDecoderState FLAC__SeekableStreamDecoderState; typedef FLAC__StreamDecoderReadStatus FLAC__SeekableStreamDecoderReadStatus; typedef FLAC__StreamDecoderSeekStatus FLAC__SeekableStreamDecoderSeekStatus; typedef FLAC__StreamDecoderTellStatus FLAC__SeekableStreamDecoderTellStatus; typedef FLAC__StreamDecoderLengthStatus FLAC__SeekableStreamDecoderLengthStatus; typedef FLAC__StreamDecoder FLAC__SeekableStreamDecoder; #endif namespace Audio { #pragma mark - #pragma mark --- Flac stream --- #pragma mark - static const uint MAX_OUTPUT_CHANNELS = 2; class FlacInputStream : public AudioStream { protected: Common::SeekableReadStream *_inStream; bool _disposeAfterUse; uint _numLoops; ::FLAC__SeekableStreamDecoder *_decoder; /** Header of the stream */ FLAC__StreamMetadata_StreamInfo _streaminfo; /** index of the first sample to be played */ FLAC__uint64 _firstSample; /** index + 1(!) of the last sample to be played - 0 is end of stream */ FLAC__uint64 _lastSample; /** total play time */ int32 _totalPlayTime; /** true if the last sample was decoded from the FLAC-API - there might still be data in the buffer */ bool _lastSampleWritten; typedef int16 SampleType; enum { BUFTYPE_BITS = 16 }; enum { // Maximal buffer size. According to the FLAC format specification, the block size is // a 16 bit value (in fact it seems the maximal block size is 32768, but we play it safe). BUFFER_SIZE = 65536 }; struct { SampleType bufData[BUFFER_SIZE]; SampleType *bufReadPos; uint bufFill; } _sampleCache; SampleType *_outBuffer; uint _requestedSamples; typedef void (*PFCONVERTBUFFERS)(SampleType*, const FLAC__int32*[], uint, const uint, const uint8); PFCONVERTBUFFERS _methodConvertBuffers; public: FlacInputStream(Common::SeekableReadStream *inStream, bool dispose, uint startTime = 0, uint endTime = 0, uint numLoops = 1); virtual ~FlacInputStream(); int readBuffer(int16 *buffer, const int numSamples); bool isStereo() const { return _streaminfo.channels >= 2; } int getRate() const { return _streaminfo.sample_rate; } bool endOfData() const { // End of data is reached if there either is no valid stream data available, // or if we reached the last sample and completely emptied the sample cache. return _streaminfo.channels == 0 || (_lastSampleWritten && _sampleCache.bufFill == 0); } int32 getTotalPlayTime() const { return _totalPlayTime; } bool isStreamDecoderReady() const { return getStreamDecoderState() == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC ; } protected: uint getChannels() const { return MIN(_streaminfo.channels, MAX_OUTPUT_CHANNELS); } bool allocateBuffer(uint minSamples); inline FLAC__StreamDecoderState getStreamDecoderState() const; inline bool processSingleBlock(); inline bool processUntilEndOfMetadata(); bool seekAbsolute(FLAC__uint64 sample); inline ::FLAC__SeekableStreamDecoderReadStatus callbackRead(FLAC__byte buffer[], FLAC_size_t *bytes); inline ::FLAC__SeekableStreamDecoderSeekStatus callbackSeek(FLAC__uint64 absoluteByteOffset); inline ::FLAC__SeekableStreamDecoderTellStatus callbackTell(FLAC__uint64 *absoluteByteOffset); inline ::FLAC__SeekableStreamDecoderLengthStatus callbackLength(FLAC__uint64 *streamLength); inline bool callbackEOF(); inline ::FLAC__StreamDecoderWriteStatus callbackWrite(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]); inline void callbackMetadata(const ::FLAC__StreamMetadata *metadata); inline void callbackError(::FLAC__StreamDecoderErrorStatus status); private: static ::FLAC__SeekableStreamDecoderReadStatus callWrapRead(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], FLAC_size_t *bytes, void *clientData); static ::FLAC__SeekableStreamDecoderSeekStatus callWrapSeek(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absoluteByteOffset, void *clientData); static ::FLAC__SeekableStreamDecoderTellStatus callWrapTell(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absoluteByteOffset, void *clientData); static ::FLAC__SeekableStreamDecoderLengthStatus callWrapLength(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *streamLength, void *clientData); static FLAC__bool callWrapEOF(const ::FLAC__SeekableStreamDecoder *decoder, void *clientData); static ::FLAC__StreamDecoderWriteStatus callWrapWrite(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData); static void callWrapMetadata(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *clientData); static void callWrapError(const ::FLAC__SeekableStreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *clientData); void setBestConvertBufferMethod(); static void convertBuffersGeneric(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits); static void convertBuffersStereoNS(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits); static void convertBuffersStereo8Bit(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits); static void convertBuffersMonoNS(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits); static void convertBuffersMono8Bit(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits); }; FlacInputStream::FlacInputStream(Common::SeekableReadStream *inStream, bool dispose, uint startTime, uint endTime, uint numLoops) #ifdef LEGACY_FLAC : _decoder(::FLAC__seekable_stream_decoder_new()), #else : _decoder(::FLAC__stream_decoder_new()), #endif _inStream(inStream), _disposeAfterUse(dispose), _numLoops(numLoops), _firstSample(0), _lastSample(0), _outBuffer(NULL), _requestedSamples(0), _lastSampleWritten(false), _methodConvertBuffers(&FlacInputStream::convertBuffersGeneric) { assert(_inStream); memset(&_streaminfo, 0, sizeof(_streaminfo)); _sampleCache.bufReadPos = NULL; _sampleCache.bufFill = 0; _methodConvertBuffers = &FlacInputStream::convertBuffersGeneric; bool success; #ifdef LEGACY_FLAC ::FLAC__seekable_stream_decoder_set_read_callback(_decoder, &FlacInputStream::callWrapRead); ::FLAC__seekable_stream_decoder_set_seek_callback(_decoder, &FlacInputStream::callWrapSeek); ::FLAC__seekable_stream_decoder_set_tell_callback(_decoder, &FlacInputStream::callWrapTell); ::FLAC__seekable_stream_decoder_set_length_callback(_decoder, &FlacInputStream::callWrapLength); ::FLAC__seekable_stream_decoder_set_eof_callback(_decoder, &FlacInputStream::callWrapEOF); ::FLAC__seekable_stream_decoder_set_write_callback(_decoder, &FlacInputStream::callWrapWrite); ::FLAC__seekable_stream_decoder_set_metadata_callback(_decoder, &FlacInputStream::callWrapMetadata); ::FLAC__seekable_stream_decoder_set_error_callback(_decoder, &FlacInputStream::callWrapError); ::FLAC__seekable_stream_decoder_set_client_data(_decoder, (void*)this); success = (::FLAC__seekable_stream_decoder_init(_decoder) == FLAC__SEEKABLE_STREAM_DECODER_OK); #else success = (::FLAC__stream_decoder_init_stream( _decoder, &FlacInputStream::callWrapRead, &FlacInputStream::callWrapSeek, &FlacInputStream::callWrapTell, &FlacInputStream::callWrapLength, &FlacInputStream::callWrapEOF, &FlacInputStream::callWrapWrite, &FlacInputStream::callWrapMetadata, &FlacInputStream::callWrapError, (void*)this ) == FLAC__STREAM_DECODER_INIT_STATUS_OK); #endif if (success) { if (processUntilEndOfMetadata() && _streaminfo.channels > 0) { // Compute the start/end sample (we use floating point arithmetics here to // avoid overflows). _firstSample = (FLAC__uint64)(startTime * (_streaminfo.sample_rate / 1000.0)); _lastSample = (FLAC__uint64)(endTime * (_streaminfo.sample_rate / 1000.0)); if (_firstSample == 0 || seekAbsolute(_firstSample)) { int32 samples = kUnknownPlayTime; if (!_lastSample) { if (_streaminfo.total_samples) samples = _streaminfo.total_samples - _firstSample; } else { samples = _lastSample - _firstSample - 1; } if (samples != kUnknownPlayTime && samples >= 0 && numLoops) { const int32 rate = _streaminfo.sample_rate; int32 seconds = samples / rate; int32 milliseconds = (1000 * (samples % rate)) / rate; _totalPlayTime = (seconds * 1000 + milliseconds) * numLoops; } else { _totalPlayTime = kUnknownPlayTime; } return; // no error occured } } } warning("FlacInputStream: could not create audio stream"); } FlacInputStream::~FlacInputStream() { if (_decoder != NULL) { #ifdef LEGACY_FLAC (void) ::FLAC__seekable_stream_decoder_finish(_decoder); ::FLAC__seekable_stream_decoder_delete(_decoder); #else (void) ::FLAC__stream_decoder_finish(_decoder); ::FLAC__stream_decoder_delete(_decoder); #endif } if (_disposeAfterUse) delete _inStream; } inline FLAC__StreamDecoderState FlacInputStream::getStreamDecoderState() const { assert(_decoder != NULL); #ifdef LEGACY_FLAC return ::FLAC__seekable_stream_decoder_get_stream_decoder_state(_decoder); #else return ::FLAC__stream_decoder_get_state(_decoder); #endif } inline bool FlacInputStream::processSingleBlock() { assert(_decoder != NULL); #ifdef LEGACY_FLAC return 0 != ::FLAC__seekable_stream_decoder_process_single(_decoder); #else return 0 != ::FLAC__stream_decoder_process_single(_decoder); #endif } inline bool FlacInputStream::processUntilEndOfMetadata() { assert(_decoder != NULL); #ifdef LEGACY_FLAC return 0 != ::FLAC__seekable_stream_decoder_process_until_end_of_metadata(_decoder); #else return 0 != ::FLAC__stream_decoder_process_until_end_of_metadata(_decoder); #endif } bool FlacInputStream::seekAbsolute(FLAC__uint64 sample) { assert(_decoder != NULL); #ifdef LEGACY_FLAC const bool result = (0 != ::FLAC__seekable_stream_decoder_seek_absolute(_decoder, sample)); #else const bool result = (0 != ::FLAC__stream_decoder_seek_absolute(_decoder, sample)); #endif if (result) { _lastSampleWritten = (_lastSample != 0 && sample >= _lastSample); // only set if we are SURE } return result; } int FlacInputStream::readBuffer(int16 *buffer, const int numSamples) { const uint numChannels = getChannels(); if (numChannels == 0) { warning("FlacInputStream: Stream not sucessfully initialised, cant playback"); return -1; // streaminfo wasnt read! } assert(numSamples % numChannels == 0); // must be multiple of channels! assert(buffer != NULL); assert(_outBuffer == NULL); assert(_requestedSamples == 0); _outBuffer = buffer; _requestedSamples = numSamples; // If there is still data in our buffer from the last time around, // copy that first. if (_sampleCache.bufFill > 0) { assert(_sampleCache.bufReadPos >= _sampleCache.bufData); assert(_sampleCache.bufFill % numChannels == 0); const uint copySamples = MIN((uint)numSamples, _sampleCache.bufFill); memcpy(buffer, _sampleCache.bufReadPos, copySamples*sizeof(buffer[0])); _outBuffer = buffer + copySamples; _requestedSamples = numSamples - copySamples; _sampleCache.bufReadPos += copySamples; _sampleCache.bufFill -= copySamples; } bool decoderOk = true; FLAC__StreamDecoderState state = getStreamDecoderState(); // Keep poking FLAC to process more samples until we completely satisfied the request // respectively until we run out of data. while (!_lastSampleWritten && _requestedSamples > 0 && state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) { assert(_sampleCache.bufFill == 0); assert(_requestedSamples % numChannels == 0); processSingleBlock(); state = getStreamDecoderState(); if (state == FLAC__STREAM_DECODER_END_OF_STREAM) { _lastSampleWritten = true; } // If we reached the end of the stream, and looping is enabled: Try to rewind if (_lastSampleWritten && _numLoops != 1) { if (_numLoops != 0) _numLoops--; seekAbsolute(_firstSample); state = getStreamDecoderState(); } } // Error handling switch (state) { case FLAC__STREAM_DECODER_END_OF_STREAM: _lastSampleWritten = true; break; case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: break; default: decoderOk = false; warning("FlacInputStream: An error occured while decoding. DecoderState is: %s", FLAC__StreamDecoderStateString[getStreamDecoderState()]); } // Compute how many samples we actually produced const int samples = (int)(_outBuffer - buffer); assert(samples % numChannels == 0); _outBuffer = NULL; // basically unnecessary, only for the purpose of the asserts _requestedSamples = 0; // basically unnecessary, only for the purpose of the asserts return decoderOk ? samples : -1; } inline ::FLAC__SeekableStreamDecoderReadStatus FlacInputStream::callbackRead(FLAC__byte buffer[], FLAC_size_t *bytes) { if (*bytes == 0) { #ifdef LEGACY_FLAC return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; /* abort to avoid a deadlock */ #else return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */ #endif } const uint32 bytesRead = _inStream->read(buffer, *bytes); if (bytesRead == 0) { #ifdef LEGACY_FLAC return _inStream->eos() ? FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK : FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; #else return _inStream->eos() ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_ABORT; #endif } *bytes = static_cast(bytesRead); #ifdef LEGACY_FLAC return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK; #else return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; #endif } void FlacInputStream::setBestConvertBufferMethod() { PFCONVERTBUFFERS tempMethod = &FlacInputStream::convertBuffersGeneric; const uint numChannels = getChannels(); const uint8 numBits = (uint8)_streaminfo.bits_per_sample; assert(numChannels >= 1); assert(numBits >= 4 && numBits <=32); if (numChannels == 1) { if (numBits == 8) tempMethod = &FlacInputStream::convertBuffersMono8Bit; if (numBits == BUFTYPE_BITS) tempMethod = &FlacInputStream::convertBuffersMonoNS; } else if (numChannels == 2) { if (numBits == 8) tempMethod = &FlacInputStream::convertBuffersStereo8Bit; if (numBits == BUFTYPE_BITS) tempMethod = &FlacInputStream::convertBuffersStereoNS; } /* else ... */ _methodConvertBuffers = tempMethod; } // 1 channel, no scaling void FlacInputStream::convertBuffersMonoNS(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) { assert(numChannels == 1); assert(numBits == BUFTYPE_BITS); FLAC__int32 const* inChannel1 = inChannels[0]; while (numSamples >= 4) { bufDestination[0] = static_cast(inChannel1[0]); bufDestination[1] = static_cast(inChannel1[1]); bufDestination[2] = static_cast(inChannel1[2]); bufDestination[3] = static_cast(inChannel1[3]); bufDestination += 4; inChannel1 += 4; numSamples -= 4; } for (; numSamples > 0; --numSamples) { *bufDestination++ = static_cast(*inChannel1++); } inChannels[0] = inChannel1; assert(numSamples == 0); // dint copy too many samples } // 1 channel, scaling from 8Bit void FlacInputStream::convertBuffersMono8Bit(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) { assert(numChannels == 1); assert(numBits == 8); assert(8 < BUFTYPE_BITS); FLAC__int32 const* inChannel1 = inChannels[0]; while (numSamples >= 4) { bufDestination[0] = static_cast(inChannel1[0]) << (BUFTYPE_BITS - 8); bufDestination[1] = static_cast(inChannel1[1]) << (BUFTYPE_BITS - 8); bufDestination[2] = static_cast(inChannel1[2]) << (BUFTYPE_BITS - 8); bufDestination[3] = static_cast(inChannel1[3]) << (BUFTYPE_BITS - 8); bufDestination += 4; inChannel1 += 4; numSamples -= 4; } for (; numSamples > 0; --numSamples) { *bufDestination++ = static_cast(*inChannel1++) << (BUFTYPE_BITS - 8); } inChannels[0] = inChannel1; assert(numSamples == 0); // dint copy too many samples } // 2 channels, no scaling void FlacInputStream::convertBuffersStereoNS(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) { assert(numChannels == 2); assert(numBits == BUFTYPE_BITS); assert(numSamples % 2 == 0); // must be integral multiply of channels FLAC__int32 const* inChannel1 = inChannels[0]; // Left Channel FLAC__int32 const* inChannel2 = inChannels[1]; // Right Channel while (numSamples >= 2*2) { bufDestination[0] = static_cast(inChannel1[0]); bufDestination[1] = static_cast(inChannel2[0]); bufDestination[2] = static_cast(inChannel1[1]); bufDestination[3] = static_cast(inChannel2[1]); bufDestination += 2 * 2; inChannel1 += 2; inChannel2 += 2; numSamples -= 2 * 2; } while (numSamples > 0) { bufDestination[0] = static_cast(*inChannel1++); bufDestination[1] = static_cast(*inChannel2++); bufDestination += 2; numSamples -= 2; } inChannels[0] = inChannel1; inChannels[1] = inChannel2; assert(numSamples == 0); // dint copy too many samples } // 2 channels, scaling from 8Bit void FlacInputStream::convertBuffersStereo8Bit(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) { assert(numChannels == 2); assert(numBits == 8); assert(numSamples % 2 == 0); // must be integral multiply of channels assert(8 < BUFTYPE_BITS); FLAC__int32 const* inChannel1 = inChannels[0]; // Left Channel FLAC__int32 const* inChannel2 = inChannels[1]; // Right Channel while (numSamples >= 2*2) { bufDestination[0] = static_cast(inChannel1[0]) << (BUFTYPE_BITS - 8); bufDestination[1] = static_cast(inChannel2[0]) << (BUFTYPE_BITS - 8); bufDestination[2] = static_cast(inChannel1[1]) << (BUFTYPE_BITS - 8); bufDestination[3] = static_cast(inChannel2[1]) << (BUFTYPE_BITS - 8); bufDestination += 2 * 2; inChannel1 += 2; inChannel2 += 2; numSamples -= 2 * 2; } while (numSamples > 0) { bufDestination[0] = static_cast(*inChannel1++) << (BUFTYPE_BITS - 8); bufDestination[1] = static_cast(*inChannel2++) << (BUFTYPE_BITS - 8); bufDestination += 2; numSamples -= 2; } inChannels[0] = inChannel1; inChannels[1] = inChannel2; assert(numSamples == 0); // dint copy too many samples } // all Purpose-conversion - slowest of em all void FlacInputStream::convertBuffersGeneric(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) { assert(numSamples % numChannels == 0); // must be integral multiply of channels if (numBits < BUFTYPE_BITS) { const uint8 kPower = (uint8)(BUFTYPE_BITS - numBits); for (; numSamples > 0; numSamples -= numChannels) { for (uint i = 0; i < numChannels; ++i) *bufDestination++ = static_cast(*(inChannels[i]++)) << kPower; } } else if (numBits > BUFTYPE_BITS) { const uint8 kPower = (uint8)(numBits - BUFTYPE_BITS); for (; numSamples > 0; numSamples -= numChannels) { for (uint i = 0; i < numChannels; ++i) *bufDestination++ = static_cast(*(inChannels[i]++) >> kPower) ; } } else { for (; numSamples > 0; numSamples -= numChannels) { for (uint i = 0; i < numChannels; ++i) *bufDestination++ = static_cast(*(inChannels[i]++)); } } assert(numSamples == 0); // dint copy too many samples } inline ::FLAC__StreamDecoderWriteStatus FlacInputStream::callbackWrite(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) { assert(frame->header.channels == _streaminfo.channels); assert(frame->header.sample_rate == _streaminfo.sample_rate); assert(frame->header.bits_per_sample == _streaminfo.bits_per_sample); assert(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER || _streaminfo.min_blocksize == _streaminfo.max_blocksize); // We require that either the sample cache is empty, or that no samples were requested assert(_sampleCache.bufFill == 0 || _requestedSamples == 0); uint numSamples = frame->header.blocksize; const uint numChannels = getChannels(); const uint8 numBits = (uint8)_streaminfo.bits_per_sample; assert(_requestedSamples % numChannels == 0); // must be integral multiply of channels const FLAC__uint64 firstSampleNumber = (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER) ? frame->header.number.sample_number : (static_cast(frame->header.number.frame_number)) * _streaminfo.max_blocksize; // Check whether we are about to reach beyond the last sample we are supposed to play. if (_lastSample != 0 && firstSampleNumber + numSamples >= _lastSample) { numSamples = (uint)(firstSampleNumber >= _lastSample ? 0 : _lastSample - firstSampleNumber); _lastSampleWritten = true; } // The value in _requestedSamples counts raw samples, so if there are more than one // channel, we have to multiply the number of available sample "pairs" by numChannels numSamples *= numChannels; const FLAC__int32 *inChannels[MAX_OUTPUT_CHANNELS]; for (uint i = 0; i < numChannels; ++i) inChannels[i] = buffer[i]; // write the incoming samples directly into the buffer provided to us by the mixer if (_requestedSamples > 0) { assert(_requestedSamples % numChannels == 0); assert(_outBuffer != NULL); // Copy & convert the available samples (limited both by how many we have available, and // by how many are actually needed). const uint copySamples = MIN(_requestedSamples, numSamples); (*_methodConvertBuffers)(_outBuffer, inChannels, copySamples, numChannels, numBits); _requestedSamples -= copySamples; numSamples -= copySamples; _outBuffer += copySamples; } // Write all remaining samples (i.e. those which didn't fit into the mixer buffer) // into the sample cache. if (_sampleCache.bufFill == 0) _sampleCache.bufReadPos = _sampleCache.bufData; const uint cacheSpace = (_sampleCache.bufData + BUFFER_SIZE) - (_sampleCache.bufReadPos + _sampleCache.bufFill); assert(numSamples <= cacheSpace); (*_methodConvertBuffers)(_sampleCache.bufReadPos + _sampleCache.bufFill, inChannels, numSamples, numChannels, numBits); _sampleCache.bufFill += numSamples; return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } inline ::FLAC__SeekableStreamDecoderSeekStatus FlacInputStream::callbackSeek(FLAC__uint64 absoluteByteOffset) { _inStream->seek(absoluteByteOffset, SEEK_SET); const bool result = (absoluteByteOffset == (FLAC__uint64)_inStream->pos()); #ifdef LEGACY_FLAC return result ? FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK : FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR; #else return result ? FLAC__STREAM_DECODER_SEEK_STATUS_OK : FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; #endif } inline ::FLAC__SeekableStreamDecoderTellStatus FlacInputStream::callbackTell(FLAC__uint64 *absoluteByteOffset) { *absoluteByteOffset = static_cast(_inStream->pos()); #ifdef LEGACY_FLAC return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK; #else return FLAC__STREAM_DECODER_TELL_STATUS_OK; #endif } inline ::FLAC__SeekableStreamDecoderLengthStatus FlacInputStream::callbackLength(FLAC__uint64 *streamLength) { *streamLength = static_cast(_inStream->size()); #ifdef LEGACY_FLAC return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK; #else return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; #endif } inline bool FlacInputStream::callbackEOF() { return _inStream->eos(); } inline void FlacInputStream::callbackMetadata(const ::FLAC__StreamMetadata *metadata) { assert(_decoder != NULL); assert(metadata->type == FLAC__METADATA_TYPE_STREAMINFO); // others arent really interesting _streaminfo = metadata->data.stream_info; setBestConvertBufferMethod(); // should be set after getting stream-information. FLAC always parses the info first } inline void FlacInputStream::callbackError(::FLAC__StreamDecoderErrorStatus status) { // some of these are non-critical-Errors debug(1, "FlacInputStream: An error occured while decoding. DecoderState is: %s", FLAC__StreamDecoderErrorStatusString[status]); } /* Static Callback Wrappers */ ::FLAC__SeekableStreamDecoderReadStatus FlacInputStream::callWrapRead(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], FLAC_size_t *bytes, void *clientData) { FlacInputStream *instance = (FlacInputStream *)clientData; assert(0 != instance); return instance->callbackRead(buffer, bytes); } ::FLAC__SeekableStreamDecoderSeekStatus FlacInputStream::callWrapSeek(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absoluteByteOffset, void *clientData) { FlacInputStream *instance = (FlacInputStream *)clientData; assert(0 != instance); return instance->callbackSeek(absoluteByteOffset); } ::FLAC__SeekableStreamDecoderTellStatus FlacInputStream::callWrapTell(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absoluteByteOffset, void *clientData) { FlacInputStream *instance = (FlacInputStream *)clientData; assert(0 != instance); return instance->callbackTell(absoluteByteOffset); } ::FLAC__SeekableStreamDecoderLengthStatus FlacInputStream::callWrapLength(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *streamLength, void *clientData) { FlacInputStream *instance = (FlacInputStream *)clientData; assert(0 != instance); return instance->callbackLength(streamLength); } FLAC__bool FlacInputStream::callWrapEOF(const ::FLAC__SeekableStreamDecoder *decoder, void *clientData) { FlacInputStream *instance = (FlacInputStream *)clientData; assert(0 != instance); return instance->callbackEOF(); } ::FLAC__StreamDecoderWriteStatus FlacInputStream::callWrapWrite(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData) { FlacInputStream *instance = (FlacInputStream *)clientData; assert(0 != instance); return instance->callbackWrite(frame, buffer); } void FlacInputStream::callWrapMetadata(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *clientData) { FlacInputStream *instance = (FlacInputStream *)clientData; assert(0 != instance); instance->callbackMetadata(metadata); } void FlacInputStream::callWrapError(const ::FLAC__SeekableStreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *clientData) { FlacInputStream *instance = (FlacInputStream *)clientData; assert(0 != instance); instance->callbackError(status); } #pragma mark - #pragma mark --- Flac factory functions --- #pragma mark - AudioStream *makeFlacStream( Common::SeekableReadStream *stream, bool disposeAfterUse, uint32 startTime, uint32 duration, uint numLoops) { uint32 endTime = duration ? (startTime + duration) : 0; FlacInputStream *input = new FlacInputStream(stream, disposeAfterUse, startTime, endTime, numLoops); if (!input->isStreamDecoderReady()) { delete input; return 0; } return input; } } // End of namespace Audio #endif // #ifdef USE_FLAC