diff options
author | Max Horn | 2003-12-19 00:32:47 +0000 |
---|---|---|
committer | Max Horn | 2003-12-19 00:32:47 +0000 |
commit | d21fc5845dc77dd977df22fd9ddc3206bf23a920 (patch) | |
tree | eed9abe12e4a103c469f875cb6dfebab746c74a4 /sound/vorbis.cpp | |
parent | 97ee61963c896e48a0acc5b4169ce96163e76b06 (diff) | |
download | scummvm-rg350-d21fc5845dc77dd977df22fd9ddc3206bf23a920.tar.gz scummvm-rg350-d21fc5845dc77dd977df22fd9ddc3206bf23a920.tar.bz2 scummvm-rg350-d21fc5845dc77dd977df22fd9ddc3206bf23a920.zip |
o Moved MP3 and Vorbis input streams to mp3.* resp. vorbis.*
o Added SoundMixer::playInputStream and made some of the other play* methods use it
o Added ProcInputStream stub (not working yet) which one day may allow us to replace the premix code, and allow other fancy stuff
o Remove AudioInputStream::readBuffer default implementation (subclasses should always provide it for max. performance)
o Some minor cleanup
svn-id: r11754
Diffstat (limited to 'sound/vorbis.cpp')
-rw-r--r-- | sound/vorbis.cpp | 126 |
1 files changed, 122 insertions, 4 deletions
diff --git a/sound/vorbis.cpp b/sound/vorbis.cpp index cd1a84ad08..fb8ec9274a 100644 --- a/sound/vorbis.cpp +++ b/sound/vorbis.cpp @@ -19,13 +19,13 @@ * */ -#include "stdafx.h" - #include "sound/vorbis.h" +#include "sound/audiostream.h" #include "common/file.h" #include "common/util.h" #ifdef USE_VORBIS + // These are wrapper functions to allow using a File object to // provide data to the OggVorbis_File object. @@ -86,9 +86,7 @@ static long tell_wrap(void *datasource) { static ov_callbacks g_File_wrap = { read_wrap, seek_wrap, close_wrap, tell_wrap }; -#endif -#ifdef USE_VORBIS VorbisTrackInfo::VorbisTrackInfo(File *file) { file_info *f = new file_info; @@ -147,4 +145,124 @@ void playSfxSound_Vorbis(SoundMixer *mixer, File *file, uint32 size, PlayingSoun mixer->playVorbis(handle, ov_file, 0, false); } + +#pragma mark - +#pragma mark --- Ogg Vorbis stream --- +#pragma mark - + + +class VorbisInputStream : public AudioInputStream { + OggVorbis_File *_ov_file; + int _end_pos; + int _numChannels; + int16 _buffer[4096]; + const int16 *_bufferEnd; + const int16 *_pos; + + void refill(); + inline bool eosIntern() const; +public: + VorbisInputStream(OggVorbis_File *file, int duration); + int readBuffer(int16 *buffer, const int numSamples); + + int16 read(); + bool eos() const { return eosIntern(); } + bool isStereo() const { return _numChannels >= 2; } + + int getRate() const { return ov_info(_ov_file, -1)->rate; } +}; + + +#ifdef CHUNKSIZE +#define VORBIS_TREMOR +#endif + + +VorbisInputStream::VorbisInputStream(OggVorbis_File *file, int duration) + : _ov_file(file), _bufferEnd(_buffer + ARRAYSIZE(_buffer)) { + + // Check the header, determine if this is a stereo stream + _numChannels = ov_info(_ov_file, -1)->channels; + + // Determine the end position + if (duration) + _end_pos = ov_pcm_tell(_ov_file) + duration; + else + _end_pos = ov_pcm_total(_ov_file, -1); + + // Read in initial data + refill(); +} + +inline int16 VorbisInputStream::read() { + assert(!eosIntern()); + + int16 sample = *_pos++; + if (_pos >= _bufferEnd) { + refill(); + } + return sample; +} + +inline bool VorbisInputStream::eosIntern() const { + return _pos >= _bufferEnd; +} + +int VorbisInputStream::readBuffer(int16 *buffer, const int numSamples) { + int samples = 0; + while (samples < numSamples && !eosIntern()) { + const int len = MIN(numSamples, samples + (int)(_bufferEnd - _pos)); + memcpy(buffer, _pos, len * 2); + buffer += len; + _pos += len; + samples += len; + if (_pos >= _bufferEnd) { + refill(); + } + } + return samples; +} + +void VorbisInputStream::refill() { + // Read the samples + uint len_left = sizeof(_buffer); + char *read_pos = (char *)_buffer; + + while (len_left > 0 && _end_pos > ov_pcm_tell(_ov_file)) { + long result = ov_read(_ov_file, read_pos, len_left, +#ifndef VORBIS_TREMOR +#ifdef SCUMM_BIG_ENDIAN + 1, +#else + 0, +#endif + 2, // 16 bit + 1, // signed +#endif + NULL); + if (result == OV_HOLE) { + // Possibly recoverable, just warn about it + warning("Corrupted data in Vorbis file"); + } else if (result <= 0) { + if (result < 0) + debug(1, "Decode error %d in Vorbis file", result); + // Don't delete it yet, that causes problems in + // the CD player emulation code. + memset(read_pos, 0, len_left); + break; + } else { + len_left -= result; + read_pos += result; + } + } + + _pos = _buffer; + _bufferEnd = (int16 *)read_pos; +} + +AudioInputStream *makeVorbisStream(OggVorbis_File *file, int duration) { + return new VorbisInputStream(file, duration); +} + + #endif |