From 1bbad356ef66a72951a58be7f1c328ba3c6d501f Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Mon, 29 Jan 2007 18:15:14 +0000 Subject: - adds support for FM-Towns SFX (thanks to Florian Kagerer for his source) - gets rid of GameFlags::hasAudioCD svn-id: r25258 --- engines/kyra/kyra.cpp | 21 ++- engines/kyra/kyra.h | 16 +-- engines/kyra/kyra2.cpp | 2 +- engines/kyra/module.mk | 1 + engines/kyra/plugin.cpp | 16 +-- engines/kyra/resource.h | 2 + engines/kyra/saveload.cpp | 23 ++- engines/kyra/scene.cpp | 43 +++--- engines/kyra/seqplayer.cpp | 4 +- engines/kyra/sequences_v1.cpp | 25 +++- engines/kyra/sound.cpp | 143 +++---------------- engines/kyra/sound.h | 46 ++++-- engines/kyra/sound_adlib.cpp | 15 +- engines/kyra/sound_towns.cpp | 321 ++++++++++++++++++++++++++++++++++++++++++ engines/kyra/staticres.cpp | 32 +++-- 15 files changed, 497 insertions(+), 213 deletions(-) create mode 100644 engines/kyra/sound_towns.cpp diff --git a/engines/kyra/kyra.cpp b/engines/kyra/kyra.cpp index 216033f2d1..fd8eeba512 100644 --- a/engines/kyra/kyra.cpp +++ b/engines/kyra/kyra.cpp @@ -146,10 +146,10 @@ int KyraEngine::init() { // TODO: We should play the native Kyra 2 Adlib music, but until that // is support, we'll use the automagic MIDI -> Adlib converter. - if (_flags.hasAudioCD) { + if (_flags.platform == Common::kPlatformFMTowns) { // no sfx enabled for CD audio music atm // later on here should be a usage of MixedSoundDriver - _sound = new SoundCD(this, _mixer); + _sound = new SoundTowns(this, _mixer); } else if (midiDriver == MD_ADLIB && _flags.gameID == GI_KYRA1) { _sound = new SoundAdlibPC(this, _mixer); assert(_sound); @@ -182,11 +182,7 @@ int KyraEngine::init() { assert(_sound); } } - if (!_sound->init()) { - error("Couldn't init sound"); - } - _sound->setVolume(255); - + _res = new Resource(this); assert(_res); _sprites = new Sprites(this, _system); @@ -207,6 +203,17 @@ int KyraEngine::init() { initStaticResource(); + if (!_sound->init()) + error("Couldn't init sound"); + + if (_flags.platform == Common::kPlatformFMTowns) + _sound->setSoundFileList(_soundFilesTowns, _soundFilesTownsCount); + else + _sound->setSoundFileList(_soundFiles, _soundFilesCount); + + _sound->setVolume(255); + _sound->loadSoundFile(0); + _paletteChanged = 1; _currentCharacter = 0; _characterList = new Character[11]; diff --git a/engines/kyra/kyra.h b/engines/kyra/kyra.h index bfe406b65b..5c54a34c41 100644 --- a/engines/kyra/kyra.h +++ b/engines/kyra/kyra.h @@ -51,7 +51,6 @@ struct GameFlags { Common::Platform platform; bool isDemo; bool useAltShapeHeader; // alternative shape header (uses 2 bytes more, those are unused though) - bool hasAudioCD; bool isTalkie; byte gameID; }; @@ -238,10 +237,6 @@ class KyraEngine : public Engine { friend class Debugger; friend class ScreenAnimator; public: - enum { - MUSIC_INTRO = 0 - }; - KyraEngine(OSystem *system, const GameFlags &flags); virtual ~KyraEngine(); @@ -805,7 +800,7 @@ protected: uint8 _configVoice; int _curMusicTheme; - int _newMusicTheme; + int _curSfxFile; int16 _lastMusicCommand; Resource *_res; @@ -974,9 +969,12 @@ protected: const uint8 * const*_specialPalettes; Timer _timers[34]; - uint32 _timerNextRun; - static const char *_musicFiles[]; - static const int _musicFilesCount; + uint32 _timerNextRun; + + static const char *_soundFiles[]; + static const int _soundFilesCount; + static const char *_soundFilesTowns[]; + static const int _soundFilesTownsCount; static const int8 _charXPosTable[]; static const int8 _addXPosTable[]; diff --git a/engines/kyra/kyra2.cpp b/engines/kyra/kyra2.cpp index 8c6abcaa53..d0c1a5c38e 100644 --- a/engines/kyra/kyra2.cpp +++ b/engines/kyra/kyra2.cpp @@ -67,7 +67,7 @@ int KyraEngine_v2::init() { } int KyraEngine_v2::go() { - _sound->loadMusicFile("K2INTRO"); + //_sound->loadMusicFile("K2INTRO"); // Temporary measure to work around the fact that there's // several WSA files with identical names in different PAK files. _res->unloadPakFile("OUTFARM.PAK"); diff --git a/engines/kyra/module.mk b/engines/kyra/module.mk index 1dd27f676d..f8159dd78b 100644 --- a/engines/kyra/module.mk +++ b/engines/kyra/module.mk @@ -20,6 +20,7 @@ MODULE_OBJS := \ sequences_v2.o \ sound_adlib.o \ sound_digital.o \ + sound_towns.o \ sound.o \ sprites.o \ staticres.o \ diff --git a/engines/kyra/plugin.cpp b/engines/kyra/plugin.cpp index b009706109..8384bb7298 100644 --- a/engines/kyra/plugin.cpp +++ b/engines/kyra/plugin.cpp @@ -36,16 +36,16 @@ struct KYRAGameDescription { namespace { -#define FLAGS(x, y, z, w, id) { Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, w, id } +#define FLAGS(x, y, z, id) { Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, id } -#define KYRA1_FLOPPY_FLAGS FLAGS(false, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_TOWNS_FLAGS FLAGS(false, true, true, false, Kyra::GI_KYRA1) -#define KYRA1_CD_FLAGS FLAGS(false, true, false, true, Kyra::GI_KYRA1) -#define KYRA1_DEMO_FLAGS FLAGS(true, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_FLOPPY_FLAGS FLAGS(false, false, false, Kyra::GI_KYRA1) +#define KYRA1_TOWNS_FLAGS FLAGS(false, true, false, Kyra::GI_KYRA1) +#define KYRA1_CD_FLAGS FLAGS(false, true, true, Kyra::GI_KYRA1) +#define KYRA1_DEMO_FLAGS FLAGS(true, false, false, Kyra::GI_KYRA1) -#define KYRA2_UNK_FLAGS FLAGS(false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_UNK_FLAGS FLAGS(false, false, false, Kyra::GI_KYRA2) -#define KYRA3_CD_FLAGS FLAGS(false, false, false, true, Kyra::GI_KYRA3) +#define KYRA3_CD_FLAGS FLAGS(false, false, true, Kyra::GI_KYRA3) const KYRAGameDescription adGameDescs[] = { { { "kyra1", 0, AD_ENTRY1("GEMCUT.EMC", "3c244298395520bb62b5edfe41688879"), Common::EN_ANY, Common::kPlatformPC }, KYRA1_FLOPPY_FLAGS }, @@ -68,7 +68,7 @@ const KYRAGameDescription adGameDescs[] = { { { "kyra2", 0, AD_ENTRY1("FATE.PAK", "28cbad1c5bf06b2d3825ae57d760d032"), Common::UNK_LANG, Common::kPlatformPC }, KYRA2_UNK_FLAGS }, // check this! (cd version?) { { "kyra3", 0, AD_ENTRY1("ONETIME.PAK", "3833ff312757b8e6147f464cca0a6587"), Common::UNK_LANG, Common::kPlatformPC }, KYRA3_CD_FLAGS }, - { { NULL, NULL, {NULL, 0, NULL, 0}, Common::UNK_LANG, Common::kPlatformUnknown }, FLAGS(0, 0, 0, 0, 0) } + { { NULL, NULL, {NULL, 0, NULL, 0}, Common::UNK_LANG, Common::kPlatformUnknown }, FLAGS(0, 0, 0, 0) } }; const PlainGameDescriptor gameList[] = { diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h index 6d0f725184..0fb99fd253 100644 --- a/engines/kyra/resource.h +++ b/engines/kyra/resource.h @@ -198,6 +198,8 @@ enum kKyraResources { kGUIStrings, kConfigStrings, + kKyra1TownsSFXTable, + kMaxResIDs }; diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp index 45d34de88e..747091d328 100644 --- a/engines/kyra/saveload.cpp +++ b/engines/kyra/saveload.cpp @@ -29,14 +29,16 @@ #include "kyra/animator.h" #include "kyra/screen.h" #include "kyra/resource.h" +#include "kyra/sound.h" -#define CURRENT_VERSION 6 +#define CURRENT_VERSION 7 // TODO: our current savefiles still use the old // flag system to check the version, we should // change that some day, but for now it works #define GF_FLOPPY (1 << 0) #define GF_TALKIE (1 << 1) +#define GF_FMTOWNS (1 << 2) namespace Kyra { void KyraEngine::loadGame(const char *fileName) { @@ -78,11 +80,15 @@ void KyraEngine::loadGame(const char *fileName) { warning("Can not load cdrom savefile for this (non cdrom) gameversion"); delete in; return; + } else if ((flags & GF_FMTOWNS) && !(_flags.platform == Common::kPlatformFMTowns)) { + warning("can not load FM-Towns savefile for this (non FM-Towns) gameversion"); + delete in; + return; } } else { warning("Make sure your savefile was from this version! (too old savefile version to detect that)"); } - + snd_playSoundEffect(0x0A); snd_playWanderScoreViaMap(0, 1); @@ -198,6 +204,10 @@ void KyraEngine::loadGame(const char *fileName) { in->readByte(); // Voice } + if (version >= 7) { + _curSfxFile = in->readByte(); + } + _screen->_disableScreen = true; loadMainScreen(8); @@ -265,7 +275,12 @@ void KyraEngine::saveGame(const char *fileName, const char *saveName) { out->writeUint32BE(MKID_BE('KYRA')); out->writeUint32BE(CURRENT_VERSION); out->write(saveName, 31); - out->writeUint32BE((_flags.isTalkie ? GF_TALKIE : GF_FLOPPY)); + if (_flags.isTalkie) + out->writeUint32BE(GF_TALKIE); + else if (_flags.platform == Common::kPlatformFMTowns) + out->writeUint32BE(GF_FMTOWNS); + else + out->writeUint32BE(GF_FLOPPY); for (int i = 0; i < 11; i++) { out->writeUint16BE(_characterList[i].sceneId); @@ -335,6 +350,8 @@ void KyraEngine::saveGame(const char *fileName, const char *saveName) { out->writeSint16BE(_lastMusicCommand); + out->writeByte(_curSfxFile); + out->flush(); // check for errors diff --git a/engines/kyra/scene.cpp b/engines/kyra/scene.cpp index 05d2c98614..e879e98186 100644 --- a/engines/kyra/scene.cpp +++ b/engines/kyra/scene.cpp @@ -43,25 +43,30 @@ void KyraEngine::enterNewScene(int sceneId, int facing, int unk1, int unk2, int _handleInput = false; _abortWalkFlag = false; _abortWalkFlag2 = false; - // just used for cd audio version, it should only load the sfx music file there - /*if (_currentCharacter->sceneId == 7 && sceneId == 24) { - _newMusicTheme = 3; - } else if (_currentCharacter->sceneId == 25 && sceneId == 109) { - _newMusicTheme = 4; - } else if (_currentCharacter->sceneId == 120 && sceneId == 37) { - _newMusicTheme = 5; - } else if (_currentCharacter->sceneId == 52 && sceneId == 199) { - _newMusicTheme = 6; - } else if (_currentCharacter->sceneId == 37 && sceneId == 120) { - _newMusicTheme = 4; - } else if (_currentCharacter->sceneId == 109 && sceneId == 25) { - _newMusicTheme = 3; - } else if (_currentCharacter->sceneId == 24 && sceneId == 7) { - _newMusicTheme = 2; - } - if (_newMusicTheme != _curMusicTheme) { - snd_playTheme(_newMusicTheme); - }*/ + // just used for fm towns version, it should only load the sfx music file there + if (_flags.platform == Common::kPlatformFMTowns) { + int newSfxFile = -1; + if (_currentCharacter->sceneId == 7 && sceneId == 24) { + newSfxFile = 2; + } else if (_currentCharacter->sceneId == 25 && sceneId == 109) { + newSfxFile = 3; + } else if (_currentCharacter->sceneId == 120 && sceneId == 37) { + newSfxFile = 4; + } else if (_currentCharacter->sceneId == 52 && sceneId == 199) { + newSfxFile = 5; + } else if (_currentCharacter->sceneId == 37 && sceneId == 120) { + newSfxFile = 3; + } else if (_currentCharacter->sceneId == 109 && sceneId == 25) { + newSfxFile = 2; + } else if (_currentCharacter->sceneId == 24 && sceneId == 7) { + newSfxFile = 1; + } + + if (newSfxFile != -1) { + _curSfxFile = newSfxFile; + _sound->loadSoundFile(_curSfxFile); + } + } switch (_currentCharacter->sceneId) { case 1: diff --git a/engines/kyra/seqplayer.cpp b/engines/kyra/seqplayer.cpp index 699175d758..5f7f020e1b 100644 --- a/engines/kyra/seqplayer.cpp +++ b/engines/kyra/seqplayer.cpp @@ -400,7 +400,9 @@ void SeqPlayer::s1_playEffect() { void SeqPlayer::s1_playTrack() { uint8 msg = *_seqData++; - if (_vm->gameFlags().hasAudioCD) { + // HACK: as long as we don't have extracted static data from the fm-towns + // version in kyra.dat we use this to get music working + if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { if (msg <= 1) _vm->snd_playWanderScoreViaMap(msg, 0); else diff --git a/engines/kyra/sequences_v1.cpp b/engines/kyra/sequences_v1.cpp index ee8f0e6e8b..541393889f 100644 --- a/engines/kyra/sequences_v1.cpp +++ b/engines/kyra/sequences_v1.cpp @@ -38,7 +38,7 @@ namespace Kyra { void KyraEngine::seq_demo() { debugC(9, kDebugLevelMain, "KyraEngine::seq_demo()"); - snd_playTheme(MUSIC_INTRO, 2); + snd_playTheme(0, 2); _screen->loadBitmap("START.CPS", 7, 7, _screen->_currentPalette); _screen->copyRegion(0, 0, 0, 0, 320, 200, 6, 0); @@ -109,10 +109,8 @@ void KyraEngine::seq_intro() { _seq->setCopyViewOffs(true); _screen->setFont(Screen::FID_8_FNT); - if (_flags.hasAudioCD) - snd_playWanderScoreViaMap(57, 0); - else - snd_playTheme(MUSIC_INTRO, 2); + if (_flags.platform != Common::kPlatformFMTowns) + snd_playTheme(0, 2); _text->setTalkCoords(144); for (int i = 0; i < ARRAYSIZE(introProcTable) && !seq_skipSequence(); ++i) { (this->*introProcTable[i])(); @@ -129,6 +127,18 @@ void KyraEngine::seq_intro() { void KyraEngine::seq_introLogos() { debugC(9, kDebugLevelMain, "KyraEngine::seq_introLogos()"); + + if (_flags.platform == Common::kPlatformFMTowns) { + _screen->loadBitmap("LOGO.CPS", 3, 3, _screen->_currentPalette); + _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0); + _screen->updateScreen(); + _screen->fadeFromBlack(); + delay(90 * _tickLength); + _screen->fadeToBlack(); + if (!_abortIntroFlag) + snd_playWanderScoreViaMap(57, 0); + } + _screen->clearPage(0); _screen->loadBitmap("TOP.CPS", 7, 7, NULL); _screen->loadBitmap("BOTTOM.CPS", 5, 5, _screen->_currentPalette); @@ -1069,8 +1079,9 @@ void KyraEngine::seq_playCredits() { _screen->clearCurPage(); _screen->setTextColorMap(colorMap); _screen->_charWidth = -1; - // we don't need that one for midi or adlib - if (_flags.hasAudioCD) + + // we only need this for the fm-towns version + if (_flags.platform == Common::kPlatformFMTowns) snd_playWanderScoreViaMap(53, 1); uint8 *buffer = 0; diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp index e0e41e69ae..2a5182d6d8 100644 --- a/engines/kyra/sound.cpp +++ b/engines/kyra/sound.cpp @@ -28,7 +28,6 @@ #include "sound/mixer.h" #include "sound/voc.h" #include "sound/audiostream.h" -#include "sound/audiocd.h" #include "sound/mp3.h" #include "sound/vorbis.h" @@ -38,7 +37,7 @@ namespace Kyra { Sound::Sound(KyraEngine *engine, Audio::Mixer *mixer) : _engine(engine), _mixer(mixer), _currentVocFile(0), _vocHandle(), _compressHandle(), - _musicEnabled(true), _sfxEnabled(true) { + _musicEnabled(true), _sfxEnabled(true), _soundFileList(0), _soundFileListSize(0) { } Sound::~Sound() { @@ -125,7 +124,7 @@ SoundMidiPC::~SoundMidiPC() { Common::StackLock lock(_mutex); - _driver->setTimerCallback(NULL, NULL); + _driver->setTimerCallback(0, 0); close(); } @@ -246,9 +245,9 @@ void SoundMidiPC::metaEvent(byte type, byte *data, uint16 length) { } } -void SoundMidiPC::loadMusicFile(const char *file) { +void SoundMidiPC::loadSoundFile(uint file) { char filename[25]; - sprintf(filename, "%s.%s", file, _useC55 ? "C55" : "XMI"); + sprintf(filename, "%s.%s", soundFilename(file), _useC55 ? "C55" : "XMI"); uint32 size; uint8 *data = (_engine->resource())->fileData(filename, &size); @@ -283,9 +282,9 @@ void SoundMidiPC::playMusic(uint8 *data, uint32 size) { _parser->setTempo(0); } -void SoundMidiPC::loadSoundEffectFile(const char *file) { +void SoundMidiPC::loadSoundEffectFile(uint file) { char filename[25]; - sprintf(filename, "%s.%s", file, _useC55 ? "C55" : "XMI"); + sprintf(filename, "%s.%s", soundFilename(file), _useC55 ? "C55" : "XMI"); uint32 size; uint8 *data = (_engine->resource())->fileData(filename, &size); @@ -434,118 +433,6 @@ void SoundMidiPC::beginFadeOut() { #pragma mark - -SoundCD::~SoundCD() { - AudioCD.stop(); -} - -bool SoundCD::init() { - _engine->checkCD(); - return true; -} - -void SoundCD::process() { - AudioCD.updateCD(); -} - -namespace { - -struct CDTrackTable { - uint32 unk1; - bool loop; - int track; -}; - -} // end of anonymous namespace - -void SoundCD::playTrack(uint8 track) { - if (track < 2) - return; - track -= 2; - - static CDTrackTable tTable[] = { - { 0x04000, 1, 0 }, - { 0x05480, 1, 6 }, - { 0x05E70, 0, 1 }, - { 0x06D90, 1, 3 }, - { 0x072C0, 0, -1 }, - { 0x075F0, 1, -1 }, - { 0x07880, 1, -1 }, - { 0x089C0, 0, -1 }, - { 0x09080, 0, -1 }, - { 0x091D0, 1, 4 }, - { 0x0A880, 1, 5 }, - { 0x0AF50, 0, -1 }, - { 0x0B1A0, 1, -1 }, - { 0x0B870, 0, -1 }, - { 0x0BCF0, 1, -1 }, - { 0x0C5D0, 1, 7 }, - { 0x0D3E0, 1, 8 }, - { 0x0e7b0, 1, 2 }, - { 0x0edc0, 0, -1 }, - { 0x0eef0, 1, 9 }, - { 0x10540, 1, 10 }, - { 0x10d80, 0, -1 }, - { 0x10E30, 0, -1 }, - { 0x10FC0, 0, -1 }, - { 0x11310, 1, -1 }, - { 0x11A20, 1, -1 }, - { 0x12380, 0, -1 }, - { 0x12540, 1, -1 }, - { 0x12730, 1, -1 }, - { 0x12A90, 1, 11 }, - { 0x134D0, 0, -1 }, - { 0x00000, 0, -1 }, - { 0x13770, 0, -1 }, - { 0x00000, 0, -1 }, - { 0x00000, 0, -1 }, - { 0x00000, 0, -1 }, - { 0x00000, 0, -1 }, - { 0x14710, 1, 12 }, - { 0x15DF0, 1, 13 }, - { 0x16030, 1, 14 }, - { 0x17030, 0, -1 }, - { 0x17650, 0, -1 }, - { 0x134D0, 0, -1 }, - { 0x178E0, 1, -1 }, - { 0x18200, 0, -1 }, - { 0x18320, 0, -1 }, - { 0x184A0, 0, -1 }, - { 0x18BB0, 0, -1 }, - { 0x19040, 0, 19 }, - { 0x19B50, 0, 20 }, - { 0x17650, 0, -1 }, - { 0x1A730, 1, 21 }, - { 0x00000, 0, -1 }, - { 0x12380, 0, -1 }, - { 0x1B810, 0, -1 }, - { 0x1BA50, 0, 15 }, - { 0x1C190, 0, 16 }, - { 0x1CA50, 0, 17 }, - { 0x1D100, 0, 18 }, - }; - - int trackNum = tTable[track].track; - bool loop = tTable[track].loop; - // could be that if the trackNum is -1, the music should be stopped - // instead of letting the old music play on - if (trackNum == -1 || trackNum == _lastTrack) - return; - - haltTrack(); - AudioCD.play(trackNum+1, loop ? -1 : 1, 0, 0); - AudioCD.updateCD(); - - _lastTrack = trackNum; -} - -void SoundCD::haltTrack() { - _lastTrack = -1; - AudioCD.stop(); - AudioCD.updateCD(); -} - -#pragma mark - - bool KyraEngine::speechEnabled() { return _flags.isTalkie && (_configVoice == 1 || _configVoice == 2); } @@ -556,17 +443,21 @@ bool KyraEngine::textEnabled() { void KyraEngine::snd_playTheme(int file, int track) { debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine::snd_playTheme(%d)", file); - assert(file < _musicFilesCount); - _curMusicTheme = _newMusicTheme = file; - _sound->loadMusicFile(_musicFiles[file]); + _curMusicTheme = file; + _sound->loadSoundFile(_curMusicTheme); _sound->playTrack(track); } void KyraEngine::snd_playSoundEffect(int track) { debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine::snd_playSoundEffect(%d)", track); - if (_flags.hasAudioCD && track == 49) { - snd_playWanderScoreViaMap(56, 1); - return; + if (_flags.platform == Common::kPlatformFMTowns) { + if (track == 49) { + snd_playWanderScoreViaMap(56, 1); + return; + } else if (track == 10) { + // I don't know what's supposed to happen here, but calling playSoundEffect will lead to crash + return; + } } _sound->playSoundEffect(track); } @@ -576,7 +467,7 @@ void KyraEngine::snd_playWanderScoreViaMap(int command, int restart) { if (restart) _lastMusicCommand = -1; - if (_flags.hasAudioCD) { + if (_flags.platform == Common::kPlatformFMTowns) { if (command == 1) { _sound->beginFadeOut(); } else if (command >= 35 && command <= 38) { diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h index 07ef0a59f0..fdb243f67e 100644 --- a/engines/kyra/sound.h +++ b/engines/kyra/sound.h @@ -76,7 +76,8 @@ public: virtual void setVolume(int volume) = 0; virtual int getVolume() = 0; - virtual void loadMusicFile(const char *file) = 0; + virtual void setSoundFileList(const char * const *list, uint s) { _soundFileList = list; _soundFileListSize = s; } + virtual void loadSoundFile(uint file) = 0; virtual void playTrack(uint8 track) = 0; virtual void haltTrack() = 0; @@ -96,13 +97,16 @@ public: void voiceStop(); protected: + const char *soundFilename(uint file) { return (file < _soundFileListSize) ? _soundFileList[file] : ""; } bool _musicEnabled; bool _sfxEnabled; KyraEngine *_engine; Audio::Mixer *_mixer; - private: + const char * const *_soundFileList; + uint _soundFileListSize; + Audio::AudioStream *_currentVocFile; Audio::SoundHandle _vocHandle; Common::File _compressHandle; @@ -128,7 +132,7 @@ public: void setVolume(int volume); int getVolume(); - void loadMusicFile(const char *file); + void loadSoundFile(uint file); void playTrack(uint8 track); void haltTrack(); @@ -139,8 +143,6 @@ public: private: void play(uint8 track); - void loadSoundFile(const char *file); - void unk1(); void unk2(); @@ -149,7 +151,7 @@ private: uint8 _trackEntries[120]; uint8 *_soundDataPtr; int _sfxPlayingSound; - Common::String _soundFileLoaded; + uint _soundFileLoaded; uint8 _sfxPriority; uint8 _sfxFourthByteOfSong; @@ -171,7 +173,7 @@ public: void setVolume(int volume); int getVolume() { return _volume; } - void loadMusicFile(const char *file); + void loadSoundFile(uint file); void playTrack(uint8 track); void haltTrack(); @@ -202,7 +204,7 @@ public: private: void playMusic(uint8 *data, uint32 size); void stopMusic(); - void loadSoundEffectFile(const char *file); + void loadSoundEffectFile(uint file); void loadSoundEffectFile(uint8 *data, uint32 size); void stopSoundEffect(); @@ -230,10 +232,10 @@ private: Common::Mutex _mutex; }; -class SoundCD : public Sound { +class SoundTowns : public Sound { public: - SoundCD(KyraEngine *engine, Audio::Mixer *mixer) : Sound(engine, mixer), _lastTrack(-1) {} - ~SoundCD(); + SoundTowns(KyraEngine *engine, Audio::Mixer *mixer); + ~SoundTowns(); bool init(); void process(); @@ -241,16 +243,31 @@ public: void setVolume(int) { /* TODO */ } int getVolume() { return 255; /* TODO */ } - void loadMusicFile(const char *) {} + void loadSoundFile(uint file); void playTrack(uint8 track); void haltTrack(); - void playSoundEffect(uint8) {} + void playSoundEffect(uint8); void beginFadeOut() { /* TODO */ } private: + void stopSoundEffect(); + void setPitch(uint8 *&data, uint32 &size, int8 sourcePitch, int8 targetPitch); + int _lastTrack; + Audio::AudioStream *_currentSFX; + Audio::SoundHandle _sfxHandle; + int _currentTrackTable; + bool _sfxIsPlaying; + uint _sfxFileIndex; + uint8 *_sfxFileData; + uint8 *_sfxPlaybackBuffer; + + static const char *_sfxFiles[]; + static const int _sfxFilenum; + static const uint8 _sfxBTTable[256]; + const uint8 *_sfxWDTable; }; class MixedSoundDriver : public Sound { @@ -264,7 +281,8 @@ public: void setVolume(int volume) { _music->setVolume(volume); _sfx->setVolume(volume); } int getVolume() { return _music->getVolume(); } - void loadMusicFile(const char *file) { _music->loadMusicFile(file); _sfx->loadMusicFile(file); } + void setSoundFileList(const char * const*list, uint s) { _music->setSoundFileList(list, s); _sfx->setSoundFileList(list, s); } + void loadSoundFile(uint file) { _music->loadSoundFile(file); _sfx->loadSoundFile(file); } void playTrack(uint8 track) { _music->playTrack(track); } void haltTrack() { _music->haltTrack(); } diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp index d0cabc8bd8..c308d1ba54 100644 --- a/engines/kyra/sound_adlib.cpp +++ b/engines/kyra/sound_adlib.cpp @@ -2213,7 +2213,7 @@ SoundAdlibPC::SoundAdlibPC(KyraEngine *engine, Audio::Mixer *mixer) assert(_driver); _sfxPlayingSound = -1; - _soundFileLoaded = ""; + _soundFileLoaded = (uint)-1; _soundTriggers = _kyra1SoundTriggers; _numSoundTriggers = _kyra1NumSoundTriggers; @@ -2252,10 +2252,6 @@ int SoundAdlibPC::getVolume() { return 0; } -void SoundAdlibPC::loadMusicFile(const char *file) { - loadSoundFile(file); -} - void SoundAdlibPC::playTrack(uint8 track) { if (_musicEnabled) { // WORKAROUND: There is a bug in the Kyra 1 "Pool of Sorrow" @@ -2263,7 +2259,7 @@ void SoundAdlibPC::playTrack(uint8 track) { // sync for each loop. To avoid that, we declare that all four // of the song channels have to jump "in sync". - if (track == 4 && _soundFileLoaded == "KYRA1B") + if (track == 4 && scumm_stricmp(soundFilename(_soundFileLoaded), "KYRA1B") == 0) _driver->setSyncJumpMask(0x000F); else _driver->setSyncJumpMask(0); @@ -2330,18 +2326,17 @@ void SoundAdlibPC::beginFadeOut() { playSoundEffect(1); } -void SoundAdlibPC::loadSoundFile(const char *file) { +void SoundAdlibPC::loadSoundFile(uint file) { if (_soundFileLoaded == file) return; - if (_soundDataPtr) { + if (_soundDataPtr) haltTrack(); - } uint8 *file_data = 0; uint32 file_size = 0; char filename[25]; - sprintf(filename, "%s.ADL", file); + sprintf(filename, "%s.ADL", soundFilename(file)); file_data = _engine->resource()->fileData(filename, &file_size); if (!file_data) { diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp new file mode 100644 index 0000000000..6e7ec74807 --- /dev/null +++ b/engines/kyra/sound_towns.cpp @@ -0,0 +1,321 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2007 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" +#include "common/system.h" +#include "kyra/resource.h" +#include "kyra/sound.h" +#include "kyra/screen.h" + +#include "sound/audiocd.h" +#include "sound/audiostream.h" + +namespace Kyra { + +SoundTowns::SoundTowns(KyraEngine *engine, Audio::Mixer *mixer) : Sound(engine, mixer), _lastTrack(-1), + _currentSFX(0), _sfxFileData(0), _sfxFileIndex((uint)-1), _sfxPlaybackBuffer(0), _sfxWDTable(0) { +} + +SoundTowns::~SoundTowns() { + AudioCD.stop(); + delete [] _sfxFileData; + stopSoundEffect(); +} + +bool SoundTowns::init() { + _engine->checkCD(); + int unused = 0; + _sfxWDTable = _engine->staticres()->loadRawData(kKyra1TownsSFXTable, unused); + return true; +} + +void SoundTowns::process() { + AudioCD.updateCD(); +} + +namespace { + +struct CDTrackTable { + uint32 fileOffset; + bool loop; + int track; +}; + +} // end of anonymous namespace + +void SoundTowns::playTrack(uint8 track) { + if (track < 2) + return; + track -= 2; + + static const CDTrackTable tTable[] = { + { 0x04000, 1, 0 }, + { 0x05480, 1, 6 }, + { 0x05E70, 0, 1 }, + { 0x06D90, 1, 3 }, + { 0x072C0, 0, -1 }, + { 0x075F0, 1, -1 }, + { 0x07880, 1, -1 }, + { 0x089C0, 0, -1 }, + { 0x09080, 0, -1 }, + { 0x091D0, 1, 4 }, + { 0x0A880, 1, 5 }, + { 0x0AF50, 0, -1 }, + { 0x0B1A0, 1, -1 }, + { 0x0B870, 0, -1 }, + { 0x0BCF0, 1, -1 }, + { 0x0C5D0, 1, 7 }, + { 0x0D3E0, 1, 8 }, + { 0x0e7b0, 1, 2 }, + { 0x0edc0, 0, -1 }, + { 0x0eef0, 1, 9 }, + { 0x10540, 1, 10 }, + { 0x10d80, 0, -1 }, + { 0x10E30, 0, -1 }, + { 0x10FC0, 0, -1 }, + { 0x11310, 1, -1 }, + { 0x11A20, 1, -1 }, + { 0x12380, 0, -1 }, + { 0x12540, 1, -1 }, + { 0x12730, 1, -1 }, + { 0x12A90, 1, 11 }, + { 0x134D0, 0, -1 }, + { 0x00000, 0, -1 }, + { 0x13770, 0, -1 }, + { 0x00000, 0, -1 }, + { 0x00000, 0, -1 }, + { 0x00000, 0, -1 }, + { 0x00000, 0, -1 }, + { 0x14710, 1, 12 }, + { 0x15DF0, 1, 13 }, + { 0x16030, 1, 14 }, + { 0x17030, 0, -1 }, + { 0x17650, 0, -1 }, + { 0x134D0, 0, -1 }, + { 0x178E0, 1, -1 }, + { 0x18200, 0, -1 }, + { 0x18320, 0, -1 }, + { 0x184A0, 0, -1 }, + { 0x18BB0, 0, -1 }, + { 0x19040, 0, 19 }, + { 0x19B50, 0, 20 }, + { 0x17650, 0, -1 }, + { 0x1A730, 1, 21 }, + { 0x00000, 0, -1 }, + { 0x12380, 0, -1 }, + { 0x1B810, 0, -1 }, + { 0x1BA50, 0, 15 }, + { 0x1C190, 0, 16 }, + { 0x1CA50, 0, 17 }, + { 0x1D100, 0, 18 }, + }; + + int trackNum = tTable[track].track; + bool loop = tTable[track].loop; + // could be that if the trackNum is -1, the music should be stopped + // instead of letting the old music play on + if (trackNum == -1 || trackNum == _lastTrack) + return; + + haltTrack(); + AudioCD.play(trackNum+1, loop ? -1 : 1, 0, 0); + AudioCD.updateCD(); + + _lastTrack = trackNum; +} + +void SoundTowns::haltTrack() { + _lastTrack = -1; + AudioCD.stop(); + AudioCD.updateCD(); +} + +void SoundTowns::loadSoundFile(uint file) { + if (_sfxFileIndex == file) + return; + _sfxFileIndex = file; + delete [] _sfxFileData; + _sfxFileData = _engine->resource()->fileData(soundFilename(file), 0); +} + +void SoundTowns::stopSoundEffect() { + _sfxIsPlaying = false; + _mixer->stopHandle(_sfxHandle); +} + +void SoundTowns::playSoundEffect(uint8 track) { + if (!_sfxEnabled || !_sfxFileData) + return; + + _sfxIsPlaying = true; + + uint8 pitch = 0x3c; + if (_sfxFileIndex == 5) { + if (track == 0x10) { + pitch = 0x3e; + track = 0x0f; + } else if (track == 0x11) { + pitch = 0x40; + track = 0x0f; + } else if (track == 0x12) { + pitch = 0x41; + track = 0x0f; + } + } + + uint8 * fileBody = _sfxFileData + 0x01b8; + int32 offset = (int32)READ_LE_UINT32(_sfxFileData + (track - 0x0b) * 4); + if (offset == -1) + return; + + struct SfxHeader { + uint32 id; + uint32 inBufferSize; + uint32 unused1; + uint32 outBufferSize; + uint32 unused2; + uint32 unused3; + uint32 unknown1; + uint32 pitch; + } *sfxHeader = (SfxHeader*)(fileBody + offset); + + uint32 sfxHeaderID = TO_LE_32(sfxHeader->id); + uint32 sfxHeaderInBufferSize = TO_LE_32(sfxHeader->inBufferSize); + uint32 sfxHeaderOutBufferSize = TO_LE_32(sfxHeader->outBufferSize); + sfxHeader->pitch = TO_LE_32(sfxHeader->pitch); + + uint32 playbackBufferSize = (sfxHeaderID == 1) ? sfxHeaderInBufferSize : sfxHeaderOutBufferSize; + + stopSoundEffect(); + _sfxPlaybackBuffer = new uint8[playbackBufferSize]; + memset(_sfxPlaybackBuffer, 0x80, playbackBufferSize); + + uint8 * sfxBody = ((uint8*)sfxHeader) + 0x20; + + if (!sfxHeaderID) { + memcpy(_sfxPlaybackBuffer, sfxBody, playbackBufferSize); + } else if (sfxHeaderID == 1) { + Screen::decodeFrame4(sfxBody, _sfxPlaybackBuffer, playbackBufferSize); + } else if (_sfxWDTable) { + uint8 * tgt = _sfxPlaybackBuffer; + uint32 sfx_BtTable_Offset = 0; + uint32 sfx_WdTable_Offset = 0; + uint32 sfx_WdTable_Number = 5; + + for (uint32 i = 0; i < sfxHeaderInBufferSize; i++) { + sfx_WdTable_Offset = (sfx_WdTable_Number * 3 << 9) + sfxBody[i] * 6; + sfx_WdTable_Number = READ_LE_UINT16(_sfxWDTable + sfx_WdTable_Offset); + + sfx_BtTable_Offset += (int16)READ_LE_UINT16(_sfxWDTable + sfx_WdTable_Offset + 2); + *tgt++ = _sfxBTTable[((sfx_BtTable_Offset >> 2) & 0xff)]; + + sfx_BtTable_Offset += (int16)READ_LE_UINT16(_sfxWDTable + sfx_WdTable_Offset + 4); + *tgt++ = _sfxBTTable[((sfx_BtTable_Offset >> 2) & 0xff)]; + } + } + + for (uint32 i = 0; i < playbackBufferSize; i++) { + if (_sfxPlaybackBuffer[i] < 0x80) + _sfxPlaybackBuffer[i] = 0x80 - _sfxPlaybackBuffer[i]; + } + + playbackBufferSize -= 0x20; + setPitch(_sfxPlaybackBuffer, playbackBufferSize, sfxHeader->pitch, pitch); + + _currentSFX = Audio::makeLinearInputStream(0x2b11, + Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_LITTLE_ENDIAN | Audio::Mixer::FLAG_AUTOFREE, + _sfxPlaybackBuffer, playbackBufferSize, 0, 0); + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, _currentSFX); +} + +void SoundTowns::setPitch(uint8 *&data, uint32 &size, int8 sourcePitch, int8 targetPitch) { + if (sourcePitch == targetPitch) + return; + + if (sourcePitch < 0) + sourcePitch = 0; + if (sourcePitch > 119) + sourcePitch = 119; + if (targetPitch < 0) + targetPitch = 0; + if (targetPitch > 119) + targetPitch = 119; + + static const float noteFrq[] = { + 0004.13, 0004.40, 0004.64, 0004.95, 0005.16, 0005.50, 0005.80, 0006.19, 0006.60, 0006.86, + 0007.43, 0007.73, 0008.25, 0008.80, 0009.28, 0009.90, 0010.31, 0011.00, 0011.60, 0012.38, + 0013.20, 0013.75, 0014.85, 0015.47, 0016.50, 0017.60, 0018.56, 0019.80, 0020.63, 0022.00, + 0023.21, 0024.75, 0026.40, 0027.50, 0029.70, 0030.94, 0033.00, 0035.20, 0037.16, 0039.60, + 0041.25, 0044.00, 0046.41, 0049.50, 0052.80, 0055.00, 0059.40, 0061.88, 0066.00, 0070.40, + 0074.25, 0079.20, 0082.50, 0088.00, 0092.83, 0099.00, 0105.60, 0110.00, 0118.80, 0123.75, + 0132.00, 0140.80, 0148.50, 0158.40, 0165.00, 0176.00, 0185.65, 0198.00, 0211.20, 0220.00, + 0237.60, 0247.50, 0264.00, 0281.60, 0297.00, 0316.80, 0330.00, 0352.00, 0371.30, 0396.00, + 0422.40, 0440.00, 0475.20, 0495.00, 0528.00, 0563.20, 0594.00, 0633.60, 0660.00, 0704.00, + 0742.60, 0792.00, 0844.80, 0880.00, 0950.40, 0990.00, 1056.00, 1126.40, 1188.00, 1267.20, + 1320.00, 1408.00, 1485.20, 1584.00, 1689.60, 1760.00, 1900.80, 1980.00, 2112.00, 2252.80, + 2376.00, 2534.40, 2640.00, 2816.00, 2970.40, 3168.00, 3379.20, 3520.00, 3801.60, 3960.00 + }; + + const float inc = noteFrq[targetPitch] / noteFrq[sourcePitch]; + + uint32 estimatedSize = (uint32)(((float) size / inc) + 1); + uint32 exactSize = 0; + uint8 * tmp = new uint8[estimatedSize]; + memset(tmp, 0x80, estimatedSize); + + int last = 0; + for (float i = 0; i < size; i += inc) { + int cur = (int) i; + if (cur == last + 2) + tmp[exactSize++] = (data[last] + data[cur - 1] + data[cur]) / 3; + else if (cur == last) + tmp[exactSize++] = (data[cur] + data[cur + 1]) / 2; + else + tmp[exactSize++] = data[cur]; + last = (int) i; + } + + size = MIN(exactSize, estimatedSize); + delete[] data; + data = tmp; +} + +const uint8 SoundTowns::_sfxBTTable[256] = { + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFE, + 0x7F, 0x7F, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, + 0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, + 0x60, 0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, + 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, + 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, + 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, + 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, + 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 +}; + +} // end of namespace Kyra diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 3bb163580e..00007ddc49 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -30,8 +30,8 @@ namespace Kyra { -#define RESFILE_VERSION 12 -#define KYRADAT_FILESIZE 67227 +#define RESFILE_VERSION 13 +#define KYRADAT_FILESIZE 142510 bool StaticResource::checkKyraDat() { Common::File kyraDat; @@ -50,7 +50,7 @@ bool StaticResource::checkKyraDat() { enum { GF_FLOPPY = 1 << 0, GF_TALKIE = 1 << 1, - GF_AUDIOCD = 1 << 2, // FM-Towns versions seems to use audio CD + GF_FMTOWNS = 1 << 2, GF_DEMO = 1 << 3, GF_ENGLISH = 1 << 4, GF_FRENCH = 1 << 5, @@ -70,8 +70,8 @@ uint32 createFeatures(const GameFlags &flags) { return GF_TALKIE; if (flags.isDemo) return GF_DEMO; - //if (flags.hasAudioCD) - // return GF_AUDIOCD; + //if (flags.platform == Common::kPlatformFMTowns) + // return GF_FMTOWNS; return GF_FLOPPY; } @@ -189,6 +189,9 @@ bool StaticResource::init() { // PALETTE table { kPaletteList, kPaletteTable, "1 33 PALTABLE" }, + + // FM-TOWNS specific + { kKyra1TownsSFXTable, kRawData, "SFXTABLE.TSX" }, { 0, 0, 0 } }; @@ -592,7 +595,9 @@ uint8 *StaticResource::getFile(const char *name, int &size) { ext = ".CD"; } else if (_engine->gameFlags().isDemo) { ext = ".DEM"; - } + } /*else if (_engine->gameFlags().platform == Common::kPlatformFMTowns) { + ext = ".TNS"; + } */ snprintf(buffer, 64, "%s%s", name, ext); uint32 tempSize = 0; uint8 *data = _engine->resource()->fileData(buffer, &tempSize); @@ -1066,7 +1071,7 @@ void KyraEngine::setupOpcodeTable() { } #undef Opcode -const char *KyraEngine::_musicFiles[] = { +const char *KyraEngine::_soundFiles[] = { "INTRO", "KYRA1A", "KYRA1B", @@ -1079,7 +1084,18 @@ const char *KyraEngine::_musicFiles[] = { "KYRAMISC" }; -const int KyraEngine::_musicFilesCount = ARRAYSIZE(_musicFiles); +const int KyraEngine::_soundFilesCount = ARRAYSIZE(KyraEngine::_soundFiles); + +const char *KyraEngine::_soundFilesTowns[] = { + "TW_INTRO.SFX", + "TW_SCEN1.SFX", + "TW_SCEN2.SFX", + "TW_SCEN3.SFX", + "TW_SCEN4.SFX", + "TW_SCEN5.SFX", +}; + +const int KyraEngine::_soundFilesTownsCount = ARRAYSIZE(KyraEngine::_soundFilesTowns); const int8 KyraEngine::_charXPosTable[] = { 0, 4, 4, 4, 0, -4, -4, -4 -- cgit v1.2.3