MOHAWK: Separate background sound handling from other sounds for Myst. Allow the scripts to change the background sound volume.

svn-id: r54953
This commit is contained in:
Bastien Bouclet 2010-12-18 13:12:56 +00:00
parent 41acf18a53
commit c870bf22d1
8 changed files with 116 additions and 56 deletions

View file

@ -215,8 +215,7 @@ bool MystConsole::Cmd_PlaySound(int argc, const char **argv) {
return true;
}
_vm->_sound->stopSound();
_vm->_sound->playSound((uint16)atoi(argv[1]));
_vm->_sound->replaceSound((uint16)atoi(argv[1]));
return false;
}

View file

@ -453,6 +453,7 @@ void MohawkEngine_Myst::changeToStack(uint16 stack) {
// Clear the resource cache and the image cache
_cache.clear();
_gfx->clearCache();
_sound->stopBackground();
}
uint16 MohawkEngine_Myst::getCardBackgroundId() {
@ -521,27 +522,17 @@ void MohawkEngine_Myst::changeToCard(uint16 card, bool updateScreen) {
soundActionVolume = _view.soundVolume;
}
// NOTE: Mixer only has 8-bit channel volume granularity,
// Myst uses 16-bit? Or is part of this balance?
soundActionVolume = (byte)(soundActionVolume / 255);
if (soundAction == kMystSoundActionContinue)
debug(2, "Continuing with current sound");
else if (soundAction == kMystSoundActionChangeVolume) {
debug(2, "Continuing with current sound, changing volume");
// TODO: Implement Volume Control..
_sound->changeBackgroundVolume(soundActionVolume);
} else if (soundAction == kMystSoundActionStop) {
debug(2, "Stopping sound");
_sound->stopSound();
_sound->stopBackground();
} else if (soundAction > 0) {
debug(2, "Playing new sound %d", soundAction);
_sound->stopSound();
// TODO: Need to keep sound handle and add function to change volume of
// looped running sound for kMystSoundActionChangeVolume type
// NOTE: All sounds are looped when played via the sound section of the
// VIEW resources.
_sound->playSound(soundAction, soundActionVolume, true);
_sound->replaceBackground(soundAction, soundActionVolume);
} else {
error("Unknown sound action %d", soundAction);
}

View file

@ -171,14 +171,20 @@ MystResourceType6::MystResourceType6(MohawkEngine_Myst *vm, Common::SeekableRead
_videoFile = convertMystVideoName(_videoFile);
// Position values require modulus 10000 to keep in sane range.
_left = rlstStream->readUint16LE() % 10000;
_top = rlstStream->readUint16LE() % 10000;
_left = rlstStream->readSint16LE() % 10000;
_top = rlstStream->readSint16LE() % 10000;
_playOnCardChange = rlstStream->readUint16LE();
_direction = rlstStream->readUint16LE();
_playBlocking = rlstStream->readUint16LE();
_loop = rlstStream->readUint16LE();
_u3 = rlstStream->readUint16LE();
// TODO: Out of bound values should clip the movie
if (_left < 0)
_left = 0;
if (_top < 0)
_top = 0;
if (_direction != 1)
warning("Type 6 _u0 != 1");
if (_u3 != 0)
@ -648,7 +654,7 @@ void MystResourceType10::updatePosition(const Common::Point &mouse) {
}
if (positionChanged && _dragSound) {
_vm->_sound->playSound(_dragSound);
_vm->_sound->replaceSound(_dragSound);
}
}

View file

@ -112,8 +112,8 @@ public:
protected:
static Common::String convertMystVideoName(Common::String name);
Common::String _videoFile;
uint16 _left;
uint16 _top;
int16 _left;
int16 _top;
uint16 _loop;
uint16 _direction; // 1 => forward, -1 => backwards
uint16 _playBlocking;

View file

@ -128,7 +128,7 @@ void MystScriptParser::setupCommonOpcodes() {
OPCODE(27, o_playSoundBlocking);
OPCODE(28, o_copyBackBufferToScreen);
OPCODE(29, o_copyImageToBackBuffer);
OPCODE(30, o_changeSound);
OPCODE(30, o_changeBackgroundSound);
OPCODE(31, o_soundPlaySwitch);
OPCODE(32, o_soundResumeBackground);
OPCODE(33, o_copyImageToScreen);
@ -558,14 +558,14 @@ void MystScriptParser::o_playSound(uint16 op, uint16 var, uint16 argc, uint16 *a
debugC(kDebugScript, "Opcode %d: playSound", op);
debugC(kDebugScript, "\tsoundId: %d", soundId);
_vm->_sound->playSound(soundId);
_vm->_sound->replaceSound(soundId);
} else
unknown(op, var, argc, argv);
}
void MystScriptParser::o_stopSoundBackground(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: stopSoundBackground", op);
//_vm->_sound->stopBackground();
_vm->_sound->stopBackground();
}
void MystScriptParser::o_playSoundBlocking(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
@ -636,7 +636,7 @@ void MystScriptParser::o_copyImageToBackBuffer(uint16 op, uint16 var, uint16 arg
// Current behaviour here and with VIEW sound block is not right as demonstrated
// by Channelwood Card 3280 (Tank Valve) and water flow sound behaviour in pipe
// on cards leading from shed...
void MystScriptParser::o_changeSound(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
void MystScriptParser::o_changeBackgroundSound(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
varUnusedCheck(op, var);
int16 *soundList = NULL;
@ -682,27 +682,20 @@ void MystScriptParser::o_changeSound(uint16 op, uint16 var, uint16 argc, uint16
}
}
// NOTE: Mixer only has 8-bit channel volume granularity,
// Myst uses 16-bit? Or is part of this balance?
soundVolume = (byte)(soundVolume / 255);
if (soundAction == kMystSoundActionContinue)
debugC(kDebugScript, "Continue current sound");
else if (soundAction == kMystSoundActionChangeVolume) {
debugC(kDebugScript, "Continue current sound, change volume");
debugC(kDebugScript, "\tVolume: %d", soundVolume);
// TODO: Implement Volume Control..
_vm->_sound->changeBackgroundVolume(soundVolume);
} else if (soundAction == kMystSoundActionStop) {
debugC(kDebugScript, "Stop sound");
_vm->_sound->stopSound();
_vm->_sound->stopBackground();
} else if (soundAction > 0) {
debugC(kDebugScript, "Play new Sound, change volume");
debugC(kDebugScript, "\tSound: %d", soundAction);
debugC(kDebugScript, "\tVolume: %d", soundVolume);
_vm->_sound->stopSound();
// TODO: Need to keep sound handle and add function to change volume of
// looped running sound for kMystSoundActionChangeVolume type
_vm->_sound->playSound(soundAction, soundVolume);
_vm->_sound->replaceBackground(soundAction, soundVolume);
} else {
debugC(kDebugScript, "Unknown");
warning("Unknown sound control value in opcode %d", op);
@ -726,13 +719,13 @@ void MystScriptParser::o_soundPlaySwitch(uint16 op, uint16 var, uint16 argc, uin
debugC(kDebugScript, "\tsoundId: %d", soundId);
if (soundId)
_vm->_sound->playSound(soundId);
_vm->_sound->replaceSound(soundId);
}
}
void MystScriptParser::o_soundResumeBackground(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
debugC(kDebugScript, "Opcode %d: soundResumeBackground", op);
//_vm->_sound->resumeBackground();
_vm->_sound->resumeBackground();
}
void MystScriptParser::o_copyImageToScreen(uint16 op, uint16 var, uint16 argc, uint16 *argv) {
@ -857,7 +850,7 @@ void MystScriptParser::o_changeStack(uint16 op, uint16 var, uint16 argc, uint16
// wrong as you're not actually linking when using this opcode. The sounds are only
// played for the full game linking.
if (!_vm->_tweaksEnabled) {
handle= _vm->_sound->playSound(soundIdLinkSrc);
handle= _vm->_sound->replaceSound(soundIdLinkSrc);
while (_vm->_mixer->isSoundHandleActive(*handle))
_vm->_system->delayMillis(10);
}
@ -872,12 +865,12 @@ void MystScriptParser::o_changeStack(uint16 op, uint16 var, uint16 argc, uint16
}
if (!_vm->_tweaksEnabled) {
handle = _vm->_sound->playSound(soundIdLinkDst);
handle = _vm->_sound->replaceSound(soundIdLinkDst);
while (_vm->_mixer->isSoundHandleActive(*handle))
_vm->_system->delayMillis(10);
}
} else {
handle = _vm->_sound->playSound(soundIdLinkSrc);
handle = _vm->_sound->replaceSound(soundIdLinkSrc);
while (_vm->_mixer->isSoundHandleActive(*handle))
_vm->_system->delayMillis(10);
@ -886,7 +879,7 @@ void MystScriptParser::o_changeStack(uint16 op, uint16 var, uint16 argc, uint16
_vm->changeToStack(_stackMap[targetStack]);
_vm->changeToCard(_startCard[targetStack], true);
handle = _vm->_sound->playSound(soundIdLinkDst);
handle = _vm->_sound->replaceSound(soundIdLinkDst);
while (_vm->_mixer->isSoundHandleActive(*handle))
_vm->_system->delayMillis(10);
}
@ -908,7 +901,7 @@ void MystScriptParser::o_changeCardPlaySoundDirectional(uint16 op, uint16 var, u
debugC(kDebugScript, "\tanimated update data size: %d", dataSize);
if (soundId)
_vm->_sound->playSound(soundId);
_vm->_sound->replaceSound(soundId);
_vm->changeToCard(cardId, false);
@ -927,7 +920,7 @@ void MystScriptParser::o_directionalUpdatePlaySound(uint16 op, uint16 var, uint1
debugC(kDebugScript, "\tanimated update data size: %d", dataSize);
if (soundId)
_vm->_sound->playSound(soundId);
_vm->_sound->replaceSound(soundId);
animatedUpdate(dataSize, &argv[3], delayBetweenSteps);
}

View file

@ -103,7 +103,7 @@ public:
DECLARE_OPCODE(o_playSoundBlocking);
DECLARE_OPCODE(o_copyBackBufferToScreen);
DECLARE_OPCODE(o_copyImageToBackBuffer);
DECLARE_OPCODE(o_changeSound);
DECLARE_OPCODE(o_changeBackgroundSound);
DECLARE_OPCODE(o_soundPlaySwitch);
DECLARE_OPCODE(o_copyImageToScreen);
DECLARE_OPCODE(o_soundResumeBackground);

View file

@ -70,9 +70,7 @@ void Sound::initMidi() {
_midiParser->setTimerRate(_midiDriver->getBaseTempo());
}
Audio::SoundHandle *Sound::playSound(uint16 id, byte volume, bool loop) {
debug (0, "Playing sound %d", id);
Audio::AudioStream *Sound::makeAudioStream(uint16 id) {
Audio::AudioStream *audStream = NULL;
switch (_vm->getGameType()) {
@ -103,6 +101,14 @@ Audio::SoundHandle *Sound::playSound(uint16 id, byte volume, bool loop) {
audStream = makeMohawkWaveStream(_vm->getResource(ID_TWAV, id));
}
return audStream;
}
Audio::SoundHandle *Sound::playSound(uint16 id, byte volume, bool loop) {
debug (0, "Playing sound %d", id);
Audio::AudioStream *audStream = makeAudioStream(id);
if (audStream) {
SndHandle *handle = getHandle();
handle->type = kUsedHandle;
@ -127,12 +133,11 @@ Audio::SoundHandle *Sound::replaceSound(uint16 id, byte volume, bool loop) {
Common::String name = _vm->getResourceName(ID_MSND, id);
// Check if sound is already playing
for (uint32 i = 0; i < _handles.size(); i++) {
if (_vm->_mixer->isSoundHandleActive(_handles[i].handle)
&& name.equals(_vm->getResourceName(ID_MSND, _handles[i].id))) {
for (uint32 i = 0; i < _handles.size(); i++)
if (_handles[i].type == kUsedHandle
&& _vm->_mixer->isSoundHandleActive(_handles[i].handle)
&& name.equals(_vm->getResourceName(ID_MSND, _handles[i].id)))
return &_handles[i].handle;
}
}
stopSound();
return playSound(id, volume, loop);
@ -552,4 +557,66 @@ bool Sound::isPlaying(uint16 id) {
return false;
}
Audio::SoundHandle *Sound::replaceBackground(uint16 id, uint16 volume) {
debug (0, "Replacing background %d", id);
//TODO: The original engine does fading
Common::String name = _vm->getResourceName(ID_MSND, id);
// Check if sound is already playing
for (uint32 i = 0; i < _handles.size(); i++)
if (_handles[i].type == kBackgroundHandle
&& _vm->_mixer->isSoundHandleActive(_handles[i].handle)
&& name.equals(_vm->getResourceName(ID_MSND, _handles[i].id)))
return &_handles[i].handle;
// Stop old background sound
stopBackground();
// Play new sound
Audio::AudioStream *audStream = makeAudioStream(id);
if (audStream) {
SndHandle *handle = getHandle();
handle->type = kBackgroundHandle;
handle->id = id;
// Set the stream to loop
audStream = Audio::makeLoopingAudioStream((Audio::RewindableAudioStream *)audStream, 0);
_vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &handle->handle, audStream, -1, volume >> 8);
return &handle->handle;
}
return NULL;
}
void Sound::stopBackground() {
for (uint32 i = 0; i < _handles.size(); i++)
if (_handles[i].type == kBackgroundHandle) {
_vm->_mixer->stopHandle(_handles[i].handle);
_handles[i].type = kFreeHandle;
_handles[i].id = 0;
}
}
void Sound::pauseBackground() {
for (uint32 i = 0; i < _handles.size(); i++)
if (_handles[i].type == kBackgroundHandle)
_vm->_mixer->pauseHandle(_handles[i].handle, true);
}
void Sound::resumeBackground() {
for (uint32 i = 0; i < _handles.size(); i++)
if (_handles[i].type == kBackgroundHandle)
_vm->_mixer->pauseHandle(_handles[i].handle, false);
}
void Sound::changeBackgroundVolume(uint16 vol) {
for (uint32 i = 0; i < _handles.size(); i++)
if (_handles[i].type == kBackgroundHandle)
_vm->_mixer->setChannelVolume(_handles[i].handle, vol >> 8);
}
} // End of namespace Mohawk

View file

@ -59,7 +59,8 @@ struct SLSTRecord {
enum SndHandleType {
kFreeHandle,
kUsedHandle
kUsedHandle,
kBackgroundHandle
};
struct SndHandle {
@ -129,10 +130,12 @@ public:
void resumeSound();
bool isPlaying(uint16 id);
void pauseBackground() {} //TODO: implement
void replaceBackground(uint16 id, uint16 volume) {}
void resumeBackground() {}
void stopBackground() {}
// Myst background sound functions
Audio::SoundHandle *replaceBackground(uint16 id, uint16 volume = 0xFFFF);
void pauseBackground();
void resumeBackground();
void stopBackground();
void changeBackgroundVolume(uint16 vol);
// Riven-specific
void playSLST(uint16 index, uint16 card);
@ -153,6 +156,7 @@ private:
Common::Array<SndHandle> _handles;
SndHandle *getHandle();
Audio::AudioStream *makeAudioStream(uint16 id);
// Riven-specific
void playSLSTSound(uint16 index, bool fade, bool loop, uint16 volume, int16 balance);