aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Horn2003-08-04 22:15:16 +0000
committerMax Horn2003-08-04 22:15:16 +0000
commitd280258e09fccc1ac3c72569a28e4cb69afef488 (patch)
treec46512447bceda823298e905bd20ed79ef9e4e45
parent679e818b0b401163b8e257be4b9b30a809e204e9 (diff)
downloadscummvm-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.cpp154
-rw-r--r--sound/audiostream.h93
-rw-r--r--sound/mixer.cpp22
-rw-r--r--sound/rate.cpp48
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;