[Scummvm-cvs-logs] SF.net SVN: scummvm: [25756] scummvm/trunk/sound
fingolfin at users.sourceforge.net
fingolfin at users.sourceforge.net
Tue Feb 20 23:18:49 CET 2007
Revision: 25756
http://scummvm.svn.sourceforge.net/scummvm/?rev=25756&view=rev
Author: fingolfin
Date: 2007-02-20 14:18:48 -0800 (Tue, 20 Feb 2007)
Log Message:
-----------
Added looping to the MP3 streams (currently virtually untested, so watch out)
Modified Paths:
--------------
scummvm/trunk/sound/mp3.cpp
scummvm/trunk/sound/mp3.h
Modified: scummvm/trunk/sound/mp3.cpp
===================================================================
--- scummvm/trunk/sound/mp3.cpp 2007-02-20 21:53:22 UTC (rev 25755)
+++ scummvm/trunk/sound/mp3.cpp 2007-02-20 22:18:48 UTC (rev 25756)
@@ -47,12 +47,11 @@
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 @@
// 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 @@
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 @@
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 @@
}
}
- 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 @@
_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 @@
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,7 +304,32 @@
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 ---
#pragma mark -
Modified: scummvm/trunk/sound/mp3.h
===================================================================
--- scummvm/trunk/sound/mp3.h 2007-02-20 21:53:22 UTC (rev 25755)
+++ scummvm/trunk/sound/mp3.h 2007-02-20 22:18:48 UTC (rev 25756)
@@ -30,6 +30,7 @@
namespace Common {
class File;
+ class SeekableReadStream;
}
namespace Audio {
@@ -47,6 +48,27 @@
*/
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
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
More information about the Scummvm-git-logs
mailing list