Add 8 sound channel support for HE games

-Allows sound looping to work

Added support for WAVE format musuc used in later HE100 games.

svn-id: r17372
This commit is contained in:
Travis Howell 2005-04-04 11:43:25 +00:00
parent d08068dff1
commit f230fe65e8
9 changed files with 88 additions and 49 deletions

View File

@ -1676,7 +1676,7 @@ void ScummEngine::akos_processQueue() {
if (_features & GF_DIGI_IMUSE)
_imuseDigital->startSfx(param_1, 63);
else
_sound->addSoundToQueue(param_1);
_sound->addSoundToQueue(param_1, 0, -1, 0);
}
break;
case 4:

View File

@ -311,7 +311,7 @@ void ScummEngine_v100he::setupOpcodes() {
OPCODE(o6_isScriptRunning),
OPCODE(o90_sin),
/* D8 */
OPCODE(o72_getSoundElapsedTimeOfSound),
OPCODE(o72_getSoundElapsedTime),
OPCODE(o6_isSoundRunning),
OPCODE(o80_getSoundVar),
OPCODE(o100_getSpriteInfo),

View File

@ -156,7 +156,7 @@ void ScummEngine_v72he::setupOpcodes() {
/* 58 */
OPCODE(o72_getTimer),
OPCODE(o72_setTimer),
OPCODE(o72_getSoundElapsedTimeOfSound),
OPCODE(o72_getSoundElapsedTime),
OPCODE(o6_wordArrayDec),
/* 5C */
OPCODE(o6_if),
@ -562,6 +562,7 @@ void ScummEngine_v72he::decodeScriptString(byte *dst, bool scriptString) {
switch(chr) {
case 'b':
// byte
error("decodeScriptString: byte unhandled");
break;
case 'c':
*dst++ = args[val--];
@ -574,6 +575,7 @@ void ScummEngine_v72he::decodeScriptString(byte *dst, bool scriptString) {
break;
case 'x':
// hexadecimal
error("decodeScriptString: hexadecimal unhandled");
break;
default:
error("decodeScriptString: Unknown type %d", chr);
@ -811,10 +813,10 @@ void ScummEngine_v72he::o72_setTimer() {
}
}
void ScummEngine_v72he::o72_getSoundElapsedTimeOfSound() {
void ScummEngine_v72he::o72_getSoundElapsedTime() {
int snd = pop();
push(_mixer->getSoundElapsedTimeOfSoundID(snd) * 10);
debug(1,"o72_getSoundElapsedTimeOfSound (%d)", snd);
push(_sound->getSoundElapsedTime(snd) * 10);
debug(1,"o72_getSoundElapsedTime (%d)", snd);
}
void ScummEngine_v72he::o72_startScript() {

View File

@ -153,7 +153,7 @@ void ScummEngine_v90he::setupOpcodes() {
/* 58 */
OPCODE(o72_getTimer),
OPCODE(o72_setTimer),
OPCODE(o72_getSoundElapsedTimeOfSound),
OPCODE(o72_getSoundElapsedTime),
OPCODE(o6_wordArrayDec),
/* 5C */
OPCODE(o6_if),
@ -746,7 +746,7 @@ void ScummEngine_v90he::o90_getSpriteInfo() {
byte subOp = fetchScriptByte();
subOp -= 30;
debug(0,"o90_getSpriteInfo (%d)", subOp);
debug(1,"o90_getSpriteInfo (%d)", subOp);
switch (subOp) {
case 0:
spriteId = pop();
@ -1001,7 +1001,7 @@ void ScummEngine_v90he::o90_setSpriteInfo() {
byte subOp = fetchScriptByte();
subOp -= 34;
debug(0,"o90_setSpriteInfo (%d)", subOp);
debug(1,"o90_setSpriteInfo (%d)", subOp);
switch (subOp) {
case 0:
args[0] = pop();
@ -1332,7 +1332,7 @@ void ScummEngine_v90he::o90_getSpriteGroupInfo() {
byte subOp = fetchScriptByte();
debug(0,"o90_getSpriteGroupInfo (%d)", subOp);
debug(1,"o90_getSpriteGroupInfo (%d)", subOp);
switch (subOp) {
case 8: // HE 99+
spriteGroupId = pop();
@ -1414,7 +1414,7 @@ void ScummEngine_v90he::o90_setSpriteGroupInfo() {
byte subOp = fetchScriptByte();
subOp -= 37;
debug(0,"o90_setSpriteGroupInfo (%d)", subOp);
debug(1,"o90_setSpriteGroupInfo (%d)", subOp);
switch (subOp) {
case 0:
type = pop() - 1;

View File

@ -33,12 +33,14 @@
#include "common/util.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/flac.h"
#include "sound/wave.h"
namespace Scumm {
@ -159,6 +161,7 @@ void Sound::setOverrideFreq(int freq) {
}
void Sound::playSound(int soundID, int heOffset, int heChannel, int heFlags) {
debug(5,"playSound: soundID %d heOffset %d heChannel %d heFlags %d\n", soundID, heOffset, heChannel, heFlags);
byte *mallocedPtr = NULL;
byte *ptr;
char *sound;
@ -166,6 +169,9 @@ void Sound::playSound(int soundID, int heOffset, int heChannel, int heFlags) {
int rate;
byte flags = SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE;
if (heChannel == -1) {
heChannel = 1;
}
if (_vm->_heversion >= 70 && soundID > _vm->_numSounds) {
debug(1, "playSound #%d", soundID);
@ -218,9 +224,7 @@ void Sound::playSound(int soundID, int heOffset, int heChannel, int heFlags) {
size = musicFile.readUint32LE();
if (music_offs > total_size || (size + music_offs > total_size) || size < 0) {
warning("playSound: Invalid music offset (%d) in music %d", soundID);
musicFile.close();
return;
error("playSound: Invalid music offset (%d) in music %d", soundID);
}
musicFile.seek(music_offs, SEEK_SET);
@ -231,7 +235,7 @@ void Sound::playSound(int soundID, int heOffset, int heChannel, int heFlags) {
_vm->_mixer->stopID(_currentMusic);
_currentMusic = soundID;
if (_vm->_heversion == 70) {
_vm->_mixer->playRaw(NULL, ptr, size, 11025, flags, soundID);
_vm->_mixer->playRaw(&_heSoundChannels[heChannel], ptr, size, 11025, flags, soundID);
return;
}
@ -266,7 +270,18 @@ void Sound::playSound(int soundID, int heOffset, int heChannel, int heFlags) {
}
// Support for later Backyard sports games sounds
else if (READ_UINT32(ptr) == MKID('RIFF')) {
// TODO: Play WAV, with set sound ID
size = READ_BE_UINT32(ptr + 4);
Common::MemoryReadStream stream(ptr, size);
if (!loadWAVFromStream(stream, size, rate, flags)) {
warning("playSound: Not a valid WAV file");
return;
}
// 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 Putt-Putt sounds - very hackish, too 8-)
else if (READ_UINT32(ptr) == MKID('DIGI') || READ_UINT32(ptr) == MKID('TALK') || READ_UINT32(ptr) == MKID('HSHD')) {
@ -280,14 +295,9 @@ void Sound::playSound(int soundID, int heOffset, int heChannel, int heFlags) {
if (READ_UINT32(ptr) == MKID('SBNG')) {
ptr += READ_BE_UINT32(ptr + 4);
debug(2, "playSound: Skipped SBNG block");
}
if (READ_UINT32(ptr) != MKID('SDAT')) {
warning("playSound: Invalid sound %d", soundID);
return; // abort
}
assert(READ_UINT32(ptr) == MKID('SDAT'));
size = READ_BE_UINT32(ptr+4) - 8;
if (heOffset < 0 || heOffset > size) {
warning("playSound: Invalid sound offset (%d) in sound %d", heOffset, soundID);
@ -301,13 +311,15 @@ void Sound::playSound(int soundID, int heOffset, int heChannel, int heFlags) {
_overrideFreq = 0;
}
// TODO: Set sound channel based on heChannel
// Set sound looping based on heFlags
if (heFlags & 1) {
_vm->_mixer->stopHandle(_heSoundChannels[heChannel]);
flags |= SoundMixer::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(NULL, sound, size, rate, flags, soundID);
_vm->_mixer->playRaw(&_heSoundChannels[heChannel], sound, size, rate, flags, soundID);
}
else if (READ_UINT32(ptr) == MKID('MRAW')) {
// pcm music in 3DO humongous games
@ -666,26 +678,26 @@ void Sound::startTalkSound(uint32 offset, uint32 b, int mode, SoundHandle *handl
}
if (_vm->_features & GF_HUMONGOUS) {
int extra = 0;
_sfxMode |= mode;
// Skip the TALK (8) and HSHD (24) chunks
_sfxFile->seek(offset + 32, SEEK_SET);
if (_sfxFile->readUint32LE() == TO_LE_32(MKID('SBNG'))) {
debug(2, "startTalkSound: Skipped SBNG block");
// Skip the SBNG, so we end up at the SDAT chunk
extra = _sfxFile->readUint32BE();
_sfxFile->seek(extra - 4, SEEK_CUR);
size = _sfxFile->readUint32BE() - 8;
} else {
_sfxFile->seek(+4, SEEK_CUR);
size = b - 40;
size = _sfxFile->readUint32BE() - 4;
_sfxFile->seek(size, SEEK_CUR);
}
size = _sfxFile->readUint32BE() - 8;
sound = (byte *)malloc(size);
_sfxFile->read(sound, size);
_vm->_mixer->playRaw(handle, sound, size, 11000, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
if (_vm->_heversion >= 70) {
int channel = _vm->VAR(_vm->VAR_SOUND_CHANNEL);
_vm->_mixer->playRaw(&_heSoundChannels[channel], sound, size, 11000, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE, 1);
} else {
_vm->_mixer->playRaw(handle, sound, size, 11000, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
}
return;
}
@ -780,7 +792,9 @@ void Sound::startTalkSound(uint32 offset, uint32 b, int mode, SoundHandle *handl
void Sound::stopTalkSound() {
if (_sfxMode & 2) {
if (_vm->_imuseDigital) {
_vm->_imuseDigital->stopSound(kTalkSoundID);
_vm->_mixer->stopID(kTalkSoundID);
} else if (_vm->_heversion >= 70) {
_vm->_imuseDigital->stopSound(1);
} else {
_vm->_mixer->stopHandle(_talkChannelHandle);
}
@ -806,6 +820,15 @@ bool Sound::isMouthSyncOff(uint pos) {
}
int Sound::getSoundElapsedTime(int sound) const {
if (sound >= 10000) {
int channel = sound - 10000;
return _vm->_mixer->getSoundElapsedTime(_heSoundChannels[channel]);
} else {
return _vm->_mixer->getSoundElapsedTimeOfSoundID(sound);
}
}
int Sound::isSoundRunning(int sound) const {
if (_vm->_imuseDigital)
return (_vm->_imuseDigital->getSoundStatus(sound) != 0);
@ -824,12 +847,9 @@ int Sound::isSoundRunning(int sound) const {
else if (_vm->_imuse)
return (_vm->_imuse->getSoundStatus(sound));
} else if (sound >= 10000) {
// TODO report sound ID on channel
// channel = sound - 10000
if (sound == 10000)
return (_vm->_mixer->isSoundIDActive(_currentMusic) ? _currentMusic : 0);
else if (sound == 10001)
return _vm->_mixer->isSoundHandleActive(_talkChannelHandle);
int channel = sound - 10000;
if (_vm->_mixer->isSoundHandleActive(_heSoundChannels[channel]))
return _vm->_mixer->getActiveChannelSoundID(_heSoundChannels[channel]);
else
return 0;
}
@ -915,10 +935,8 @@ void Sound::stopSound(int sound) {
else if (_vm->_imuse)
_vm->_imuse->stopSound(_vm->_imuse->getSoundStatus(-1));
} else if ( sound >= 10000) {
// TODO: Stop sound channel
// channel = sound - 10000
if (sound == 10000)
_vm->_mixer->stopID(_currentMusic);
int channel = sound - 10000;
_vm->_mixer->stopHandle(_heSoundChannels[channel]);
}
}

View File

@ -85,6 +85,7 @@ protected:
int16 _currentMusic;
public:
SoundHandle _talkChannelHandle; // Handle of mixer channel actor is talking on
SoundHandle _heSoundChannels[8];
bool _soundsPaused;
byte _sfxMode;
@ -100,6 +101,7 @@ public:
void startTalkSound(uint32 offset, uint32 b, int mode, SoundHandle *handle = NULL);
void stopTalkSound();
bool isMouthSyncOff(uint pos);
int getSoundElapsedTime(int sound) const;
int isSoundRunning(int sound) const;
bool isSoundInUse(int sound) const;
void stopSound(int sound);

View File

@ -916,12 +916,13 @@ uint8 *ScummEngine_v72he::drawWizImage(int resNum, int state, int x1, int y1, in
cw = width;
ch = height;
} else {
VirtScreen *pvs = &virtscr[kMainVirtScreen];
if (dstPtr) {
cw = READ_LE_UINT32(dstPtr + 0x4);
ch = READ_LE_UINT32(dstPtr + 0x8);
assert(cw <= pvs->w && ch <= pvs->h);
dst = dstPtr;
} else {
VirtScreen *pvs = &virtscr[kMainVirtScreen];
if (flags & kWIFMarkBufferDirty) {
dst = pvs->getPixels(0, pvs->topline);
} else {

View File

@ -367,6 +367,14 @@ bool SoundMixer::isSoundIDActive(int id) {
return false;
}
int SoundMixer::getActiveChannelSoundID(SoundHandle handle) {
Common::StackLock lock(_mutex);
const int index = handle._val % NUM_CHANNELS;
if (_channels[index])
return _channels[index]->getId();
return 0;
}
bool SoundMixer::isSoundHandleActive(SoundHandle handle) {
Common::StackLock lock(_mutex);
const int index = handle._val % NUM_CHANNELS;

View File

@ -204,10 +204,18 @@ public:
*/
bool isSoundIDActive(int id);
/**
* Get the sound ID of handle sound
*
* @param handle sound to query
* @return sound ID if active
*/
int getActiveChannelSoundID(SoundHandle handle);
/**
* Check if a sound with the given hANDLE is active.
*
* @param handle the sound to query
* @param handle sound to query
* @return true if the sound is active
*/
bool isSoundHandleActive(SoundHandle handle);