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

imuse_sndmgr.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM 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/endian.h"
00024 #include "common/stream.h"
00025 
00026 #include "engines/grim/resource.h"
00027 
00028 #include "engines/grim/imuse/imuse_sndmgr.h"
00029 #include "engines/grim/imuse/imuse_mcmp_mgr.h"
00030 
00031 namespace Grim {
00032 
00033 ImuseSndMgr::ImuseSndMgr(bool demo) {
00034     _demo = demo;
00035     for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) {
00036         memset(&_sounds[l], 0, sizeof(SoundDesc));
00037     }
00038 }
00039 
00040 ImuseSndMgr::~ImuseSndMgr() {
00041     for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) {
00042         closeSound(&_sounds[l]);
00043     }
00044 }
00045 
00046 void ImuseSndMgr::countElements(SoundDesc *sound) {
00047     uint32 tag;
00048     int32 size = 0;
00049     uint32 pos = sound->inStream->pos();
00050 
00051     do {
00052         tag = sound->inStream->readUint32BE();
00053         switch(tag) {
00054         case MKTAG('T','E','X','T'):
00055         case MKTAG('S','T','O','P'):
00056         case MKTAG('F','R','M','T'):
00057             size = sound->inStream->readUint32BE();
00058             sound->inStream->seek(size, SEEK_CUR);
00059             break;
00060         case MKTAG('R','E','G','N'):
00061             sound->numRegions++;
00062             size = sound->inStream->readUint32BE();
00063             sound->inStream->seek(size, SEEK_CUR);
00064             break;
00065         case MKTAG('J','U','M','P'):
00066             sound->numJumps++;
00067             size = sound->inStream->readUint32BE();
00068             sound->inStream->seek(size, SEEK_CUR);
00069             break;
00070         case MKTAG('D','A','T','A'):
00071             break;
00072         default:
00073             error("ImuseSndMgr::countElements() Unknown MAP tag '%s'", Common::tag2string(tag).c_str());
00074         }
00075     } while (tag != MKTAG('D','A','T','A'));
00076 
00077     sound->inStream->seek(pos, SEEK_SET);
00078 }
00079 
00080 void ImuseSndMgr::parseSoundHeader(SoundDesc *sound, int &headerSize) {
00081     Common::SeekableReadStream *data = sound->inStream;
00082 
00083     uint32 tag = data->readUint32BE();
00084     if (tag == MKTAG('R','I','F','F')) {
00085         sound->region = new Region[1];
00086         sound->jump = new Jump[1];
00087         sound->numJumps = 0;
00088         sound->numRegions = 1;
00089         sound->region[0].offset = 0;
00090         data->seek(18, SEEK_CUR);
00091         sound->channels = data->readByte();
00092         data->readByte();
00093         sound->freq = data->readUint32LE();
00094         data->seek(6, SEEK_CUR);
00095         sound->bits = data->readByte();
00096         data->seek(5, SEEK_CUR);
00097         sound->region[0].length = data->readUint32LE();
00098         headerSize = 44;
00099     } else if (tag == MKTAG('i','M','U','S')) {
00100         int32 size = 0;
00101         int32 headerStart = data->pos();
00102         data->seek(12, SEEK_CUR);
00103 
00104         int curIndexRegion = 0;
00105         int curIndexJump = 0;
00106 
00107         sound->numRegions = 0;
00108         sound->numJumps = 0;
00109         countElements(sound);
00110         sound->region = new Region [sound->numRegions];
00111         sound->jump = new Jump [sound->numJumps];
00112 
00113         do {
00114             tag = data->readUint32BE();
00115             switch(tag) {
00116             case MKTAG('F','R','M','T'):
00117                 data->seek(12, SEEK_CUR);
00118                 sound->bits = data->readUint32BE();
00119                 sound->freq = data->readUint32BE();
00120                 sound->channels = data->readUint32BE();
00121                 break;
00122             case MKTAG('T','E','X','T'):
00123             case MKTAG('S','T','O','P'):
00124                 size = data->readUint32BE();
00125                 data->seek(size, SEEK_CUR);
00126                 break;
00127             case MKTAG('R','E','G','N'):
00128                 data->seek(4, SEEK_CUR);
00129                 sound->region[curIndexRegion].offset = data->readUint32BE();
00130                 sound->region[curIndexRegion].length = data->readUint32BE();
00131                 curIndexRegion++;
00132                 break;
00133             case MKTAG('J','U','M','P'):
00134                 data->seek(4, SEEK_CUR);
00135                 sound->jump[curIndexJump].offset = data->readUint32BE();
00136                 sound->jump[curIndexJump].dest = data->readUint32BE();
00137                 sound->jump[curIndexJump].hookId = data->readUint32BE();
00138                 sound->jump[curIndexJump].fadeDelay = data->readUint32BE();
00139                 curIndexJump++;
00140                 break;
00141             case MKTAG('D','A','T','A'):
00142                 data->seek(4, SEEK_CUR);
00143                 break;
00144             default:
00145                 error("ImuseSndMgr::prepareSound(%s) Unknown MAP tag '%s'", sound->name, Common::tag2string(tag).c_str());
00146             }
00147         } while (tag != MKTAG('D','A','T','A'));
00148         headerSize = data->pos() - headerStart;
00149         int i;
00150         for (i = 0; i < sound->numRegions; i++) {
00151             sound->region[i].offset -= headerSize;
00152         }
00153         for (i = 0; i < sound->numJumps; i++) {
00154             sound->jump[i].offset -= headerSize;
00155             sound->jump[i].dest -= headerSize;
00156         }
00157     } else {
00158         error("ImuseSndMgr::prepareSound() Unknown sound format");
00159     }
00160 }
00161 
00162 ImuseSndMgr::SoundDesc *ImuseSndMgr::allocSlot() {
00163     for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) {
00164         if (!_sounds[l].inUse) {
00165             _sounds[l].inUse = true;
00166             return &_sounds[l];
00167         }
00168     }
00169 
00170     return nullptr;
00171 }
00172 
00173 ImuseSndMgr::SoundDesc *ImuseSndMgr::openSound(const char *soundName, int volGroupId) {
00174     Common::String s = soundName;
00175     s.toLowercase();
00176     soundName = s.c_str();
00177     const char *extension = soundName + strlen(soundName) - 3;
00178     int headerSize = 0;
00179 
00180     SoundDesc *sound = allocSlot();
00181     if (!sound) {
00182         error("ImuseSndMgr::openSound() Can't alloc free sound slot");
00183     }
00184 
00185     strcpy(sound->name, soundName);
00186     sound->volGroupId = volGroupId;
00187     sound->inStream = nullptr;
00188 
00189     sound->inStream = g_resourceloader->openNewStreamFile(soundName);
00190     if (!sound->inStream) {
00191         closeSound(sound);
00192         return nullptr;
00193     }
00194 
00195     if (!_demo && scumm_stricmp(extension, "imu") == 0) {
00196         parseSoundHeader(sound, headerSize);
00197         sound->mcmpData = false;
00198         sound->headerSize = headerSize;
00199     } else if (scumm_stricmp(extension, "wav") == 0 || scumm_stricmp(extension, "imc") == 0 ||
00200             (_demo && scumm_stricmp(extension, "imu") == 0)) {
00201         sound->mcmpMgr = new McmpMgr();
00202         if (!sound->mcmpMgr->openSound(soundName, sound->inStream, headerSize)) {
00203             closeSound(sound);
00204             return nullptr;
00205         }
00206         parseSoundHeader(sound, headerSize);
00207         sound->mcmpData = true;
00208     } else {
00209         error("ImuseSndMgr::openSound() Unrecognized extension for sound file %s", soundName);
00210     }
00211 
00212     return sound;
00213 }
00214 
00215 void ImuseSndMgr::closeSound(SoundDesc *sound) {
00216     assert(checkForProperHandle(sound));
00217 
00218     if (sound->mcmpMgr) {
00219         delete sound->mcmpMgr;
00220         sound->mcmpMgr = nullptr;
00221     }
00222 
00223     if (sound->region) {
00224         delete[] sound->region;
00225         sound->region = nullptr;
00226     }
00227 
00228     if (sound->jump) {
00229         delete[] sound->jump;
00230         sound->jump = nullptr;
00231     }
00232 
00233     if (sound->inStream) {
00234         delete sound->inStream;
00235         sound->inStream = nullptr;
00236     }
00237 
00238     memset(sound, 0, sizeof(SoundDesc));
00239 }
00240 
00241 ImuseSndMgr::SoundDesc *ImuseSndMgr::cloneSound(SoundDesc *sound) {
00242     assert(checkForProperHandle(sound));
00243 
00244     return openSound(sound->name, sound->volGroupId);
00245 }
00246 
00247 bool ImuseSndMgr::checkForProperHandle(SoundDesc *sound) {
00248     if (!sound)
00249         return false;
00250 
00251     for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) {
00252         if (sound == &_sounds[l])
00253             return true;
00254     }
00255 
00256     return false;
00257 }
00258 
00259 int ImuseSndMgr::getFreq(SoundDesc *sound) {
00260     assert(checkForProperHandle(sound));
00261     return sound->freq;
00262 }
00263 
00264 int ImuseSndMgr::getBits(SoundDesc *sound) {
00265     assert(checkForProperHandle(sound));
00266     return sound->bits;
00267 }
00268 
00269 int ImuseSndMgr::getChannels(SoundDesc *sound) {
00270     assert(checkForProperHandle(sound));
00271     return sound->channels;
00272 }
00273 
00274 bool ImuseSndMgr::isEndOfRegion(SoundDesc *sound, int region) {
00275     assert(checkForProperHandle(sound));
00276     assert(region >= 0 && region < sound->numRegions);
00277     return sound->endFlag;
00278 }
00279 
00280 int ImuseSndMgr::getNumRegions(SoundDesc *sound) {
00281     assert(checkForProperHandle(sound));
00282     return sound->numRegions;
00283 }
00284 
00285 int ImuseSndMgr::getNumJumps(SoundDesc *sound) {
00286     assert(checkForProperHandle(sound));
00287     return sound->numJumps;
00288 }
00289 
00290 int ImuseSndMgr::getRegionOffset(SoundDesc *sound, int region) {
00291     assert(checkForProperHandle(sound));
00292     assert(region >= 0 && region < sound->numRegions);
00293     return sound->region[region].offset;
00294 }
00295 
00296 int ImuseSndMgr::getRegionLength(SoundDesc *sound, int region) {
00297     assert(checkForProperHandle(sound));
00298     assert(region >= 0 && region < sound->numRegions);
00299     return sound->region[region].length;
00300 }
00301 
00302 int ImuseSndMgr::getJumpIdByRegionAndHookId(SoundDesc *sound, int region, int hookId) {
00303     assert(checkForProperHandle(sound));
00304     assert(region >= 0 && region < sound->numRegions);
00305     int32 offset = sound->region[region].offset;
00306     for (int l = 0; l < sound->numJumps; l++) {
00307         if (offset == sound->jump[l].offset) {
00308             if (sound->jump[l].hookId == hookId)
00309                 return l;
00310         }
00311     }
00312 
00313     return -1;
00314 }
00315 
00316 int ImuseSndMgr::getRegionIdByJumpId(SoundDesc *sound, int jumpId) {
00317     assert(checkForProperHandle(sound));
00318     assert(jumpId >= 0 && jumpId < sound->numJumps);
00319     int32 dest = sound->jump[jumpId].dest;
00320     for (int l = 0; l < sound->numRegions; l++) {
00321         if (dest == sound->region[l].offset) {
00322             return l;
00323         }
00324     }
00325 
00326     return -1;
00327 }
00328 
00329 int ImuseSndMgr::getJumpHookId(SoundDesc *sound, int number) {
00330     assert(checkForProperHandle(sound));
00331     assert(number >= 0 && number < sound->numJumps);
00332     return sound->jump[number].hookId;
00333 }
00334 
00335 int ImuseSndMgr::getJumpFade(SoundDesc *sound, int number) {
00336     assert(checkForProperHandle(sound));
00337     assert(number >= 0 && number < sound->numJumps);
00338     return sound->jump[number].fadeDelay;
00339 }
00340 
00341 int32 ImuseSndMgr::getDataFromRegion(SoundDesc *sound, int region, byte **buf, int32 offset, int32 size) {
00342     assert(checkForProperHandle(sound));
00343     assert(buf && offset >= 0 && size >= 0);
00344     assert(region >= 0 && region < sound->numRegions);
00345 
00346     int32 region_offset = sound->region[region].offset;
00347     int32 region_length = sound->region[region].length;
00348 
00349     if (offset + size > region_length) {
00350         size = region_length - offset;
00351         sound->endFlag = true;
00352     } else {
00353         sound->endFlag = false;
00354     }
00355 
00356     if (sound->mcmpData) {
00357         size = sound->mcmpMgr->decompressSample(region_offset + offset, size, buf);
00358     } else {
00359         *buf = static_cast<byte *>(malloc(size));
00360         sound->inStream->seek(region_offset + offset + sound->headerSize, SEEK_SET);
00361         sound->inStream->read(*buf, size);
00362     }
00363 
00364     return size;
00365 }
00366 
00367 } // end of namespace Grim


Generated on Sat May 25 2019 05:00:47 for ResidualVM by doxygen 1.7.1
curved edge   curved edge