aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorMax Horn2007-02-20 22:18:48 +0000
committerMax Horn2007-02-20 22:18:48 +0000
commit42745b188eb239b726ebfc086e6964247859890f (patch)
treea5fc03c9c8f275998984f8a0879f2436dba12103 /sound
parentacdb32d84d43ed18454cb8d681983fd7b0cda349 (diff)
downloadscummvm-rg350-42745b188eb239b726ebfc086e6964247859890f.tar.gz
scummvm-rg350-42745b188eb239b726ebfc086e6964247859890f.tar.bz2
scummvm-rg350-42745b188eb239b726ebfc086e6964247859890f.zip
Added looping to the MP3 streams (currently virtually untested, so watch out)
svn-id: r25756
Diffstat (limited to 'sound')
-rw-r--r--sound/mp3.cpp78
-rw-r--r--sound/mp3.h22
2 files changed, 84 insertions, 16 deletions
diff --git a/sound/mp3.cpp b/sound/mp3.cpp
index a245f5dc79..1ac43cdfd5 100644
--- a/sound/mp3.cpp
+++ b/sound/mp3.cpp
@@ -47,12 +47,11 @@ protected:
mad_frame _frame;
mad_synth _synth;
- mad_timer_t _startTime;
- mad_timer_t _endTime;
+ const mad_timer_t _startTime;
+ const mad_timer_t _endTime;
mad_timer_t _totalTime;
- // TODO: For looping, we will have to use a SeekableReadStream here
- Common::ReadStream *_inStream;
+ Common::SeekableReadStream *_inStream;
bool _disposeAfterUse;
enum {
@@ -62,17 +61,16 @@ protected:
// This buffer contains a slab of input data
byte _buf[BUFFER_SIZE + MAD_BUFFER_GUARD];
-
- uint32 _posInFrame;
- int _curChannel;
-
+ uint _numLoops;
+ uint _posInFrame;
bool _eos;
public:
- MP3InputStream(Common::ReadStream *inStream,
+ MP3InputStream(Common::SeekableReadStream *inStream,
bool dispose,
mad_timer_t start = mad_timer_zero,
- mad_timer_t end = mad_timer_zero);
+ mad_timer_t end = mad_timer_zero,
+ uint numLoops = 1);
~MP3InputStream();
bool init();
@@ -84,24 +82,24 @@ public:
int getRate() const { return _frame.header.samplerate; }
protected:
+ void rewind();
void decodeMP3Data();
bool readMP3Data();
};
-MP3InputStream::MP3InputStream(Common::ReadStream *inStream, bool dispose, mad_timer_t start, mad_timer_t end) :
+MP3InputStream::MP3InputStream(Common::SeekableReadStream *inStream, bool dispose, mad_timer_t start, mad_timer_t end, uint numLoops) :
_inStream(inStream),
_disposeAfterUse(dispose),
_startTime(start),
_endTime(end),
_totalTime(mad_timer_zero),
+ _numLoops(numLoops),
+ _posInFrame(0),
_eos(false) {
// 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);
- _posInFrame = 0;
- _curChannel = 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).
@@ -126,6 +124,24 @@ MP3InputStream::~MP3InputStream() {
delete _inStream;
}
+void MP3InputStream::rewind() {
+ // Start over again: reset the decoders, seek back to the start of the file, etc.
+
+ mad_synth_finish(&_synth);
+ mad_frame_finish(&_frame);
+ mad_stream_finish(&_stream);
+
+ _inStream->seek(0, SEEK_SET);
+ _totalTime = mad_timer_zero;
+ _posInFrame = 0;
+ _eos = false;
+
+ // Reinit MAD
+ mad_stream_init(&_stream);
+ mad_frame_init(&_frame);
+ mad_synth_init(&_synth);
+}
+
void MP3InputStream::decodeMP3Data() {
if (_eos)
return;
@@ -141,7 +157,7 @@ void MP3InputStream::decodeMP3Data() {
}
}
- while (true) {
+ while (!_eos) {
_stream.error = MAD_ERROR_NONE;
// Decode the next header. Note: mad_frame_decode would do this for us, too.
@@ -191,6 +207,12 @@ void MP3InputStream::decodeMP3Data() {
_posInFrame = 0;
break;
}
+
+ if (_eos) {
+ // If looping is enabled, try again
+ if (_numLoops == 0 || --_numLoops > 0)
+ rewind();
+ }
} while (_stream.error == MAD_ERROR_BUFLEN);
@@ -244,7 +266,6 @@ static inline int scale_sample(mad_fixed_t sample) {
int MP3InputStream::readBuffer(int16 *buffer, const int numSamples) {
int samples = 0;
- assert(_curChannel == 0); // Paranoia check
// Keep going as long as we have input available
while (samples < numSamples && !_eos) {
const int len = MIN(numSamples, samples + (int)(_synth.pcm.length - _posInFrame) * MAD_NCHANNELS(&_frame.header));
@@ -283,6 +304,31 @@ AudioStream *makeMP3Stream(Common::File *file, uint32 size) {
return new MP3InputStream(stream, true);
}
+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);
+ }
+
+ MP3InputStream *mp3Stream = new MP3InputStream(stream, disposeAfterUse, start, end, numLoops);
+
+ return mp3Stream;
+}
+
#pragma mark -
#pragma mark --- MP3 Audio CD emulation ---
diff --git a/sound/mp3.h b/sound/mp3.h
index 4f31337fcf..354e880404 100644
--- a/sound/mp3.h
+++ b/sound/mp3.h
@@ -30,6 +30,7 @@
namespace Common {
class File;
+ class SeekableReadStream;
}
namespace Audio {
@@ -47,6 +48,27 @@ DigitalTrackInfo *getMP3Track(int track);
*/
AudioStream *makeMP3Stream(Common::File *file, uint32 size);
+
+/**
+ * Create a new AudioStream from the MP3 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 *makeMP3Stream(
+ Common::SeekableReadStream *stream,
+ bool disposeAfterUse,
+ uint32 startTime = 0,
+ uint32 duration = 0,
+ uint numLoops = 1);
+
} // End of namespace Audio
#endif // #ifdef USE_MAD