diff options
author | Max Horn | 2006-02-11 22:45:04 +0000 |
---|---|---|
committer | Max Horn | 2006-02-11 22:45:04 +0000 |
commit | 26ee630756ebdd7c96bccede0881a8c8b98e8f2b (patch) | |
tree | 26e378d5cf990a2b81c2c96e9e683a7f333b62e8 /engines/scumm/imuse_digi/dimuse_sndmgr.cpp | |
parent | 2a9a0d4211b1ea5723f1409d91cb95de8984429e (diff) | |
download | scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.gz scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.tar.bz2 scummvm-rg350-26ee630756ebdd7c96bccede0881a8c8b98e8f2b.zip |
Moved engines to the new engines/ directory
svn-id: r20582
Diffstat (limited to 'engines/scumm/imuse_digi/dimuse_sndmgr.cpp')
-rw-r--r-- | engines/scumm/imuse_digi/dimuse_sndmgr.cpp | 625 |
1 files changed, 625 insertions, 0 deletions
diff --git a/engines/scumm/imuse_digi/dimuse_sndmgr.cpp b/engines/scumm/imuse_digi/dimuse_sndmgr.cpp new file mode 100644 index 0000000000..7d3d06f16e --- /dev/null +++ b/engines/scumm/imuse_digi/dimuse_sndmgr.cpp @@ -0,0 +1,625 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001-2006 The ScummVM project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + */ + +#include "common/stdafx.h" +#include "common/scummsys.h" +#include "common/util.h" + +#include "sound/voc.h" +#include "sound/vorbis.h" +#include "sound/mp3.h" + +#include "scumm/scumm.h" +#include "scumm/util.h" +#include "scumm/imuse_digi/dimuse.h" +#include "scumm/imuse_digi/dimuse_sndmgr.h" +#include "scumm/imuse_digi/dimuse_bndmgr.h" + +namespace Scumm { + +ImuseDigiSndMgr::ImuseDigiSndMgr(ScummEngine *scumm) { + for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) { + memset(&_sounds[l], 0, sizeof(soundStruct)); + } + _vm = scumm; + _disk = 0; + _cacheBundleDir = new BundleDirCache(); + BundleCodecs::initializeImcTables(); +} + +ImuseDigiSndMgr::~ImuseDigiSndMgr() { + for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) { + closeSound(&_sounds[l]); + } + + delete _cacheBundleDir; +} + +void ImuseDigiSndMgr::countElements(byte *ptr, int &numRegions, int &numJumps, int &numSyncs) { + uint32 tag; + int32 size = 0; + + do { + tag = READ_BE_UINT32(ptr); ptr += 4; + switch(tag) { + case MKID_BE('TEXT'): + case MKID_BE('STOP'): + case MKID_BE('FRMT'): + case MKID_BE('DATA'): + size = READ_BE_UINT32(ptr); ptr += size + 4; + break; + case MKID_BE('REGN'): + numRegions++; + size = READ_BE_UINT32(ptr); ptr += size + 4; + break; + case MKID_BE('JUMP'): + numJumps++; + size = READ_BE_UINT32(ptr); ptr += size + 4; + break; + case MKID_BE('SYNC'): + numSyncs++; + size = READ_BE_UINT32(ptr); ptr += size + 4; + break; + default: + error("ImuseDigiSndMgr::countElements() Unknown sfx header '%s'", tag2str(tag)); + } + } while (tag != MKID_BE('DATA')); +} + +void ImuseDigiSndMgr::prepareSoundFromRMAP(Common::File *file, soundStruct *sound, int32 offset, int32 size) { + int l; + + file->seek(offset, SEEK_SET); + uint32 tag = file->readUint32BE(); + assert(tag == 'RMAP'); + int32 version = file->readUint32BE(); + if (version != 2) { + error("ImuseDigiSndMgr::prepareSoundFromRMAP: Wrong version number, expected 2, but it's: %d.", version); + } + sound->bits = file->readUint32BE(); + sound->freq = file->readUint32BE(); + sound->channels = file->readUint32BE(); + sound->numRegions = file->readUint32BE(); + sound->numJumps = file->readUint32BE(); + sound->numSyncs = file->readUint32BE(); + sound->region = (_region *)malloc(sizeof(_region) * sound->numRegions); + sound->jump = (_jump *)malloc(sizeof(_jump) * sound->numJumps); + sound->sync = (_sync *)malloc(sizeof(_sync) * sound->numSyncs); + for (l = 0; l < sound->numRegions; l++) { + sound->region[l].offset = file->readUint32BE(); + sound->region[l].length = file->readUint32BE(); + } + for (l = 0; l < sound->numJumps; l++) { + sound->jump[l].offset = file->readUint32BE(); + sound->jump[l].dest = file->readUint32BE(); + sound->jump[l].hookId = file->readUint32BE(); + sound->jump[l].fadeDelay = file->readUint32BE(); + } + for (l = 0; l < sound->numSyncs; l++) { + sound->sync[l].size = file->readUint32BE(); + sound->sync[l].ptr = (byte *)malloc(sound->sync[l].size); + file->read(sound->sync[l].ptr, sound->sync[l].size); + } +} + +void ImuseDigiSndMgr::prepareSound(byte *ptr, soundStruct *sound) { + if (READ_UINT32(ptr) == MKID('Crea')) { + bool quit = false; + int len; + + int32 offset = READ_LE_UINT16(ptr + 20); + int16 code = READ_LE_UINT16(ptr + 24); + + sound->region = (_region *)malloc(sizeof(_region) * 70); + sound->jump = (_jump *)malloc(sizeof(_jump)); + sound->resPtr = ptr; + sound->bits = 8; + sound->channels = 1; + + while (!quit) { + len = READ_LE_UINT32(ptr + offset); + code = len & 0xFF; + if ((code != 0) && (code != 1) && (code != 6) && (code != 7)) { + // try again with 2 bytes forward (workaround for some FT sounds (ex.362, 363) + offset += 2; + len = READ_LE_UINT32(ptr + offset); + code = len & 0xFF; + if ((code != 0) && (code != 1) && (code != 6) && (code != 7)) { + error("Invalid code in VOC file : %d", code); + } + } + offset += 4; + len >>= 8; + switch(code) { + case 0: + quit = true; + break; + case 1: + { + int time_constant = ptr[offset]; + offset += 2; + len -= 2; + sound->freq = getSampleRateFromVOCRate(time_constant); + sound->region[sound->numRegions].offset = offset; + sound->region[sound->numRegions].length = len; + sound->numRegions++; + } + break; + case 6: // begin of loop + sound->jump[0].dest = offset + 8; + sound->jump[0].hookId = 0; + sound->jump[0].fadeDelay = 0; + break; + case 7: // end of loop + sound->jump[0].offset = offset - 4; + sound->numJumps++; + sound->region[sound->numRegions].offset = offset - 4; + sound->region[sound->numRegions].length = 0; + sound->numRegions++; + break; + default: + error("Invalid code in VOC file : %d", code); + quit = true; + break; + } + offset += len; + } + } else if (READ_UINT32(ptr) == MKID('iMUS')) { + uint32 tag; + int32 size = 0; + byte *s_ptr = ptr; + ptr += 16; + + int curIndexRegion = 0; + int curIndexJump = 0; + int curIndexSync = 0; + + sound->numRegions = 0; + sound->numJumps = 0; + sound->numSyncs = 0; + countElements(ptr, sound->numRegions, sound->numJumps, sound->numSyncs); + sound->region = (_region *)malloc(sizeof(_region) * sound->numRegions); + sound->jump = (_jump *)malloc(sizeof(_jump) * sound->numJumps); + sound->sync = (_sync *)malloc(sizeof(_sync) * sound->numSyncs); + + do { + tag = READ_BE_UINT32(ptr); ptr += 4; + switch(tag) { + case MKID_BE('FRMT'): + ptr += 12; + sound->bits = READ_BE_UINT32(ptr); ptr += 4; + sound->freq = READ_BE_UINT32(ptr); ptr += 4; + sound->channels = READ_BE_UINT32(ptr); ptr += 4; + break; + case MKID_BE('TEXT'): + case MKID_BE('STOP'): + size = READ_BE_UINT32(ptr); ptr += size + 4; + break; + case MKID_BE('REGN'): + ptr += 4; + sound->region[curIndexRegion].offset = READ_BE_UINT32(ptr); ptr += 4; + sound->region[curIndexRegion].length = READ_BE_UINT32(ptr); ptr += 4; + curIndexRegion++; + break; + case MKID_BE('JUMP'): + ptr += 4; + sound->jump[curIndexJump].offset = READ_BE_UINT32(ptr); ptr += 4; + sound->jump[curIndexJump].dest = READ_BE_UINT32(ptr); ptr += 4; + sound->jump[curIndexJump].hookId = READ_BE_UINT32(ptr); ptr += 4; + sound->jump[curIndexJump].fadeDelay = READ_BE_UINT32(ptr); ptr += 4; + curIndexJump++; + break; + case MKID_BE('SYNC'): + size = READ_BE_UINT32(ptr); ptr += 4; + sound->sync[curIndexSync].size = size; + sound->sync[curIndexSync].ptr = (byte *)malloc(size); + memcpy(sound->sync[curIndexSync].ptr, ptr, size); + curIndexSync++; + ptr += size; + break; + case MKID_BE('DATA'): + ptr += 4; + break; + default: + error("ImuseDigiSndMgr::prepareSound(%d/%s) Unknown sfx header '%s'", sound->soundId, sound->name, tag2str(tag)); + } + } while (tag != MKID_BE('DATA')); + sound->offsetData = ptr - s_ptr; + } else { + error("ImuseDigiSndMgr::prepareSound(): Unknown sound format"); + } +} + +ImuseDigiSndMgr::soundStruct *ImuseDigiSndMgr::allocSlot() { + for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) { + if (!_sounds[l].inUse) { + _sounds[l].inUse = true; + return &_sounds[l]; + } + } + + return NULL; +} + +bool ImuseDigiSndMgr::openMusicBundle(soundStruct *sound, int disk) { + bool result = false; + + sound->bundle = new BundleMgr(_cacheBundleDir); + if (_vm->_gameId == GID_CMI) { + if (_vm->_features & GF_DEMO) { + result = sound->bundle->open("music.bun", sound->compressed); + } else { + char musicfile[20]; + if (disk == -1) + disk = _vm->VAR(_vm->VAR_CURRENTDISK); + sprintf(musicfile, "musdisk%d.bun", disk); +// if (_disk != _vm->VAR(_vm->VAR_CURRENTDISK)) { +// _vm->_imuseDigital->parseScriptCmds(0x1000, 0, 0, 0, 0, 0, 0, 0); +// _vm->_imuseDigital->parseScriptCmds(0x2000, 0, 0, 0, 0, 0, 0, 0); +// _vm->_imuseDigital->stopAllSounds(); +// sound->bundle->closeFile(); +// } + + result = sound->bundle->open(musicfile, sound->compressed, true); + + // FIXME: Shouldn't we only set _disk if result == true? + _disk = (byte)_vm->VAR(_vm->VAR_CURRENTDISK); + } + } else if (_vm->_gameId == GID_DIG) + result = sound->bundle->open("digmusic.bun", sound->compressed, true); + else + error("ImuseDigiSndMgr::openMusicBundle() Don't know which bundle file to load"); + + _vm->VAR(_vm->VAR_MUSIC_BUNDLE_LOADED) = result ? 1 : 0; + + return result; +} + +bool ImuseDigiSndMgr::openVoiceBundle(soundStruct *sound, int disk) { + bool result = false; + + sound->bundle = new BundleMgr(_cacheBundleDir); + if (_vm->_gameId == GID_CMI) { + if (_vm->_features & GF_DEMO) { + result = sound->bundle->open("voice.bun", sound->compressed); + } else { + char voxfile[20]; + if (disk == -1) + disk = _vm->VAR(_vm->VAR_CURRENTDISK); + sprintf(voxfile, "voxdisk%d.bun", disk); +// if (_disk != _vm->VAR(_vm->VAR_CURRENTDISK)) { +// _vm->_imuseDigital->parseScriptCmds(0x1000, 0, 0, 0, 0, 0, 0, 0); +// _vm->_imuseDigital->parseScriptCmds(0x2000, 0, 0, 0, 0, 0, 0, 0); +// _vm->_imuseDigital->stopAllSounds(); +// sound->bundle->closeFile(); +// } + + result = sound->bundle->open(voxfile, sound->compressed); + + // FIXME: Shouldn't we only set _disk if result == true? + _disk = (byte)_vm->VAR(_vm->VAR_CURRENTDISK); + } + } else if (_vm->_gameId == GID_DIG) + result = sound->bundle->open("digvoice.bun", sound->compressed); + else + error("ImuseDigiSndMgr::openVoiceBundle() Don't know which bundle file to load"); + + _vm->VAR(_vm->VAR_VOICE_BUNDLE_LOADED) = result ? 1 : 0; + + return result; +} + +ImuseDigiSndMgr::soundStruct *ImuseDigiSndMgr::openSound(int32 soundId, const char *soundName, int soundType, int volGroupId, int disk) { + assert(soundId >= 0); + assert(soundType); + + soundStruct *sound = allocSlot(); + if (!sound) { + error("ImuseDigiSndMgr::openSound() can't alloc free sound slot"); + } + + const bool header_outside = ((_vm->_gameId == GID_CMI) && !(_vm->_features & GF_DEMO)); + bool result = false; + byte *ptr = NULL; + + switch (soundType) { + case IMUSE_RESOURCE: + assert(soundName[0] == 0); // Paranoia check + + _vm->ensureResourceLoaded(rtSound, soundId); + _vm->res.lock(rtSound, soundId); + ptr = _vm->getResourceAddress(rtSound, soundId); + if (ptr == NULL) { + closeSound(sound); + return NULL; + } + sound->resPtr = ptr; + break; + case IMUSE_BUNDLE: + if (volGroupId == IMUSE_VOLGRP_VOICE) + result = openVoiceBundle(sound, disk); + else if (volGroupId == IMUSE_VOLGRP_MUSIC) + result = openMusicBundle(sound, disk); + else + error("ImuseDigiSndMgr::openSound() Don't know how load sound: %d", soundId); + if (!result) { + closeSound(sound); + return NULL; + } + if (sound->compressed) { + char fileName[24]; + int32 offset = 0, size = 0; + sprintf(fileName, "%s.map", soundName); + Common::File *rmapFile = sound->bundle->getFile(fileName, offset, size); + if (!rmapFile) { + closeSound(sound); + return NULL; + } + prepareSoundFromRMAP(rmapFile, sound, offset, size); + strcpy(sound->name, soundName); + sound->soundId = soundId; + sound->type = soundType; + sound->volGroupId = volGroupId; + sound->disk = _disk; + return sound; + } else if (soundName[0] == 0) { + if (sound->bundle->decompressSampleByIndex(soundId, 0, 0x2000, &ptr, 0, header_outside) == 0 || ptr == NULL) { + closeSound(sound); + return NULL; + } + } else { + if (sound->bundle->decompressSampleByName(soundName, 0, 0x2000, &ptr, header_outside) == 0 || ptr == NULL) { + closeSound(sound); + return NULL; + } + } + sound->resPtr = 0; + break; + default: + error("ImuseDigiSndMgr::openSound() Unknown soundType %d (trying to load sound %d)", soundType, soundId); + } + + strcpy(sound->name, soundName); + sound->soundId = soundId; + sound->type = soundType; + sound->volGroupId = volGroupId; + sound->disk = _disk; + prepareSound(ptr, sound); + if ((soundType == IMUSE_BUNDLE) && !sound->compressed) { + free(ptr); + } + return sound; +} + +void ImuseDigiSndMgr::closeSound(soundStruct *soundHandle) { + assert(checkForProperHandle(soundHandle)); + + if (soundHandle->resPtr) { + bool found = false; + for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) { + if ((_sounds[l].soundId == soundHandle->soundId) && (&_sounds[l] != soundHandle)) + found = true; + } + if (!found) + _vm->res.unlock(rtSound, soundHandle->soundId); + } + + if (soundHandle->compressedStream) + delete soundHandle->compressedStream; + + delete soundHandle->bundle; + + for (int r = 0; r < soundHandle->numSyncs; r++) + free(soundHandle->sync[r].ptr); + free(soundHandle->region); + free(soundHandle->jump); + free(soundHandle->sync); + memset(soundHandle, 0, sizeof(soundStruct)); +} + +ImuseDigiSndMgr::soundStruct *ImuseDigiSndMgr::cloneSound(soundStruct *soundHandle) { + assert(checkForProperHandle(soundHandle)); + + return openSound(soundHandle->soundId, soundHandle->name, soundHandle->type, soundHandle->volGroupId, soundHandle->disk); +} + +bool ImuseDigiSndMgr::checkForProperHandle(soundStruct *soundHandle) { + if (!soundHandle) + return false; + for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) { + if (soundHandle == &_sounds[l]) + return true; + } + return false; +} + +bool ImuseDigiSndMgr::isCompressed(soundStruct *soundHandle) { + assert(checkForProperHandle(soundHandle)); + return soundHandle->compressed; +} + +int ImuseDigiSndMgr::getFreq(soundStruct *soundHandle) { + assert(checkForProperHandle(soundHandle)); + return soundHandle->freq; +} + +int ImuseDigiSndMgr::getBits(soundStruct *soundHandle) { + assert(checkForProperHandle(soundHandle)); + return soundHandle->bits; +} + +int ImuseDigiSndMgr::getChannels(soundStruct *soundHandle) { + assert(checkForProperHandle(soundHandle)); + return soundHandle->channels; +} + +bool ImuseDigiSndMgr::isEndOfRegion(soundStruct *soundHandle, int region) { + assert(checkForProperHandle(soundHandle)); + assert(region >= 0 && region < soundHandle->numRegions); + return soundHandle->endFlag; +} + +int ImuseDigiSndMgr::getNumRegions(soundStruct *soundHandle) { + assert(checkForProperHandle(soundHandle)); + return soundHandle->numRegions; +} + +int ImuseDigiSndMgr::getNumJumps(soundStruct *soundHandle) { + assert(checkForProperHandle(soundHandle)); + return soundHandle->numJumps; +} + +int ImuseDigiSndMgr::getRegionOffset(soundStruct *soundHandle, int region) { + debug(5, "getRegionOffset() region:%d", region); + assert(checkForProperHandle(soundHandle)); + assert(region >= 0 && region < soundHandle->numRegions); + return soundHandle->region[region].offset; +} + +int ImuseDigiSndMgr::getJumpIdByRegionAndHookId(soundStruct *soundHandle, int region, int hookId) { + debug(5, "getJumpIdByRegionAndHookId() region:%d, hookId:%d", region, hookId); + assert(checkForProperHandle(soundHandle)); + assert(region >= 0 && region < soundHandle->numRegions); + int32 offset = soundHandle->region[region].offset; + for (int l = 0; l < soundHandle->numJumps; l++) { + if (offset == soundHandle->jump[l].offset) { + if (soundHandle->jump[l].hookId == hookId) + return l; + } + } + + return -1; +} + +void ImuseDigiSndMgr::getSyncSizeAndPtrById(soundStruct *soundHandle, int number, int32 &sync_size, byte **sync_ptr) { + assert(checkForProperHandle(soundHandle)); + assert(number >= 0); + if (number < soundHandle->numSyncs) { + sync_size = soundHandle->sync[number].size; + *sync_ptr = soundHandle->sync[number].ptr; + } else { + sync_size = 0; + *sync_ptr = NULL; + } +} + +int ImuseDigiSndMgr::getRegionIdByJumpId(soundStruct *soundHandle, int jumpId) { + debug(5, "getRegionIdByJumpId() jumpId:%d", jumpId); + assert(checkForProperHandle(soundHandle)); + assert(jumpId >= 0 && jumpId < soundHandle->numJumps); + int32 dest = soundHandle->jump[jumpId].dest; + for (int l = 0; l < soundHandle->numRegions; l++) { + if (dest == soundHandle->region[l].offset) { + return l; + } + } + + return -1; +} + +int ImuseDigiSndMgr::getJumpHookId(soundStruct *soundHandle, int number) { + debug(5, "getJumpHookId() number:%d", number); + assert(checkForProperHandle(soundHandle)); + assert(number >= 0 && number < soundHandle->numJumps); + return soundHandle->jump[number].hookId; +} + +int ImuseDigiSndMgr::getJumpFade(soundStruct *soundHandle, int number) { + debug(5, "getJumpFade() number:%d", number); + assert(checkForProperHandle(soundHandle)); + assert(number >= 0 && number < soundHandle->numJumps); + return soundHandle->jump[number].fadeDelay; +} + +int32 ImuseDigiSndMgr::getDataFromRegion(soundStruct *soundHandle, int region, byte **buf, int32 offset, int32 size) { + debug(5, "getDataFromRegion() region:%d, offset:%d, size:%d, numRegions:%d", region, offset, size, soundHandle->numRegions); + assert(checkForProperHandle(soundHandle)); + assert(buf && offset >= 0 && size >= 0); + assert(region >= 0 && region < soundHandle->numRegions); + + int32 region_offset = soundHandle->region[region].offset; + int32 region_length = soundHandle->region[region].length; + int32 offset_data = soundHandle->offsetData; + int32 start = region_offset - offset_data; + + if (offset + size + offset_data > region_length) { + size = region_length - offset; + soundHandle->endFlag = true; + } else { + soundHandle->endFlag = false; + } + + int header_size = soundHandle->offsetData; + bool header_outside = ((_vm->_gameId == GID_CMI) && !(_vm->_features & GF_DEMO)); + if ((soundHandle->bundle) && (!soundHandle->compressed)) { + size = soundHandle->bundle->decompressSampleByCurIndex(start + offset, size, buf, header_size, header_outside); + } else if (soundHandle->resPtr) { + *buf = (byte *)malloc(size); + memcpy(*buf, soundHandle->resPtr + start + offset + header_size, size); + } else if ((soundHandle->bundle) && (soundHandle->compressed)) { + *buf = (byte *)malloc(size); + char fileName[24]; + sprintf(fileName, "%s_reg%03d", soundHandle->name, region); + if (scumm_stricmp(fileName, soundHandle->lastFileName) != 0) { + int32 offs = 0, len = 0; + Common::File *cmpFile; + bool oggMode = false; + sprintf(fileName, "%s_reg%03d.mp3", soundHandle->name, region); + cmpFile = soundHandle->bundle->getFile(fileName, offs, len); +#ifndef USE_MAD + if (len) + error("Mad library compiled support needed!"); +#endif + if (!len) { + sprintf(fileName, "%s_reg%03d.ogg", soundHandle->name, region); + cmpFile = soundHandle->bundle->getFile(fileName, offs, len); +#ifndef USE_VORBIS + if (len) + error("Vorbis library compiled support needed!"); +#endif + assert(len); + oggMode = true; + } + if (!soundHandle->compressedStream) { +#ifdef USE_VORBIS + if (oggMode) + soundHandle->compressedStream = makeVorbisStream(cmpFile, len); +#endif +#ifdef USE_MAD + if (!oggMode) + soundHandle->compressedStream = makeMP3Stream(cmpFile, len); +#endif + assert(soundHandle->compressedStream); + } + strcpy(soundHandle->lastFileName, fileName); + } + size = soundHandle->compressedStream->readBuffer((int16 *)*buf, size / 2) * 2; + if (soundHandle->compressedStream->endOfData()) { + delete soundHandle->compressedStream; + soundHandle->compressedStream = NULL; + soundHandle->lastFileName[0] = 0; + } + } + + return size; +} + +} // End of namespace Scumm |