From 4b13982116828453efd4a445328d455d9b820149 Mon Sep 17 00:00:00 2001 From: Benjamin Haisch Date: Tue, 14 Oct 2008 21:12:52 +0000 Subject: TOLTECS: Implemented preliminary sound playback; some stuff is still missing (correct volumes etc.) --- engines/toltecs/module.mk | 1 + engines/toltecs/movie.cpp | 4 +- engines/toltecs/screen.cpp | 12 ++- engines/toltecs/screen.h | 3 +- engines/toltecs/script.cpp | 19 +++-- engines/toltecs/sound.cpp | 178 ++++++++++++++++++++++++++++++++++++++++++++ engines/toltecs/sound.h | 80 ++++++++++++++++++++ engines/toltecs/toltecs.cpp | 19 +++-- engines/toltecs/toltecs.h | 2 + 9 files changed, 304 insertions(+), 14 deletions(-) create mode 100644 engines/toltecs/sound.cpp create mode 100644 engines/toltecs/sound.h (limited to 'engines') diff --git a/engines/toltecs/module.mk b/engines/toltecs/module.mk index 49d4e19f65..1d9d50ce85 100644 --- a/engines/toltecs/module.mk +++ b/engines/toltecs/module.mk @@ -14,6 +14,7 @@ MODULE_OBJS = \ screen.o \ script.o \ segmap.o \ + sound.o \ sprite.o diff --git a/engines/toltecs/movie.cpp b/engines/toltecs/movie.cpp index b5665aaf47..6e59882efc 100644 --- a/engines/toltecs/movie.cpp +++ b/engines/toltecs/movie.cpp @@ -54,7 +54,7 @@ void MoviePlayer::playMovie(uint resIndex) { memset(moviePalette, 0, sizeof(moviePalette)); - _vm->_screen->finishTextDrawItems(); + _vm->_screen->finishTalkTextItems(); _vm->_screen->clearSprites(); _vm->_arc->openResource(resIndex); @@ -154,7 +154,7 @@ void MoviePlayer::playMovie(uint resIndex) { break; case 8: // stop subtitles _vm->_script->getSlotData(subtitleSlot)[0] = 0xFF; - _vm->_screen->finishTextDrawItems(); + _vm->_screen->finishTalkTextItems(); break; default: error("Unknown chunk type %d at %08X", chunkType, _vm->_arc->pos() - 5 - chunkSize); diff --git a/engines/toltecs/screen.cpp b/engines/toltecs/screen.cpp index 8951c1eb6a..cde0138be3 100644 --- a/engines/toltecs/screen.cpp +++ b/engines/toltecs/screen.cpp @@ -496,12 +496,22 @@ int16 Screen::getTalkTextDuration() { return _talkTextItems[_talkTextItemNum].duration; } -void Screen::finishTextDrawItems() { +void Screen::finishTalkTextItems() { for (int16 i = 0; i <= _talkTextItemNum; i++) { _talkTextItems[i].duration = 0; } } +void Screen::keepTalkTextItemsAlive() { + for (int16 i = 0; i <= _talkTextItemNum; i++) { + TalkTextItem *item = &_talkTextItems[i]; + if (item->fontNum == -1) + item->duration = 0; + else if (item->duration > 0) + item->duration = 2; + } +} + void Screen::registerFont(uint fontIndex, uint resIndex) { _fontResIndexArray[fontIndex] = resIndex; } diff --git a/engines/toltecs/screen.h b/engines/toltecs/screen.h index 752d5a4c7c..ff27bb2ba5 100644 --- a/engines/toltecs/screen.h +++ b/engines/toltecs/screen.h @@ -197,7 +197,8 @@ public: void addTalkTextRect(Font &font, int16 x, int16 &y, int16 length, int16 width, TalkTextItem *item); void addTalkTextItemsToRenderQueue(); int16 getTalkTextDuration(); - void finishTextDrawItems(); + void finishTalkTextItems(); + void keepTalkTextItemsAlive(); // Font/text void registerFont(uint fontIndex, uint resIndex); diff --git a/engines/toltecs/script.cpp b/engines/toltecs/script.cpp index 13cc0ea5e0..4f50ca265b 100644 --- a/engines/toltecs/script.cpp +++ b/engines/toltecs/script.cpp @@ -41,6 +41,7 @@ #include "toltecs/script.h" #include "toltecs/screen.h" #include "toltecs/segmap.h" +#include "toltecs/sound.h" namespace Toltecs { @@ -445,7 +446,7 @@ void ScriptInterpreter::execKernelOpcode(uint16 kernelOpcode) { debug(0, "o2_updateScreen()"); - // TODO? updateSamples(); + _vm->_sound->updateSpeech(); _vm->_screen->updateShakeScreen(); @@ -592,6 +593,7 @@ void ScriptInterpreter::execKernelOpcode(uint16 kernelOpcode) { { debug(0, "o2_loadScene(resIndex: %d; flag: %d)", arg16(4), arg8(3)); if (arg8(3) == 0) { + _vm->_sound->stopSpeech(); _vm->loadScene(arg16(4)); } else { _vm->_screen->loadMouseCursor(arg16(4)); @@ -845,7 +847,10 @@ void ScriptInterpreter::execKernelOpcode(uint16 kernelOpcode) { case 54:// TODO { - debug(0, "o2_playSound2(%d, %d, %d)", arg16(7), arg16(5), arg16(3)); + //debug(0, "o2_playSound2(%d, %d, %d)", arg16(7), arg16(5), arg16(3)); + + _vm->_sound->playSound(arg16(3), arg16(5), arg16(7)); + break; } @@ -878,15 +883,13 @@ void ScriptInterpreter::execKernelOpcode(uint16 kernelOpcode) { case 59:// TODO { - debug(0, "o2_precacheResources(%04X)", arg16(3)); + debug(0, "o2_precacheSprites(%04X)", arg16(3)); break; } case 60:// TODO { debug(0, "o2_precacheSounds1(%04X)", arg16(3)); - // CHECKME - _vm->_screen->clearSprites(); break; } @@ -896,6 +899,12 @@ void ScriptInterpreter::execKernelOpcode(uint16 kernelOpcode) { break; } + case 62:// TODO - this opcode was never executed while I completed the game + { + debug(0, "o2_precacheSounds2(%04X)", arg16(3)); + break; + } + case 63:// ok { _regs.sp = _savedSp; diff --git a/engines/toltecs/sound.cpp b/engines/toltecs/sound.cpp new file mode 100644 index 0000000000..a3e7a76fe8 --- /dev/null +++ b/engines/toltecs/sound.cpp @@ -0,0 +1,178 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 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. + * + * + */ + +#include "common/events.h" +#include "common/keyboard.h" +#include "common/file.h" +#include "common/savefile.h" +#include "common/config-manager.h" + +#include "base/plugins.h" +#include "base/version.h" + +#include "graphics/cursorman.h" + +#include "sound/mixer.h" + +#include "toltecs/toltecs.h" +#include "toltecs/palette.h" +#include "toltecs/render.h" +#include "toltecs/resource.h" +#include "toltecs/screen.h" +#include "toltecs/script.h" +#include "toltecs/segmap.h" +#include "toltecs/sound.h" + +namespace Toltecs { + +Sound::Sound(ToltecsEngine *vm) : _vm(vm) { + for (int i = 0; i < 4; i++) { + channels[i].type = 0; + channels[i].resIndex = -1; + } +} + +Sound::~Sound() { +} + +void Sound::playSpeech(int16 resIndex) { + + // TODO + + debug(0, "playSpeech(%d)", resIndex); + + internalPlaySound(resIndex, -3, 50 /*TODO*/, 64); + +} + +void Sound::playSound(int16 resIndex, int16 type, int16 volume) { + + // TODO: Use the right volumes + + debug(0, "playSound(%d, %d, %d)", resIndex, type, volume); + + if (volume == -1 || type == -2) { + if (type == -1) { + internalPlaySound(resIndex, type, 50 /*TODO*/, 64); + } else { + internalPlaySound(resIndex, type, 100 /*TODO*/, 64); + } + } else { + internalPlaySound(resIndex, type, 100 /*TODO*/, 64); + } + +} + +void Sound::playSoundAtPos(int16 resIndex, int16 x, int16 y) { + + // TODO: Everything + + debug(0, "playSoundAtPos(%d, %d, %d)", resIndex, x, y); + + internalPlaySound(resIndex, 1, 50, 64); + +} + +void Sound::internalPlaySound(int16 resIndex, int16 type, int16 volume, int16 panning) { + + // TODO + + if (resIndex == -1) { + // Stop all sounds + _vm->_mixer->stopAll(); + _vm->_screen->keepTalkTextItemsAlive(); + for (int i = 0; i < 4; i++) { + channels[i].type = 0; + channels[i].resIndex = -1; + } + } else if (type == -2) { + // Stop sounds with specified resIndex + for (int i = 0; i < 4; i++) { + if (channels[i].resIndex == resIndex) { + _vm->_mixer->stopHandle(channels[i].handle); + channels[i].type = 0; + channels[i].resIndex = -1; + } + } + } else { + + if (type == -3) { + // Stop sounds with type == -3 and play new sound + stopSpeech(); + } + + // Play new sound in empty channel + + int freeChannel = -1; + for (int i = 0; i < 4; i++) { + if (channels[i].type == 0) { + freeChannel = i; + break; + } + } + + // If all channels are in use no new sound will be played + if (freeChannel >= 0) { + + byte *soundData = _vm->_res->load(resIndex); + uint32 soundSize = _vm->_res->getCurItemSize(); + + byte flags = Audio::Mixer::FLAG_UNSIGNED; + // Sounds with type == -1 loop + if (type == -1) + flags |= Audio::Mixer::FLAG_LOOP; + Audio::AudioStream *stream = Audio::makeLinearInputStream(soundData, soundSize, 22050, flags, 0, 0); + + channels[freeChannel].type = type; + channels[freeChannel].resIndex = resIndex; + + _vm->_mixer->playInputStream(Audio::Mixer::kPlainSoundType/*TODO*/, &channels[freeChannel].handle, + stream, -1, volume, panning); + + } + + } + +} + +void Sound::updateSpeech() { + for (int i = 0; i < 4; i++) { + if (channels[i].type == -3 && _vm->_mixer->isSoundHandleActive(channels[i].handle)) { + _vm->_screen->keepTalkTextItemsAlive(); + break; + } + } +} + +void Sound::stopSpeech() { + for (int i = 0; i < 4; i++) { + if (channels[i].type == -3) { + _vm->_mixer->stopHandle(channels[i].handle); + _vm->_screen->keepTalkTextItemsAlive(); + channels[i].type = 0; + channels[i].resIndex = -1; + } + } +} + +} // End of namespace Toltecs diff --git a/engines/toltecs/sound.h b/engines/toltecs/sound.h new file mode 100644 index 0000000000..02f7a96eb3 --- /dev/null +++ b/engines/toltecs/sound.h @@ -0,0 +1,80 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 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. + * + * + */ + +#ifndef TOLTECS_SOUND_H +#define TOLTECS_SOUND_H + +#include "common/scummsys.h" +#include "common/endian.h" +#include "common/util.h" +#include "common/file.h" +#include "common/savefile.h" +#include "common/system.h" +#include "common/hash-str.h" +#include "common/events.h" +#include "common/keyboard.h" +#include "common/array.h" + +#include "sound/audiostream.h" +#include "sound/mixer.h" +#include "sound/voc.h" +#include "sound/audiocd.h" + +#include "engines/engine.h" + +#include "toltecs/toltecs.h" + +namespace Toltecs { + +// 0x1219 + +struct SoundChannel { + int16 resIndex; + int16 type; + Audio::SoundHandle handle; +}; + +class Sound { +public: + Sound(ToltecsEngine *vm); + ~Sound(); + + void playSpeech(int16 resIndex); + void playSound(int16 resIndex, int16 type, int16 volume); + void playSoundAtPos(int16 resIndex, int16 x, int16 y); + void updateSpeech(); + void stopSpeech(); + +protected: + ToltecsEngine *_vm; + + SoundChannel channels[4]; + + void internalPlaySound(int16 resIndex, int16 type, int16 volume, int16 panning); + +}; + + +} // End of namespace Toltecs + +#endif /* TOLTECS_SOUND_H */ diff --git a/engines/toltecs/toltecs.cpp b/engines/toltecs/toltecs.cpp index a5c1caf89f..3aa160ac72 100644 --- a/engines/toltecs/toltecs.cpp +++ b/engines/toltecs/toltecs.cpp @@ -47,6 +47,7 @@ #include "toltecs/script.h" #include "toltecs/screen.h" #include "toltecs/segmap.h" +#include "toltecs/sound.h" #include "toltecs/microtiles.h" namespace Toltecs { @@ -134,6 +135,8 @@ int ToltecsEngine::go() { _segmap = new SegmentMap(this); _moviePlayer = new MoviePlayer(this); _menuSystem = new MenuSystem(this); + + _sound = new Sound(this); _system->showMouse(true); @@ -141,7 +144,10 @@ int ToltecsEngine::go() { #ifdef TEST_MOVIE _screen->registerFont(0, 0x0D); _screen->registerFont(1, 0x0E); - _moviePlayer->playMovie(0x000012D8); + //_moviePlayer->playMovie(0x000012D8); + //_moviePlayer->playMovie(0x000012D7); + //_moviePlayer->playMovie(0x); + _moviePlayer->playMovie(0x000012E0); #endif //#define TEST_MENU @@ -151,7 +157,7 @@ int ToltecsEngine::go() { _screen->loadMouseCursor(12); _palette->loadAddPalette(9, 224); _palette->setDeltaPalette(_palette->getMainPalette(), 7, 0, 31, 224); - _screen->finishTextDrawItems(); + _screen->finishTalkTextItems(); _screen->clearSprites(); while (1) { updateInput(); @@ -174,6 +180,8 @@ int ToltecsEngine::go() { delete _segmap; delete _moviePlayer; delete _menuSystem; + + delete _sound; return 0; } @@ -335,7 +343,7 @@ void ToltecsEngine::setGuiHeight(int16 guiHeight) { void ToltecsEngine::setCamera(int16 x, int16 y) { - _screen->finishTextDrawItems(); + _screen->finishTalkTextItems(); /* // TODO: Fix checks; sometimes cameraY ended up being negative @@ -401,14 +409,14 @@ void ToltecsEngine::updateCamera() { //dirtyFullRefresh = -1; _cameraX = _newCameraX; _screen->_fullRefresh = true; - _screen->finishTextDrawItems(); + _screen->finishTalkTextItems(); } if (_cameraY != _newCameraY) { //dirtyFullRefresh = -1; _cameraY = _newCameraY; _screen->_fullRefresh = true; - _screen->finishTextDrawItems(); + _screen->finishTalkTextItems(); } debug(0, "ToltecsEngine::updateCamera() _cameraX = %d; _cameraY = %d", _cameraX, _cameraY); @@ -438,6 +446,7 @@ void ToltecsEngine::talk(int16 slotIndex, int16 slotOffset) { if (_doSpeech) { int16 resIndex = READ_LE_UINT16(scanData + 1); debug(0, "ToltecsEngine::talk() playSound(resIndex: %d)", resIndex); + _sound->playSpeech(resIndex); } if (_doText) { _screen->updateTalkText(slotIndex, slotOffset); diff --git a/engines/toltecs/toltecs.h b/engines/toltecs/toltecs.h index e0d64bda36..b9d08c3d59 100644 --- a/engines/toltecs/toltecs.h +++ b/engines/toltecs/toltecs.h @@ -59,6 +59,7 @@ class ResourceCache; class ScriptInterpreter; class Screen; class SegmentMap; +class Sound; class ToltecsEngine : public ::Engine { Common::KeyState _keyPressed; @@ -112,6 +113,7 @@ public: ScriptInterpreter *_script; Screen *_screen; SegmentMap *_segmap; + Sound *_sound; uint _sceneResIndex; int16 _sceneWidth, _sceneHeight; -- cgit v1.2.3