Ticket #9066: streaming_voc_patch_v2.patch
File streaming_voc_patch_v2.patch, 19.7 KB (added by , 14 years ago) |
---|
-
engines/agos/sound.cpp
diff --git a/engines/agos/sound.cpp b/engines/agos/sound.cpp index d20c07a..37c121a 100644
a b public: 135 135 class VocSound : public BaseSound { 136 136 public: 137 137 VocSound(Audio::Mixer *mixer, File *file, uint32 base = 0, bool bigEndian = false) : BaseSound(mixer, file, base, bigEndian) {} 138 Audio::AudioStream *makeAudioStream(uint sound); 138 139 void playSound(uint sound, uint loopSound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, byte flags, int vol = 0); 139 140 }; 140 141 … … void WavSound::playSound(uint sound, uint loopSound, Audio::Mixer::SoundType typ 255 256 _mixer->playInputStream(type, handle, new LoopingAudioStream(this, sound, loopSound, (flags & Audio::Mixer::FLAG_LOOP) != 0), -1, vol); 256 257 } 257 258 259 Audio::AudioStream *VocSound::makeAudioStream(uint sound) { 260 _file->seek(_offsets[sound], SEEK_SET); 261 return Audio::makeVOCStream(_file); 262 } 263 258 264 void VocSound::playSound(uint sound, uint loopSound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, byte flags, int vol) { 259 265 if (_offsets == NULL) 260 266 return; 261 267 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); 266 270 } 267 271 268 272 void 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) { 420 420 return; 421 421 } 422 422 _sndFile.seek(soundOffset); 423 Audio::AudioStream *stream = Audio::makeVOCStream( _sndFile, Audio::Mixer::FLAG_UNSIGNED);423 Audio::AudioStream *stream = Audio::makeVOCStream(&_sndFile); 424 424 if (stream) { 425 425 _mixer->playInputStream(soundType, soundHandle, stream); 426 426 } -
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() { 230 230 231 231 // static res 232 232 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 namespace247 248 233 const Sound::SpeechCodecs Sound::_supportedCodecs[] = { 249 { ".VOC", makeVOCStream },250 { "", makeVOCStream },234 { ".VOC", Audio::makeVOCStream }, 235 { "", Audio::makeVOCStream }, 251 236 252 237 #ifdef USE_MAD 253 238 { ".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 662 662 #endif 663 663 break; 664 664 default: 665 input = Audio::makeVOCStream( *_sfxFile, Audio::Mixer::FLAG_UNSIGNED);665 input = Audio::makeVOCStream(_sfxFile); 666 666 break; 667 667 } 668 668 -
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) { 589 589 uint32 size; 590 590 const uint32 offs = res_getDataOffset(kResourceTypeSound, num, &size); 591 591 _fData.seek(offs); 592 Audio::AudioStream *stream = Audio::makeVOCStream( _fData, Audio::Mixer::FLAG_UNSIGNED);592 Audio::AudioStream *stream = Audio::makeVOCStream(&_fData); 593 593 if (stream) { 594 594 _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, stream); 595 595 } … … void ToucheEngine::res_loadSpeechSegment(int num) { 647 647 return; 648 648 } 649 649 _fSpeech[i].seek(offs); 650 stream = Audio::makeVOCStream( _fSpeech[i], Audio::Mixer::FLAG_UNSIGNED);650 stream = Audio::makeVOCStream(&_fSpeech[i]); 651 651 } else { 652 652 if (num >= 750) { 653 653 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 173 173 } 174 174 175 175 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 */ 188 template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE> 189 class 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 198 protected: 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 218 public: 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 272 template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE> 273 int 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 176 336 #pragma mark - 177 337 #pragma mark --- Input stream factory --- 178 338 #pragma mark - … … AudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate, byte f 202 362 const bool isLE = (flags & Audio::Mixer::FLAG_LITTLE_ENDIAN) != 0; 203 363 const bool autoFree = (flags & Audio::Mixer::FLAG_AUTOFREE) != 0; 204 364 365 205 366 uint loopOffset = 0, loopLen = 0; 206 367 if (flags & Audio::Mixer::FLAG_LOOP) { 207 368 if (loopEnd == 0) … … AudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate, byte f 236 397 } 237 398 238 399 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 413 AudioStream *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 239 438 #pragma mark - 240 439 #pragma mark --- Appendable audio stream --- 241 440 #pragma mark - … … BaseAppendableMemoryStream::~BaseAppendableMemoryStream() { 306 505 template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE> 307 506 int AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) { 308 507 Common::StackLock lock(_mutex); 309 310 508 int samples = numSamples; 311 509 while (samples > 0 && !eosIntern()) { 312 510 Buffer buf = *_bufferQueue.begin(); -
sound/audiostream.h
diff --git a/sound/audiostream.h b/sound/audiostream.h index a917957..570b3a2 100644
a b 28 28 29 29 #include "common/util.h" 30 30 #include "common/scummsys.h" 31 31 #include "common/stream.h" 32 32 33 33 namespace Audio { 34 34 … … public: 109 109 virtual int32 getTotalPlayTime() const { return kUnknownPlayTime; } 110 110 }; 111 111 112 112 113 /** 113 114 * Factory function for a raw linear AudioStream, which will simply treat all data 114 115 * in the buffer described by ptr and len as raw sample data in the specified … … public: 118 119 */ 119 120 AudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate, byte flags, uint loopStart, uint loopEnd); 120 121 122 123 /** Struct used to define the audio data to be played by a LinearDiskStream */ 124 125 struct 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 136 AudioStream *makeLinearDiskStream(Common::SeekableReadStream *stream, LinearDiskStreamAudioBlock *block, int 137 numBlocks, int rate, byte flags, bool takeOwnership, uint loopStart, uint loopEnd); 138 121 139 /** 122 140 * An audio stream to which additional data can be appended on-the-fly. 123 141 * 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) { 166 166 return loadVOCFromStream(stream, size, rate, loops, begin_loop, end_loop); 167 167 } 168 168 169 AudioStream *makeVOCStream(Common::ReadStream &stream, byte flags, uint loopStart, uint loopEnd) { 169 170 #ifdef STREAM_AUDIO_FROM_DISK 171 172 int 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 287 AudioStream *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 301 AudioStream *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 170 305 int size, rate; 171 306 172 byte *data = loadVOCFromStream(stream, size, rate); 307 byte *data = loadVOCFromStream(*stream, size, rate); 308 309 if (disposeStreamAfterUse) 310 delete stream; 311 173 312 if (!data) 174 313 return 0; 175 314 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 177 317 } 178 318 179 319 -
sound/voc.h
diff --git a/sound/voc.h b/sound/voc.h index 2b4796e..2a18f0f 100644
a b 41 41 #include "common/scummsys.h" 42 42 43 43 namespace Common { class ReadStream; } 44 namespace Common { class SeekableReadStream; } 44 45 45 46 namespace Audio { 46 47 … … struct VocBlockHeader { 78 79 extern int getSampleRateFromVOCRate(int vocSR); 79 80 80 81 /** 81 * Try to load a VOC from the given s eekable stream. Returns a pointer to memory82 * Try to load a VOC from the given stream. Returns a pointer to memory 82 83 * containing the PCM sample data (allocated with malloc). It is the callers 83 84 * responsibility to dellocate that data again later on! Currently this 84 85 * function only supports uncompressed raw PCM data. … … extern byte *loadVOCFromStream(Common::ReadStream &stream, int &size, int &rate) 92 93 * 93 94 * This function uses loadVOCFromStream() internally. 94 95 */ 95 AudioStream *makeVOCStream(Common:: ReadStream &stream, byte flags = 0, uint loopStart = 0, uint loopEnd= 0);96 AudioStream *makeVOCStream(Common::SeekableReadStream *stream, bool disposeStreamAfterUse = false, uint32 loopStart = 0, uint32 loopEnd = 0, uint numLoops = 0); 96 97 97 98 } // End of namespace Audio 98 99