diff options
author | Max Horn | 2003-08-04 22:15:16 +0000 |
---|---|---|
committer | Max Horn | 2003-08-04 22:15:16 +0000 |
commit | d280258e09fccc1ac3c72569a28e4cb69afef488 (patch) | |
tree | c46512447bceda823298e905bd20ed79ef9e4e45 | |
parent | 679e818b0b401163b8e257be4b9b30a809e204e9 (diff) | |
download | scummvm-rg350-d280258e09fccc1ac3c72569a28e4cb69afef488.tar.gz scummvm-rg350-d280258e09fccc1ac3c72569a28e4cb69afef488.tar.bz2 scummvm-rg350-d280258e09fccc1ac3c72569a28e4cb69afef488.zip |
renamed eof -> eos (end of stream); hid MP3/Vorbis stream classes completly (by providing factory methods); new readBuffer method for AudioInputStream for improved speed of the mixer; new MusicStream class (subclassed for MP3/Vorbis sound) which offers a getRate method; some other tweaks
svn-id: r9467
-rw-r--r-- | sound/audiostream.cpp | 154 | ||||
-rw-r--r-- | sound/audiostream.h | 93 | ||||
-rw-r--r-- | sound/mixer.cpp | 22 | ||||
-rw-r--r-- | sound/rate.cpp | 48 |
4 files changed, 214 insertions, 103 deletions
diff --git a/sound/audiostream.cpp b/sound/audiostream.cpp index dd2bbaf781..e636e96cb2 100644 --- a/sound/audiostream.cpp +++ b/sound/audiostream.cpp @@ -47,17 +47,7 @@ protected: const byte *_loopPtr; const byte *_loopEnd; -public: - LinearMemoryStream(const byte *ptr, uint len, uint loopOffset, uint loopLen) - : _ptr(ptr), _end(ptr+len), _loopPtr(0), _loopEnd(0) { - if (loopLen) { - _loopPtr = _ptr + loopOffset; - _loopEnd = _loopPtr + loopLen; - } - if (stereo) // Stereo requires even sized data - assert(len % 2 == 0); - } - int16 read() { + inline int16 readIntern() { //assert(_ptr < _end); int16 val = readSample<is16Bit, isUnsigned>(_ptr); _ptr += (is16Bit ? 2 : 1); @@ -67,12 +57,36 @@ public: } return val; } - bool eof() const { - return _ptr >= _end; + inline bool eosIntern() const { return _ptr >= _end; }; +public: + LinearMemoryStream(const byte *ptr, uint len, uint loopOffset, uint loopLen) + : _ptr(ptr), _end(ptr+len), _loopPtr(0), _loopEnd(0) { + if (loopLen) { + _loopPtr = _ptr + loopOffset; + _loopEnd = _loopPtr + loopLen; + } + if (stereo) // Stereo requires even sized data + assert(len % 2 == 0); } - bool isStereo() const { - return stereo; + int readBuffer(int16 *buffer, int numSamples) { + int samples = 0; + do { + const int len = MIN(numSamples, (_end - _ptr) / (is16Bit ? 2 : 1)); + for (; samples < len; samples++) { + *buffer++ = readSample<is16Bit, isUnsigned>(_ptr); + _ptr += (is16Bit ? 2 : 1); + } + if (_loopPtr && _ptr == _end) { + _ptr = _loopPtr; + _end = _loopEnd; + } + } while (samples < numSamples && !eosIntern()); + return samples; } + + int16 read() { return readIntern(); } + bool eos() const { return eosIntern(); } + bool isStereo() const { return stereo; } }; @@ -90,14 +104,16 @@ protected: byte *_pos; byte *_end; + inline int16 readIntern(); + inline bool eosIntern() const { return _end == _pos; }; public: WrappedMemoryStream(uint bufferSize); - ~WrappedMemoryStream() { free(_bufferStart); } - int16 read(); - bool eof() const; - bool isStereo() const { - return stereo; - } + ~WrappedMemoryStream() { free(_bufferStart); } + int readBuffer(int16 *buffer, int numSamples); + + int16 read() { return readIntern(); } + bool eos() const { return eosIntern(); } + bool isStereo() const { return stereo; } void append(const byte *data, uint32 len); }; @@ -113,7 +129,7 @@ WrappedMemoryStream<stereo, is16Bit, isUnsigned>::WrappedMemoryStream(uint buffe } template<bool stereo, bool is16Bit, bool isUnsigned> -int16 WrappedMemoryStream<stereo, is16Bit, isUnsigned>::read() { +inline int16 WrappedMemoryStream<stereo, is16Bit, isUnsigned>::readIntern() { //assert(_pos != _end); int16 val = readSample<is16Bit, isUnsigned>(_pos); _pos += (is16Bit ? 2 : 1); @@ -126,8 +142,12 @@ int16 WrappedMemoryStream<stereo, is16Bit, isUnsigned>::read() { } template<bool stereo, bool is16Bit, bool isUnsigned> -bool WrappedMemoryStream<stereo, is16Bit, isUnsigned>::eof() const { - return _end == _pos; +int WrappedMemoryStream<stereo, is16Bit, isUnsigned>::readBuffer(int16 *buffer, int numSamples) { + int samples; + for (samples = 0; samples < numSamples && !eosIntern(); samples++) { + *buffer++ = readIntern(); + } + return samples; } template<bool stereo, bool is16Bit, bool isUnsigned> @@ -160,6 +180,37 @@ void WrappedMemoryStream<stereo, is16Bit, isUnsigned>::append(const byte *data, #ifdef USE_MAD +class MP3InputStream : public MusicStream { + struct mad_stream _stream; + struct mad_frame _frame; + struct mad_synth _synth; + mad_timer_t _duration; + uint32 _posInFrame; + uint32 _bufferSize; + int _size; + bool _isStereo; + int _curChannel; + File *_file; + byte *_ptr; + int _rate; + bool _initialized; + + bool init(); + void refill(); + inline int16 readIntern(); + inline bool eosIntern() const; +public: + MP3InputStream(File *file, mad_timer_t duration, uint size = 0); + ~MP3InputStream(); + int readBuffer(int16 *buffer, int numSamples); + + int16 read() { return readIntern(); } + bool eos() const { return eosIntern(); } + bool isStereo() const { return _isStereo; } + + int getRate() const { return _rate; } +}; + /** * Playback the MP3 data in the given file for the specified duration. @@ -299,7 +350,7 @@ void MP3InputStream::refill() { _posInFrame = 0; } -bool MP3InputStream::eof() const { +inline bool MP3InputStream::eosIntern() const { return (_size < 0 || _posInFrame >= _synth.pcm.length); } @@ -317,7 +368,7 @@ static inline int scale_sample(mad_fixed_t sample) { return sample >> (MAD_F_FRACBITS + 1 - 16); } -int16 MP3InputStream::read() { +inline int16 MP3InputStream::readIntern() { if (_size < 0 || _posInFrame >= _synth.pcm.length) { // EOF return 0; } @@ -343,6 +394,18 @@ int16 MP3InputStream::read() { return sample; } +int MP3InputStream::readBuffer(int16 *buffer, int numSamples) { + int samples; + for (samples = 0; samples < numSamples && !eosIntern(); samples++) { + *buffer++ = readIntern(); + } + return samples; +} + +MusicStream *makeMP3Stream(File *file, mad_timer_t duration, uint size) { + return new MP3InputStream(file, duration, size); +} + #endif @@ -353,6 +416,29 @@ int16 MP3InputStream::read() { #ifdef USE_VORBIS +class VorbisInputStream : public MusicStream { + OggVorbis_File *_ov_file; + int _end_pos; + bool _eofFlag; + int _numChannels; + int16 _buffer[4096]; + int16 *_pos; + + void refill(); + inline int16 readIntern(); + inline bool eosIntern() const; +public: + VorbisInputStream(OggVorbis_File *file, int duration); + int readBuffer(int16 *buffer, int numSamples); + + int16 read() { return readIntern(); } + bool eos() const { return eosIntern(); } + bool isStereo() const { return _numChannels >= 2; } + + int getRate() const { return ov_info(_ov_file, -1)->rate; } +}; + + #ifdef CHUNKSIZE #define VORBIS_TREMOR #endif @@ -371,14 +457,14 @@ VorbisInputStream::VorbisInputStream(OggVorbis_File *file, int duration) _eofFlag = false; } -int16 VorbisInputStream::read() { +inline int16 VorbisInputStream::readIntern() { if (_pos >= _buffer + ARRAYSIZE(_buffer)) { refill(); } return *_pos++; } -bool VorbisInputStream::eof() const { +inline bool VorbisInputStream::eosIntern() const { if (_eofFlag) return true; if (_pos < _buffer + ARRAYSIZE(_buffer)) @@ -386,6 +472,14 @@ bool VorbisInputStream::eof() const { return (_end_pos <= ov_pcm_tell(_ov_file)); } +int VorbisInputStream::readBuffer(int16 *buffer, int numSamples) { + int samples; + for (samples = 0; samples < numSamples && !eosIntern(); samples++) { + *buffer++ = readIntern(); + } + return samples; +} + void VorbisInputStream::refill() { // Read the samples uint len_left = sizeof(_buffer); @@ -426,6 +520,10 @@ void VorbisInputStream::refill() { _pos = _buffer; } +MusicStream *makeVorbisStream(OggVorbis_File *file, int duration) { + return new VorbisInputStream(file, duration); +} + #endif diff --git a/sound/audiostream.h b/sound/audiostream.h index 50738ba550..a68fbc5526 100644 --- a/sound/audiostream.h +++ b/sound/audiostream.h @@ -24,6 +24,7 @@ #include "stdafx.h" #include "common/scummsys.h" +#include "common/util.h" #ifdef USE_MAD #include <mad.h> #endif @@ -47,10 +48,34 @@ class AudioInputStream { public: virtual ~AudioInputStream() {} + /** + * Fill the given buffer with up to numSamples samples. + * Returns the actual number of samples read, or -1 if + * a critical error occured (note: you *must* check if + * this value is less than what you requested, this can + * happend when the stream is fully used up). + * For stereo stream, buffer will be filled with interleaved + * left and right channel samples. + * + * For maximum efficency, subclasses should always override + * the default implementation! + */ + virtual int readBuffer(int16 *buffer, int numSamples) { + int samples; + for (samples = 0; samples < numSamples && !eos(); samples++) { + *buffer++ = read(); + } + return samples; + } + + /** Read a singel (16 bit signed) sample from the stream. */ virtual int16 read() = 0; - //virtual int size() const = 0; + + /** Is this a stereo stream? */ virtual bool isStereo() const = 0; - virtual bool eof() const = 0; + + /* End of stream reached? */ + virtual bool eos() const = 0; virtual int getRate() const { return -1; } }; @@ -65,64 +90,34 @@ protected: int _len; public: ZeroInputStream(uint len) : _len(len) { } + int readBuffer(int16 *buffer, int numSamples) { + int samples = MIN(_len, numSamples); + memset(buffer, 0, samples * 2); + _len -= samples; + return samples; + } int16 read() { assert(_len > 0); _len--; return 0; } int size() const { return _len; } bool isStereo() const { return false; } - bool eof() const { return _len <= 0; } + bool eos() const { return _len <= 0; } }; -#ifdef USE_MAD -class MP3InputStream : public AudioInputStream { - struct mad_stream _stream; - struct mad_frame _frame; - struct mad_synth _synth; - mad_timer_t _duration; - uint32 _posInFrame; - uint32 _bufferSize; - int _size; - bool _isStereo; - int _curChannel; - File *_file; - byte *_ptr; - int _rate; - bool _initialized; - - bool init(); - void refill(); +class MusicStream : public AudioInputStream { public: - MP3InputStream(File *file, mad_timer_t duration, uint size = 0); - ~MP3InputStream(); - int16 read(); - bool eof() const; - bool isStereo() const { return _isStereo; } - - int getRate() const { return _rate; } + virtual int getRate() const = 0; }; -#endif - - -#ifdef USE_VORBIS -class VorbisInputStream : public AudioInputStream { - OggVorbis_File *_ov_file; - int _end_pos; - bool _eofFlag; - int _numChannels; - int16 _buffer[4096]; - int16 *_pos; - - void refill(); -public: - VorbisInputStream(OggVorbis_File *file, int duration); - int16 read(); - bool eof() const; - bool isStereo() const { return _numChannels >= 2; } -}; -#endif - AudioInputStream *makeLinearInputStream(byte _flags, const byte *ptr, uint32 len, uint loopOffset, uint loopLen); WrappedAudioInputStream *makeWrappedInputStream(byte _flags, uint32 len); +#ifdef USE_MAD +MusicStream *makeMP3Stream(File *file, mad_timer_t duration, uint size = 0); +#endif + +#ifdef USE_VORBIS +MusicStream *makeVorbisStream(OggVorbis_File *file, int duration); +#endif + #endif diff --git a/sound/mixer.cpp b/sound/mixer.cpp index dbc87f01f7..8ca9d360d8 100644 --- a/sound/mixer.cpp +++ b/sound/mixer.cpp @@ -709,7 +709,7 @@ void ChannelRaw::mix(int16 *data, uint len) { assert(_input); assert(_converter); - if (_input->eof()) { + if (_input->eos()) { // TODO: call drain method destroy(); return; @@ -820,7 +820,7 @@ void ChannelStream::mix(int16 *data, uint len) { assert(_input); assert(_converter); - if (_input->eof()) { + if (_input->eos()) { // TODO: call drain method // Normally, the stream stays around even if all its data is used up. @@ -929,7 +929,7 @@ static inline int scale_sample(mad_fixed_t sample) { ChannelMP3::ChannelMP3(SoundMixer *mixer, PlayingSoundHandle *handle, File *file, uint size) : Channel(mixer, handle) { // Create the input stream - _input = new MP3InputStream(file, mad_timer_zero, size); + _input = makeMP3Stream(file, mad_timer_zero, size); // Get a rate converter instance //printf("ChannelMP3: inrate %d, outrate %d, stereo %d\n", _input->getRate(), mixer->getOutputRate(), _input->isStereo()); @@ -951,7 +951,7 @@ void ChannelMP3::mix(int16 *data, uint len) { assert(_input); assert(_converter); - if (_input->eof()) { + if (_input->eos()) { // TODO: call drain method destroy(); return; @@ -1013,7 +1013,7 @@ void ChannelMP3::mix(int16 *data, uint len) { ChannelMP3CDMusic::ChannelMP3CDMusic(SoundMixer *mixer, PlayingSoundHandle *handle, File *file, mad_timer_t duration) : Channel(mixer, handle) { // Create the input stream - _input = new MP3InputStream(file, duration, 0); + _input = makeMP3Stream(file, duration, 0); // Get a rate converter instance //printf("ChannelMP3CDMusic: inrate %d, outrate %d, stereo %d\n", _input->getRate(), mixer->getOutputRate(), _input->isStereo()); @@ -1034,7 +1034,7 @@ void ChannelMP3CDMusic::mix(int16 *data, uint len) { assert(_input); assert(_converter); - if (_input->eof()) { + if (_input->eos()) { // TODO: call drain method destroy(); return; @@ -1158,15 +1158,11 @@ void ChannelMP3CDMusic::mix(int16 *data, uint len) { ChannelVorbis::ChannelVorbis(SoundMixer *mixer, PlayingSoundHandle *handle, OggVorbis_File *ov_file, int duration, bool is_cd_track) : Channel(mixer, handle) { #ifdef SOX_HACK - vorbis_info *vi; - // Create the input stream - _input = new VorbisInputStream(ov_file, duration); + _input = makeVorbisStream(ov_file, duration); // Get a rate converter instance - vi = ov_info(ov_file, -1); - assert(vi->channels == 1 || vi->channels == 2); - _converter = makeRateConverter(vi->rate, mixer->getOutputRate(), _input->isStereo()); + _converter = makeRateConverter(_input->getRate(), mixer->getOutputRate(), _input->isStereo()); #else _ov_file = ov_file; @@ -1187,7 +1183,7 @@ void ChannelVorbis::mix(int16 *data, uint len) { assert(_input); assert(_converter); - if (_input->eof()) { + if (_input->eos()) { // TODO: call drain method destroy(); return; diff --git a/sound/rate.cpp b/sound/rate.cpp index 89a6f4a15e..955c0bbf47 100644 --- a/sound/rate.cpp +++ b/sound/rate.cpp @@ -30,9 +30,20 @@ #include "stdafx.h" #include "sound/rate.h" - +/** + * The precision of the fractional computations used by the rate converter. + * Normally you should never have to modify this value. + */ #define FRAC_BITS 16 +/** + * The size of the intermediate input cache. Bigger values may increase + * performance, but only until some point (depends largely on cache size, + * target processor and various other factors), at which it will decrease + * again. + */ +#define INTERMEDIATE_BUFFER_SIZE 512 + /** * Audio rate converter based on simple linear Interpolation. @@ -48,7 +59,9 @@ template<bool stereo, bool reverseStereo> class LinearRateConverter : public RateConverter { protected: - bool _reverseStereo; + st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE]; + const st_sample_t *inPtr; + int inLen; /** fractional position of the output stream in input stream unit */ unsigned long opos, opos_frac; @@ -101,6 +114,8 @@ LinearRateConverter<stereo, reverseStereo>::LinearRateConverter(st_rate_t inrate ilast[0] = ilast[1] = 0; icur[0] = icur[1] = 0; + + inLen = 0; } /* @@ -112,6 +127,9 @@ int LinearRateConverter<stereo, reverseStereo>::flow(AudioInputStream &input, st { st_sample_t *ostart, *oend; st_sample_t out[2], tmpOut; + + const int numChannels = stereo ? 2 : 1; + int i; ostart = obuf; oend = obuf + osamp * 2; @@ -120,16 +138,17 @@ int LinearRateConverter<stereo, reverseStereo>::flow(AudioInputStream &input, st // read enough input samples so that ipos > opos while (ipos <= opos) { - - // Abort if we reached the end of the input buffer - if (input.eof()) - goto the_end; - - ilast[0] = icur[0]; - icur[0] = input.read(); - if (stereo) { - ilast[1] = icur[1]; - icur[1] = input.read(); + // Check if we have to refill the buffer + if (inLen == 0) { + inPtr = inBuf; + inLen = input.readBuffer(inBuf, ARRAYSIZE(inBuf)); + if (inLen <= 0) + goto the_end; + } + for (i = 0; i < numChannels; i++) { + ilast[i] = icur[i]; + icur[i] = *inPtr++; + inLen--; } ipos++; } @@ -185,7 +204,10 @@ public: int16 tmp[2]; st_size_t len = osamp; assert(input.isStereo() == stereo); - while (!input.eof() && len--) { + +// TODO: use readBuffer + + while (!input.eos() && len--) { tmp[0] = tmp[1] = (input.read() * vol) >> 8; if (stereo) tmp[reverseStereo ? 0 : 1] = (input.read() * vol) >> 8; |