diff options
-rw-r--r-- | scumm/sound.h | 8 | ||||
-rw-r--r-- | sound/mixer.cpp | 231 | ||||
-rw-r--r-- | sound/mixer.h | 186 |
3 files changed, 213 insertions, 212 deletions
diff --git a/scumm/sound.h b/scumm/sound.h index 32fa39c183..ce50c3a198 100644 --- a/scumm/sound.h +++ b/scumm/sound.h @@ -26,7 +26,13 @@ class DigitalTrackInfo; class File; class Scumm; -struct MP3OffsetTable; + +struct MP3OffsetTable { /* Compressed Sound (.SO3) */ + int org_offset; + int new_offset; + int num_tags; + int compressed_size; +}; class Sound { protected: diff --git a/sound/mixer.cpp b/sound/mixer.cpp index 4d444b8626..f68a99a2cb 100644 --- a/sound/mixer.cpp +++ b/sound/mixer.cpp @@ -25,6 +25,111 @@ #include "common/engine.h" // for warning/error/debug #include "common/file.h" + +class ChannelRaw : public Channel { + SoundMixer *_mixer; + void *_ptr; + uint32 _pos; + uint32 _size; + uint32 _fpSpeed; + uint32 _fpPos; + uint32 _realSize, _rate; + byte _flags; + void *_loop_ptr; + uint32 _loop_size; + +public: + ChannelRaw(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags, int id); + + void mix(int16 *data, uint len); + void realDestroy(); +}; + +class ChannelStream : public Channel { + SoundMixer *_mixer; + byte *_ptr; + byte *_endOfData; + byte *_endOfBuffer; + byte *_pos; + uint32 _fpSpeed; + uint32 _fpPos; + uint32 _bufferSize; + uint32 _rate; + int32 _timeOut; + int32 _setTimeOut; + byte _flags; + +public: + ChannelStream(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags, int32 timout, int32 buffer_size); + + void append(void *sound, uint32 size); + void mix(int16 *data, uint len); + void realDestroy(); +}; + +#ifdef USE_MAD + +class ChannelMP3 : public Channel { + SoundMixer *_mixer; + void *_ptr; + struct mad_stream _stream; + struct mad_frame _frame; + struct mad_synth _synth; + uint32 _silenceCut; + uint32 _posInFrame; + uint32 _position; + uint32 _size; + byte _flags; + +public: + ChannelMP3(SoundMixer *mixer, void *sound, uint size, byte flags); + + void mix(int16 *data, uint len); + void realDestroy(); + +}; + +class ChannelMP3CDMusic:public Channel { + SoundMixer *_mixer; + void *_ptr; + struct mad_stream _stream; + struct mad_frame _frame; + struct mad_synth _synth; + uint32 _posInFrame; + uint32 _size; + uint32 _bufferSize; + mad_timer_t _duration; + File *_file; + bool _initialized; + + +public: + ChannelMP3CDMusic(SoundMixer *mixer, File *file, mad_timer_t duration); + + void mix(int16 *data, uint len); + void realDestroy(); + bool soundFinished(); +}; + +#endif + +#ifdef USE_VORBIS +class ChannelVorbis : public Channel { + SoundMixer *_mixer; + OggVorbis_File *_ov_file; + int _end_pos; + bool _eof_flag, _is_cd_track; + +public: + ChannelVorbis(SoundMixer *mixer, OggVorbis_File *ov_file, int duration, bool is_cd_track); + + void mix(int16 *data, uint len); + void realDestroy(); + bool soundFinished(); +}; +#endif + + SoundMixer::SoundMixer() { memset(this,0,sizeof(SoundMixer)); // palmos @@ -264,44 +369,6 @@ void SoundMixer::setMusicVolume(int volume) { _musicVolume = volume; } -bool SoundMixer::Channel::soundFinished() { - warning("sound_finished should never be called on a non-MP3 mixer "); - return false; -} - -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::ChannelRaw::ChannelRaw(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags, int id) { - _id = id; - _mixer = mixer; - _flags = flags; - _ptr = sound; - _pos = 0; - _fpPos = 0; - _fpSpeed = (1 << 16) * rate / mixer->_outputRate; - _toBeDestroyed = false; - _realSize = size; - - // adjust the magnitude to prevent division error - while (size & 0xFFFF0000) - size >>= 1, rate = (rate >> 1) + 1; - - _rate = rate; - _size = size * mixer->_outputRate / rate; - if (_flags & FLAG_16BITS) - _size = _size >> 1; - if (_flags & FLAG_STEREO) - _size = _size >> 1; - - if (flags & FLAG_LOOP) { - _loop_ptr = _ptr; - _loop_size = _size; - } -} - /* * Class that performs cubic interpolation on integer data. * It is expected that the data is equidistant, i.e. all have the same @@ -581,7 +648,45 @@ static int16 mixer_element_size[] = { 4, 4 }; -void SoundMixer::ChannelRaw::mix(int16 *data, uint len) { +bool Channel::soundFinished() { + warning("sound_finished should never be called on a non-MP3 mixer "); + return false; +} + +void Channel::append(void *sound, uint32 size) { + error("append method should never be called on something else than a _STREAM mixer "); +} + +/* RAW mixer */ +ChannelRaw::ChannelRaw(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags, int id) { + _id = id; + _mixer = mixer; + _flags = flags; + _ptr = sound; + _pos = 0; + _fpPos = 0; + _fpSpeed = (1 << 16) * rate / mixer->_outputRate; + _toBeDestroyed = false; + _realSize = size; + + // adjust the magnitude to prevent division error + while (size & 0xFFFF0000) + size >>= 1, rate = (rate >> 1) + 1; + + _rate = rate; + _size = size * mixer->_outputRate / rate; + if (_flags & SoundMixer::FLAG_16BITS) + _size = _size >> 1; + if (_flags & SoundMixer::FLAG_STEREO) + _size = _size >> 1; + + if (flags & SoundMixer::FLAG_LOOP) { + _loop_ptr = _ptr; + _loop_size = _size; + } +} + +void ChannelRaw::mix(int16 *data, uint len) { byte *s, *end; if (_toBeDestroyed) { @@ -599,12 +704,12 @@ void SoundMixer::ChannelRaw::mix(int16 *data, uint len) { const uint32 fp_speed = _fpSpeed; const int16 *vol_tab = _mixer->_volumeTable; - mixer_helper_table[_flags & 0x07] (data, &len, &s, &_fpPos, fp_speed, vol_tab, end, (_flags & FLAG_REVERSE_STEREO) ? true : false); + mixer_helper_table[_flags & 0x07] (data, &len, &s, &_fpPos, fp_speed, vol_tab, end, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false); _pos = s - (byte *)_ptr; if (_size < 1) { - if (_flags & FLAG_LOOP) { + if (_flags & SoundMixer::FLAG_LOOP) { _ptr = _loop_ptr; _size = _loop_size; _pos = 0; @@ -616,8 +721,8 @@ void SoundMixer::ChannelRaw::mix(int16 *data, uint len) { } -void SoundMixer::ChannelRaw::realDestroy() { - if (_flags & FLAG_AUTOFREE) +void ChannelRaw::realDestroy() { + if (_flags & SoundMixer::FLAG_AUTOFREE) free(_ptr); _mixer->unInsert(this); delete this; @@ -625,7 +730,7 @@ void SoundMixer::ChannelRaw::realDestroy() { #define WARP_WORKAROUND 50000 -SoundMixer::ChannelStream::ChannelStream(SoundMixer *mixer, void *sound, uint32 size, uint rate, +ChannelStream::ChannelStream(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags, int32 timeout, int32 buffer_size) { _mixer = mixer; _flags = flags; @@ -634,7 +739,7 @@ SoundMixer::ChannelStream::ChannelStream(SoundMixer *mixer, void *sound, uint32 memcpy(_ptr, sound, size); _endOfData = _ptr + size; _endOfBuffer = _ptr + _bufferSize; - if (_flags & FLAG_AUTOFREE) + if (_flags & SoundMixer::FLAG_AUTOFREE) free(sound); _pos = _ptr; _fpPos = 0; @@ -649,7 +754,7 @@ SoundMixer::ChannelStream::ChannelStream(SoundMixer *mixer, void *sound, uint32 _rate = rate; } -void SoundMixer::ChannelStream::append(void *data, uint32 len) { +void ChannelStream::append(void *data, uint32 len) { byte *new_end = _endOfData + len; byte *cur_pos = _pos; /* This is just to prevent the variable to move during the tests :-) */ if (new_end > (_ptr + _bufferSize)) { @@ -673,7 +778,7 @@ void SoundMixer::ChannelStream::append(void *data, uint32 len) { _endOfData = new_end; } -void SoundMixer::ChannelStream::mix(int16 *data, uint len) { +void ChannelStream::mix(int16 *data, uint len) { uint32 fp_pos; const uint32 fp_speed = _fpSpeed; const int16 *vol_tab = _mixer->_volumeTable; @@ -697,7 +802,7 @@ void SoundMixer::ChannelStream::mix(int16 *data, uint len) { fp_pos = _fpPos; if (_pos < end_of_data) { - mixer_helper_table[_flags & 0x07] (data, &len, &_pos, &fp_pos, fp_speed, vol_tab, end_of_data, (_flags & FLAG_REVERSE_STEREO) ? true : false); + mixer_helper_table[_flags & 0x07] (data, &len, &_pos, &fp_pos, fp_speed, vol_tab, end_of_data, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false); } else { int wrap_offset = 0; @@ -709,7 +814,7 @@ void SoundMixer::ChannelStream::mix(int16 *data, uint len) { } - mixer_helper_table[_flags & 0x07] (data, &len, &_pos, &fp_pos, fp_speed, vol_tab, _endOfBuffer + wrap_offset, (_flags & FLAG_REVERSE_STEREO) ? true : false); + mixer_helper_table[_flags & 0x07] (data, &len, &_pos, &fp_pos, fp_speed, vol_tab, _endOfBuffer + wrap_offset, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false); // recover from wrap if (wrap_offset) @@ -720,21 +825,21 @@ void SoundMixer::ChannelStream::mix(int16 *data, uint len) { //FIXME: what is wrong ? warning("bad play sound in stream(wrap around)"); _pos = _ptr; - mixer_helper_table[_flags & 0x07] (data, &len, &_pos, &fp_pos, fp_speed, vol_tab, end_of_data, (_flags & FLAG_REVERSE_STEREO) ? true : false); + mixer_helper_table[_flags & 0x07] (data, &len, &_pos, &fp_pos, fp_speed, vol_tab, end_of_data, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false); } } _timeOut = _setTimeOut; _fpPos = fp_pos; } -void SoundMixer::ChannelStream::realDestroy() { +void ChannelStream::realDestroy() { free(_ptr); _mixer->unInsert(this); delete this; } #ifdef USE_MAD -SoundMixer::ChannelMP3::ChannelMP3(SoundMixer *mixer, void *sound, uint size, byte flags) { +ChannelMP3::ChannelMP3(SoundMixer *mixer, void *sound, uint size, byte flags) { _mixer = mixer; _flags = flags; _posInFrame = 0xFFFFFFFF; @@ -780,7 +885,7 @@ static inline int scale_sample(mad_fixed_t sample) { return sample >> (MAD_F_FRACBITS + 1 - 16); } -void SoundMixer::ChannelMP3::mix(int16 *data, uint len) { +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; @@ -840,8 +945,8 @@ void SoundMixer::ChannelMP3::mix(int16 *data, uint len) { } } -void SoundMixer::ChannelMP3::realDestroy() { - if (_flags & FLAG_AUTOFREE) +void ChannelMP3::realDestroy() { + if (_flags & SoundMixer::FLAG_AUTOFREE) free(_ptr); _mixer->unInsert(this); mad_synth_finish(&_synth); @@ -853,7 +958,7 @@ void SoundMixer::ChannelMP3::realDestroy() { #define MP3CD_BUFFERING_SIZE 131072 -SoundMixer::ChannelMP3CDMusic::ChannelMP3CDMusic(SoundMixer *mixer, File *file, +ChannelMP3CDMusic::ChannelMP3CDMusic(SoundMixer *mixer, File *file, mad_timer_t duration){ _mixer = mixer; _file = file; @@ -873,7 +978,7 @@ SoundMixer::ChannelMP3CDMusic::ChannelMP3CDMusic(SoundMixer *mixer, File *file, mad_synth_init(&_synth); } -void SoundMixer::ChannelMP3CDMusic::mix(int16 *data, uint len) { +void ChannelMP3CDMusic::mix(int16 *data, uint len) { mad_fixed_t const *ch; mad_timer_t frame_duration; unsigned char volume = _mixer->_musicVolume / 8; @@ -973,11 +1078,11 @@ void SoundMixer::ChannelMP3CDMusic::mix(int16 *data, uint len) { } } -bool SoundMixer::ChannelMP3CDMusic::soundFinished() { +bool ChannelMP3CDMusic::soundFinished() { return mad_timer_compare(_duration, mad_timer_zero) <= 0; } -void SoundMixer::ChannelMP3CDMusic::realDestroy() { +void ChannelMP3CDMusic::realDestroy() { free(_ptr); _mixer->unInsert(this); mad_synth_finish(&_synth); @@ -990,7 +1095,7 @@ void SoundMixer::ChannelMP3CDMusic::realDestroy() { #endif #ifdef USE_VORBIS -SoundMixer::ChannelVorbis::ChannelVorbis(SoundMixer *mixer, OggVorbis_File *ov_file, int duration, bool is_cd_track) { +ChannelVorbis::ChannelVorbis(SoundMixer *mixer, OggVorbis_File *ov_file, int duration, bool is_cd_track) { _mixer = mixer; _ov_file = ov_file; @@ -1004,7 +1109,7 @@ SoundMixer::ChannelVorbis::ChannelVorbis(SoundMixer *mixer, OggVorbis_File *ov_f _toBeDestroyed = false; } -void SoundMixer::ChannelVorbis::mix(int16 *data, uint len) { +void ChannelVorbis::mix(int16 *data, uint len) { if (_toBeDestroyed) { realDestroy(); return; @@ -1071,12 +1176,12 @@ void SoundMixer::ChannelVorbis::mix(int16 *data, uint len) { realDestroy(); } -void SoundMixer::ChannelVorbis::realDestroy() { +void ChannelVorbis::realDestroy() { _mixer->unInsert(this); delete this; } -bool SoundMixer::ChannelVorbis::soundFinished() { +bool ChannelVorbis::soundFinished() { return _eof_flag || (_end_pos > 0 && ov_pcm_tell(_ov_file) >= _end_pos); } diff --git a/sound/mixer.h b/sound/mixer.h index d98c670098..60be556dc1 100644 --- a/sound/mixer.h +++ b/sound/mixer.h @@ -26,151 +26,55 @@ #if defined(HAVE_CONFIG_H) #include "config.h" #endif - -#include <stdio.h> - #ifdef USE_MAD #include <mad.h> #endif - #ifdef USE_VORBIS #include <vorbis/vorbisfile.h> #endif - +#include <stdio.h> #include "common/scummsys.h" #include "common/system.h" + typedef uint32 PlayingSoundHandle; class File; -class SoundMixer { -private: - class Channel { - public: - bool _toBeDestroyed; - int _id; - Channel() : _id(-1) {} - virtual void mix(int16 *data, uint len) = 0; - void destroy() { - _toBeDestroyed = true; - } - virtual void realDestroy() = 0; - virtual void append(void *sound, uint32 size); - virtual bool soundFinished(); - }; - - class ChannelRaw : public Channel { - SoundMixer *_mixer; - void *_ptr; - uint32 _pos; - uint32 _size; - uint32 _fpSpeed; - uint32 _fpPos; - uint32 _realSize, _rate; - byte _flags; - void *_loop_ptr; - uint32 _loop_size; - - public: - ChannelRaw(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags, int id); - - void mix(int16 *data, uint len); - void realDestroy(); - }; - - class ChannelStream : public Channel { - SoundMixer *_mixer; - byte *_ptr; - byte *_endOfData; - byte *_endOfBuffer; - byte *_pos; - uint32 _fpSpeed; - uint32 _fpPos; - uint32 _bufferSize; - uint32 _rate; - int32 _timeOut; - int32 _setTimeOut; - byte _flags; - - public: - ChannelStream(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags, int32 timout, int32 buffer_size); - - void append(void *sound, uint32 size); - void mix(int16 *data, uint len); - void realDestroy(); - }; - -#ifdef USE_MAD - - class ChannelMP3 : public Channel { - SoundMixer *_mixer; - void *_ptr; - struct mad_stream _stream; - struct mad_frame _frame; - struct mad_synth _synth; - uint32 _silenceCut; - uint32 _posInFrame; - uint32 _position; - uint32 _size; - byte _flags; - - public: - ChannelMP3(SoundMixer *mixer, void *sound, uint size, byte flags); - - void mix(int16 *data, uint len); - void realDestroy(); - - }; - - class ChannelMP3CDMusic:public Channel { - SoundMixer *_mixer; - void *_ptr; - struct mad_stream _stream; - struct mad_frame _frame; - struct mad_synth _synth; - uint32 _posInFrame; - uint32 _size; - uint32 _bufferSize; - mad_timer_t _duration; - File *_file; - bool _initialized; - - - public: - ChannelMP3CDMusic(SoundMixer *mixer, File *file, mad_timer_t duration); - - void mix(int16 *data, uint len); - void realDestroy(); - bool soundFinished(); - }; +class Channel { +public: + bool _toBeDestroyed; + int _id; + Channel() : _id(-1) {} + virtual void mix(int16 *data, uint len) = 0; + void destroy() { + _toBeDestroyed = true; + } + virtual void realDestroy() = 0; + virtual void append(void *sound, uint32 size); + virtual bool soundFinished(); +}; -#endif +class SoundMixer { +public: + typedef void PremixProc (void *param, int16 *data, uint len); -#ifdef USE_VORBIS - class ChannelVorbis : public Channel { - SoundMixer *_mixer; - OggVorbis_File *_ov_file; - int _end_pos; - bool _eof_flag, _is_cd_track; - - public: - ChannelVorbis(SoundMixer *mixer, OggVorbis_File *ov_file, int duration, bool is_cd_track); - - void mix(int16 *data, uint len); - void realDestroy(); - bool soundFinished(); + enum { + NUM_CHANNELS = 16 }; -#endif +private: static void onGenerateSamples(void *s, byte *samples, int len); -public: - typedef void PremixProc (void *param, int16 *data, uint len); - OSystem *_syst; void *_mutex; + void *_premixParam; + PremixProc *_premixProc; + + PlayingSoundHandle *_handles[NUM_CHANNELS]; + +public: uint _outputRate; int16 *_volumeTable; @@ -178,18 +82,11 @@ public: bool _paused; - enum { - NUM_CHANNELS = 16 - }; - - void *_premixParam; - PremixProc *_premixProc; - Channel *_channels[NUM_CHANNELS]; - PlayingSoundHandle *_handles[NUM_CHANNELS]; int _beginSlots; +public: SoundMixer(); ~SoundMixer(); @@ -219,46 +116,39 @@ public: int playVorbis(PlayingSoundHandle *handle, OggVorbis_File *ov_file, int duration, bool is_cd_track); #endif - /* Premix procedure, useful when using fmopl adlib */ + /** Premix procedure, useful when using fmopl adlib */ void setupPremix(void * param, PremixProc * proc); - /* mix */ + /** mix */ void mix(int16 * buf, uint len); - /* stop all currently playing sounds */ + /** stop all currently playing sounds */ void stopAll(); - /* stop playing a specific sound */ + /** stop playing a specific sound */ void stop(int index); - /* stop playing a specific sound */ + /** stop playing a specific sound */ void stopID(int id); - /* append to existing sound */ + /** append to existing sound */ int append(int index, void * sound, uint32 size, uint rate, byte flags); - /* is any channel active? */ + /** is any channel active? */ bool hasActiveChannel(); - /* bind to the OSystem object => mixer will be + /** bind to the OSystem object => mixer will be * invoked automatically when samples need * to be generated */ bool bindToSystem(OSystem *syst); - /* set the volume, 0-256 */ + /** set the volume, 0-256 */ void setVolume(int volume); void setMusicVolume(int volume); - /* pause - unpause */ + /** pause - unpause */ void pause(bool paused); }; -struct MP3OffsetTable { /* Compressed Sound (.SO3) */ - int org_offset; - int new_offset; - int num_tags; - int compressed_size; -}; - #endif |