diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/audiostream.cpp | 15 | ||||
-rw-r--r-- | sound/audiostream.h | 14 | ||||
-rw-r--r-- | sound/flac.cpp | 26 | ||||
-rw-r--r-- | sound/fmopl.h | 4 | ||||
-rw-r--r-- | sound/midiplugin.h | 2 | ||||
-rw-r--r-- | sound/mp3.cpp | 70 | ||||
-rw-r--r-- | sound/softsynth/mt32/mt32emu.h | 2 | ||||
-rw-r--r-- | sound/vorbis.cpp | 13 |
8 files changed, 138 insertions, 8 deletions
diff --git a/sound/audiostream.cpp b/sound/audiostream.cpp index 0fba6affdb..4454a09fe6 100644 --- a/sound/audiostream.cpp +++ b/sound/audiostream.cpp @@ -102,6 +102,11 @@ AudioStream* AudioStream::openStreamFile(const Common::String &basename, uint32 #pragma mark --- LinearMemoryStream --- #pragma mark - +inline int32 calculatePlayTime(int rate, int samples) { + int32 seconds = samples / rate; + int32 milliseconds = (1000 * (samples % rate)) / rate; + return seconds * 1000 + milliseconds; +} /** * A simple raw audio stream, purely memory based. It operates on a single @@ -122,10 +127,11 @@ protected: const byte *_loopEnd; const int _rate; const byte *_origPtr; + const int32 _playtime; public: LinearMemoryStream(int rate, const byte *ptr, uint len, uint loopOffset, uint loopLen, bool autoFreeMemory) - : _ptr(ptr), _end(ptr+len), _loopPtr(0), _loopEnd(0), _rate(rate) { + : _ptr(ptr), _end(ptr+len), _loopPtr(0), _loopEnd(0), _rate(rate), _playtime(calculatePlayTime(rate, len / (is16Bit ? 2 : 1) / (stereo ? 2 : 1))) { // Verify the buffer sizes are sane if (is16Bit && stereo) @@ -147,10 +153,11 @@ public: } int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { return stereo; } - bool endOfData() const { return _ptr >= _end; } + bool isStereo() const { return stereo; } + bool endOfData() const { return _ptr >= _end; } - int getRate() const { return _rate; } + int getRate() const { return _rate; } + int32 getTotalPlayTime() const { return _playtime; } }; template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE> diff --git a/sound/audiostream.h b/sound/audiostream.h index ed6b37e51c..04133936ee 100644 --- a/sound/audiostream.h +++ b/sound/audiostream.h @@ -93,6 +93,20 @@ public: * NULL in case of an error (e.g. invalid/nonexisting file) */ static AudioStream* openStreamFile(const Common::String &basename, uint32 startTime = 0, uint32 duration = 0, uint numLoops = 1); + + enum { + kUnknownPlayTime = -1 + }; + + /** + * Returns total playtime of the AudioStream object. + * Note that this does not require to return an playtime, if the + * playtime of the AudioStream is unknown it returns 'kUnknownPlayTime'. + * @see kUnknownPlayTime + * + * @return playtime in milliseconds + */ + virtual int32 getTotalPlayTime() const { return kUnknownPlayTime; } }; /** diff --git a/sound/flac.cpp b/sound/flac.cpp index 8dc3586142..f058d2dc6f 100644 --- a/sound/flac.cpp +++ b/sound/flac.cpp @@ -102,6 +102,9 @@ protected: /** 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; @@ -141,6 +144,8 @@ public: 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: @@ -235,7 +240,28 @@ FlacInputStream::FlacInputStream(Common::SeekableReadStream *inStream, bool disp // 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 } } diff --git a/sound/fmopl.h b/sound/fmopl.h index cc2f967f25..890a2d1a56 100644 --- a/sound/fmopl.h +++ b/sound/fmopl.h @@ -167,7 +167,7 @@ int OPLTimerOver(FM_OPL *OPL, int c); void OPLWriteReg(FM_OPL *OPL, int r, int v); void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length); -#endif - // Factory method FM_OPL *makeAdlibOPL(int rate); + +#endif diff --git a/sound/midiplugin.h b/sound/midiplugin.h index c3b407a142..0247e160e1 100644 --- a/sound/midiplugin.h +++ b/sound/midiplugin.h @@ -84,7 +84,7 @@ private: friend class Common::Singleton<SingletonBaseType>; public: - const MidiPlugin::list &getPlugins() const; + const MidiPlugin::List &getPlugins() const; }; /** Convenience shortcut for accessing the MIDI manager. */ diff --git a/sound/mp3.cpp b/sound/mp3.cpp index 72ed361926..eea725ce3a 100644 --- a/sound/mp3.cpp +++ b/sound/mp3.cpp @@ -63,6 +63,8 @@ protected: const mad_timer_t _endTime; mad_timer_t _totalTime; + int32 _totalPlayTime; + mad_stream _stream; mad_frame _frame; mad_synth _synth; @@ -87,6 +89,7 @@ public: bool endOfData() const { return _state == MP3_STATE_EOS; } bool isStereo() const { return MAD_NCHANNELS(&_frame.header) == 2; } int getRate() const { return _frame.header.samplerate; } + int32 getTotalPlayTime() const { return _totalPlayTime; } protected: void decodeMP3Data(); @@ -111,6 +114,73 @@ MP3InputStream::MP3InputStream(Common::SeekableReadStream *inStream, bool dispos // may read a few bytes beyond the end of the input buffer). memset(_buf + BUFFER_SIZE, 0, MAD_BUFFER_GUARD); + // 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_stream_init(&_stream); + mad_frame_init(&_frame); + + // Reset the stream data + _inStream->seek(0, SEEK_SET); + + // Update state + _state = MP3_STATE_READY; + + // Read the first few sample bytes + readMP3Data(); + + do { + // If necessary, load more data into the stream decoder + if (_stream.error == MAD_ERROR_BUFLEN) + readMP3Data(); + + while (_state == MP3_STATE_READY) { + _stream.error = MAD_ERROR_NONE; + + // Decode the next header. Note: mad_frame_decode would do this for us, too. + // However, for seeking we don't want to decode the full frame (else it would + // be far too slow). + if (mad_header_decode(&_frame.header, &_stream) == -1) { + if (_stream.error == MAD_ERROR_BUFLEN) { + break; // Read more data + } else if (MAD_RECOVERABLE(_stream.error)) { + debug(6, "MP3InputStream: Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream)); + continue; + } else { + warning("MP3InputStream: Unrecoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream)); + break; + } + } + + // Sum up the total playback time so far + mad_timer_add(&length, _frame.header.duration); + } + } while (_state != MP3_STATE_EOS); + + mad_synth_finish(&_synth); + mad_frame_finish(&_frame); + + // Reinit stream + _state = MP3_STATE_INIT; + + // Reset the stream data + _inStream->seek(0, SEEK_SET); + } + + _totalPlayTime = mad_timer_count(length, MAD_UNITS_MILLISECONDS); + + if (numLoops && mad_timer_sign(length) >= 0) + _totalPlayTime *= numLoops; + else + _totalPlayTime = kUnknownPlayTime; + // Decode the first chunk of data. This is necessary so that _frame // is setup and isStereo() and getRate() return correct results. decodeMP3Data(); diff --git a/sound/softsynth/mt32/mt32emu.h b/sound/softsynth/mt32/mt32emu.h index 0aa4df7488..6eedf04bc0 100644 --- a/sound/softsynth/mt32/mt32emu.h +++ b/sound/softsynth/mt32/mt32emu.h @@ -29,7 +29,7 @@ #define MT32EMU_MONITOR_PARTIALS 0 // Determines how the waveform cache file is handled (must be regenerated after sampling rate change) #define MT32EMU_WAVECACHEMODE 0 // Load existing cache if possible, otherwise generate and save cache -//#define MT32EMU_WAVECACHEMODE 1 // Load existing cache if possible, otherwise generage but don't save cache +//#define MT32EMU_WAVECACHEMODE 1 // Load existing cache if possible, otherwise generate but don't save cache //#define MT32EMU_WAVECACHEMODE 2 // Ignore existing cache, generate and save cache //#define MT32EMU_WAVECACHEMODE 3 // Ignore existing cache, generate but don't save cache diff --git a/sound/vorbis.cpp b/sound/vorbis.cpp index a4b0f854e9..64f67d2a13 100644 --- a/sound/vorbis.cpp +++ b/sound/vorbis.cpp @@ -92,6 +92,7 @@ protected: bool _isStereo; int _rate; uint _numLoops; + const uint _totalNumLoops; #ifdef USE_TREMOR ogg_int64_t _startTime; @@ -118,6 +119,17 @@ public: bool isStereo() const { return _isStereo; } int getRate() const { return _rate; } + int32 getTotalPlayTime() const { + if (!_totalNumLoops) + return AudioStream::kUnknownPlayTime; + +#ifdef USE_TREMOR + return (_endTime - _startTime) * _totalNumLoops; +#else + return (int32)((_endTime - _startTime) * 1000.0) * _totalNumLoops; +#endif + } + protected: void refill(); }; @@ -126,6 +138,7 @@ VorbisInputStream::VorbisInputStream(Common::SeekableReadStream *inStream, bool _inStream(inStream), _disposeAfterUse(dispose), _numLoops(numLoops), + _totalNumLoops(numLoops), _bufferEnd(_buffer + ARRAYSIZE(_buffer)) { bool err = (ov_open_callbacks(inStream, &_ovFile, NULL, 0, g_stream_wrap) < 0); |