2002-04-21 17:46:42 +00:00
|
|
|
/* ScummVM - Scumm Interpreter
|
|
|
|
* Copyright (C) 2001 Ludvig Strigeus
|
2005-01-01 16:09:25 +00:00
|
|
|
* Copyright (C) 2001-2005 The ScummVM project
|
2002-04-21 17:46:42 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*
|
|
|
|
* $Header$
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2002-04-14 18:13:08 +00:00
|
|
|
#include "stdafx.h"
|
2005-01-10 22:06:49 +00:00
|
|
|
|
2002-09-08 01:08:12 +00:00
|
|
|
#include "common/file.h"
|
2003-07-05 16:01:55 +00:00
|
|
|
#include "common/util.h"
|
2005-01-10 22:06:49 +00:00
|
|
|
#include "common/system.h"
|
2002-04-14 18:13:08 +00:00
|
|
|
|
2003-08-05 21:46:56 +00:00
|
|
|
#include "sound/mixer.h"
|
|
|
|
#include "sound/rate.h"
|
2003-08-06 17:13:04 +00:00
|
|
|
#include "sound/audiostream.h"
|
2004-11-27 15:58:18 +00:00
|
|
|
#include "sound/flac.h"
|
2003-12-19 00:32:47 +00:00
|
|
|
#include "sound/mp3.h"
|
|
|
|
#include "sound/vorbis.h"
|
2003-07-28 20:42:54 +00:00
|
|
|
|
2003-08-05 23:03:42 +00:00
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
#pragma mark --- Channel classes ---
|
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Channels used by the sound mixer.
|
|
|
|
*/
|
2003-06-22 01:55:53 +00:00
|
|
|
class Channel {
|
2004-12-27 00:27:00 +00:00
|
|
|
public:
|
|
|
|
const SoundMixer::SoundType _type;
|
2003-12-17 01:32:00 +00:00
|
|
|
private:
|
2003-06-22 01:55:53 +00:00
|
|
|
SoundMixer *_mixer;
|
2003-07-06 16:52:09 +00:00
|
|
|
PlayingSoundHandle *_handle;
|
2003-12-26 02:19:31 +00:00
|
|
|
bool _autofreeStream;
|
2004-11-28 22:15:09 +00:00
|
|
|
bool _permanent;
|
2003-08-31 20:26:21 +00:00
|
|
|
byte _volume;
|
2004-01-29 18:15:27 +00:00
|
|
|
int8 _balance;
|
2003-09-02 13:48:20 +00:00
|
|
|
bool _paused;
|
2003-12-22 19:08:19 +00:00
|
|
|
int _id;
|
2004-02-12 16:25:28 +00:00
|
|
|
uint32 _samplesConsumed;
|
|
|
|
uint32 _samplesDecoded;
|
|
|
|
uint32 _mixerTimeStamp;
|
2003-08-31 20:26:21 +00:00
|
|
|
|
2003-12-17 01:32:00 +00:00
|
|
|
protected:
|
|
|
|
RateConverter *_converter;
|
2004-01-03 14:10:13 +00:00
|
|
|
AudioStream *_input;
|
2003-12-17 01:32:00 +00:00
|
|
|
|
2003-06-22 01:55:53 +00:00
|
|
|
public:
|
2003-08-05 23:03:42 +00:00
|
|
|
|
2004-12-27 00:27:00 +00:00
|
|
|
Channel(SoundMixer *mixer, PlayingSoundHandle *handle, SoundMixer::SoundType type, int id = -1);
|
|
|
|
Channel(SoundMixer *mixer, PlayingSoundHandle *handle, SoundMixer::SoundType type, AudioStream *input, bool autofreeStream, bool reverseStereo = false, int id = -1, bool permanent = false);
|
2003-12-22 19:08:19 +00:00
|
|
|
virtual ~Channel();
|
2003-12-17 02:19:24 +00:00
|
|
|
|
2003-12-22 19:08:19 +00:00
|
|
|
void mix(int16 *data, uint len);
|
2003-12-17 02:19:24 +00:00
|
|
|
|
2004-11-28 22:15:09 +00:00
|
|
|
bool isPermanent() const {
|
|
|
|
return _permanent;
|
|
|
|
}
|
2003-12-22 19:08:19 +00:00
|
|
|
bool isFinished() const {
|
|
|
|
return _input->endOfStream();
|
2003-12-17 02:19:24 +00:00
|
|
|
}
|
2003-12-16 15:34:17 +00:00
|
|
|
void pause(bool paused) {
|
2003-09-02 13:48:20 +00:00
|
|
|
_paused = paused;
|
|
|
|
}
|
2003-12-16 15:34:17 +00:00
|
|
|
bool isPaused() {
|
2003-09-02 13:48:20 +00:00
|
|
|
return _paused;
|
|
|
|
}
|
2004-01-29 18:15:27 +00:00
|
|
|
void setVolume(const byte volume) {
|
2003-08-31 20:26:21 +00:00
|
|
|
_volume = volume;
|
|
|
|
}
|
2004-01-29 18:15:27 +00:00
|
|
|
void setBalance(const int8 balance) {
|
|
|
|
_balance = balance;
|
2003-08-05 23:03:42 +00:00
|
|
|
}
|
2003-12-22 19:08:19 +00:00
|
|
|
int getId() const {
|
|
|
|
return _id;
|
|
|
|
}
|
2004-02-12 16:25:28 +00:00
|
|
|
uint32 getElapsedTime();
|
2003-08-05 02:05:37 +00:00
|
|
|
};
|
|
|
|
|
2004-10-11 22:01:21 +00:00
|
|
|
|
2003-08-05 23:03:42 +00:00
|
|
|
#pragma mark -
|
|
|
|
#pragma mark --- SoundMixer ---
|
|
|
|
#pragma mark -
|
2003-06-15 01:56:47 +00:00
|
|
|
|
2003-08-05 18:17:26 +00:00
|
|
|
|
2002-08-24 15:31:37 +00:00
|
|
|
SoundMixer::SoundMixer() {
|
2005-01-01 18:53:47 +00:00
|
|
|
_syst = &OSystem::instance();
|
2004-02-28 12:58:13 +00:00
|
|
|
_mutex = _syst->createMutex();
|
2003-06-22 13:48:47 +00:00
|
|
|
|
2004-10-11 22:01:21 +00:00
|
|
|
_premixChannel = 0;
|
2003-06-22 14:30:32 +00:00
|
|
|
int i = 0;
|
2003-06-22 13:48:47 +00:00
|
|
|
|
2004-12-27 00:27:00 +00:00
|
|
|
for (i = 0; i < ARRAYSIZE(_volumeForSoundType); i++)
|
2004-12-27 23:33:19 +00:00
|
|
|
_volumeForSoundType[i] = kMaxMixerVolume;
|
2003-06-22 13:48:47 +00:00
|
|
|
|
|
|
|
_paused = false;
|
2003-12-24 17:42:22 +00:00
|
|
|
|
2003-06-22 14:30:32 +00:00
|
|
|
for (i = 0; i != NUM_CHANNELS; i++)
|
2003-12-22 19:08:19 +00:00
|
|
|
_channels[i] = 0;
|
2003-12-24 17:42:22 +00:00
|
|
|
|
2004-02-24 22:39:42 +00:00
|
|
|
_mixerReady = _syst->setSoundCallback(mixCallback, this);
|
2004-11-27 15:58:18 +00:00
|
|
|
_outputRate = (uint)_syst->getOutputSampleRate();
|
2004-07-16 10:24:29 +00:00
|
|
|
|
|
|
|
if (_outputRate == 0)
|
|
|
|
error("OSystem returned invalid sample rate");
|
|
|
|
|
|
|
|
debug(1, "Output sample rate: %d Hz", _outputRate);
|
2002-08-18 21:42:22 +00:00
|
|
|
}
|
|
|
|
|
2002-08-24 15:31:37 +00:00
|
|
|
SoundMixer::~SoundMixer() {
|
2004-02-24 22:39:42 +00:00
|
|
|
_syst->clearSoundCallback();
|
2004-11-28 22:15:09 +00:00
|
|
|
stopAll(true);
|
2004-10-11 22:01:21 +00:00
|
|
|
|
|
|
|
delete _premixChannel;
|
|
|
|
_premixChannel = 0;
|
|
|
|
|
2004-02-28 12:58:13 +00:00
|
|
|
_syst->deleteMutex(_mutex);
|
2002-08-18 21:42:22 +00:00
|
|
|
}
|
|
|
|
|
2004-09-04 13:13:23 +00:00
|
|
|
bool SoundMixer::isPaused() {
|
|
|
|
return _paused;
|
|
|
|
}
|
|
|
|
|
2004-12-27 02:58:55 +00:00
|
|
|
void SoundMixer::setupPremix(AudioStream *stream, SoundType type) {
|
2004-10-11 22:01:21 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
|
|
|
|
|
|
|
delete _premixChannel;
|
|
|
|
_premixChannel = 0;
|
|
|
|
|
|
|
|
if (stream == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Create the channel
|
2004-12-27 02:58:55 +00:00
|
|
|
_premixChannel = new Channel(this, 0, type, stream, false);
|
2003-09-05 20:48:32 +00:00
|
|
|
}
|
|
|
|
|
2003-12-21 00:44:31 +00:00
|
|
|
void SoundMixer::insertChannel(PlayingSoundHandle *handle, Channel *chan) {
|
2003-12-22 19:08:19 +00:00
|
|
|
|
2003-06-22 01:34:28 +00:00
|
|
|
int index = -1;
|
|
|
|
for (int i = 0; i != NUM_CHANNELS; i++) {
|
2003-12-22 19:08:19 +00:00
|
|
|
if (_channels[i] == 0) {
|
2003-06-22 01:34:28 +00:00
|
|
|
index = i;
|
|
|
|
break;
|
2002-08-24 15:31:37 +00:00
|
|
|
}
|
|
|
|
}
|
2003-06-22 01:34:28 +00:00
|
|
|
if(index == -1) {
|
|
|
|
warning("SoundMixer::out of mixer slots");
|
|
|
|
delete chan;
|
2003-12-21 00:44:31 +00:00
|
|
|
return;
|
2002-06-02 20:30:21 +00:00
|
|
|
}
|
2003-06-22 01:34:28 +00:00
|
|
|
|
2002-06-02 20:30:21 +00:00
|
|
|
_channels[index] = chan;
|
|
|
|
if (handle)
|
2003-12-24 00:25:18 +00:00
|
|
|
handle->setIndex(index);
|
2002-05-12 16:53:13 +00:00
|
|
|
}
|
|
|
|
|
2004-11-28 23:02:28 +00:00
|
|
|
void SoundMixer::playRaw(PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags,
|
2004-12-27 00:27:00 +00:00
|
|
|
int id, byte volume, int8 balance, uint32 loopStart, uint32 loopEnd, SoundType type) {
|
2003-10-04 11:50:21 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
2003-07-05 16:01:55 +00:00
|
|
|
|
2003-07-04 14:10:44 +00:00
|
|
|
// Prevent duplicate sounds
|
2003-07-04 20:08:02 +00:00
|
|
|
if (id != -1) {
|
2003-07-05 16:01:55 +00:00
|
|
|
for (int i = 0; i != NUM_CHANNELS; i++)
|
2003-12-22 19:08:19 +00:00
|
|
|
if (_channels[i] != 0 && _channels[i]->getId() == id) {
|
2003-12-26 01:32:29 +00:00
|
|
|
if ((flags & SoundMixer::FLAG_AUTOFREE) != 0)
|
2003-12-22 19:08:19 +00:00
|
|
|
free(sound);
|
2003-12-21 00:44:31 +00:00
|
|
|
return;
|
2003-12-22 19:08:19 +00:00
|
|
|
}
|
2003-12-21 00:44:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the input stream
|
2004-01-03 14:10:13 +00:00
|
|
|
AudioStream *input;
|
2003-12-21 00:44:31 +00:00
|
|
|
if (flags & SoundMixer::FLAG_LOOP) {
|
|
|
|
if (loopEnd == 0) {
|
2003-12-26 01:32:29 +00:00
|
|
|
input = makeLinearInputStream(rate, flags, (byte *)sound, size, 0, size);
|
2003-12-21 00:44:31 +00:00
|
|
|
} else {
|
|
|
|
assert(loopStart < loopEnd && loopEnd <= size);
|
2003-12-26 01:32:29 +00:00
|
|
|
input = makeLinearInputStream(rate, flags, (byte *)sound, size, loopStart, loopEnd - loopStart);
|
2003-12-21 00:44:31 +00:00
|
|
|
}
|
|
|
|
} else {
|
2003-12-26 01:32:29 +00:00
|
|
|
input = makeLinearInputStream(rate, flags, (byte *)sound, size, 0, 0);
|
2003-07-04 20:08:02 +00:00
|
|
|
}
|
2003-07-04 14:10:44 +00:00
|
|
|
|
2003-12-21 00:44:31 +00:00
|
|
|
// Create the channel
|
2004-12-27 00:27:00 +00:00
|
|
|
Channel *chan = new Channel(this, handle, type, input, true, (flags & SoundMixer::FLAG_REVERSE_STEREO) != 0, id);
|
2004-01-29 18:15:27 +00:00
|
|
|
chan->setVolume(volume);
|
|
|
|
chan->setBalance(balance);
|
2003-12-21 00:44:31 +00:00
|
|
|
insertChannel(handle, chan);
|
2002-04-14 18:13:08 +00:00
|
|
|
}
|
|
|
|
|
2004-12-27 00:27:00 +00:00
|
|
|
void SoundMixer::playInputStream(SoundType type, PlayingSoundHandle *handle, AudioStream *input,
|
2004-11-28 23:02:28 +00:00
|
|
|
int id, byte volume, int8 balance, bool autofreeStream, bool permanent) {
|
2003-12-19 00:32:47 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
|
|
|
|
2003-12-23 19:14:57 +00:00
|
|
|
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) {
|
2003-12-26 02:19:31 +00:00
|
|
|
if (autofreeStream)
|
|
|
|
delete input;
|
2003-12-23 19:14:57 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-19 00:32:47 +00:00
|
|
|
// Create the channel
|
2004-12-27 00:27:00 +00:00
|
|
|
Channel *chan = new Channel(this, handle, type, input, autofreeStream, false, id, permanent);
|
2004-01-29 18:15:27 +00:00
|
|
|
chan->setVolume(volume);
|
|
|
|
chan->setBalance(balance);
|
2003-12-21 00:44:31 +00:00
|
|
|
insertChannel(handle, chan);
|
2003-12-19 00:32:47 +00:00
|
|
|
}
|
|
|
|
|
2002-08-24 15:31:37 +00:00
|
|
|
void SoundMixer::mix(int16 *buf, uint len) {
|
2003-10-04 11:50:21 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
2003-07-14 20:09:14 +00:00
|
|
|
|
2003-12-19 00:32:47 +00:00
|
|
|
// zero the buf
|
|
|
|
memset(buf, 0, 2 * len * sizeof(int16));
|
2002-04-14 18:13:08 +00:00
|
|
|
|
2003-09-06 10:47:30 +00:00
|
|
|
if (!_paused) {
|
2004-10-11 22:01:21 +00:00
|
|
|
if (_premixChannel)
|
|
|
|
_premixChannel->mix(buf, len);
|
2003-12-19 00:32:47 +00:00
|
|
|
|
2003-06-21 23:29:34 +00:00
|
|
|
// now mix all channels
|
2003-05-23 16:47:45 +00:00
|
|
|
for (int i = 0; i != NUM_CHANNELS; i++)
|
2003-12-22 19:08:19 +00:00
|
|
|
if (_channels[i]) {
|
|
|
|
if (_channels[i]->isFinished()) {
|
|
|
|
delete _channels[i];
|
|
|
|
_channels[i] = 0;
|
|
|
|
} else if (!_channels[i]->isPaused())
|
|
|
|
_channels[i]->mix(buf, len);
|
|
|
|
}
|
2003-05-23 16:47:45 +00:00
|
|
|
}
|
2002-04-14 18:13:08 +00:00
|
|
|
}
|
|
|
|
|
2003-07-25 01:19:14 +00:00
|
|
|
void SoundMixer::mixCallback(void *s, byte *samples, int len) {
|
|
|
|
assert(s);
|
|
|
|
assert(samples);
|
|
|
|
// Len is the number of bytes in the buffer; we divide it by
|
|
|
|
// four to get the number of samples (stereo 16 bit).
|
2002-07-07 18:04:03 +00:00
|
|
|
((SoundMixer *)s)->mix((int16 *)samples, len >> 2);
|
2002-04-14 18:13:08 +00:00
|
|
|
}
|
|
|
|
|
2004-11-28 22:15:09 +00:00
|
|
|
void SoundMixer::stopAll(bool force) {
|
2003-10-04 11:50:21 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
2002-07-07 18:04:03 +00:00
|
|
|
for (int i = 0; i != NUM_CHANNELS; i++)
|
2003-12-22 19:08:19 +00:00
|
|
|
if (_channels[i] != 0) {
|
2004-11-28 22:15:09 +00:00
|
|
|
if (force || !_channels[i]->isPermanent()) {
|
|
|
|
delete _channels[i];
|
|
|
|
_channels[i] = 0;
|
|
|
|
}
|
2003-12-22 19:08:19 +00:00
|
|
|
}
|
2002-04-14 18:13:08 +00:00
|
|
|
}
|
|
|
|
|
2003-03-18 21:46:44 +00:00
|
|
|
void SoundMixer::stopID(int id) {
|
2003-10-04 11:50:21 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
2003-06-21 23:29:34 +00:00
|
|
|
for (int i = 0; i != NUM_CHANNELS; i++) {
|
2003-12-22 19:08:19 +00:00
|
|
|
if (_channels[i] != 0 && _channels[i]->getId() == id) {
|
|
|
|
delete _channels[i];
|
|
|
|
_channels[i] = 0;
|
2003-03-18 21:46:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-07-14 20:09:14 +00:00
|
|
|
void SoundMixer::stopHandle(PlayingSoundHandle handle) {
|
2003-10-04 11:50:21 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
2003-11-08 23:05:04 +00:00
|
|
|
|
2003-07-14 20:09:14 +00:00
|
|
|
// Simply ignore stop requests for handles of sounds that already terminated
|
2003-12-24 00:25:18 +00:00
|
|
|
if (!handle.isActive())
|
2003-07-14 20:09:14 +00:00
|
|
|
return;
|
|
|
|
|
2003-12-24 00:25:18 +00:00
|
|
|
int index = handle.getIndex();
|
2003-08-30 18:12:49 +00:00
|
|
|
|
2003-07-14 20:09:14 +00:00
|
|
|
if ((index < 0) || (index >= NUM_CHANNELS)) {
|
|
|
|
warning("soundMixer::stopHandle has invalid index %d", index);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-12-22 19:08:19 +00:00
|
|
|
if (_channels[index]) {
|
|
|
|
delete _channels[index];
|
|
|
|
_channels[index] = 0;
|
|
|
|
}
|
2003-07-14 20:09:14 +00:00
|
|
|
}
|
|
|
|
|
2003-08-31 20:26:21 +00:00
|
|
|
void SoundMixer::setChannelVolume(PlayingSoundHandle handle, byte volume) {
|
2003-10-04 11:50:21 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
2003-11-08 23:05:04 +00:00
|
|
|
|
2003-12-24 00:25:18 +00:00
|
|
|
if (!handle.isActive())
|
2003-08-31 20:26:21 +00:00
|
|
|
return;
|
|
|
|
|
2003-12-24 00:25:18 +00:00
|
|
|
int index = handle.getIndex();
|
2003-08-31 20:26:21 +00:00
|
|
|
|
|
|
|
if ((index < 0) || (index >= NUM_CHANNELS)) {
|
|
|
|
warning("soundMixer::setChannelVolume has invalid index %d", index);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_channels[index])
|
2004-01-29 18:15:27 +00:00
|
|
|
_channels[index]->setVolume(volume);
|
2003-08-31 20:26:21 +00:00
|
|
|
}
|
|
|
|
|
2004-01-29 18:15:27 +00:00
|
|
|
void SoundMixer::setChannelBalance(PlayingSoundHandle handle, int8 balance) {
|
2003-10-04 11:50:21 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
2003-11-08 23:05:04 +00:00
|
|
|
|
2003-12-24 00:25:18 +00:00
|
|
|
if (!handle.isActive())
|
2003-08-31 20:26:21 +00:00
|
|
|
return;
|
|
|
|
|
2003-12-24 00:25:18 +00:00
|
|
|
int index = handle.getIndex();
|
2003-08-31 20:26:21 +00:00
|
|
|
|
|
|
|
if ((index < 0) || (index >= NUM_CHANNELS)) {
|
2004-01-29 18:15:27 +00:00
|
|
|
warning("soundMixer::setChannelBalance has invalid index %d", index);
|
2003-08-31 20:26:21 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_channels[index])
|
2004-01-29 18:15:27 +00:00
|
|
|
_channels[index]->setBalance(balance);
|
2003-08-31 20:26:21 +00:00
|
|
|
}
|
|
|
|
|
2004-11-27 15:58:18 +00:00
|
|
|
uint32 SoundMixer::getSoundElapsedTime(PlayingSoundHandle handle) {
|
2004-02-12 16:25:28 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
|
|
|
|
|
|
|
if (!handle.isActive())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
int index = handle.getIndex();
|
|
|
|
|
|
|
|
if ((index < 0) || (index >= NUM_CHANNELS)) {
|
2004-11-27 15:58:18 +00:00
|
|
|
warning("soundMixer::getSoundElapsedTime has invalid index %d", index);
|
2004-02-12 16:25:28 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_channels[index])
|
|
|
|
return _channels[index]->getElapsedTime();
|
|
|
|
|
2004-11-27 15:58:18 +00:00
|
|
|
warning("soundMixer::getSoundElapsedTime has no channel object for index %d", index);
|
2004-02-12 16:25:28 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-09-05 20:48:32 +00:00
|
|
|
void SoundMixer::pauseAll(bool paused) {
|
2003-09-06 10:47:30 +00:00
|
|
|
_paused = paused;
|
2003-08-09 19:19:27 +00:00
|
|
|
}
|
|
|
|
|
2003-09-02 13:48:20 +00:00
|
|
|
void SoundMixer::pauseID(int id, bool paused) {
|
2003-10-04 11:50:21 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
2003-09-02 13:48:20 +00:00
|
|
|
for (int i = 0; i != NUM_CHANNELS; i++) {
|
2003-12-22 19:08:19 +00:00
|
|
|
if (_channels[i] != 0 && _channels[i]->getId() == id) {
|
2003-09-02 13:48:20 +00:00
|
|
|
_channels[i]->pause(paused);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-09-02 22:38:53 +00:00
|
|
|
void SoundMixer::pauseHandle(PlayingSoundHandle handle, bool paused) {
|
2003-10-04 11:50:21 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
2003-09-02 13:48:20 +00:00
|
|
|
|
|
|
|
// Simply ignore pause/unpause requests for handles of sound that alreayd terminated
|
2003-12-24 00:25:18 +00:00
|
|
|
if (!handle.isActive())
|
2003-09-02 13:48:20 +00:00
|
|
|
return;
|
|
|
|
|
2003-12-24 00:25:18 +00:00
|
|
|
int index = handle.getIndex();
|
2003-09-02 13:48:20 +00:00
|
|
|
|
|
|
|
if ((index < 0) || (index >= NUM_CHANNELS)) {
|
|
|
|
warning("soundMixer::pauseHandle has invalid index %d", index);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_channels[index])
|
2003-09-02 22:38:53 +00:00
|
|
|
_channels[index]->pause(paused);
|
2003-09-02 13:48:20 +00:00
|
|
|
}
|
|
|
|
|
2004-09-19 12:22:47 +00:00
|
|
|
bool SoundMixer::isSoundIDActive(int id) {
|
2004-09-19 13:54:24 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
2004-09-19 12:22:47 +00:00
|
|
|
for (int i = 0; i != NUM_CHANNELS; i++)
|
|
|
|
if (_channels[i] && _channels[i]->getId() == id)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2004-12-27 00:27:00 +00:00
|
|
|
bool SoundMixer::hasActiveChannelOfType(SoundType type) {
|
2003-10-04 11:50:21 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
2003-06-21 23:29:34 +00:00
|
|
|
for (int i = 0; i != NUM_CHANNELS; i++)
|
2004-12-28 11:19:36 +00:00
|
|
|
if (_channels[i] && _channels[i]->_type == type)
|
2002-04-14 18:13:08 +00:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2004-12-27 00:27:00 +00:00
|
|
|
void SoundMixer::setVolumeForSoundType(SoundType type, int volume) {
|
|
|
|
assert(0 <= type && type < ARRAYSIZE(_volumeForSoundType));
|
|
|
|
|
2002-07-28 15:03:45 +00:00
|
|
|
// Check range
|
2004-12-27 23:33:19 +00:00
|
|
|
if (volume > kMaxMixerVolume)
|
|
|
|
volume = kMaxMixerVolume;
|
2002-07-28 15:03:45 +00:00
|
|
|
else if (volume < 0)
|
|
|
|
volume = 0;
|
2004-11-28 23:02:28 +00:00
|
|
|
|
|
|
|
// TODO: Maybe we should do logarithmic (not linear) volume
|
|
|
|
// scaling? See also Player_V2::setMasterVolume
|
2002-07-28 15:03:45 +00:00
|
|
|
|
2004-12-27 00:27:00 +00:00
|
|
|
_volumeForSoundType[type] = volume;
|
2002-04-14 18:13:08 +00:00
|
|
|
}
|
|
|
|
|
2004-12-27 00:27:00 +00:00
|
|
|
int SoundMixer::getVolumeForSoundType(SoundType type) const {
|
|
|
|
assert(0 <= type && type < ARRAYSIZE(_volumeForSoundType));
|
|
|
|
|
|
|
|
return _volumeForSoundType[type];
|
2002-07-21 06:55:33 +00:00
|
|
|
}
|
|
|
|
|
2003-08-05 02:05:37 +00:00
|
|
|
|
2003-08-05 23:03:42 +00:00
|
|
|
#pragma mark -
|
|
|
|
#pragma mark --- Channel implementations ---
|
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
|
2004-12-27 00:27:00 +00:00
|
|
|
Channel::Channel(SoundMixer *mixer, PlayingSoundHandle *handle, SoundMixer::SoundType type, int id)
|
|
|
|
: _type(type), _mixer(mixer), _handle(handle), _autofreeStream(true),
|
2004-12-27 23:33:19 +00:00
|
|
|
_volume(SoundMixer::kMaxChannelVolume), _balance(0), _paused(false), _id(id), _samplesConsumed(0),
|
2004-02-12 16:25:28 +00:00
|
|
|
_samplesDecoded(0), _mixerTimeStamp(0), _converter(0), _input(0) {
|
2003-12-22 19:08:19 +00:00
|
|
|
assert(mixer);
|
|
|
|
}
|
|
|
|
|
2004-12-27 00:27:00 +00:00
|
|
|
Channel::Channel(SoundMixer *mixer, PlayingSoundHandle *handle, SoundMixer::SoundType type, AudioStream *input,
|
|
|
|
bool autofreeStream, bool reverseStereo, int id, bool permanent)
|
|
|
|
: _type(type), _mixer(mixer), _handle(handle), _autofreeStream(autofreeStream),
|
2004-12-27 23:33:19 +00:00
|
|
|
_volume(SoundMixer::kMaxChannelVolume), _balance(0), _paused(false), _id(id), _samplesConsumed(0),
|
2004-11-28 22:15:09 +00:00
|
|
|
_samplesDecoded(0), _mixerTimeStamp(0), _converter(0), _input(input), _permanent(permanent) {
|
2003-12-22 19:08:19 +00:00
|
|
|
assert(mixer);
|
|
|
|
assert(input);
|
|
|
|
|
|
|
|
// Get a rate converter instance
|
|
|
|
_converter = makeRateConverter(_input->getRate(), mixer->getOutputRate(), _input->isStereo(), reverseStereo);
|
|
|
|
}
|
|
|
|
|
2003-08-05 23:03:42 +00:00
|
|
|
Channel::~Channel() {
|
|
|
|
delete _converter;
|
2003-12-26 02:19:31 +00:00
|
|
|
if (_autofreeStream)
|
|
|
|
delete _input;
|
2003-08-05 23:03:42 +00:00
|
|
|
if (_handle)
|
2003-12-24 00:25:18 +00:00
|
|
|
_handle->resetIndex();
|
2003-08-05 23:03:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* len indicates the number of sample *pairs*. So a value of
|
|
|
|
10 means that the buffer contains twice 10 sample, each
|
|
|
|
16 bits, for a total of 40 bytes.
|
|
|
|
*/
|
|
|
|
void Channel::mix(int16 *data, uint len) {
|
|
|
|
assert(_input);
|
2003-12-19 01:30:19 +00:00
|
|
|
|
2003-12-22 19:08:19 +00:00
|
|
|
if (_input->endOfData()) {
|
2003-12-19 01:30:19 +00:00
|
|
|
// TODO: call drain method
|
2003-08-05 23:03:42 +00:00
|
|
|
} else {
|
|
|
|
assert(_converter);
|
2003-09-05 23:27:11 +00:00
|
|
|
|
2004-01-29 18:15:27 +00:00
|
|
|
// From the channel balance/volume and the global volume, we compute
|
|
|
|
// the effective volume for the left and right channel. Note the
|
|
|
|
// slightly odd divisor: the 255 reflects the fact that the maximal
|
|
|
|
// value for _volume is 255, while the 127 is there because the
|
|
|
|
// balance value ranges from -127 to 127. The mixer (music/sound)
|
|
|
|
// volume is in the range 0 - 256.
|
2003-09-05 23:27:11 +00:00
|
|
|
// Hence, the vol_l/vol_r values will be in that range, too
|
|
|
|
|
2004-12-27 00:27:00 +00:00
|
|
|
int vol = _mixer->getVolumeForSoundType(_type) * _volume;
|
2004-01-29 18:15:27 +00:00
|
|
|
st_volume_t vol_l, vol_r;
|
|
|
|
|
|
|
|
if (_balance == 0) {
|
2004-12-27 23:33:19 +00:00
|
|
|
vol_l = vol / SoundMixer::kMaxChannelVolume;
|
|
|
|
vol_r = vol / SoundMixer::kMaxChannelVolume;
|
2004-01-29 18:15:27 +00:00
|
|
|
} else if (_balance < 0) {
|
2004-12-27 23:33:19 +00:00
|
|
|
vol_l = vol / SoundMixer::kMaxChannelVolume;
|
|
|
|
vol_r = ((127 + _balance) * vol) / (SoundMixer::kMaxChannelVolume * 127);
|
2004-01-29 18:15:27 +00:00
|
|
|
} else {
|
2004-12-27 23:33:19 +00:00
|
|
|
vol_l = ((127 - _balance) * vol) / (SoundMixer::kMaxChannelVolume * 127);
|
|
|
|
vol_r = vol / SoundMixer::kMaxChannelVolume;
|
2004-01-29 18:15:27 +00:00
|
|
|
}
|
2003-09-05 23:27:11 +00:00
|
|
|
|
2004-02-12 16:25:28 +00:00
|
|
|
_samplesConsumed = _samplesDecoded;
|
2004-09-28 20:19:37 +00:00
|
|
|
_mixerTimeStamp = g_system->getMillis();
|
2004-02-12 16:25:28 +00:00
|
|
|
|
2003-09-05 23:27:11 +00:00
|
|
|
_converter->flow(*_input, data, len, vol_l, vol_r);
|
2004-02-12 16:25:28 +00:00
|
|
|
|
|
|
|
_samplesDecoded += len;
|
2003-08-05 23:03:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-02-12 16:25:28 +00:00
|
|
|
uint32 Channel::getElapsedTime() {
|
|
|
|
if (_mixerTimeStamp == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Convert the number of samples into a time duration. To avoid
|
|
|
|
// overflow, this has to be done in a somewhat non-obvious way.
|
|
|
|
|
|
|
|
uint rate = _mixer->getOutputRate();
|
|
|
|
|
|
|
|
uint32 seconds = _samplesConsumed / rate;
|
|
|
|
uint32 milliseconds = (1000 * (_samplesConsumed % rate)) / rate;
|
|
|
|
|
2004-09-28 20:19:37 +00:00
|
|
|
uint32 delta = g_system->getMillis() - _mixerTimeStamp;
|
2004-02-12 16:25:28 +00:00
|
|
|
|
|
|
|
// In theory it would seem like a good idea to limit the approximation
|
|
|
|
// so that it never exceeds the theoretical upper bound set by
|
|
|
|
// _samplesDecoded. Meanwhile, back in the real world, doing so makes
|
|
|
|
// the Broken Sword cutscenes noticeably jerkier. I guess the mixer
|
|
|
|
// isn't invoked at the regular intervals that I first imagined.
|
|
|
|
|
|
|
|
// FIXME: This won't work very well if the sound is paused.
|
|
|
|
return 1000 * seconds + milliseconds + delta;
|
|
|
|
}
|