diff options
-rw-r--r-- | sound/mixer.cpp | 791 |
1 files changed, 2 insertions, 789 deletions
diff --git a/sound/mixer.cpp b/sound/mixer.cpp index ea19bbe4eb..adb8d8254d 100644 --- a/sound/mixer.cpp +++ b/sound/mixer.cpp @@ -21,15 +21,12 @@ */ #include "stdafx.h" -#include "mixer.h" #include "common/engine.h" // for warning/error/debug #include "common/file.h" #include "common/util.h" -#define NEW_MIXER_CODE - -#ifdef NEW_MIXER_CODE -#include "rate.h" +#include "sound/mixer.h" +#include "sound/rate.h" class Channel { protected: @@ -113,126 +110,6 @@ public: #endif -#else // NEW_MIXER_CODE - -class Channel { -protected: - SoundMixer *_mixer; - PlayingSoundHandle *_handle; -public: - int _id; - Channel(SoundMixer *mixer, PlayingSoundHandle *handle) - : _mixer(mixer), _handle(handle), _id(-1) { - assert(mixer); - } - virtual ~Channel() { - if (_handle) - *_handle = 0; - } - - /* len indicates the number of sample *pairs*. So a value of - 10 means that the buffer contains twice 10 sample, each - 16 bits, for a total of 40 bytes. - */ - virtual void mix(int16 *data, uint len) = 0; - void destroy(); - virtual bool isMusicChannel() const = 0; -}; - -class ChannelRaw : public Channel { - byte *_ptr; - byte _flags; - uint32 _pos; - uint32 _size; - uint32 _fpSpeed; - uint32 _fpPos; - uint32 _realSize, _rate; - byte *_loop_ptr; - uint32 _loop_size; - -public: - ChannelRaw(SoundMixer *mixer, PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags, int id, uint32 loopStart, uint32 loopEnd); - ~ChannelRaw(); - - void mix(int16 *data, uint len); - bool isMusicChannel() const { return false; } -}; - -class ChannelStream : public Channel { - byte *_ptr; - byte *_endOfData; - byte *_endOfBuffer; - byte *_pos; - uint32 _fpSpeed; - uint32 _fpPos; - uint32 _bufferSize; - uint32 _rate; - byte _flags; - bool _finished; - -public: - ChannelStream(SoundMixer *mixer, PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags, uint32 buffer_size); - ~ChannelStream(); - - void mix(int16 *data, uint len); - void append(void *sound, uint32 size); - bool isMusicChannel() const { return true; } - void finish() { _finished = true; } -}; - -#ifdef USE_MAD -class ChannelMP3Common : public Channel { -protected: - byte *_ptr; - struct mad_stream _stream; - struct mad_frame _frame; - struct mad_synth _synth; - uint32 _posInFrame; - uint32 _size; - bool _initialized; - -public: - ChannelMP3Common(SoundMixer *mixer, PlayingSoundHandle *handle); - ~ChannelMP3Common(); -}; - -class ChannelMP3 : public ChannelMP3Common { - uint32 _position; - -public: - ChannelMP3(SoundMixer *mixer, PlayingSoundHandle *handle, File *file, uint size); - - void mix(int16 *data, uint len); - bool isMusicChannel() const { return false; } -}; - -class ChannelMP3CDMusic : public ChannelMP3Common { - uint32 _bufferSize; - mad_timer_t _duration; - File *_file; - -public: - ChannelMP3CDMusic(SoundMixer *mixer, PlayingSoundHandle *handle, File *file, mad_timer_t duration); - - void mix(int16 *data, uint len); - bool isMusicChannel() const { return true; } -}; -#endif // USE_MAD - -#ifdef USE_VORBIS -class ChannelVorbis : public Channel { - OggVorbis_File *_ov_file; - int _end_pos; - bool _is_cd_track; -public: - ChannelVorbis(SoundMixer *mixer, PlayingSoundHandle *handle, OggVorbis_File *ov_file, int duration, bool is_cd_track); - void mix(int16 *data, uint len); - bool isMusicChannel() const { return _is_cd_track; } -}; -#endif - -#endif - void Channel::destroy() { for (int i = 0; i != SoundMixer::NUM_CHANNELS; i++) @@ -487,7 +364,6 @@ void SoundMixer::setMusicVolume(int volume) { _musicVolume = volume; } -#ifdef NEW_MIXER_CODE /* RAW mixer */ ChannelRaw::ChannelRaw(SoundMixer *mixer, PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags, int id, uint32 loopStart, uint32 loopEnd) @@ -595,666 +471,3 @@ ChannelVorbis::ChannelVorbis(SoundMixer *mixer, PlayingSoundHandle *handle, OggV _is_cd_track = is_cd_track; } #endif // USE_VORBIS - -#else // NEW_MIXER_CODE - -/* - * Class that performs cubic interpolation on integer data. - * It is expected that the data is equidistant, i.e. all have the same - * horizontal distance. This is obviously the case for sampled audio. - */ -class CubicInterpolator { -protected: - int x0, x1, x2, x3; - int a, b, c, d; - -public: - CubicInterpolator(int8 a0, int8 b0, int8 c0) : x0(2 * a0 - b0), x1(a0), x2(b0), x3(c0) { - // We use a simple linear interpolation for x0 - updateCoefficients(); - } - - inline void feedData() { - x0 = x1; - x1 = x2; - x2 = x3; - x3 = 2 * x2 - x1; // Simple linear interpolation - updateCoefficients(); - } - - inline void feedData(int8 xNew) { - x0 = x1; - x1 = x2; - x2 = x3; - x3 = xNew; - updateCoefficients(); - } - - /* t must be a 16.16 fixed point number between 0 and 1 */ - inline int interpolate(uint32 fpPos) { - int result = 0; - int t = fpPos >> 8; - result = (a * t + b) >> 8; - result = (result * t + c) >> 8; - result = (result * t + d) >> 8; - result = (result / 3 + 1) >> 1; - - return result; - } - -protected: - inline void updateCoefficients() { - a = ((-x0 * 2) + (x1 * 5) - (x2 * 4) + x3); - b = ((x0 + x2 - (2 * x1)) * 6) << 8; - c = ((-4 * x0) + x1 + (x2 * 4) - x3) << 8; - d = (x1 * 6) << 8; - } -}; - -static inline void clamped_add_16(int16& a, int b) { - int val = a + b; - - if (val > 32767) - a = 32767; - else if (val < -32768) - a = -32768; - else - a = val; -} - -static void mix_signed_mono_8(int16 *data, uint &len, byte *&s, uint32 &fp_pos, - int fp_speed, int volume, byte *s_end, bool reverse_stereo) { - int inc = 1, result; - CubicInterpolator interp(*s, *(s + 1), *(s + 2)); - - do { - do { - result = interp.interpolate(fp_pos) * volume; - - clamped_add_16(*data++, result); - clamped_add_16(*data++, result); - - fp_pos += fp_speed; - inc = fp_pos >> 16; - s += inc; - len--; - fp_pos &= 0x0000FFFF; - } while (!inc && len && (s < s_end)); - - if (s + 2 < s_end) - interp.feedData(*(s + 2)); - else - interp.feedData(); - - } while (len && (s < s_end)); -} - -static void mix_unsigned_mono_8(int16 *data, uint &len, byte *&s, uint32 &fp_pos, - int fp_speed, int volume, byte *s_end, bool reverse_stereo) { - int inc = 1, result; - CubicInterpolator interp(*s ^ 0x80, *(s + 1) ^ 0x80, *(s + 2) ^ 0x80); - - do { - do { - result = interp.interpolate(fp_pos) * volume; - - clamped_add_16(*data++, result); - clamped_add_16(*data++, result); - - fp_pos += fp_speed; - inc = fp_pos >> 16; - s += inc; - len--; - fp_pos &= 0x0000FFFF; - } while (!inc && len && (s < s_end)); - - if (s + 2 < s_end) - interp.feedData(*(s + 2) ^ 0x80); - else - interp.feedData(); - - } while (len && (s < s_end)); -} - -static void mix_signed_stereo_8(int16 *data, uint &len, byte *&s, uint32 &fp_pos, - int fp_speed, int volume, byte *s_end, bool reverse_stereo) { - warning("Mixing stereo signed 8 bit is not supported yet "); -} -static void mix_unsigned_stereo_8(int16 *data, uint &len, byte *&s, uint32 &fp_pos, - int fp_speed, int volume, byte *s_end, bool reverse_stereo) { - int inc = 1; - CubicInterpolator left(*s ^ 0x80, *(s + 2) ^ 0x80, *(s + 4) ^ 0x80); - CubicInterpolator right(*(s + 1) ^ 0x80, *(s + 3) ^ 0x80, *(s + 5) ^ 0x80); - - do { - do { - if (!reverse_stereo) { - clamped_add_16(*data++, left.interpolate(fp_pos) * volume); - clamped_add_16(*data++, right.interpolate(fp_pos) * volume); - } else { - clamped_add_16(*data++, right.interpolate(fp_pos) * volume); - clamped_add_16(*data++, left.interpolate(fp_pos) * volume); - } - - fp_pos += fp_speed; - inc = (fp_pos >> 16) << 1; - s += inc; - len--; - fp_pos &= 0x0000FFFF; - } while (!inc && len && (s < s_end)); - - if (s + 5 < s_end) { - left.feedData(*(s + 4) ^ 0x80); - right.feedData(*(s + 5) ^ 0x80); - } else { - left.feedData(); - right.feedData(); - } - - } while (len && (s < s_end)); -} -static void mix_signed_mono_16(int16 *data, uint &len, byte *&s, uint32 &fp_pos, - int fp_speed, int volume, byte *s_end, bool reverse_stereo) { - do { - int16 sample = ((int16)READ_BE_UINT16(s) * volume) / 256; - fp_pos += fp_speed; - - clamped_add_16(*data++, sample); - clamped_add_16(*data++, sample); - - s += (fp_pos >> 16) << 1; - fp_pos &= 0x0000FFFF; - } while ((--len) && (s < s_end)); -} -static void mix_unsigned_mono_16(int16 *data, uint &len, byte *&s, uint32 &fp_pos, - int fp_speed, int volume, byte *s_end, bool reverse_stereo) { - warning("Mixing mono unsigned 16 bit is not supported yet "); -} -static void mix_signed_stereo_16(int16 *data, uint &len, byte *&s, uint32 &fp_pos, - int fp_speed, int volume, byte *s_end, bool reverse_stereo) { - do { - int16 leftS = ((int16)READ_BE_UINT16(s) * volume) / 256; - int16 rightS = ((int16)READ_BE_UINT16(s+2) * volume) / 256; - fp_pos += fp_speed; - - if (!reverse_stereo) { - clamped_add_16(*data++, leftS); - clamped_add_16(*data++, rightS); - } else { - clamped_add_16(*data++, rightS); - clamped_add_16(*data++, leftS); - } - s += (fp_pos >> 16) << 2; - fp_pos &= 0x0000FFFF; - } while ((--len) && (s < s_end)); -} -static void mix_unsigned_stereo_16(int16 *data, uint &len, byte *&s, uint32 &fp_pos, - int fp_speed, int volume, byte *s_end, bool reverse_stereo) { - warning("Mixing stereo unsigned 16 bit is not supported yet "); -} - -typedef void MixProc(int16 *data, uint &len, byte *&s, - uint32 &fp_pos, int fp_speed, int volume, - 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, - mix_signed_stereo_16, mix_unsigned_stereo_16 -}; - -static int16 mixer_element_size[] = { - 1, 1, - 2, 2, - 2, 2, - 4, 4 -}; - -/* RAW mixer */ -ChannelRaw::ChannelRaw(SoundMixer *mixer, PlayingSoundHandle *handle, void *sound, uint32 size, uint rate, byte flags, int id, uint32 loopStart, uint32 loopEnd) - : Channel(mixer, handle) { - _id = id; - _ptr = (byte *)sound; - - _flags = flags; - _pos = 0; - _fpPos = 0; - _fpSpeed = (1 << 16) * rate / mixer->getOutputRate(); - _realSize = size; - - // adjust the magnitude to prevent division error - while (size & 0xFFFF0000) - size >>= 1, rate = (rate >> 1) + 1; - - _rate = rate; - _size = size * mixer->getOutputRate() / 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; - } -} - -ChannelRaw::~ChannelRaw() { - if (_flags & SoundMixer::FLAG_AUTOFREE) - free(_ptr); -} - -void ChannelRaw::mix(int16 *data, uint len) { - byte *s, *end; - - if (len > _size) - len = _size; - _size -= len; - - s = _ptr + _pos; - end = _ptr + _realSize; - - mixer_helper_table[_flags & 0x07] (data, len, s, _fpPos, _fpSpeed, _mixer->getVolume(), end, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false); - - _pos = s - _ptr; - - if (_size <= 0) { - if (_flags & SoundMixer::FLAG_LOOP) { - _ptr = _loop_ptr; - _size = _loop_size; - _pos = 0; - _fpPos = 0; - } else { - destroy(); - } - } -} - -#define WARP_WORKAROUND 50000 - -ChannelStream::ChannelStream(SoundMixer *mixer, PlayingSoundHandle *handle, - void *sound, uint32 size, uint rate, - byte flags, uint32 buffer_size) - : Channel(mixer, handle) { - assert(size <= buffer_size); - - _flags = flags; - _bufferSize = buffer_size; - _ptr = (byte *)malloc(_bufferSize + WARP_WORKAROUND); - memcpy(_ptr, sound, size); - _endOfData = _ptr + size; - _endOfBuffer = _ptr + _bufferSize; - _pos = _ptr; - _fpPos = 0; - _fpSpeed = (1 << 16) * rate / mixer->getOutputRate(); - - // adjust the magnitude to prevent division error - while (size & 0xFFFF0000) - size >>= 1, rate = (rate >> 1) + 1; - - _rate = rate; - _finished = false; -} - -ChannelStream::~ChannelStream() { - free(_ptr); -} - -void ChannelStream::append(void *data, uint32 len) { - if (_endOfData + len > _endOfBuffer) { - /* Wrap-around case */ - uint32 size_to_end_of_buffer = _endOfBuffer - _endOfData; - uint32 new_size = len - size_to_end_of_buffer; - if ((_endOfData < _pos) || (_ptr + new_size >= _pos)) { - debug(2, "Mixer full... Trying to not break too much (A)"); - return; - } - memcpy(_endOfData, (byte*)data, size_to_end_of_buffer); - memcpy(_ptr, (byte *)data + size_to_end_of_buffer, new_size); - _endOfData = _ptr + new_size; - } else { - if ((_endOfData < _pos) && (_endOfData + len >= _pos)) { - debug(2, "Mixer full... Trying to not break too much (B)"); - return; - } - memcpy(_endOfData, data, len); - _endOfData += len; - } -} - -void ChannelStream::mix(int16 *data, uint len) { - if (_pos == _endOfData) { - // Normally, the stream stays around even if all its data is used up. - // This is in case more data is streamed into it. To make the stream - // go away, one can either stop() it (which takes effect immediately, - // ignoring any remaining sound data), or finish() it, which means - // it will finish playing before it terminates itself. - if (_finished) { - destroy(); - } else { - // Since the buffer is empty now, reset the position to the start - _pos = _endOfData = _ptr; - _fpPos = 0; - } - - return; - } - - MixProc *mixProc = mixer_helper_table[_flags & 0x07]; - - if (_pos < _endOfData) { - mixProc(data, len, _pos, _fpPos, _fpSpeed, _mixer->getVolume(), _endOfData, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false); - } else { - int wrapOffset = 0; - const uint32 outLen = mixer_element_size[_flags & 0x07] * len; - - // see if we will wrap - if (_pos + outLen > _endOfBuffer) { - wrapOffset = _pos + outLen - _endOfBuffer; - debug(2, "using wrap workaround for %d bytes", wrapOffset); - assert(wrapOffset <= WARP_WORKAROUND); - memcpy(_endOfBuffer, _ptr, wrapOffset); - } - - mixProc(data, len, _pos, _fpPos, _fpSpeed, _mixer->getVolume(), _endOfBuffer + wrapOffset, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false); - - // recover from wrap - if (wrapOffset) - _pos = _ptr + wrapOffset; - - // shouldn't happen anymore - if (len != 0) { - //FIXME: what is wrong ? - warning("bad play sound in stream (wrap around)"); - _pos = _ptr; - mixProc(data, len, _pos, _fpPos, _fpSpeed, _mixer->getVolume(), _endOfData, (_flags & SoundMixer::FLAG_REVERSE_STEREO) ? true : false); - } - } -} - -#ifdef USE_MAD -ChannelMP3Common::ChannelMP3Common(SoundMixer *mixer, PlayingSoundHandle *handle) - : Channel(mixer, handle) { - mad_stream_init(&_stream); -#ifdef _WIN32_WCE - // Lower sample rate to 11 kHz on WinCE if necessary - if (_syst->property(OSystem::PROP_GET_SAMPLE_RATE, 0) != 22050) - mad_stream_options(&_stream, MAD_OPTION_HALFSAMPLERATE); -#endif - mad_frame_init(&_frame); - mad_synth_init(&_synth); - - _initialized = false; -} - -ChannelMP3Common::~ChannelMP3Common() { - 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)); - - /* clip */ - if (sample > MAD_F_ONE - 1) - sample = MAD_F_ONE - 1; - else if (sample < -MAD_F_ONE) - sample = -MAD_F_ONE; - - /* quantize and scale to not saturate when mixing a lot of channels */ - return sample >> (MAD_F_FRACBITS + 1 - 16); -} - -ChannelMP3::ChannelMP3(SoundMixer *mixer, PlayingSoundHandle *handle, File *file, uint size) - : ChannelMP3Common(mixer, handle) { - _posInFrame = 0xFFFFFFFF; - _position = 0; - _ptr = (byte *)malloc(size + MAD_BUFFER_GUARD); - - _size = file->read(_ptr, size); -} - -void ChannelMP3::mix(int16 *data, uint len) { - const int volume = _mixer->getVolume(); - - // Exit if all data is used up (this also covers the case were reading from the file failed). - if (_position >= _size) { - destroy(); - return; - } - - while (1) { - - int16 sample; - while ((_posInFrame < _synth.pcm.length) && (len > 0)) { - sample = (int16)((scale_sample(_synth.pcm.samples[0][_posInFrame]) * volume) / 256); - clamped_add_16(*data++, sample); - if (_synth.pcm.channels > 1) - sample = (int16)((scale_sample(_synth.pcm.samples[1][_posInFrame]) * volume) / 256); - clamped_add_16(*data++, sample); - len--; - _posInFrame++; - } - if (len == 0) - return; - - if (_position >= _size) { - destroy(); - return; - } - - mad_stream_buffer(&_stream, _ptr + _position, - _size + MAD_BUFFER_GUARD - _position); - - if (mad_frame_decode(&_frame, &_stream) == -1) { - /* End of audio... */ - if (_stream.error == MAD_ERROR_BUFLEN) { - destroy(); - return; - } else if (!MAD_RECOVERABLE(_stream.error)) { - error("MAD frame decode error !"); - } - } - mad_synth_frame(&_synth, &_frame); - _posInFrame = 0; - _position = _stream.next_frame - _ptr; - } -} - -#define MP3CD_BUFFERING_SIZE 131072 - -ChannelMP3CDMusic::ChannelMP3CDMusic(SoundMixer *mixer, PlayingSoundHandle *handle, File *file, mad_timer_t duration) - : ChannelMP3Common(mixer, handle) { - _file = file; - _duration = duration; - _bufferSize = MP3CD_BUFFERING_SIZE; - _ptr = (byte *)malloc(MP3CD_BUFFERING_SIZE); -} - -void ChannelMP3CDMusic::mix(int16 *data, uint len) { - mad_timer_t frame_duration; - const int volume = _mixer->getMusicVolume(); - - if (!_initialized) { - // just skipped - memset(_ptr, 0, _bufferSize); - _size = _file->read(_ptr, _bufferSize); - if (_size <= 0) { - debug(1, "Failed to read MP3 data during channel initialisation !"); - destroy(); - return; - } - // Resync - mad_stream_buffer(&_stream, _ptr, _size); - - // Skip the first two frames (see ChannelMP3::ChannelMP3 for an explanation) - int skip_loop = 2; - while (skip_loop != 0) { - if (mad_frame_decode(&_frame, &_stream) == 0) { - /* Do not decrease duration - see if it's a problem */ - skip_loop--; - } else { - if (!MAD_RECOVERABLE(_stream.error)) { - debug(1, "Unrecoverable error while skipping !"); - destroy(); - return; - } - } - } - - // FIXME: Fingolfin asks: why is this call to mad_synth_frame - // necessary? Or rather, *is* it actually necessary? - mad_synth_frame(&_synth, &_frame); - - // We are supposed to be in synch - mad_frame_mute(&_frame); - mad_synth_mute(&_synth); - // Resume decoding - if (mad_frame_decode(&_frame, &_stream) == 0) { - _posInFrame = 0; - _initialized = true; - } else { - debug(1, "Cannot resume decoding"); - destroy(); - return; - } - } - - while (1) { - - // TODO: Check _synth.pcm.samplerate and perform rate conversion of appropriate - // TODO: Check _synth.pcm.channels to support stereo - - // Get samples, play samples ... - int16 sample; - while ((_posInFrame < _synth.pcm.length) && (len > 0)) { - sample = (int16)((scale_sample(_synth.pcm.samples[0][_posInFrame]) * volume) / 256); - clamped_add_16(*data++, sample); - if (_synth.pcm.channels > 1) - sample = (int16)((scale_sample(_synth.pcm.samples[1][_posInFrame]) * volume) / 256); - clamped_add_16(*data++, sample); - len--; - _posInFrame++; - } - if (len == 0) - return; - - // See if we have finished - // May be incorrect to check the size at the end of a frame but I suppose - // they are short enough :) - frame_duration = _frame.header.duration; - mad_timer_negate(&frame_duration); - mad_timer_add(&_duration, frame_duration); - - if (mad_timer_compare(_duration, mad_timer_zero) <= 0) { - destroy(); - return; - } - if (mad_frame_decode(&_frame, &_stream) == -1) { - if (_stream.error == MAD_ERROR_BUFLEN) { - int not_decoded; - - if (!_stream.next_frame) { - not_decoded = 0; - memset(_ptr, 0, _bufferSize + MAD_BUFFER_GUARD); - } else { - not_decoded = _stream.bufend - _stream.next_frame; - memcpy(_ptr, _stream.next_frame, not_decoded); - } - _size = _file->read(_ptr + not_decoded, _bufferSize - not_decoded); - if (_size <= 0) { - return; - } - _stream.error = (enum mad_error)0; - // Restream - mad_stream_buffer(&_stream, _ptr, _size + not_decoded); - if (mad_frame_decode(&_frame, &_stream) == -1) { - debug(1, "Error %d decoding after restream !", _stream.error); - } - } else if (!MAD_RECOVERABLE(_stream.error)) { - error("MAD frame decode error in MP3 CDMUSIC !"); - } - } - mad_synth_frame(&_synth, &_frame); - _posInFrame = 0; - } -} -#endif // USE_MAD - -#ifdef USE_VORBIS -ChannelVorbis::ChannelVorbis(SoundMixer *mixer, PlayingSoundHandle *handle, OggVorbis_File *ov_file, int duration, bool is_cd_track) - : Channel(mixer, handle) { - _ov_file = ov_file; - - if (duration) - _end_pos = ov_pcm_tell(ov_file) + duration; - else - _end_pos = 0; - _is_cd_track = is_cd_track; -} - -void ChannelVorbis::mix(int16 *data, uint len) { - if (_end_pos > 0 && ov_pcm_tell(_ov_file) >= _end_pos) { - destroy(); - return; - } - - int channels = ov_info(_ov_file, -1)->channels; - uint len_left = len * channels * 2; - int16 *samples = new int16[len_left / 2]; - char *read_pos = (char *) samples; - bool eof_flag = false; - const int volume = isMusicChannel() ? _mixer->getMusicVolume() : _mixer->getVolume(); - - // Read the samples - while (len_left > 0) { - long result = ov_read(_ov_file, read_pos, len_left, -#ifndef VORBIS_TREMOR -#ifdef SCUMM_BIG_ENDIAN - 1, -#else - 0, -#endif - 2, 1, -#endif - NULL); - if (result == 0) { - eof_flag = true; - memset(read_pos, 0, len_left); - break; - } else if (result == OV_HOLE) { - // Possibly recoverable, just warn about it - warning("Corrupted data in Vorbis file"); - } else if (result < 0) { - debug(1, "Decode error %d in Vorbis file", result); - eof_flag = true; - memset(read_pos, 0, len_left); - break; - } else { - len_left -= result; - read_pos += result; - } - } - - // Mix the samples in - for (uint i = 0; i < len; i++) { - int16 sample = (int16)(samples[i * channels] * volume / 256); - clamped_add_16(*data++, sample); - if (channels > 1) - sample = (int16)(samples[i * channels + 1] * volume / 256); - clamped_add_16(*data++, sample); - } - - delete [] samples; - - if (eof_flag) - destroy(); -} -#endif // USE_VORBIS - -#endif // NEW_MIXER_CODE - |