aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--insane.cpp29
-rw-r--r--sound/mixer.cpp211
-rw-r--r--sound/mixer.h26
3 files changed, 195 insertions, 71 deletions
diff --git a/insane.cpp b/insane.cpp
index fbaa7f1cb9..067b5a566b 100644
--- a/insane.cpp
+++ b/insane.cpp
@@ -133,6 +133,7 @@ void SmushPlayer::parseAHDR()
void SmushPlayer::parseIACT() {
unsigned int pos, bpos, tag, sublen, subpos, trk, idx, flags;
+ bool new_mixer = false;
byte * buf;
flags = SoundMixer::FLAG_AUTOFREE;
@@ -156,13 +157,14 @@ void SmushPlayer::parseIACT() {
g_scumm->_mixer->_channels[idx] == NULL) {
_imusTrk[idx] = trk;
_imusSize[idx] = 0;
+ new_mixer = true;
break;
}
}
}
if (idx == 8) {
- warning("iMUS table full\n");
+ warning("iMUS table full ");
return;
}
@@ -256,8 +258,11 @@ void SmushPlayer::parseIACT() {
debug(3, "trk %d: iMUSE play part, len 0x%x rate %d remain 0x%x",
trk, bpos, _imusRate[idx], _imusSubSize[idx]);
- g_scumm->_mixer->append(idx, buf, bpos,
- _imusRate[idx], flags);
+ if (new_mixer) {
+ g_scumm->_mixer->play_stream(NULL, idx, buf, bpos, _imusRate[idx], flags);
+ } else {
+ g_scumm->_mixer->append(idx, buf, bpos, _imusRate[idx], flags);
+ }
/* FIXME: append with re-used idx may cause problems
with signed/unsigned issues */
@@ -785,6 +790,7 @@ void SmushPlayer::parseFOBJ()
void SmushPlayer::parsePSAD() // FIXME: Needs to append to
{ // a sound buffer
unsigned int pos, sublen, tag, idx, trk;
+ bool new_mixer = false;
byte * buf;
pos = 0;
@@ -802,9 +808,10 @@ void SmushPlayer::parsePSAD() // FIXME: Needs to append to
for (idx = 0; idx < 8; idx++) {
if (_psadTrk[idx] == 0 &&
g_scumm->_mixer->_channels[idx] == NULL) {
- _psadTrk[idx] = trk;
- _saudSize[idx] = 0;
- break;
+ _psadTrk[idx] = trk;
+ _saudSize[idx] = 0;
+ new_mixer = true;
+ break;
}
}
}
@@ -852,9 +859,13 @@ void SmushPlayer::parsePSAD() // FIXME: Needs to append to
debug(3, "trk %d: SDAT part len 0x%x rate %d",
trk, sublen, _strkRate[idx]);
-
- g_scumm->_mixer->append(idx, buf, sublen,
- _strkRate[idx], SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
+
+ if (new_mixer) {
+ g_scumm->_mixer->play_stream(NULL, idx, buf, sublen, _strkRate[idx], SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
+ } else {
+ g_scumm->_mixer->append(idx, buf, sublen,
+ _strkRate[idx], SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
+ }
break;
case 'SMRK' :
_psadTrk[idx] = 0;
diff --git a/sound/mixer.cpp b/sound/mixer.cpp
index a804d60f39..723b790e38 100644
--- a/sound/mixer.cpp
+++ b/sound/mixer.cpp
@@ -39,25 +39,32 @@ void SoundMixer::uninsert(Channel *chan) {
}
int SoundMixer::append(int index, void *sound, uint32 size, uint rate, byte flags) {
- Channel *chan = _channels[index];
- if (!chan) {
- chan = new Channel_RAW(this, sound, size, rate, flags);
- _channels[index] = chan;
- return 0;
- }
+ Channel *chan = _channels[index];
+ if (!chan) {
+ warning("Trying to stream to an unexistant streamer ");
+ play_stream(NULL, index, sound, size, rate, flags);
+ chan = _channels[index];
+ }
- chan->append(sound, size);
- return 1;
+ chan->append(sound, size);
+ return 1;
+}
+
+int SoundMixer::insert_at(PlayingSoundHandle *handle, int index, Channel *chan) {
+ if (_channels[index] != NULL) {
+ error("Trying to put a mixer where it cannot go ");
+ }
+ _channels[index] = chan;
+ _handles[index] = handle;
+ if (handle)
+ *handle = index + 1;
+ return index;
}
int SoundMixer::insert(PlayingSoundHandle *handle, Channel *chan) {
for(int i=0; i!=NUM_CHANNELS; i++) {
if (_channels[i] == NULL) {
- _channels[i] = chan;
- _handles[i] = handle;
- if (handle)
- *handle = i + 1;
- return i;
+ return insert_at(handle, i, chan);
}
}
@@ -72,6 +79,10 @@ int SoundMixer::play_raw(PlayingSoundHandle *handle, void *sound, uint32 size, u
return insert(handle, new Channel_RAW(this, sound, size, rate, flags));
}
+int SoundMixer::play_stream(PlayingSoundHandle *handle, int idx, void *sound, uint32 size, uint rate, byte flags) {
+ return insert_at(handle, idx, new Channel_STREAM(this, sound, size, rate, flags));
+}
+
#ifdef COMPRESSED_SOUND_FILE
int SoundMixer::play_mp3(PlayingSoundHandle *handle, void *sound, uint32 size, byte flags) {
return insert(handle, new Channel_MP3(this, sound, size, flags));
@@ -162,11 +173,15 @@ void SoundMixer::set_volume(int volume) {
#ifdef COMPRESSED_SOUND_FILE
bool SoundMixer::Channel::sound_finished() {
- warning("Should never be called on a non-MP3 mixer ");
+ warning("sound_finished should never be called on a non-MP3 mixer ");
return false;
}
#endif
+void SoundMixer::Channel::append(void *sound, uint32 size) {
+ error("append method should never be called on something else than a _STREAM mixer ");
+}
+
/* RAW mixer */
SoundMixer::Channel_RAW::Channel_RAW(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags) {
_mixer = mixer;
@@ -188,84 +203,70 @@ SoundMixer::Channel_RAW::Channel_RAW(SoundMixer *mixer, void *sound, uint32 size
if (_flags & FLAG_STEREO) _size = _size >> 1;
}
-void SoundMixer::Channel_RAW::append(void *data, uint32 len) {
- int _cur_size;
- void *holder;
-
- _mixer->_paused = true; /* Don't mix while we do this */
-
- /* Init our variables */
- _cur_size = _realsize - _pos;
- holder = malloc(len + _cur_size);
-
- /* Prepare the new buffer */
- memcpy(holder, (byte*)_ptr + _pos, _cur_size);
- memcpy((byte *)holder + _cur_size, data, len);
-
- /* Quietly slip in the new data */
- if (_flags & FLAG_AUTOFREE) free(_ptr);
- _ptr = holder;
-
- /* Reset sizes */
- _realsize = _cur_size + len;
- _size = _realsize * _mixer->_output_rate / _rate;
- if (_flags & FLAG_16BITS) _size = _size >> 1;
- if (_flags & FLAG_STEREO) _size = _size >> 1;
- _pos = 0;
- _fp_pos = 0;
-
- _mixer->_paused = false; /* Mix again now */
-}
-
-static void mix_signed_mono_8(int16 *data, uint len, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab) {
+static int16 *mix_signed_mono_8(int16 *data, uint *len_ptr, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab, byte *s_end) {
uint32 fp_pos = *fp_pos_ptr;
byte *s = *s_ptr;
+ uint len = *len_ptr;
do {
fp_pos += fp_speed;
*data++ += vol_tab[*s];
*data++ += vol_tab[*s];
s += fp_pos >> 16;
fp_pos &= 0x0000FFFF;
- } while (--len);
+ } while ((--len) && (s < s_end));
*fp_pos_ptr = fp_pos;
*s_ptr = s;
+ *len_ptr = len;
+
+ return data;
}
-static void mix_unsigned_mono_8(int16 *data, uint len, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab) {
+static int16 *mix_unsigned_mono_8(int16 *data, uint *len_ptr, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab, byte *s_end) {
uint32 fp_pos = *fp_pos_ptr;
byte *s = *s_ptr;
+ uint len = *len_ptr;
do {
fp_pos += fp_speed;
*data++ += vol_tab[*s ^ 0x80];
*data++ += vol_tab[*s ^ 0x80];
s += fp_pos >> 16;
fp_pos &= 0x0000FFFF;
- } while (--len);
+ } while ((--len) && (s < s_end));
*fp_pos_ptr = fp_pos;
*s_ptr = s;
+ *len_ptr = len;
+
+ return data;
}
-static void mix_signed_stereo_8(int16 *data, uint len, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab) {
+static int16 *mix_signed_stereo_8(int16 *data, uint *len_ptr, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab, byte *s_end) {
warning("Mixing stereo signed 8 bit is not supported yet ");
+
+ return data;
}
-static void mix_unsigned_stereo_8(int16 *data, uint len, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab) {
+static int16 *mix_unsigned_stereo_8(int16 *data, uint *len_ptr, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab, byte *s_end) {
uint32 fp_pos = *fp_pos_ptr;
byte *s = *s_ptr;
+ uint len = *len_ptr;
do {
fp_pos += fp_speed;
*data++ += vol_tab[*s ^ 0x80];
*data++ += vol_tab[*(s + 1) ^ 0x80];
s += (fp_pos >> 16) << 1;
fp_pos &= 0x0000FFFF;
- } while (--len);
+ } while ((--len) && (s < s_end));
*fp_pos_ptr = fp_pos;
*s_ptr = s;
+ *len_ptr = len;
+
+ return data;
}
-static void mix_signed_mono_16(int16 *data, uint len, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab) {
+static int16 *mix_signed_mono_16(int16 *data, uint *len_ptr, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab, byte *s_end) {
uint32 fp_pos = *fp_pos_ptr;
unsigned char volume = ((int) vol_tab[1]) * 32 / 255;
byte *s = *s_ptr;
+ uint len = *len_ptr;
do {
int16 sample = (((int16)(*s << 8) | *(s + 1)) * volume) / 32;
fp_pos += fp_speed;
@@ -273,34 +274,45 @@ static void mix_signed_mono_16(int16 *data, uint len, byte **s_ptr, uint32 *fp_p
*data++ += sample;
s += (fp_pos >> 16) << 1;
fp_pos &= 0x0000FFFF;
- } while (--len);
+ } while ((--len) && (s < s_end));
*fp_pos_ptr = fp_pos;
*s_ptr = s;
+ *len_ptr = len;
+
+ return data;
}
-static void mix_unsigned_mono_16(int16 *data, uint len, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab) {
+static int16 *mix_unsigned_mono_16(int16 *data, uint *len_ptr, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab, byte *s_end) {
warning("Mixing mono unsigned 16 bit is not supported yet ");
+
+ return data;
}
-static void mix_signed_stereo_16(int16 *data, uint len, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab) {
+static int16 *mix_signed_stereo_16(int16 *data, uint *len_ptr, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab, byte *s_end) {
uint32 fp_pos = *fp_pos_ptr;
unsigned char volume = ((int) vol_tab[1]) * 32 / 255;
byte *s = *s_ptr;
+ uint len = *len_ptr;
do {
fp_pos += fp_speed;
*data++ += (((int16)(*(s ) << 8) | *(s + 1)) * volume) / 32;
*data++ += (((int16)(*(s + 2) << 8) | *(s + 3)) * volume) / 32;
s += (fp_pos >> 16) << 2;
fp_pos &= 0x0000FFFF;
- } while (--len);
+ } while ((--len) && (s < s_end));
*fp_pos_ptr = fp_pos;
*s_ptr = s;
+ *len_ptr = len;
+
+ return data;
}
-static void mix_unsigned_stereo_16(int16 *data, uint len, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab) {
+static int16 *mix_unsigned_stereo_16(int16 *data, uint *len_ptr, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab, byte *s_end) {
warning("Mixing stereo unsigned 16 bit is not supported yet ");
+
+ return data;
}
-static void (*mixer_helper_table[16])(int16 *data, uint len, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab) = {
+static int16 *(*mixer_helper_table[16])(int16 *data, uint *len_ptr, byte **s_ptr, uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab, byte *s_end) = {
mix_signed_mono_8,
mix_unsigned_mono_8,
mix_signed_stereo_8,
@@ -349,7 +361,7 @@ void SoundMixer::Channel_RAW::mix(int16 *data, uint len) {
const uint32 fp_speed = _fp_speed;
const int16 *vol_tab = _mixer->_volume_table;
- mixer_helper_table[_flags & 0x07](data, len, &s, &fp_pos, fp_speed, vol_tab);
+ mixer_helper_table[_flags & 0x07](data, &len, &s, &fp_pos, fp_speed, vol_tab, (byte *) _ptr + _realsize);
_pos = s - (byte*) _ptr;
_fp_pos = fp_pos;
@@ -370,6 +382,89 @@ void SoundMixer::Channel_RAW::real_destroy() {
delete this;
}
+/* STREAM mixer */
+SoundMixer::Channel_STREAM::Channel_STREAM(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags) {
+ _mixer = mixer;
+ _flags = flags;
+ _buffer_size = 1024 * size;
+ _ptr = (byte *) malloc(_buffer_size);
+ memcpy(_ptr, sound, size);
+ _end_of_data = _ptr + size;
+ if (_flags & FLAG_AUTOFREE)
+ free(sound);
+ _pos = _ptr;
+ _fp_pos = 0;
+ _fp_speed = (1 << 16) * rate / mixer->_output_rate;
+ _to_be_destroyed = false;
+
+ /* adjust the magnitute to prevent division error */
+ while (size & 0xFFFF0000)
+ size >>= 1, rate = (rate>>1) + 1;
+
+
+ _rate = rate;
+}
+
+void SoundMixer::Channel_STREAM::append(void *data, uint32 len) {
+ byte *new_end = _end_of_data + len;
+ byte *cur_pos = _pos; /* This is just to prevent the variable to move during the tests :-) */
+
+ if (new_end > (_ptr + _buffer_size)) {
+ /* Wrap-around case */
+ if ((_end_of_data < cur_pos) ||
+ (new_end >= cur_pos)) {
+ warning("Mixer full... Trying to not break too much ");
+ return;
+ } memcpy(_end_of_data, data, (_ptr + _buffer_size) - _end_of_data);
+ memcpy(_ptr, (byte *) data + ((_ptr + _buffer_size) - _end_of_data), len - ((_ptr + _buffer_size) - _end_of_data));
+ } else {
+ if ((_end_of_data < cur_pos) &&
+ (new_end >= cur_pos)) {
+ warning("Mixer full... Trying to not break too much ");
+ return;
+ }
+ memcpy(_end_of_data, data, len);
+ }
+ _end_of_data = new_end;
+}
+
+void SoundMixer::Channel_STREAM::mix(int16 *data, uint len) {
+ uint32 fp_pos;
+ const uint32 fp_speed = _fp_speed;
+ const int16 *vol_tab = _mixer->_volume_table;
+ byte *end_of_data = _end_of_data;
+
+ if (_to_be_destroyed) {
+ real_destroy();
+ return;
+ }
+
+ fp_pos = _fp_pos;
+
+ if (_pos < end_of_data) {
+ mixer_helper_table[_flags & 0x07](data, &len, &_pos, &fp_pos, fp_speed, vol_tab, end_of_data);
+ } else {
+ mixer_helper_table[_flags & 0x07](data, &len, &_pos, &fp_pos, fp_speed, vol_tab, _ptr + _buffer_size);
+ if (len != 0) {
+ _pos = _ptr;
+ mixer_helper_table[_flags & 0x07](data, &len, &_pos, &fp_pos, fp_speed, vol_tab, end_of_data);
+ }
+ }
+ if (len != 0) {
+ warning("Streaming underflow ");
+ real_destroy();
+ return;
+ }
+ _fp_pos = fp_pos;
+}
+
+void SoundMixer::Channel_STREAM::real_destroy() {
+ free(_ptr);
+ _mixer->uninsert(this);
+ delete this;
+}
+
+
/* MP3 mixer goes here */
#ifdef COMPRESSED_SOUND_FILE
diff --git a/sound/mixer.h b/sound/mixer.h
index fc9d687f15..99b36903bb 100644
--- a/sound/mixer.h
+++ b/sound/mixer.h
@@ -36,7 +36,7 @@ private:
virtual void mix(int16 *data, uint len) = 0;
void destroy() { _to_be_destroyed = true; }
virtual void real_destroy() = 0;
- virtual void append(void *sound, uint32 size) = 0;
+ virtual void append(void *sound, uint32 size);
#ifdef COMPRESSED_SOUND_FILE
virtual bool sound_finished();
#endif
@@ -54,12 +54,30 @@ private:
public:
- void append(void *sound, uint32 size);
void mix(int16 *data, uint len);
Channel_RAW(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags);
void real_destroy();
};
+ class Channel_STREAM : public Channel {
+ SoundMixer *_mixer;
+ byte *_ptr;
+ byte *_end_of_data;
+ byte *_pos;
+ uint32 _fp_speed;
+ uint32 _fp_pos;
+ uint32 _buffer_size;
+ uint32 _rate;
+ byte _flags;
+
+
+ public:
+ void append(void *sound, uint32 size);
+ void mix(int16 *data, uint len);
+ Channel_STREAM(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags);
+ void real_destroy();
+ };
+
#ifdef COMPRESSED_SOUND_FILE
class Channel_MP3 : public Channel {
@@ -75,7 +93,6 @@ private:
byte _flags;
public:
- virtual void append(void *sound, uint32 size) {} // FIXME, FAKE
void mix(int16 *data, uint len);
Channel_MP3(SoundMixer *mixer, void *sound, uint size, byte flags);
void real_destroy();
@@ -95,7 +112,6 @@ private:
FILE *_file;
bool _initialized;
public:
- virtual void append(void *sound, uint32 size) {} // FIXME, FAKE
void mix(int16 *data, uint len);
Channel_MP3_CDMUSIC(SoundMixer *mixer, FILE* file, mad_timer_t duration);
void real_destroy();
@@ -126,6 +142,7 @@ public:
PlayingSoundHandle *_handles[NUM_CHANNELS];
int insert(PlayingSoundHandle *handle, Channel *chan);
+ int insert_at(PlayingSoundHandle *handle, int index, Channel *chan);
void append(void *data, uint32 len);
void uninsert(Channel *chan);
@@ -139,6 +156,7 @@ public:
FLAG_FILE = 16, /* sound is a FILE * that's read from */
};
int play_raw(PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags);
+ int play_stream(PlayingSoundHandle *handle, int index, void *sound, uint32 size, uint rate, byte flags);
#ifdef COMPRESSED_SOUND_FILE
int play_mp3(PlayingSoundHandle *handle, void *sound, uint32 size, byte flags);
int play_mp3_cdtrack(PlayingSoundHandle *handle, FILE* file, mad_timer_t duration);