aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorLionel Ulmer2002-06-02 20:30:21 +0000
committerLionel Ulmer2002-06-02 20:30:21 +0000
commit8b7207666e236988ebd568eeaa5386314f90cdb9 (patch)
tree8e861c514cc01fb411888582018a5699064e7995 /sound
parent4387c22d30298575b2c5a193d0b61a3080a9bd8c (diff)
downloadscummvm-rg350-8b7207666e236988ebd568eeaa5386314f90cdb9.tar.gz
scummvm-rg350-8b7207666e236988ebd568eeaa5386314f90cdb9.tar.bz2
scummvm-rg350-8b7207666e236988ebd568eeaa5386314f90cdb9.zip
Fix the streaming used in the movies in TheDig (warning, did not test
Full Throttle). This should be less buggy (ie crash less often, maybe not better quality) than the previous code. NOTE: the '1024 *' is here for testing purposes and will need to be severely reduced :-/ svn-id: r4396
Diffstat (limited to 'sound')
-rw-r--r--sound/mixer.cpp211
-rw-r--r--sound/mixer.h26
2 files changed, 175 insertions, 62 deletions
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);