diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/mixer.cpp | 173 | ||||
-rw-r--r-- | sound/mixer.h | 8 |
2 files changed, 70 insertions, 111 deletions
diff --git a/sound/mixer.cpp b/sound/mixer.cpp index cdcba77d34..b919ced842 100644 --- a/sound/mixer.cpp +++ b/sound/mixer.cpp @@ -39,9 +39,9 @@ class ChannelRaw : public Channel { public: ChannelRaw(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags, int id); + ~ChannelRaw(); void mix(int16 *data, uint len); - void realDestroy(); }; class ChannelStream : public Channel { @@ -57,9 +57,9 @@ class ChannelStream : public Channel { public: ChannelStream(SoundMixer *mixer, void *sound, uint32 size, uint rate, byte flags, int32 buffer_size); + ~ChannelStream(); void mix(int16 *data, uint len); - void realDestroy(); void append(void *sound, uint32 size); }; @@ -78,10 +78,9 @@ class ChannelMP3 : public Channel { public: ChannelMP3(SoundMixer *mixer, void *sound, uint size, byte flags); + ~ChannelMP3(); void mix(int16 *data, uint len); - void realDestroy(); - }; class ChannelMP3CDMusic : public Channel { @@ -99,9 +98,9 @@ class ChannelMP3CDMusic : public Channel { public: ChannelMP3CDMusic(SoundMixer *mixer, File *file, mad_timer_t duration); + ~ChannelMP3CDMusic(); void mix(int16 *data, uint len); - void realDestroy(); bool soundFinished(); }; @@ -117,7 +116,6 @@ 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 @@ -138,6 +136,7 @@ SoundMixer::~SoundMixer() { for (int i = 0; i != NUM_CHANNELS; i++) { delete _channels[i]; } + _syst->delete_mutex(_mutex); } int SoundMixer::append(int index, void *sound, uint32 size) { @@ -154,21 +153,20 @@ int SoundMixer::append(int index, void *sound, uint32 size) { return 1; } -int SoundMixer::insertAt(PlayingSoundHandle *handle, int index, Channel *chan) { - if(index == -1) { - for (int i = 0; i != NUM_CHANNELS; i++) - if (_channels[i] == NULL) { - index = i; - break; - } - if(index == -1) { - warning("SoundMixer::out of mixer slots"); - return -1; +int SoundMixer::insertChannel(PlayingSoundHandle *handle, Channel *chan) { + int index = -1; + for (int i = 0; i != NUM_CHANNELS; i++) { + if (_channels[i] == NULL) { + index = i; + break; } } - if (_channels[index] != NULL) { - error("Trying to put a mixer where it cannot go "); + if(index == -1) { + warning("SoundMixer::out of mixer slots"); + delete chan; + return -1; } + _channels[index] = chan; _handles[index] = handle; if (handle) @@ -177,54 +175,25 @@ int SoundMixer::insertAt(PlayingSoundHandle *handle, int index, Channel *chan) { } int SoundMixer::playRaw(PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags, int id) { - for (int i = 0; i != NUM_CHANNELS; i++) { - if (_channels[i] == NULL) { - return insertAt(handle, i, new ChannelRaw(this, sound, size, rate, flags, id)); - } - } - - warning("SoundMixer::out of mixer slots"); - return -1; + return insertChannel(handle, new ChannelRaw(this, sound, size, rate, flags, id)); } int SoundMixer::playStream(void *sound, uint32 size, uint rate, byte flags, int32 buffer_size) { - return insertAt(NULL, -1, new ChannelStream(this, sound, size, rate, flags, buffer_size)); + return insertChannel(NULL, new ChannelStream(this, sound, size, rate, flags, buffer_size)); } #ifdef USE_MAD int SoundMixer::playMP3(PlayingSoundHandle *handle, void *sound, uint32 size, byte flags) { - for (int i = 0; i != NUM_CHANNELS; i++) { - if (_channels[i] == NULL) { - return insertAt(handle, i, new ChannelMP3(this, sound, size, flags)); - } - } - - warning("SoundMixer::out of mixer slots"); - return -1; + return insertChannel(handle, new ChannelMP3(this, sound, size, flags)); } int SoundMixer::playMP3CDTrack(PlayingSoundHandle *handle, File *file, mad_timer_t duration) { - /* Stop the previously playing CD track (if any) */ - for (int i = 0; i != NUM_CHANNELS; i++) { - if (_channels[i] == NULL) { - return insertAt(handle, i, new ChannelMP3CDMusic(this, file, duration)); - } - } - - warning("SoundMixer::out of mixer slots"); - return -1; + return insertChannel(handle, new ChannelMP3CDMusic(this, file, duration)); } #endif #ifdef USE_VORBIS int SoundMixer::playVorbis(PlayingSoundHandle *handle, OggVorbis_File *ov_file, int duration, bool is_cd_track) { - for (int i = 0; i != NUM_CHANNELS; i++) { - if (_channels[i] == NULL) { - return insertAt(handle, i, new ChannelVorbis(this, ov_file, duration, is_cd_track)); - } - } - - warning("SoundMixer::out of mixer slots"); - return -1; + return insertChannel(handle, -1, new ChannelVorbis(this, ov_file, duration, is_cd_track)); } #endif @@ -251,7 +220,6 @@ void SoundMixer::mix(int16 *buf, uint len) { *_handles[i] = 0; _handles[i] = NULL; } - _channels[i]->realDestroy(); delete _channels[i]; _channels[i] = NULL; } else @@ -610,9 +578,11 @@ static int16 *mix_unsigned_stereo_16(int16 *data, uint *len_ptr, byte **s_ptr, u return data; } -static int16 *(*mixer_helper_table[8]) (int16 *data, uint *len_ptr, byte **s_ptr, - uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab, - byte *s_end, bool reverse_stereo) = { +typedef int16 *MixProc(int16 *data, uint *len_ptr, byte **s_ptr, + uint32 *fp_pos_ptr, int fp_speed, const int16 *vol_tab, + byte *s_end, bool reverse_stereo); + +static MixProc *mixer_helper_table[8] = { mix_signed_mono_8, mix_unsigned_mono_8, mix_signed_stereo_8, mix_unsigned_stereo_8, mix_signed_mono_16, mix_unsigned_mono_16, @@ -659,6 +629,11 @@ ChannelRaw::ChannelRaw(SoundMixer *mixer, void *sound, uint32 size, uint rate, b } } +ChannelRaw::~ChannelRaw() { + if (_flags & SoundMixer::FLAG_AUTOFREE) + free(_ptr); +} + void ChannelRaw::mix(int16 *data, uint len) { byte *s, *end; @@ -669,10 +644,9 @@ void ChannelRaw::mix(int16 *data, uint len) { s = _ptr + _pos; end = _ptr + _realSize; - 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 & SoundMixer::FLAG_REVERSE_STEREO) ? true : false); + mixer_helper_table[_flags & 0x07] (data, &len, &s, &_fpPos, _fpSpeed, vol_tab, end, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false); _pos = s - _ptr; @@ -683,15 +657,9 @@ void ChannelRaw::mix(int16 *data, uint len) { _pos = 0; _fpPos = 0; } else { - _toBeDestroyed = true; + destroy(); } } - -} - -void ChannelRaw::realDestroy() { - if (_flags & SoundMixer::FLAG_AUTOFREE) - free(_ptr); } #define WARP_WORKAROUND 50000 @@ -716,6 +684,10 @@ ChannelStream::ChannelStream(SoundMixer *mixer, void *sound, uint32 size, uint r _rate = rate; } +ChannelStream::~ChannelStream() { + free(_ptr); +} + 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 :-) */ @@ -741,19 +713,14 @@ void ChannelStream::append(void *data, uint32 len) { } void ChannelStream::mix(int16 *data, uint len) { - uint32 fp_pos; - const uint32 fp_speed = _fpSpeed; const int16 *vol_tab = _mixer->_volumeTable; - byte *end_of_data = _endOfData; - if (_pos == end_of_data) { + if (_pos == _endOfData) { return; } - 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 & SoundMixer::FLAG_REVERSE_STEREO) ? true : false); + if (_pos < _endOfData) { + mixer_helper_table[_flags & 0x07] (data, &len, &_pos, &_fpPos, _fpSpeed, vol_tab, _endOfData, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false); } else { int wrap_offset = 0; @@ -765,7 +732,7 @@ void ChannelStream::mix(int16 *data, uint len) { } - mixer_helper_table[_flags & 0x07] (data, &len, &_pos, &fp_pos, fp_speed, vol_tab, _endOfBuffer + wrap_offset, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false); + mixer_helper_table[_flags & 0x07] (data, &len, &_pos, &_fpPos, _fpSpeed, vol_tab, _endOfBuffer + wrap_offset, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false); // recover from wrap if (wrap_offset) @@ -776,14 +743,9 @@ void 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 & SoundMixer::FLAG_REVERSE_STEREO) ? true : false); + mixer_helper_table[_flags & 0x07] (data, &len, &_pos, &_fpPos, _fpSpeed, vol_tab, _endOfData, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false); } } - _fpPos = fp_pos; -} - -void ChannelStream::realDestroy() { - free(_ptr); } #ifdef USE_MAD @@ -818,6 +780,14 @@ ChannelMP3::ChannelMP3(SoundMixer *mixer, void *sound, uint size, byte flags) { _silenceCut = 576 * 2; } +ChannelMP3::~ChannelMP3() { + if (_flags & SoundMixer::FLAG_AUTOFREE) + free(_ptr); + mad_synth_finish(&_synth); + mad_frame_finish(&_frame); + mad_stream_finish(&_stream); +} + static inline int scale_sample(mad_fixed_t sample) { /* round */ sample += (1L << (MAD_F_FRACBITS - 16)); @@ -852,20 +822,19 @@ void ChannelMP3::mix(int16 *data, uint len) { } while ((_posInFrame < _synth.pcm.length) && (len > 0)) { - int16 sample = (int16)((scale_sample(*ch) * volume) / 32); + int16 sample = (int16)((scale_sample(*ch++) * volume) / 32); *data = clamped_add_16(*data, sample); data++; *data = clamped_add_16(*data, sample); data++; len--; - ch++; _posInFrame++; } if (len == 0) return; if (_position >= _size) { - _toBeDestroyed = true; + destroy(); return; } @@ -875,7 +844,7 @@ void ChannelMP3::mix(int16 *data, uint len) { if (mad_frame_decode(&_frame, &_stream) == -1) { /* End of audio... */ if (_stream.error == MAD_ERROR_BUFLEN) { - _toBeDestroyed = true; + destroy(); return; } else if (!MAD_RECOVERABLE(_stream.error)) { error("MAD frame decode error !"); @@ -887,14 +856,6 @@ void ChannelMP3::mix(int16 *data, uint len) { } } -void ChannelMP3::realDestroy() { - if (_flags & SoundMixer::FLAG_AUTOFREE) - free(_ptr); - mad_synth_finish(&_synth); - mad_frame_finish(&_frame); - mad_stream_finish(&_stream); -} - #define MP3CD_BUFFERING_SIZE 131072 ChannelMP3CDMusic::ChannelMP3CDMusic(SoundMixer *mixer, File *file, @@ -916,6 +877,13 @@ ChannelMP3CDMusic::ChannelMP3CDMusic(SoundMixer *mixer, File *file, mad_synth_init(&_synth); } +ChannelMP3CDMusic::~ChannelMP3CDMusic() { + free(_ptr); + mad_synth_finish(&_synth); + mad_frame_finish(&_frame); + mad_stream_finish(&_stream); +} + void ChannelMP3CDMusic::mix(int16 *data, uint len) { mad_fixed_t const *ch; mad_timer_t frame_duration; @@ -927,7 +895,7 @@ void ChannelMP3CDMusic::mix(int16 *data, uint len) { memset(_ptr, 0, _bufferSize); _size = _file->read(_ptr, _bufferSize); if (!_size) { - _toBeDestroyed = true; + destroy(); return; } // Resync @@ -943,7 +911,7 @@ void ChannelMP3CDMusic::mix(int16 *data, uint len) { } else { if (!MAD_RECOVERABLE(_stream.error)) { debug(1, "Unrecoverable error while skipping !"); - _toBeDestroyed = true; + destroy(); return; } } @@ -957,7 +925,7 @@ void ChannelMP3CDMusic::mix(int16 *data, uint len) { _initialized = true; } else { debug(1, "Cannot resume decoding"); - _toBeDestroyed = true; + destroy(); return; } } @@ -1015,13 +983,6 @@ bool ChannelMP3CDMusic::soundFinished() { return mad_timer_compare(_duration, mad_timer_zero) <= 0; } -void ChannelMP3CDMusic::realDestroy() { - free(_ptr); - mad_synth_finish(&_synth); - mad_frame_finish(&_frame); - mad_stream_finish(&_stream); -} - #endif #ifdef USE_VORBIS @@ -1049,8 +1010,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->_musicVolume : _mixer->_volumeTable[1]; // Read the samples while (len_left > 0) { @@ -1098,10 +1058,7 @@ void ChannelVorbis::mix(int16 *data, uint len) { delete [] samples; if (_eof_flag && ! _is_cd_track) - _toBeDestroyed = true; -} - -void ChannelVorbis::realDestroy() { + destroy(); } bool ChannelVorbis::soundFinished() { diff --git a/sound/mixer.h b/sound/mixer.h index afe6560a73..06f22e38fc 100644 --- a/sound/mixer.h +++ b/sound/mixer.h @@ -54,11 +54,11 @@ public: bool _toBeDestroyed; int _id; Channel() : _mixer(0), _toBeDestroyed(false), _id(-1) {} + virtual ~Channel() {} virtual void mix(int16 *data, uint len) = 0; void destroy() { _toBeDestroyed = true; } - virtual void realDestroy() = 0; virtual bool soundFinished(); }; @@ -141,15 +141,17 @@ public: * to be generated */ bool bindToSystem(OSystem *syst); - /** set the volume, 0-256 */ + /** set the global volume, 0-256 */ void setVolume(int volume); + + /** set the music volume, 0-256 */ void setMusicVolume(int volume); /** pause - unpause */ void pause(bool paused); private: - int insertAt(PlayingSoundHandle *handle, int index, Channel *chan); + int insertChannel(PlayingSoundHandle *handle, Channel *chan); }; #endif |