ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

voc.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/debug.h"
00024 #include "common/endian.h"
00025 #include "common/util.h"
00026 #include "common/stream.h"
00027 #include "common/textconsole.h"
00028 #include "common/list.h"
00029 
00030 #include "audio/audiostream.h"
00031 #include "audio/decoders/raw.h"
00032 #include "audio/decoders/voc.h"
00033 
00034 namespace Audio {
00035 
00036 namespace {
00037 
00038 bool checkVOCHeader(Common::ReadStream &stream) {
00039     VocFileHeader fileHeader;
00040 
00041     if (stream.read(&fileHeader, 8) != 8)
00042         return false;
00043 
00044     if (!memcmp(&fileHeader, "VTLK", 4)) {
00045         if (stream.read(&fileHeader, sizeof(VocFileHeader)) != sizeof(VocFileHeader))
00046             return false;
00047     } else if (!memcmp(&fileHeader, "Creative", 8)) {
00048         if (stream.read(((byte *)&fileHeader) + 8, sizeof(VocFileHeader) - 8) != sizeof(VocFileHeader) - 8)
00049             return false;
00050     } else {
00051         return false;
00052     }
00053 
00054     if (memcmp(fileHeader.desc, "Creative Voice File", 19) != 0)
00055         return false;
00056     //if (fileHeader.desc[19] != 0x1A)
00057     //  debug(3, "checkVOCHeader: Partially invalid header");
00058 
00059     int32 offset = FROM_LE_16(fileHeader.datablock_offset);
00060     int16 version = FROM_LE_16(fileHeader.version);
00061     int16 code = FROM_LE_16(fileHeader.id);
00062 
00063     if (offset != sizeof(VocFileHeader))
00064         return false;
00065 
00066     // 0x100 is an invalid VOC version used by German version of DOTT (Disk) and
00067     // French version of Simon the Sorcerer 2 (CD)
00068     if (version != 0x010A && version != 0x0114 && version != 0x0100)
00069         return false;
00070 
00071     if (code != ~version + 0x1234)
00072         return false;
00073 
00074     return true;
00075 }
00076 
00077 class VocStream : public SeekableAudioStream {
00078 public:
00079     VocStream(Common::SeekableReadStream *stream, bool isUnsigned, DisposeAfterUse::Flag disposeAfterUse);
00080     ~VocStream();
00081 
00082     virtual int readBuffer(int16 *buffer, const int numSamples);
00083 
00084     virtual bool isStereo() const { return false; }
00085 
00086     virtual int getRate() const { return _rate; }
00087 
00088     virtual bool endOfData() const { return (_curBlock == _blocks.end()) && (_blockLeft == 0); }
00089 
00090     virtual bool seek(const Timestamp &where);
00091 
00092     virtual Timestamp getLength() const { return _length; }
00093 private:
00094     void preProcess();
00095 
00096     Common::SeekableReadStream *const _stream;
00097     const DisposeAfterUse::Flag _disposeAfterUse;
00098 
00099     const bool _isUnsigned;
00100 
00101     int _rate;
00102     Timestamp _length;
00103 
00104     struct Block {
00105         uint8 code;
00106         uint32 length;
00107 
00108         union {
00109             struct {
00110                 uint32 offset;
00111                 int rate;
00112                 int samples;
00113             } sampleBlock;
00114 
00115             struct {
00116                 int count;
00117             } loopBlock;
00118         };
00119     };
00120 
00121     typedef Common::List<Block> BlockList;
00122     BlockList _blocks;
00123 
00124     BlockList::const_iterator _curBlock;
00125     uint32 _blockLeft;
00126 
00131     void updateBlockIfNeeded();
00132 
00133     // Do some internal buffering for systems with really slow slow disk i/o
00134     enum {
00141         kSampleBufferLength = 2048
00142     };
00143     byte _buffer[kSampleBufferLength];
00144 
00151     int fillBuffer(int maxSamples);
00152 };
00153 
00154 VocStream::VocStream(Common::SeekableReadStream *stream, bool isUnsigned, DisposeAfterUse::Flag disposeAfterUse)
00155     : _stream(stream), _disposeAfterUse(disposeAfterUse), _isUnsigned(isUnsigned), _rate(0),
00156       _length(), _blocks(), _curBlock(_blocks.end()), _blockLeft(0), _buffer() {
00157     preProcess();
00158 }
00159 
00160 VocStream::~VocStream() {
00161     if (_disposeAfterUse == DisposeAfterUse::YES)
00162         delete _stream;
00163 }
00164 
00165 int VocStream::readBuffer(int16 *buffer, const int numSamples) {
00166     int samplesLeft = numSamples;
00167     while (samplesLeft > 0) {
00168         // Try to read up to "samplesLeft" samples.
00169         int len = fillBuffer(samplesLeft);
00170 
00171         // In case we were not able to read any samples
00172         // we will stop reading here.
00173         if (!len)
00174             break;
00175 
00176         // Adjust the samples left to read.
00177         samplesLeft -= len;
00178 
00179         // Copy the data to the caller's buffer.
00180         const byte *src = _buffer;
00181         while (len-- > 0)
00182             *buffer++ = (*src++ << 8) ^ (_isUnsigned ? 0x8000 : 0);
00183     }
00184 
00185     return numSamples - samplesLeft;
00186 }
00187 
00188 void VocStream::updateBlockIfNeeded() {
00189     // Have we now finished this block? If so, read the next block
00190     if (_blockLeft == 0 && _curBlock != _blocks.end()) {
00191         // Find the next sample block
00192         while (true) {
00193             // Next block
00194             ++_curBlock;
00195 
00196             // Check whether we reached the end of the stream
00197             // yet.
00198             if (_curBlock == _blocks.end())
00199                 return;
00200 
00201             // Skip all none sample blocks for now
00202             if (_curBlock->code != 1 && _curBlock->code != 9)
00203                 continue;
00204 
00205             _stream->seek(_curBlock->sampleBlock.offset, SEEK_SET);
00206 
00207             // In case of an error we will stop
00208             // stream playback.
00209             if (_stream->err()) {
00210                 _blockLeft = 0;
00211                 _curBlock = _blocks.end();
00212             } else {
00213                 _blockLeft = _curBlock->sampleBlock.samples;
00214             }
00215 
00216             return;
00217         }
00218     }
00219 }
00220 
00221 int VocStream::fillBuffer(int maxSamples) {
00222     int bufferedSamples = 0;
00223     byte *dst = _buffer;
00224 
00225     // We can only read up to "kSampleBufferLength" samples
00226     // so we take this into consideration, when trying to
00227     // read up to maxSamples.
00228     maxSamples = MIN<int>(kSampleBufferLength, maxSamples);
00229 
00230     // We will only read up to maxSamples
00231     while (maxSamples > 0 && !endOfData()) {
00232         // Calculate how many samples we can safely read
00233         // from the current block.
00234         const int len = MIN<int>(maxSamples, _blockLeft);
00235 
00236         // Try to read all the sample data and update the
00237         // destination pointer.
00238         const int bytesRead = _stream->read(dst, len);
00239         dst += bytesRead;
00240 
00241         // Calculate how many samples we actually read.
00242         const int samplesRead = bytesRead;
00243 
00244         // Update all status variables
00245         bufferedSamples += samplesRead;
00246         maxSamples -= samplesRead;
00247         _blockLeft -= samplesRead;
00248 
00249         // In case of an error we will stop
00250         // stream playback.
00251         if (_stream->err()) {
00252             _blockLeft = 0;
00253             _curBlock = _blocks.end();
00254             break;
00255         }
00256 
00257         // Advance to the next block in case the current
00258         // one is already finished.
00259         updateBlockIfNeeded();
00260     }
00261 
00262     return bufferedSamples;
00263 }
00264 
00265 bool VocStream::seek(const Timestamp &where) {
00266     // Invalidate stream
00267     _blockLeft = 0;
00268     _curBlock = _blocks.end();
00269 
00270     if (where > _length)
00271         return false;
00272 
00273     // Search for the block containing the requested sample
00274     const uint32 seekSample = convertTimeToStreamPos(where, getRate(), isStereo()).totalNumberOfFrames();
00275     uint32 curSample = 0;
00276 
00277     for (_curBlock = _blocks.begin(); _curBlock != _blocks.end(); ++_curBlock) {
00278         // Skip all none sample blocks for now
00279         if (_curBlock->code != 1 && _curBlock->code != 9)
00280             continue;
00281 
00282         uint32 nextBlockSample = curSample + _curBlock->sampleBlock.samples;
00283 
00284         if (nextBlockSample > seekSample)
00285             break;
00286 
00287         curSample = nextBlockSample;
00288     }
00289 
00290     if (_curBlock == _blocks.end()) {
00291         return ((seekSample - curSample) == 0);
00292     } else {
00293         const uint32 offset = seekSample - curSample;
00294 
00295         _stream->seek(_curBlock->sampleBlock.offset + offset, SEEK_SET);
00296 
00297         // In case of an error we will stop
00298         // stream playback.
00299         if (_stream->err()) {
00300             _blockLeft = 0;
00301             _curBlock = _blocks.end();
00302         } else {
00303             _blockLeft = _curBlock->sampleBlock.samples - offset;
00304         }
00305 
00306         return true;
00307     }
00308 }
00309 
00310 void VocStream::preProcess() {
00311     Block block;
00312 
00313     // Scan through the file and collect all blocks
00314     while (true) {
00315         block.code = _stream->readByte();
00316         block.length = 0;
00317 
00318         // If we hit EOS here we found the end of the VOC file.
00319         // According to http://wiki.multimedia.cx/index.php?title=Creative_Voice
00320         // there is no need for an "Terminator" block to be present.
00321         // In case we hit a "Terminator" block we also break here.
00322         if (_stream->eos() || block.code == 0)
00323             break;
00324         // We will allow invalid block numbers as terminators. This is needed,
00325         // since some games ship broken VOC files. The following occasions are
00326         // known:
00327         // - 128 is used as terminator in Simon 1 Amiga CD32
00328         // - Full Throttle contains a VOC file with an incorrect block length
00329         //   resulting in a sample (127) to be read as block code.
00330         if (block.code > 9) {
00331             warning("VocStream::preProcess: Caught %d as terminator", block.code);
00332             break;
00333         }
00334 
00335         block.length = _stream->readByte();
00336         block.length |= _stream->readByte() << 8;
00337         block.length |= _stream->readByte() << 16;
00338 
00339         // Premature end of stream => error!
00340         if (_stream->eos() || _stream->err()) {
00341             warning("VocStream::preProcess: Reading failed");
00342             return;
00343         }
00344 
00345         uint32 skip = 0;
00346 
00347         switch (block.code) {
00348         // Sound data
00349         case 1:
00350         // Sound data (New format)
00351         case 9:
00352             if (block.code == 1) {
00353                 if (block.length < 2) {
00354                     warning("Invalid sound data block length %d in VOC file", block.length);
00355                     return;
00356                 }
00357 
00358                 // Read header data
00359                 int freqDiv = _stream->readByte();
00360                 // Prevent division through 0
00361                 if (freqDiv == 256) {
00362                     warning("Invalid frequency divisor 256 in VOC file");
00363                     return;
00364                 }
00365                 block.sampleBlock.rate = getSampleRateFromVOCRate(freqDiv);
00366 
00367                 int codec = _stream->readByte();
00368                 // We only support 8bit PCM
00369                 if (codec != 0) {
00370                     warning("Unhandled codec %d in VOC file", codec);
00371                     return;
00372                 }
00373 
00374                 block.sampleBlock.samples = skip = block.length - 2;
00375                 block.sampleBlock.offset = _stream->pos();
00376 
00377                 // Check the last block if there is any
00378                 if (_blocks.size() > 0) {
00379                     BlockList::iterator lastBlock = _blocks.end();
00380                     --lastBlock;
00381                     // When we have found a block 8 as predecessor
00382                     // we need to use its settings
00383                     if (lastBlock->code == 8) {
00384                         block.sampleBlock.rate = lastBlock->sampleBlock.rate;
00385                         // Remove the block since we don't need it anymore
00386                         _blocks.erase(lastBlock);
00387                     }
00388                 }
00389             } else {
00390                 if (block.length < 12) {
00391                     warning("Invalid sound data (wew format) block length %d in VOC file", block.length);
00392                     return;
00393                 }
00394 
00395                 block.sampleBlock.rate = _stream->readUint32LE();
00396                 int bitsPerSample = _stream->readByte();
00397                 // We only support 8bit PCM
00398                 if (bitsPerSample != 8) {
00399                     warning("Unhandled bits per sample %d in VOC file", bitsPerSample);
00400                     return;
00401                 }
00402                 int channels = _stream->readByte();
00403                 // We only support mono
00404                 if (channels != 1) {
00405                     warning("Unhandled channel count %d in VOC file", channels);
00406                     return;
00407                 }
00408                 int codec = _stream->readUint16LE();
00409                 // We only support 8bit PCM
00410                 if (codec != 0) {
00411                     warning("Unhandled codec %d in VOC file", codec);
00412                     return;
00413                 }
00414                 /*uint32 reserved = */_stream->readUint32LE();
00415                 block.sampleBlock.offset = _stream->pos();
00416                 block.sampleBlock.samples = skip = block.length - 12;
00417             }
00418 
00419             // Check whether we found a new highest rate
00420             if (_rate < block.sampleBlock.rate)
00421                 _rate = block.sampleBlock.rate;
00422             break;
00423 
00424         // Silence
00425         case 3: {
00426             if (block.length != 3) {
00427                 warning("Invalid silence block length %d in VOC file", block.length);
00428                 return;
00429             }
00430 
00431             block.sampleBlock.offset = 0;
00432 
00433             block.sampleBlock.samples = _stream->readUint16LE() + 1;
00434             int freqDiv = _stream->readByte();
00435             // Prevent division through 0
00436             if (freqDiv == 256) {
00437                 warning("Invalid frequency divisor 256 in VOC file");
00438                 return;
00439             }
00440             block.sampleBlock.rate = getSampleRateFromVOCRate(freqDiv);
00441             } break;
00442 
00443         // Repeat start
00444         case 6:
00445             if (block.length != 2) {
00446                 warning("Invalid repeat start block length %d in VOC file", block.length);
00447                 return;
00448             }
00449 
00450             block.loopBlock.count = _stream->readUint16LE() + 1;
00451             break;
00452 
00453         // Repeat end
00454         case 7:
00455             break;
00456 
00457         // Extra info
00458         case 8: {
00459             if (block.length != 4)
00460                 return;
00461 
00462             int freqDiv = _stream->readUint16LE();
00463             // Prevent division through 0
00464             if (freqDiv == 65536) {
00465                 warning("Invalid frequency divisor 65536 in VOC file");
00466                 return;
00467             }
00468 
00469             int codec = _stream->readByte();
00470             // We only support RAW 8bit PCM.
00471             if (codec != 0) {
00472                 warning("Unhandled codec %d in VOC file", codec);
00473                 return;
00474             }
00475 
00476             int channels = _stream->readByte() + 1;
00477             // We only support mono sound right now
00478             if (channels != 1) {
00479                 warning("Unhandled channel count %d in VOC file", channels);
00480                 return;
00481             }
00482 
00483             block.sampleBlock.offset = 0;
00484             block.sampleBlock.samples = 0;
00485             block.sampleBlock.rate = 256000000L / (65536L - freqDiv);
00486             } break;
00487 
00488         default:
00489             warning("Unhandled code %d in VOC file (len %d)", block.code, block.length);
00490             // Skip the whole block and try to use the next one.
00491             skip = block.length;
00492         }
00493 
00494         // Premature end of stream => error!
00495         if (_stream->eos() || _stream->err()) {
00496             warning("VocStream::preProcess: Reading failed");
00497             return;
00498         }
00499 
00500         // Skip the rest of the block
00501         if (skip)
00502             _stream->skip(skip);
00503 
00504         _blocks.push_back(block);
00505     }
00506 
00507     // Since we determined the sample rate we need for playback now, we will
00508     // initialize the play length.
00509     _length = Timestamp(0, _rate);
00510 
00511     // Calculate the total play time and do some more sanity checks
00512     for (BlockList::const_iterator i = _blocks.begin(), end = _blocks.end(); i != end; ++i) {
00513         // Check whether we found a block 8 which survived, this is not
00514         // allowed to happen!
00515         if (i->code == 8) {
00516             warning("VOC file contains unused block 8");
00517             return;
00518         }
00519 
00520         // For now only use blocks with actual samples
00521         if (i->code != 1 && i->code != 9)
00522             continue;
00523 
00524         // Check the sample rate
00525         if (i->sampleBlock.rate != _rate) {
00526             warning("VOC file contains chunks with different sample rates (%d != %d)", _rate, i->sampleBlock.rate);
00527             return;
00528         }
00529 
00530         _length = _length.addFrames(i->sampleBlock.samples);
00531     }
00532 
00533     // Set the current block to the first block in the stream
00534     rewind();
00535 }
00536 
00537 } // End of anonymous namespace
00538 
00539 int getSampleRateFromVOCRate(int vocSR) {
00540     if (vocSR == 0xa5 || vocSR == 0xa6) {
00541         return 11025;
00542     } else if (vocSR == 0xd2 || vocSR == 0xd3) {
00543         return 22050;
00544     } else {
00545         int sr = 1000000L / (256L - vocSR);
00546         // inexact sampling rates occur e.g. in the kitchen in Monkey Island,
00547         // very easy to reach right from the start of the game.
00548         //warning("inexact sample rate used: %i (0x%x)", sr, vocSR);
00549         return sr;
00550     }
00551 }
00552 
00553 SeekableAudioStream *makeVOCStream(Common::SeekableReadStream *stream, byte flags, DisposeAfterUse::Flag disposeAfterUse) {
00554     if (!checkVOCHeader(*stream)) {
00555         if (disposeAfterUse == DisposeAfterUse::YES)
00556             delete stream;
00557         return 0;
00558     }
00559 
00560     SeekableAudioStream *audioStream = new VocStream(stream, (flags & Audio::FLAG_UNSIGNED) != 0, disposeAfterUse);
00561 
00562     if (audioStream->endOfData()) {
00563         delete audioStream;
00564         return 0;
00565     } else {
00566         return audioStream;
00567     }
00568 }
00569 
00570 } // End of namespace Audio


Generated on Sat Feb 16 2019 05:01:11 for ResidualVM by doxygen 1.7.1
curved edge   curved edge