aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sound/audiocd.cpp7
-rw-r--r--sound/mixer.cpp112
-rw-r--r--sound/mixer.h36
-rw-r--r--sound/mixer_intern.h11
4 files changed, 159 insertions, 7 deletions
diff --git a/sound/audiocd.cpp b/sound/audiocd.cpp
index b1bd474a4c..d60ae2fab2 100644
--- a/sound/audiocd.cpp
+++ b/sound/audiocd.cpp
@@ -60,7 +60,7 @@ void AudioCDManager::play(int track, int numLoops, int startFrame, int duration,
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 @@ void AudioCDManager::play(int track, int numLoops, int startFrame, int duration,
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 @@ void AudioCDManager::play(int track, int numLoops, int startFrame, int duration,
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)
diff --git a/sound/mixer.cpp b/sound/mixer.cpp
index 5ad8924fe1..7bfb11fdbb 100644
--- a/sound/mixer.cpp
+++ b/sound/mixer.cpp
@@ -170,7 +170,7 @@ private:
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,6 +180,23 @@ public:
}
};
+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 ---
@@ -283,7 +300,47 @@ void MixerImpl::playInputStream(
}
// 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);
@@ -586,5 +643,56 @@ void SimpleChannel::mix(int16 *data, uint len) {
}
}
+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
diff --git a/sound/mixer.h b/sound/mixer.h
index dbb947cc7e..528a17c6c3 100644
--- a/sound/mixer.h
+++ b/sound/mixer.h
@@ -29,6 +29,7 @@
#include "common/scummsys.h"
#include "common/mutex.h"
+#include "sound/timestamp.h"
class OSystem;
@@ -36,6 +37,7 @@ class OSystem;
namespace Audio {
class AudioStream;
+class SeekableAudioStream;
class Channel;
class Mixer;
class MixerImpl;
@@ -167,7 +169,39 @@ public:
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.
diff --git a/sound/mixer_intern.h b/sound/mixer_intern.h
index d74fc70a1c..0cd8793ff3 100644
--- a/sound/mixer_intern.h
+++ b/sound/mixer_intern.h
@@ -90,7 +90,16 @@ public:
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);