aboutsummaryrefslogtreecommitdiff
path: root/scumm
diff options
context:
space:
mode:
authorTravis Howell2006-01-05 07:06:47 +0000
committerTravis Howell2006-01-05 07:06:47 +0000
commite01afb0bd4b80c387a6170ee45a74ad684038b49 (patch)
tree3807c3801aa8b0b973474dc929c7062e5ccffb47 /scumm
parentc2702891ceef6f08b3e5b6c22346119202101813 (diff)
downloadscummvm-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.cpp14
-rw-r--r--scumm/intern.h9
-rw-r--r--scumm/module.mk1
-rw-r--r--scumm/resource.cpp7
-rw-r--r--scumm/resource_v7he.cpp115
-rw-r--r--scumm/script_v100he.cpp18
-rw-r--r--scumm/script_v72he.cpp10
-rw-r--r--scumm/script_v7he.cpp4
-rw-r--r--scumm/script_v80he.cpp22
-rw-r--r--scumm/script_v90he.cpp2
-rw-r--r--scumm/scumm.cpp23
-rw-r--r--scumm/scumm.h20
-rw-r--r--scumm/sound.cpp259
-rw-r--r--scumm/sound.h28
-rw-r--r--scumm/sound_he.cpp506
-rw-r--r--scumm/vars.cpp2
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;