Ticket #9066: streaming_voc_patch_v2_clean.patch
File streaming_voc_patch_v2_clean.patch, 17.8 KB (added by , 15 years ago) |
---|
-
engines/agos/sound.cpp
diff --git a/engines/agos/sound.cpp b/engines/agos/sound.cpp index d20c07a..cdf28e9 100644
a b public: 133 133 }; 134 134 135 135 class VocSound : public BaseSound { 136 byte _flags; 136 137 public: 137 VocSound(Audio::Mixer *mixer, File *file, uint32 base = 0, bool bigEndian = false) : BaseSound(mixer, file, base, bigEndian) {} 138 VocSound(Audio::Mixer *mixer, File *file, uint32 base = 0, bool bigEndian = false) : BaseSound(mixer, file, base, bigEndian), _flags(0) {} 139 Audio::AudioStream *makeAudioStream(uint sound); 138 140 void playSound(uint sound, uint loopSound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, byte flags, int vol = 0); 139 141 }; 140 142 … … void WavSound::playSound(uint sound, uint loopSound, Audio::Mixer::SoundType typ 255 257 _mixer->playInputStream(type, handle, new LoopingAudioStream(this, sound, loopSound, (flags & Audio::Mixer::FLAG_LOOP) != 0), -1, vol); 256 258 } 257 259 258 void VocSound::playSound(uint sound, uint loopSound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, byte flags, int vol) { 259 if (_offsets == NULL) 260 return; 261 260 Audio::AudioStream *VocSound::makeAudioStream(uint sound) { 262 261 _file->seek(_offsets[sound], SEEK_SET); 262 return Audio::makeVOCStream(*_file, _flags); 263 } 263 264 264 Audio::AudioStream *stream = Audio::makeVOCStream(*_file, flags); 265 _mixer->playInputStream(type, handle, stream); 265 void VocSound::playSound(uint sound, uint loopSound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, byte flags, int vol) { 266 convertVolume(vol); 267 _flags = flags; 268 _mixer->playInputStream(type, handle, new LoopingAudioStream(this, sound, loopSound, (flags & Audio::Mixer::FLAG_LOOP) != 0), -1, vol); 266 269 } 267 270 268 271 void RawSound::playSound(uint sound, uint loopSound, Audio::Mixer::SoundType type, Audio::SoundHandle *handle, byte flags, int vol) { -
engines/kyra/sound.cpp
diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp index 4d42b1e..91945d9 100644
a b namespace { 235 235 // A simple wrapper to create VOC streams the way like creating MP3, OGG/Vorbis and FLAC streams. 236 236 // Possible TODO: Think of making this complete and moving it to sound/voc.cpp ? 237 237 Audio::AudioStream *makeVOCStream(Common::SeekableReadStream *stream, bool disposeAfterUse, uint32 startTime, uint32 duration, uint numLoops) { 238 239 #ifdef STREAM_AUDIO_FROM_DISK 240 Audio::AudioStream *as = Audio::makeVOCStream(*stream, Audio::Mixer::FLAG_UNSIGNED, 0, 0, disposeAfterUse); 241 #else 238 242 Audio::AudioStream *as = Audio::makeVOCStream(*stream, Audio::Mixer::FLAG_UNSIGNED); 239 243 240 244 if (disposeAfterUse) 241 245 delete stream; 246 #endif 242 247 243 248 return as; 244 249 } -
sound/audiostream.cpp
diff --git a/sound/audiostream.cpp b/sound/audiostream.cpp index 61a2e77..36c86fe 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 _playtime = calculatePlayTime(rate, len / (is16Bit ? 2 : 1) / (stereo ? 2 : 1)); 252 } 253 254 255 virtual ~LinearDiskStream() { 256 if (_ownsStream) { 257 delete _stream; 258 } 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 // In case calling code relies on the position of this stream staying 323 // constant, I restore the location if I've changed it. This is probably 324 // not necessary. 325 if (restoreFilePosition) { 326 _stream->seek(oldPos, SEEK_SET); 327 } 328 329 return numSamples-samples; 330 } 331 332 333 176 334 #pragma mark - 177 335 #pragma mark --- Input stream factory --- 178 336 #pragma mark - … … AudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate, byte f 202 360 const bool isLE = (flags & Audio::Mixer::FLAG_LITTLE_ENDIAN) != 0; 203 361 const bool autoFree = (flags & Audio::Mixer::FLAG_AUTOFREE) != 0; 204 362 363 205 364 uint loopOffset = 0, loopLen = 0; 206 365 if (flags & Audio::Mixer::FLAG_LOOP) { 207 366 if (loopEnd == 0) … … AudioStream *makeLinearInputStream(const byte *ptr, uint32 len, int rate, byte f 236 395 } 237 396 238 397 398 399 400 401 #define MAKE_LINEAR_DISK(STEREO, UNSIGNED) \ 402 if (is16Bit) { \ 403 if (isLE) \ 404 return new LinearDiskStream<STEREO, true, UNSIGNED, true>(rate, loopStart, loopEnd, takeOwnership, &stream, block, numBlocks); \ 405 else \ 406 return new LinearDiskStream<STEREO, true, UNSIGNED, false>(rate, loopStart, loopEnd, takeOwnership, &stream, block, numBlocks); \ 407 } else \ 408 return new LinearDiskStream<STEREO, false, UNSIGNED, false>(rate, loopStart, loopEnd, takeOwnership, &stream, block, numBlocks) 409 410 411 AudioStream *makeLinearDiskStream(Common::SeekableReadStream& stream, LinearDiskStreamAudioBlock* block, int numBlocks, int rate, byte flags, bool takeOwnership, uint loopStart, uint loopEnd) { 412 const bool isStereo = (flags & Audio::Mixer::FLAG_STEREO) != 0; 413 const bool is16Bit = (flags & Audio::Mixer::FLAG_16BITS) != 0; 414 const bool isUnsigned = (flags & Audio::Mixer::FLAG_UNSIGNED) != 0; 415 const bool isLE = (flags & Audio::Mixer::FLAG_LITTLE_ENDIAN) != 0; 416 417 418 if (isStereo) { 419 if (isUnsigned) { 420 MAKE_LINEAR_DISK(true, true); 421 } else { 422 MAKE_LINEAR_DISK(true, false); 423 } 424 } else { 425 if (isUnsigned) { 426 MAKE_LINEAR_DISK(false, true); 427 } else { 428 MAKE_LINEAR_DISK(false, false); 429 } 430 } 431 } 432 433 434 435 239 436 #pragma mark - 240 437 #pragma mark --- Appendable audio stream --- 241 438 #pragma mark - … … BaseAppendableMemoryStream::~BaseAppendableMemoryStream() { 306 503 template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE> 307 504 int AppendableMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) { 308 505 Common::StackLock lock(_mutex); 309 310 506 int samples = numSamples; 311 507 while (samples > 0 && !eosIntern()) { 312 508 Buffer buf = *_bufferQueue.begin(); -
sound/audiostream.h
diff --git a/sound/audiostream.h b/sound/audiostream.h index a917957..543c0ad 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..0853018 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, byte flags, 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, flags, takeOwnership, begin_loop, end_loop); 296 } 297 298 #endif 299 300 301 AudioStream *makeVOCStream(Common::SeekableReadStream &stream, byte flags, uint loopStart, uint loopEnd, bool takeOwnershipOfStream) { 302 #ifdef STREAM_AUDIO_FROM_DISK 303 return makeVOCDiskStream(stream, flags, takeOwnershipOfStream); 304 #else 170 305 int size, rate; 171 306 172 307 byte *data = loadVOCFromStream(stream, size, rate); 308 173 309 if (!data) 174 310 return 0; 175 311 176 312 return makeLinearInputStream(data, size, rate, flags | Audio::Mixer::FLAG_AUTOFREE, loopStart, loopEnd); 313 #endif 177 314 } 178 315 179 316 -
sound/voc.h
diff --git a/sound/voc.h b/sound/voc.h index 2b4796e..c696afb 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, byte flags = 0, uint loopStart = 0, uint loopEnd = 0, bool takeOwnershipOfStream = false); 96 97 97 98 } // End of namespace Audio 98 99