diff options
-rw-r--r-- | engines/tucker/resource.cpp | 2 | ||||
-rw-r--r-- | sound/flac.cpp | 92 | ||||
-rw-r--r-- | sound/flac.h | 3 | ||||
-rw-r--r-- | sound/mp3.cpp | 117 | ||||
-rw-r--r-- | sound/mp3.h | 3 | ||||
-rw-r--r-- | sound/vorbis.cpp | 133 | ||||
-rw-r--r-- | sound/vorbis.h | 3 |
7 files changed, 89 insertions, 264 deletions
diff --git a/engines/tucker/resource.cpp b/engines/tucker/resource.cpp index e868dbaef8..8bc6e2c8e3 100644 --- a/engines/tucker/resource.cpp +++ b/engines/tucker/resource.cpp @@ -43,7 +43,7 @@ enum { struct CompressedSoundFile { const char *filename; - Audio::SeekableAudioStream *(*makeStream)(Common::SeekableReadStream *stream, bool disposeAfterUse, uint32 startTime, uint32 duration, uint numLoops); + Audio::AudioStream *(*makeStream)(Common::SeekableReadStream *stream, bool disposeAfterUse, uint32 startTime, uint32 duration, uint numLoops); }; static const CompressedSoundFile compressedSoundFilesTable[] = { diff --git a/sound/flac.cpp b/sound/flac.cpp index d907137e8c..2036156991 100644 --- a/sound/flac.cpp +++ b/sound/flac.cpp @@ -92,17 +92,11 @@ protected: /** 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 */ FLAC__uint64 _lastSample; /** total play time */ - int32 _totalPlayTime; - - uint _numLoops; ///< Number of loops to play - uint _numPlayedLoops; ///< Number of loops which have been played + Timestamp _length; /** true if the last sample was decoded from the FLAC-API - there might still be data in the buffer */ bool _lastSampleWritten; @@ -130,7 +124,7 @@ protected: public: - FlacInputStream(Common::SeekableReadStream *inStream, bool dispose, uint startTime = 0, uint endTime = 0, uint numLoops = 1); + FlacInputStream(Common::SeekableReadStream *inStream, bool dispose); virtual ~FlacInputStream(); int readBuffer(int16 *buffer, const int numSamples); @@ -144,17 +138,9 @@ public: } bool seek(const Timestamp &where); - // TODO: We can definitly increase the precision here, since FLAC allows us to catch the sample count - Timestamp getLength() const { return Timestamp(_totalPlayTime, getRate()); } + Timestamp getLength() const { return _length; } bool isStreamDecoderReady() const { return getStreamDecoderState() == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC ; } - - void setNumLoops(uint numLoops = 1) { - _numLoops = numLoops; - _numPlayedLoops = 0; - } - uint getNumPlayedLoops() { return _numPlayedLoops; } - protected: uint getChannels() const { return MIN<uint>(_streaminfo.channels, MAX_OUTPUT_CHANNELS); } @@ -193,7 +179,7 @@ private: 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) +FlacInputStream::FlacInputStream(Common::SeekableReadStream *inStream, bool dispose) #ifdef LEGACY_FLAC : _decoder(::FLAC__seekable_stream_decoder_new()), #else @@ -201,9 +187,7 @@ FlacInputStream::FlacInputStream(Common::SeekableReadStream *inStream, bool disp #endif _inStream(inStream), _disposeAfterUse(dispose), - _numLoops(numLoops), - _numPlayedLoops(0), - _firstSample(0), _lastSample(0), + _length(0, 1000), _lastSample(0), _outBuffer(NULL), _requestedSamples(0), _lastSampleWritten(false), _methodConvertBuffers(&FlacInputStream::convertBuffersGeneric) { @@ -244,34 +228,9 @@ FlacInputStream::FlacInputStream(Common::SeekableReadStream *inStream, bool disp #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 = !endTime ? _streaminfo.total_samples + 1 : (FLAC__uint64)(endTime * (_streaminfo.sample_rate / 1000.0)); - - if (_firstSample == 0 || seekAbsolute(_firstSample)) { - int32 samples = -1; - - if (!_lastSample) { - if (_streaminfo.total_samples) - samples = _streaminfo.total_samples - _firstSample; - } else { - samples = _lastSample - _firstSample - 1; - } - - if (samples != -1 && samples >= 0 && numLoops) { - const int32 rate = _streaminfo.sample_rate; - - int32 seconds = samples / rate; - int32 milliseconds = (1000 * (samples % rate)) / rate; - - _totalPlayTime = (seconds * 1000 + milliseconds); - } else { - _totalPlayTime = 0; - } - - return; // no error occured - } + _lastSample = _streaminfo.total_samples + 1; + _length = Timestamp(0, _lastSample - 1, getRate()); + return; // no error occured } } @@ -381,16 +340,8 @@ int FlacInputStream::readBuffer(int16 *buffer, const int numSamples) { processSingleBlock(); state = getStreamDecoderState(); - if (state == FLAC__STREAM_DECODER_END_OF_STREAM) { + if (state == FLAC__STREAM_DECODER_END_OF_STREAM) _lastSampleWritten = true; - ++_numPlayedLoops; - } - - // If we reached the end of the stream, and looping is enabled: Try to rewind - if (_lastSampleWritten && (!_numLoops || _numPlayedLoops < _numLoops)) { - seekAbsolute(_firstSample); - state = getStreamDecoderState(); - } } // Error handling @@ -774,27 +725,36 @@ void FlacInputStream::callWrapError(const ::FLAC__SeekableStreamDecoder *decoder #pragma mark - -SeekableAudioStream *makeFlacStream( +AudioStream *makeFlacStream( Common::SeekableReadStream *stream, bool disposeAfterUse, uint32 startTime, uint32 duration, uint numLoops) { - uint32 endTime = duration ? (startTime + duration) : 0; + SeekableAudioStream *input = new FlacInputStream(stream, disposeAfterUse); + assert(input); - FlacInputStream *input = new FlacInputStream(stream, disposeAfterUse, startTime, endTime, numLoops); - if (!input->isStreamDecoderReady()) { - delete input; - return 0; + if (startTime || duration) { + Timestamp start(startTime, 1000), end(startTime + duration, 1000); + + if (!duration) + end = input->getLength(); + + input = new SubSeekableAudioStream(input, start, end); + assert(input); } - return input; + + if (numLoops) + return new LoopingAudioStream(input, numLoops); + else + return input; } SeekableAudioStream *makeFlacStream( Common::SeekableReadStream *stream, bool disposeAfterUse) { - return makeFlacStream(stream, disposeAfterUse, 0, 0, 1); + return new FlacInputStream(stream, disposeAfterUse); } } // End of namespace Audio diff --git a/sound/flac.h b/sound/flac.h index dd1c5dd770..5b8acf1154 100644 --- a/sound/flac.h +++ b/sound/flac.h @@ -51,6 +51,7 @@ namespace Common { namespace Audio { +class AudioStream; class SeekableAudioStream; /** @@ -69,7 +70,7 @@ class SeekableAudioStream; * @param numLoops how often the data shall be looped (0 = infinite) * @return a new AudioStream, or NULL, if an error occured */ -SeekableAudioStream *makeFlacStream( +AudioStream *makeFlacStream( Common::SeekableReadStream *stream, bool disposeAfterUse, uint32 startTime, diff --git a/sound/mp3.cpp b/sound/mp3.cpp index 7c590b0ef9..2ee4637a83 100644 --- a/sound/mp3.cpp +++ b/sound/mp3.cpp @@ -59,16 +59,9 @@ protected: uint _posInFrame; State _state; - const mad_timer_t _startTime; - const mad_timer_t _endTime; + Timestamp _length; mad_timer_t _totalTime; - int32 _totalPlayTime; // Length of one loop iteration - uint32 _length; // Total length of the MP3 stream - - uint _numLoops; ///< Number of loops to play - uint _numPlayedLoops; ///< Number of loops which have been played - mad_stream _stream; mad_frame _frame; mad_synth _synth; @@ -82,10 +75,7 @@ protected: public: MP3InputStream(Common::SeekableReadStream *inStream, - bool dispose, - mad_timer_t start = mad_timer_zero, - mad_timer_t end = mad_timer_zero, - uint numLoops = 1); + bool dispose); ~MP3InputStream(); int readBuffer(int16 *buffer, const int numSamples); @@ -95,15 +85,7 @@ public: int getRate() const { return _frame.header.samplerate; } bool seek(const Timestamp &where); - // TODO: Maybe we can have a more precise implementation of this - Timestamp getLength() const { return Timestamp(_totalPlayTime, getRate()); } - - void setNumLoops(uint numLoops) { - _numLoops = numLoops; - _numPlayedLoops = 0; - } - uint getNumPlayedLoops() { return _numPlayedLoops; } - + Timestamp getLength() const { return _length; } protected: void decodeMP3Data(); void readMP3Data(); @@ -113,19 +95,14 @@ protected: void deinitStream(); }; -MP3InputStream::MP3InputStream(Common::SeekableReadStream *inStream, bool dispose, mad_timer_t start, mad_timer_t end, uint numLoops) : +MP3InputStream::MP3InputStream(Common::SeekableReadStream *inStream, bool dispose) : _inStream(inStream), _disposeAfterUse(dispose), - _numLoops(numLoops), _posInFrame(0), _state(MP3_STATE_INIT), - _startTime(start), - _endTime(end), + _length(0, 1000), _totalTime(mad_timer_zero) { - // Make sure that either start < end, or end is zero (indicating "play until end") - assert(mad_timer_compare(_startTime, _endTime) < 0 || mad_timer_sign(_endTime) == 0); - // The MAD_BUFFER_GUARD must always contain zeros (the reason // for this is that the Layer III Huffman decoder of libMAD // may read a few bytes beyond the end of the input buffer). @@ -137,33 +114,13 @@ MP3InputStream::MP3InputStream(Common::SeekableReadStream *inStream, bool dispos while (_state != MP3_STATE_EOS) readHeader(); - _length = mad_timer_count(_totalTime, MAD_UNITS_MILLISECONDS); + _length = Timestamp(mad_timer_count(_totalTime, MAD_UNITS_MILLISECONDS), getRate()); deinitStream(); // Reinit stream _state = MP3_STATE_INIT; - // Calculate play time - mad_timer_t length; - - mad_timer_set(&length, 0, 0, 1000); - mad_timer_add(&length, start); - mad_timer_negate(&length); - - if (mad_timer_sign(end) != 0) { - mad_timer_add(&length, end); - } else { - mad_timer_set(&_totalTime, _length / 1000, _length % 1000, 1000); - mad_timer_add(&length, _totalTime); - _totalTime = mad_timer_zero; - } - - _totalPlayTime = mad_timer_count(length, MAD_UNITS_MILLISECONDS); - - if (mad_timer_sign(length) < 0) - _totalPlayTime = 0; - // Decode the first chunk of data. This is necessary so that _frame // is setup and isStereo() and getRate() return correct results. decodeMP3Data(); @@ -189,18 +146,9 @@ void MP3InputStream::decodeMP3Data() { readMP3Data(); while (_state == MP3_STATE_READY) { + // TODO: Do we need to use readHeader, when we do not do any seeking here? readHeader(); - // If we have not yet reached the start point, skip to the next frame - if (mad_timer_compare(_totalTime, _startTime) < 0) - continue; - - // If an end time is specified and we are past it, stop - if (mad_timer_sign(_endTime) > 0 && mad_timer_compare(_totalTime, _endTime) >= 0) { - _state = MP3_STATE_EOS; - break; - } - // Decode the next frame if (mad_frame_decode(&_frame, &_stream) == -1) { if (_stream.error == MAD_ERROR_BUFLEN) { @@ -222,18 +170,6 @@ void MP3InputStream::decodeMP3Data() { _posInFrame = 0; break; } - - if (_state == MP3_STATE_EOS) { - ++_numPlayedLoops; - // If looping is on and there are loops left, rewind to the start - if (!_numLoops || _numPlayedLoops < _numLoops) { - deinitStream(); - - // Reset the decoder state to indicate we should start over - _state = MP3_STATE_INIT; - } - } - } while (_state != MP3_STATE_EOS && _stream.error == MAD_ERROR_BUFLEN); if (_stream.error != MAD_ERROR_NONE) @@ -271,15 +207,15 @@ void MP3InputStream::readMP3Data() { } bool MP3InputStream::seek(const Timestamp &where) { - const uint32 time = where.msecs(); - - if (time == _length) { + if (where == _length) { _state = MP3_STATE_EOS; return true; - } else if (time > _length) { + } else if (where > _length) { return false; } + const uint32 time = where.msecs(); + mad_timer_t destination; mad_timer_set(&destination, time / 1000, time % 1000, 1000); @@ -402,33 +338,36 @@ int MP3InputStream::readBuffer(int16 *buffer, const int numSamples) { #pragma mark --- MP3 factory functions --- #pragma mark - -SeekableAudioStream *makeMP3Stream( +AudioStream *makeMP3Stream( Common::SeekableReadStream *stream, bool disposeAfterUse, uint32 startTime, uint32 duration, uint numLoops) { - mad_timer_t start; - mad_timer_t end; - - // Both startTime and duration are given in milliseconds. - // Calculate the appropriate mad_timer_t values from them. - mad_timer_set(&start, startTime / 1000, startTime % 1000, 1000); - if (duration == 0) { - end = mad_timer_zero; - } else { - int endTime = startTime + duration; - mad_timer_set(&end, endTime / 1000, endTime % 1000, 1000); + SeekableAudioStream *mp3 = new MP3InputStream(stream, disposeAfterUse); + assert(mp3); + + if (startTime || duration) { + Timestamp start(startTime, 1000), end(startTime + duration, 1000); + + if (!duration) + end = mp3->getLength(); + + mp3 = new SubSeekableAudioStream(mp3, start, end); + assert(mp3); } - return new MP3InputStream(stream, disposeAfterUse, start, end, numLoops); + if (numLoops) + return new LoopingAudioStream(mp3, numLoops); + else + return mp3; } SeekableAudioStream *makeMP3Stream( Common::SeekableReadStream *stream, bool disposeAfterUse) { - return makeMP3Stream(stream, disposeAfterUse, 0, 0, 1); + return new MP3InputStream(stream, disposeAfterUse); } } // End of namespace Audio diff --git a/sound/mp3.h b/sound/mp3.h index c0245636a3..9eb62e10e7 100644 --- a/sound/mp3.h +++ b/sound/mp3.h @@ -51,6 +51,7 @@ namespace Common { namespace Audio { +class AudioStream; class SeekableAudioStream; /** @@ -69,7 +70,7 @@ class SeekableAudioStream; * @param numLoops how often the data shall be looped (0 = infinite) * @return a new SeekableAudioStream, or NULL, if an error occured */ -SeekableAudioStream *makeMP3Stream( +AudioStream *makeMP3Stream( Common::SeekableReadStream *stream, bool disposeAfterUse, uint32 startTime, diff --git a/sound/vorbis.cpp b/sound/vorbis.cpp index 1ed608c0b5..e6da9eaf6d 100644 --- a/sound/vorbis.cpp +++ b/sound/vorbis.cpp @@ -93,16 +93,7 @@ protected: bool _isStereo; int _rate; - uint _numLoops; ///< Number of loops to play - uint _numPlayedLoops; ///< Number of loops which have been played - -#ifdef USE_TREMOR - ogg_int64_t _startTime; - ogg_int64_t _endTime; -#else - double _startTime; - double _endTime; -#endif + Timestamp _length; OggVorbis_File _ovFile; @@ -112,7 +103,7 @@ protected: public: // startTime / duration are in milliseconds - VorbisInputStream(Common::SeekableReadStream *inStream, bool dispose, uint startTime = 0, uint endTime = 0, uint numLoops = 1); + VorbisInputStream(Common::SeekableReadStream *inStream, bool dispose); ~VorbisInputStream(); int readBuffer(int16 *buffer, const int numSamples); @@ -121,30 +112,16 @@ public: bool isStereo() const { return _isStereo; } int getRate() const { return _rate; } - void setNumLoops(uint numLoops) { - _numLoops = numLoops; - _numPlayedLoops = 0; - } - uint getNumPlayedLoops() { return _numPlayedLoops; } - bool seek(const Timestamp &where); - // TODO: Maybe we can have a more precise implementation of this - Timestamp getLength() const { -#ifdef USE_TREMOR - return Timestamp(_endTime, getRate()); -#else - return Timestamp((uint32)(_endTime * 1000.0), getRate()); -#endif - } - + Timestamp getLength() const { return _length; } protected: bool refill(); }; -VorbisInputStream::VorbisInputStream(Common::SeekableReadStream *inStream, bool dispose, uint startTime, uint endTime, uint numLoops) : +VorbisInputStream::VorbisInputStream(Common::SeekableReadStream *inStream, bool dispose) : _inStream(inStream), _disposeAfterUse(dispose), - _numLoops(numLoops), + _length(0, 1000), _bufferEnd(_buffer + ARRAYSIZE(_buffer)) { int res = ov_open_callbacks(inStream, &_ovFile, NULL, 0, g_stream_wrap); @@ -155,41 +132,11 @@ VorbisInputStream::VorbisInputStream(Common::SeekableReadStream *inStream, bool } #ifdef USE_TREMOR - /* TODO: Symbian may have to use scumm_fixdfdi here? To quote: - "SumthinWicked says: fixing "relocation truncated to fit: ARM_26 __fixdfdi" during linking on GCC, see portdefs.h" - */ - - // In Tremor, the ov_time_seek() and ov_time_seek_page() calls take seeking - // positions in milliseconds as 64 bit integers, rather than in seconds as - // doubles as in Vorbisfile. - ogg_int64_t totalTime; - _startTime = startTime; - _endTime = endTime; + _length = Timestamp(ov_time_total(&_ovFile, -1), getRate()); #else - double totalTime; - _startTime = startTime / 1000.0; - _endTime = endTime / 1000.0; + _length = Timestamp(ov_time_total(&_ovFile, -1) * 1000.0, getRate()); #endif - // If endTime was 0, or is past the end of the file, set it to the maximal time possible - totalTime = ov_time_total(&_ovFile, -1); - if (_endTime == 0 || _endTime > totalTime) - _endTime = totalTime; - - // If the specified time range is empty, abort early. - if (_startTime >= _endTime) { - _pos = _bufferEnd; - return; - } - - // Seek to the start position - res = ov_time_seek(&_ovFile, _startTime); - if (res < 0) { - warning("Error seeking in Vorbis stream (%d)", res); - _pos = _bufferEnd; - return; - } - // Read in initial data if (!refill()) return; @@ -206,7 +153,7 @@ VorbisInputStream::~VorbisInputStream() { } int VorbisInputStream::readBuffer(int16 *buffer, const int numSamples) { - int res, samples = 0; + int samples = 0; while (samples < numSamples && _pos < _bufferEnd) { const int len = MIN(numSamples - samples, (int)(_bufferEnd - _pos)); memcpy(buffer, _pos, len * 2); @@ -216,24 +163,6 @@ int VorbisInputStream::readBuffer(int16 *buffer, const int numSamples) { if (_pos >= _bufferEnd) { if (!refill()) break; - - // If we are still out of data, and also past the end of specified - // time range, check whether looping is enabled... - if (_pos >= _bufferEnd && ov_time_tell(&_ovFile) >= _endTime) { - ++_numPlayedLoops; - // If looping is on and there are loops left, rewind to the start - if (!_numLoops || _numPlayedLoops < _numLoops) { - res = ov_time_seek(&_ovFile, _startTime); - if (res < 0) { - warning("Error seeking in Vorbis stream (%d)", res); - _pos = _bufferEnd; - break; - } - - if (!refill()) - break; - } - } } } return samples; @@ -252,26 +181,12 @@ bool VorbisInputStream::seek(const Timestamp &where) { bool VorbisInputStream::refill() { // Read the samples - int res; uint len_left = sizeof(_buffer); char *read_pos = (char *)_buffer; while (len_left > 0) { - if (ov_time_tell(&_ovFile) >= _endTime) { - // If looping is on and there are loops left, rewind to the start - if (_numLoops == 1) - break; // Last loop, abort - if (_numLoops != 0) - _numLoops--; - res = ov_time_seek(&_ovFile, _startTime); - if (res < 0) { - warning("Error seeking in Vorbis stream (%d)", res); - _pos = _bufferEnd; - return false; - } - } - long result; + #ifdef USE_TREMOR // Tremor ov_read() always returns data as signed 16 bit interleaved PCM // in host byte order. As such, it does not take arguments to request @@ -297,9 +212,10 @@ bool VorbisInputStream::refill() { // Possibly recoverable, just warn about it warning("Corrupted data in Vorbis file"); } else if (result == 0) { - warning("End of file while reading from Vorbis file"); - _pos = _bufferEnd; - return false; + //warning("End of file while reading from Vorbis file"); + //_pos = _bufferEnd; + //return false; + break; } else if (result < 0) { warning("Error reading from Vorbis stream (%d)", int(result)); _pos = _bufferEnd; @@ -324,29 +240,36 @@ bool VorbisInputStream::refill() { #pragma mark - -SeekableAudioStream *makeVorbisStream( +AudioStream *makeVorbisStream( Common::SeekableReadStream *stream, bool disposeAfterUse, uint32 startTime, uint32 duration, uint numLoops) { - uint32 endTime = duration ? (startTime + duration) : 0; + SeekableAudioStream *input = new VorbisInputStream(stream, disposeAfterUse); + assert(input); + + if (startTime || duration) { + Timestamp start(startTime, 1000), end(startTime + duration, 1000); - VorbisInputStream *input = new VorbisInputStream(stream, disposeAfterUse, startTime, endTime, numLoops); + if (!duration) + end = input->getLength(); - if (input->endOfData()) { - delete input; - return 0; + input = new SubSeekableAudioStream(input, start, end); + assert(input); } - return input; + if (numLoops) + return new LoopingAudioStream(input, numLoops); + else + return input; } SeekableAudioStream *makeVorbisStream( Common::SeekableReadStream *stream, bool disposeAfterUse) { - return makeVorbisStream(stream, disposeAfterUse, 0, 0, 1); + return new VorbisInputStream(stream, disposeAfterUse); } } // End of namespace Audio diff --git a/sound/vorbis.h b/sound/vorbis.h index 8ac7354f1f..e0c6f07b58 100644 --- a/sound/vorbis.h +++ b/sound/vorbis.h @@ -51,6 +51,7 @@ namespace Common { namespace Audio { +class AudioStream; class SeekableAudioStream; /** @@ -69,7 +70,7 @@ class SeekableAudioStream; * @param numLoops how often the data shall be looped (0 = infinite) * @return a new SeekableAudioStream, or NULL, if an error occured */ -SeekableAudioStream *makeVorbisStream( +AudioStream *makeVorbisStream( Common::SeekableReadStream *stream, bool disposeAfterUse, uint32 startTime, |