aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorMax Horn2003-07-25 01:19:14 +0000
committerMax Horn2003-07-25 01:19:14 +0000
commit791efd853aacee15bb2f5b2e575c59fd9bb7480d (patch)
treeb950b381c024de5d9b0306017f897d0a1915802d /sound
parent95bb74e2b886c22adce2fd0bdd40083b8d8efb53 (diff)
downloadscummvm-rg350-791efd853aacee15bb2f5b2e575c59fd9bb7480d.tar.gz
scummvm-rg350-791efd853aacee15bb2f5b2e575c59fd9bb7480d.tar.bz2
scummvm-rg350-791efd853aacee15bb2f5b2e575c59fd9bb7480d.zip
lots of mixer changes: replaced _volumeTable by _globalVolume (applying volume after resampling is more accurate); made more member vars of SoundMixer protected (and thus added some new getter methods); added (untested) support for a second (stereo) channel when playing MP3
svn-id: r9184
Diffstat (limited to 'sound')
-rw-r--r--sound/mixer.cpp146
-rw-r--r--sound/mixer.h45
2 files changed, 104 insertions, 87 deletions
diff --git a/sound/mixer.cpp b/sound/mixer.cpp
index 3ea8951c15..61aafb8710 100644
--- a/sound/mixer.cpp
+++ b/sound/mixer.cpp
@@ -26,7 +26,6 @@
#include "common/file.h"
#include "common/util.h"
-
class Channel {
protected:
SoundMixer *_mixer;
@@ -41,6 +40,11 @@ public:
if (_handle)
*_handle = 0;
}
+
+ /* 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.
+ */
virtual void mix(int16 *data, uint len) = 0;
void destroy() {
for (int i = 0; i != SoundMixer::NUM_CHANNELS; i++)
@@ -54,12 +58,12 @@ public:
class ChannelRaw : public Channel {
byte *_ptr;
+ byte _flags;
uint32 _pos;
uint32 _size;
uint32 _fpSpeed;
uint32 _fpPos;
uint32 _realSize, _rate;
- byte _flags;
byte *_loop_ptr;
uint32 _loop_size;
@@ -170,7 +174,7 @@ SoundMixer::SoundMixer() {
_outputRate = 0;
- _volumeTable = (int16 *)calloc(256 * sizeof(int16), 1);
+ _globalVolume = 0;
_musicVolume = 0;
_paused = false;
@@ -181,13 +185,17 @@ SoundMixer::SoundMixer() {
SoundMixer::~SoundMixer() {
_syst->clear_sound_proc();
- free(_volumeTable);
for (int i = 0; i != NUM_CHANNELS; i++) {
delete _channels[i];
}
_syst->delete_mutex(_mutex);
}
+int SoundMixer::newStream(void *sound, uint32 size, uint rate, byte flags, uint32 buffer_size) {
+ StackLock lock(_mutex);
+ return insertChannel(NULL, new ChannelStream(this, 0, sound, size, rate, flags, buffer_size));
+}
+
void SoundMixer::appendStream(int index, void *sound, uint32 size) {
StackLock lock(_mutex);
@@ -253,11 +261,6 @@ int SoundMixer::playRaw(PlayingSoundHandle *handle, void *sound, uint32 size, ui
return insertChannel(handle, new ChannelRaw(this, handle, sound, size, rate, flags, id));
}
-int SoundMixer::newStream(void *sound, uint32 size, uint rate, byte flags, uint32 buffer_size) {
- StackLock lock(_mutex);
- return insertChannel(NULL, new ChannelStream(this, 0, sound, size, rate, flags, buffer_size));
-}
-
#ifdef USE_MAD
int SoundMixer::playMP3(PlayingSoundHandle *handle, void *sound, uint32 size, byte flags) {
StackLock lock(_mutex);
@@ -298,7 +301,11 @@ void SoundMixer::mix(int16 *buf, uint len) {
}
}
-void SoundMixer::onGenerateSamples(void *s, byte *samples, int len) {
+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).
((SoundMixer *)s)->mix((int16 *)samples, len >> 2);
}
@@ -311,7 +318,7 @@ bool SoundMixer::bindToSystem(OSystem *syst) {
if (rate == 0)
error("OSystem returned invalid sample rate");
- return syst->set_sound_proc(onGenerateSamples, this, OSystem::SOUND_16BIT);
+ return syst->set_sound_proc(mixCallback, this, OSystem::SOUND_16BIT);
}
void SoundMixer::stopAll() {
@@ -376,13 +383,18 @@ bool SoundMixer::hasActiveSFXChannel() {
return false;
}
-bool SoundMixer::isActiveChannel(int index) {
+bool SoundMixer::isChannelActive(int index) {
StackLock lock(_mutex);
if (_channels[index])
return _channels[index]->isActive();
return false;
}
+bool SoundMixer::isChannelUsed(int index) {
+ StackLock lock(_mutex);
+ return (_channels[index] != NULL);
+}
+
void SoundMixer::setupPremix(void *param, PremixProc *proc) {
StackLock lock(_mutex);
_premixParam = param;
@@ -390,20 +402,13 @@ void SoundMixer::setupPremix(void *param, PremixProc *proc) {
}
void SoundMixer::setVolume(int volume) {
- int i;
-
// Check range
if (volume > 256)
volume = 256;
else if (volume < 0)
volume = 0;
- // The volume table takes 8 bit unsigned data as index and returns 16 bit signed
- for (i = 0; i < 128; i++)
- _volumeTable[i] = i * volume;
-
- for (i = -128; i < 0; i++)
- _volumeTable[i + 256] = i * volume;
+ _globalVolume = volume;
}
void SoundMixer::setMusicVolume(int volume) {
@@ -481,13 +486,13 @@ static inline void clamped_add_16(int16& a, int b) {
}
static void mix_signed_mono_8(int16 *data, uint &len, byte *&s, uint32 &fp_pos,
- int fp_speed, const int16 *vol_tab, byte *s_end, bool reverse_stereo) {
+ int fp_speed, int volume, byte *s_end, bool reverse_stereo) {
int inc = 1, result;
- CubicInterpolator interp(vol_tab[*s], vol_tab[*(s + 1)], vol_tab[*(s + 2)]);
+ CubicInterpolator interp(*s, *(s + 1), *(s + 2));
do {
do {
- result = interp.interpolate(fp_pos);
+ result = interp.interpolate(fp_pos) * volume / 256;
clamped_add_16(*data++, result);
clamped_add_16(*data++, result);
@@ -500,7 +505,7 @@ static void mix_signed_mono_8(int16 *data, uint &len, byte *&s, uint32 &fp_pos,
} while (!inc && len && (s < s_end));
if (s + 2 < s_end)
- interp.feedData(vol_tab[*(s + 2)]);
+ interp.feedData(*(s + 2));
else
interp.feedData();
@@ -508,13 +513,13 @@ static void mix_signed_mono_8(int16 *data, uint &len, byte *&s, uint32 &fp_pos,
}
static void mix_unsigned_mono_8(int16 *data, uint &len, byte *&s, uint32 &fp_pos,
- int fp_speed, const int16 *vol_tab, byte *s_end, bool reverse_stereo) {
+ int fp_speed, int volume, byte *s_end, bool reverse_stereo) {
int inc = 1, result;
- CubicInterpolator interp(vol_tab[*s ^ 0x80], vol_tab[*(s + 1) ^ 0x80], vol_tab[*(s + 2) ^ 0x80]);
+ CubicInterpolator interp(*s ^ 0x80, *(s + 1) ^ 0x80, *(s + 2) ^ 0x80);
do {
do {
- result = interp.interpolate(fp_pos);
+ result = interp.interpolate(fp_pos) * volume / 256;
clamped_add_16(*data++, result);
clamped_add_16(*data++, result);
@@ -527,7 +532,7 @@ static void mix_unsigned_mono_8(int16 *data, uint &len, byte *&s, uint32 &fp_pos
} while (!inc && len && (s < s_end));
if (s + 2 < s_end)
- interp.feedData(vol_tab[*(s + 2) ^ 0x80]);
+ interp.feedData(*(s + 2) ^ 0x80);
else
interp.feedData();
@@ -535,23 +540,23 @@ static void mix_unsigned_mono_8(int16 *data, uint &len, byte *&s, uint32 &fp_pos
}
static void mix_signed_stereo_8(int16 *data, uint &len, byte *&s, uint32 &fp_pos,
- int fp_speed, const int16 *vol_tab, byte *s_end, bool reverse_stereo) {
+ int fp_speed, int volume, byte *s_end, bool reverse_stereo) {
warning("Mixing stereo signed 8 bit is not supported yet ");
}
static void mix_unsigned_stereo_8(int16 *data, uint &len, byte *&s, uint32 &fp_pos,
- int fp_speed, const int16 *vol_tab, byte *s_end, bool reverse_stereo) {
+ int fp_speed, int volume, byte *s_end, bool reverse_stereo) {
int inc = 1;
- CubicInterpolator left(vol_tab[*s ^ 0x80], vol_tab[*(s + 2) ^ 0x80], vol_tab[*(s + 4) ^ 0x80]);
- CubicInterpolator right(vol_tab[*(s + 1) ^ 0x80], vol_tab[*(s + 3) ^ 0x80], vol_tab[*(s + 5) ^ 0x80]);
+ CubicInterpolator left(*s ^ 0x80, *(s + 2) ^ 0x80, *(s + 4) ^ 0x80);
+ CubicInterpolator right(*(s + 1) ^ 0x80, *(s + 3) ^ 0x80, *(s + 5) ^ 0x80);
do {
do {
if (!reverse_stereo) {
- clamped_add_16(*data++, left.interpolate(fp_pos));
- clamped_add_16(*data++, right.interpolate(fp_pos));
+ clamped_add_16(*data++, left.interpolate(fp_pos) * volume / 256);
+ clamped_add_16(*data++, right.interpolate(fp_pos) * volume / 256);
} else {
- clamped_add_16(*data++, right.interpolate(fp_pos));
- clamped_add_16(*data++, left.interpolate(fp_pos));
+ clamped_add_16(*data++, right.interpolate(fp_pos) * volume / 256);
+ clamped_add_16(*data++, left.interpolate(fp_pos) * volume / 256);
}
fp_pos += fp_speed;
@@ -562,8 +567,8 @@ static void mix_unsigned_stereo_8(int16 *data, uint &len, byte *&s, uint32 &fp_p
} while (!inc && len && (s < s_end));
if (s + 5 < s_end) {
- left.feedData(vol_tab[*(s + 4) ^ 0x80]);
- right.feedData(vol_tab[*(s + 5) ^ 0x80]);
+ left.feedData(*(s + 4) ^ 0x80);
+ right.feedData(*(s + 5) ^ 0x80);
} else {
left.feedData();
right.feedData();
@@ -572,8 +577,7 @@ static void mix_unsigned_stereo_8(int16 *data, uint &len, byte *&s, uint32 &fp_p
} while (len && (s < s_end));
}
static void mix_signed_mono_16(int16 *data, uint &len, byte *&s, uint32 &fp_pos,
- int fp_speed, const int16 *vol_tab, byte *s_end, bool reverse_stereo) {
- unsigned char volume = ((int)vol_tab[1]);
+ int fp_speed, int volume, byte *s_end, bool reverse_stereo) {
do {
int16 sample = ((int16)READ_BE_UINT16(s) * volume) / 256;
fp_pos += fp_speed;
@@ -586,13 +590,11 @@ static void mix_signed_mono_16(int16 *data, uint &len, byte *&s, uint32 &fp_pos,
} while ((--len) && (s < s_end));
}
static void mix_unsigned_mono_16(int16 *data, uint &len, byte *&s, uint32 &fp_pos,
- int fp_speed, const int16 *vol_tab, byte *s_end, bool reverse_stereo) {
+ int fp_speed, int volume, byte *s_end, bool reverse_stereo) {
warning("Mixing mono unsigned 16 bit is not supported yet ");
}
static void mix_signed_stereo_16(int16 *data, uint &len, byte *&s, uint32 &fp_pos,
- int fp_speed, const int16 *vol_tab, byte *s_end, bool reverse_stereo) {
- unsigned char volume = (int)vol_tab[1];
-
+ int fp_speed, int volume, byte *s_end, bool reverse_stereo) {
do {
int16 leftS = ((int16)READ_BE_UINT16(s) * volume) / 256;
int16 rightS = ((int16)READ_BE_UINT16(s+2) * volume) / 256;
@@ -610,12 +612,12 @@ static void mix_signed_stereo_16(int16 *data, uint &len, byte *&s, uint32 &fp_po
} while ((--len) && (s < s_end));
}
static void mix_unsigned_stereo_16(int16 *data, uint &len, byte *&s, uint32 &fp_pos,
- int fp_speed, const int16 *vol_tab, byte *s_end, bool reverse_stereo) {
+ int fp_speed, int volume, byte *s_end, bool reverse_stereo) {
warning("Mixing stereo unsigned 16 bit is not supported yet ");
}
typedef void MixProc(int16 *data, uint &len, byte *&s,
- uint32 &fp_pos, int fp_speed, const int16 *vol_tab,
+ uint32 &fp_pos, int fp_speed, int volume,
byte *s_end, bool reverse_stereo);
static MixProc *mixer_helper_table[8] = {
@@ -641,11 +643,12 @@ bool Channel::isActive() {
ChannelRaw::ChannelRaw(SoundMixer *mixer, PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags, int id)
: Channel(mixer, handle) {
_id = id;
- _flags = flags;
_ptr = (byte *)sound;
+ _flags = flags;
+
_pos = 0;
_fpPos = 0;
- _fpSpeed = (1 << 16) * rate / mixer->_outputRate;
+ _fpSpeed = (1 << 16) * rate / mixer->getOutputRate();
_realSize = size;
// adjust the magnitude to prevent division error
@@ -653,7 +656,7 @@ ChannelRaw::ChannelRaw(SoundMixer *mixer, PlayingSoundHandle *handle, void *soun
size >>= 1, rate = (rate >> 1) + 1;
_rate = rate;
- _size = size * mixer->_outputRate / rate;
+ _size = size * mixer->getOutputRate() / rate;
if (_flags & SoundMixer::FLAG_16BITS)
_size = _size >> 1;
if (_flags & SoundMixer::FLAG_STEREO)
@@ -680,9 +683,7 @@ void ChannelRaw::mix(int16 *data, uint len) {
s = _ptr + _pos;
end = _ptr + _realSize;
- const int16 *vol_tab = _mixer->_volumeTable;
-
- mixer_helper_table[_flags & 0x07] (data, len, s, _fpPos, _fpSpeed, vol_tab, end, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false);
+ mixer_helper_table[_flags & 0x07] (data, len, s, _fpPos, _fpSpeed, _mixer->getVolume(), end, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false);
_pos = s - _ptr;
@@ -712,7 +713,7 @@ ChannelStream::ChannelStream(SoundMixer *mixer, PlayingSoundHandle *handle, void
_endOfBuffer = _ptr + _bufferSize;
_pos = _ptr;
_fpPos = 0;
- _fpSpeed = (1 << 16) * rate / mixer->_outputRate;
+ _fpSpeed = (1 << 16) * rate / mixer->getOutputRate();
_finished = false;
// adjust the magnitude to prevent division error
@@ -768,11 +769,10 @@ void ChannelStream::mix(int16 *data, uint len) {
return;
}
- const int16 *vol_tab = _mixer->_volumeTable;
MixProc *mixProc = mixer_helper_table[_flags & 0x07];
if (_pos < _endOfData) {
- mixProc(data, len, _pos, _fpPos, _fpSpeed, vol_tab, _endOfData, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false);
+ mixProc(data, len, _pos, _fpPos, _fpSpeed, _mixer->getVolume(), _endOfData, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false);
} else {
int wrapOffset = 0;
const uint32 outLen = mixer_element_size[_flags & 0x07] * len;
@@ -785,7 +785,7 @@ void ChannelStream::mix(int16 *data, uint len) {
memcpy(_endOfBuffer, _ptr, wrapOffset);
}
- mixProc(data, len, _pos, _fpPos, _fpSpeed, vol_tab, _endOfBuffer + wrapOffset, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false);
+ mixProc(data, len, _pos, _fpPos, _fpSpeed, _mixer->getVolume(), _endOfBuffer + wrapOffset, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false);
// recover from wrap
if (wrapOffset)
@@ -796,7 +796,7 @@ void ChannelStream::mix(int16 *data, uint len) {
//FIXME: what is wrong ?
warning("bad play sound in stream (wrap around)");
_pos = _ptr;
- mixProc(data, len, _pos, _fpPos, _fpSpeed, vol_tab, _endOfData, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false);
+ mixProc(data, len, _pos, _fpPos, _fpSpeed, _mixer->getVolume(), _endOfData, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false);
}
}
}
@@ -861,12 +861,9 @@ static inline int scale_sample(mad_fixed_t sample) {
}
void ChannelMP3::mix(int16 *data, uint len) {
- mad_fixed_t const * ch;
- const int16 * vol_tab = _mixer->_volumeTable;
- unsigned char volume = ((int)vol_tab[1]) / 8;
+ const int volume = _mixer->getVolume();
while (1) {
- ch = _synth.pcm.samples[0] + _posInFrame;
/* Skip _silence_cut a the start */
if ((_posInFrame < _synth.pcm.length) && (_silenceCut > 0)) {
@@ -875,13 +872,15 @@ void ChannelMP3::mix(int16 *data, uint len) {
if (diff > _silenceCut)
diff = _silenceCut;
_silenceCut -= diff;
- ch += diff;
_posInFrame += diff;
}
+ int16 sample;
while ((_posInFrame < _synth.pcm.length) && (len > 0)) {
- int16 sample = (int16)((scale_sample(*ch++) * volume) / 32);
+ sample = (int16)((scale_sample(_synth.pcm.samples[0][_posInFrame]) * volume) / 256);
clamped_add_16(*data++, sample);
+ if (_synth.pcm.channels > 1)
+ sample = (int16)((scale_sample(_synth.pcm.samples[1][_posInFrame]) * volume) / 256);
clamped_add_16(*data++, sample);
len--;
_posInFrame++;
@@ -925,16 +924,15 @@ ChannelMP3CDMusic::ChannelMP3CDMusic(SoundMixer *mixer, PlayingSoundHandle *hand
}
void ChannelMP3CDMusic::mix(int16 *data, uint len) {
- mad_fixed_t const *ch;
mad_timer_t frame_duration;
- unsigned char volume = _mixer->_musicVolume / 8;
+ int volume = _mixer->getMusicVolume();
if (!_initialized) {
int skip_loop;
// just skipped
memset(_ptr, 0, _bufferSize);
_size = _file->read(_ptr, _bufferSize);
- if (!_size) {
+ if (_size <= 0) {
destroy();
return;
}
@@ -971,18 +969,24 @@ void ChannelMP3CDMusic::mix(int16 *data, uint len) {
}
while (1) {
+
+ // TODO: Check _synth.pcm.samplerate and perform rate conversion of appropriate
+ // TODO: Check _synth.pcm.channels to support stereo
+
// Get samples, play samples ...
- ch = _synth.pcm.samples[0] + _posInFrame;
+ int16 sample;
while ((_posInFrame < _synth.pcm.length) && (len > 0)) {
- int16 sample = (int16)((scale_sample(*ch++) * volume) / 32);
+ sample = (int16)((scale_sample(_synth.pcm.samples[0][_posInFrame]) * volume) / 256);
clamped_add_16(*data++, sample);
+ if (_synth.pcm.channels > 1)
+ sample = (int16)((scale_sample(_synth.pcm.samples[1][_posInFrame]) * volume) / 256);
clamped_add_16(*data++, sample);
len--;
_posInFrame++;
}
- if (len == 0) {
+ if (len == 0)
return;
- }
+
// See if we have finished
// May be incorrect to check the size at the end of a frame but I suppose
// they are short enough :)
@@ -1051,7 +1055,7 @@ void ChannelVorbis::mix(int16 *data, uint len) {
uint len_left = len * channels * 2;
int16 *samples = new int16[len_left / 2];
char *read_pos = (char *) samples;
- int volume = _is_cd_track ? _mixer->_musicVolume : _mixer->_volumeTable[1];
+ int volume = _is_cd_track ? _mixer->getMusicVolume() : _mixer->getVolume();
// Read the samples
while (len_left > 0) {
diff --git a/sound/mixer.h b/sound/mixer.h
index c98f9d4af7..6c7e8edf97 100644
--- a/sound/mixer.h
+++ b/sound/mixer.h
@@ -43,6 +43,7 @@ class Channel;
class File;
class SoundMixer {
+ friend class Channel;
public:
typedef void PremixProc (void *param, int16 *data, uint len);
@@ -50,6 +51,16 @@ public:
NUM_CHANNELS = 16
};
+ enum {
+ // Do *NOT* change any of these flags without looking at the code in mixer.cpp
+ FLAG_UNSIGNED = 1 << 0, // unsigned samples (default: signed)
+ FLAG_STEREO = 1 << 1, // sound is in stereo (default: mono)
+ FLAG_16BITS = 1 << 2, // sound is 16 bits wide (default: 8bit)
+ FLAG_AUTOFREE = 1 << 3, // sound buffer is freed automagically at the end of playing
+ FLAG_REVERSE_STEREO = 1 << 4, // reverse the left and right stereo channel
+ FLAG_LOOP = 1 << 5 // loop the audio
+ };
+
private:
OSystem *_syst;
OSystem::MutexRef _mutex;
@@ -57,10 +68,9 @@ private:
void *_premixParam;
PremixProc *_premixProc;
-public:
uint _outputRate;
- int16 *_volumeTable;
+ int _globalVolume;
int _musicVolume;
bool _paused;
@@ -72,15 +82,6 @@ public:
~SoundMixer();
// start playing a raw sound
- enum {
- // Do *NOT* change any of these flags without looking at the code in mixer.cpp
- FLAG_UNSIGNED = 1 << 0, // unsigned samples
- FLAG_STEREO = 1 << 1, // sound is in stereo
- FLAG_16BITS = 1 << 2, // sound is 16 bits wide
- FLAG_AUTOFREE = 1 << 3, // sound buffer is freed automagically at the end of playing
- FLAG_REVERSE_STEREO = 1 << 4, // sound should be reverse stereo
- FLAG_LOOP = 1 << 5 // loop the audio
- };
int playRaw(PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags, int id = -1);
#ifdef USE_MAD
int playMP3(PlayingSoundHandle *handle, void *sound, uint32 size, byte flags);
@@ -118,21 +119,33 @@ public:
bool hasActiveSFXChannel();
/** Check whether the specified channel is active. */
- bool isActiveChannel(int index);
+ bool isChannelActive(int index);
+
+ /** Check whether the specified channel is in use. */
+ bool isChannelUsed(int index);
/** bind to the OSystem object => mixer will be
* invoked automatically when samples need
* to be generated */
bool bindToSystem(OSystem *syst);
+ /** pause - unpause */
+ void pause(bool paused);
+
/** set the global volume, 0-256 */
void setVolume(int volume);
+
+ /** query the global volume, 0-256 */
+ int getVolume() const { return _globalVolume; }
/** set the music volume, 0-256 */
void setMusicVolume(int volume);
-
- /** pause - unpause */
- void pause(bool paused);
+
+ /** query the music volume, 0-256 */
+ int getMusicVolume() const { return _musicVolume; }
+
+ /** query the output rate in kHz */
+ uint getOutputRate() const { return _outputRate; }
private:
int insertChannel(PlayingSoundHandle *handle, Channel *chan);
@@ -140,7 +153,7 @@ private:
/** mix */
void mix(int16 * buf, uint len);
- static void onGenerateSamples(void *s, byte *samples, int len);
+ static void mixCallback(void *s, byte *samples, int len);
};
#endif