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

lordhoto at users.sourceforge.net lordhoto at users.sourceforge.net
Tue Jan 5 22:10:34 CET 2010


Revision: 47045
          http://scummvm.svn.sourceforge.net/scummvm/?rev=47045&view=rev
Author:   lordhoto
Date:     2010-01-05 21:10:34 +0000 (Tue, 05 Jan 2010)

Log Message:
-----------
- Initial implementation of looping of SeekableAudioStreams in Mixer.
- Adapted AudioCD code to use this for audio CD emulation.

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

Modified: scummvm/trunk/sound/audiocd.cpp
===================================================================
--- scummvm/trunk/sound/audiocd.cpp	2010-01-05 21:05:32 UTC (rev 47044)
+++ scummvm/trunk/sound/audiocd.cpp	2010-01-05 21:10:34 UTC (rev 47045)
@@ -60,7 +60,7 @@
 		char trackName[2][16];
 		sprintf(trackName[0], "track%d", track);
 		sprintf(trackName[1], "track%02d", track);
-		Audio::AudioStream *stream = 0;
+		Audio::SeekableAudioStream *stream = 0;
 
 		for (int i = 0; !stream && i < 2; ++i) {
 			/*
@@ -69,7 +69,7 @@
 			repetitions. Finally, -1 means infinitely many
 			*/
 			// We multiply by 40 / 3 = 1000 / 75 to convert frames to milliseconds
-			stream = AudioStream::openStreamFile(trackName[i], startFrame * 40 / 3, duration * 40 / 3, (numLoops < 1) ? numLoops + 1 : numLoops);
+			stream = AudioStream::openStreamFile(trackName[i]);
 		}
 
 		// Stop any currently playing emulated track
@@ -77,7 +77,8 @@
 
 		if (stream != 0) {
 			_emulating = true;
-			_mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_handle, stream);
+			_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));
 		} else {
 			_emulating = false;
 			if (!only_emulate)

Modified: scummvm/trunk/sound/mixer.cpp
===================================================================
--- scummvm/trunk/sound/mixer.cpp	2010-01-05 21:05:32 UTC (rev 47044)
+++ scummvm/trunk/sound/mixer.cpp	2010-01-05 21:10:34 UTC (rev 47045)
@@ -170,7 +170,7 @@
 	AudioStream *_input;
 
 public:
-	SimpleChannel(Mixer *mixer, Mixer::SoundType type, AudioStream *input, bool autofreeStream, bool reverseStereo = false, int id = -1, bool permanent = false);
+	SimpleChannel(Mixer *mixer, Mixer::SoundType type, AudioStream *input, bool autofreeStream, bool reverseStereo, int id, bool permanent);
 	~SimpleChannel();
 
 	void mix(int16 *data, uint len);
@@ -180,7 +180,24 @@
 	}
 };
 
+class LoopingChannel : public Channel {
+public:
+	LoopingChannel(Mixer *mixer, Mixer::SoundType type, SeekableAudioStream *input, uint loopCount, Timestamp loopStart, Timestamp loopEnd, bool autofreeStream, bool reverseStereo, int id, bool permanent);
+	~LoopingChannel();
 
+	void mix(int16 *data, uint len);
+	bool isFinished() const;
+private:
+	uint _loopCount;
+	Timestamp _loopStart;
+	Timestamp _loopEnd;
+
+	bool _autofreeStream;
+	RateConverter *_converter;
+	SeekableAudioStream *_input;
+	Timestamp _pos;
+};
+
 #pragma mark -
 #pragma mark --- Mixer ---
 #pragma mark -
@@ -283,12 +300,52 @@
 	}
 
 	// Create the channel
-	SimpleChannel *chan = new SimpleChannel(this, type, input, autofreeStream, reverseStereo, id, permanent);
+	Channel *chan = new SimpleChannel(this, type, input, autofreeStream, reverseStereo, id, permanent);
 	chan->setVolume(volume);
 	chan->setBalance(balance);
 	insertChannel(handle, chan);
 }
 
+void MixerImpl::playInputStreamLooping(
+			SoundType type,
+			SoundHandle *handle,
+			SeekableAudioStream *input,
+			uint loopCount,
+			Timestamp loopStart, Timestamp loopEnd,
+			int id, byte volume, int8 balance,
+			bool autofreeStream,
+			bool permanent,
+			bool reverseStereo) {
+	Common::StackLock lock(_mutex);
+
+	if (input == 0) {
+		warning("input stream is 0");
+		return;
+	}
+
+	// Prevent duplicate sounds
+	if (id != -1) {
+		for (int i = 0; i != NUM_CHANNELS; i++)
+			if (_channels[i] != 0 && _channels[i]->getId() == id) {
+				if (autofreeStream)
+					delete input;
+				return;
+			}
+	}
+
+	if (loopEnd.msecs() == 0)
+		loopEnd = input->getLength();
+
+	// Create the channel
+	Channel *chan = new LoopingChannel(this, type, input, loopCount,
+	                                   loopStart.convertToFramerate(getOutputRate()),
+	                                   loopEnd.convertToFramerate(getOutputRate()),
+	                                   autofreeStream, reverseStereo, id, permanent);
+	chan->setVolume(volume);
+	chan->setBalance(balance);
+	insertChannel(handle, chan);
+}
+
 void MixerImpl::mixCallback(byte *samples, uint len) {
 	assert(samples);
 
@@ -586,5 +643,56 @@
 	}
 }
 
+LoopingChannel::LoopingChannel(Mixer *mixer, Mixer::SoundType type, SeekableAudioStream *input, uint loopCount,
+                               Timestamp loopStart, Timestamp loopEnd, bool autofreeStream, bool reverseStereo,
+                               int id, bool permanent)
+    : Channel(mixer, type, id, permanent), _loopCount(loopCount), _loopStart(loopStart), _loopEnd(loopEnd),
+      _autofreeStream(autofreeStream), _converter(0), _input(input), _pos(0, mixer->getOutputRate()) {
+	_input->seek(loopStart);
+	// Get a rate converter instance
+	_converter = makeRateConverter(_input->getRate(), mixer->getOutputRate(), _input->isStereo(), reverseStereo);
+}
 
+LoopingChannel::~LoopingChannel() {
+	delete _converter;
+	if (_autofreeStream)
+		delete _input;
+}
+
+void LoopingChannel::mix(int16 *data, uint len) {
+	Timestamp newPos = _pos.addFrames(len);
+	int frameDiff = newPos.frameDiff(_loopEnd);
+	bool needLoop = false;
+
+	assert(frameDiff <= (int)len);
+
+	if (frameDiff >= 0) {
+		len -= frameDiff;
+		needLoop = true;
+	}
+
+	_samplesConsumed = _samplesDecoded;
+	_mixerTimeStamp = g_system->getMillis();
+	_pauseTime = 0;
+	uint samplesRead = _converter->flow(*_input, data, len, getLeftVolume(), getRightVolume());
+	_samplesDecoded += samplesRead;
+	_pos = _pos.addFrames(samplesRead);
+
+	if (needLoop) {
+		if (!_loopCount || _loopCount > 1) {
+			if (_loopCount > 1)
+				--_loopCount;
+
+			_input->seek(_loopStart);
+			samplesRead = _converter->flow(*_input, data + len * 2, frameDiff, getLeftVolume(), getRightVolume());
+			_samplesDecoded += samplesRead;
+			_pos = _loopStart.addFrames(samplesRead);
+		}
+	}
+}
+
+bool LoopingChannel::isFinished() const {
+	return (_loopCount == 1) && (_pos == _loopEnd);
+}
+
 } // End of namespace Audio

Modified: scummvm/trunk/sound/mixer.h
===================================================================
--- scummvm/trunk/sound/mixer.h	2010-01-05 21:05:32 UTC (rev 47044)
+++ scummvm/trunk/sound/mixer.h	2010-01-05 21:10:34 UTC (rev 47045)
@@ -29,6 +29,7 @@
 #include "common/scummsys.h"
 #include "common/mutex.h"
 
+#include "sound/timestamp.h"
 
 class OSystem;
 
@@ -36,6 +37,7 @@
 namespace Audio {
 
 class AudioStream;
+class SeekableAudioStream;
 class Channel;
 class Mixer;
 class MixerImpl;
@@ -167,8 +169,40 @@
 		bool permanent = false,
 		bool reverseStereo = false) = 0;
 
+	/**
+	 * Start playing the given audio input stream with looping.
+	 *
+	 * Note that the sound id assigned below is unique. At most one stream
+	 * with a given id can play at any given time. Trying to play a sound
+	 * with an id that is already in use causes the new sound to be not played.
+	 *
+	 * @param type	the type (voice/sfx/music) of the stream
+	 * @param handle	a SoundHandle which can be used to reference and control
+	 *                  the stream via suitable mixer methods
+	 * @param input	the actual SeekableAudioStream to be played
+	 * @param loopCount			how often the data shall be looped (0 = infinite)
+	 * @param loopStart			the (optional) time offset from which to start playback
+	 * @param loopEnd			the (optional) time offset where the loop should end
+	 * @param id	a unique id assigned to this stream
+	 * @param volume	the volume with which to play the sound, ranging from 0 to 255
+	 * @param balance	the balance with which to play the sound, ranging from -128 to 127
+	 * @param autofreeStream	a flag indicating whether the stream should be
+	 *                          freed after playback finished
+	 * @param permanent	a flag indicating whether a plain stopAll call should
+	 *                  not stop this particular stream
+	 * @param reverseStereo	a flag indicating whether left and right channels shall be swapped
+	 */
+	virtual void playInputStreamLooping(
+		SoundType type,
+		SoundHandle *handle,
+		SeekableAudioStream *input,
+		uint loopCount,
+		Timestamp loopStart = Timestamp(0, 1000), Timestamp loopEnd = Timestamp(0, 1000),
+		int id = -1, byte volume = kMaxChannelVolume, int8 balance = 0,
+		bool autofreeStream = true,
+		bool permanent = false,
+		bool reverseStereo = false) = 0;
 
-
 	/**
 	 * Stop all currently playing sounds.
 	 */

Modified: scummvm/trunk/sound/mixer_intern.h
===================================================================
--- scummvm/trunk/sound/mixer_intern.h	2010-01-05 21:05:32 UTC (rev 47044)
+++ scummvm/trunk/sound/mixer_intern.h	2010-01-05 21:10:34 UTC (rev 47045)
@@ -90,8 +90,17 @@
 		bool permanent = false,
 		bool reverseStereo = false);
 
+	virtual void playInputStreamLooping(
+		SoundType type,
+		SoundHandle *handle,
+		SeekableAudioStream *input,
+		uint loopCount,
+		Timestamp loopStart = Timestamp(0, 1000), Timestamp loopEnd = Timestamp(0, 1000),
+		int id = -1, byte volume = kMaxChannelVolume, int8 balance = 0,
+		bool autofreeStream = true,
+		bool permanent = false,
+		bool reverseStereo = false);
 
-
 	virtual void stopAll();
 	virtual void stopID(int id);
 	virtual void stopHandle(SoundHandle handle);


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