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

3do.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/textconsole.h"
00024 #include "common/stream.h"
00025 #include "common/util.h"
00026 
00027 #include "audio/decoders/3do.h"
00028 #include "audio/decoders/adpcm_intern.h"
00029 
00030 namespace Audio {
00031 
00032 // Reuses ADPCM table
00033 #define audio_3DO_ADP4_stepSizeTable Ima_ADPCMStream::_imaTable
00034 #define audio_3DO_ADP4_stepSizeIndex ADPCMStream::_stepAdjustTable
00035 
00036 RewindableAudioStream *make3DO_ADP4AudioStream(Common::SeekableReadStream *stream, uint16 sampleRate, bool stereo, uint32 *audioLengthMSecsPtr, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_ADP4_PersistentSpace *persistentSpace) {
00037     if (stereo) {
00038         warning("make3DO_ADP4Stream(): stereo currently not supported");
00039         return 0;
00040     }
00041 
00042     if (audioLengthMSecsPtr) {
00043         // Caller requires the milliseconds of audio
00044         uint32 audioLengthMSecs = stream->size() * 2 * 1000 / sampleRate; // 1 byte == 2 16-bit sample
00045         if (stereo) {
00046             audioLengthMSecs /= 2;
00047         }
00048         *audioLengthMSecsPtr = audioLengthMSecs;
00049     }
00050 
00051     return new Audio3DO_ADP4_Stream(stream, sampleRate, stereo, disposeAfterUse, persistentSpace);
00052 }
00053 
00054 Audio3DO_ADP4_Stream::Audio3DO_ADP4_Stream(Common::SeekableReadStream *stream, uint16 sampleRate, bool stereo, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_ADP4_PersistentSpace *persistentSpace)
00055     : _sampleRate(sampleRate), _stereo(stereo),
00056       _stream(stream, disposeAfterUse) {
00057 
00058     _callerDecoderData = persistentSpace;
00059     memset(&_initialDecoderData, 0, sizeof(_initialDecoderData));
00060     _initialRead = true;
00061 
00062     reset();
00063 }
00064 
00065 void Audio3DO_ADP4_Stream::reset() {
00066     memcpy(&_curDecoderData, &_initialDecoderData, sizeof(_curDecoderData));
00067     _streamBytesLeft = _stream->size();
00068     _stream->seek(0);
00069 }
00070 
00071 bool Audio3DO_ADP4_Stream::rewind() {
00072     reset();
00073     return true;
00074 }
00075 
00076 int16 Audio3DO_ADP4_Stream::decodeSample(byte compressedNibble) {
00077     int16 currentStep = audio_3DO_ADP4_stepSizeTable[_curDecoderData.stepIndex];
00078     int32 decodedSample = _curDecoderData.lastSample;
00079     int16 delta = currentStep >> 3;
00080 
00081     if (compressedNibble & 1)
00082         delta += currentStep >> 2;
00083 
00084     if (compressedNibble & 2)
00085         delta += currentStep >> 1;
00086 
00087     if (compressedNibble & 4)
00088         delta += currentStep;
00089 
00090     if (compressedNibble & 8) {
00091         decodedSample -= delta;
00092     } else {
00093         decodedSample += delta;
00094     }
00095 
00096     _curDecoderData.lastSample = CLIP<int32>(decodedSample, -32768, 32767);
00097 
00098     _curDecoderData.stepIndex += audio_3DO_ADP4_stepSizeIndex[compressedNibble & 0x07];
00099     _curDecoderData.stepIndex = CLIP<int16>(_curDecoderData.stepIndex, 0, ARRAYSIZE(audio_3DO_ADP4_stepSizeTable) - 1);
00100 
00101    return _curDecoderData.lastSample;
00102 }
00103 
00104 // Writes the requested amount (or less) of samples into buffer and returns the amount of samples, that got written
00105 int Audio3DO_ADP4_Stream::readBuffer(int16 *buffer, const int numSamples) {
00106     int8  byteCache[AUDIO_3DO_CACHE_SIZE];
00107     int8 *byteCachePtr = NULL;
00108     int   byteCacheSize = 0;
00109     int   requestedBytesLeft = 0;
00110     int   decodedSamplesCount = 0;
00111 
00112     int8  compressedByte = 0;
00113 
00114     if (endOfData())
00115         return 0; // no more bytes left
00116 
00117     if (_callerDecoderData) {
00118         // copy caller decoder data over
00119         memcpy(&_curDecoderData, _callerDecoderData, sizeof(_curDecoderData));
00120         if (_initialRead) {
00121             _initialRead = false;
00122             memcpy(&_initialDecoderData, &_curDecoderData, sizeof(_initialDecoderData));
00123         }
00124     }
00125 
00126     requestedBytesLeft = numSamples >> 1; // 1 byte for 2 16-bit sample
00127     if (requestedBytesLeft > _streamBytesLeft)
00128         requestedBytesLeft = _streamBytesLeft; // not enough bytes left
00129 
00130     // in case caller requests an uneven amount of samples, we will return an even amount
00131 
00132     // buffering, so that direct decoding of files and such runs way faster
00133     while (requestedBytesLeft) {
00134         if (requestedBytesLeft > AUDIO_3DO_CACHE_SIZE) {
00135             byteCacheSize = AUDIO_3DO_CACHE_SIZE;
00136         } else {
00137             byteCacheSize = requestedBytesLeft;
00138         }
00139 
00140         requestedBytesLeft -= byteCacheSize;
00141         _streamBytesLeft   -= byteCacheSize;
00142 
00143         // Fill our byte cache
00144         _stream->read(byteCache, byteCacheSize);
00145 
00146         byteCachePtr = byteCache;
00147 
00148         // Mono
00149         while (byteCacheSize) {
00150             compressedByte = *byteCachePtr++;
00151             byteCacheSize--;
00152 
00153             buffer[decodedSamplesCount] = decodeSample(compressedByte >> 4);
00154             decodedSamplesCount++;
00155             buffer[decodedSamplesCount] = decodeSample(compressedByte & 0x0f);
00156             decodedSamplesCount++;
00157         }
00158     }
00159 
00160     if (_callerDecoderData) {
00161         // copy caller decoder data back
00162         memcpy(_callerDecoderData, &_curDecoderData, sizeof(_curDecoderData));
00163     }
00164 
00165     return decodedSamplesCount;
00166 }
00167 
00168 // ============================================================================
00169 static int16 audio_3DO_SDX2_SquareTable[256] = {
00170     -32768,-32258,-31752,-31250,-30752,-30258,-29768,-29282,-28800,-28322,
00171     -27848,-27378,-26912,-26450,-25992,-25538,-25088,-24642,-24200,-23762,
00172     -23328,-22898,-22472,-22050,-21632,-21218,-20808,-20402,-20000,-19602,
00173     -19208,-18818,-18432,-18050,-17672,-17298,-16928,-16562,-16200,-15842,
00174     -15488,-15138,-14792,-14450,-14112,-13778,-13448,-13122,-12800,-12482,
00175     -12168,-11858,-11552,-11250,-10952,-10658,-10368,-10082, -9800, -9522,
00176      -9248, -8978, -8712, -8450, -8192, -7938, -7688, -7442, -7200, -6962,
00177      -6728, -6498, -6272, -6050, -5832, -5618, -5408, -5202, -5000, -4802,
00178      -4608, -4418, -4232, -4050, -3872, -3698, -3528, -3362, -3200, -3042,
00179      -2888, -2738, -2592, -2450, -2312, -2178, -2048, -1922, -1800, -1682,
00180      -1568, -1458, -1352, -1250, -1152, -1058,  -968,  -882,  -800,  -722,
00181       -648,  -578,  -512,  -450,  -392,  -338,  -288,  -242,  -200,  -162,
00182       -128,   -98,   -72,   -50,   -32,   -18,    -8,    -2,     0,     2,
00183          8,    18,    32,    50,    72,    98,   128,   162,   200,   242,
00184        288,   338,   392,   450,   512,   578,   648,   722,   800,   882,
00185        968,  1058,  1152,  1250,  1352,  1458,  1568,  1682,  1800,  1922,
00186       2048,  2178,  2312,  2450,  2592,  2738,  2888,  3042,  3200,  3362,
00187       3528,  3698,  3872,  4050,  4232,  4418,  4608,  4802,  5000,  5202,
00188       5408,  5618,  5832,  6050,  6272,  6498,  6728,  6962,  7200,  7442,
00189       7688,  7938,  8192,  8450,  8712,  8978,  9248,  9522,  9800, 10082,
00190      10368, 10658, 10952, 11250, 11552, 11858, 12168, 12482, 12800, 13122,
00191      13448, 13778, 14112, 14450, 14792, 15138, 15488, 15842, 16200, 16562,
00192      16928, 17298, 17672, 18050, 18432, 18818, 19208, 19602, 20000, 20402,
00193      20808, 21218, 21632, 22050, 22472, 22898, 23328, 23762, 24200, 24642,
00194      25088, 25538, 25992, 26450, 26912, 27378, 27848, 28322, 28800, 29282,
00195      29768, 30258, 30752, 31250, 31752, 32258
00196 };
00197 
00198 Audio3DO_SDX2_Stream::Audio3DO_SDX2_Stream(Common::SeekableReadStream *stream, uint16 sampleRate, bool stereo, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_SDX2_PersistentSpace *persistentSpace)
00199     : _sampleRate(sampleRate), _stereo(stereo),
00200       _stream(stream, disposeAfterUse) {
00201 
00202     _callerDecoderData = persistentSpace;
00203     memset(&_initialDecoderData, 0, sizeof(_initialDecoderData));
00204     _initialRead = true;
00205 
00206     reset();
00207 }
00208 
00209 void Audio3DO_SDX2_Stream::reset() {
00210     memcpy(&_curDecoderData, &_initialDecoderData, sizeof(_curDecoderData));
00211     _streamBytesLeft = _stream->size();
00212     _stream->seek(0);
00213 }
00214 
00215 bool Audio3DO_SDX2_Stream::rewind() {
00216     reset();
00217     return true;
00218 }
00219 
00220 // Writes the requested amount (or less) of samples into buffer and returns the amount of samples, that got written
00221 int Audio3DO_SDX2_Stream::readBuffer(int16 *buffer, const int numSamples) {
00222     int8  byteCache[AUDIO_3DO_CACHE_SIZE];
00223     int8 *byteCachePtr = NULL;
00224     int   byteCacheSize = 0;
00225     int   requestedBytesLeft = numSamples; // 1 byte per 16-bit sample
00226     int   decodedSamplesCount = 0;
00227 
00228     int8  compressedByte = 0;
00229     uint8 squareTableOffset = 0;
00230     int16 decodedSample = 0;
00231 
00232     if (endOfData())
00233         return 0; // no more bytes left
00234 
00235     if (_stereo) {
00236         // We expect numSamples to be even in case of Stereo audio
00237         assert((numSamples & 1) == 0);
00238     }
00239 
00240     if (_callerDecoderData) {
00241         // copy caller decoder data over
00242         memcpy(&_curDecoderData, _callerDecoderData, sizeof(_curDecoderData));
00243         if (_initialRead) {
00244             _initialRead = false;
00245             memcpy(&_initialDecoderData, &_curDecoderData, sizeof(_initialDecoderData));
00246         }
00247     }
00248 
00249     requestedBytesLeft = numSamples;
00250     if (requestedBytesLeft > _streamBytesLeft)
00251         requestedBytesLeft = _streamBytesLeft; // not enough bytes left
00252 
00253     // buffering, so that direct decoding of files and such runs way faster
00254     while (requestedBytesLeft) {
00255         if (requestedBytesLeft > AUDIO_3DO_CACHE_SIZE) {
00256             byteCacheSize = AUDIO_3DO_CACHE_SIZE;
00257         } else {
00258             byteCacheSize = requestedBytesLeft;
00259         }
00260 
00261         requestedBytesLeft -= byteCacheSize;
00262         _streamBytesLeft   -= byteCacheSize;
00263 
00264         // Fill our byte cache
00265         _stream->read(byteCache, byteCacheSize);
00266 
00267         byteCachePtr = byteCache;
00268 
00269         if (!_stereo) {
00270             // Mono
00271             while (byteCacheSize) {
00272                 compressedByte = *byteCachePtr++;
00273                 byteCacheSize--;
00274                 squareTableOffset = compressedByte + 128;
00275 
00276                 if (!(compressedByte & 1))
00277                     _curDecoderData.lastSample1 = 0;
00278 
00279                 decodedSample = _curDecoderData.lastSample1 + audio_3DO_SDX2_SquareTable[squareTableOffset];
00280                 _curDecoderData.lastSample1 = decodedSample;
00281 
00282                 buffer[decodedSamplesCount] = decodedSample;
00283                 decodedSamplesCount++;
00284             }
00285         } else {
00286             // Stereo
00287             while (byteCacheSize) {
00288                 compressedByte = *byteCachePtr++;
00289                 byteCacheSize--;
00290                 squareTableOffset = compressedByte + 128;
00291 
00292                 if (!(decodedSamplesCount & 1)) {
00293                     // First channel
00294                     if (!(compressedByte & 1))
00295                         _curDecoderData.lastSample1 = 0;
00296 
00297                     decodedSample = _curDecoderData.lastSample1 + audio_3DO_SDX2_SquareTable[squareTableOffset];
00298                     _curDecoderData.lastSample1 = decodedSample;
00299                 } else {
00300                     // Second channel
00301                     if (!(compressedByte & 1))
00302                         _curDecoderData.lastSample2 = 0;
00303 
00304                     decodedSample = _curDecoderData.lastSample2 + audio_3DO_SDX2_SquareTable[squareTableOffset];
00305                     _curDecoderData.lastSample2 = decodedSample;
00306                 }
00307 
00308                 buffer[decodedSamplesCount] = decodedSample;
00309                 decodedSamplesCount++;
00310             }
00311         }
00312     }
00313 
00314     if (_callerDecoderData) {
00315         // copy caller decoder data back
00316         memcpy(_callerDecoderData, &_curDecoderData, sizeof(_curDecoderData));
00317     }
00318 
00319     return decodedSamplesCount;
00320 }
00321 
00322 RewindableAudioStream *make3DO_SDX2AudioStream(Common::SeekableReadStream *stream, uint16 sampleRate, bool stereo, uint32 *audioLengthMSecsPtr, DisposeAfterUse::Flag disposeAfterUse, audio_3DO_SDX2_PersistentSpace *persistentSpace) {
00323     if (stereo) {
00324         if (stream->size() & 1) {
00325             warning("make3DO_SDX2Stream(): stereo data is uneven size");
00326             return 0;
00327         }
00328     }
00329 
00330     if (audioLengthMSecsPtr) {
00331         // Caller requires the milliseconds of audio
00332         uint32 audioLengthMSecs = stream->size() * 1000 / sampleRate; // 1 byte == 1 16-bit sample
00333         if (stereo) {
00334             audioLengthMSecs /= 2;
00335         }
00336         *audioLengthMSecsPtr = audioLengthMSecs;
00337     }
00338 
00339     return new Audio3DO_SDX2_Stream(stream, sampleRate, stereo, disposeAfterUse, persistentSpace);
00340 }
00341 
00342 } // End of namespace Audio


Generated on Sat Dec 7 2019 05:00:22 for ResidualVM by doxygen 1.7.1
curved edge   curved edge