Added looping support and an enhanced factory function to the Vorbis code

svn-id: r25789
This commit is contained in:
Max Horn 2007-02-22 14:30:12 +00:00
parent 1c02ed60d0
commit f16ab37698
3 changed files with 76 additions and 23 deletions

View File

@ -208,10 +208,11 @@ void MP3InputStream::decodeMP3Data() {
break;
}
if (_eos) {
// If looping is enabled, rewind to the start
if (_numLoops == 0 || --_numLoops > 0)
rewind();
if (_eos && _numLoops != 1) {
// If looping is on and there are loops left, rewind to the start
if (_numLoops != 0)
_numLoops--;
rewind();
}
} while (_stream.error == MAD_ERROR_BUFLEN);

View File

@ -86,17 +86,12 @@ static ov_callbacks g_stream_wrap = {
class VorbisInputStream : public AudioStream {
protected:
OggVorbis_File _ovFile;
Common::SeekableReadStream *_inStream;
bool _disposeAfterUse;
int16 _buffer[4096];
const int16 *_bufferEnd;
const int16 *_pos;
bool _isStereo;
int _rate;
uint _numLoops;
#ifdef USE_TREMOR
ogg_int64_t _startTime;
@ -106,25 +101,31 @@ protected:
double _endTime;
#endif
void refill();
inline bool eosIntern() const;
OggVorbis_File _ovFile;
int16 _buffer[4096];
const int16 *_bufferEnd;
const int16 *_pos;
public:
// startTime / duration are in milliseconds
VorbisInputStream(Common::SeekableReadStream *inStream, bool dispose, uint startTime = 0, uint endTime = 0);
VorbisInputStream(Common::SeekableReadStream *inStream, bool dispose, uint startTime = 0, uint endTime = 0, uint numLoops = 1);
~VorbisInputStream();
int readBuffer(int16 *buffer, const int numSamples);
bool endOfData() const { return eosIntern(); }
bool endOfData() const { return _pos >= _bufferEnd; }
bool isStereo() const { return _isStereo; }
int getRate() const { return _rate; }
protected:
void refill();
};
VorbisInputStream::VorbisInputStream(Common::SeekableReadStream *inStream, bool dispose, uint startTime, uint endTime) :
VorbisInputStream::VorbisInputStream(Common::SeekableReadStream *inStream, bool dispose, uint startTime, uint endTime, uint numLoops) :
_inStream(inStream),
_disposeAfterUse(dispose),
_numLoops(numLoops),
_bufferEnd(_buffer + ARRAYSIZE(_buffer)) {
bool err = (ov_open_callbacks(inStream, &_ovFile, NULL, 0, g_stream_wrap) < 0);
@ -176,13 +177,9 @@ VorbisInputStream::~VorbisInputStream() {
delete _inStream;
}
inline bool VorbisInputStream::eosIntern() const {
return _pos >= _bufferEnd;
}
int VorbisInputStream::readBuffer(int16 *buffer, const int numSamples) {
int samples = 0;
while (samples < numSamples && !eosIntern()) {
while (samples < numSamples && _pos < _bufferEnd) {
const int len = MIN(numSamples - samples, (int)(_bufferEnd - _pos));
memcpy(buffer, _pos, len * 2);
buffer += len;
@ -190,6 +187,17 @@ int VorbisInputStream::readBuffer(int16 *buffer, const int numSamples) {
samples += len;
if (_pos >= _bufferEnd) {
refill();
// 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) {
if (_numLoops != 1) {
// If looping is on and there are loops left, rewind to the start
if (_numLoops != 0)
_numLoops--;
ov_time_seek(&_ovFile, _startTime);
refill();
}
}
}
}
return samples;
@ -200,7 +208,16 @@ void VorbisInputStream::refill() {
uint len_left = sizeof(_buffer);
char *read_pos = (char *)_buffer;
while (len_left > 0 && ov_time_tell(&_ovFile) < _endTime) {
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--;
ov_time_seek(&_ovFile, _startTime);
}
long result;
#ifdef USE_TREMOR
// Tremor ov_read() always returns data as signed 16 bit interleaved PCM
@ -260,6 +277,19 @@ AudioStream *makeVorbisStream(File *file, uint32 size) {
return new VorbisInputStream(stream, true);
}
AudioStream *makeVorbisStream(
Common::SeekableReadStream *stream,
bool disposeAfterUse,
uint32 startTime,
uint32 duration,
uint numLoops) {
uint32 endTime = duration ? (startTime + duration) : 0;
return new VorbisInputStream(stream, disposeAfterUse, startTime, endTime, numLoops);
}
#pragma mark -
#pragma mark --- Ogg Vorbis Audio CD emulation ---

View File

@ -30,6 +30,7 @@
namespace Common {
class File;
class SeekableReadStream;
}
namespace Audio {
@ -40,13 +41,34 @@ class DigitalTrackInfo;
DigitalTrackInfo *getVorbisTrack(int track);
/**
* Create a new AudioStream from the Vorbis data in the given
* Create a new AudioStream from the Ogg Vorbis data in the given
* file. If you only want to play part of that file, then seek
* to the start position in file before passing it to this
* factory function, and specify the appropriate size.
*/
AudioStream *makeVorbisStream(Common::File *file, uint32 size);
/**
* Create a new AudioStream from the Ogg Vorbis data in the given stream.
* Allows for looping (which is why we require a SeekableReadStream),
* and specifying only a portion of the data to be played, based
* on time offsets.
*
* @param stream the SeekableReadStream from which to read the MP3 data
* @param disposeAfterUse whether to delete the stream after use
* @param startTime the (optional) time offset in milliseconds from which to start playback
* @param duration the (optional) time in milliseconds specifying how long to play
* @param numLoops how often the data shall be looped (0 = infinite)
* @return a new AudioStream, or NULL, if an error occured
*/
AudioStream *makeVorbisStream(
Common::SeekableReadStream *stream,
bool disposeAfterUse,
uint32 startTime = 0,
uint32 duration = 0,
uint numLoops = 1);
} // End of namespace Audio
#endif // #ifdef USE_VORBIS