diff options
author | Lionel Ulmer | 2002-06-02 20:30:21 +0000 |
---|---|---|
committer | Lionel Ulmer | 2002-06-02 20:30:21 +0000 |
commit | 8b7207666e236988ebd568eeaa5386314f90cdb9 (patch) | |
tree | 8e861c514cc01fb411888582018a5699064e7995 | |
parent | 4387c22d30298575b2c5a193d0b61a3080a9bd8c (diff) | |
download | scummvm-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
-rw-r--r-- | insane.cpp | 29 | ||||
-rw-r--r-- | sound/mixer.cpp | 211 | ||||
-rw-r--r-- | sound/mixer.h | 26 |
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); |