[Scummvm-cvs-logs] SF.net SVN: scummvm:[47109] scummvm/trunk/sound

lordhoto at users.sourceforge.net lordhoto at users.sourceforge.net
Thu Jan 7 15:20:36 CET 2010


Revision: 47109
          http://scummvm.svn.sourceforge.net/scummvm/?rev=47109&view=rev
Author:   lordhoto
Date:     2010-01-07 14:20:36 +0000 (Thu, 07 Jan 2010)

Log Message:
-----------
First step of a slight revision of the new AudioStream looping API:
- Create a RewinadableAudioStream, for streams which can only be reset to the start
- Create a LoopableAudioStream, which loops a whole RewindableAudioStream
- Make SeekableAudioStream a subclass of RewindableAudioStream
- Create a SubSeekableAudioStream, which allows of limiting the range of an SeekableAudioStream to be played.

- Adapt AudioCD code.

Modified Paths:
--------------
    scummvm/trunk/sound/audiocd.cpp
    scummvm/trunk/sound/audiostream.cpp
    scummvm/trunk/sound/audiostream.h

Modified: scummvm/trunk/sound/audiocd.cpp
===================================================================
--- scummvm/trunk/sound/audiocd.cpp	2010-01-07 13:56:56 UTC (rev 47108)
+++ scummvm/trunk/sound/audiocd.cpp	2010-01-07 14:20:36 UTC (rev 47109)
@@ -62,23 +62,28 @@
 		sprintf(trackName[1], "track%02d", track);
 		Audio::SeekableAudioStream *stream = 0;
 
-		for (int i = 0; !stream && i < 2; ++i) {
+		for (int i = 0; !stream && i < 2; ++i)
+			stream = SeekableAudioStream::openStreamFile(trackName[i]);
+
+		// Stop any currently playing emulated track
+		_mixer->stopHandle(_handle);
+
+		if (stream != 0) {
+			if (startFrame != 0 || duration != 0) {
+				stream = new SubSeekableAudioStream(stream, Timestamp(0, startFrame, 75), Timestamp(0, startFrame + duration, 75));
+				assert(stream);
+			}
+
 			/*
 			FIXME: Seems numLoops == 0 and numLoops == 1 both indicate a single repetition,
 			while all other positive numbers indicate precisely the number of desired
 			repetitions. Finally, -1 means infinitely many
 			*/
-			// We multiply by 40 / 3 = 1000 / 75 to convert frames to milliseconds
-			stream = SeekableAudioStream::openStreamFile(trackName[i]);
-		}
+			AudioStream *output = new LoopingAudioStream(stream, (numLoops < 1) ? numLoops + 1 : numLoops);
+			assert(output);
 
-		// Stop any currently playing emulated track
-		_mixer->stopHandle(_handle);
-
-		if (stream != 0) {
 			_emulating = true;
-			_mixer->playInputStreamLooping(Audio::Mixer::kMusicSoundType, &_handle, stream, (numLoops < 1) ? numLoops + 1 : numLoops,
-			                               Timestamp(startFrame * 40 / 3, 1000), Timestamp(startFrame * 40 / 3 + duration * 40 / 3, 1000));
+			_mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_handle, output);
 		} else {
 			_emulating = false;
 			if (!only_emulate)

Modified: scummvm/trunk/sound/audiostream.cpp
===================================================================
--- scummvm/trunk/sound/audiostream.cpp	2010-01-07 13:56:56 UTC (rev 47108)
+++ scummvm/trunk/sound/audiostream.cpp	2010-01-07 14:20:36 UTC (rev 47109)
@@ -99,6 +99,80 @@
 }
 
 #pragma mark -
+#pragma mark --- LoopingAudioStream ---
+#pragma mark -
+
+LoopingAudioStream::LoopingAudioStream(RewindableAudioStream *stream, uint loops, bool disposeAfterUse)
+    : _parent(stream), _disposeAfterUse(disposeAfterUse), _loops(loops), _completeIterations(0) {
+}
+
+LoopingAudioStream::~LoopingAudioStream() {
+	if (_disposeAfterUse)
+		delete _parent;
+}
+
+int LoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) {
+	int samplesRead = _parent->readBuffer(buffer, numSamples);
+
+	if (_parent->endOfStream()) {
+		++_completeIterations;
+		if (_completeIterations == _loops)
+			return samplesRead;
+
+		int remainingSamples = numSamples - samplesRead;
+
+		if (!_parent->rewind()) {
+			// TODO: Properly indicate error
+			_loops = _completeIterations = 1;
+			return samplesRead;
+		}
+
+		samplesRead += _parent->readBuffer(buffer, remainingSamples);
+	}
+
+	return samplesRead;
+}
+
+bool LoopingAudioStream::endOfData() const {
+	return (_loops != 0 && (_completeIterations == _loops));
+}
+
+#pragma mark -
+#pragma mark --- SubSeekableAudioStream ---
+#pragma mark -
+
+SubSeekableAudioStream::SubSeekableAudioStream(SeekableAudioStream *parent, const Timestamp start, const Timestamp end, bool disposeAfterUse)
+    : _parent(parent), _disposeAfterUse(disposeAfterUse), _isStereo(parent->isStereo()),
+      _start(start.convertToFramerate(getRate())), _pos(0, getRate()), _length(end.convertToFramerate(getRate())) {
+	// TODO: This really looks like Timestamp::operator-
+	_length = Timestamp(_length.secs() - _start.secs(), _length.numberOfFrames() - _start.numberOfFrames(), getRate());
+	_parent->seek(_start);
+}
+
+SubSeekableAudioStream::~SubSeekableAudioStream() {
+	if (_disposeAfterUse)
+		delete _parent;
+}
+
+int SubSeekableAudioStream::readBuffer(int16 *buffer, const int numSamples) {
+	int framesLeft = MIN(_length.frameDiff(_pos) * (_isStereo ? 2 : 1), numSamples);
+	int framesRead = _parent->readBuffer(buffer, framesLeft);
+	_pos = _pos.addFrames(framesRead / (_isStereo ? 2 : 1));
+	return framesRead;
+}
+
+bool SubSeekableAudioStream::seek(const Timestamp &where) {
+	_pos = where.convertToFramerate(getRate());
+	// TODO: This really looks like Timestamp::operator+
+	if (_parent->seek(Timestamp(_pos.secs() + _start.secs(), _pos.numberOfFrames() + _start.numberOfFrames(), getRate()))) {
+		return true;
+	} else {
+		_pos = _length;
+		return false;
+	}
+}
+
+#pragma mark -
 #pragma mark --- LinearMemoryStream ---
 #pragma mark -
 

Modified: scummvm/trunk/sound/audiostream.h
===================================================================
--- scummvm/trunk/sound/audiostream.h	2010-01-07 13:56:56 UTC (rev 47108)
+++ scummvm/trunk/sound/audiostream.h	2010-01-07 14:20:36 UTC (rev 47109)
@@ -102,11 +102,61 @@
 };
 
 /**
+ * A rewindable audio stream. This allows for restting the AudioStream
+ * to its initial state. Note that rewinding itself is not required to
+ * be working when the stream is being played by Mixer!
+ */
+class RewindableAudioStream : public AudioStream {
+public:
+	/**
+	 * Rewinds the stream to its start.
+	 *
+	 * @return true on success, false otherwise.
+	 */
+	virtual bool rewind() = 0;
+};
+
+/**
+ * A looping audio stream. This object does nothing beides using
+ * a RewindableAudioStream to play a stream in a loop.
+ */
+class LoopingAudioStream : public AudioStream {
+public:
+	/**
+	 * Creates a looping audio stream object.
+	 *
+	 * @param stream Stream to loop
+	 * @param loops How often to loop (0 = infinite)
+	 * @param disposeAfteruse Destroy the stream after the LoopingAudioStream has finished playback.
+	 */
+	LoopingAudioStream(RewindableAudioStream *stream, uint loops, bool disposeAfterUse = true);
+	~LoopingAudioStream();
+
+	int readBuffer(int16 *buffer, const int numSamples);
+	bool endOfData() const;
+
+	bool isStereo() const { return _parent->isStereo(); }
+	int getRate() const { return _parent->getRate(); }
+
+	/** 
+	 * Returns number of loops the stream has played.
+	 * @param numLoops number of loops to play, 0 - infinite
+	 */
+	uint getCompleteIterations() const { return _completeIterations; }
+private:
+	RewindableAudioStream *_parent;
+	bool _disposeAfterUse;
+
+	uint _loops;
+	uint _completeIterations;
+};
+
+/**
  * A seekable audio stream. Subclasses of this class implement a
  * working seeking. The seeking itself is not required to be
  * working when the stream is being played by Mixer!
  */
-class SeekableAudioStream : public AudioStream {
+class SeekableAudioStream : public RewindableAudioStream {
 public:
 	/**
 	 * Tries to load a file by trying all available formats.
@@ -142,9 +192,50 @@
 	 * @return length as Timestamp.
 	 */
 	virtual Timestamp getLength() const = 0;
+
+	virtual bool rewind() { return seek(0); }
 };
 
+/**
+ * A SubSeekableAudioStream provides access to a SeekableAudioStream
+ * just in the range [start, end).
+ * The same caveats apply to SubSeekableAudioStream as do to SeekableAudioStream.
+ * 
+ * Manipulating the parent stream directly /will/ mess up a substream.
+ */
+class SubSeekableAudioStream : public SeekableAudioStream {
+public:
+	/**
+	 * Creates a new SubSeekableAudioStream.
+	 *
+	 * @param parent parent stream object.
+	 * @param start Start time.
+	 * @param end End time.
+	 * @param disposeAfterUse Whether the parent stream object should be destroied on desctruction of the SubSeekableAudioStream.
+	 */
+	SubSeekableAudioStream(SeekableAudioStream *parent, const Timestamp start, const Timestamp end, bool disposeAfterUse = true);
+	~SubSeekableAudioStream();
 
+	int readBuffer(int16 *buffer, const int numSamples);
+
+	bool isStereo() const { return _isStereo; }
+
+	int getRate() const { return _parent->getRate(); }
+
+	bool endOfData() const { return (_pos >= _length) || _parent->endOfStream(); }
+
+	bool seek(const Timestamp &where);
+
+	Timestamp getLength() const { return _length; }
+private:
+	SeekableAudioStream *_parent;
+	bool _disposeAfterUse;
+	const bool _isStereo;
+
+	const Timestamp _start;
+	Timestamp _pos, _length;
+};
+
 /**
  * Factory function for a raw linear AudioStream, which will simply treat all
  * data in the buffer described by ptr and len as raw sample data in the


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