diff options
author | Travis Howell | 2006-01-05 07:06:47 +0000 |
---|---|---|
committer | Travis Howell | 2006-01-05 07:06:47 +0000 |
commit | e01afb0bd4b80c387a6170ee45a74ad684038b49 (patch) | |
tree | 3807c3801aa8b0b973474dc929c7062e5ccffb47 /scumm | |
parent | c2702891ceef6f08b3e5b6c22346119202101813 (diff) | |
download | scummvm-rg350-e01afb0bd4b80c387a6170ee45a74ad684038b49.tar.gz scummvm-rg350-e01afb0bd4b80c387a6170ee45a74ad684038b49.tar.bz2 scummvm-rg350-e01afb0bd4b80c387a6170ee45a74ad684038b49.zip |
Initial support for sound code in HE games.
Split HE sound functions into separate file.
svn-id: r19909
Diffstat (limited to 'scumm')
-rw-r--r-- | scumm/actor.cpp | 14 | ||||
-rw-r--r-- | scumm/intern.h | 9 | ||||
-rw-r--r-- | scumm/module.mk | 1 | ||||
-rw-r--r-- | scumm/resource.cpp | 7 | ||||
-rw-r--r-- | scumm/resource_v7he.cpp | 115 | ||||
-rw-r--r-- | scumm/script_v100he.cpp | 18 | ||||
-rw-r--r-- | scumm/script_v72he.cpp | 10 | ||||
-rw-r--r-- | scumm/script_v7he.cpp | 4 | ||||
-rw-r--r-- | scumm/script_v80he.cpp | 22 | ||||
-rw-r--r-- | scumm/script_v90he.cpp | 2 | ||||
-rw-r--r-- | scumm/scumm.cpp | 23 | ||||
-rw-r--r-- | scumm/scumm.h | 20 | ||||
-rw-r--r-- | scumm/sound.cpp | 259 | ||||
-rw-r--r-- | scumm/sound.h | 28 | ||||
-rw-r--r-- | scumm/sound_he.cpp | 506 | ||||
-rw-r--r-- | scumm/vars.cpp | 2 |
16 files changed, 766 insertions, 274 deletions
diff --git a/scumm/actor.cpp b/scumm/actor.cpp index 2ae09deb5d..a28cc6f7c0 100644 --- a/scumm/actor.cpp +++ b/scumm/actor.cpp @@ -1146,9 +1146,14 @@ void Actor::drawActorCostume(bool hitTestMode) { if (_vm->_heversion >= 80 && _heNoTalkAnimation == 0 && _animProgress == 0) { if (_vm->getTalkingActor() == _number && !_vm->_string[0].no_talk_anim) { - // Get sound var 19 of sound 1, if sound code is active. - // Otherwise choose random animation - setTalkCondition(_vm->_rnd.getRandomNumberRng(1, 10)); + int talkState = 0; + + if (_vm->_sound->isSoundCodeUsed(1)) + talkState = _vm->_sound->getSoundVar(1, 19); + if (talkState == 0) + talkState = _vm->_rnd.getRandomNumberRng(1, 10); + + setTalkCondition(talkState); } else { setTalkCondition(1); } @@ -1557,8 +1562,7 @@ void Actor::setActorCostume(int c) { if (_vm->_heversion >= 71 && _vm->getTalkingActor() == _number) { if (_vm->_heversion <= 95 || (_vm->_heversion >= 98 && _vm->VAR(_vm->VAR_SKIP_RESET_TALK_ACTOR) == 0)) { - // TODO - // _vm->setTalkingActor(0); + _vm->setTalkingActor(0); } } } diff --git a/scumm/intern.h b/scumm/intern.h index ff8614f8b7..3d7a7c61ac 100644 --- a/scumm/intern.h +++ b/scumm/intern.h @@ -1086,7 +1086,8 @@ protected: const OpcodeEntryV80he *_opcodesV80he; - int32 _heSBNGId; + int32 _heSndResId; + int _curSndId, _sndOffs1, _sndOffs2; public: ScummEngine_v80he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex); @@ -1102,11 +1103,13 @@ protected: virtual void clearDrawQueues(); + void createSound(int snd1id, int snd2id); + void drawLine(int x1, int y1, int x, int unk1, int unk2, int type, int id); void drawPixel(int x, int y, int flags); /* HE version 80 script opcodes */ - void o80_loadSBNG(); + void o80_createSound(); void o80_getFileSize(); void o80_stringToInt(); void o80_getSoundVar(); @@ -1300,7 +1303,7 @@ protected: void o100_resourceRoutines(); void o100_wizImageOps(); void o100_jumpToScript(); - void o100_loadSBNG(); + void o100_createSound(); void o100_dim2dim2Array(); void o100_paletteOps(); void o100_jumpToScriptUnk(); diff --git a/scumm/module.mk b/scumm/module.mk index 60498cb631..547a64e174 100644 --- a/scumm/module.mk +++ b/scumm/module.mk @@ -42,6 +42,7 @@ MODULE_OBJS := \ scumm/script_v6he.o \ scumm/scumm.o \ scumm/sound.o \ + scumm/sound_he.o \ scumm/string.o \ scumm/usage_bits.o \ scumm/util.o \ diff --git a/scumm/resource.cpp b/scumm/resource.cpp index a2ad0988e5..63deb1b520 100644 --- a/scumm/resource.cpp +++ b/scumm/resource.cpp @@ -1005,6 +1005,8 @@ bool ScummEngine::isResourceInUse(int type, int i) const { return _sound->isSoundInUse(i); case rtCharset: return _charset->getCurID() == i; + case rtSpoolBuffer: + return _sound->isSoundRunning(10000 + i); default: return false; } @@ -1348,6 +1350,9 @@ void ScummEngine::allocateArrays() { allocResTypeData(rtImage, MKID('AWIZ'), _numImages, "images", 1); allocResTypeData(rtTalkie, MKID('TLKE'), _numTalkies, "talkie", 1); + if (_heversion >= 70) { + allocResTypeData(rtSpoolBuffer, MKID('NONE'), 9, "spool buffer", 0); + } } void ScummEngine::dumpResource(const char *tag, int idx, const byte *ptr, int length) { @@ -1577,6 +1582,8 @@ const char *resTypeFromId(int id) { return "Image"; case rtTalkie: return "Talkie"; + case rtSpoolBuffer: + return "SpoolBuffer"; case rtNumTypes: return "NumTypes"; default: diff --git a/scumm/resource_v7he.cpp b/scumm/resource_v7he.cpp index 9c95bbdb48..931ca67266 100644 --- a/scumm/resource_v7he.cpp +++ b/scumm/resource_v7he.cpp @@ -1797,4 +1797,119 @@ int ScummEngine_v72he::getSoundResourceSize(int id) { return size; } +void ScummEngine_v80he::createSound(int snd1id, int snd2id) { + debug(0, "createSound: snd1id %d snd2id %d", snd1id, snd2id); + + byte *snd1Ptr, *snd2Ptr; + byte *sbng1Ptr, *sbng2Ptr; + byte *sdat1Ptr, *sdat2Ptr; + byte *src, *dst, *tmp; + int curOffs, len, offs, size; + + if (snd2id == -1) { + _sndOffs1 = 0; + _sndOffs2 = 0; + return; + } + + if (snd1id != _curSndId) { + _curSndId = snd1id; + _sndOffs1 = 0; + _sndOffs2 = 0; + } + + res.lock(rtSound, snd1id); + res.lock(rtSound, snd2id); + + snd1Ptr = getResourceAddress(rtSound, snd1id); + snd2Ptr = getResourceAddress(rtSound, snd2id); + + int i; + int chan = -1; + for (i = 0; i < ARRAYSIZE(_sound->_heChannel); i++) { + if (_sound->_heChannel[i].sound == snd1id) + chan = i; + } + + sbng1Ptr = heFindResource(MKID('SBNG'), snd1Ptr); + sbng2Ptr = heFindResource(MKID('SBNG'), snd2Ptr); + + if (sbng1Ptr != NULL && sbng2Ptr != NULL) { + if (chan != -1 && _sound->_heChannel[chan].codeOffs > 0) { + curOffs = _sound->_heChannel[chan].codeOffs; + + src = snd1Ptr + curOffs; + dst = sbng1Ptr + 8; + size = READ_BE_UINT32(sbng1Ptr + 4); + len = sbng1Ptr - snd1Ptr + size - curOffs; + memcpy(dst, src, len); + + + dst = sbng1Ptr + 8; + while ((offs = READ_LE_UINT16(dst)) != 0) + dst += offs; + } else { + dst = sbng1Ptr + 8; + } + + _sound->_heChannel[chan].codeOffs = sbng1Ptr - snd1Ptr + 8; + + tmp = sbng2Ptr + 8; + while ((offs = READ_LE_UINT16(tmp)) != 0) { + tmp += offs; + } + + src = sbng2Ptr + 8; + len = tmp - sbng2Ptr - 6; + memcpy(dst, src, len); + + int time; + while (READ_LE_UINT16(dst) != 0) { + time = READ_LE_UINT32(dst + 2); + time += _sndOffs2; + size = READ_LE_UINT16(dst); + WRITE_LE_UINT32(dst + 2, time); + dst += size; + } + } + + int size1, size2; + + sdat1Ptr = heFindResource(MKID('SDAT'), snd1Ptr); + assert(sdat1Ptr); + sdat2Ptr = heFindResource(MKID('SDAT'), snd2Ptr); + assert(sdat2Ptr); + + size1 = READ_BE_UINT32(sdat1Ptr + 4) - 8 - _sndOffs1; + size2 = READ_BE_UINT32(sdat2Ptr + 4) - 8; + + if (size2 < size1) { + src = sdat2Ptr + 8; + dst = sdat1Ptr + 8 + _sndOffs1; + len = size2; + + memcpy(dst, src, len); + + _sndOffs1 += size2; + _sndOffs2 += size2; + } else { + src = sdat2Ptr + 8; + dst = sdat1Ptr + 8 + _sndOffs1; + len = size1; + + memcpy(dst, src, len); + + int tmp3 = size2 - size1; + if (tmp3 != 0) { + // TODO: Additional copy + } + + _sndOffs1 += tmp3; + _sndOffs2 += size2; + } + + res.unlock(rtSound, snd1id); + res.unlock(rtSound, snd2id); +} + } // End of namespace Scumm diff --git a/scumm/script_v100he.cpp b/scumm/script_v100he.cpp index 49763c31c9..7dcaec45e2 100644 --- a/scumm/script_v100he.cpp +++ b/scumm/script_v100he.cpp @@ -68,7 +68,7 @@ void ScummEngine_v100he::setupOpcodes() { OPCODE(o6_loadRoomWithEgo), OPCODE(o6_invalid), OPCODE(o72_setFilePath), - OPCODE(o100_loadSBNG), + OPCODE(o100_createSound), /* 18 */ OPCODE(o6_cutscene), OPCODE(o6_pop), @@ -708,28 +708,25 @@ void ScummEngine_v100he::o100_jumpToScript() { runScript(script, (flags == 128 || flags == 129), (flags == 130 || flags == 129), args); } -void ScummEngine_v100he::o100_loadSBNG() { - // Loads SBNG sound resource +void ScummEngine_v100he::o100_createSound() { byte subOp = fetchScriptByte(); switch (subOp) { case 0: - _heSBNGId = pop(); + _heSndResId = pop(); break; case 53: - //loadSBNG(_heSBNGId, -1); + createSound(_heSndResId, -1); break; case 92: // dummy case break; case 128: - //loadSBNG(_heSBNGId, pop(); - pop(); + createSound(_heSndResId, pop()); break; default: - error("o100_loadSBNG: default case %d", subOp); + error("o100_createSound: default case %d", subOp); } - debug(1,"o100_loadSBNG stub (%d)",subOp); } void ScummEngine_v100he::o100_dim2dimArray() { @@ -1679,7 +1676,8 @@ void ScummEngine_v100he::o100_startSound() { value = pop(); var = pop(); _heSndSoundId = pop(); - debug(0,"o100_startSound: case 29 (snd %d, var %d, value %d)", _heSndSoundId, var, value); + _sound->setSoundVar(_heSndSoundId, var, value); + debug(0,"o100_startSound: case 83 (snd %d, var %d, value %d)", _heSndSoundId, var, value); break; case 92: debug(0, "o100_startSound (ID %d, Offset %d, Channel %d, Flags %d)", _heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags); diff --git a/scumm/script_v72he.cpp b/scumm/script_v72he.cpp index bc8fbbcfab..516827daca 100644 --- a/scumm/script_v72he.cpp +++ b/scumm/script_v72he.cpp @@ -868,9 +868,7 @@ void ScummEngine_v72he::o72_getTimer() { int cmd = fetchScriptByte(); if (cmd == 10 || cmd == 50) { - checkRange(3, 1, timer, "o72_getTimer: Timer %d out of range(%d)"); - int diff = _system->getMillis() - _timers[timer]; - push(diff); + push(getHETimer(timer)); } else { push(0); } @@ -881,8 +879,7 @@ void ScummEngine_v72he::o72_setTimer() { int cmd = fetchScriptByte(); if (cmd == 158 || cmd == 61) { - checkRange(3, 1, timer, "o72_setTimer: Timer %d out of range(%d)"); - _timers[timer] = _system->getMillis(); + setHETimer(timer); } else { error("TIMER command %d?", cmd); } @@ -890,8 +887,7 @@ void ScummEngine_v72he::o72_setTimer() { void ScummEngine_v72he::o72_getSoundPosition() { int snd = pop(); - push(_sound->getSoundElapsedTime(snd) * 10); - debug(1,"o72_getSoundPosition (%d)", snd); + push(_sound->getSoundPos(snd)); } void ScummEngine_v72he::o72_startScript() { diff --git a/scumm/script_v7he.cpp b/scumm/script_v7he.cpp index b5e7ee5e66..6153ecbf1b 100644 --- a/scumm/script_v7he.cpp +++ b/scumm/script_v7he.cpp @@ -436,11 +436,13 @@ void ScummEngine_v70he::o70_startSound() { value = pop(); var = pop(); _heSndSoundId = pop(); + _sound->setSoundVar(_heSndSoundId, var, value); debug(0,"o70_startSound: case 23 (snd %d, var %d, value %d)", _heSndSoundId, var, value); break; case 25: value = pop(); _heSndSoundId = pop(); + debug(0, "o70_startSound: case 25 (ID %d, Offset 0, Channel 0, Flags 8)", _heSndSoundId); _sound->addSoundToQueue(_heSndSoundId, 0, 0, 8); case 56: _heSndFlags |= 16; @@ -467,7 +469,7 @@ void ScummEngine_v70he::o70_startSound() { _heSndFlags |= 1; break; case 255: - debug(1, "o70_startSound (ID %d, Offset %d, Channel %d, Flags %d)", _heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags); + debug(0, "o70_startSound (ID %d, Offset %d, Channel %d, Flags %d)", _heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags); _sound->addSoundToQueue(_heSndSoundId, _heSndOffset, _heSndChannel, _heSndFlags); _heSndFlags = 0; break; diff --git a/scumm/script_v80he.cpp b/scumm/script_v80he.cpp index 600b22bf1e..a771f87c7f 100644 --- a/scumm/script_v80he.cpp +++ b/scumm/script_v80he.cpp @@ -129,7 +129,7 @@ void ScummEngine_v80he::setupOpcodes() { OPCODE(o6_writeWordVar), /* 44 */ OPCODE(o6_invalid), - OPCODE(o80_loadSBNG), + OPCODE(o80_createSound), OPCODE(o80_getFileSize), OPCODE(o6_wordArrayWrite), /* 48 */ @@ -376,28 +376,25 @@ const char *ScummEngine_v80he::getOpcodeDesc(byte i) { return _opcodesV80he[i].desc; } -void ScummEngine_v80he::o80_loadSBNG() { - // Loads SBNG sound resource +void ScummEngine_v80he::o80_createSound() { byte subOp = fetchScriptByte(); switch (subOp) { case 27: - //loadSBNG(_heSBNGId, pop(); - pop(); + createSound(_heSndResId, pop()); break; case 217: - //loadSBNG(_heSBNGId, -1); + createSound(_heSndResId, -1); break; case 232: - _heSBNGId = pop(); + _heSndResId = pop(); break; case 255: // dummy case break; default: - error("o80_loadSBNG: default case %d", subOp); + error("o80_createSound: default case %d", subOp); } - debug(1,"o80_loadSBNG stub (%d)",subOp); } void ScummEngine_v80he::o80_getFileSize() { @@ -432,14 +429,9 @@ void ScummEngine_v80he::o80_stringToInt() { } void ScummEngine_v80he::o80_getSoundVar() { - // Checks sound variable int var = pop(); int snd = pop(); - int rnd = _rnd.getRandomNumberRng(1, 3); - - checkRange(27, 0, var, "Illegal sound variable %d"); - push (rnd); - debug(1,"o80_getSoundVar stub (snd %d, var %d)", snd, var); + push(_sound->getSoundVar(snd, var)); } void ScummEngine_v80he::o80_localizeArrayToRoom() { diff --git a/scumm/script_v90he.cpp b/scumm/script_v90he.cpp index 5b6eddecbb..2f2a01abe0 100644 --- a/scumm/script_v90he.cpp +++ b/scumm/script_v90he.cpp @@ -127,7 +127,7 @@ void ScummEngine_v90he::setupOpcodes() { OPCODE(o6_writeWordVar), /* 44 */ OPCODE(o90_getObjectData), - OPCODE(o80_loadSBNG), + OPCODE(o80_createSound), OPCODE(o80_getFileSize), OPCODE(o6_wordArrayWrite), /* 48 */ diff --git a/scumm/scumm.cpp b/scumm/scumm.cpp index 7aa7104364..3be3704c53 100644 --- a/scumm/scumm.cpp +++ b/scumm/scumm.cpp @@ -1210,7 +1210,7 @@ ScummEngine::ScummEngine(GameDetector *detector, OSystem *syst, const ScummGameS _actorClipOverride.right = 640; _skipDrawObject = 0; - memset(_timers, 0, sizeof(_timers)); + memset(_heTimers, 0, sizeof(_heTimers)); memset(_akosQueue, 0, sizeof(_akosQueue)); _akosQueuePos = 0; @@ -1340,6 +1340,8 @@ ScummEngine::ScummEngine(GameDetector *detector, OSystem *syst, const ScummGameS VAR_SKIP_RESET_TALK_ACTOR = 0xFF; VAR_MUSIC_CHANNEL = 0xFF; VAR_SOUND_CHANNEL = 0xFF; + VAR_SOUNDCODE_TMR = 0xFF; + VAR_DEFAULT_SOUND_CHANNEL = 0xFF; VAR_NUM_SCRIPT_CYCLES = 0xFF; VAR_SCRIPT_CYCLE = 0xFF; @@ -1605,7 +1607,10 @@ ScummEngine_v72he::ScummEngine_v72he(GameDetector *detector, OSystem *syst, cons ScummEngine_v80he::ScummEngine_v80he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex) : ScummEngine_v72he(detector, syst, gs, md5sum, substResFileNameIndex) { - _heSBNGId = 0; + _heSndResId = 0; + _curSndId = 0; + _sndOffs1 = 0; + _sndOffs2 = 0; } ScummEngine_v90he::ScummEngine_v90he(GameDetector *detector, OSystem *syst, const ScummGameSettings &gs, uint8 md5sum[16], int substResFileNameIndex) @@ -2489,6 +2494,9 @@ load_game: _fullRedraw = true; } + if (_heversion >= 80) { + _sound->processSoundCode(); + } runAllScripts(); checkExecVerbs(); checkAndRunSentenceScript(); @@ -2609,6 +2617,17 @@ load_game: #pragma mark --- SCUMM --- #pragma mark - +int ScummEngine::getHETimer(int timer) { + checkRange(15, 1, timer, "getHETimer: Timer %d out of range(%d)"); + int time = _system->getMillis() - _heTimers[timer]; + return time; +} + +void ScummEngine::setHETimer(int timer) { + checkRange(15, 1, timer, "setHETimer: Timer %d out of range(%d)"); + _heTimers[timer] = _system->getMillis(); +} + void ScummEngine::pauseGame() { pauseDialog(); } diff --git a/scumm/scumm.h b/scumm/scumm.h index c73dd16ae6..091f90d828 100644 --- a/scumm/scumm.h +++ b/scumm/scumm.h @@ -311,8 +311,9 @@ enum ResTypes { rtRoomImage = 18, rtImage = 19, rtTalkie = 20, - rtLast = 20, - rtNumTypes = 21 + rtSpoolBuffer = 21, + rtLast = 21, + rtNumTypes = 22 }; class ResourceManager { @@ -1074,14 +1075,19 @@ protected: bool testGfxOtherUsageBits(int strip, int bit); public: - uint8 *_hePalettes; - byte _HEV7ActorPalette[256]; byte _roomPalette[256]; byte *_shadowPalette; bool _skipDrawObject; - int _timers[4]; int _voiceMode; + // HE specific + byte _HEV7ActorPalette[256]; + uint8 *_hePalettes; + + int _heTimers[16]; + int getHETimer(int timer); + void setHETimer(int timer); + protected: int _shadowPaletteSize; byte _currentPalette[3 * 256]; @@ -1310,7 +1316,7 @@ public: byte VAR_SAVELOAD_SCRIPT; // V6/V7 (not HE) byte VAR_SAVELOAD_SCRIPT2; // V6/V7 (not HE) - // V6/V7 specific variables (actually, they are only used in FT and Sam, it seems?) + // V6/V7 specific variables (FT & Sam & Max specific) byte VAR_CHARSET_MASK; // V6 specific variables @@ -1328,6 +1334,8 @@ public: byte VAR_SKIP_RESET_TALK_ACTOR; byte VAR_MUSIC_CHANNEL; byte VAR_SOUND_CHANNEL; + byte VAR_SOUNDCODE_TMR; + byte VAR_DEFAULT_SOUND_CHANNEL; byte VAR_SCRIPT_CYCLE; byte VAR_NUM_SCRIPT_CYCLES; diff --git a/scumm/sound.cpp b/scumm/sound.cpp index 9102ab7bd0..01e292bea3 100644 --- a/scumm/sound.cpp +++ b/scumm/sound.cpp @@ -29,6 +29,7 @@ #include "scumm/util.h" #include "common/config-manager.h" +#include "common/system.h" #include "common/timer.h" #include "common/util.h" @@ -79,6 +80,7 @@ Sound::Sound(ScummEngine *parent) _sfxMode(0), _heMusicTracks(0) { + memset(_heChannel, 0, sizeof(_heChannel)); memset(_soundQue, 0, sizeof(_soundQue)); memset(_soundQue2, 0, sizeof(_soundQue2)); memset(_mouthSyncTimes, 0, sizeof(_mouthSyncTimes)); @@ -92,9 +94,16 @@ Sound::~Sound() { void Sound::addSoundToQueue(int sound, int heOffset, int heChannel, int heFlags) { if (_vm->VAR_LAST_SOUND != 0xFF) _vm->VAR(_vm->VAR_LAST_SOUND) = sound; + + if (heFlags & 16) { + playHESound(sound, heOffset, heChannel, heFlags); + return; + } + // HE music resources are in separate file if (sound <= _vm->_numSounds) _vm->ensureResourceLoaded(rtSound, sound); + addSoundToQueue2(sound, heOffset, heChannel, heFlags); } @@ -140,8 +149,12 @@ void Sound::processSoundQueues() { heOffset = _soundQue2[_soundQue2Pos].offset; heChannel = _soundQue2[_soundQue2Pos].channel; heFlags = _soundQue2[_soundQue2Pos].flags; - if (snd) - playSound(snd, heOffset, heChannel, heFlags); + if (snd) { + if (_vm->_heversion>= 60) + playHESound(snd, heOffset, heChannel, heFlags); + else + playSound(snd); + } } while (i < _soundQuePos) { @@ -168,64 +181,7 @@ void Sound::processSoundQueues() { _soundQuePos = 0; } -void Sound::setOverrideFreq(int freq) { - _overrideFreq = freq; -} - -void Sound::setupHEMusicFile() { - int i, total_size; - char buf[32], buf1[128]; - Common::File musicFile; - - sprintf(buf, "%s.he4", _vm->getGameName()); - - if (_vm->_substResFileNameIndex > 0) { - _vm->generateSubstResFileName(buf, buf1, sizeof(buf1)); - strcpy(buf, buf1); - } - if (musicFile.open(buf) == true) { - musicFile.seek(4, SEEK_SET); - total_size = musicFile.readUint32BE(); - musicFile.seek(16, SEEK_SET); - _heMusicTracks = musicFile.readUint32LE(); - debug(0, "Total music tracks %d", _heMusicTracks); - - int musicStart = (_vm->_heversion >= 80) ? 56 : 20; - musicFile.seek(musicStart, SEEK_SET); - - _heMusic = (HEMusic *)malloc((_heMusicTracks + 1) * sizeof(HEMusic)); - for (i = 0; i < _heMusicTracks; i++) { - _heMusic[i].id = musicFile.readUint32LE(); - _heMusic[i].offset = musicFile.readUint32LE(); - _heMusic[i].size = musicFile.readUint32LE(); - - if (_vm->_heversion >= 80) { - musicFile.seek(+9, SEEK_CUR); - } else { - musicFile.seek(+13, SEEK_CUR); - } - } - - musicFile.close(); - } -} - -bool Sound::getHEMusicDetails(int id, int &musicOffs, int &musicSize) { - int i; - - for (i = 0; i < _heMusicTracks; i++) { - if (_heMusic[i].id == id) { - musicOffs = _heMusic[i].offset; - musicSize = _heMusic[i].size; - return 1; - } - } - - return 0; -} - -void Sound::playSound(int soundID, int heOffset, int heChannel, int heFlags) { - debug(5,"playSound: soundID %d heOffset %d heChannel %d heFlags %d", soundID, heOffset, heChannel, heFlags); +void Sound::playSound(int soundID) { byte *mallocedPtr = NULL; byte *ptr; char *sound; @@ -233,56 +189,10 @@ void Sound::playSound(int soundID, int heOffset, int heChannel, int heFlags) { int rate; byte flags = Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE; - if (heChannel == -1) { - heChannel = 1; - } - if (_vm->_heversion >= 70 && soundID > _vm->_numSounds) { - debug(1, "playSound #%d", soundID); - - if (soundID >= 10000) { - // Special codes, used in pjgames - return; - } - - int music_offs; - char buf[32], buf1[128]; - Common::File musicFile; - - sprintf(buf, "%s.he4", _vm->getGameName()); - - if (_vm->_substResFileNameIndex > 0) { - _vm->generateSubstResFileName(buf, buf1, sizeof(buf1)); - strcpy(buf, buf1); - } - if (musicFile.open(buf) == false) { - warning("playSound: Can't open music file %s", buf); - return; - } - if (!getHEMusicDetails(soundID, music_offs, size)) { - debug(0, "playSound: musicID %d not found", soundID); - return; - } - - musicFile.seek(music_offs, SEEK_SET); - ptr = (byte *)malloc(size); - musicFile.read(ptr, size); - musicFile.close(); + debugC(DEBUG_SOUND, "playSound #%d (room %d)", soundID, + _vm->getResourceRoomNr(rtSound, soundID)); - _vm->_mixer->stopID(_currentMusic); - _currentMusic = soundID; - if (_vm->_heversion == 70) { - _vm->_mixer->playRaw(&_heSoundChannels[heChannel], ptr, size, 11025, flags, soundID); - return; - } - - // This pointer will be freed at the end of the function - mallocedPtr = ptr; - } else { - debugC(DEBUG_SOUND, "playSound #%d (room %d)", soundID, - _vm->getResourceRoomNr(rtSound, soundID)); - - ptr = _vm->getResourceAddress(rtSound, soundID); - } + ptr = _vm->getResourceAddress(rtSound, soundID); if (!ptr) { return; @@ -304,7 +214,6 @@ void Sound::playSound(int soundID, int heOffset, int heChannel, int heFlags) { memcpy(sound, ptr, size); _vm->_mixer->playRaw(NULL, sound, size, rate, flags, soundID); } - // WORKAROUND bug # 1311447 else if (READ_UINT32(ptr) == MKID(0x460e200d)) { // This sound resource occurs in the Macintosh version of Monkey Island. @@ -327,91 +236,6 @@ void Sound::playSound(int soundID, int heOffset, int heChannel, int heFlags) { memcpy(sound, ptr, size); _vm->_mixer->playRaw(NULL, sound, size, rate, flags, soundID); } - - // Support for sound in later Backyard sports games - else if (READ_UINT32(ptr) == MKID('RIFF')) { - uint16 type; - int blockAlign; - size = READ_LE_UINT32(ptr + 4); - Common::MemoryReadStream stream(ptr, size); - - if (!loadWAVFromStream(stream, size, rate, flags, &type, &blockAlign)) { - error("playSound: Not a valid WAV file"); - } - - if (type == 17) { - AudioStream *voxStream = new ADPCMInputStream(&stream, size, kADPCMIma, (flags & Audio::Mixer::FLAG_STEREO) ? 2 : 1, blockAlign); - - sound = (char *)malloc(size * 4); - size = voxStream->readBuffer((int16*)sound, size * 2); - size *= 2; // 16bits. - } else { - // Allocate a sound buffer, copy the data into it, and play - sound = (char *)malloc(size); - memcpy(sound, ptr + stream.pos(), size); - } - _vm->_mixer->playRaw(&_heSoundChannels[heChannel], sound, size, rate, flags, soundID); - } - // Support for sound in Humongous Entertainment games - else if (READ_UINT32(ptr) == MKID('DIGI') || READ_UINT32(ptr) == MKID('TALK') || READ_UINT32(ptr) == MKID('HSHD')) { - int priority; - - if (READ_UINT32(ptr) == MKID('HSHD')) { - priority = READ_LE_UINT16(ptr + 10); - rate = READ_LE_UINT16(ptr + 14); - ptr += READ_BE_UINT32(ptr + 4); - } else { - priority = READ_LE_UINT16(ptr + 18); - rate = READ_LE_UINT16(ptr + 22); - ptr += 8 + READ_BE_UINT32(ptr + 12); - } - - if (READ_UINT32(ptr) == MKID('SBNG')) { - ptr += READ_BE_UINT32(ptr + 4); - } - - assert(READ_UINT32(ptr) == MKID('SDAT')); - size = READ_BE_UINT32(ptr+4) - 8; - if (heOffset < 0 || heOffset > size) { - // Occurs when making fireworks in puttmoon - debug(0, "playSound: Invalid sound offset (%d) in sound %d", heOffset, soundID); - heOffset = 0; - } - size -= heOffset; - - if (_overrideFreq) { - // Used by the piano in Fatty Bear's Birthday Surprise - rate = _overrideFreq; - _overrideFreq = 0; - } - - if (heFlags & 1) { - // TODO - // flags |= Audio::Mixer::FLAG_LOOP; - } - - // Allocate a sound buffer, copy the data into it, and play - sound = (char *)malloc(size); - memcpy(sound, ptr + heOffset + 8, size); - _vm->_mixer->playRaw(&_heSoundChannels[heChannel], sound, size, rate, flags, soundID); - } - // Support for PCM music in 3DO versions of Humongous Entertainment games - else if (READ_UINT32(ptr) == MKID('MRAW')) { - ptr += 8 + READ_BE_UINT32(ptr+12); - if (READ_UINT32(ptr) != MKID('SDAT')) - return; - - size = READ_BE_UINT32(ptr+4) - 8; - rate = 22050; - flags = Audio::Mixer::FLAG_AUTOFREE; - - // Allocate a sound buffer, copy the data into it, and play - sound = (char *)malloc(size); - memcpy(sound, ptr + 8, size); - _vm->_mixer->stopID(_currentMusic); - _currentMusic = soundID; - _vm->_mixer->playRaw(NULL, sound, size, rate, flags, soundID); - } // Support for sampled sound effects in Monkey Island 1 and 2 else if (READ_UINT32(ptr) == MKID('SBL ')) { debugC(DEBUG_SOUND, "Using SBL sound effect"); @@ -696,30 +520,6 @@ static int compareMP3OffsetTable(const void *a, const void *b) { return ((const MP3OffsetTable *)a)->org_offset - ((const MP3OffsetTable *)b)->org_offset; } -void Sound::startHETalkSound(uint32 offset) { - byte *ptr; - int32 size; - - if (ConfMan.getBool("speech_mute")) - return; - - if (!_sfxFile->isOpen()) { - error("startHETalkSound: Speech file is not open"); - return; - } - - _sfxMode |= 2; - _vm->res.nukeResource(rtSound, 1); - _sfxFile->seek(offset + 4, SEEK_SET); - size = _sfxFile->readUint32BE() - 8; - _vm->res.createResource(rtSound, 1, size); - ptr = _vm->getResourceAddress(rtSound, 1); - _sfxFile->read(ptr, size); - - int channel = (_vm->VAR_SOUND_CHANNEL != 0xFF) ? _vm->VAR(_vm->VAR_SOUND_CHANNEL) : 0; - addSoundToQueue2(1, 0, channel, 0); -} - void Sound::startTalkSound(uint32 offset, uint32 b, int mode, Audio::SoundHandle *handle) { int num = 0, i; int size = 0; @@ -1008,7 +808,13 @@ void Sound::stopSound(int sound) { if (_vm->_heversion >= 70) { if ( sound >= 10000) { - _vm->_mixer->stopHandle(_heSoundChannels[sound - 10000]); + int chan = sound - 10000; + _vm->_mixer->stopHandle(_heSoundChannels[chan]); + _heChannel[chan].sound = 0; + _heChannel[chan].priority = 0; + _heChannel[chan].sbngBlock = 0; + _heChannel[chan].codeOffs = 0; + memset(_heChannel[chan].soundVars, 0, sizeof(_heChannel[chan].soundVars)); } } else if (_vm->_heversion >= 60) { if (sound == -2) { @@ -1033,6 +839,16 @@ void Sound::stopSound(int sound) { if (_vm->_musicEngine) _vm->_musicEngine->stopSound(sound); + for (i = 0; i < ARRAYSIZE(_heChannel); i++) { + if (_heChannel[i].sound == sound) { + _heChannel[i].sound = 0; + _heChannel[i].priority = 0; + _heChannel[i].sbngBlock = 0; + _heChannel[i].codeOffs = 0; + memset(_heChannel[i].soundVars, 0, sizeof(_heChannel[i].soundVars)); + } + } + for (i = 0; i < ARRAYSIZE(_soundQue2); i++) { if (_soundQue2[i].sound == sound) { _soundQue2[i].sound = 0; @@ -1050,6 +866,9 @@ void Sound::stopAllSounds() { stopCDTimer(); } + // Clear sound channels for HE games + memset(_heChannel, 0, sizeof(_heChannel)); + // Clear the (secondary) sound queue _soundQue2Pos = 0; memset(_soundQue2, 0, sizeof(_soundQue2)); diff --git a/scumm/sound.h b/scumm/sound.h index 7bc34cfab1..a8e3cd9715 100644 --- a/scumm/sound.h +++ b/scumm/sound.h @@ -95,6 +95,16 @@ protected: HEMusic *_heMusic; int16 _heMusicTracks; +public: // Used by createSound() + struct { + int sound; + int codeOffs; + int priority; + int sbngBlock; + int soundVars[27]; + int timer; + } _heChannel[9]; + public: Audio::SoundHandle _talkChannelHandle; // Handle of mixer channel actor is talking on Audio::SoundHandle _heSoundChannels[8]; @@ -109,9 +119,8 @@ public: void addSoundToQueue2(int sound, int heOffset = 0, int heChannel = 0, int heFlags = 0); void processSound(); void processSoundQueues(); - void setOverrideFreq(int freq); - void playSound(int soundID, int heOffset, int heChannel, int heFlags); - void startHETalkSound(uint32 offset); + + void playSound(int soundID); void startTalkSound(uint32 offset, uint32 b, int mode, Audio::SoundHandle *handle = NULL); void stopTalkSound(); bool isMouthSyncOff(uint pos); @@ -134,8 +143,19 @@ public: void updateCD(); int getCurrentCDSound() const { return _currentCDSound; } - void setupHEMusicFile(); + // HE specific bool getHEMusicDetails(int id, int &musicOffs, int &musicSize); + int isSoundCodeUsed(int sound); + int getSoundPos(int sound); + int getSoundPriority(int sound); + int getSoundVar(int sound, int var); + void setSoundVar(int sound, int var, int val); + void playHESound(int soundID, int heOffset, int heChannel, int heFlags); + void processSoundCode(); + void processSoundOpcodes(int sound, byte *codePtr, int *soundVars); + void setOverrideFreq(int freq); + void setupHEMusicFile(); + void startHETalkSound(uint32 offset); // Used by the save/load system: void saveLoadWithSerializer(Serializer *ser); diff --git a/scumm/sound_he.cpp b/scumm/sound_he.cpp new file mode 100644 index 0000000000..662417ef26 --- /dev/null +++ b/scumm/sound_he.cpp @@ -0,0 +1,506 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2005 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. + * + * $Header$ + * + */ + +#include "common/stdafx.h" +#include "scumm/actor.h" +#include "scumm/scumm.h" +#include "scumm/sound.h" +#include "scumm/util.h" + +#include "common/config-manager.h" +#include "common/system.h" +#include "common/timer.h" +#include "common/util.h" + +#include "sound/adpcm.h" +#include "sound/audiocd.h" +#include "sound/flac.h" +#include "sound/mididrv.h" +#include "sound/mixer.h" +#include "sound/mp3.h" +#include "sound/voc.h" +#include "sound/vorbis.h" +#include "sound/wave.h" + +namespace Scumm { + +int Sound::isSoundCodeUsed(int sound) { + int chan = -1; + for (int i = 0; i < ARRAYSIZE(_heChannel); i ++) { + if (_heChannel[i].sound == sound) + chan = i; + } + + if (chan != -1) { + return _heChannel[chan].sbngBlock; + } else { + return 0; + } +} + +int Sound::getSoundPos(int sound) { + int chan = -1; + for (int i = 0; i < ARRAYSIZE(_heChannel); i ++) { + if (_heChannel[i].sound == sound) + chan = i; + } + + if (chan != -1) { + int time = _vm->getHETimer(chan + 4) * 11025 / 1000; + return time; + } else { + return 0; + } +} + +int Sound::getSoundPriority(int sound) { + int chan = -1; + for (int i = 0; i < ARRAYSIZE(_heChannel); i ++) { + if (_heChannel[i].sound == sound) + chan = i; + } + + if (chan != -1) { + return _heChannel[chan].priority; + } else { + return 0; + } +} + +int Sound::getSoundVar(int sound, int var) { + checkRange(25, 0, var, "Illegal sound variable %d"); + + int chan = -1; + for (int i = 0; i < ARRAYSIZE(_heChannel); i ++) { + if (_heChannel[i].sound == sound) + chan = i; + } + + if (chan != -1) { + //debug(1, "getSoundVar: sound %d var %d result %d\n", sound, var, _heChannel[chan].soundVars[var]); + return _heChannel[chan].soundVars[var]; + } else { + return 0; + } +} + +void Sound::setSoundVar(int sound, int var, int val) { + checkRange(25, 0, var, "Illegal sound variable %d"); + + int chan = -1; + for (int i = 0; i < ARRAYSIZE(_heChannel); i ++) { + if (_heChannel[i].sound == sound) + chan = i; + } + + if (chan != -1) { + _heChannel[chan].soundVars[var] = val; + } +} + +void Sound::setOverrideFreq(int freq) { + _overrideFreq = freq; +} + +void Sound::setupHEMusicFile() { + int i, total_size; + char buf[32], buf1[128]; + Common::File musicFile; + + sprintf(buf, "%s.he4", _vm->getGameName()); + + if (_vm->_substResFileNameIndex > 0) { + _vm->generateSubstResFileName(buf, buf1, sizeof(buf1)); + strcpy(buf, buf1); + } + if (musicFile.open(buf) == true) { + musicFile.seek(4, SEEK_SET); + total_size = musicFile.readUint32BE(); + musicFile.seek(16, SEEK_SET); + _heMusicTracks = musicFile.readUint32LE(); + debug(0, "Total music tracks %d", _heMusicTracks); + + int musicStart = (_vm->_heversion >= 80) ? 56 : 20; + musicFile.seek(musicStart, SEEK_SET); + + _heMusic = (HEMusic *)malloc((_heMusicTracks + 1) * sizeof(HEMusic)); + for (i = 0; i < _heMusicTracks; i++) { + _heMusic[i].id = musicFile.readUint32LE(); + _heMusic[i].offset = musicFile.readUint32LE(); + _heMusic[i].size = musicFile.readUint32LE(); + + if (_vm->_heversion >= 80) { + musicFile.seek(+9, SEEK_CUR); + } else { + musicFile.seek(+13, SEEK_CUR); + } + } + + musicFile.close(); + } +} + +bool Sound::getHEMusicDetails(int id, int &musicOffs, int &musicSize) { + int i; + + for (i = 0; i < _heMusicTracks; i++) { + if (_heMusic[i].id == id) { + musicOffs = _heMusic[i].offset; + musicSize = _heMusic[i].size; + return 1; + } + } + + return 0; +} + +void Sound::processSoundCode() { + byte *codePtr; + int chan, tmr, size, time; + + for (chan = 0; chan < ARRAYSIZE(_heChannel); chan++) { + if (_heChannel[chan].sound == 0) { + continue; + } + + if (_heChannel[chan].codeOffs == -1) { + continue; + } + + tmr = _vm->getHETimer(chan + 4) * 11025 / 1000; + tmr += _vm->VAR(_vm->VAR_SOUNDCODE_TMR); + if (tmr < 0) + tmr = 0; + + if (_heChannel[chan].sound > _vm->_numSounds) { + codePtr = _vm->getResourceAddress(rtSpoolBuffer, chan); + } else { + codePtr = _vm->getResourceAddress(rtSound, _heChannel[chan].sound); + } + assert(codePtr); + codePtr += _heChannel[chan].codeOffs; + + while(1) { + size = READ_LE_UINT16(codePtr); + time = READ_LE_UINT32(codePtr + 2); + + if (size == 0) { + _heChannel[chan].codeOffs = -1; + break; + } + + debug(1, "Channel %d Timer %d Time %d", chan,tmr, time); + if (time >= tmr) + break; + + processSoundOpcodes(_heChannel[chan].sound, codePtr + 6, _heChannel[chan].soundVars); + + codePtr += size; + _heChannel[chan].codeOffs += size; + } + } +} + +void Sound::processSoundOpcodes(int sound, byte *codePtr, int *soundVars) { + int edi, opcode, var, val; + + while(READ_LE_UINT16(codePtr) != 0) { + codePtr += 2; + opcode = READ_LE_UINT16(codePtr); codePtr += 2; + opcode &= ~0xF000; + opcode /= 16; + edi = opcode; + opcode &= ~3; + edi &= 3; + + debug(1, "processSoundOpcodes: sound %d opcode %d", sound, opcode); + switch (opcode) { + case 0: // Continue + break; + case 16: // Set talk state + val = READ_LE_UINT16(codePtr); codePtr += 2; + setSoundVar(sound, 19, val); + break; + case 32: // Set var + var = READ_LE_UINT16(codePtr); codePtr += 2; + val = READ_LE_UINT16(codePtr); codePtr += 2; + if (edi == 2) { + val = getSoundVar(sound, val); + } + setSoundVar(sound, var, val); + break; + case 48: // Add + var = READ_LE_UINT16(codePtr); codePtr += 2;; + val = READ_LE_UINT16(codePtr); codePtr += 2;; + + val = getSoundVar(sound, var) + val; + setSoundVar(sound, var, val); + break; + case 56: // Subtract + var = READ_LE_UINT16(codePtr); codePtr += 2;; + val = READ_LE_UINT16(codePtr); codePtr += 2;; + + val = getSoundVar(sound, var) - val; + setSoundVar(sound, var, val); + break; + case 64: // Multiple + var = READ_LE_UINT16(codePtr); codePtr += 2;; + val = READ_LE_UINT16(codePtr); codePtr += 2; + if (edi == 2) { + val = getSoundVar(sound, val); + } + + val = getSoundVar(sound, var) * val; + setSoundVar(sound, var, val); + break; + case 80: // Divide + var = READ_LE_UINT16(codePtr); codePtr += 2;; + val = READ_LE_UINT16(codePtr); codePtr += 2; + if (edi == 2) { + val = getSoundVar(sound, val); + } + + val = getSoundVar(sound, var) / val; + setSoundVar(sound, var, val); + break; + case 96: // Increment + var = READ_LE_UINT16(codePtr); codePtr += 2; + val = getSoundVar(sound, var) + 1; + setSoundVar(sound, var, val); + break; + case 104: // Decrement + var = READ_LE_UINT16(codePtr); codePtr += 2; + val = getSoundVar(sound, var) - 1; + setSoundVar(sound, var, val); + break; + default: + error("Illegal sound %d opcode %d", sound, opcode); + } + } +} + +void Sound::playHESound(int soundID, int heOffset, int heChannel, int heFlags) { + debug(0,"playHESound: soundID %d heOffset %d heChannel %d heFlags %d", soundID, heOffset, heChannel, heFlags); + byte *mallocedPtr = NULL; + byte *ptr, *spoolPtr; + char *sound; + int size = -1; + int rate; + byte flags = Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE; + + if (heChannel == -1) { + if (_vm->_heversion >= 95 && _vm->VAR(_vm->VAR_DEFAULT_SOUND_CHANNEL) != 0) + heChannel = _vm->VAR(_vm->VAR_DEFAULT_SOUND_CHANNEL); + else + heChannel = 1; + } + + if (soundID > _vm->_numSounds) { + if (soundID >= 10000) { + // Special codes, used in pjgames + return; + } + + int music_offs; + char buf[32], buf1[128]; + Common::File musicFile; + + sprintf(buf, "%s.he4", _vm->getGameName()); + + if (_vm->_substResFileNameIndex > 0) { + _vm->generateSubstResFileName(buf, buf1, sizeof(buf1)); + strcpy(buf, buf1); + } + if (musicFile.open(buf) == false) { + warning("playSound: Can't open music file %s", buf); + return; + } + if (!getHEMusicDetails(soundID, music_offs, size)) { + debug(0, "playSound: musicID %d not found", soundID); + return; + } + + musicFile.seek(music_offs, SEEK_SET); + + if (_vm->_heversion == 70) { + spoolPtr = (byte *)malloc(size); + musicFile.read(spoolPtr, size); + } else { + spoolPtr = _vm->res.createResource(rtSpoolBuffer, heChannel, size); + assert(spoolPtr); + musicFile.read(spoolPtr, size); + } + musicFile.close(); + + _vm->_mixer->stopID(_currentMusic); + _currentMusic = soundID; + if (_vm->_heversion == 70) { + _vm->_mixer->playRaw(&_heSoundChannels[heChannel], spoolPtr, size, 11025, flags, soundID); + return; + } + + // This pointer will be freed at the end of the function + mallocedPtr = spoolPtr; + } + + if (soundID > _vm->_numSounds) { + ptr = _vm->getResourceAddress(rtSpoolBuffer, heChannel); + } else { + ptr = _vm->getResourceAddress(rtSound, soundID); + } + + if (!ptr) { + return; + } + + // Support for sound in later Backyard sports games + if (READ_UINT32(ptr) == MKID('RIFF')) { + uint16 type; + int blockAlign; + size = READ_LE_UINT32(ptr + 4); + Common::MemoryReadStream stream(ptr, size); + + if (!loadWAVFromStream(stream, size, rate, flags, &type, &blockAlign)) { + error("playSound: Not a valid WAV file"); + } + + if (type == 17) { + AudioStream *voxStream = new ADPCMInputStream(&stream, size, kADPCMIma, (flags & Audio::Mixer::FLAG_STEREO) ? 2 : 1, blockAlign); + + sound = (char *)malloc(size * 4); + size = voxStream->readBuffer((int16*)sound, size * 2); + size *= 2; // 16bits. + } else { + // Allocate a sound buffer, copy the data into it, and play + sound = (char *)malloc(size); + memcpy(sound, ptr + stream.pos(), size); + } + _vm->_mixer->playRaw(&_heSoundChannels[heChannel], sound, size, rate, flags, soundID); + } + // Support for sound in Humongous Entertainment games + else if (READ_UINT32(ptr) == MKID('DIGI') || READ_UINT32(ptr) == MKID('TALK') || READ_UINT32(ptr) == MKID('HSHD')) { + byte *sndPtr = ptr; + int priority; + + if (READ_UINT32(ptr) == MKID('HSHD')) { + priority = READ_LE_UINT16(ptr + 10); + rate = READ_LE_UINT16(ptr + 14); + ptr += READ_BE_UINT32(ptr + 4); + } else { + priority = READ_LE_UINT16(ptr + 18); + rate = READ_LE_UINT16(ptr + 22); + ptr += 8 + READ_BE_UINT32(ptr + 12); + } + + //if (_vm->_mixer->isSoundHandleActive(_heSoundChannels[heChannel]) && _heChannel[heChannel].priority > priority) + // return; + + int codeOffs = -1; + if (READ_UINT32(ptr) == MKID('SBNG')) { + codeOffs = ptr - sndPtr + 8; + ptr += READ_BE_UINT32(ptr + 4); + } + + assert(READ_UINT32(ptr) == MKID('SDAT')); + size = READ_BE_UINT32(ptr+4) - 8; + if (heOffset < 0 || heOffset > size) { + // Occurs when making fireworks in puttmoon + debug(0, "playSound: Invalid sound offset (offset %d, size %d) in sound %d", heOffset, size, soundID); + heOffset = 0; + } + size -= heOffset; + + if (_overrideFreq) { + // Used by the piano in Fatty Bear's Birthday Surprise + rate = _overrideFreq; + _overrideFreq = 0; + } + + if (heFlags & 1) { + flags |= Audio::Mixer::FLAG_LOOP; + } + + // Allocate a sound buffer, copy the data into it, and play + sound = (char *)malloc(size); + memcpy(sound, ptr + heOffset + 8, size); + //_vm->_mixer->stopHandle(_heSoundChannels[heChannel]); + _vm->_mixer->playRaw(&_heSoundChannels[heChannel], sound, size, rate, flags, soundID); + + _vm->setHETimer(heChannel + 4); + _heChannel[heChannel].sound = soundID; + _heChannel[heChannel].priority = priority; + _heChannel[heChannel].timer = 0; + _heChannel[heChannel].sbngBlock = (codeOffs != 0) ? 1 : 0; + _heChannel[heChannel].codeOffs = codeOffs; + memset(_heChannel[heChannel].soundVars, 0, sizeof(_heChannel[heChannel].soundVars)); + } + // Support for PCM music in 3DO versions of Humongous Entertainment games + else if (READ_UINT32(ptr) == MKID('MRAW')) { + ptr += 8 + READ_BE_UINT32(ptr+12); + if (READ_UINT32(ptr) != MKID('SDAT')) + return; + + size = READ_BE_UINT32(ptr+4) - 8; + rate = 22050; + flags = Audio::Mixer::FLAG_AUTOFREE; + + // Allocate a sound buffer, copy the data into it, and play + sound = (char *)malloc(size); + memcpy(sound, ptr + 8, size); + _vm->_mixer->stopID(_currentMusic); + _currentMusic = soundID; + _vm->_mixer->playRaw(NULL, sound, size, rate, flags, soundID); + } + else { + //if (_vm->_musicEngine) { + // _vm->_musicEngine->startSound(soundID); + //} + } + + free(mallocedPtr); +} + +void Sound::startHETalkSound(uint32 offset) { + byte *ptr; + int32 size; + + if (ConfMan.getBool("speech_mute")) + return; + + if (!_sfxFile->isOpen()) { + error("startHETalkSound: Speech file is not open"); + return; + } + + _sfxMode |= 2; + _vm->res.nukeResource(rtSound, 1); + _sfxFile->seek(offset + 4, SEEK_SET); + size = _sfxFile->readUint32BE() - 8; + _vm->res.createResource(rtSound, 1, size); + ptr = _vm->getResourceAddress(rtSound, 1); + _sfxFile->read(ptr, size); + + int channel = (_vm->VAR_SOUND_CHANNEL != 0xFF) ? _vm->VAR(_vm->VAR_SOUND_CHANNEL) : 0; + addSoundToQueue2(1, 0, channel, 0); +} + +} // End of namespace Scumm diff --git a/scumm/vars.cpp b/scumm/vars.cpp index d4e9c574e8..82a97a673b 100644 --- a/scumm/vars.cpp +++ b/scumm/vars.cpp @@ -298,6 +298,7 @@ void ScummEngine_v72he::setupScummVars() { VAR_PLATFORM = 78; // 1 is PC, 2 is Macintosh VAR_WINDOWS_VERSION = 79; // 31 is Windows 3.1, 40 is Windows 95+ VAR_CURRENT_CHARSET = 80; + VAR_SOUNDCODE_TMR = 84; VAR_KEY_STATE = 86; VAR_NUM_SOUND_CHANNELS = 88; if (_heversion >= 90) { @@ -310,6 +311,7 @@ void ScummEngine_v72he::setupScummVars() { VAR_U32_VERSION = 107; VAR_U32_ARRAY_UNK = 116; VAR_WIZ_TCOLOR = 117; + VAR_DEFAULT_SOUND_CHANNEL = 120; } if (_heversion >= 98) { VAR_SKIP_RESET_TALK_ACTOR = 125; |