diff options
-rw-r--r-- | saga/actor.cpp | 5 | ||||
-rw-r--r-- | saga/font.cpp | 9 | ||||
-rw-r--r-- | saga/game.cpp | 73 | ||||
-rw-r--r-- | saga/game.h | 4 | ||||
-rw-r--r-- | saga/game_mod.h | 11 | ||||
-rw-r--r-- | saga/interface.cpp | 4 | ||||
-rw-r--r-- | saga/music.cpp | 32 | ||||
-rw-r--r-- | saga/music.h | 3 | ||||
-rw-r--r-- | saga/rscfile.cpp | 4 | ||||
-rw-r--r-- | saga/rscfile_mod.h | 1 | ||||
-rw-r--r-- | saga/saga.cpp | 36 | ||||
-rw-r--r-- | saga/scene.cpp | 4 | ||||
-rw-r--r-- | saga/script.cpp | 8 | ||||
-rw-r--r-- | saga/sndres.cpp | 123 | ||||
-rw-r--r-- | saga/sndres.h | 4 | ||||
-rw-r--r-- | saga/sound.cpp | 118 | ||||
-rw-r--r-- | saga/sound.h | 1 | ||||
-rw-r--r-- | saga/sprite.cpp | 6 |
18 files changed, 292 insertions, 154 deletions
diff --git a/saga/actor.cpp b/saga/actor.cpp index efec4379e5..f1337a1cb6 100644 --- a/saga/actor.cpp +++ b/saga/actor.cpp @@ -69,12 +69,11 @@ int Actor::reg() { } Actor::Actor(SagaEngine *vm) : _vm(vm), _initialized(false) { - int result; int i; // Get actor resource file context - result = GAME_GetFileContext(&_actorContext, GAME_RESOURCEFILE, 0); - if (result != SUCCESS) { + _actorContext = GAME_GetFileContext(GAME_RESOURCEFILE, 0); + if (_actorContext == NULL) { error("Actor::Actor(): Couldn't load actor module resource context."); } diff --git a/saga/font.cpp b/saga/font.cpp index 736237c6d4..d317b17a94 100644 --- a/saga/font.cpp +++ b/saga/font.cpp @@ -37,8 +37,8 @@ Font::Font(SagaEngine *vm) : _vm(vm), _initialized(false) { int i; // Load font module resource context - if (GAME_GetFileContext(&_fontContext, - GAME_RESOURCEFILE, 0) != SUCCESS) { + _fontContext = GAME_GetFileContext(GAME_RESOURCEFILE, 0); + if (_fontContext == NULL) { error("Font::Font(): Couldn't get resource context."); } @@ -102,7 +102,8 @@ int Font::loadFont(uint32 font_rn, int font_id) { } if (fontres_len < FONT_DESCSIZE) { - error("Font::loadFont(): Invalid font length."); + warning("Font::loadFont(): Invalid font length (%d < %d)", fontres_len, FONT_DESCSIZE); + return FAILURE; } MemoryReadStream readS(fontres_p, fontres_len); @@ -119,7 +120,7 @@ int Font::loadFont(uint32 font_rn, int font_id) { fh.c_width = readS.readUint16LE(); fh.row_length = readS.readUint16LE(); - debug(1, "Font::loadFont(): Reading font resource..."); + debug(1, "Font::loadFont(): Reading font resource #%d...", font_rn); debug(2, "Character width: %d", fh.c_width); debug(2, "Character height: %d", fh.c_height); diff --git a/saga/game.cpp b/saga/game.cpp index f109206421..99b0bfd2ea 100644 --- a/saga/game.cpp +++ b/saga/game.cpp @@ -57,24 +57,33 @@ GAME_SOUNDINFO ITEDEMO_GameSound = { GAME_SOUND_VOC, 0, 0, 0 }; -// Inherit the Earth - win32 Wyrmkeep Demo version +// Inherit the Earth - win32 Wyrmkeep Linux Demo version GAME_FILEDESC ITEWINDEMO_GameFiles[] = { {"ITED.RSC", GAME_RESOURCEFILE}, {"SCRIPTSD.RSC", GAME_SCRIPTFILE}, {"SOUNDSD.RSC", GAME_SOUNDFILE}, + {"VOICESD.RSC", GAME_VOICEFILE}, + {"MUSICD.RSC", GAME_MUSICFILE} +}; + +// Inherit the Earth - win32 Wyrmkeep Demo version older release +GAME_FILEDESC ITEWINDEMOOld_GameFiles[] = { + {"ITED.RSC", GAME_RESOURCEFILE}, + {"SCRIPTSD.RSC", GAME_SCRIPTFILE}, + {"SOUNDSD.RSC", GAME_SOUNDFILE}, {"VOICESD.RSC", GAME_VOICEFILE} }; // Inherit the Earth - Diskette version GAME_FILEDESC ITEDISK_GameFiles[] = { - {"ITE.RSC", GAME_RESOURCEFILE} , - {"SCRIPTS.RSC", GAME_SCRIPTFILE} , + {"ITE.RSC", GAME_RESOURCEFILE}, + {"SCRIPTS.RSC", GAME_SCRIPTFILE}, {"VOICES.RSC", GAME_SOUNDFILE | GAME_VOICEFILE} }; GAME_FONTDESC ITEDISK_GameFonts[] = { - {GAME_FONT_MEDIUM, 0} , - {GAME_FONT_LARGE, 1} , + {GAME_FONT_MEDIUM, 0}, + {GAME_FONT_LARGE, 1}, {GAME_FONT_SMALL, 2} }; @@ -174,12 +183,13 @@ GAMEDESC GameDescs[] = { 0 // features }, - // Inherit the earth - win32 Wyrmkeep Demo version + // Inherit the earth - Linux Demo version + // Note: it should be before win32 version { - "ite-demo-win", + "ite-demo", GID_ITE, GAME_ITE_WINDEMO, - "Inherit the Earth (Win32 Demo)", + "Inherit the Earth (Linux Demo)", 320, 200, 137, ITE_DEFAULT_SCENE, @@ -189,13 +199,31 @@ GAMEDESC GameDescs[] = { ARRAYSIZE(ITECD_GameFonts), ITECD_GameFonts, &ITECD_GameSound, - 0 + GF_VOX_VOICES + }, + + // Inherit the earth - Win32 Demo version + { + "ite-demo", + GID_ITE, + GAME_ITE_WINDEMO, + "Inherit the Earth (Win32 Demo)", + 320, 200, + 137, + ITE_DEFAULT_SCENE, + &ITE_Resources, + ARRAYSIZE(ITEWINDEMOOld_GameFiles), + ITEWINDEMO_GameFiles, + ARRAYSIZE(ITECD_GameFonts), + ITECD_GameFonts, + &ITECD_GameSound, + GF_VOX_VOICES }, // Inherit the earth - CD version // NOTE: it should be before floppy version { - "itecd", + "ite", GID_ITE, GAME_ITE_CD, "Inherit the Earth (DOS CD Version)", @@ -343,27 +371,17 @@ int LoadLanguage() { return SUCCESS; } -int GAME_GetFileContext(RSCFILE_CONTEXT ** ctxt_p, uint16 type, int param) { +RSCFILE_CONTEXT *GAME_GetFileContext(uint16 type, int param) { RSCFILE_CONTEXT *found_ctxt = NULL; uint16 i; - if (ctxt_p == NULL) { - return FAILURE; - } - for (i = 0; i < GameModule.gfile_n; i++) { if (GameModule.gfile_data[i].file_types & type) { found_ctxt = GameModule.gfile_data[i].file_ctxt; } } - if (found_ctxt != NULL) { - *ctxt_p = found_ctxt; - } else { - *ctxt_p = NULL; - } - - return SUCCESS; + return found_ctxt; } DetectedGameList GAME_ProbeGame(const FSList &fslist) { @@ -560,15 +578,8 @@ int GAME_GetGameType() { return GameModule.gamedesc->gd_game_type; } -GameList GAME_GameList() { - int gNum = ARRAYSIZE(GameDescs); - int i; - GameList games; - - for (i = 0; i < gNum; i++) - games.push_back(GameDescs[i].toGameSettings()); - - return games; +uint32 GAME_GetFeatures() { + return GameModule.gamedesc->features; } } // End of namespace Saga diff --git a/saga/game.h b/saga/game.h index d92a15dcc2..1cbefa8156 100644 --- a/saga/game.h +++ b/saga/game.h @@ -47,8 +47,8 @@ struct GAME_FILEDESC { struct GAMEDESC { const char *name; - int gd_game_type; - uint32 gd_game_id; + const int gd_game_type; + const uint32 gd_game_id; const char *gd_title; int gd_logical_w; int gd_logical_h; diff --git a/saga/game_mod.h b/saga/game_mod.h index 6e2254fcc8..0d69ab83e7 100644 --- a/saga/game_mod.h +++ b/saga/game_mod.h @@ -51,7 +51,8 @@ enum GAME_FILETYPES { enum GAME_SOUNDINFO_TYPES { GAME_SOUND_PCM = 0, GAME_SOUND_VOC, - GAME_SOUND_WAV + GAME_SOUND_WAV, + GAME_SOUND_VOX }; enum GAME_FONT_IDS { @@ -64,6 +65,10 @@ enum GAME_FONT_IDS { GAME_FONT_LARGE3 }; +enum GAME_FEATURES { + GF_VOX_VOICES = 1 +}; + struct GAME_DISPLAYINFO { int logical_w; int logical_h; @@ -96,7 +101,7 @@ struct GAME_RESOURCEDESC { int GAME_Register(); int GAME_Init(); -int GAME_GetFileContext(RSCFILE_CONTEXT **ctxt_p, uint16 type, int param); +RSCFILE_CONTEXT *GAME_GetFileContext(uint16 type, int param); int GAME_GetFontInfo(GAME_FONTDESC **, int *); int GAME_GetResourceInfo(GAME_RESOURCEDESC *); int GAME_GetSoundInfo(GAME_SOUNDINFO *); @@ -104,8 +109,8 @@ int GAME_GetDisplayInfo(GAME_DISPLAYINFO *); int GAME_GetSceneInfo(GAME_SCENEDESC *); int GAME_GetGame(); int GAME_GetGameType(); -GameList GAME_GameList(); DetectedGameList GAME_ProbeGame(const FSList &fslist); +uint32 GAME_GetFeatures(); } // End of namespace Saga diff --git a/saga/interface.cpp b/saga/interface.cpp index 5b3a59f24d..c104d6092a 100644 --- a/saga/interface.cpp +++ b/saga/interface.cpp @@ -177,8 +177,8 @@ Interface::Interface(SagaEngine *vm) : _vm(vm), _initialized(false) { } // Load interface module resource file context - result = GAME_GetFileContext(&_interfaceContext, GAME_RESOURCEFILE, 0); - if (result != SUCCESS) { + _interfaceContext = GAME_GetFileContext(GAME_RESOURCEFILE, 0); + if (_interfaceContext == NULL) { return; } diff --git a/saga/music.cpp b/saga/music.cpp index 164f4c754f..d8ab563e65 100644 --- a/saga/music.cpp +++ b/saga/music.cpp @@ -308,10 +308,22 @@ Music::Music(SoundMixer *mixer, MidiDriver *driver, int enabled) : _mixer(mixer) // know why it has 27 elements, but the last one represents a // very short tune. Perhaps it's a dummy? // - // TODO: The demo uses compressed music? + // FIXME: Well, it's a hack which I don't like. Logically it should + // call LoadResource() et al, but I don't want to load those + // huge files into memory. So I use FileContext just for getting file + // name and reuse its opened file a bit. + // + // Proper approach would be to extend resource manager so it could + // return File object. - if (file.open("music.rsc")) { + _musicContext = GAME_GetFileContext(GAME_MUSICFILE, 0); + if (_musicContext != NULL) { _hasDigiMusic = true; + + debug(0, "DHFJKHDFKJLHDFKLJHDFKJHDASF"); + _musicFname = RSC_FileName(_musicContext); + + file.open(_musicFname); file.seek(-ARRAYSIZE(_digiTableITECD) * 8, SEEK_END); for (int i = 0; i < ARRAYSIZE(_digiTableITECD); i++) { @@ -403,13 +415,18 @@ int Music::play(uint32 music_rn, uint16 flags) { uint32 length = _digiTableITECD[music_rn - 9].length; if (length > 0) { - audioStream = makeRAWStream("music.rsc", start, length, flags == MUSIC_LOOP); + audioStream = makeRAWStream(_musicFname, start, length, flags == MUSIC_LOOP); } } // No digitized music - try standalone MIDI. - if (!audioStream) + if (!audioStream) { midiFile.open(_midiTableITECD[music_rn - 9].filename); + + if (!midiFile.isOpen()) { + warning("Cannot open music file %s", _midiTableITECD[music_rn - 9].filename); + } + } } } @@ -437,7 +454,7 @@ int Music::play(uint32 music_rn, uint16 flags) { } else { // Load XMI resource data - GAME_GetFileContext(&rsc_ctxt, GAME_RESOURCEFILE, 0); + rsc_ctxt = GAME_GetFileContext(GAME_RESOURCEFILE, 0); if (RSC_LoadResource(rsc_ctxt, music_rn, &resource_data, &resource_size) != SUCCESS ) { @@ -449,6 +466,11 @@ int Music::play(uint32 music_rn, uint16 flags) { parser = MidiParser::createParser_XMIDI(); } + if (resource_size <= 0) { + warning("Music::play(): Resource load failed: %u", music_rn); + return FAILURE; + } + if (!parser->loadMusic(resource_data, resource_size)) { warning("Error reading track!"); delete parser; diff --git a/saga/music.h b/saga/music.h index 21e6292859..f7249628de 100644 --- a/saga/music.h +++ b/saga/music.h @@ -126,6 +126,9 @@ private: int _musicInitialized; int _enabled; bool _hasDigiMusic; + + RSCFILE_CONTEXT *_musicContext; + const char *_musicFname; }; } // End of namespace Saga diff --git a/saga/rscfile.cpp b/saga/rscfile.cpp index 804de7f5ee..929c1c5f6e 100644 --- a/saga/rscfile.cpp +++ b/saga/rscfile.cpp @@ -211,6 +211,10 @@ int RSC_GetResourceOffset(RSCFILE_CONTEXT *rsc, uint32 res_num, uint32 *res_offs return SUCCESS; } +const char *RSC_FileName(RSCFILE_CONTEXT *rsc) { + return rsc->rc_file_fspec; +} + int RSC_LoadResource(RSCFILE_CONTEXT *rsc, uint32 res_num, byte **res_p, size_t *res_size_p) { uint32 res_offset; size_t res_size; diff --git a/saga/rscfile_mod.h b/saga/rscfile_mod.h index 1efb879a18..4bcf7ce32c 100644 --- a/saga/rscfile_mod.h +++ b/saga/rscfile_mod.h @@ -39,6 +39,7 @@ int RSC_GetResourceSize(RSCFILE_CONTEXT *, uint32, uint32 *); int RSC_GetResourceOffset(RSCFILE_CONTEXT *, uint32, uint32 *); int RSC_LoadResource(RSCFILE_CONTEXT *, uint32, byte **, size_t *); int RSC_FreeResource(byte *); +const char *RSC_FileName(RSCFILE_CONTEXT *rsc); } // End of namespace Saga diff --git a/saga/saga.cpp b/saga/saga.cpp index 42f9b6a5e3..1c05086ebf 100644 --- a/saga/saga.cpp +++ b/saga/saga.cpp @@ -55,8 +55,24 @@ #include "saga/game_mod.h" #include "saga/palanim.h" +static const GameSettings saga_games[] = { + {"ite", "Inherit the Earth", 0}, + {"ite-demo", "Inherit the Earth (Demo)", 0}, + {"ihnm", "I Have No Mouth and I Must Scream", 0 }, + {"ihnm-demo", "I Have No Mouth and I Must Scream (Demo)", 0 }, + {0, 0, 0} +}; + GameList Engine_SAGA_gameList() { - return Saga::GAME_GameList(); + GameList games; + const GameSettings *g = saga_games; + + while (g->name) { + games.push_back(*g); + g++; + } + + return games; } DetectedGameList Engine_SAGA_detectGames(const FSList &fslist) { @@ -124,13 +140,17 @@ void SagaEngine::go() { CVAR_RegisterFunc(CF_quitfunc, "quit", NULL, CVAR_NONE, 0, 0, this); - // Process config file - // FIXME - /* - if (CFG_Read(NULL) != SUCCESS) { - warning("Couldn't read configuration file"); - } - */ + // Add some default directories + // Win32 demo & full game + File::addDefaultDirectory("graphics"); + File::addDefaultDirectory("music"); + File::addDefaultDirectory("sound"); + + // Linux demo + File::addDefaultDirectory("itedata"); + + // Mac demos & full game + File::addDefaultDirectory("patch"); // Process command line diff --git a/saga/scene.cpp b/saga/scene.cpp index bccc198b5c..8b91cfbd94 100644 --- a/saga/scene.cpp +++ b/saga/scene.cpp @@ -75,8 +75,8 @@ Scene::Scene(SagaEngine *vm) : _vm(vm), _initialized(false) { GAME_GetSceneInfo(&gs_desc); // Load scene module resource context - result = GAME_GetFileContext(&_sceneContext, GAME_RESOURCEFILE, 0); - if (result != SUCCESS) { + _sceneContext = GAME_GetFileContext(GAME_RESOURCEFILE, 0); + if (_sceneContext == NULL) { warning("Scene::Scene(): Couldn't load scene resource context"); return; } diff --git a/saga/script.cpp b/saga/script.cpp index 50035fa5d8..feef94dc9b 100644 --- a/saga/script.cpp +++ b/saga/script.cpp @@ -70,14 +70,14 @@ Script::Script() { debug(0, "Initializing scripting subsystem"); // Load script resource file context - result = GAME_GetFileContext(&_scriptContext, GAME_SCRIPTFILE, 0); - if (result != SUCCESS) { + _scriptContext = GAME_GetFileContext(GAME_SCRIPTFILE, 0); + if (_scriptContext == NULL) { error("Couldn't get script file context"); } // Load script LUT resource - result = GAME_GetFileContext(&s_lut_ctxt, GAME_RESOURCEFILE, 0); - if (result != SUCCESS) { + s_lut_ctxt = GAME_GetFileContext(GAME_RESOURCEFILE, 0); + if (s_lut_ctxt == NULL) { error("Couldn't get resource file context"); } diff --git a/saga/sndres.cpp b/saga/sndres.cpp index c36845d99c..f491f0aff3 100644 --- a/saga/sndres.cpp +++ b/saga/sndres.cpp @@ -36,16 +36,14 @@ namespace Saga { SndRes::SndRes(SagaEngine *vm) : _vm(vm) { - int result; - /* Load sound module resource file contexts */ - result = GAME_GetFileContext(&_sfx_ctxt, GAME_SOUNDFILE, 0); - if (result != SUCCESS) { + _sfx_ctxt = GAME_GetFileContext(GAME_SOUNDFILE, 0); + if (_sfx_ctxt == NULL) { return; } - result = GAME_GetFileContext(&_voice_ctxt, GAME_VOICEFILE, 0); - if (result != SUCCESS) { + _voice_ctxt = GAME_GetFileContext(GAME_VOICEFILE, 0); + if (_voice_ctxt == NULL) { return; } @@ -72,7 +70,8 @@ int SndRes::playSound(uint32 sound_rn, int volume) { int SndRes::playVoice(uint32 voice_rn) { SOUNDBUFFER snd_buffer; - int result; + int result = FAILURE; + bool voiceFile = false; debug(0, "SndRes::playVoice(%ld)", voice_rn); @@ -90,34 +89,40 @@ int SndRes::playVoice(uint32 voice_rn) { else f.open("P2_A.iaf"); - if (!f.isOpen()) - return FAILURE; + if (f.isOpen()) { + size = f.size(); + byte *snd_res = (byte *)malloc(size); + f.read(snd_res, size); + f.close(); - size = f.size(); - byte *snd_res = (byte *)malloc(size); - f.read(snd_res, size); - f.close(); - - if (!voc) { - snd_buffer.s_stereo = 0; - snd_buffer.s_samplebits = 16; - snd_buffer.s_freq = 22050; - snd_buffer.s_buf = snd_res; - snd_buffer.s_buf_len = size; - snd_buffer.s_signed = 1; - result = SUCCESS; - } else { - result = loadVocSound(snd_res, size, &snd_buffer); - RSC_FreeResource(snd_res); + if (!voc) { + snd_buffer.s_stereo = 0; + snd_buffer.s_samplebits = 16; + snd_buffer.s_freq = 22050; + snd_buffer.s_buf = snd_res; + snd_buffer.s_buf_len = size; + snd_buffer.s_signed = 1; + result = SUCCESS; + } else { + result = loadVocSound(snd_res, size, &snd_buffer); + RSC_FreeResource(snd_res); + } + voiceFile = true; } - } else + } + + // File is not present. It is DOS CD or Floppy + if (result != SUCCESS) result = load(_voice_ctxt, voice_rn, &snd_buffer); if (result != SUCCESS) { return FAILURE; } - _vm->_sound->playVoice(&snd_buffer); + if (GAME_GetFeatures() & GF_VOX_VOICES && !voiceFile) + _vm->_sound->playVoxVoice(&snd_buffer); + else + _vm->_sound->playVoice(&snd_buffer); return SUCCESS; } @@ -248,6 +253,7 @@ int SndRes::loadVocSound(byte *snd_res, size_t snd_res_len, SOUNDBUFFER *snd_buf int SndRes::getVoiceLength(uint32 voice_rn) { int res_type = _snd_info.res_type; uint32 length = 0; + bool voiceFile = false; double ms_f; int ms_i = -1; @@ -268,11 +274,13 @@ int SndRes::getVoiceLength(uint32 voice_rn) { length = f.size(); res_type = GAME_SOUND_VOC; f.close(); + voiceFile = true; } else if (f.open("P2_A.iaf")) { result = SUCCESS; length = f.size(); res_type = GAME_SOUND_PCM; f.close(); + voiceFile = true; } } @@ -284,7 +292,11 @@ int SndRes::getVoiceLength(uint32 voice_rn) { } } - if (res_type == GAME_SOUND_PCM) { + if (GAME_GetFeatures() & GF_VOX_VOICES && !voiceFile) { + // Rough hack, fix this to be accurate + ms_f = (double)length / 22050 * 2000.0; + ms_i = (int)ms_f; + } else if (res_type == GAME_SOUND_PCM) { ms_f = (double)length / (_snd_info.sample_size / CHAR_BIT) / (_snd_info.freq) * 1000.0; ms_i = (int)ms_f; } else if (res_type == GAME_SOUND_VOC) { @@ -298,59 +310,4 @@ int SndRes::getVoiceLength(uint32 voice_rn) { return ms_i; } -int SndRes::ITEVOC_Resample(long src_freq, long dst_freq, byte *src_buf, - size_t src_buf_len, byte **dst_buf, size_t *dst_buf_len) { - byte *resamp_buf; - size_t resamp_len; - - byte src_samp_a; - byte src_samp_b; - - const byte *read_pa; - const byte *read_pb; - - byte *write_pa; - byte *write_pb; - byte *write_pc; - - size_t src_i; - - assert(src_freq == 14705); - assert(dst_freq == 22050); - - resamp_len = (size_t) (src_buf_len * 1.5); - resamp_buf = (byte *)malloc(resamp_len); - if (resamp_buf == NULL) { - return FAILURE; - } - - read_pa = src_buf; - read_pb = src_buf + 1; - - write_pa = resamp_buf; - write_pb = resamp_buf + 1; - write_pc = resamp_buf + 2; - - for (src_i = 0; src_i < src_buf_len / 2; src_i++) { - src_samp_a = *read_pa; - src_samp_b = *read_pb; - - read_pa += 2; - read_pb += 2; - - *write_pa = src_samp_a; - *write_pb = (byte) ((src_samp_a / 2) + (src_samp_b / 2)); - *write_pc = src_samp_b; - - write_pa += 3; - write_pb += 3; - write_pc += 3; - } - - *dst_buf = resamp_buf; - *dst_buf_len = resamp_len; - - return SUCCESS; -} - } // End of namespace Saga diff --git a/saga/sndres.h b/saga/sndres.h index 53de34641a..bbe91fe02d 100644 --- a/saga/sndres.h +++ b/saga/sndres.h @@ -70,8 +70,6 @@ public: int playSound(uint32 sound_rn, int volume); int playVoice(uint32 voice_rn); int getVoiceLength(uint32 voice_rn); - int ITEVOC_Resample(long src_freq, long dst_freq, byte *src_buf, - size_t src_buf_len, byte **dst_buf, size_t *dst_buf_len); private: int load(RSCFILE_CONTEXT *snd_ctxt, uint32 snd_rn, SOUNDBUFFER *snd_buf_i); @@ -79,7 +77,7 @@ public: int _init; - RSCFILE_CONTEXT *_sfx_ctxt; + RSCFILE_CONTEXT *_sfx_ctxt; RSCFILE_CONTEXT *_voice_ctxt; GAME_SOUNDINFO _snd_info; diff --git a/saga/sound.cpp b/saga/sound.cpp index a6859134ae..e63f675ca0 100644 --- a/saga/sound.cpp +++ b/saga/sound.cpp @@ -25,9 +25,118 @@ #include "saga/sound.h" #include "saga/game_mod.h" +#include "sound/audiostream.h" #include "sound/mixer.h" namespace Saga { +#define BUFFER_SIZE 4096 + +// Routines to convert 12 bit linear samples to the +// Dialogic or Oki ADPCM coding format. +class VOXInputStream : public AudioStream { +private: + const byte *_buf; + uint32 _pos; + uint32 _inputLen; + bool _evenPos; + + struct adpcmStatus { + int16 last; + int16 stepIndex; + } _status; + + int16 stepAdjust(byte); + int16 adpcmDecode(byte); + +public: + VOXInputStream(const byte *input, int inputLen); + ~VOXInputStream() {}; + + int readBuffer(int16 *buffer, const int numSamples); + + bool endOfData() const { return _pos >= _inputLen; } + bool isStereo() const { return false; } + int getRate() const { return 22050; } +}; + + +VOXInputStream::VOXInputStream(const byte *input, int inputLen) + : _buf(input), _pos(0), _inputLen(inputLen), _evenPos(true) { + + _status.last = 0; + _status.stepIndex = 0; +} + +int VOXInputStream::readBuffer(int16 *buffer, const int numSamples) { + int samples = 0; + + while (samples < numSamples && !endOfData()) { + const int len = MIN(numSamples - samples, (int) (_inputLen - _pos)); + + // * 16 effectively converts 12-bit input to 16-bit output + for (int i = 0; i < len; i++) { + if (_evenPos) + buffer[i] = adpcmDecode((_buf[_pos] >> 4) & 0x0f) * 16; + else { + buffer[i] = adpcmDecode(_buf[_pos] & 0x0f) * 16; + _pos++; + } + _evenPos = !_evenPos; + } + + samples += len; + } + return samples; +} + +// adjust the step for use on the next sample. +int16 VOXInputStream::stepAdjust(byte code) { + static int16 adjusts[] = {-1, -1, -1, -1, 2, 4, 6, 8}; + + return adjusts[code & 0x07]; +} + +static int16 stepSize[49] = { 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, + 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, + 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, + 724, 796, 876, 963, 1060, 1166, 1282, 1408, 1552 }; + +// Decode Linear to ADPCM +int16 VOXInputStream::adpcmDecode(byte code) { + int16 diff, E, SS, samp; + + SS = stepSize[_status.stepIndex]; + E = SS/8; + if (code & 0x01) + E += SS/4; + if (code & 0x02) + E += SS/2; + if (code & 0x04) + E += SS; + diff = (code & 0x08) ? -E : E; + samp = _status.last + diff; + + // Clip the values to +/- 2^11 (supposed to be 12 bits) + if(samp > 2048) + samp = 2048; + if(samp < -2048) + samp = -2048; + + _status.last = samp; + _status.stepIndex += stepAdjust(code); + if(_status.stepIndex < 0) + _status.stepIndex = 0; + if(_status.stepIndex > 48) + _status.stepIndex = 48; + + return samp; +} + +AudioStream *makeVOXStream(const byte *input, int size) { + AudioStream *audioStream = new VOXInputStream(input, size); + + return audioStream; +} Sound::Sound(SagaEngine *vm, SoundMixer *mixer, int enabled) : _vm(vm), _mixer(mixer), _enabled(enabled) { @@ -119,6 +228,15 @@ int Sound::playVoice(SOUNDBUFFER *buf) { return playSoundBuffer(&_voiceHandle, buf, 255, false); } +int Sound::playVoxVoice(SOUNDBUFFER *buf) { + AudioStream *audioStream; + + audioStream = makeVOXStream(buf->s_buf, buf->s_buf_len); + _mixer->playInputStream(&_voiceHandle, audioStream, false); + + return SUCCESS; +} + int Sound::pauseVoice() { if (!_soundInitialized) { return FAILURE; diff --git a/saga/sound.h b/saga/sound.h index 46d05f5ede..06292c2099 100644 --- a/saga/sound.h +++ b/saga/sound.h @@ -54,6 +54,7 @@ public: int stopSound(); int playVoice(SOUNDBUFFER *buf); + int playVoxVoice(SOUNDBUFFER *buf); int pauseVoice(); int resumeVoice(); int stopVoice(); diff --git a/saga/sprite.cpp b/saga/sprite.cpp index 102b2360f8..96631006e9 100644 --- a/saga/sprite.cpp +++ b/saga/sprite.cpp @@ -37,13 +37,11 @@ namespace Saga { Sprite::Sprite(SagaEngine *vm) : _vm(vm), _initialized(false) { - int result; - debug(0, "Initializing sprite subsystem..."); // Load sprite module resource context - result = GAME_GetFileContext(&_spriteContext, GAME_RESOURCEFILE, 0); - if (result != SUCCESS) { + _spriteContext = GAME_GetFileContext(GAME_RESOURCEFILE, 0); + if (_spriteContext == NULL) { return; } |