Ticket #9066: streaming_voc_patch_v2.patch

File streaming_voc_patch_v2.patch, 19.7 KB (added by lordhoto, 15 years ago)

This time the correct version 2 of the patch, the last one missed the AGOS loop change.

  • engines/agos/sound.cpp

    diff --git a/engines/agos/sound.cpp b/engines/agos/sound.cpp
    index d20c07a..37c121a 100644
    a b public:  
    135135class VocSound : public BaseSound {
    136136public:
    137137        VocSound(Audio::Mixer *mixer, File *file, uint32 base = 0, bool bigEndian = false) : BaseSound(mixer, file, base, bigEndian) {}
     138        Audio::AudioStream *makeAudioStream(uint sound);
    138139        void playSound(uint sound, uint loopSound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, byte flags, int vol = 0);
    139140};
    140141
    void WavSound::playSound(uint sound, uint loopSound, Audio::Mixer::SoundType typ  
    255256        _mixer->playInputStream(type, handle, new LoopingAudioStream(this, sound, loopSound, (flags & Audio::Mixer::FLAG_LOOP) != 0), -1, vol);
    256257}
    257258
     259Audio::AudioStream *VocSound::makeAudioStream(uint sound) {
     260        _file->seek(_offsets[sound], SEEK_SET);
     261        return Audio::makeVOCStream(_file);
     262}
     263
    258264void VocSound::playSound(uint sound, uint loopSound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, byte flags, int vol) {
    259265        if (_offsets == NULL)
    260266                return;
    261267
    262         _file->seek(_offsets[sound], SEEK_SET);
    263 
    264         Audio::AudioStream *stream = Audio::makeVOCStream(*_file, flags);
    265         _mixer->playInputStream(type, handle, stream);
     268        convertVolume(vol);
     269        _mixer->playInputStream(type, handle, new LoopingAudioStream(this, sound, loopSound, (flags & Audio::Mixer::FLAG_LOOP) != 0), -1, vol);
    266270}
    267271
    268272void RawSound::playSound(uint sound, uint loopSound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, byte flags, int vol) {
  • engines/igor/igor.cpp

    diff --git a/engines/igor/igor.cpp b/engines/igor/igor.cpp
    index 6cf7bda..c105ded 100644
    a b void IgorEngine::playSound(int num, int type) {  
    420420                return;
    421421        }
    422422        _sndFile.seek(soundOffset);
    423         Audio::AudioStream *stream = Audio::makeVOCStream(_sndFile, Audio::Mixer::FLAG_UNSIGNED);
     423        Audio::AudioStream *stream = Audio::makeVOCStream(&_sndFile);
    424424        if (stream) {
    425425                _mixer->playInputStream(soundType, soundHandle, stream);
    426426        }
  • engines/kyra/sound.cpp

    diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp
    index 4d42b1e..fae8696 100644
    a b bool KyraEngine_v1::snd_voiceIsPlaying() {  
    230230
    231231// static res
    232232
    233 namespace {
    234 
    235 // A simple wrapper to create VOC streams the way like creating MP3, OGG/Vorbis and FLAC streams.
    236 // Possible TODO: Think of making this complete and moving it to sound/voc.cpp ?
    237 Audio::AudioStream *makeVOCStream(Common::SeekableReadStream *stream, bool disposeAfterUse, uint32 startTime, uint32 duration, uint numLoops) {
    238         Audio::AudioStream *as = Audio::makeVOCStream(*stream, Audio::Mixer::FLAG_UNSIGNED);
    239 
    240         if (disposeAfterUse)
    241                 delete stream;
    242 
    243         return as;
    244 }
    245 
    246 } // end of anonymous namespace
    247 
    248233const Sound::SpeechCodecs Sound::_supportedCodecs[] = {
    249         { ".VOC", makeVOCStream },
    250         { "", makeVOCStream },
     234        { ".VOC", Audio::makeVOCStream },
     235        { "", Audio::makeVOCStream },
    251236
    252237#ifdef USE_MAD
    253238        { ".VO3", Audio::makeMP3Stream },
  • engines/scumm/sound.cpp

    diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
    index 2362427..86bb2fc 100644
    a b void Sound::startTalkSound(uint32 offset, uint32 b, int mode, Audio::SoundHandle  
    662662        #endif
    663663                        break;
    664664                default:
    665                         input = Audio::makeVOCStream(*_sfxFile, Audio::Mixer::FLAG_UNSIGNED);
     665                        input = Audio::makeVOCStream(_sfxFile);
    666666                        break;
    667667                }
    668668
  • engines/touche/resource.cpp

    diff --git a/engines/touche/resource.cpp b/engines/touche/resource.cpp
    index 0434b19..a0f5a8c 100644
    a b void ToucheEngine::res_loadSound(int priority, int num) {  
    589589                uint32 size;
    590590                const uint32 offs = res_getDataOffset(kResourceTypeSound, num, &size);
    591591                _fData.seek(offs);
    592                 Audio::AudioStream *stream = Audio::makeVOCStream(_fData, Audio::Mixer::FLAG_UNSIGNED);
     592                Audio::AudioStream *stream = Audio::makeVOCStream(&_fData);
    593593                if (stream) {
    594594                        _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, stream);
    595595                }
    void ToucheEngine::res_loadSpeechSegment(int num) {  
    647647                                return;
    648648                        }
    649649                        _fSpeech[i].seek(offs);
    650                         stream = Audio::makeVOCStream(_fSpeech[i], Audio::Mixer::FLAG_UNSIGNED);
     650                        stream = Audio::makeVOCStream(&_fSpeech[i]);
    651651                } else {
    652652                        if (num >= 750) {
    653653                                num -= 750;
  • sound/audiostream.cpp

    diff --git a/sound/audiostream.cpp b/sound/audiostream.cpp
    index 61a2e77..5ac179b 100644
    a b int LinearMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buf  
    173173}
    174174
    175175
     176
     177#pragma mark -
     178#pragma mark --- LinearDiskStream ---
     179#pragma mark -
     180
     181
     182
     183/**
     184 *  LinearDiskStream.  This can stream linear (PCM) audio from disk.  The
     185 *  function takes an pointer to an array of LinearDiskStreamAudioBlock which defines the
     186 *  start position and length of each block of uncompressed audio in the stream.
     187 */
     188template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
     189class LinearDiskStream : public AudioStream {
     190
     191// Allow backends to override buffer size
     192#ifdef CUSTOM_AUDIO_BUFFER_SIZE
     193        static const int32 BUFFER_SIZE = CUSTOM_AUDIO_BUFFER_SIZE;
     194#else
     195        static const int32 BUFFER_SIZE = 16384;
     196#endif
     197
     198protected:
     199        byte* _buffer;                  ///< Streaming buffer
     200        const byte *_ptr;               ///< Pointer to current position in stream buffer
     201        const int _rate;                ///< Sample rate of stream
     202
     203        int32 _playtime;                ///< Calculated total play time
     204        Common::SeekableReadStream *_stream;    ///< Stream to read data from
     205        int32 _filePos;                 ///< Current position in stream
     206        int32 _diskLeft;                ///< Samples left in stream in current block not yet read to buffer
     207        int32 _bufferLeft;              ///< Samples left in buffer in current block
     208        bool _ownsStream;               ///< If true, delete stream object when LinearDiskStream is destructed
     209
     210        LinearDiskStreamAudioBlock *_audioBlock;        ///< Audio block list
     211        int _audioBlockCount;           ///< Number of blocks in _audioBlock
     212        int _currentBlock;              ///< Current audio block number
     213
     214        int _beginLoop;                 ///< Loop parameter, currently not implemented
     215        int _endLoop;                   ///< Loop parameter, currently not implemented
     216
     217
     218public:
     219        LinearDiskStream(int rate, uint beginLoop, uint endLoop, bool takeOwnership, Common::SeekableReadStream *stream, LinearDiskStreamAudioBlock *block, uint numBlocks)
     220                : _rate(rate), _stream(stream), _beginLoop(beginLoop), _endLoop(endLoop), _ownsStream(takeOwnership),
     221                  _audioBlockCount(numBlocks) {
     222
     223                // Allocate streaming buffer
     224                if (is16Bit) {
     225                        _buffer = (byte *)malloc(BUFFER_SIZE * sizeof(int16));
     226                } else {
     227                        _buffer = (byte *)malloc(BUFFER_SIZE * sizeof(byte));
     228                }
     229                _ptr = _buffer;
     230                _bufferLeft = 0;
     231
     232                // Copy audio block data to our buffer
     233                _audioBlock = new LinearDiskStreamAudioBlock[numBlocks];
     234                memcpy(_audioBlock, block, numBlocks * sizeof(LinearDiskStreamAudioBlock));
     235
     236                // TODO/FIXME: We also free the "block" parameter here, since it isn't freed anywhere else.
     237                // We also might not be able to assume we can use "delete[]" here, but so far "makeVOCDiskStream"
     238                // is the only place which uses "LinearDiskStream" and that one uses "new[]".
     239                delete[] block;
     240
     241                // Set current buffer state, playing first block
     242                _currentBlock = 0;
     243                _filePos = _audioBlock[_currentBlock].pos;
     244                _diskLeft = _audioBlock[_currentBlock].len;
     245
     246                // Add up length of all blocks in order to caluclate total play time
     247                int len = 0;
     248                for (int r = 0; r < _audioBlockCount; r++) {
     249                        len += _audioBlock[r].len;
     250                }
     251
     252                _playtime = calculatePlayTime(rate, len / (is16Bit ? 2 : 1) / (stereo ? 2 : 1));
     253        }
     254
     255
     256        virtual ~LinearDiskStream() {
     257                if (_ownsStream)
     258                        delete _stream;
     259
     260                delete[] _audioBlock;
     261                free(_buffer);
     262        }
     263        int readBuffer(int16 *buffer, const int numSamples);
     264
     265        bool isStereo() const                   { return stereo; }
     266        bool endOfData() const                  { return (_currentBlock == _audioBlockCount - 1) && (_diskLeft == 0) && (_bufferLeft == 0); }
     267
     268        int getRate() const                     { return _rate; }
     269        int32 getTotalPlayTime() const  { return _playtime; }
     270};
     271
     272template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
     273int LinearDiskStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) {
     274        int oldPos = _stream->pos();
     275        bool restoreFilePosition = false;
     276
     277        int samples = numSamples;
     278
     279        while (samples > 0 && ((_diskLeft > 0 || _bufferLeft > 0) || (_currentBlock != _audioBlockCount - 1))  ) {
     280
     281                // Output samples in the buffer to the output           
     282                int len = MIN(samples, _bufferLeft);
     283                samples -= len;
     284                _bufferLeft -= len;
     285
     286                while (len > 0) {
     287                        *buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, _ptr, isLE);
     288                        _ptr += (is16Bit ? 2 : 1);
     289                        len--;
     290                }
     291
     292                // Have we now finished this block?  If so, read the next block
     293                if ((_bufferLeft == 0) && (_diskLeft == 0) && (_currentBlock != _audioBlockCount - 1)) {
     294                        // Next block
     295                        _currentBlock++;
     296
     297                        _filePos = _audioBlock[_currentBlock].pos;
     298                        _diskLeft = _audioBlock[_currentBlock].len;
     299                }
     300                       
     301
     302                // Now read more data from disk if there is more to be read
     303                if ((_bufferLeft == 0) && (_diskLeft > 0)) {
     304                        int32 readAmount = MIN(_diskLeft, BUFFER_SIZE);
     305
     306                        _stream->seek(_filePos, SEEK_SET);
     307                        _stream->read(_buffer, readAmount * (is16Bit? 2: 1));
     308
     309                        // Amount of data in buffer is now the amount read in, and
     310                        // the amount left to read on disk is decreased by the same amount
     311                        _bufferLeft = readAmount;
     312                        _diskLeft -= readAmount;
     313                        _ptr = (byte*) _buffer;
     314                        _filePos += readAmount * (is16Bit? 2: 1);
     315
     316                        // Set this flag now we've used the file, it restores it's
     317                        // original position.
     318                        restoreFilePosition = true;
     319                }
     320
     321
     322        }
     323
     324        // In case calling code relies on the position of this stream staying
     325        // constant, I restore the location if I've changed it.  This is probably
     326        // not necessary.       
     327        if (restoreFilePosition) {
     328                _stream->seek(oldPos, SEEK_SET);
     329        }
     330
     331        return numSamples-samples;
     332}
     333
     334
     335
    176336#pragma mark -
    177337#pragma mark --- Input stream factory ---
    178338#pragma mark -
    AudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate, byte f  
    202362        const bool isLE       = (flags & Audio::Mixer::FLAG_LITTLE_ENDIAN) != 0;
    203363        const bool autoFree   = (flags & Audio::Mixer::FLAG_AUTOFREE) != 0;
    204364
     365
    205366        uint loopOffset = 0, loopLen = 0;
    206367        if (flags & Audio::Mixer::FLAG_LOOP) {
    207368                if (loopEnd == 0)
    AudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate, byte f  
    236397}
    237398
    238399
     400
     401
     402
     403#define MAKE_LINEAR_DISK(STEREO, UNSIGNED) \
     404                if (is16Bit) { \
     405                        if (isLE) \
     406                                return new LinearDiskStream<STEREO, true, UNSIGNED, true>(rate, loopStart, loopEnd, takeOwnership, stream, block, numBlocks); \
     407                        else  \
     408                                return new LinearDiskStream<STEREO, true, UNSIGNED, false>(rate, loopStart, loopEnd, takeOwnership, stream, block, numBlocks); \
     409                } else \
     410                        return new LinearDiskStream<STEREO, false, UNSIGNED, false>(rate, loopStart, loopEnd, takeOwnership, stream, block, numBlocks)
     411
     412
     413AudioStream *makeLinearDiskStream(Common::SeekableReadStream *stream, LinearDiskStreamAudioBlock *block, int numBlocks, int rate, byte flags, bool takeOwnership, uint loopStart, uint loopEnd) {
     414        const bool isStereo   = (flags & Audio::Mixer::FLAG_STEREO) != 0;
     415        const bool is16Bit    = (flags & Audio::Mixer::FLAG_16BITS) != 0;
     416        const bool isUnsigned = (flags & Audio::Mixer::FLAG_UNSIGNED) != 0;
     417        const bool isLE       = (flags & Audio::Mixer::FLAG_LITTLE_ENDIAN) != 0;
     418
     419
     420        if (isStereo) {
     421                if (isUnsigned) {
     422                        MAKE_LINEAR_DISK(true, true);
     423                } else {
     424                        MAKE_LINEAR_DISK(true, false);
     425                }
     426        } else {
     427                if (isUnsigned) {
     428                        MAKE_LINEAR_DISK(false, true);
     429                } else {
     430                        MAKE_LINEAR_DISK(false, false);
     431                }
     432        }
     433}
     434
     435
     436
     437
    239438#pragma mark -
    240439#pragma mark --- Appendable audio stream ---
    241440#pragma mark -
    BaseAppendableMemoryStream::~BaseAppendableMemoryStream() {  
    306505template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
    307506int AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) {
    308507        Common::StackLock lock(_mutex);
    309 
    310508        int samples = numSamples;
    311509        while (samples > 0 && !eosIntern()) {
    312510                Buffer buf = *_bufferQueue.begin();
  • sound/audiostream.h

    diff --git a/sound/audiostream.h b/sound/audiostream.h
    index a917957..570b3a2 100644
    a b  
    2828
    2929#include "common/util.h"
    3030#include "common/scummsys.h"
    31 
     31#include "common/stream.h"
    3232
    3333namespace Audio {
    3434
    public:  
    109109        virtual int32 getTotalPlayTime() const { return kUnknownPlayTime; }
    110110};
    111111
     112
    112113/**
    113114 * Factory function for a raw linear AudioStream, which will simply treat all data
    114115 * in the buffer described by ptr and len as raw sample data in the specified
    public:  
    118119 */
    119120AudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate, byte flags, uint loopStart, uint loopEnd);
    120121
     122
     123/** Struct used to define the audio data to be played by a LinearDiskStream */
     124
     125struct LinearDiskStreamAudioBlock {
     126        int32 pos;              ///< Position in stream of the block
     127        int32 len;              ///< Length of the block (in samples)
     128};
     129
     130
     131/** Factory function for a Linear Disk Stream.  This can stream linear (PCM) audio from disk.  The
     132 *  function takes an pointer to an array of LinearDiskStreamAudioBlock which defines the
     133 *  start position and length of each block of uncompressed audio in the stream.
     134 */
     135
     136AudioStream *makeLinearDiskStream(Common::SeekableReadStream *stream, LinearDiskStreamAudioBlock *block, int
     137                numBlocks, int rate, byte flags, bool takeOwnership, uint loopStart, uint loopEnd);
     138
    121139/**
    122140 * An audio stream to which additional data can be appended on-the-fly.
    123141 * Used by SMUSH, iMuseDigital, the Kyrandia 3 VQA player, etc.
  • sound/voc.cpp

    diff --git a/sound/voc.cpp b/sound/voc.cpp
    index 3e8d8c2..6b48ea5 100644
    a b byte *loadVOCFromStream(Common::ReadStream &stream, int &size, int &rate) {  
    166166        return loadVOCFromStream(stream, size, rate, loops, begin_loop, end_loop);
    167167}
    168168
    169 AudioStream *makeVOCStream(Common::ReadStream &stream, byte flags, uint loopStart, uint loopEnd) {
     169
     170#ifdef STREAM_AUDIO_FROM_DISK
     171
     172int parseVOCFormat(Common::SeekableReadStream& stream, LinearDiskStreamAudioBlock* block, int &rate, int &loops, int &begin_loop, int &end_loop) {
     173        VocFileHeader fileHeader;
     174        int currentBlock = 0;
     175        int size = 0;
     176
     177        if (stream.read(&fileHeader, 8) != 8)
     178                goto invalid;
     179
     180        if (!memcmp(&fileHeader, "VTLK", 4)) {
     181                if (stream.read(&fileHeader, sizeof(VocFileHeader)) != sizeof(VocFileHeader))
     182                        goto invalid;
     183        } else if (!memcmp(&fileHeader, "Creative", 8)) {
     184                if (stream.read(((byte *)&fileHeader) + 8, sizeof(VocFileHeader) - 8) != sizeof(VocFileHeader) - 8)
     185                        goto invalid;
     186        } else {
     187        invalid:;
     188                warning("loadVOCFromStream: Invalid header");
     189                return 0;
     190        }
     191
     192        if (memcmp(fileHeader.desc, "Creative Voice File", 19) != 0)
     193                error("loadVOCFromStream: Invalid header");
     194        if (fileHeader.desc[19] != 0x1A)
     195                debug(3, "loadVOCFromStream: Partially invalid header");
     196
     197        int32 offset = FROM_LE_16(fileHeader.datablock_offset);
     198        int16 version = FROM_LE_16(fileHeader.version);
     199        int16 code = FROM_LE_16(fileHeader.id);
     200        assert(offset == sizeof(VocFileHeader));
     201        // 0x100 is an invalid VOC version used by German version of DOTT (Disk) and
     202        // French version of Simon the Sorcerer 2 (CD)
     203        assert(version == 0x010A || version == 0x0114 || version == 0x0100);
     204        assert(code == ~version + 0x1234);
     205
     206        int len;
     207        size = 0;
     208        begin_loop = 0;
     209        end_loop = 0;
     210
     211        while ((code = stream.readByte())) {
     212                len = stream.readByte();
     213                len |= stream.readByte() << 8;
     214                len |= stream.readByte() << 16;
     215
     216                switch (code) {
     217                case 1:
     218                case 9: {
     219                        int packing;
     220                        if (code == 1) {
     221                                int time_constant = stream.readByte();
     222                                packing = stream.readByte();
     223                                len -= 2;
     224                                rate = getSampleRateFromVOCRate(time_constant);
     225                        } else {
     226                                rate = stream.readUint32LE();
     227                                int bits = stream.readByte();
     228                                int channels = stream.readByte();
     229                                if (bits != 8 || channels != 1) {
     230                                        warning("Unsupported VOC file format (%d bits per sample, %d channels)", bits, channels);
     231                                        break;
     232                                }
     233                                packing = stream.readUint16LE();
     234                                stream.readUint32LE();
     235                                len -= 12;
     236                        }
     237                        debug(9, "VOC Data Block: %d, %d, %d", rate, packing, len);
     238                        if (packing == 0) {
     239                               
     240                                // Found a data block - so add it to the block list
     241                                block[currentBlock].pos = stream.pos();
     242                                block[currentBlock].len = len;
     243                                currentBlock++;
     244
     245                                stream.seek(len, SEEK_CUR);
     246
     247                                size += len;
     248                                begin_loop = size;
     249                                end_loop = size;
     250                        } else {
     251                                warning("VOC file packing %d unsupported", packing);
     252                        }
     253                        } break;
     254                case 3: // silence
     255                        // occur with a few Igor sounds, voc file starts with a silence block with a
     256                        // frequency different from the data block. Just ignore fow now (implementing
     257                        // it wouldn't make a big difference anyway...)
     258                        assert(len == 3);
     259                        stream.readUint16LE();
     260                        stream.readByte();
     261                        break;
     262                case 6: // begin of loop
     263                        assert(len == 2);
     264                        loops = stream.readUint16LE();
     265                        break;
     266                case 7: // end of loop
     267                        assert(len == 0);
     268                        break;
     269                case 8: // "Extended"
     270                        // This occures in the LoL Intro demo. This block can usually be used to create stereo
     271                        // sound, but the LoL intro has only an empty block, thus this dummy implementation will
     272                        // work.
     273                        assert(len == 4);
     274                        stream.readUint16LE();
     275                        stream.readByte();
     276                        stream.readByte();
     277                        break;
     278                default:
     279                        warning("Unhandled code in VOC file : %d", code);
     280                        return 0;
     281                }
     282        }
     283        debug(4, "VOC Data Size : %d", size);
     284        return currentBlock;
     285}
     286
     287AudioStream *makeVOCDiskStream(Common::SeekableReadStream *stream, bool takeOwnership) {
     288        const int MAX_AUDIO_BLOCKS = 256;
     289
     290        LinearDiskStreamAudioBlock* block = new LinearDiskStreamAudioBlock[MAX_AUDIO_BLOCKS];
     291        int rate, loops, begin_loop, end_loop;
     292
     293        int numBlocks = parseVOCFormat(*stream, block, rate, loops, begin_loop, end_loop);
     294
     295        return makeLinearDiskStream(stream, block, numBlocks, rate, Audio::Mixer::FLAG_UNSIGNED, takeOwnership, begin_loop, end_loop);
     296}
     297
     298#endif
     299
     300
     301AudioStream *makeVOCStream(Common::SeekableReadStream *stream, bool disposeStreamAfterUse, uint loopStart, uint loopEnd, uint numLoops) {
     302#ifdef STREAM_AUDIO_FROM_DISK
     303        return makeVOCDiskStream(stream, disposeStreamAfterUse);
     304#else
    170305        int size, rate;
    171306
    172         byte *data = loadVOCFromStream(stream, size, rate);
     307        byte *data = loadVOCFromStream(*stream, size, rate);
     308
     309        if (disposeStreamAfterUse)
     310                delete stream;
     311
    173312        if (!data)
    174313                return 0;
    175314
    176         return makeLinearInputStream(data, size, rate, flags | Audio::Mixer::FLAG_AUTOFREE, loopStart, loopEnd);
     315        return makeLinearInputStream(data, size, rate, Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE, loopStart, loopEnd);
     316#endif
    177317}
    178318
    179319
  • sound/voc.h

    diff --git a/sound/voc.h b/sound/voc.h
    index 2b4796e..2a18f0f 100644
    a b  
    4141#include "common/scummsys.h"
    4242
    4343namespace Common { class ReadStream; }
     44namespace Common { class SeekableReadStream; }
    4445
    4546namespace Audio {
    4647
    struct VocBlockHeader {  
    7879extern int getSampleRateFromVOCRate(int vocSR);
    7980
    8081/**
    81  * Try to load a VOC from the given seekable stream. Returns a pointer to memory
     82 * Try to load a VOC from the given stream. Returns a pointer to memory
    8283 * containing the PCM sample data (allocated with malloc). It is the callers
    8384 * responsibility to dellocate that data again later on! Currently this
    8485 * function only supports uncompressed raw PCM data.
    extern byte *loadVOCFromStream(Common::ReadStream &stream, int &size, int &rate)  
    9293 *
    9394 * This function uses loadVOCFromStream() internally.
    9495 */
    95 AudioStream *makeVOCStream(Common::ReadStream &stream, byte flags = 0, uint loopStart = 0, uint loopEnd = 0);
     96AudioStream *makeVOCStream(Common::SeekableReadStream *stream, bool disposeStreamAfterUse = false, uint32 loopStart = 0, uint32 loopEnd = 0, uint numLoops = 0);
    9697
    9798} // End of namespace Audio
    9899