[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