/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * 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 3 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, see . * */ #include "common/scummsys.h" #include "audio/audiostream.h" #include "audio/decoders/flac.h" #include "audio/decoders/voc.h" #include "audio/decoders/vorbis.h" #include "audio/decoders/mp3.h" #include "scumm/resource.h" #include "scumm/scumm.h" #include "scumm/imuse_digi/dimuse_bndmgr.h" #include "scumm/imuse_digi/dimuse_codecs.h" #include "scumm/imuse_digi/dimuse_sndmgr.h" namespace Scumm { ImuseDigiSndMgr::ImuseDigiSndMgr(ScummEngine *scumm) { for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) { memset(&_sounds[l], 0, sizeof(SoundDesc)); } _vm = scumm; _disk = 0; _cacheBundleDir = new BundleDirCache(scumm); assert(_cacheBundleDir); BundleCodecs::initializeImcTables(); } ImuseDigiSndMgr::~ImuseDigiSndMgr() { for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) { closeSound(&_sounds[l]); } delete _cacheBundleDir; BundleCodecs::releaseImcTables(); } ImuseDigiSndMgr::SoundDesc *ImuseDigiSndMgr::allocSlot() { for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) { if (!_sounds[l].inUse) { _sounds[l].inUse = true; _sounds[l].scheduledForDealloc = false; return &_sounds[l]; } } return nullptr; } bool ImuseDigiSndMgr::openMusicBundle(SoundDesc *sound, int &disk) { bool result = false; bool compressed = false; sound->bundle = new BundleMgr(_vm, _cacheBundleDir); assert(sound->bundle); if (_vm->_game.id == GID_CMI) { if (_vm->_game.features & GF_DEMO) { result = sound->bundle->open("music.bun", compressed); } else { char musicfile[20]; if (disk == -1) disk = _vm->VAR(_vm->VAR_CURRENTDISK); Common::sprintf_s(musicfile, "musdisk%d.bun", disk); // if (_disk != _vm->VAR(_vm->VAR_CURRENTDISK)) { // _vm->_DiMUSE_v1->parseScriptCmds(0x1000, 0, 0, 0, 0, 0, 0, 0); // _vm->_DiMUSE_v1->parseScriptCmds(0x2000, 0, 0, 0, 0, 0, 0, 0); // _vm->_DiMUSE_v1->stopAllSounds(); // sound->bundle->closeFile(); // } result = sound->bundle->open(musicfile, compressed); // FIXME: Shouldn't we only set _disk if result == true? _disk = (byte)_vm->VAR(_vm->VAR_CURRENTDISK); } } else if (_vm->_game.id == GID_DIG) result = sound->bundle->open("digmusic.bun", compressed); 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(SoundDesc *sound, int &disk) { bool result = false; bool compressed = false; sound->bundle = new BundleMgr(_vm, _cacheBundleDir); assert(sound->bundle); if (_vm->_game.id == GID_CMI) { if (_vm->_game.features & GF_DEMO) { result = sound->bundle->open("voice.bun", compressed); } else { char voxfile[20]; if (disk == -1) disk = _vm->VAR(_vm->VAR_CURRENTDISK); Common::sprintf_s(voxfile, "voxdisk%d.bun", disk); // if (_disk != _vm->VAR(_vm->VAR_CURRENTDISK)) { // _vm->_DiMUSE_v1->parseScriptCmds(0x1000, 0, 0, 0, 0, 0, 0, 0); // _vm->_DiMUSE_v1->parseScriptCmds(0x2000, 0, 0, 0, 0, 0, 0, 0); // _vm->_DiMUSE_v1->stopAllSounds(); // sound->bundle->closeFile(); // } result = sound->bundle->open(voxfile, compressed); // FIXME: Shouldn't we only set _disk if result == true? _disk = (byte)_vm->VAR(_vm->VAR_CURRENTDISK); } } else if (_vm->_game.id == GID_DIG) result = sound->bundle->open("digvoice.bun", 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::SoundDesc *ImuseDigiSndMgr::openSound(int32 soundId, const char *soundName, int soundType, int volGroupId, int disk) { assert(soundId >= 0); assert(soundType); SoundDesc *sound = allocSlot(); if (!sound) { error("ImuseDigiSndMgr::openSound() can't alloc free sound slot"); } const bool header_outside = ((_vm->_game.id == GID_CMI) && !(_vm->_game.features & GF_DEMO)); bool result = false; byte *ptr = nullptr; switch (soundType) { case IMUSE_RESOURCE: assert(soundName[0] == 0); // Paranoia check _vm->_res->lock(rtSound, soundId); ptr = _vm->getResourceAddress(rtSound, soundId); if (ptr == nullptr) { closeSound(sound); return nullptr; } sound->resPtr = ptr; sound->resSize = _vm->getResourceSize(rtSound, soundId) - 8; 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 nullptr; } if (soundName[0] != 0) { if (sound->bundle->readFile(soundName, 0x2000, &ptr, header_outside) == 0 || ptr == nullptr) { closeSound(sound); free(ptr); return nullptr; } } sound->resPtr = nullptr; break; default: error("ImuseDigiSndMgr::openSound() Unknown soundType %d (trying to load sound %d)", soundType, soundId); } Common::strlcpy(sound->name, soundName, sizeof(sound->name)); sound->soundId = soundId; if (soundType == IMUSE_BUNDLE) { free(ptr); } return sound; } void ImuseDigiSndMgr::closeSound(SoundDesc *soundDesc) { // Check if there's an actual sound to close... if (!checkForProperHandle(soundDesc)) return; if (soundDesc->resPtr) { bool found = false; for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) { if ((_sounds[l].soundId == soundDesc->soundId) && (&_sounds[l] != soundDesc)) found = true; } if (!found) _vm->_res->unlock(rtSound, soundDesc->soundId); } delete soundDesc->bundle; memset(soundDesc, 0, sizeof(SoundDesc)); } ImuseDigiSndMgr::SoundDesc *ImuseDigiSndMgr::findSoundById(int soundId) { SoundDesc *soundDesc = nullptr; for (int i = 0; i < MAX_IMUSE_SOUNDS; i++) { if (_sounds[i].soundId == soundId) { soundDesc = &_sounds[i]; break; } } return soundDesc; } ImuseDigiSndMgr::SoundDesc *ImuseDigiSndMgr::getSounds() { return _sounds; } void ImuseDigiSndMgr::scheduleSoundForDeallocation(int soundId) { SoundDesc *soundDesc = nullptr; for (int i = 0; i < MAX_IMUSE_SOUNDS; i++) { if (_sounds[i].soundId == soundId) { soundDesc = &_sounds[i]; } } // Check if there's an actual sound to deallocate... if (!checkForProperHandle(soundDesc)) return; soundDesc->scheduledForDealloc = true; } void ImuseDigiSndMgr::closeSoundById(int soundId) { SoundDesc *soundDesc = nullptr; for (int i = 0; i < MAX_IMUSE_SOUNDS; i++) { if (_sounds[i].soundId == soundId) { soundDesc = &_sounds[i]; } } if (soundDesc) { assert(checkForProperHandle(soundDesc)); if (soundDesc->resPtr) { _vm->_res->unlock(rtSound, soundDesc->soundId); } delete soundDesc->bundle; memset(soundDesc, 0, sizeof(SoundDesc)); } } bool ImuseDigiSndMgr::checkForProperHandle(SoundDesc *soundDesc) { if (!soundDesc) return false; for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) { if (soundDesc == &_sounds[l]) return true; } return false; } } // End of namespace Scumm