[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