diff options
| author | Alyssa Milburn | 2011-07-07 09:24:10 +0200 |
|---|---|---|
| committer | Alyssa Milburn | 2011-07-07 09:24:10 +0200 |
| commit | 66e81d633f987310f12038147ae01b8ce4f640f7 (patch) | |
| tree | 6035a7124789c3e6cdff5f603e9933529b7efdc7 /engines | |
| parent | affaa1f4d6cf5f27f654029133b1aec7b9eca4b5 (diff) | |
| parent | 72da8ef5adf82d8a65da299207f30af5058ca8a9 (diff) | |
| download | scummvm-rg350-66e81d633f987310f12038147ae01b8ce4f640f7.tar.gz scummvm-rg350-66e81d633f987310f12038147ae01b8ce4f640f7.tar.bz2 scummvm-rg350-66e81d633f987310f12038147ae01b8ce4f640f7.zip | |
Merge remote-tracking branch 'origin/master' into soltys_wip2
Diffstat (limited to 'engines')
74 files changed, 1737 insertions, 1295 deletions
diff --git a/engines/agi/preagi_winnie.cpp b/engines/agi/preagi_winnie.cpp index 1df31ff72a..af26fe62d0 100644 --- a/engines/agi/preagi_winnie.cpp +++ b/engines/agi/preagi_winnie.cpp @@ -86,27 +86,30 @@ void Winnie::parseObjHeader(WTP_OBJ_HDR *objHdr, byte *buffer, int len) { } uint32 Winnie::readRoom(int iRoom, uint8 *buffer, WTP_ROOM_HDR &roomHdr) { - char szFile[256] = {0}; + Common::String fileName; if (_vm->getPlatform() == Common::kPlatformPC) - sprintf(szFile, IDS_WTP_ROOM_DOS, iRoom); + fileName = Common::String::format(IDS_WTP_ROOM_DOS, iRoom); else if (_vm->getPlatform() == Common::kPlatformAmiga) - sprintf(szFile, IDS_WTP_ROOM_AMIGA, iRoom); + fileName = Common::String::format(IDS_WTP_ROOM_AMIGA, iRoom); else if (_vm->getPlatform() == Common::kPlatformC64) - sprintf(szFile, IDS_WTP_ROOM_C64, iRoom); + fileName = Common::String::format(IDS_WTP_ROOM_C64, iRoom); else if (_vm->getPlatform() == Common::kPlatformApple2GS) - sprintf(szFile, IDS_WTP_ROOM_APPLE, iRoom); + fileName = Common::String::format(IDS_WTP_ROOM_APPLE, iRoom); + Common::File file; - if (!file.open(szFile)) { - warning ("Could not open file \'%s\'", szFile); + if (!file.open(fileName)) { + warning("Could not open file \'%s\'", fileName.c_str()); return 0; } + uint32 filelen = file.size(); - if (_vm->getPlatform() == Common::kPlatformC64) { //Skip the loading address + if (_vm->getPlatform() == Common::kPlatformC64) { // Skip the loading address filelen -= 2; file.seek(2, SEEK_CUR); } - memset(buffer, 0, sizeof(buffer)); + + memset(buffer, 0, 4096); file.read(buffer, filelen); file.close(); @@ -116,26 +119,30 @@ uint32 Winnie::readRoom(int iRoom, uint8 *buffer, WTP_ROOM_HDR &roomHdr) { } uint32 Winnie::readObj(int iObj, uint8 *buffer) { - char szFile[256] = {0}; + Common::String fileName; + if (_vm->getPlatform() == Common::kPlatformPC) - sprintf(szFile, IDS_WTP_OBJ_DOS, iObj); + fileName = Common::String::format(IDS_WTP_OBJ_DOS, iObj); else if (_vm->getPlatform() == Common::kPlatformAmiga) - sprintf(szFile, IDS_WTP_OBJ_AMIGA, iObj); + fileName = Common::String::format(IDS_WTP_OBJ_AMIGA, iObj); else if (_vm->getPlatform() == Common::kPlatformC64) - sprintf(szFile, IDS_WTP_OBJ_C64, iObj); + fileName = Common::String::format(IDS_WTP_OBJ_C64, iObj); else if (_vm->getPlatform() == Common::kPlatformApple2GS) - sprintf(szFile, IDS_WTP_OBJ_APPLE, iObj); + fileName = Common::String::format(IDS_WTP_OBJ_APPLE, iObj); + Common::File file; - if (!file.open(szFile)) { - warning ("Could not open file \'%s\'", szFile); + if (!file.open(fileName)) { + warning ("Could not open file \'%s\'", fileName.c_str()); return 0; } + uint32 filelen = file.size(); - if (_vm->getPlatform() == Common::kPlatformC64) { //Skip the loading address + if (_vm->getPlatform() == Common::kPlatformC64) { // Skip the loading address filelen -= 2; file.seek(2, SEEK_CUR); } - memset(buffer, 0, sizeof(buffer)); + + memset(buffer, 0, 2048); file.read(buffer, filelen); file.close(); return filelen; @@ -461,8 +468,6 @@ void Winnie::keyHelp() { } void Winnie::inventory() { - char szMissing[41] = {0}; - if (_game.iObjHave) printObjStr(_game.iObjHave, IDI_WTP_OBJ_TAKE); else { @@ -470,8 +475,9 @@ void Winnie::inventory() { _vm->drawStr(IDI_WTP_ROW_MENU, IDI_WTP_COL_MENU, IDA_DEFAULT, IDS_WTP_INVENTORY_0); } - sprintf(szMissing, IDS_WTP_INVENTORY_1, _game.nObjMiss); - _vm->drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_MENU, IDA_DEFAULT, szMissing); + Common::String missing = Common::String::format(IDS_WTP_INVENTORY_1, _game.nObjMiss); + + _vm->drawStr(IDI_WTP_ROW_OPTION_4, IDI_WTP_COL_MENU, IDA_DEFAULT, missing.c_str()); _vm->_gfx->doUpdate(); _vm->_system->updateScreen(); //TODO: Move to game's main loop _vm->getSelection(kSelAnyKey); @@ -1042,16 +1048,15 @@ phase2: } void Winnie::drawPic(const char *szName) { - char szFile[256] = {0}; - Common::File file; + Common::String fileName = szName; - // construct filename if (_vm->getPlatform() != Common::kPlatformAmiga) - sprintf(szFile, "%s.pic", szName); - else - strcpy(szFile, szName); - if (!file.open(szFile)) { - warning ("Could not open file \'%s\'", szFile); + fileName += ".pic"; + + Common::File file; + + if (!file.open(fileName)) { + warning ("Could not open file \'%s\'", fileName.c_str()); return; } @@ -1142,12 +1147,11 @@ void Winnie::gameOver() { } void Winnie::saveGame() { - Common::OutSaveFile* outfile; - char szFile[256] = {0}; int i = 0; - sprintf(szFile, IDS_WTP_FILE_SAVEGAME); - if (!(outfile = _vm->getSaveFileMan()->openForSaving(szFile))) + Common::OutSaveFile *outfile = _vm->getSaveFileMan()->openForSaving(IDS_WTP_FILE_SAVEGAME); + + if (!outfile) return; outfile->writeUint32BE(MKTAG('W','I','N','N')); // header @@ -1171,19 +1175,18 @@ void Winnie::saveGame() { outfile->finalize(); if (outfile->err()) - warning("Can't write file '%s'. (Disk full?)", szFile); + warning("Can't write file '%s'. (Disk full?)", IDS_WTP_FILE_SAVEGAME); delete outfile; } void Winnie::loadGame() { - Common::InSaveFile* infile; - char szFile[256] = {0}; int saveVersion = 0; int i = 0; - sprintf(szFile, IDS_WTP_FILE_SAVEGAME); - if (!(infile = _vm->getSaveFileMan()->openForLoading(szFile))) + Common::InSaveFile *infile = _vm->getSaveFileMan()->openForLoading(IDS_WTP_FILE_SAVEGAME); + + if (!infile) return; if (infile->readUint32BE() == MKTAG('W','I','N','N')) { diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index cdb5140002..2f0c13740f 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -688,8 +688,6 @@ int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X, int16 di; uint16 j; int16 mouseX, mouseY; - int16 var_16; - int16 var_14; int16 currentSelection, oldSelection; int16 var_4; SelectionMenu *menu; @@ -731,9 +729,6 @@ int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X, manageEvents(); getMouseData(mouseUpdateStatus, &button, (uint16 *)&mouseX, (uint16 *)&mouseY); - var_16 = mouseX; - var_14 = mouseY; - menuVar = 0; do { diff --git a/engines/cruise/cruise_main.cpp b/engines/cruise/cruise_main.cpp index a97583c972..031c53b96a 100644 --- a/engines/cruise/cruise_main.cpp +++ b/engines/cruise/cruise_main.cpp @@ -902,18 +902,8 @@ bool createDialog(int objOvl, int objIdx, int x, int y) { if (!obj2Ovl) obj2Ovl = j; char verbe_name[80]; - char obj1_name[80]; - char obj2_name[80]; - char r_verbe_name[80]; - char r_obj1_name[80]; - char r_obj2_name[80]; verbe_name[0] = 0; - obj1_name[0] = 0; - obj2_name[0] = 0; - r_verbe_name[0] = 0; - r_obj1_name[0] = 0; - r_obj2_name[0] = 0; ovlDataStruct *ovl2 = NULL; ovlDataStruct *ovl3 = NULL; diff --git a/engines/cruise/mainDraw.cpp b/engines/cruise/mainDraw.cpp index 814d0aa9e9..14b6daf4bb 100644 --- a/engines/cruise/mainDraw.cpp +++ b/engines/cruise/mainDraw.cpp @@ -440,7 +440,6 @@ void buildSegment() { // is segment on screen ? if (!((tempAX > 199) || (tempDX < 0))) { - int dx = Y1; int cx = X2 - X1; if (cx == 0) { // vertical line @@ -473,7 +472,6 @@ void buildSegment() { } else { if (cx < 0) { cx = -cx; - dx = Y2; SWAP(X1, X2); SWAP(Y1, Y2); @@ -1490,9 +1488,6 @@ void mainDraw(int16 param) { if (currentObjPtr->animLoop > 0) currentObjPtr->animLoop--; } else { - int16 data2; - data2 = currentObjPtr->animStart; - change = false; currentObjPtr->animStep = 0; @@ -1512,9 +1507,6 @@ void mainDraw(int16 param) { if (currentObjPtr->animLoop > 0) currentObjPtr->animLoop--; } else { - int16 data2; - data2 = currentObjPtr->animStart; - change = false; currentObjPtr->animStep = 0; diff --git a/engines/cruise/script.cpp b/engines/cruise/script.cpp index 4e76194a45..cf28548e7d 100644 --- a/engines/cruise/script.cpp +++ b/engines/cruise/script.cpp @@ -231,9 +231,7 @@ int32 opcodeType2() { int type = getByteFromScript(); int overlay = getByteFromScript(); - int firstOffset; - int offset; - firstOffset = offset = getShortFromScript(); + int offset = getShortFromScript(); offset += index; int typ7 = type & 7; diff --git a/engines/dreamweb/detection.cpp b/engines/dreamweb/detection.cpp index d32be6a2b7..ef4a746b62 100644 --- a/engines/dreamweb/detection.cpp +++ b/engines/dreamweb/detection.cpp @@ -43,7 +43,7 @@ public: AdvancedMetaEngine(DreamWeb::gameDescriptions, sizeof(DreamWeb::DreamWebGameDescription), dreamWebGames) { _singleid = "dreamweb"; - _guioptions = Common::GUIO_NOMIDI; + _guioptions = Common::GUIO_NOMIDI | Common::GUIO_NOLAUNCHLOAD; } virtual const char *getName() const { diff --git a/engines/dreamweb/detection_tables.h b/engines/dreamweb/detection_tables.h index 0449361a98..6c7d8e4809 100644 --- a/engines/dreamweb/detection_tables.h +++ b/engines/dreamweb/detection_tables.h @@ -31,6 +31,7 @@ namespace DreamWeb { using Common::GUIO_NONE; static const DreamWebGameDescription gameDescriptions[] = { + // International floppy release { { "dreamweb", @@ -81,6 +82,23 @@ static const DreamWebGameDescription gameDescriptions[] = { }, }, + // French CD release + { + { + "dreamweb", + "CD", + { + {"dreamwfr.r00", 0, "e354582a8564faf5c515df92f207e8d1", 154657}, + {"dreamwfr.r02", 0, "57f3f08d5aefd04184eac76927eced80", 200575}, + AD_LISTEND + }, + Common::FR_FRA, + Common::kPlatformPC, + ADGF_CD | ADGF_UNSTABLE, + GUIO_NONE + }, + }, + // German floppy release { { @@ -132,6 +150,23 @@ static const DreamWebGameDescription gameDescriptions[] = { }, }, + // Spanish CD release + { + { + "dreamweb", + "CD", + { + {"dreamwsp.r00", 0, "2df07174321de39c4f17c9ff654b268a", 153608}, + {"dreamwsp.r02", 0, "577d435ad5da08fb1bcf6ea3dd6e0b9e", 199499}, + AD_LISTEND + }, + Common::ES_ESP, + Common::kPlatformPC, + ADGF_CD | ADGF_UNSTABLE, + GUIO_NONE + }, + }, + // Italian floppy release { { diff --git a/engines/engine.cpp b/engines/engine.cpp index b952f065ad..b19daa2611 100644 --- a/engines/engine.cpp +++ b/engines/engine.cpp @@ -410,7 +410,7 @@ void Engine::openMainMenuDialog() { // value, which is quite bad since it could // be a fatal loading error, which renders // the engine unusable. - if (_saveSlotToLoad > 0) + if (_saveSlotToLoad >= 0) loadGameState(_saveSlotToLoad); syncSoundSettings(); diff --git a/engines/groovie/saveload.cpp b/engines/groovie/saveload.cpp index a0463db0be..14e7a09cb2 100644 --- a/engines/groovie/saveload.cpp +++ b/engines/groovie/saveload.cpp @@ -102,7 +102,7 @@ Common::InSaveFile *SaveLoad::openForLoading(const Common::String &target, int s // Fill the SaveStateDescriptor if it was provided if (descriptor) { // Initialize the SaveStateDescriptor - descriptor->setVal("save_slot", Common::String('0' + slot)); + descriptor->setSaveSlot(slot); descriptor->setDeletableFlag(true); descriptor->setWriteProtectedFlag(false); @@ -132,7 +132,7 @@ Common::InSaveFile *SaveLoad::openForLoading(const Common::String &target, int s description += c; } } - descriptor->setVal("description", description); + descriptor->setDescription(description); } // Return a substream, skipping the metadata diff --git a/engines/groovie/script.cpp b/engines/groovie/script.cpp index f87e6bb91b..5a24559e8b 100644 --- a/engines/groovie/script.cpp +++ b/engines/groovie/script.cpp @@ -1350,15 +1350,15 @@ void Script::o_checkvalidsaves() { uint count = 0; SaveStateList::iterator it = list.begin(); while (it != list.end()) { - int8 slot = it->getVal("save_slot").lastChar() - '0'; + int8 slot = it->getSaveSlot(); if (SaveLoad::isSlotValid(slot)) { - debugScript(2, true, " Found valid savegame: %s", it->getVal("description").c_str()); + debugScript(2, true, " Found valid savegame: %s", it->getDescription().c_str()); // Mark this slot as used setVariable(slot, 1); // Cache this slot's description - _saveNames[slot] = it->getVal("description"); + _saveNames[slot] = it->getDescription(); count++; } it++; diff --git a/engines/kyra/debugger.cpp b/engines/kyra/debugger.cpp index e8dd9e9a15..4a48ac0674 100644 --- a/engines/kyra/debugger.cpp +++ b/engines/kyra/debugger.cpp @@ -71,7 +71,7 @@ bool Debugger::cmd_loadPalette(int argc, const char **argv) { } if (_vm->game() != GI_KYRA1 && _vm->resource()->getFileSize(argv[1]) != 768) { - uint8 *buffer = (uint8 *)malloc(320 * 200 * sizeof(uint8)); + uint8 *buffer = new uint8[320 * 200 * sizeof(uint8)]; if (!buffer) { DebugPrintf("ERROR: Cannot allocate buffer for screen region!\n"); return true; @@ -82,7 +82,7 @@ bool Debugger::cmd_loadPalette(int argc, const char **argv) { palette.copy(_vm->screen()->getCPagePtr(5), 0, 256); _vm->screen()->copyBlockToPage(5, 0, 0, 320, 200, buffer); - free(buffer); + delete[] buffer; } else if (!_vm->screen()->loadPalette(argv[1], palette)) { DebugPrintf("ERROR: Palette '%s' not found!\n", argv[1]); return true; diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp index eac82ec2c5..eba2f8f279 100644 --- a/engines/kyra/gui_lok.cpp +++ b/engines/kyra/gui_lok.cpp @@ -576,6 +576,15 @@ void GUI_LoK::setupSavegames(Menu &menu, int num) { if ((in = _vm->openSaveForReading(_vm->getSavegameFilename(_saveSlots[i + _savegameOffset]), header))) { Common::strlcpy(_savegameNames[i], header.description.c_str(), ARRAYSIZE(_savegameNames[0])); + // Trim long GMM save descriptions to fit our save slots + _screen->_charWidth = -2; + int fC = _screen->getTextWidth(_savegameNames[i]); + while (_savegameNames[i][0] && (fC > 240 )) { + _savegameNames[i][strlen(_savegameNames[i]) - 1] = 0; + fC = _screen->getTextWidth(_savegameNames[i]); + } + _screen->_charWidth = 0; + Util::convertISOToDOS(_savegameNames[i]); menu.item[i].itemString = _savegameNames[i]; @@ -693,12 +702,15 @@ void GUI_LoK::updateSavegameString() { if (_keyPressed.keycode) { length = strlen(_savegameName); + _screen->_charWidth = -2; + int width = _screen->getTextWidth(_savegameName) + 7; + _screen->_charWidth = 0; char inputKey = _keyPressed.ascii; Util::convertISOToDOS(inputKey); if ((uint8)inputKey > 31 && (uint8)inputKey < (_vm->gameFlags().lang == Common::JA_JPN ? 128 : 226)) { - if (length < ARRAYSIZE(_savegameName)-1) { + if ((length < ARRAYSIZE(_savegameName)-1) && (width <= 240)) { _savegameName[length] = inputKey; _savegameName[length+1] = 0; redrawTextfield(); diff --git a/engines/kyra/gui_lol.cpp b/engines/kyra/gui_lol.cpp index fb11040168..c64d3e7723 100644 --- a/engines/kyra/gui_lol.cpp +++ b/engines/kyra/gui_lol.cpp @@ -2572,9 +2572,19 @@ void GUI_LoL::setupSaveMenuSlots(Menu &menu, int num) { slotOffs = 1; } + int saveSlotMaxLen = ((_screen->getScreenDim(8))->w << 3) - _screen->getCharWidth('W'); + for (int i = startSlot; i < num && _savegameOffset + i - slotOffs < _savegameListSize; ++i) { if (_savegameList[_saveSlots[i + _savegameOffset - slotOffs]]) { Common::strlcpy(s, _savegameList[_saveSlots[i + _savegameOffset - slotOffs]], 80); + + // Trim long GMM save descriptions to fit our save slots + int fC = _screen->getTextWidth(s); + while (s[0] && fC >= saveSlotMaxLen) { + s[strlen(s) - 1] = 0; + fC = _screen->getTextWidth(s); + } + menu.item[i].itemString = s; s += (strlen(s) + 1); menu.item[i].saveSlot = _saveSlots[i + _savegameOffset - slotOffs]; diff --git a/engines/kyra/gui_v2.cpp b/engines/kyra/gui_v2.cpp index 0b82df8cd5..dcc53b7c9e 100644 --- a/engines/kyra/gui_v2.cpp +++ b/engines/kyra/gui_v2.cpp @@ -457,6 +457,15 @@ void GUI_v2::setupSavegameNames(Menu &menu, int num) { Common::strlcpy(s, header.description.c_str(), 80); Util::convertISOToDOS(s); + // Trim long GMM save descriptions to fit our save slots + _screen->_charWidth = -2; + int fC = _screen->getTextWidth(s); + while (s[0] && fC > 240) { + s[strlen(s) - 1] = 0; + fC = _screen->getTextWidth(s); + } + _screen->_charWidth = 0; + menu.item[i].saveSlot = _saveSlots[i + _savegameOffset]; menu.item[i].enabled = true; delete in; diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index 3d81368d2d..3b2c9b67eb 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -83,7 +83,9 @@ KyraEngine_v1::KyraEngine_v1(OSystem *system, const GameFlags &flags) } void KyraEngine_v1::pauseEngineIntern(bool pause) { - _sound->pause(pause); + Engine::pauseEngineIntern(pause); + if (_sound) + _sound->pause(pause); _timer->pause(pause); } diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index b4304a6de0..8f008a58b6 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -3359,7 +3359,7 @@ void SJISFont::drawChar(uint16 c, byte *dst, int pitch) const { color2 = _colorMap[0]; } - _font->drawChar(dst, c, 640, 1, color1, color2); + _font->drawChar(dst, c, 640, 1, color1, color2, 640, 400); } #pragma mark - diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp index 3713537afd..4da35cc28b 100644 --- a/engines/kyra/sound.cpp +++ b/engines/kyra/sound.cpp @@ -43,10 +43,6 @@ Sound::Sound(KyraEngine_v1 *vm, Audio::Mixer *mixer) Sound::~Sound() { } -void Sound::pause(bool paused) { - _mixer->pauseAll(paused); -} - bool Sound::voiceFileIsPresent(const char *file) { for (int i = 0; _supportedCodecs[i].fileext; ++i) { Common::String f = file; diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h index 566b37ff43..c3c32331be 100644 --- a/engines/kyra/sound.h +++ b/engines/kyra/sound.h @@ -156,7 +156,7 @@ public: /** * Stops all audio playback when paused. Continues after end of pause. */ - virtual void pause(bool paused); + virtual void pause(bool paused) {} void enableMusic(int enable) { _musicEnabled = enable; } int musicEnabled() const { return _musicEnabled; } diff --git a/engines/kyra/sound_midi.cpp b/engines/kyra/sound_midi.cpp index dc0f8c11ec..26b6b31d0a 100644 --- a/engines/kyra/sound_midi.cpp +++ b/engines/kyra/sound_midi.cpp @@ -716,9 +716,6 @@ void SoundMidiPC::beginFadeOut() { } void SoundMidiPC::pause(bool paused) { - // Stop all mixer related sounds - Sound::pause(paused); - Common::StackLock lock(_mutex); if (paused) { diff --git a/engines/lastexpress/data/snd.cpp b/engines/lastexpress/data/snd.cpp index d92ebbc5e3..28d20df9bd 100644 --- a/engines/lastexpress/data/snd.cpp +++ b/engines/lastexpress/data/snd.cpp @@ -36,13 +36,329 @@ namespace LastExpress { +#pragma region Sound filters tables + +static const int filterData[1424] = { + 0, 0, 0, 0, 128, 256, 384, 512, 0, 0, 0, 0, 128, 256, + 384, 512, 0, 0, 0, 0, 192, 320, 448, 576, 0, 0, 0, 0, + 192, 320, 448, 576, 64, 64, 64, 64, 256, 384, 512, 640, + 64, 64, 64, 64, 256, 384, 512, 640, 128, 128, 128, 128, + 320, 448, 576, 704, 128, 128, 128, 128, 320, 448, 576, + 704, 192, 192, 192, 192, 384, 512, 640, 768, 192, 192, + 192, 192, 384, 512, 640, 768, 256, 256, 256, 256, 448, + 576, 704, 832, 256, 256, 256, 256, 448, 576, 704, 832, + 320, 320, 320, 320, 512, 640, 768, 896, 320, 320, 320, + 320, 512, 640, 768, 896, 384, 384, 384, 384, 576, 704, + 832, 960, 384, 384, 384, 384, 576, 704, 832, 960, 448, + 448, 448, 448, 640, 768, 896, 1024, 448, 448, 448, 448, + 640, 768, 896, 1024, 512, 512, 512, 512, 704, 832, 960, + 1088, 512, 512, 512, 512, 704, 832, 960, 1088, 576, + 576, 576, 576, 768, 896, 1024, 1152, 576, 576, 576, + 576, 768, 896, 1024, 1152, 640, 640, 640, 640, 832, + 960, 1088, 1216, 640, 640, 640, 640, 832, 960, 1088, + 1216, 704, 704, 704, 704, 896, 1024, 1152, 1280, 704, + 704, 704, 704, 896, 1024, 1152, 1280, 768, 768, 768, + 768, 960, 1088, 1216, 1344, 768, 768, 768, 768, 960, + 1088, 1216, 1344, 832, 832, 832, 832, 1024, 1152, 1280, + 1408, 832, 832, 832, 832, 1024, 1152, 1280, 1408, 896, + 896, 896, 896, 1088, 1216, 1344, 1472, 896, 896, 896, + 896, 1088, 1216, 1344, 1472, 960, 960, 960, 960, 1152, + 1280, 1408, 1536, 960, 960, 960, 960, 1152, 1280, 1408, + 1536, 1024, 1024, 1024, 1024, 1216, 1344, 1472, 1600, + 1024, 1024, 1024, 1024, 1216, 1344, 1472, 1600, 1088, + 1088, 1088, 1088, 1280, 1408, 1536, 1664, 1088, 1088, + 1088, 1088, 1280, 1408, 1536, 1664, 1152, 1152, 1152, + 1152, 1344, 1472, 1600, 1728, 1152, 1152, 1152, 1152, + 1344, 1472, 1600, 1728, 1216, 1216, 1216, 1216, 1408, + 1536, 1664, 1792, 1216, 1216, 1216, 1216, 1408, 1536, + 1664, 1792, 1280, 1280, 1280, 1280, 1472, 1600, 1728, + 1856, 1280, 1280, 1280, 1280, 1472, 1600, 1728, 1856, + 1344, 1344, 1344, 1344, 1536, 1664, 1792, 1920, 1344, + 1344, 1344, 1344, 1536, 1664, 1792, 1920, 1408, 1408, + 1408, 1408, 1600, 1728, 1856, 1984, 1408, 1408, 1408, + 1408, 1600, 1728, 1856, 1984, 1472, 1472, 1472, 1472, + 1664, 1792, 1920, 2048, 1472, 1472, 1472, 1472, 1664, + 1792, 1920, 2048, 1536, 1536, 1536, 1536, 1728, 1856, + 1984, 2112, 1536, 1536, 1536, 1536, 1728, 1856, 1984, + 2112, 1600, 1600, 1600, 1600, 1792, 1920, 2048, 2176, + 1600, 1600, 1600, 1600, 1792, 1920, 2048, 2176, 1664, + 1664, 1664, 1664, 1856, 1984, 2112, 2240, 1664, 1664, + 1664, 1664, 1856, 1984, 2112, 2240, 1728, 1728, 1728, + 1728, 1920, 2048, 2176, 2304, 1728, 1728, 1728, 1728, + 1920, 2048, 2176, 2304, 1792, 1792, 1792, 1792, 1984, + 2112, 2240, 2368, 1792, 1792, 1792, 1792, 1984, 2112, + 2240, 2368, 1856, 1856, 1856, 1856, 2048, 2176, 2304, + 2432, 1856, 1856, 1856, 1856, 2048, 2176, 2304, 2432, + 1920, 1920, 1920, 1920, 2112, 2240, 2368, 2496, 1920, + 1920, 1920, 1920, 2112, 2240, 2368, 2496, 1984, 1984, + 1984, 1984, 2176, 2304, 2432, 2560, 1984, 1984, 1984, + 1984, 2176, 2304, 2432, 2560, 2048, 2048, 2048, 2048, + 2240, 2368, 2496, 2624, 2048, 2048, 2048, 2048, 2240, + 2368, 2496, 2624, 2112, 2112, 2112, 2112, 2304, 2432, + 2560, 2688, 2112, 2112, 2112, 2112, 2304, 2432, 2560, + 2688, 2176, 2176, 2176, 2176, 2368, 2496, 2624, 2752, + 2176, 2176, 2176, 2176, 2368, 2496, 2624, 2752, 2240, + 2240, 2240, 2240, 2432, 2560, 2688, 2816, 2240, 2240, + 2240, 2240, 2432, 2560, 2688, 2816, 2304, 2304, 2304, + 2304, 2496, 2624, 2752, 2880, 2304, 2304, 2304, 2304, + 2496, 2624, 2752, 2880, 2368, 2368, 2368, 2368, 2560, + 2688, 2816, 2944, 2368, 2368, 2368, 2368, 2560, 2688, + 2816, 2944, 2432, 2432, 2432, 2432, 2624, 2752, 2880, + 3008, 2432, 2432, 2432, 2432, 2624, 2752, 2880, 3008, + 2496, 2496, 2496, 2496, 2688, 2816, 2944, 3072, 2496, + 2496, 2496, 2496, 2688, 2816, 2944, 3072, 2560, 2560, + 2560, 2560, 2752, 2880, 3008, 3136, 2560, 2560, 2560, + 2560, 2752, 2880, 3008, 3136, 2624, 2624, 2624, 2624, + 2816, 2944, 3072, 3200, 2624, 2624, 2624, 2624, 2816, + 2944, 3072, 3200, 2688, 2688, 2688, 2688, 2880, 3008, + 3136, 3264, 2688, 2688, 2688, 2688, 2880, 3008, 3136, + 3264, 2752, 2752, 2752, 2752, 2944, 3072, 3200, 3328, + 2752, 2752, 2752, 2752, 2944, 3072, 3200, 3328, 2816, + 2816, 2816, 2816, 3008, 3136, 3264, 3392, 2816, 2816, + 2816, 2816, 3008, 3136, 3264, 3392, 2880, 2880, 2880, + 2880, 3072, 3200, 3328, 3456, 2880, 2880, 2880, 2880, + 3072, 3200, 3328, 3456, 2944, 2944, 2944, 2944, 3136, + 3264, 3392, 3520, 2944, 2944, 2944, 2944, 3136, 3264, + 3392, 3520, 3008, 3008, 3008, 3008, 3200, 3328, 3456, + 3584, 3008, 3008, 3008, 3008, 3200, 3328, 3456, 3584, + 3072, 3072, 3072, 3072, 3264, 3392, 3520, 3648, 3072, + 3072, 3072, 3072, 3264, 3392, 3520, 3648, 3136, 3136, + 3136, 3136, 3328, 3456, 3584, 3712, 3136, 3136, 3136, + 3136, 3328, 3456, 3584, 3712, 3200, 3200, 3200, 3200, + 3392, 3520, 3648, 3776, 3200, 3200, 3200, 3200, 3392, + 3520, 3648, 3776, 3264, 3264, 3264, 3264, 3456, 3584, + 3712, 3840, 3264, 3264, 3264, 3264, 3456, 3584, 3712, + 3840, 3328, 3328, 3328, 3328, 3520, 3648, 3776, 3904, + 3328, 3328, 3328, 3328, 3520, 3648, 3776, 3904, 3392, + 3392, 3392, 3392, 3584, 3712, 3840, 3968, 3392, 3392, + 3392, 3392, 3584, 3712, 3840, 3968, 3456, 3456, 3456, + 3456, 3648, 3776, 3904, 4032, 3456, 3456, 3456, 3456, + 3648, 3776, 3904, 4032, 3520, 3520, 3520, 3520, 3712, + 3840, 3968, 4096, 3520, 3520, 3520, 3520, 3712, 3840, + 3968, 4096, 3584, 3584, 3584, 3584, 3776, 3904, 4032, + 4160, 3584, 3584, 3584, 3584, 3776, 3904, 4032, 4160, + 3648, 3648, 3648, 3648, 3840, 3968, 4096, 4224, 3648, + 3648, 3648, 3648, 3840, 3968, 4096, 4224, 3712, 3712, + 3712, 3712, 3904, 4032, 4160, 4288, 3712, 3712, 3712, + 3712, 3904, 4032, 4160, 4288, 3776, 3776, 3776, 3776, + 3968, 4096, 4224, 4352, 3776, 3776, 3776, 3776, 3968, + 4096, 4224, 4352, 3840, 3840, 3840, 3840, 4032, 4160, + 4288, 4416, 3840, 3840, 3840, 3840, 4032, 4160, 4288, + 4416, 3904, 3904, 3904, 3904, 4096, 4224, 4352, 4480, + 3904, 3904, 3904, 3904, 4096, 4224, 4352, 4480, 3968, + 3968, 3968, 3968, 4160, 4288, 4416, 4544, 3968, 3968, + 3968, 3968, 4160, 4288, 4416, 4544, 4032, 4032, 4032, + 4032, 4224, 4352, 4480, 4608, 4032, 4032, 4032, 4032, + 4224, 4352, 4480, 4608, 4096, 4096, 4096, 4096, 4288, + 4416, 4544, 4672, 4096, 4096, 4096, 4096, 4288, 4416, + 4544, 4672, 4160, 4160, 4160, 4160, 4352, 4480, 4608, + 4.6, 4160, 4160, 4160, 4160, 4352, 4480, 4608, 4736, + 4224, 4224, 4224, 4224, 4416, 4544, 4672, 4800, 4224, + 4224, 4224, 4224, 4416, 4544, 4672, 4800, 4288, 4288, + 4288, 4288, 4480, 4608, 4736, 4864, 4288, 4288, 4288, + 4288, 4480, 4608, 4736, 4864, 4352, 4352, 4352, 4352, + 4544, 4672, 4800, 4928, 4352, 4352, 4352, 4352, 4544, + 4672, 4800, 4928, 4416, 4416, 4416, 4416, 4608, 4736, + 4864, 4992, 4416, 4416, 4416, 4416, 4608, 4736, 4864, + 4992, 4480, 4480, 4480, 4480, 4672, 4800, 4928, 5056, + 4480, 4480, 4480, 4480, 4672, 4800, 4928, 5056, 4544, + 4544, 4544, 4544, 4736, 4864, 4992, 5120, 4544, 4544, + 4544, 4544, 4736, 4864, 4992, 5120, 4608, 4608, 4608, + 4608, 4800, 4928, 5056, 5184, 4608, 4608, 4608, 4608, + 4800, 4928, 5056, 5184, 4672, 4672, 4672, 4672, 4864, + 4992, 5120, 5248, 4672, 4672, 4672, 4672, 4864, 4992, + 5120, 5248, 4736, 4736, 4736, 4736, 4928, 5056, 5184, + 5312, 4736, 4736, 4736, 4736, 4928, 5056, 5184, 5312, + 4800, 4800, 4800, 4800, 4992, 5120, 5248, 5376, 4800, + 4800, 4800, 4800, 4992, 5120, 5248, 5376, 4864, 4864, + 4864, 4864, 5056, 5184, 5312, 5440, 4864, 4864, 4864, + 4864, 5056, 5184, 5312, 5440, 4928, 4928, 4928, 4928, + 5120, 5248, 5376, 5504, 4928, 4928, 4928, 4928, 5120, + 5248, 5376, 5504, 4992, 4992, 4992, 4992, 5184, 5312, + 5440, 5568, 4992, 4992, 4992, 4992, 5184, 5312, 5440, + 5568, 5056, 5056, 5056, 5056, 5248, 5376, 5504, 5632, + 5056, 5056, 5056, 5056, 5248, 5376, 5504, 5632, 5120, + 5120, 5120, 5120, 5312, 5440, 5568, 5632, 5120, 5120, + 5120, 5120, 5312, 5440, 5568, 5632, 5184, 5184, 5184, + 5184, 5376, 5504, 5632, 5632, 5184, 5184, 5184, 5184, + 5376, 5504, 5632, 5632, 5248, 5248, 5248, 5248, 5440, + 5568, 5632, 5632, 5248, 5248, 5248, 5248, 5440, 5568, + 5632, 5632, 5312, 5312, 5312, 5312, 5504, 5632, 5632, + 5632, 5312, 5312, 5312, 5312, 5504, 5632, 5632, 5632, + 5376, 5376, 5376, 5376, 5568, 5632, 5632, 5632, 5376, + 5376, 5376, 5376, 5568, 5632, 5632, 5632, 5440, 5440, + 5440, 5440, 5632, 5632, 5632, 5632, 5440, 5440, 5440, + 5440, 5632, 5632, 5632, 5632, 5504, 5504, 5504, 5504, + 5632, 5632, 5632, 5632, 5504, 5504, 5504, 5504, 5632, + 5632, 5632, 5632, 5568, 5568, 5568, 5568, 5632, 5632, + 5632, 5632, 5568, 5568, 5568, 5568, 5632, 5632, 5632, + 5632 +}; + +static const int filterData2[1424] = { + 0, 2, 4, 6, 7, 9, 11, 13, 0, -2, -4, -6, -7, -9, -11, + -13, 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, + -11, -13, -15, 1, 3, 5, 7, 10, 12, 14, 16, -1, -3, -5, + -7, -10, -12, -14, -16, 1, 3, 6, 8, 11, 13, 16, 18, + -1, -3, -6, -8, -11, -13, -16, -18, 1, 4, 6, 9, 12, + 15, 17, 20, -1, -4, -6, -9, -12, -15, -17, -20, 1, 4, + 7, 10, 13, 16, 19, 22, -1, -4, -7, -10, -13, -16, -19, + -22, 1, 4, 8, 11, 14, 17, 21, 24, -1, -4, -8, -11, -14, + -17, -21, -24, 1, 5, 8, 12, 15, 19, 22, 26, -1, -5, + -8, -12, -15, -19, -22, -26, 2, 6, 10, 14, 18, 22, 26, + 30, -2, -6, -10, -14, -18, -22, -26, -30, 2, 6, 10, + 14, 19, 23, 27, 31, -2, -6, -10, -14, -19, -23, -27, + -31, 2, 7, 11, 16, 21, 26, 30, 35, -2, -7, -11, -16, + -21, -26, -30, -35, 2, 7, 13, 18, 23, 28, 34, 39, -2, + -7, -13, -18, -23, -28, -34, -39, 2, 8, 14, 20, 25, + 31, 37, 43, -2, -8, -14, -20, -25, -31, -37, -43, 3, + 9, 15, 21, 28, 34, 40, 46, -3, -9, -15, -21, -28, -34, + -40, -46, 3, 10, 17, 24, 31, 38, 45, 52, -3, -10, -17, + -24, -31, -38, -45, -52, 3, 11, 19, 27, 34, 42, 50, + 58, -3, -11, -19, -27, -34, -42, -50, -58, 4, 12, 21, + 29, 38, 46, 55, 63, -4, -12, -21, -29, -38, -46, -55, + -63, 4, 13, 23, 32, 41, 50, 60, 69, -4, -13, -23, -32, + -41, -50, -60, -69, 5, 15, 25, 35, 46, 56, 66, 76, -5, + -15, -25, -35, -46, -56, -66, -76, 5, 16, 28, 39, 50, + 61, 73, 84, -5, -16, -28, -39, -50, -61, -73, -84, 6, + 18, 31, 43, 56, 68, 81, 93, -6, -18, -31, -43, -56, + -68, -81, -93, 6, 20, 34, 48, 61, 75, 89, 103, -6, -20, + -34, -48, -61, -75, -89, -103, 7, 22, 37, 52, 67, 82, + 97, 112, -7, -22, -37, -52, -67, -82, -97, -112, 8, + 24, 41, 57, 74, 90, 107, 123, -8, -24, -41, -57, -74, + -90, -107, -123, 9, 27, 45, 63, 82, 100, 118, 136, -9, + -27, -45, -63, -82, -100, -118, -136, 10, 30, 50, 70, + 90, 110, 130, 150, -10, -30, -50, -70, -90, -110, -130, + -150, 11, 33, 55, 77, 99, 121, 143, 165, -11, -33, -55, + -77, -99, -121, -143, -165, 12, 36, 60, 84, 109, 133, + 157, 181, -12, -36, -60, -84, -109, -133, -157, -181, + 13, 40, 66, 93, 120, 147, 173, 200, -13, -40, -66, -93, + -120, -147, -173, -200, 14, 44, 73, 103, 132, 162, 191, + 221, -14, -44, -73, -103, -132, -162, -191, -221, 16, + 48, 81, 113, 146, 178, 211, 243, -16, -48, -81, -113, + -146, -178, -211, -243, 17, 53, 89, 125, 160, 196, 232, + 268, -17, -53, -89, -125, -160, -196, -232, -268, 19, + 58, 98, 137, 176, 215, 255, 294, -19, -58, -98, -137, + -176, -215, -255, -294, 21, 64, 108, 151, 194, 237, + 281, 324, -21, -64, -108, -151, -194, -237, -281, -324, + 23, 71, 118, 166, 213, 261, 308, 356, -23, -71, -118, + -166, -213, -261, -308, -356, 26, 78, 130, 182, 235, + 287, 339, 391, -26, -78, -130, -182, -235, -287, -339, + -391, 28, 86, 143, 201, 258, 316, 373, 431, -28, -86, + -143, -201, -258, -316, -373, -431, 31, 94, 158, 221, + 284, 347, 411, 474, -31, -94, -158, -221, -284, -347, + -411, -474, 34, 104, 174, 244, 313, 383, 453, 523, -34, + -104, -174, -244, -313, -383, -453, -523, 38, 115, 191, + 268, 345, 422, 498, 575, -38, -115, -191, -268, -345, + -422, -498, -575, 42, 126, 210, 294, 379, 463, 547, + 631, -42, -126, -210, -294, -379, -463, -547, -631, + 46, 139, 231, 324, 417, 510, 602, 695, -46, -139, -231, + -324, -417, -510, -602, -695, 51, 153, 255, 357, 459, + 561, 663, 765, -51, -153, -255, -357, -459, -561, -663, + -765, 56, 168, 280, 392, 505, 617, 729, 841, -56, -168, + -280, -392, -505, -617, -729, -841, 61, 185, 308, 432, + 555, 679, 802, 926, -61, -185, -308, -432, -555, -679, + -802, -926, 68, 204, 340, 476, 612, 748, 884, 1020, + -68, -204, -340, -476, -612, -748, -884, -1020, 74, + 224, 373, 523, 672, 822, 971, 1121, -74, -224, -373, + -523, -672, -822, -971, -1121, 82, 246, 411, 575, 740, + 904, 1069, 1233, -82, -246, -411, -575, -740, -904, + -1069, -1233, 90, 271, 452, 633, 814, 995, 1176, 1357, + -90, -271, -452, -633, -814, -995, -1176, -1357, 99, + 298, 497, 696, 895, 1094, 1293, 1492, -99, -298, -497, + -696, -895, -1094, -1293, -1492, 109, 328, 547, 766, + 985, 1204, 1423, 1642, -109, -328, -547, -766, -985, + -1204, -1423, -1642, 120, 361, 601, 842, 1083, 1324, + 1564, 1805, -120, -361, -601, -842, -1083, -1324, -1564, + -1805, 132, 397, 662, 927, 1192, 1457, 1722, 1987, -132, + -397, -662, -927, -1192, -1457, -1722, -1987, 145, 437, + 728, 1020, 1311, 1603, 1894, 2186, -145, -437, -728, + -1020, -1311, -1603, -1894, -2186, 160, 480, 801, 1121, + 1442, 1762, 2083, 2403, -160, -480, -801, -1121, -1442, + -1762, -2083, -2403, 176, 529, 881, 1234, 1587, 1940, + 2292, 2645, -176, -529, -881, -1234, -1587, -1940, -2292, + -2645, 194, 582, 970, 1358, 1746, 2134, 2522, 2910, + -194, -582, -970, -1358, -1746, -2134, -2522, -2910, + 213, 640, 1066, 1493, 1920, 2347, 2773, 3200, -213, + -640, -1066, -1493, -1920, -2347, -2773, -3200, 234, + 704, 1173, 1643, 2112, 2582, 3051, 3521, -234, -704, + -1173, -1643, -2112, -2582, -3051, -3521, 258, 774, + 1291, 1807, 2324, 2840, 3357, 3873, -258, -774, -1291, + -1807, -2324, -2840, -3357, -3873, 284, 852, 1420, 1988, + 2556, 3124, 3692, 4260, -284, -852, -1420, -1988, -2556, + -3124, -3692, -4260, 312, 937, 1561, 2186, 2811, 3436, + 4060, 4685, -312, -937, -1561, -2186, -2811, -3436, + -4060, -4685, 343, 1030, 1718, 2405, 3092, 3779, 4467, + 5154, -343, -1030, -1718, -2405, -3092, -3779, -4467, + -5154, 378, 1134, 1890, 2646, 3402, 4158, 4914, 5670, + -378, -1134, -1890, -2646, -3402, -4158, -4914, -5670, + 415, 1247, 2079, 2911, 3742, 4574, 5406, 6238, -415, + -1247, -2079, -2911, -3742, -4574, -5406, -6238, 457, + 1372, 2287, 3202, 4117, 5032, 5947, 6862, -457, -1372, + -2287, -3202, -4117, -5032, -5947, -6862, 503, 1509, + 2516, 3522, 4529, 5535, 6542, 7548, -503, -1509, -2516, + -3522, -4529, -5535, -6542, -7548, 553, 1660, 2767, + 3874, 4981, 6088, 7195, 8302, -553, -1660, -2767, -3874, + -4981, -6088, -7195, -8302, 608, 1826, 3044, 4262, 5479, + 6697, 7915, 9133, -608, -1826, -3044, -4262, -5479, + -6697, -7915, -9133, 669, 2009, 3348, 4688, 6027, 7367, + 8706, 10046, -669, -2009, -3348, -4688, -6027, -7367, + -8706, -10046, 736, 2210, 3683, 5157, 6630, 8104, 9577, + 11051, -736, -2210, -3683, -5157, -6630, -8104, -9577, + -11051, 810, 2431, 4052, 5673, 7294, 8915, 10536, 12157, + -810, -2431, -4052, -5673, -7294, -8915, -10536, -12157, + 891, 2674, 4457, 6240, 8023, 9806, 11589, 13372, -891, + -2674, -4457, -6240, -8023, -9806, -11589, -13372, 980, + 2941, 4903, 6864, 8825, 10786, 12748, 14709, -980, -2941, + -4903, -6864, -8825, -10786, -12748, -14709, 1078, 3236, + 5393, 7551, 9708, 11866, 14023, 16181, -1078, -3236, + -5393, -7551, -9708, -11866, -14023, -16181, 1186, 3559, + 5933, 8306, 10679, 13052, 15426, 17799, -1186, -3559, + -5933, -8306, -10679, -13052, -15426, -17799, 1305, + 3915, 6526, 9136, 11747, 14357, 16968, 19578, -1305, + -3915, -6526, -9136, -11747, -14357, -16968, -19578, + 1435, 4307, 7179, 10051, 12922, 15794, 18666, 21538, + -1435, -4307, -7179, -10051, -12922, -15794, -18666, + -21538, 1579, 4738, 7896, 11055, 14214, 17373, 20531, + 23690, -1579, -4738, -7896, -11055, -14214, -17373, + -20531, -23690, 1737, 5212, 8686, 12161, 15636, 19111, + 22585, 26060, -1737, -5212, -8686, -12161, -15636, -19111, + -22585, -26060, 1911, 5733, 9555, 13377, 17200, 21022, + 24844, 28666, -1911, -5733, -9555, -13377, -17200, -21022, + -24844, -28666, 2102, 6306, 10511, 14715, 18920, 23124, + 27329, 31533, -2102, -6306, -10511, -14715, -18920, + -23124, -27329, -31533, 2312, 6937, 11562, 16187, 20812, + 25437, 30062, 32767, -2312, -6937, -11562, -16187, -20812, + -25437, -30062, -32767, 2543, 7631, 12718, 17806, 22893, + 27981, 32767, 32767, -2543, -7631, -12718, -17806, -22893, + -27981, -32767, -32767, 2798, 8394, 13990, 19586, 25183, + 30779, 32767, 32767, -2798, -8394, -13990, -19586, -25183, + -30779, -32767, -32767, 3077, 9233, 15389, 21545, 27700, + 32767, 32767, 32767, -3077, -9233, -15389, -21545, -27700, + -32767, -32767, -32767, 3385, 10157, 16928, 23700, 30471, + 32767, 32767, 32767, -3385, -10157, -16928, -23700, + -30471, -32767, -32767, -32767, 3724, 11172, 18621, + 26069, 32767, 32767, 32767, 32767, -3724, -11172, -18621, + -26069, -32767, -32767, -32767, -32767, 4095, 12287, + 20479, 28671, 32767, 32767, 32767, 32767, -4095, -12287, + -20479, -28671, -32767, -32767, -32767, -32767 +}; + +static const int p1s[17] = { 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4, 0 }; +static const int p2s[17] = { 0, 1, 1, 3, 1, 5, 3, 7, 1, 9, 5, 11, 3, 13, 7, 15, 1 }; + +#pragma endregion + // Last Express ADPCM is similar to MS IMA mono, but inverts its nibbles // and does not have the 4 byte per channel requirement class LastExpress_ADPCMStream : public Audio::Ima_ADPCMStream { public: - LastExpress_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, uint32 blockSize) : - Audio::Ima_ADPCMStream(stream, disposeAfterUse, size, 44100, 1, blockSize) {} + LastExpress_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, uint32 blockSize, int32 filterId) : + Audio::Ima_ADPCMStream(stream, disposeAfterUse, size, 44100, 1, blockSize) { + _currentFilterId = -1; + _nextFilterId = filterId; + } int readBuffer(int16 *buffer, const int numSamples) { int samples = 0; @@ -67,6 +383,45 @@ public: return samples; } + + void setFilterId(int32 filterId) { _nextFilterId = filterId; } + +private: + int32 _currentFilterId; + int32 _nextFilterId; // the sound filter id, -1 for none + + /** + * Sound filter + * + * @param [in] data If non-null, the input data + * @param [in,out] buffer If non-null, the output buffer. + * @param p1 The first filter input. + * @param p2 The second filter input. + */ + static void soundFilter(byte *data, int16 *buffer, int p1, int p2) { + int data1, data2, data1p, data2p; + byte idx; + + data2 = data[0]; + data1 = data[1] << 6; + + data += 2; + + for (int count = 0; count < 735; count++) { + idx = data[count] >> 4; + + data1p = filterData[idx + data1]; + data2p = CLIP(filterData2[idx + data1] + data2, -32767, 32767); + + buffer[2 * count] = (p2 * data2p) >> p1; + + idx = data[count] & 0xF; + + data1 = filterData[idx + data1p]; + data2 = CLIP(filterData2[idx + data1p] + data2p, -32767, 32767); + buffer[2 * count + 1] = (p2 * data2) >> p1; + } + } }; ////////////////////////////////////////////////////////////////////////// @@ -92,8 +447,8 @@ void SimpleSound::loadHeader(Common::SeekableReadStream *in) { _blockSize = _size / _blocks; } -Audio::AudioStream *SimpleSound::makeDecoder(Common::SeekableReadStream *in, uint32 size) const { - return new LastExpress_ADPCMStream(in, DisposeAfterUse::YES, size, _blockSize); +Audio::AudioStream *SimpleSound::makeDecoder(Common::SeekableReadStream *in, uint32 size, int32 filterId) const { + return new LastExpress_ADPCMStream(in, DisposeAfterUse::YES, size, _blockSize, filterId); } void SimpleSound::play(Audio::AudioStream *as) { @@ -103,10 +458,11 @@ void SimpleSound::play(Audio::AudioStream *as) { ////////////////////////////////////////////////////////////////////////// // StreamedSound ////////////////////////////////////////////////////////////////////////// -StreamedSound::StreamedSound() {} +StreamedSound::StreamedSound() : _as(NULL), _loaded(false) {} + StreamedSound::~StreamedSound() {} -bool StreamedSound::load(Common::SeekableReadStream *stream) { +bool StreamedSound::load(Common::SeekableReadStream *stream, int32 filterId) { if (!stream) return false; @@ -115,14 +471,27 @@ bool StreamedSound::load(Common::SeekableReadStream *stream) { loadHeader(stream); // Start decoding the input stream - Audio::AudioStream *as = makeDecoder(stream, _size); + _as = makeDecoder(stream, _size, filterId); // Start playing the decoded audio stream - play(as); + play(_as); + + _loaded = true; return true; } +bool StreamedSound::isFinished() { + if (!_loaded) + return false; + + return !g_system->getMixer()->isSoundHandleActive(_handle); +} + +void StreamedSound::setFilterId(int32 filterId) { + ((LastExpress_ADPCMStream *)_as)->setFilterId(filterId); +} + ////////////////////////////////////////////////////////////////////////// // StreamedSound ////////////////////////////////////////////////////////////////////////// @@ -172,4 +541,8 @@ void AppendableSound::finish() { _finished = true; } +bool AppendableSound::isFinished() { + return _as->endOfStream(); +} + } // End of namespace LastExpress diff --git a/engines/lastexpress/data/snd.h b/engines/lastexpress/data/snd.h index 95a136ee1c..7111d939e7 100644 --- a/engines/lastexpress/data/snd.h +++ b/engines/lastexpress/data/snd.h @@ -55,10 +55,11 @@ public: virtual ~SimpleSound(); void stop() const; + virtual bool isFinished() = 0; protected: void loadHeader(Common::SeekableReadStream *in); - Audio::AudioStream *makeDecoder(Common::SeekableReadStream *in, uint32 size) const; + Audio::AudioStream *makeDecoder(Common::SeekableReadStream *in, uint32 size, int32 filterId = -1) const; void play(Audio::AudioStream *as); uint32 _size; ///< data size @@ -75,7 +76,14 @@ public: StreamedSound(); ~StreamedSound(); - bool load(Common::SeekableReadStream *stream); + bool load(Common::SeekableReadStream *stream, int32 filterId = -1); + virtual bool isFinished(); + + void setFilterId(int32 filterId); + +private: + Audio::AudioStream *_as; + bool _loaded; }; class AppendableSound : public SimpleSound { @@ -87,6 +95,8 @@ public: void queueBuffer(Common::SeekableReadStream *bufferIn); void finish(); + virtual bool isFinished(); + private: Audio::QueuingAudioStream *_as; bool _finished; diff --git a/engines/lastexpress/resource.h b/engines/lastexpress/resource.h index 7dc909ab34..9e05a90399 100644 --- a/engines/lastexpress/resource.h +++ b/engines/lastexpress/resource.h @@ -26,6 +26,8 @@ #include "lastexpress/data/archive.h" #include "lastexpress/shared.h" +#include "common/array.h" + namespace LastExpress { class Background; diff --git a/engines/lastexpress/shared.h b/engines/lastexpress/shared.h index 69816a3d6c..7b640c773a 100644 --- a/engines/lastexpress/shared.h +++ b/engines/lastexpress/shared.h @@ -89,6 +89,27 @@ enum SoundState { kSoundState2 = 2 }; +enum SoundStatus { + kSoundStatus_20 = 0x20, + kSoundStatus_40 = 0x40, + kSoundStatus_180 = 0x180, + kSoundStatusClosed = 0x200, + kSoundStatus_400 = 0x400, + + kSoundStatus_8000 = 0x8000, + kSoundStatus_20000 = 0x20000, + kSoundStatus_100000 = 0x100000, + kSoundStatus_20000000 = 0x20000000, + kSoundStatus_40000000 = 0x40000000, + + kSoundStatusClear0 = 0x10, + kSoundStatusFilter = 0x1F, + kSoundStatusCached = 0x80, + kSoundStatusClear3 = 0x200, + kSoundStatusClear4 = 0x800, + kSoundStatusClearAll = 0xFFFFFFE0 +}; + ////////////////////////////////////////////////////////////////////////// // Time values ////////////////////////////////////////////////////////////////////////// diff --git a/engines/lastexpress/sound/entry.cpp b/engines/lastexpress/sound/entry.cpp index c34bb4f0cc..87d8ccdb30 100644 --- a/engines/lastexpress/sound/entry.cpp +++ b/engines/lastexpress/sound/entry.cpp @@ -38,15 +38,15 @@ namespace LastExpress { +#define SOUNDCACHE_ENTRY_SIZE 92160 +#define FILTER_BUFFER_SIZE 2940 + ////////////////////////////////////////////////////////////////////////// // SoundEntry ////////////////////////////////////////////////////////////////////////// SoundEntry::SoundEntry(LastExpressEngine *engine) : _engine(engine) { _type = kSoundTypeNone; - _currentDataPtr = 0; - _soundData = NULL; - _blockCount = 0; _time = 0; @@ -55,7 +55,7 @@ SoundEntry::SoundEntry(LastExpressEngine *engine) : _engine(engine) { _field_34 = 0; _field_38 = 0; _field_3C = 0; - _field_40 = 0; + _variant = 0; _entity = kEntityPlayer; _field_48 = 0; _priority = 0; @@ -63,13 +63,14 @@ SoundEntry::SoundEntry(LastExpressEngine *engine) : _engine(engine) { _subtitle = NULL; _soundStream = NULL; + + _queued = false; } SoundEntry::~SoundEntry() { - // Entries that have been queued would have their streamed disposed automatically + // Entries that have been queued will have their streamed disposed automatically if (!_soundStream) SAFE_DELETE(_stream); - delete _soundStream; // Zero passed pointers @@ -79,18 +80,12 @@ SoundEntry::~SoundEntry() { void SoundEntry::open(Common::String name, SoundFlag flag, int priority) { _priority = priority; setType(flag); - setStatus(flag); - - // Add entry to sound list - getSoundQueue()->addToQueue(this); - - // Add entry to cache and load sound data - getSoundQueue()->setupCache(this); - loadSoundData(name); + setupStatus(flag); + loadStream(name); } void SoundEntry::close() { - _status.status |= kSoundStatusRemoved; + _status.status |= kSoundStatusClosed; // Loop until ready while (!(_status.status1 & 4) && !(getSoundQueue()->getFlag() & 8) && (getSoundQueue()->getFlag() & 1)) @@ -114,6 +109,43 @@ void SoundEntry::close() { } } +void SoundEntry::play() { + if (!_stream) { + warning("[SoundEntry::play] stream has been disposed"); + return; + } + + // Prepare sound stream + if (!_soundStream) + _soundStream = new StreamedSound(); + + // Compute current filter id + int32 filterId = _status.status & kSoundStatusFilter; + // TODO adjust status (based on stepIndex) + + if (_queued) { + _soundStream->setFilterId(filterId); + } else { + _stream->seek(0); + + // Load the stream and start playing + _soundStream->load(_stream, filterId); + + _queued = true; + } +} + +bool SoundEntry::isFinished() { + if (!_stream) + return true; + + if (!_soundStream || !_queued) + return false; + + // TODO check that all data has been queued + return _soundStream->isFinished(); +} + void SoundEntry::setType(SoundFlag flag) { switch (flag & kFlagType9) { default: @@ -186,10 +218,10 @@ void SoundEntry::setType(SoundFlag flag) { } } -void SoundEntry::setStatus(SoundFlag flag) { +void SoundEntry::setupStatus(SoundFlag flag) { SoundStatus statusFlag = (SoundStatus)flag; - if (!((statusFlag & 0xFF) & kSoundStatusClear1)) - statusFlag = (SoundStatus)(statusFlag | kSoundStatusClear2); + if (!((statusFlag & 0xFF) & kSoundStatusFilter)) + statusFlag = (SoundStatus)(statusFlag | kSoundStatusCached); if (((statusFlag & 0xFF00) >> 8) & kSoundStatusClear0) _status.status = (uint32)statusFlag; @@ -197,11 +229,7 @@ void SoundEntry::setStatus(SoundFlag flag) { _status.status = (statusFlag | kSoundStatusClear4); } -void SoundEntry::setInCache() { - _status.status |= kSoundStatusClear2; -} - -void SoundEntry::loadSoundData(Common::String name) { +void SoundEntry::loadStream(Common::String name) { _name2 = name; // Load sound data @@ -210,11 +238,8 @@ void SoundEntry::loadSoundData(Common::String name) { if (!_stream) _stream = getArchive("DEFAULT.SND"); - if (_stream) { - warning("[Sound::loadSoundData] Not implemented"); - } else { - _status.status = kSoundStatusRemoved; - } + if (!_stream) + _status.status = kSoundStatusClosed; } void SoundEntry::update(uint val) { @@ -225,7 +250,7 @@ void SoundEntry::update(uint val) { if (val) { if (getSoundQueue()->getFlag() & 32) { - _field_40 = val; + _variant = val; value2 = val * 2 + 1; } @@ -237,15 +262,65 @@ void SoundEntry::update(uint val) { } } +bool SoundEntry::updateSound() { + bool result; + char sub[16]; + + if (_status.status2 & 4) { + result = false; + } else { + if (_status.status2 & 0x80) { + if (_field_48 <= getSound()->getData2()) { + _status.status |= 0x20; + _status.status &= ~0x8000; + strcpy(sub, _name2.c_str()); + + int l = strlen(sub) + 1; + if (l - 1 > 4) + sub[l - 1 - 4] = 0; + showSubtitle(sub); + } + } else { + if (!(getSoundQueue()->getFlag() & 0x20)) { + if (!(_status.status3 & 8)) { + if (_entity) { + if (_entity < 0x80) { + updateEntryFlag(getSound()->getSoundFlag(_entity)); + } + } + } + } + //if (status.status2 & 0x40 && !((uint32)_status.status & 0x180) && v1->soundBuffer) + // Sound_FillSoundBuffer(v1); + } + result = true; + } + + return result; +} + +void SoundEntry::updateEntryFlag(SoundFlag flag) { + if (flag) { + if (getSoundQueue()->getFlag() & 0x20 && _type != kSoundType9 && _type != kSoundType7) + update(flag); + else + _status.status = flag + (_status.status & ~0x1F); + } else { + _variant = 0; + _status.status |= 0x80u; + _status.status &= ~0x10001F; + } +} + void SoundEntry::updateState() { if (getSoundQueue()->getFlag() & 32) { if (_type != kSoundType9 && _type != kSoundType7 && _type != kSoundType5) { - uint32 newStatus = _status.status & kSoundStatusClear1; + uint32 variant = _status.status & kSoundStatusFilter; _status.status &= kSoundStatusClearAll; - _field_40 = newStatus; - _status.status |= newStatus * 2 + 1; + _variant = variant; + _status.status |= variant * 2 + 1; } } @@ -253,13 +328,14 @@ void SoundEntry::updateState() { } void SoundEntry::reset() { - _status.status |= kSoundStatusRemoved; + _status.status |= kSoundStatusClosed; _entity = kEntityPlayer; if (_stream) { if (!_soundStream) { SAFE_DELETE(_stream); } else { + // the original stream will be disposed _soundStream->stop(); SAFE_DELETE(_soundStream); } @@ -307,13 +383,6 @@ void SoundEntry::saveLoadWithSerializer(Common::Serializer &s) { } } -void SoundEntry::loadStream() { - if (!_soundStream) - _soundStream = new StreamedSound(); - - _soundStream->load(_stream); -} - ////////////////////////////////////////////////////////////////////////// // SubtitleEntry ////////////////////////////////////////////////////////////////////////// @@ -335,7 +404,7 @@ void SubtitleEntry::load(Common::String filename, SoundEntry *soundEntry) { _sound = soundEntry; // Load subtitle data - if (_engine->getResourceManager()->hasFile(filename)) { + if (_engine->getResourceManager()->hasFile(_filename)) { if (getSoundQueue()->getSubtitleFlag() & 2) return; @@ -369,6 +438,8 @@ void SubtitleEntry::setupAndDraw() { } getSoundQueue()->setCurrentSubtitle(this); + + // TODO Missing code } void SubtitleEntry::draw() { @@ -384,13 +455,11 @@ void SubtitleEntry::draw() { } void SubtitleEntry::drawOnScreen() { - getSoundQueue()->setSubtitleFlag(getSoundQueue()->getSubtitleFlag() & -1); - if (_data == NULL) return; - if (getSoundQueue()->getSubtitleFlag() & 1) - _engine->getGraphicsManager()->draw(_data, GraphicsManager::kBackgroundOverlay); + getSoundQueue()->setSubtitleFlag(getSoundQueue()->getSubtitleFlag() & -2); + _engine->getGraphicsManager()->draw(_data, GraphicsManager::kBackgroundOverlay); } } // End of namespace LastExpress diff --git a/engines/lastexpress/sound/entry.h b/engines/lastexpress/sound/entry.h index 60795332f8..a88b0b7210 100644 --- a/engines/lastexpress/sound/entry.h +++ b/engines/lastexpress/sound/entry.h @@ -76,27 +76,6 @@ namespace LastExpress { class LastExpressEngine; class SubtitleEntry; -enum SoundStatus { - kSoundStatus_20 = 0x20, - kSoundStatus_40 = 0x40, - kSoundStatus_180 = 0x180, - kSoundStatusRemoved = 0x200, - kSoundStatus_400 = 0x400, - - kSoundStatus_8000 = 0x8000, - kSoundStatus_20000 = 0x20000, - kSoundStatus_100000 = 0x100000, - kSoundStatus_20000000 = 0x20000000, - kSoundStatus_40000000 = 0x40000000, - - kSoundStatusClear0 = 0x10, - kSoundStatusClear1 = 0x1F, - kSoundStatusClear2 = 0x80, - kSoundStatusClear3 = 0x200, - kSoundStatusClear4 = 0x800, - kSoundStatusClearAll = 0xFFFFFFE0 -}; - union SoundStatusUnion { uint32 status; byte status1; @@ -119,16 +98,13 @@ public: void open(Common::String name, SoundFlag flag, int priority); void close(); - - void setStatus(SoundFlag flag); - void setType(SoundFlag flag); - void setInCache(); - void loadSoundData(Common::String name); + void play(); + void reset(); + bool isFinished(); void update(uint val); + bool updateSound(); void updateState(); - void reset(); - - void loadStream(); + void updateEntryFlag(SoundFlag flag); // Subtitles void showSubtitle(Common::String filename); @@ -150,12 +126,7 @@ public: Common::String getName2() { return _name2; } // Streams - Common::SeekableReadStream *getStream() { return _stream; } - StreamedSound *getStreamedSound() { return _soundStream; } - -public: - // TODO replace by on-the-fly allocated buffer - void *_soundData; + SimpleSound *getSoundStream() { return _soundStream; } private: LastExpressEngine *_engine; @@ -164,18 +135,18 @@ private: SoundType _type; // int //int _data; //int _endOffset; - int _currentDataPtr; + byte * _currentDataPtr; //int _currentBufferPtr; int _blockCount; uint32 _time; //int _size; //int _field_28; - Common::SeekableReadStream *_stream; // int - //int _field_30; + Common::SeekableReadStream *_stream; // The file stream + //int _archive; int _field_34; int _field_38; int _field_3C; - int _field_40; + int _variant; EntityIndex _entity; int _field_48; uint32 _priority; @@ -184,8 +155,13 @@ private: // original has pointer to the next structure in the list (not used) SubtitleEntry *_subtitle; - // Sound stream - StreamedSound *_soundStream; + // Sound buffer & stream + bool _queued; + StreamedSound *_soundStream; // the filtered sound stream + + void setType(SoundFlag flag); + void setupStatus(SoundFlag flag); + void loadStream(Common::String name); }; ////////////////////////////////////////////////////////////////////////// @@ -204,7 +180,7 @@ public: // Accessors SoundStatusUnion getStatus() { return _status; } - SoundEntry *getSoundEntry() { return _sound; } + SoundEntry *getSoundEntry() { return _sound; } private: LastExpressEngine *_engine; diff --git a/engines/lastexpress/sound/queue.cpp b/engines/lastexpress/sound/queue.cpp index cbd942f082..0a6442ceed 100644 --- a/engines/lastexpress/sound/queue.cpp +++ b/engines/lastexpress/sound/queue.cpp @@ -32,18 +32,11 @@ namespace LastExpress { -#define SOUNDCACHE_ENTRY_SIZE 92160 -#define SOUNDCACHE_MAX_SIZE 6 - SoundQueue::SoundQueue(LastExpressEngine *engine) : _engine(engine) { _state = 0; _currentType = kSoundType16; _flag = 0; - // Cache and filter buffers - memset(&_buffer, 0, sizeof(_buffer)); - _soundCacheData = malloc(6 * SOUNDCACHE_ENTRY_SIZE); - _subtitlesFlag = 0; _currentSubtitle = NULL; } @@ -53,17 +46,12 @@ SoundQueue::~SoundQueue() { SAFE_DELETE(*i); _soundList.clear(); - // Entries in the cache are just pointers to sound list entries - _soundCache.clear(); - for (Common::List<SubtitleEntry *>::iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) SAFE_DELETE(*i); _subtitles.clear(); _currentSubtitle = NULL; - free(_soundCacheData); - // Zero passed pointers _engine = NULL; } @@ -76,14 +64,17 @@ void SoundQueue::handleTimer() { for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { SoundEntry *entry = (*i); - if (entry->getStream() == NULL) { - SAFE_DELETE(*i); + + // When the entry has stopped playing, we remove his buffer + if (entry->isFinished()) { + entry->close(); + SAFE_DELETE(entry); i = _soundList.reverse_erase(i); continue; - } else if (!entry->getStreamedSound()) { - // TODO: stream any sound in the queue after filtering - entry->loadStream(); } + + // Queue the entry data, applying filtering + entry->play(); } } @@ -111,9 +102,80 @@ void SoundQueue::removeFromQueue(Common::String filename) { } void SoundQueue::updateQueue() { - Common::StackLock locker(_mutex); + //Common::StackLock locker(_mutex); + + //warning("[Sound::updateQueue] Not implemented"); + + int maxPriority = 0; + Common::List<SoundEntry *>::iterator lsnd; + SoundEntry *msnd; + + bool loopedPlaying; + + loopedPlaying = 0; + //++g_sound_flag; + + for (lsnd = _soundList.begin(); lsnd != _soundList.end(); ++lsnd) { + if ((*lsnd)->getType() == kSoundType1) + break; + } + + if (getSoundState() & 1) { + if (!(*lsnd) || getFlags()->flag_3 || (*lsnd && (*lsnd)->getTime() > getSound()->getLoopingSoundDuration())) { + getSound()->playLoopingSound(0x45); + } else { + if (getSound()->getData1() && getSound()->getData2() >= getSound()->getData1()) { + (*lsnd)->update(getSound()->getData0()); + getSound()->setData1(0); + } + } + } + + msnd = NULL; + + for (lsnd = _soundList.begin(); lsnd != _soundList.end(); ++lsnd) { + if ((*lsnd)->getStatus().status2 & 0x1) { // Sound is stopped + // original code + //if ((*lsnd)->soundBuffer) + // Sound_RemoveSoundDataFromCache(*lsnd); + //if ((*lsnd)->archive) { + // Archive_SetStatusNotLoaded((*lsnd)->archive); + // (*lsnd)->archive = 0; + // (*lsnd)->field_28 = 3; + //} + + if (_soundList.size() < 6) { + if ((*lsnd)->getStatus().status1 & 0x1F) { + int pri = (*lsnd)->getPriority() + ((*lsnd)->getStatus().status1 & 0x1F); + + if (pri > maxPriority) { + msnd = *lsnd; + maxPriority = pri; + } + } + } + } + + if (!(*lsnd)->updateSound() && !((*lsnd)->getStatus().status3 & 0x8)) { + if (msnd == *lsnd) { + maxPriority = 0; + msnd = 0; + } + if (*lsnd) { + (*lsnd)->close(); + SAFE_DELETE(*lsnd); + lsnd = _soundList.reverse_erase(lsnd); + } + } + } + + + // We don't need this + //if (msnd) + // msnd->updateEntryInternal(); - warning("[Sound::updateQueue] Not implemented"); + getFlags()->flag_3 = 0; + //--g_sound_flag; } void SoundQueue::resetQueue() { @@ -301,11 +363,11 @@ void SoundQueue::updateSubtitles() { if (!(status & kSoundStatus_40) || status & kSoundStatus_180 || soundEntry->getTime() == 0 - || (status & kSoundStatusClear1) < 6 + || (status & kSoundStatusFilter) < 6 || ((getFlags()->nis & 0x8000) && soundEntry->getPriority() < 90)) { current_index = 0; } else { - current_index = soundEntry->getPriority() + (status & kSoundStatusClear1); + current_index = soundEntry->getPriority() + (status & kSoundStatusFilter); if (_currentSubtitle == (*i)) current_index += 4; @@ -334,66 +396,6 @@ void SoundQueue::updateSubtitles() { } ////////////////////////////////////////////////////////////////////////// -// Cache -////////////////////////////////////////////////////////////////////////// -bool SoundQueue::setupCache(SoundEntry *entry) { - if (entry->_soundData) - return true; - - if (_soundCache.size() >= SOUNDCACHE_MAX_SIZE) { - - SoundEntry *cacheEntry = NULL; - uint32 size = 1000; - - for (Common::List<SoundEntry *>::iterator i = _soundCache.begin(); i != _soundCache.end(); ++i) { - if (!((*i)->getStatus().status & kSoundStatus_180)) { - uint32 newSize = (*i)->getPriority() + ((*i)->getStatus().status & kSoundStatusClear1); - - if (newSize < size) { - cacheEntry = (*i); - size = newSize; - } - } - } - - if (entry->getPriority() <= size) - return false; - - if (!cacheEntry) - error("[SoundManager::setupCache] Cannot find a valid entry"); - - cacheEntry->setInCache(); - - // TODO: Wait until the cache entry is ready to be removed - while (!(cacheEntry->getStatus().status1 & 1)) - ; - - if (cacheEntry->_soundData) - removeFromCache(cacheEntry); - - _soundCache.push_back(entry); - entry->_soundData = (char *)_soundCacheData + SOUNDCACHE_ENTRY_SIZE * (_soundCache.size() - 1); - } else { - _soundCache.push_back(entry); - entry->_soundData = (char *)_soundCacheData + SOUNDCACHE_ENTRY_SIZE * (_soundCache.size() - 1); - } - - return true; -} - -void SoundQueue::removeFromCache(SoundEntry *entry) { - for (Common::List<SoundEntry *>::iterator i = _soundCache.begin(); i != _soundCache.end(); ++i) { - if ((*i) == entry) { - // Remove sound buffer - entry->_soundData = NULL; - - // Remove entry from sound cache - i = _soundCache.reverse_erase(i); - } - } -} - -////////////////////////////////////////////////////////////////////////// // Savegame ////////////////////////////////////////////////////////////////////////// void SoundQueue::saveLoadWithSerializer(Common::Serializer &s) { @@ -432,362 +434,13 @@ uint32 SoundQueue::count() { } ////////////////////////////////////////////////////////////////////////// -// Sound filters -////////////////////////////////////////////////////////////////////////// -static const int filterData[1424] = { - 0, 0, 0, 0, 128, 256, 384, 512, 0, 0, 0, 0, 128, 256, - 384, 512, 0, 0, 0, 0, 192, 320, 448, 576, 0, 0, 0, 0, - 192, 320, 448, 576, 64, 64, 64, 64, 256, 384, 512, 640, - 64, 64, 64, 64, 256, 384, 512, 640, 128, 128, 128, 128, - 320, 448, 576, 704, 128, 128, 128, 128, 320, 448, 576, - 704, 192, 192, 192, 192, 384, 512, 640, 768, 192, 192, - 192, 192, 384, 512, 640, 768, 256, 256, 256, 256, 448, - 576, 704, 832, 256, 256, 256, 256, 448, 576, 704, 832, - 320, 320, 320, 320, 512, 640, 768, 896, 320, 320, 320, - 320, 512, 640, 768, 896, 384, 384, 384, 384, 576, 704, - 832, 960, 384, 384, 384, 384, 576, 704, 832, 960, 448, - 448, 448, 448, 640, 768, 896, 1024, 448, 448, 448, 448, - 640, 768, 896, 1024, 512, 512, 512, 512, 704, 832, 960, - 1088, 512, 512, 512, 512, 704, 832, 960, 1088, 576, - 576, 576, 576, 768, 896, 1024, 1152, 576, 576, 576, - 576, 768, 896, 1024, 1152, 640, 640, 640, 640, 832, - 960, 1088, 1216, 640, 640, 640, 640, 832, 960, 1088, - 1216, 704, 704, 704, 704, 896, 1024, 1152, 1280, 704, - 704, 704, 704, 896, 1024, 1152, 1280, 768, 768, 768, - 768, 960, 1088, 1216, 1344, 768, 768, 768, 768, 960, - 1088, 1216, 1344, 832, 832, 832, 832, 1024, 1152, 1280, - 1408, 832, 832, 832, 832, 1024, 1152, 1280, 1408, 896, - 896, 896, 896, 1088, 1216, 1344, 1472, 896, 896, 896, - 896, 1088, 1216, 1344, 1472, 960, 960, 960, 960, 1152, - 1280, 1408, 1536, 960, 960, 960, 960, 1152, 1280, 1408, - 1536, 1024, 1024, 1024, 1024, 1216, 1344, 1472, 1600, - 1024, 1024, 1024, 1024, 1216, 1344, 1472, 1600, 1088, - 1088, 1088, 1088, 1280, 1408, 1536, 1664, 1088, 1088, - 1088, 1088, 1280, 1408, 1536, 1664, 1152, 1152, 1152, - 1152, 1344, 1472, 1600, 1728, 1152, 1152, 1152, 1152, - 1344, 1472, 1600, 1728, 1216, 1216, 1216, 1216, 1408, - 1536, 1664, 1792, 1216, 1216, 1216, 1216, 1408, 1536, - 1664, 1792, 1280, 1280, 1280, 1280, 1472, 1600, 1728, - 1856, 1280, 1280, 1280, 1280, 1472, 1600, 1728, 1856, - 1344, 1344, 1344, 1344, 1536, 1664, 1792, 1920, 1344, - 1344, 1344, 1344, 1536, 1664, 1792, 1920, 1408, 1408, - 1408, 1408, 1600, 1728, 1856, 1984, 1408, 1408, 1408, - 1408, 1600, 1728, 1856, 1984, 1472, 1472, 1472, 1472, - 1664, 1792, 1920, 2048, 1472, 1472, 1472, 1472, 1664, - 1792, 1920, 2048, 1536, 1536, 1536, 1536, 1728, 1856, - 1984, 2112, 1536, 1536, 1536, 1536, 1728, 1856, 1984, - 2112, 1600, 1600, 1600, 1600, 1792, 1920, 2048, 2176, - 1600, 1600, 1600, 1600, 1792, 1920, 2048, 2176, 1664, - 1664, 1664, 1664, 1856, 1984, 2112, 2240, 1664, 1664, - 1664, 1664, 1856, 1984, 2112, 2240, 1728, 1728, 1728, - 1728, 1920, 2048, 2176, 2304, 1728, 1728, 1728, 1728, - 1920, 2048, 2176, 2304, 1792, 1792, 1792, 1792, 1984, - 2112, 2240, 2368, 1792, 1792, 1792, 1792, 1984, 2112, - 2240, 2368, 1856, 1856, 1856, 1856, 2048, 2176, 2304, - 2432, 1856, 1856, 1856, 1856, 2048, 2176, 2304, 2432, - 1920, 1920, 1920, 1920, 2112, 2240, 2368, 2496, 1920, - 1920, 1920, 1920, 2112, 2240, 2368, 2496, 1984, 1984, - 1984, 1984, 2176, 2304, 2432, 2560, 1984, 1984, 1984, - 1984, 2176, 2304, 2432, 2560, 2048, 2048, 2048, 2048, - 2240, 2368, 2496, 2624, 2048, 2048, 2048, 2048, 2240, - 2368, 2496, 2624, 2112, 2112, 2112, 2112, 2304, 2432, - 2560, 2688, 2112, 2112, 2112, 2112, 2304, 2432, 2560, - 2688, 2176, 2176, 2176, 2176, 2368, 2496, 2624, 2752, - 2176, 2176, 2176, 2176, 2368, 2496, 2624, 2752, 2240, - 2240, 2240, 2240, 2432, 2560, 2688, 2816, 2240, 2240, - 2240, 2240, 2432, 2560, 2688, 2816, 2304, 2304, 2304, - 2304, 2496, 2624, 2752, 2880, 2304, 2304, 2304, 2304, - 2496, 2624, 2752, 2880, 2368, 2368, 2368, 2368, 2560, - 2688, 2816, 2944, 2368, 2368, 2368, 2368, 2560, 2688, - 2816, 2944, 2432, 2432, 2432, 2432, 2624, 2752, 2880, - 3008, 2432, 2432, 2432, 2432, 2624, 2752, 2880, 3008, - 2496, 2496, 2496, 2496, 2688, 2816, 2944, 3072, 2496, - 2496, 2496, 2496, 2688, 2816, 2944, 3072, 2560, 2560, - 2560, 2560, 2752, 2880, 3008, 3136, 2560, 2560, 2560, - 2560, 2752, 2880, 3008, 3136, 2624, 2624, 2624, 2624, - 2816, 2944, 3072, 3200, 2624, 2624, 2624, 2624, 2816, - 2944, 3072, 3200, 2688, 2688, 2688, 2688, 2880, 3008, - 3136, 3264, 2688, 2688, 2688, 2688, 2880, 3008, 3136, - 3264, 2752, 2752, 2752, 2752, 2944, 3072, 3200, 3328, - 2752, 2752, 2752, 2752, 2944, 3072, 3200, 3328, 2816, - 2816, 2816, 2816, 3008, 3136, 3264, 3392, 2816, 2816, - 2816, 2816, 3008, 3136, 3264, 3392, 2880, 2880, 2880, - 2880, 3072, 3200, 3328, 3456, 2880, 2880, 2880, 2880, - 3072, 3200, 3328, 3456, 2944, 2944, 2944, 2944, 3136, - 3264, 3392, 3520, 2944, 2944, 2944, 2944, 3136, 3264, - 3392, 3520, 3008, 3008, 3008, 3008, 3200, 3328, 3456, - 3584, 3008, 3008, 3008, 3008, 3200, 3328, 3456, 3584, - 3072, 3072, 3072, 3072, 3264, 3392, 3520, 3648, 3072, - 3072, 3072, 3072, 3264, 3392, 3520, 3648, 3136, 3136, - 3136, 3136, 3328, 3456, 3584, 3712, 3136, 3136, 3136, - 3136, 3328, 3456, 3584, 3712, 3200, 3200, 3200, 3200, - 3392, 3520, 3648, 3776, 3200, 3200, 3200, 3200, 3392, - 3520, 3648, 3776, 3264, 3264, 3264, 3264, 3456, 3584, - 3712, 3840, 3264, 3264, 3264, 3264, 3456, 3584, 3712, - 3840, 3328, 3328, 3328, 3328, 3520, 3648, 3776, 3904, - 3328, 3328, 3328, 3328, 3520, 3648, 3776, 3904, 3392, - 3392, 3392, 3392, 3584, 3712, 3840, 3968, 3392, 3392, - 3392, 3392, 3584, 3712, 3840, 3968, 3456, 3456, 3456, - 3456, 3648, 3776, 3904, 4032, 3456, 3456, 3456, 3456, - 3648, 3776, 3904, 4032, 3520, 3520, 3520, 3520, 3712, - 3840, 3968, 4096, 3520, 3520, 3520, 3520, 3712, 3840, - 3968, 4096, 3584, 3584, 3584, 3584, 3776, 3904, 4032, - 4160, 3584, 3584, 3584, 3584, 3776, 3904, 4032, 4160, - 3648, 3648, 3648, 3648, 3840, 3968, 4096, 4224, 3648, - 3648, 3648, 3648, 3840, 3968, 4096, 4224, 3712, 3712, - 3712, 3712, 3904, 4032, 4160, 4288, 3712, 3712, 3712, - 3712, 3904, 4032, 4160, 4288, 3776, 3776, 3776, 3776, - 3968, 4096, 4224, 4352, 3776, 3776, 3776, 3776, 3968, - 4096, 4224, 4352, 3840, 3840, 3840, 3840, 4032, 4160, - 4288, 4416, 3840, 3840, 3840, 3840, 4032, 4160, 4288, - 4416, 3904, 3904, 3904, 3904, 4096, 4224, 4352, 4480, - 3904, 3904, 3904, 3904, 4096, 4224, 4352, 4480, 3968, - 3968, 3968, 3968, 4160, 4288, 4416, 4544, 3968, 3968, - 3968, 3968, 4160, 4288, 4416, 4544, 4032, 4032, 4032, - 4032, 4224, 4352, 4480, 4608, 4032, 4032, 4032, 4032, - 4224, 4352, 4480, 4608, 4096, 4096, 4096, 4096, 4288, - 4416, 4544, 4672, 4096, 4096, 4096, 4096, 4288, 4416, - 4544, 4672, 4160, 4160, 4160, 4160, 4352, 4480, 4608, - 4736, 4160, 4160, 4160, 4160, 4352, 4480, 4608, 4736, - 4224, 4224, 4224, 4224, 4416, 4544, 4672, 4800, 4224, - 4224, 4224, 4224, 4416, 4544, 4672, 4800, 4288, 4288, - 4288, 4288, 4480, 4608, 4736, 4864, 4288, 4288, 4288, - 4288, 4480, 4608, 4736, 4864, 4352, 4352, 4352, 4352, - 4544, 4672, 4800, 4928, 4352, 4352, 4352, 4352, 4544, - 4672, 4800, 4928, 4416, 4416, 4416, 4416, 4608, 4736, - 4864, 4992, 4416, 4416, 4416, 4416, 4608, 4736, 4864, - 4992, 4480, 4480, 4480, 4480, 4672, 4800, 4928, 5056, - 4480, 4480, 4480, 4480, 4672, 4800, 4928, 5056, 4544, - 4544, 4544, 4544, 4736, 4864, 4992, 5120, 4544, 4544, - 4544, 4544, 4736, 4864, 4992, 5120, 4608, 4608, 4608, - 4608, 4800, 4928, 5056, 5184, 4608, 4608, 4608, 4608, - 4800, 4928, 5056, 5184, 4672, 4672, 4672, 4672, 4864, - 4992, 5120, 5248, 4672, 4672, 4672, 4672, 4864, 4992, - 5120, 5248, 4736, 4736, 4736, 4736, 4928, 5056, 5184, - 5312, 4736, 4736, 4736, 4736, 4928, 5056, 5184, 5312, - 4800, 4800, 4800, 4800, 4992, 5120, 5248, 5376, 4800, - 4800, 4800, 4800, 4992, 5120, 5248, 5376, 4864, 4864, - 4864, 4864, 5056, 5184, 5312, 5440, 4864, 4864, 4864, - 4864, 5056, 5184, 5312, 5440, 4928, 4928, 4928, 4928, - 5120, 5248, 5376, 5504, 4928, 4928, 4928, 4928, 5120, - 5248, 5376, 5504, 4992, 4992, 4992, 4992, 5184, 5312, - 5440, 5568, 4992, 4992, 4992, 4992, 5184, 5312, 5440, - 5568, 5056, 5056, 5056, 5056, 5248, 5376, 5504, 5632, - 5056, 5056, 5056, 5056, 5248, 5376, 5504, 5632, 5120, - 5120, 5120, 5120, 5312, 5440, 5568, 5632, 5120, 5120, - 5120, 5120, 5312, 5440, 5568, 5632, 5184, 5184, 5184, - 5184, 5376, 5504, 5632, 5632, 5184, 5184, 5184, 5184, - 5376, 5504, 5632, 5632, 5248, 5248, 5248, 5248, 5440, - 5568, 5632, 5632, 5248, 5248, 5248, 5248, 5440, 5568, - 5632, 5632, 5312, 5312, 5312, 5312, 5504, 5632, 5632, - 5632, 5312, 5312, 5312, 5312, 5504, 5632, 5632, 5632, - 5376, 5376, 5376, 5376, 5568, 5632, 5632, 5632, 5376, - 5376, 5376, 5376, 5568, 5632, 5632, 5632, 5440, 5440, - 5440, 5440, 5632, 5632, 5632, 5632, 5440, 5440, 5440, - 5440, 5632, 5632, 5632, 5632, 5504, 5504, 5504, 5504, - 5632, 5632, 5632, 5632, 5504, 5504, 5504, 5504, 5632, - 5632, 5632, 5632, 5568, 5568, 5568, 5568, 5632, 5632, - 5632, 5632, 5568, 5568, 5568, 5568, 5632, 5632, 5632, - 5632 -}; - -static const int filterData2[1424] = { - 0, 2, 4, 6, 7, 9, 11, 13, 0, -2, -4, -6, -7, -9, -11, - -13, 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, - -11, -13, -15, 1, 3, 5, 7, 10, 12, 14, 16, -1, -3, -5, - -7, -10, -12, -14, -16, 1, 3, 6, 8, 11, 13, 16, 18, - -1, -3, -6, -8, -11, -13, -16, -18, 1, 4, 6, 9, 12, - 15, 17, 20, -1, -4, -6, -9, -12, -15, -17, -20, 1, 4, - 7, 10, 13, 16, 19, 22, -1, -4, -7, -10, -13, -16, -19, - -22, 1, 4, 8, 11, 14, 17, 21, 24, -1, -4, -8, -11, -14, - -17, -21, -24, 1, 5, 8, 12, 15, 19, 22, 26, -1, -5, - -8, -12, -15, -19, -22, -26, 2, 6, 10, 14, 18, 22, 26, - 30, -2, -6, -10, -14, -18, -22, -26, -30, 2, 6, 10, - 14, 19, 23, 27, 31, -2, -6, -10, -14, -19, -23, -27, - -31, 2, 7, 11, 16, 21, 26, 30, 35, -2, -7, -11, -16, - -21, -26, -30, -35, 2, 7, 13, 18, 23, 28, 34, 39, -2, - -7, -13, -18, -23, -28, -34, -39, 2, 8, 14, 20, 25, - 31, 37, 43, -2, -8, -14, -20, -25, -31, -37, -43, 3, - 9, 15, 21, 28, 34, 40, 46, -3, -9, -15, -21, -28, -34, - -40, -46, 3, 10, 17, 24, 31, 38, 45, 52, -3, -10, -17, - -24, -31, -38, -45, -52, 3, 11, 19, 27, 34, 42, 50, - 58, -3, -11, -19, -27, -34, -42, -50, -58, 4, 12, 21, - 29, 38, 46, 55, 63, -4, -12, -21, -29, -38, -46, -55, - -63, 4, 13, 23, 32, 41, 50, 60, 69, -4, -13, -23, -32, - -41, -50, -60, -69, 5, 15, 25, 35, 46, 56, 66, 76, -5, - -15, -25, -35, -46, -56, -66, -76, 5, 16, 28, 39, 50, - 61, 73, 84, -5, -16, -28, -39, -50, -61, -73, -84, 6, - 18, 31, 43, 56, 68, 81, 93, -6, -18, -31, -43, -56, - -68, -81, -93, 6, 20, 34, 48, 61, 75, 89, 103, -6, -20, - -34, -48, -61, -75, -89, -103, 7, 22, 37, 52, 67, 82, - 97, 112, -7, -22, -37, -52, -67, -82, -97, -112, 8, - 24, 41, 57, 74, 90, 107, 123, -8, -24, -41, -57, -74, - -90, -107, -123, 9, 27, 45, 63, 82, 100, 118, 136, -9, - -27, -45, -63, -82, -100, -118, -136, 10, 30, 50, 70, - 90, 110, 130, 150, -10, -30, -50, -70, -90, -110, -130, - -150, 11, 33, 55, 77, 99, 121, 143, 165, -11, -33, -55, - -77, -99, -121, -143, -165, 12, 36, 60, 84, 109, 133, - 157, 181, -12, -36, -60, -84, -109, -133, -157, -181, - 13, 40, 66, 93, 120, 147, 173, 200, -13, -40, -66, -93, - -120, -147, -173, -200, 14, 44, 73, 103, 132, 162, 191, - 221, -14, -44, -73, -103, -132, -162, -191, -221, 16, - 48, 81, 113, 146, 178, 211, 243, -16, -48, -81, -113, - -146, -178, -211, -243, 17, 53, 89, 125, 160, 196, 232, - 268, -17, -53, -89, -125, -160, -196, -232, -268, 19, - 58, 98, 137, 176, 215, 255, 294, -19, -58, -98, -137, - -176, -215, -255, -294, 21, 64, 108, 151, 194, 237, - 281, 324, -21, -64, -108, -151, -194, -237, -281, -324, - 23, 71, 118, 166, 213, 261, 308, 356, -23, -71, -118, - -166, -213, -261, -308, -356, 26, 78, 130, 182, 235, - 287, 339, 391, -26, -78, -130, -182, -235, -287, -339, - -391, 28, 86, 143, 201, 258, 316, 373, 431, -28, -86, - -143, -201, -258, -316, -373, -431, 31, 94, 158, 221, - 284, 347, 411, 474, -31, -94, -158, -221, -284, -347, - -411, -474, 34, 104, 174, 244, 313, 383, 453, 523, -34, - -104, -174, -244, -313, -383, -453, -523, 38, 115, 191, - 268, 345, 422, 498, 575, -38, -115, -191, -268, -345, - -422, -498, -575, 42, 126, 210, 294, 379, 463, 547, - 631, -42, -126, -210, -294, -379, -463, -547, -631, - 46, 139, 231, 324, 417, 510, 602, 695, -46, -139, -231, - -324, -417, -510, -602, -695, 51, 153, 255, 357, 459, - 561, 663, 765, -51, -153, -255, -357, -459, -561, -663, - -765, 56, 168, 280, 392, 505, 617, 729, 841, -56, -168, - -280, -392, -505, -617, -729, -841, 61, 185, 308, 432, - 555, 679, 802, 926, -61, -185, -308, -432, -555, -679, - -802, -926, 68, 204, 340, 476, 612, 748, 884, 1020, - -68, -204, -340, -476, -612, -748, -884, -1020, 74, - 224, 373, 523, 672, 822, 971, 1121, -74, -224, -373, - -523, -672, -822, -971, -1121, 82, 246, 411, 575, 740, - 904, 1069, 1233, -82, -246, -411, -575, -740, -904, - -1069, -1233, 90, 271, 452, 633, 814, 995, 1176, 1357, - -90, -271, -452, -633, -814, -995, -1176, -1357, 99, - 298, 497, 696, 895, 1094, 1293, 1492, -99, -298, -497, - -696, -895, -1094, -1293, -1492, 109, 328, 547, 766, - 985, 1204, 1423, 1642, -109, -328, -547, -766, -985, - -1204, -1423, -1642, 120, 361, 601, 842, 1083, 1324, - 1564, 1805, -120, -361, -601, -842, -1083, -1324, -1564, - -1805, 132, 397, 662, 927, 1192, 1457, 1722, 1987, -132, - -397, -662, -927, -1192, -1457, -1722, -1987, 145, 437, - 728, 1020, 1311, 1603, 1894, 2186, -145, -437, -728, - -1020, -1311, -1603, -1894, -2186, 160, 480, 801, 1121, - 1442, 1762, 2083, 2403, -160, -480, -801, -1121, -1442, - -1762, -2083, -2403, 176, 529, 881, 1234, 1587, 1940, - 2292, 2645, -176, -529, -881, -1234, -1587, -1940, -2292, - -2645, 194, 582, 970, 1358, 1746, 2134, 2522, 2910, - -194, -582, -970, -1358, -1746, -2134, -2522, -2910, - 213, 640, 1066, 1493, 1920, 2347, 2773, 3200, -213, - -640, -1066, -1493, -1920, -2347, -2773, -3200, 234, - 704, 1173, 1643, 2112, 2582, 3051, 3521, -234, -704, - -1173, -1643, -2112, -2582, -3051, -3521, 258, 774, - 1291, 1807, 2324, 2840, 3357, 3873, -258, -774, -1291, - -1807, -2324, -2840, -3357, -3873, 284, 852, 1420, 1988, - 2556, 3124, 3692, 4260, -284, -852, -1420, -1988, -2556, - -3124, -3692, -4260, 312, 937, 1561, 2186, 2811, 3436, - 4060, 4685, -312, -937, -1561, -2186, -2811, -3436, - -4060, -4685, 343, 1030, 1718, 2405, 3092, 3779, 4467, - 5154, -343, -1030, -1718, -2405, -3092, -3779, -4467, - -5154, 378, 1134, 1890, 2646, 3402, 4158, 4914, 5670, - -378, -1134, -1890, -2646, -3402, -4158, -4914, -5670, - 415, 1247, 2079, 2911, 3742, 4574, 5406, 6238, -415, - -1247, -2079, -2911, -3742, -4574, -5406, -6238, 457, - 1372, 2287, 3202, 4117, 5032, 5947, 6862, -457, -1372, - -2287, -3202, -4117, -5032, -5947, -6862, 503, 1509, - 2516, 3522, 4529, 5535, 6542, 7548, -503, -1509, -2516, - -3522, -4529, -5535, -6542, -7548, 553, 1660, 2767, - 3874, 4981, 6088, 7195, 8302, -553, -1660, -2767, -3874, - -4981, -6088, -7195, -8302, 608, 1826, 3044, 4262, 5479, - 6697, 7915, 9133, -608, -1826, -3044, -4262, -5479, - -6697, -7915, -9133, 669, 2009, 3348, 4688, 6027, 7367, - 8706, 10046, -669, -2009, -3348, -4688, -6027, -7367, - -8706, -10046, 736, 2210, 3683, 5157, 6630, 8104, 9577, - 11051, -736, -2210, -3683, -5157, -6630, -8104, -9577, - -11051, 810, 2431, 4052, 5673, 7294, 8915, 10536, 12157, - -810, -2431, -4052, -5673, -7294, -8915, -10536, -12157, - 891, 2674, 4457, 6240, 8023, 9806, 11589, 13372, -891, - -2674, -4457, -6240, -8023, -9806, -11589, -13372, 980, - 2941, 4903, 6864, 8825, 10786, 12748, 14709, -980, -2941, - -4903, -6864, -8825, -10786, -12748, -14709, 1078, 3236, - 5393, 7551, 9708, 11866, 14023, 16181, -1078, -3236, - -5393, -7551, -9708, -11866, -14023, -16181, 1186, 3559, - 5933, 8306, 10679, 13052, 15426, 17799, -1186, -3559, - -5933, -8306, -10679, -13052, -15426, -17799, 1305, - 3915, 6526, 9136, 11747, 14357, 16968, 19578, -1305, - -3915, -6526, -9136, -11747, -14357, -16968, -19578, - 1435, 4307, 7179, 10051, 12922, 15794, 18666, 21538, - -1435, -4307, -7179, -10051, -12922, -15794, -18666, - -21538, 1579, 4738, 7896, 11055, 14214, 17373, 20531, - 23690, -1579, -4738, -7896, -11055, -14214, -17373, - -20531, -23690, 1737, 5212, 8686, 12161, 15636, 19111, - 22585, 26060, -1737, -5212, -8686, -12161, -15636, -19111, - -22585, -26060, 1911, 5733, 9555, 13377, 17200, 21022, - 24844, 28666, -1911, -5733, -9555, -13377, -17200, -21022, - -24844, -28666, 2102, 6306, 10511, 14715, 18920, 23124, - 27329, 31533, -2102, -6306, -10511, -14715, -18920, - -23124, -27329, -31533, 2312, 6937, 11562, 16187, 20812, - 25437, 30062, 32767, -2312, -6937, -11562, -16187, -20812, - -25437, -30062, -32767, 2543, 7631, 12718, 17806, 22893, - 27981, 32767, 32767, -2543, -7631, -12718, -17806, -22893, - -27981, -32767, -32767, 2798, 8394, 13990, 19586, 25183, - 30779, 32767, 32767, -2798, -8394, -13990, -19586, -25183, - -30779, -32767, -32767, 3077, 9233, 15389, 21545, 27700, - 32767, 32767, 32767, -3077, -9233, -15389, -21545, -27700, - -32767, -32767, -32767, 3385, 10157, 16928, 23700, 30471, - 32767, 32767, 32767, -3385, -10157, -16928, -23700, - -30471, -32767, -32767, -32767, 3724, 11172, 18621, - 26069, 32767, 32767, 32767, 32767, -3724, -11172, -18621, - -26069, -32767, -32767, -32767, -32767, 4095, 12287, - 20479, 28671, 32767, 32767, 32767, 32767, -4095, -12287, - -20479, -28671, -32767, -32767, -32767, -32767 -}; - -static const int p1s[17] = { 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4, 0 }; -static const int p2s[17] = { 0, 1, 1, 3, 1, 5, 3, 7, 1, 9, 5, 11, 3, 13, 7, 15, 1 }; - -static void soundFilter(byte *data, int16 *buffer, int p1, int p2); - -void SoundQueue::applyFilter(SoundEntry *entry, int16 *buffer) { - if ((((byte *)entry->_soundData)[1] << 6) > 0x1600) { - entry->setStatus(entry->getStatus().status | kSoundStatus_20000000); - } else { - int variant = entry->getStatus().status & 0x1f; - - soundFilter((byte *)entry->_soundData, buffer, p1s[variant], p2s[variant]); - } -} - - -static void soundFilter(byte *data, int16 *buffer, int p1, int p2) { - int data1, data2, data1p, data2p; - byte idx; - - data2 = data[0]; - data1 = data[1] << 6; - - data += 2; - - for (int count = 0; count < 735; count++) { - idx = data[count] >> 4; - data1p = filterData[idx + data1]; - data2p = CLIP(filterData2[idx + data1] + data2, -32767, 32767); - - buffer[2 * count] = (p2 * data2p) >> p1; - - idx = data[count] & 0xF; - - data1 = filterData[idx + data1p]; - data2 = CLIP(filterData2[idx + data1p] + data2p, -32767, 32767); - buffer[2 * count + 1] = (p2 * data2) >> p1; - } -} - -////////////////////////////////////////////////////////////////////////// // Debug ////////////////////////////////////////////////////////////////////////// void SoundQueue::stopAllSound() { Common::StackLock locker(_mutex); for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) - (*i)->getStreamedSound()->stop(); + (*i)->getSoundStream()->stop(); } } // End of namespace LastExpress diff --git a/engines/lastexpress/sound/queue.h b/engines/lastexpress/sound/queue.h index 3748a266e0..75fe06883a 100644 --- a/engines/lastexpress/sound/queue.h +++ b/engines/lastexpress/sound/queue.h @@ -78,9 +78,6 @@ public: void setCurrentSubtitle(SubtitleEntry *entry) { _currentSubtitle = entry; } SubtitleEntry *getCurrentSubtitle() { return _currentSubtitle; } - // Cache - bool setupCache(SoundEntry *entry); - // Serializable void saveLoadWithSerializer(Common::Serializer &ser); uint32 count(); @@ -109,7 +106,6 @@ private: // Entries Common::List<SoundEntry *> _soundList; ///< List of all sound entries - Common::List<SoundEntry *> _soundCache; ///< List of entries with a data buffer void *_soundCacheData; // Subtitles @@ -117,12 +113,6 @@ private: Common::List<SubtitleEntry *> _subtitles; SubtitleEntry *_currentSubtitle; - // Filters - int32 _buffer[2940]; ///< Static sound buffer - - void removeFromCache(SoundEntry *entry); - void applyFilter(SoundEntry *entry, int16 *buffer); - friend class Debugger; }; diff --git a/engines/lastexpress/sound/sound.cpp b/engines/lastexpress/sound/sound.cpp index c726769495..c04b6d361f 100644 --- a/engines/lastexpress/sound/sound.cpp +++ b/engines/lastexpress/sound/sound.cpp @@ -162,13 +162,17 @@ bool SoundManager::playSoundWithSubtitles(Common::String filename, SoundFlag fla entry->setStatus(entry->getStatus().status | kSoundStatus_8000); } else { // Get subtitles name - while (filename.size() > 4) + uint32 size = filename.size(); + while (filename.size() > size - 4) filename.deleteLastChar(); entry->showSubtitle(filename); entry->updateState(); } + // Add entry to sound list + _queue->addToQueue(entry); + return (entry->getType() != kSoundTypeNone); } diff --git a/engines/lastexpress/sound/sound.h b/engines/lastexpress/sound/sound.h index 797e52646e..517543f470 100644 --- a/engines/lastexpress/sound/sound.h +++ b/engines/lastexpress/sound/sound.h @@ -64,7 +64,13 @@ public: // Accessors SoundQueue *getQueue() { return _queue; } - uint32 getData2() { return _data2; } + uint32 getData0() { return _data0; } + int32 getData1() { return _data1; } + int32 getData2() { return _data2; } + uint32 getLoopingSoundDuration() { return _loopingSoundDuration; } + + // Setters + void setData1(int32 data) { _data1 = data; } private: LastExpressEngine *_engine; @@ -78,8 +84,8 @@ private: // Unknown data uint32 _data0; - uint32 _data1; - uint32 _data2; + int32 _data1; + int32 _data2; }; } // End of namespace LastExpress diff --git a/engines/lure/disk.cpp b/engines/lure/disk.cpp index 9212508be0..552da73f18 100644 --- a/engines/lure/disk.cpp +++ b/engines/lure/disk.cpp @@ -98,7 +98,6 @@ void Disk::openFile(uint8 fileNum) { error("Could not open %s", sFilename); char buffer[7]; - uint32 bytesRead; // If it's the support file, then move to the correct language area @@ -130,7 +129,7 @@ void Disk::openFile(uint8 fileNum) { // Validate the header - bytesRead = _fileHandle->read(buffer, 6); + _fileHandle->read(buffer, 6); buffer[6] = '\0'; if (strcmp(buffer, HEADER_IDENT_STRING) != 0) error("The file %s was not a valid VGA file", sFilename); diff --git a/engines/lure/hotspots.cpp b/engines/lure/hotspots.cpp index 97fbaa72ae..f38bac6e12 100644 --- a/engines/lure/hotspots.cpp +++ b/engines/lure/hotspots.cpp @@ -763,7 +763,7 @@ void Hotspot::showMessage(uint16 messageId, uint16 destCharacterId) { MemoryBlock *data = res.messagesData(); Hotspot *hotspot; uint8 *msgData = (uint8 *) data->data(); - uint16 v2, idVal; + uint16 idVal; messageId &= 0x7fff; // Skip through header to find table for given character @@ -781,7 +781,6 @@ void Hotspot::showMessage(uint16 messageId, uint16 destCharacterId) { // Scan through secondary list uint16 *v = (uint16 *) (msgData + READ_LE_UINT16(msgData + idx + sizeof(uint16))); - v2 = 0; while ((idVal = READ_LE_UINT16(v)) != 0xffff) { ++v; if (READ_LE_UINT16(v) == messageId) break; diff --git a/engines/lure/sound.cpp b/engines/lure/sound.cpp index cf28e0bb74..85b86a8400 100644 --- a/engines/lure/sound.cpp +++ b/engines/lure/sound.cpp @@ -31,7 +31,9 @@ #include "common/endian.h" #include "audio/midiparser.h" +namespace Common { DECLARE_SINGLETON(Lure::SoundManager); +} namespace Lure { diff --git a/engines/made/detection.cpp b/engines/made/detection.cpp index e8c948af4e..1320daaf9d 100644 --- a/engines/made/detection.cpp +++ b/engines/made/detection.cpp @@ -542,7 +542,7 @@ public: virtual bool hasFeature(MetaEngineFeature f) const; virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; - const ADGameDescription *fallbackDetect(const Common::FSList &fslist, const FileMap &allFiles) const; + const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const; }; @@ -564,7 +564,7 @@ bool MadeMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGame return gd != 0; } -const ADGameDescription *MadeMetaEngine::fallbackDetect(const Common::FSList &fslist, const FileMap &allFiles) const { +const ADGameDescription *MadeMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const { // Set the default values for the fallback descriptor's ADGameDescription part. Made::g_fallbackDesc.desc.language = Common::UNK_LANG; Made::g_fallbackDesc.desc.platform = Common::kPlatformPC; diff --git a/engines/mohawk/console.cpp b/engines/mohawk/console.cpp index 05012bec3d..e7dc84606c 100644 --- a/engines/mohawk/console.cpp +++ b/engines/mohawk/console.cpp @@ -700,14 +700,25 @@ bool LivingBooksConsole::Cmd_DrawImage(int argc, const char **argv) { } bool LivingBooksConsole::Cmd_ChangePage(int argc, const char **argv) { - if (argc == 1) { - DebugPrintf("Usage: changePage <page> [<mode>]\n"); + if (argc < 2 || argc > 3) { + DebugPrintf("Usage: changePage <page>[.<subpage>] [<mode>]\n"); return true; } - if (_vm->tryLoadPageStart(argc == 2 ? _vm->getCurMode() : (LBMode)atoi(argv[2]), atoi(argv[1]))) - return false; - DebugPrintf("no such page %d\n", atoi(argv[1])); + int page, subpage = 0; + if (sscanf(argv[1], "%d.%d", &page, &subpage) == 0) { + DebugPrintf("Usage: changePage <page>[.<subpage>] [<mode>]\n"); + return true; + } + LBMode mode = argc == 2 ? _vm->getCurMode() : (LBMode)atoi(argv[2]); + if (subpage == 0) { + if (_vm->tryLoadPageStart(mode, page)) + return false; + } else { + if (_vm->loadPage(mode, page, subpage)) + return false; + } + DebugPrintf("no such page %d.%d\n", page, subpage); return true; } diff --git a/engines/mohawk/cursors.cpp b/engines/mohawk/cursors.cpp index 3284a3228f..78e099ccfe 100644 --- a/engines/mohawk/cursors.cpp +++ b/engines/mohawk/cursors.cpp @@ -252,6 +252,17 @@ void LivingBooksCursorManager_v2::setCursor(uint16 id) { } } +void LivingBooksCursorManager_v2::setCursor(const Common::String &name) { + if (!_sysArchive) + return; + + uint16 id = _sysArchive->findResourceID(ID_TCUR, name); + if (id == 0xffff) + error("Could not find cursor '%s'", name.c_str()); + else + setCursor(id); +} + PECursorManager::PECursorManager(const Common::String &appName) { _exe = new Common::PEResources(); diff --git a/engines/mohawk/cursors.h b/engines/mohawk/cursors.h index d92b6b4285..7bfa491904 100644 --- a/engines/mohawk/cursors.h +++ b/engines/mohawk/cursors.h @@ -56,6 +56,7 @@ public: virtual void showCursor(); virtual void hideCursor(); virtual void setCursor(uint16 id); + virtual void setCursor(const Common::String &name) {} virtual void setDefaultCursor(); virtual bool hasSource() const { return false; } @@ -157,6 +158,7 @@ public: ~LivingBooksCursorManager_v2(); void setCursor(uint16 id); + void setCursor(const Common::String &name); bool hasSource() const { return _sysArchive != 0; } private: diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h index 2243dd1c1d..01eac0aaba 100644 --- a/engines/mohawk/detection_tables.h +++ b/engines/mohawk/detection_tables.h @@ -1474,6 +1474,21 @@ static const MohawkGameDescription gameDescriptions[] = { 0 }, + { + { + "arthurrace", + "", + AD_ENTRY1("BookOutline", "f0a9251824a648fce1b49cb7c1a0ba67"), + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_UNSTABLE, + Common::GUIO_NONE + }, + GType_LIVINGBOOKSV3, + 0, + 0 + }, + // From zerep in bug #3287894 { { diff --git a/engines/mohawk/livingbooks.cpp b/engines/mohawk/livingbooks.cpp index 06500bc725..f9d18ff7ff 100644 --- a/engines/mohawk/livingbooks.cpp +++ b/engines/mohawk/livingbooks.cpp @@ -87,8 +87,14 @@ void LBPage::open(Archive *mhk, uint16 baseId) { _baseId = baseId; _vm->addArchive(_mhk); - if (_vm->hasResource(ID_BCOD, baseId)) + if (!_vm->hasResource(ID_BCOD, baseId)) { + // assume that BCOD is mandatory for v4/v5 + if (_vm->getGameType() == GType_LIVINGBOOKSV4 || _vm->getGameType() == GType_LIVINGBOOKSV5) + error("missing BCOD resource (id %d)", baseId); + _code = new LBCode(_vm, 0); + } else { _code = new LBCode(_vm, baseId); + } loadBITL(baseId); for (uint i = 0; i < _items.size(); i++) @@ -2300,8 +2306,6 @@ void LBItem::readData(uint16 type, uint16 size, Common::MemoryReadStreamEndian * { assert(size == 4); uint offset = stream->readUint32(); - if (!_page->_code) - error("no BCOD?"); _page->_code->runCode(this, offset); } break; @@ -2823,8 +2827,6 @@ int LBItem::runScriptEntry(LBScriptEntry *entry) { break; case kLBOpSendExpression: - if (!_page->_code) - error("no BCOD?"); _page->_code->runCode(this, entry->offset); break; @@ -2858,8 +2860,6 @@ int LBItem::runScriptEntry(LBScriptEntry *entry) { case kLBOpJumpUnlessExpression: case kLBOpBreakExpression: case kLBOpJumpToExpression: - if (!_page->_code) - error("no BCOD?"); { LBValue r = _page->_code->runCode(this, entry->offset); // FIXME @@ -2884,257 +2884,24 @@ void LBItem::setNextTime(uint16 min, uint16 max, uint32 start) { debug(9, "nextTime is now %d frames away", _nextTime - (uint)(_vm->_system->getMillis() / 16)); } -enum LBTokenType { - kLBNoToken, - kLBNameToken, - kLBStringToken, - kLBOperatorToken, - kLBIntegerToken, - kLBEndToken -}; - -static Common::String readToken(const Common::String &source, uint &pos, LBTokenType &type) { - Common::String token; - type = kLBNoToken; - - bool done = false; - while (pos < source.size() && !done) { - if (type == kLBStringToken) { - if (source[pos] == '"') { - pos++; - return token; - } - - token += source[pos]; - pos++; - continue; - } - - switch (source[pos]) { - case ' ': - pos++; - done = true; - break; - - case ')': - if (type == kLBNoToken) { - type = kLBEndToken; - return Common::String(); - } - done = true; - break; - - case ';': - if (type == kLBNoToken) { - pos++; - type = kLBEndToken; - return Common::String(); - } - done = true; - break; - - case '@': - // FIXME - error("found @ in string '%s', not supported yet", source.c_str()); - - case '+': - case '-': - case '!': - case '=': - case '>': - case '<': - if (type == kLBNoToken) - type = kLBOperatorToken; - if (type == kLBOperatorToken) - token += source[pos]; - else - done = true; - break; - - case '"': - if (type == kLBNoToken) - type = kLBStringToken; - else - done = true; - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (type == kLBNoToken) - type = kLBIntegerToken; - if (type == kLBNameToken || type == kLBIntegerToken) - token += source[pos]; - else - done = true; - break; - - default: - if (type == kLBNoToken) - type = kLBNameToken; - if (type == kLBNameToken) - token += source[pos]; - else - done = true; - break; - } - - if (!done) - pos++; - } - - if (type == kLBStringToken) - error("readToken: ran out of input while parsing string from '%s'", source.c_str()); - - if (!token.size()) { - assert(type == kLBNoToken); - type = kLBEndToken; - } - - return token; -} - -LBValue LBItem::parseValue(const Common::String &source, uint &pos) { - LBTokenType type, postOpType; - Common::String preOp, postOp; - - Common::String str = readToken(source, pos, type); - if (type == kLBOperatorToken) { - preOp = str; - str = readToken(source, pos, type); - } - - LBValue value; - if (type == kLBStringToken) { - value.type = kLBValueString; - value.string = str; - } else if (type == kLBIntegerToken) { - value.type = kLBValueInteger; - value.integer = atoi(str.c_str()); - } else if (type == kLBNameToken) { - value = _vm->_variables[str]; - } else { - error("expected string/integer as value in '%s', got '%s'", source.c_str(), str.c_str()); - } - - uint readAheadPos = pos; - postOp = readToken(source, readAheadPos, postOpType); - if (postOpType != kLBEndToken) { - if (postOpType != kLBOperatorToken) - error("expected operator after '%s' in '%s', got '%s'", str.c_str(), source.c_str(), postOp.c_str()); - // might be a comparison operator, caller will handle other cases if valid - if (postOp == "-" || postOp == "+") { - pos = readAheadPos; - LBValue nextValue = parseValue(source, pos); - if (value.type != kLBValueInteger || nextValue.type != kLBValueInteger) - error("expected integer for arthmetic operator in '%s'", source.c_str()); - if (postOp == "+") - value.integer += nextValue.integer; - else if (postOp == "-") - value.integer -= nextValue.integer; - } - } - - if (preOp.size()) { - if (preOp == "!") { - if (value.type == kLBValueInteger) - value.integer = !value.integer; - else - error("expected integer after ! operator in '%s'", source.c_str()); - } else { - error("expected valid operator before '%s' in '%s', got '%s'", str.c_str(), source.c_str(), preOp.c_str()); - } - } - - return value; -} - void LBItem::runCommand(const Common::String &command) { - uint pos = 0; - LBTokenType type; + LBCode tempCode(_vm, 0); debug(2, "running command '%s'", command.c_str()); - while (pos < command.size()) { - Common::String varname = readToken(command, pos, type); - if (type != kLBNameToken) - error("expected name as lvalue of command '%s', got '%s'", command.c_str(), varname.c_str()); - Common::String op = readToken(command, pos, type); - if (type != kLBOperatorToken || (op != "=" && op != "++" && op != "--")) - error("expected assignment/postincrement/postdecrement operator for command '%s', got '%s'", command.c_str(), op.c_str()); - - if (op == "=") { - LBValue value = parseValue(command, pos); - _vm->_variables[varname] = value; - } else { - if (_vm->_variables[varname].type != kLBValueInteger) - error("expected integer after postincrement/postdecrement operator in '%s'", command.c_str()); - if (op == "++") - _vm->_variables[varname].integer++; - else if (op == "--") - _vm->_variables[varname].integer--; - } - - if (pos < command.size() && command[pos] == ';') - pos++; - } + uint offset = tempCode.parseCode(command); + tempCode.runCode(this, offset); } bool LBItem::checkCondition(const Common::String &condition) { - uint pos = 0; - LBTokenType type; + LBCode tempCode(_vm, 0); debug(3, "checking condition '%s'", condition.c_str()); - if (condition.size() <= pos || condition[pos] != '(') - error("bad condition '%s' (started wrong)", condition.c_str()); - pos++; - - LBValue value1 = parseValue(condition, pos); - - Common::String op = readToken(condition, pos, type); - if (type == kLBEndToken) { - if (condition.size() != pos + 1 || condition[pos] != ')') - error("bad condition '%s' (ended wrong)", condition.c_str()); - - if (value1.type == kLBValueInteger) - return value1.integer; - else - error("expected comparison operator for condition '%s'", condition.c_str()); - } - if (type != kLBOperatorToken || (op != "!=" && op != "==" && op != ">" && op != "<" && op != ">=" && op != "<=")) - error("expected comparison operator for condition '%s', got '%s'", condition.c_str(), op.c_str()); - - LBValue value2 = parseValue(condition, pos); - - if (condition.size() != pos + 1 || condition[pos] != ')') - error("bad condition '%s' (ended wrong)", condition.c_str()); - - if (op == "!=") - return (value1 != value2); - else if (op == "==") - return (value1 == value2); - - if (value1.type != kLBValueInteger || value2.type != kLBValueInteger) - error("evaluation operator %s in condition '%s' expected two integer operands!", op.c_str(), condition.c_str()); - - if (op == ">") - return (value1.integer > value2.integer); - else if (op == ">=") - return (value1.integer >= value2.integer); - else if (op == "<") - return (value1.integer < value2.integer); - else if (op == "<=") - return (value1.integer <= value2.integer); + uint offset = tempCode.parseCode(condition); + LBValue result = tempCode.runCode(this, offset); - return false; // unreachable + return result.toInt(); } LBSoundItem::LBSoundItem(MohawkEngine_LivingBooks *vm, LBPage *page, Common::Rect rect) : LBItem(vm, page, rect) { diff --git a/engines/mohawk/livingbooks.h b/engines/mohawk/livingbooks.h index ed198a60c1..ad2fe56a52 100644 --- a/engines/mohawk/livingbooks.h +++ b/engines/mohawk/livingbooks.h @@ -434,7 +434,6 @@ protected: void runScript(uint event, uint16 data = 0, uint16 from = 0); int runScriptEntry(LBScriptEntry *entry); - LBValue parseValue(const Common::String &command, uint &pos); void runCommand(const Common::String &command); bool checkCondition(const Common::String &condition); @@ -689,6 +688,7 @@ public: LBMode getCurMode() { return _curMode; } bool tryLoadPageStart(LBMode mode, uint page); + bool loadPage(LBMode mode, uint page, uint subpage); void prevPage(); void nextPage(); @@ -717,7 +717,6 @@ private: Common::Queue<DelayedEvent> _eventQueue; LBItem *_focus; void destroyPage(); - bool loadPage(LBMode mode, uint page, uint subpage); void updatePage(); uint16 _lastSoundOwner, _lastSoundId; diff --git a/engines/mohawk/livingbooks_code.cpp b/engines/mohawk/livingbooks_code.cpp index e72318d86a..e9ef2516e2 100644 --- a/engines/mohawk/livingbooks_code.cpp +++ b/engines/mohawk/livingbooks_code.cpp @@ -127,6 +127,12 @@ Common::Rect LBValue::toRect() const { } LBCode::LBCode(MohawkEngine_LivingBooks *vm, uint16 baseId) : _vm(vm) { + if (!baseId) { + _data = NULL; + _size = 0; + return; + } + Common::SeekableSubReadStreamEndian *bcodStream = _vm->wrapStreamEndian(ID_BCOD, baseId); uint32 totalSize = bcodStream->readUint32(); @@ -172,12 +178,8 @@ LBValue LBCode::runCode(LBItem *src, uint32 offset) { } void LBCode::nextToken() { - if (_currOffset + 1 >= _size) { - // TODO - warning("went off the end of code"); - _currToken = kTokenEndOfFile; - _currValue = LBValue(); - return; + if (_currOffset >= _size) { + error("went off the end of code"); } _currToken = _data[_currOffset++]; @@ -186,6 +188,8 @@ void LBCode::nextToken() { switch (_currToken) { case kTokenIdentifier: { + if (_currOffset + 2 > _size) + error("went off the end of code reading identifier"); uint16 offset = READ_BE_UINT16(_data + _currOffset); // TODO: check string exists _currValue = _strings[offset]; @@ -195,9 +199,13 @@ void LBCode::nextToken() { case kTokenLiteral: { + if (_currOffset + 1 > _size) + error("went off the end of code reading literal"); byte literalType = _data[_currOffset++]; switch (literalType) { case kLBCodeLiteralInteger: + if (_currOffset + 2 > _size) + error("went off the end of code reading literal integer"); _currValue = READ_BE_UINT16(_data + _currOffset); _currOffset += 2; break; @@ -211,6 +219,8 @@ void LBCode::nextToken() { case kTokenConstEventId: case 0x5e: // TODO: ?? case kTokenKeycode: + if (_currOffset + 2 > _size) + error("went off the end of code reading immediate"); _currValue = READ_BE_UINT16(_data + _currOffset); _currOffset += 2; break; @@ -227,6 +237,8 @@ void LBCode::nextToken() { case kTokenString: { + if (_currOffset + 2 > _size) + error("went off the end of code reading string"); uint16 offset = READ_BE_UINT16(_data + _currOffset); // TODO: check string exists _currValue = _strings[offset]; @@ -265,27 +277,27 @@ LBValue LBCode::runCode(byte terminator) { void LBCode::parseStatement() { parseComparisons(); - if (_currToken != kTokenAnd && _currToken != kTokenOr) - return; - byte op = _currToken; - if (op == kTokenAnd) - debugN(" && "); - else - debugN(" || "); + while (_currToken == kTokenAnd || _currToken == kTokenOr) { + byte op = _currToken; + if (op == kTokenAnd) + debugN(" && "); + else + debugN(" || "); - nextToken(); - parseComparisons(); + nextToken(); + parseComparisons(); - LBValue val2 = _stack.pop(); - LBValue val1 = _stack.pop(); - bool result; - if (op == kTokenAnd) - result = !val1.isZero() && !val2.isZero(); - else - result = !val1.isZero() || !val2.isZero(); + LBValue val2 = _stack.pop(); + LBValue val1 = _stack.pop(); + bool result; + if (op == kTokenAnd) + result = !val1.isZero() && !val2.isZero(); + else + result = !val1.isZero() || !val2.isZero(); - debugN(" [--> %s]", result ? "true" : "false"); - _stack.push(result); + debugN(" [--> %s]", result ? "true" : "false"); + _stack.push(result); + } } void LBCode::parseComparisons() { @@ -353,49 +365,95 @@ void LBCode::parseComparisons() { void LBCode::parseConcat() { parseArithmetic1(); - if (_currToken != kTokenConcat) - return; - - debugN(" & "); - nextToken(); - parseArithmetic1(); + while (_currToken == kTokenConcat) { + debugN(" & "); + nextToken(); + parseArithmetic1(); - LBValue val2 = _stack.pop(); - LBValue val1 = _stack.pop(); - Common::String result = val1.toString() + val2.toString(); - debugN(" [--> \"%s\"]", result.c_str()); - _stack.push(result); + LBValue val2 = _stack.pop(); + LBValue val1 = _stack.pop(); + Common::String result = val1.toString() + val2.toString(); + debugN(" [--> \"%s\"]", result.c_str()); + _stack.push(result); + } } void LBCode::parseArithmetic1() { parseArithmetic2(); - if (_currToken != kTokenMinus && _currToken != kTokenPlus) - return; - - byte op = _currToken; - if (op == kTokenMinus) - debugN(" - "); - else if (op == kTokenPlus) - debugN(" + "); + while (_currToken == kTokenMinus || _currToken == kTokenPlus) { + byte op = _currToken; + if (op == kTokenMinus) + debugN(" - "); + else if (op == kTokenPlus) + debugN(" + "); - nextToken(); - parseArithmetic2(); - - LBValue val2 = _stack.pop(); - LBValue val1 = _stack.pop(); - LBValue result; - // TODO: cope with non-integers - if (op == kTokenMinus) - result = val1.toInt() - val2.toInt(); - else - result = val1.toInt() + val2.toInt(); - _stack.push(result); + nextToken(); + parseArithmetic2(); + + LBValue val2 = _stack.pop(); + LBValue val1 = _stack.pop(); + LBValue result; + // TODO: cope with non-integers + if (op == kTokenMinus) + result = val1.toInt() - val2.toInt(); + else + result = val1.toInt() + val2.toInt(); + debugN(" [--> %d]", result.toInt()); + _stack.push(result); + } } void LBCode::parseArithmetic2() { - // FIXME: other math operators parseMain(); + + while (true) { + byte op = _currToken; + switch (op) { + case kTokenMultiply: + debugN(" * "); + break; + case kTokenDivide: + debugN(" / "); + break; + case kTokenIntDivide: + debugN(" div "); + break; + case kTokenModulo: + debugN(" %% "); + break; + default: + return; + } + + nextToken(); + parseMain(); + + LBValue val2 = _stack.pop(); + LBValue val1 = _stack.pop(); + LBValue result; + // TODO: cope with non-integers + if (op == kTokenMultiply) { + result = val1.toInt() * val2.toInt(); + } else if (val2.toInt() == 0) { + result = 1; + } else { + switch (op) { + case kTokenDivide: + // TODO: fp divide + result = val1.toInt() / val2.toInt(); + break; + case kTokenIntDivide: + result = val1.toInt() / val2.toInt(); + break; + case kTokenModulo: + result = val1.toInt() % val2.toInt(); + break; + } + } + + _stack.push(result); + } } void LBCode::parseMain() { @@ -549,6 +607,16 @@ void LBCode::parseMain() { } } +LBItem *LBCode::resolveItem(const LBValue &value) { + if (value.type == kLBValueItemPtr) + return value.item; + if (value.type == kLBValueString) + return _vm->getItemByName(value.string); + if (value.type == kLBValueInteger) + return _vm->getItemById(value.integer); + return NULL; +} + Common::Array<LBValue> LBCode::readParams() { Common::Array<LBValue> params; @@ -616,8 +684,8 @@ struct CodeCommandInfo { #define NUM_GENERAL_COMMANDS 129 CodeCommandInfo generalCommandInfo[NUM_GENERAL_COMMANDS] = { - { "eval", 0 }, - { "random", 0 }, + { "eval", &LBCode::cmdEval }, + { "random", &LBCode::cmdRandom }, { "stringLen", 0 }, { "substring", 0 }, { "max", 0 }, @@ -773,6 +841,26 @@ void LBCode::cmdUnimplemented(const Common::Array<LBValue> ¶ms) { warning("unimplemented command called"); } +void LBCode::cmdEval(const Common::Array<LBValue> ¶ms) { + // FIXME: v4 eval is different? + if (params.size() != 1) + error("incorrect number of parameters (%d) to eval", params.size()); + + LBCode tempCode(_vm, 0); + + uint offset = tempCode.parseCode(params[0].toString()); + _stack.push(tempCode.runCode(_currSource, offset)); +} + +void LBCode::cmdRandom(const Common::Array<LBValue> ¶ms) { + if (params.size() != 2) + error("incorrect number of parameters (%d) to random", params.size()); + + int min = params[0].toInt(); + int max = params[1].toInt(); + _stack.push(_vm->_rnd->getRandomNumberRng(min, max)); +} + void LBCode::cmdGetRect(const Common::Array<LBValue> ¶ms) { if (params.size() < 2) { _stack.push(getRectFromParams(params)); @@ -915,7 +1003,7 @@ CodeCommandInfo itemCommandInfo[NUM_ITEM_COMMANDS] = { { "moveTo", &LBCode::itemMoveTo }, { "mute", 0 }, { "play", 0 }, - { "seek", 0 }, + { "seek", &LBCode::itemSeek }, { "seekToFrame", 0 }, { "setParent", &LBCode::itemSetParent }, { "setZOrder", 0 }, @@ -951,6 +1039,17 @@ void LBCode::itemMoveTo(const Common::Array<LBValue> ¶ms) { warning("ignoring moveTo"); } +void LBCode::itemSeek(const Common::Array<LBValue> ¶ms) { + if (params.size() != 2) + error("incorrect number of parameters (%d) to seek", params.size()); + + LBItem *item = resolveItem(params[0]); + if (!item) + error("attempted seek on invalid item (%s)", params[0].toString().c_str()); + uint seekTo = params[1].toInt(); + item->seek(seekTo); +} + void LBCode::itemSetParent(const Common::Array<LBValue> ¶ms) { if (params.size() > 2) error("incorrect number of parameters (%d) to setParent", params.size()); @@ -1035,4 +1134,278 @@ void LBCode::runNotifyCommand() { } } +/* + * Helper function for parseCode/parseCodeSymbol: + * Returns an unused string id. + */ +uint LBCode::nextFreeString() { + for (uint i = 0; i <= 0xffff; i++) { + if (!_strings.contains(i)) + return i; + } + + error("nextFreeString couldn't find a space"); +} + +/* + * Helper function for parseCode: + * Given a name, appends the appropriate data to the provided code array and + * returns true if it's a function, or false otherwise. + */ +bool LBCode::parseCodeSymbol(const Common::String &name, uint &pos, Common::Array<byte> &code) { + // first, check whether the name matches a known function + for (uint i = 0; i < 2; i++) { + byte cmdToken; + CodeCommandInfo *cmdInfo; + uint cmdCount; + + switch (i) { + case 0: + cmdInfo = generalCommandInfo; + cmdToken = kTokenGeneralCommand; + cmdCount = NUM_GENERAL_COMMANDS; + break; + case 1: + cmdInfo = itemCommandInfo; + cmdToken = kTokenItemCommand; + cmdCount = NUM_ITEM_COMMANDS; + break; + } + + for (uint n = 0; n < cmdCount; n++) { + const char *cmdName = cmdInfo[n].name; + if (!cmdName) + continue; + if (!name.equalsIgnoreCase(cmdName)) + continue; + + // found a matching function + code.push_back(cmdToken); + code.push_back(n + 1); + return true; + } + } + + // not a function, so must be an identifier + code.push_back(kTokenIdentifier); + + uint stringId = nextFreeString(); + _strings[stringId] = name; + + char tmp[2]; + WRITE_BE_UINT16(tmp, (int16)stringId); + code.push_back(tmp[0]); + code.push_back(tmp[1]); + + return false; +} + +/* + * Parse a string for later execution, and return the offset where it was + * stored. + */ +uint LBCode::parseCode(const Common::String &source) { + struct LBCodeOperator { + byte token; + byte op; + byte lookahead1; + byte lookahead1Op; + byte lookahead2; + byte lookahead2Op; + }; + + #define NUM_LB_OPERATORS 11 + static const LBCodeOperator operators[NUM_LB_OPERATORS] = { + { '+', kTokenPlus, '+', kTokenPlusPlus, '=', kTokenPlusEquals }, + { '-', kTokenMinus, '-', kTokenMinusMinus, '=', kTokenMinusEquals }, + { '/', kTokenDivide, '=', kTokenDivideEquals, 0, 0 }, + { '*', kTokenMultiply, '=', kTokenMultiplyEquals, 0, 0 }, + { '=', kTokenAssign, '=', kTokenEquals, 0, 0 }, + { '>', kTokenGreaterThan, '=', kTokenGreaterThanEq, 0, 0 }, + { '<', kTokenLessThan, '=', kTokenLessThanEq, 0, 0 }, + { '!', kTokenNot, '=', kTokenNotEq, 0, 0 }, + { '&', kTokenConcat, '&', kTokenAnd, '=', kTokenAndEquals }, + { '|', 0, '|', kTokenOr, 0, 0 }, + { ';', kTokenEndOfStatement, 0, 0, 0, 0 } + }; + + uint pos = 0; + Common::Array<byte> code; + Common::Array<uint> counterPositions; + bool wasFunction = false; + + while (pos < source.size()) { + byte token = source[pos]; + byte lookahead = 0; + if (pos + 1 < source.size()) + lookahead = source[pos + 1]; + pos++; + + if (token != ' ' && token != '(' && wasFunction) + error("while parsing script '%s', encountered incomplete function call", source.c_str()); + + // First, we check for simple operators. + for (uint i = 0; i < NUM_LB_OPERATORS; i++) { + if (token != operators[i].token) + continue; + if (lookahead) { + if (lookahead == operators[i].lookahead1) { + code.push_back(operators[i].lookahead1Op); + token = 0; + } else if (lookahead == operators[i].lookahead2) { + code.push_back(operators[i].lookahead2Op); + token = 0; + } + if (!token) { + pos++; + break; + } + } + if (operators[i].op) { + code.push_back(operators[i].op); + token = 0; + } + break; + } + if (!token) + continue; + + // Then, we check for more complex tokens. + switch (token) { + // whitespace + case ' ': + // ignore + break; + // literal string + case '"': + case '\'': + { + Common::String tempString; + while (pos < source.size()) { + if (source[pos] == token) + break; + tempString += source[pos++]; + } + if (pos++ == source.size()) + error("while parsing script '%s', string had no end", source.c_str()); + + code.push_back(kTokenString); + + uint stringId = nextFreeString(); + _strings[stringId] = tempString; + + char tmp[2]; + WRITE_BE_UINT16(tmp, (int16)stringId); + code.push_back(tmp[0]); + code.push_back(tmp[1]); + } + break; + // open bracket + case '(': + if (wasFunction) { + // function call parameters + wasFunction = false; + // we will need to back-patch the parameter count, + // if parameters are encountered + counterPositions.push_back(code.size()); + code.push_back(1); + // if the next token is a ) then there are no + // parameters, otherwise start with 1 and increment + // if/when we encounter commas + for (uint i = pos; i < source.size(); i++) { + if (source[i] == ' ') + continue; + if (source[i] != ')') + break; + code[code.size() - 1] = 0; + break; + } + } else { + // brackets around expression + counterPositions.push_back(0); + } + code.push_back(kTokenOpenBracket); + break; + // close bracket + case ')': + if (counterPositions.empty()) + error("while parsing script '%s', encountered unmatched )", source.c_str()); + counterPositions.pop_back(); + code.push_back(kTokenCloseBracket); + break; + // comma (seperating function params) + case ',': + { + if (counterPositions.empty()) + error("while parsing script '%s', encountered unexpected ,", source.c_str()); + code.push_back(kTokenComma); + uint counterPos = counterPositions.back(); + if (!counterPos) + error("while parsing script '%s', encountered , outside parameter list", source.c_str()); + code[counterPos]++; + } + break; + // old-style explicit function call + case '@': + { + Common::String tempString; + while (pos < source.size()) { + if (!isalpha(source[pos]) && !isdigit(source[pos])) + break; + tempString += source[pos++]; + } + wasFunction = parseCodeSymbol(tempString, pos, code); + if (!wasFunction) + error("while parsing script '%s', encountered explicit function call to unknown function '%s'", + source.c_str(), tempString.c_str()); + } + break; + default: + if (isdigit(token)) { + const char *in = source.c_str() + pos - 1; + // FIXME: handle floats? + char *endptr; + long int intValue = strtol(in, &endptr, 0); + assert(endptr > in); + pos += (endptr - in) - 1; + + // FIXME: handle storing longs if needed + code.push_back(kTokenLiteral); + code.push_back(kLBCodeLiteralInteger); + char tmp[2]; + WRITE_BE_UINT16(tmp, (int16)intValue); + code.push_back(tmp[0]); + code.push_back(tmp[1]); + } else if (isalpha(token)) { + Common::String tempString; + tempString += token; + while (pos < source.size()) { + if (!isalpha(source[pos]) && !isdigit(source[pos])) + break; + tempString += source[pos++]; + } + wasFunction = parseCodeSymbol(tempString, pos, code); + } else { + error("while parsing script '%s', couldn't parse '%c'", source.c_str(), token); + } + } + } + + if (wasFunction) + error("while parsing script '%s', encountered incomplete function call", source.c_str()); + if (counterPositions.size()) + error("while parsing script '%s', unmatched (", source.c_str()); + + code.push_back(kTokenEndOfFile); + + uint codeOffset = _size; + byte *newData = new byte[_size + code.size()]; + memcpy(newData, _data, _size); + memcpy(newData, &code[0], code.size()); + delete[] _data; + _data = newData; + _size += code.size(); + return codeOffset; +} + } // End of namespace Mohawk diff --git a/engines/mohawk/livingbooks_code.h b/engines/mohawk/livingbooks_code.h index 9602e2d22d..9c58ed7a46 100644 --- a/engines/mohawk/livingbooks_code.h +++ b/engines/mohawk/livingbooks_code.h @@ -181,6 +181,7 @@ public: ~LBCode(); LBValue runCode(LBItem *src, uint32 offset); + uint parseCode(const Common::String &source); protected: MohawkEngine_LivingBooks *_vm; @@ -206,6 +207,7 @@ protected: void parseArithmetic2(); void parseMain(); + LBItem *resolveItem(const LBValue &value); Common::Array<LBValue> readParams(); Common::Rect getRectFromParams(const Common::Array<LBValue> ¶ms); @@ -213,8 +215,13 @@ protected: void runItemCommand(); void runNotifyCommand(); + uint nextFreeString(); + bool parseCodeSymbol(const Common::String &name, uint &pos, Common::Array<byte> &code); + public: void cmdUnimplemented(const Common::Array<LBValue> ¶ms); + void cmdEval(const Common::Array<LBValue> ¶ms); + void cmdRandom(const Common::Array<LBValue> ¶ms); void cmdGetRect(const Common::Array<LBValue> ¶ms); void cmdTopLeft(const Common::Array<LBValue> ¶ms); void cmdBottomRight(const Common::Array<LBValue> ¶ms); @@ -228,9 +235,10 @@ public: void cmdSetHitTest(const Common::Array<LBValue> ¶ms); void cmdKey(const Common::Array<LBValue> ¶ms); - void itemSetParent(const Common::Array<LBValue> ¶ms); - void itemMoveTo(const Common::Array<LBValue> ¶ms); void itemIsPlaying(const Common::Array<LBValue> ¶ms); + void itemMoveTo(const Common::Array<LBValue> ¶ms); + void itemSeek(const Common::Array<LBValue> ¶ms); + void itemSetParent(const Common::Array<LBValue> ¶ms); }; } // End of namespace Mohawk diff --git a/engines/mohawk/myst_scripts.cpp b/engines/mohawk/myst_scripts.cpp index 17f6de534f..307be2dd05 100644 --- a/engines/mohawk/myst_scripts.cpp +++ b/engines/mohawk/myst_scripts.cpp @@ -560,6 +560,7 @@ void MystScriptParser::o_playSoundBlocking(uint16 op, uint16 var, uint16 argc, u debugC(kDebugScript, "Opcode %d: playSoundBlocking", op); debugC(kDebugScript, "\tsoundId: %d", soundId); + _vm->_sound->stopSound(); _vm->_sound->playSoundBlocking(soundId); } diff --git a/engines/mohawk/myst_stacks/mechanical.cpp b/engines/mohawk/myst_stacks/mechanical.cpp index d6dd1b5407..12d9dc7e2f 100644 --- a/engines/mohawk/myst_stacks/mechanical.cpp +++ b/engines/mohawk/myst_stacks/mechanical.cpp @@ -102,6 +102,7 @@ void Mechanical::setupOpcodes() { void Mechanical::disablePersistentScripts() { _fortressSimulationRunning = false; + _elevatorRotationLeverMoving = false; _elevatorGoingMiddle = false; _birdSinging = false; _fortressRotationRunning = false; @@ -126,10 +127,10 @@ void Mechanical::runPersistentScripts() { uint16 Mechanical::getVar(uint16 var) { switch(var) { - case 0: // Sirrus's Secret Panel State - return _state.sirrusPanelState; - case 1: // Achenar's Secret Panel State + case 0: // Achenar's Secret Panel State return _state.achenarPanelState; + case 1: // Sirrus's Secret Panel State + return _state.sirrusPanelState; case 2: // Achenar's Secret Room Crate Lid Open and Blue Page Present if (_state.achenarCrateOpened) { if (_globals.bluePagesInBook & 4 || _globals.heldPage == 3) @@ -195,16 +196,21 @@ uint16 Mechanical::getVar(uint16 var) { void Mechanical::toggleVar(uint16 var) { switch(var) { - case 0: // Sirrus's Secret Panel State - _state.sirrusPanelState ^= 1; - case 1: // Achenar's Secret Panel State + case 0: // Achenar's Secret Panel State _state.achenarPanelState ^= 1; + break; + case 1: // Sirrus's Secret Panel State + _state.sirrusPanelState ^= 1; + break; case 3: // Achenar's Secret Room Crate State _state.achenarCrateOpened ^= 1; + break; case 4: // Myst Book Room Staircase State _mystStaircaseState ^= 1; + break; case 10: // Fortress Staircase State _state.staircaseState ^= 1; + break; case 16: // Code Lock Shape #1 - Left case 17: // Code Lock Shape #2 case 18: // Code Lock Shape #3 @@ -242,6 +248,7 @@ bool Mechanical::setVarValue(uint16 var, uint16 value) { switch (var) { case 13: _elevatorPosition = value; + break; case 14: // Elevator going down when at top _elevatorGoingDown = value; break; @@ -724,6 +731,7 @@ void Mechanical::birdSing_run() { uint32 time = _vm->_system->getMillis(); if (_birdSingEndTime < time) { _bird->pauseMovie(true); + _vm->_sound->stopSound(); _birdSinging = false; } } diff --git a/engines/mohawk/resource.cpp b/engines/mohawk/resource.cpp index 9b39692958..f01375bacf 100644 --- a/engines/mohawk/resource.cpp +++ b/engines/mohawk/resource.cpp @@ -294,7 +294,7 @@ bool MohawkArchive::openStream(Common::SeekableReadStream *stream) { // We need to do this because of the way Mohawk is set up (this is much more "proper" // than passing _stream at the right offset). We may want to do that in the future, though. if (tag == ID_TMOV) { - if (index == fileTable.size() - 1) + if (index == fileTable.size()) res.size = stream->size() - fileTable[index - 1].offset; else res.size = fileTable[index].offset - fileTable[index - 1].offset; @@ -304,7 +304,6 @@ bool MohawkArchive::openStream(Common::SeekableReadStream *stream) { debug(4, "Entry[%02x]: ID = %04x (%d) Index = %04x", j, id, id, index); } - // Return to next TypeTable entry stream->seek(absOffset + (i + 1) * 8 + 4); diff --git a/engines/mohawk/sound.cpp b/engines/mohawk/sound.cpp index 6144c89e21..791b18db49 100644 --- a/engines/mohawk/sound.cpp +++ b/engines/mohawk/sound.cpp @@ -141,6 +141,19 @@ Audio::SoundHandle *Sound::replaceSoundMyst(uint16 id, byte volume, bool loop) { && name.equals(_vm->getResourceName(ID_MSND, convertMystID(_handles[i].id)))) return &_handles[i].handle; + // The original engine also forces looping for those sounds + switch (id) { + case 2205: + case 2207: + case 5378: + case 7220: + case 9119: // Elevator engine sound in mechanical age is looping. + case 9120: + case 9327: + loop = true; + break; + } + stopSound(); return playSound(id, volume, loop); } diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index 2f86f3693b..3eea1e871a 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -28,6 +28,7 @@ #include "common/hashmap.h" #include "common/hash-str.h" #include "common/stream.h" +#include "common/array.h" #include "graphics/surface.h" diff --git a/engines/savestate.cpp b/engines/savestate.cpp index 551c39b880..0b187ce630 100644 --- a/engines/savestate.cpp +++ b/engines/savestate.cpp @@ -24,49 +24,34 @@ #include "graphics/surface.h" #include "common/textconsole.h" -void SaveStateDescriptor::setThumbnail(Graphics::Surface *t) { - if (_thumbnail.get() == t) - return; - - _thumbnail = Common::SharedPtr<Graphics::Surface>(t, Graphics::SharedPtrSurfaceDeleter()); +SaveStateDescriptor::SaveStateDescriptor() + // FIXME: default to 0 (first slot) or to -1 (invalid slot) ? + : _slot(-1), _description(), _isDeletable(true), _isWriteProtected(false), + _saveDate(), _saveTime(), _playTime(), _thumbnail() { } -bool SaveStateDescriptor::getBool(const Common::String &key) const { - if (contains(key)) { - const Common::String value = getVal(key); - bool valueAsBool; - if (Common::parseBool(value, valueAsBool)) - return valueAsBool; - error("SaveStateDescriptor: %s '%s' has unknown value '%s' for boolean '%s'", - save_slot().c_str(), description().c_str(), value.c_str(), key.c_str()); - } - return false; +SaveStateDescriptor::SaveStateDescriptor(int s, const Common::String &d) + : _slot(s), _description(d), _isDeletable(true), _isWriteProtected(false), + _saveDate(), _saveTime(), _playTime(), _thumbnail() { } -void SaveStateDescriptor::setDeletableFlag(bool state) { - setVal("is_deletable", state ? "true" : "false"); -} +void SaveStateDescriptor::setThumbnail(Graphics::Surface *t) { + if (_thumbnail.get() == t) + return; -void SaveStateDescriptor::setWriteProtectedFlag(bool state) { - setVal("is_write_protected", state ? "true" : "false"); + _thumbnail = Common::SharedPtr<Graphics::Surface>(t, Graphics::SharedPtrSurfaceDeleter()); } void SaveStateDescriptor::setSaveDate(int year, int month, int day) { - Common::String buffer; - buffer = Common::String::format("%.2d.%.2d.%.4d", day, month, year); - setVal("save_date", buffer); + _saveDate = Common::String::format("%.2d.%.2d.%.4d", day, month, year); } void SaveStateDescriptor::setSaveTime(int hour, int min) { - Common::String buffer; - buffer = Common::String::format("%.2d:%.2d", hour, min); - setVal("save_time", buffer); + _saveTime = Common::String::format("%.2d:%.2d", hour, min); } void SaveStateDescriptor::setPlayTime(int hours, int minutes) { - Common::String buffer; - buffer = Common::String::format("%.2d:%.2d", hours, minutes); - setVal("play_time", buffer); + _playTime = Common::String::format("%.2d:%.2d", hours, minutes); } void SaveStateDescriptor::setPlayTime(uint32 msecs) { diff --git a/engines/savestate.h b/engines/savestate.h index df01732058..6cbdb22edf 100644 --- a/engines/savestate.h +++ b/engines/savestate.h @@ -24,7 +24,7 @@ #define ENGINES_SAVESTATE_H #include "common/array.h" -#include "common/hash-str.h" +#include "common/str.h" #include "common/ptr.h" @@ -33,65 +33,60 @@ struct Surface; } /** - * A hashmap describing details about a given save state. - * TODO - * Guaranteed to contain save_slot and description values. - * Additional ideas: Playtime, creation date, thumbnail, ... + * Object describing a save state. + * + * This at least includes the save slot number and a human readable + * description of the save state. + * + * Further possibilites are a thumbnail, play time, creation date, + * creation time, delete protected, write protection. */ -class SaveStateDescriptor : public Common::StringMap { -protected: - Common::SharedPtr<Graphics::Surface> _thumbnail; // can be 0 - +class SaveStateDescriptor { public: - SaveStateDescriptor() : _thumbnail() { - setVal("save_slot", "-1"); // FIXME: default to 0 (first slot) or to -1 (invalid slot) ? - setVal("description", ""); - } - - SaveStateDescriptor(int s, const Common::String &d) : _thumbnail() { - setVal("save_slot", Common::String::format("%d", s)); - setVal("description", d); - } + SaveStateDescriptor(); + SaveStateDescriptor(int s, const Common::String &d); - SaveStateDescriptor(const Common::String &s, const Common::String &d) : _thumbnail() { - setVal("save_slot", s); - setVal("description", d); - } - - /** The saveslot id, as it would be passed to the "-x" command line switch. */ - Common::String &save_slot() { return getVal("save_slot"); } + /** + * @param slot The saveslot id, as it would be passed to the "-x" command line switch. + */ + void setSaveSlot(int slot) { _slot = slot; } - /** The saveslot id, as it would be passed to the "-x" command line switch (read-only variant). */ - const Common::String &save_slot() const { return getVal("save_slot"); } + /** + * @return The saveslot id, as it would be passed to the "-x" command line switch. + */ + int getSaveSlot() const { return _slot; } - /** A human readable description of the save state. */ - Common::String &description() { return getVal("description"); } + /** + * @param desc A human readable description of the save state. + */ + void setDescription(const Common::String &desc) { _description = desc; } - /** A human readable description of the save state (read-only variant). */ - const Common::String &description() const { return getVal("description"); } + /** + * @return A human readable description of the save state. + */ + const Common::String &getDescription() const { return _description; } /** Optional entries only included when querying via MetaEngine::querySaveMetaInfo */ /** - * Returns the value of a given key as boolean. - * It accepts 'true', 'yes' and '1' for true and - * 'false', 'no' and '0' for false. - * (FIXME:) On unknown value it errors out ScummVM. - * On unknown key it returns false as default. + * Defines whether the save state is allowed to be deleted. */ - bool getBool(const Common::String &key) const; + void setDeletableFlag(bool state) { _isDeletable = state; } /** - * Sets the 'is_deletable' key, which indicates if the - * given savestate is safe for deletion. + * Queries whether the save state is allowed to be deleted. */ - void setDeletableFlag(bool state); + bool getDeletableFlag() const { return _isDeletable; } /** - * Sets the 'is_write_protected' key, which indicates if the - * given savestate can be overwritten or not + * Defines whether the save state is write protected. */ - void setWriteProtectedFlag(bool state); + void setWriteProtectedFlag(bool state) { _isWriteProtected = state; } + + /** + * Queries whether the save state is write protected. + */ + bool getWriteProtectedFlag() const { return _isWriteProtected; } /** * Return a thumbnail graphics surface representing the savestate visually. @@ -109,24 +104,100 @@ public: void setThumbnail(Graphics::Surface *t); /** - * Sets the 'save_date' key properly, based on the given values. + * Sets the date the save state was created. + * + * @param year Year of creation. + * @param month Month of creation. + * @param day Day of creation. */ void setSaveDate(int year, int month, int day); /** - * Sets the 'save_time' key properly, based on the given values. + * Queries a human readable description of the date the save state was created. + * + * This will return an empty string in case the value is not set. + */ + const Common::String &getSaveDate() const { return _saveDate; } + + /** + * Sets the time the save state was created. + * + * @param hour Hour of creation. + * @param min Minute of creation. */ void setSaveTime(int hour, int min); /** - * Sets the 'play_time' key properly, based on the given values. + * Queries a human readable description of the time the save state was created. + * + * This will return an empty string in case the value is not set. + */ + const Common::String &getSaveTime() const { return _saveTime; } + + /** + * Sets the time the game was played before the save state was created. + * + * @param hours How many hours the user played the game so far. + * @param min How many minutes the user played the game so far. */ void setPlayTime(int hours, int minutes); /** - * Sets the 'play_time' key properly, based on the given value. + * Sets the time the game was played before the save state was created. + * + * @param msecs How many milliseconds the user played the game so far. */ void setPlayTime(uint32 msecs); + + /** + * Queries a human readable description of the time the game was played + * before the save state was created. + * + * This will return an empty string in case the value is not set. + */ + const Common::String &getPlayTime() const { return _playTime; } + +private: + /** + * The saveslot id, as it would be passed to the "-x" command line switch. + */ + int _slot; + + /** + * A human readable description of the save state. + */ + Common::String _description; + + /** + * Whether the save state can be deleted. + */ + bool _isDeletable; + + /** + * Whether the save state is write protected. + */ + bool _isWriteProtected; + + /** + * Human readable description of the date the save state was created. + */ + Common::String _saveDate; + + /** + * Human readable description of the time the save state was created. + */ + Common::String _saveTime; + + /** + * Human readable description of the time the game was played till the + * save state was created. + */ + Common::String _playTime; + + /** + * The thumbnail of the save state. + */ + Common::SharedPtr<Graphics::Surface> _thumbnail; }; /** List of savestates. */ diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp index 9f10691767..7b8db22e3f 100644 --- a/engines/sci/engine/kstring.cpp +++ b/engines/sci/engine/kstring.cpp @@ -730,6 +730,10 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) { case 8: { // Dup const char *rawString = 0; uint32 size = 0; + reg_t stringHandle; + // We allocate the new string first because if the StringTable needs to + // grow, our rawString pointer will be invalidated + SciString *dupString = s->_segMan->allocateString(&stringHandle); if (argv[1].segment == s->_segMan->getStringSegmentId()) { SciString *string = s->_segMan->lookupString(argv[1]); @@ -741,8 +745,6 @@ reg_t kString(EngineState *s, int argc, reg_t *argv) { size = string.size() + 1; } - reg_t stringHandle; - SciString *dupString = s->_segMan->allocateString(&stringHandle); dupString->setSize(size); for (uint32 i = 0; i < size; i++) diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp index 4ab0b9719f..dbe2135143 100644 --- a/engines/sci/graphics/screen.cpp +++ b/engines/sci/graphics/screen.cpp @@ -338,7 +338,7 @@ void GfxScreen::drawLine(Common::Point startPoint, Common::Point endPoint, byte void GfxScreen::putKanjiChar(Graphics::FontSJIS *commonFont, int16 x, int16 y, uint16 chr, byte color) { byte *displayPtr = _displayScreen + y * _displayWidth * 2 + x * 2; // we don't use outline, so color 0 is actually not used - commonFont->drawChar(displayPtr, chr, _displayWidth, 1, color, 0); + commonFont->drawChar(displayPtr, chr, _displayWidth, 1, color, 0, -1, -1); } byte GfxScreen::getVisual(int x, int y) { diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp index 7fb834ce98..eaae64dc77 100644 --- a/engines/scumm/charset.cpp +++ b/engines/scumm/charset.cpp @@ -779,7 +779,7 @@ void CharsetRendererV3::printChar(int chr, bool ignoreCharsetMask) { drawBits1(*vs, dst, charPtr, drawTop, origWidth, origHeight, vs->format.bytesPerPixel); #ifndef DISABLE_TOWNS_DUAL_LAYER_MODE else if (_vm->_cjkFont) - _vm->_cjkFont->drawChar(vs, chr, _left, drawTop, _color, _shadowColor); + _vm->_cjkFont->drawChar(*vs, chr, _left, drawTop, _color, _shadowColor); #endif } else { dst = (byte *)_vm->_textSurface.getBasePtr(_left * _vm->_textSurfaceMultiplier, _top * _vm->_textSurfaceMultiplier); diff --git a/engines/scumm/imuse/instrument.h b/engines/scumm/imuse/instrument.h index 3555d319e6..79cbd49032 100644 --- a/engines/scumm/imuse/instrument.h +++ b/engines/scumm/imuse/instrument.h @@ -39,7 +39,6 @@ public: virtual void send(MidiChannel *mc) = 0; virtual void copy_to(Instrument *dest) = 0; virtual bool is_valid() = 0; - virtual operator int() { return 255; } }; class Instrument { diff --git a/engines/scumm/imuse_digi/dimuse_codecs.cpp b/engines/scumm/imuse_digi/dimuse_codecs.cpp index 69cd89320c..6edfe0bd33 100644 --- a/engines/scumm/imuse_digi/dimuse_codecs.cpp +++ b/engines/scumm/imuse_digi/dimuse_codecs.cpp @@ -105,7 +105,9 @@ static const byte imxOtherTable[6][64] = { void releaseImcTables() { free(_destImcTable); + _destImcTable = NULL; free(_destImcTable2); + _destImcTable2 = NULL; } void initializeImcTables() { diff --git a/engines/sword2/controls.cpp b/engines/sword2/controls.cpp index 6ce447a4cc..3611294eb8 100644 --- a/engines/sword2/controls.cpp +++ b/engines/sword2/controls.cpp @@ -477,6 +477,8 @@ void Widget::createSurfaceImage(int state, uint32 res, int x, int y, uint32 pc) // Points to just after frame header, ie. start of sprite data _sprites[state].data = frame + FrameHeader::size(); + _sprites[state].colorTable = colTablePtr; + _sprites[state].isText = false; _vm->_screen->createSurface(&_sprites[state], &_surfaces[state]._surface); _surfaces[state]._original = true; diff --git a/engines/sword2/render.cpp b/engines/sword2/render.cpp index 1e068d6061..8bf9d922d5 100644 --- a/engines/sword2/render.cpp +++ b/engines/sword2/render.cpp @@ -699,8 +699,6 @@ int32 Screen::initializePsxBackgroundLayer(byte *parallax) { */ int32 Screen::initializePsxParallaxLayer(byte *parallax) { - uint16 plxXres, plxYres; - uint16 xTiles, yTiles; uint16 i, j, k; byte *data; byte *dst; @@ -714,10 +712,10 @@ int32 Screen::initializePsxParallaxLayer(byte *parallax) { return RD_OK; } - plxXres = READ_LE_UINT16(parallax); - plxYres = READ_LE_UINT16(parallax + 2); - xTiles = READ_LE_UINT16(parallax + 4); - yTiles = READ_LE_UINT16(parallax + 6); + // uint16 plxXres = READ_LE_UINT16(parallax); + // uint16 plxYres = READ_LE_UINT16(parallax + 2); + uint16 xTiles = READ_LE_UINT16(parallax + 4); + uint16 yTiles = READ_LE_UINT16(parallax + 6); // Beginning of parallax table composed by uint32, // if word is 0, corresponding tile contains no data and must be skipped, diff --git a/engines/sword25/gfx/animationtemplateregistry.cpp b/engines/sword25/gfx/animationtemplateregistry.cpp index 43c099c89d..8184b49eba 100644 --- a/engines/sword25/gfx/animationtemplateregistry.cpp +++ b/engines/sword25/gfx/animationtemplateregistry.cpp @@ -34,7 +34,9 @@ #include "sword25/gfx/animationtemplateregistry.h" #include "sword25/gfx/animationtemplate.h" +namespace Common { DECLARE_SINGLETON(Sword25::AnimationTemplateRegistry); +} namespace Sword25 { diff --git a/engines/sword25/gfx/graphicengine.cpp b/engines/sword25/gfx/graphicengine.cpp index 91133b9fd2..14ba032107 100644 --- a/engines/sword25/gfx/graphicengine.cpp +++ b/engines/sword25/gfx/graphicengine.cpp @@ -156,7 +156,7 @@ RenderObjectPtr<Panel> GraphicEngine::getMainPanel() { } void GraphicEngine::setVsync(bool vsync) { - warning("STUB: SetVsync(%d)", vsync); + // ScummVM has no concept of VSync } bool GraphicEngine::getVsync() const { diff --git a/engines/sword25/gfx/image/art.cpp b/engines/sword25/gfx/image/art.cpp index e9715481c6..2ba102e779 100644 --- a/engines/sword25/gfx/image/art.cpp +++ b/engines/sword25/gfx/image/art.cpp @@ -2030,7 +2030,6 @@ static void art_svp_intersect_add_seg(ArtIntersectCtx *ctx, const ArtSVPSeg *in_ ArtActiveSeg *seg = art_new(ArtActiveSeg, 1); ArtActiveSeg *test; double x0, y0; - ArtActiveSeg *beg_range; ArtActiveSeg *last = NULL; ArtActiveSeg *left, *right; ArtPriPoint *pri_pt = art_new(ArtPriPoint, 1); @@ -2058,7 +2057,6 @@ static void art_svp_intersect_add_seg(ArtIntersectCtx *ctx, const ArtSVPSeg *in_ x0 = in_seg->points[0].x; y0 = in_seg->points[0].y; - beg_range = NULL; for (test = ctx->active_head; test != NULL; test = test->right) { double d; int test_bneg = test->flags & ART_ACTIVE_FLAGS_BNEG; diff --git a/engines/sword25/gfx/image/renderedimage.cpp b/engines/sword25/gfx/image/renderedimage.cpp index f5f33d8e02..3b29b0333f 100644 --- a/engines/sword25/gfx/image/renderedimage.cpp +++ b/engines/sword25/gfx/image/renderedimage.cpp @@ -72,7 +72,10 @@ static byte *readSavegameThumbnail(const Common::String &filename, uint &fileSiz // Seek to the actual PNG image loadString(*file); // Marker (BS25SAVEGAME) - loadString(*file); // Version + Common::String storedVersionID = loadString(*file); // Version + if (storedVersionID != "SCUMMVM1") + loadString(*file); + loadString(*file); // Description uint32 compressedGamedataSize = atoi(loadString(*file).c_str()); loadString(*file); // Uncompressed game data size diff --git a/engines/sword25/gfx/image/vectorimage.cpp b/engines/sword25/gfx/image/vectorimage.cpp index b9ce5f7e00..45d43c465e 100644 --- a/engines/sword25/gfx/image/vectorimage.cpp +++ b/engines/sword25/gfx/image/vectorimage.cpp @@ -247,9 +247,6 @@ VectorImage::VectorImage(const byte *pFileData, uint fileSize, bool &success, co return; } - // readout SWF size - Common::Rect movieRect = flashRectToBSRect(bs); - // Get frame rate and frame count /* uint32 frameRate = */ bs.getUInt16(); diff --git a/engines/sword25/kernel/inputpersistenceblock.cpp b/engines/sword25/kernel/inputpersistenceblock.cpp index c1cd771e39..2d45dfb640 100644 --- a/engines/sword25/kernel/inputpersistenceblock.cpp +++ b/engines/sword25/kernel/inputpersistenceblock.cpp @@ -35,9 +35,10 @@ namespace Sword25 { -InputPersistenceBlock::InputPersistenceBlock(const void *data, uint dataLength) : +InputPersistenceBlock::InputPersistenceBlock(const void *data, uint dataLength, int version) : _data(static_cast<const byte *>(data), dataLength), - _errorState(NONE) { + _errorState(NONE), + _version(version) { _iter = _data.begin(); } diff --git a/engines/sword25/kernel/inputpersistenceblock.h b/engines/sword25/kernel/inputpersistenceblock.h index f643b06bc1..7e68137246 100644 --- a/engines/sword25/kernel/inputpersistenceblock.h +++ b/engines/sword25/kernel/inputpersistenceblock.h @@ -46,7 +46,7 @@ public: OUT_OF_SYNC }; - InputPersistenceBlock(const void *data, uint dataLength); + InputPersistenceBlock(const void *data, uint dataLength, int version); virtual ~InputPersistenceBlock(); void read(int16 &value); @@ -64,6 +64,8 @@ public: return _errorState; } + int getVersion() const { return _version; } + private: bool checkMarker(byte marker); bool checkBlockSize(int size); @@ -72,6 +74,8 @@ private: Common::Array<byte> _data; Common::Array<byte>::const_iterator _iter; ErrorState _errorState; + + int _version; }; } // End of namespace Sword25 diff --git a/engines/sword25/kernel/persistenceservice.cpp b/engines/sword25/kernel/persistenceservice.cpp index c88360e031..27d669caa1 100644 --- a/engines/sword25/kernel/persistenceservice.cpp +++ b/engines/sword25/kernel/persistenceservice.cpp @@ -50,7 +50,9 @@ static const char *SAVEGAME_DIRECTORY = "saves"; static const char *FILE_MARKER = "BS25SAVEGAME"; static const uint SLOT_COUNT = 18; static const uint FILE_COPY_BUFFER_SIZE = 1024 * 10; -static const char *VERSIONID = "SCUMMVM1"; +static const char *VERSIONIDOLD = "SCUMMVM1"; +static const char *VERSIONID = "SCUMMVM2"; +static const int VERSIONNUM = 2; #define MAX_SAVEGAME_SIZE 100 @@ -99,6 +101,7 @@ struct SavegameInformation { bool isOccupied; bool isCompatible; Common::String description; + int version; uint gamedataLength; uint gamedataOffset; uint gamedataUncompressedLength; @@ -147,9 +150,15 @@ struct PersistenceService::Impl { // Read in the header Common::String storedMarker = loadString(file); Common::String storedVersionID = loadString(file); + if (storedVersionID == VERSIONIDOLD) { + curSavegameInfo.version = 1; + } else { + Common::String versionNum = loadString(file); + curSavegameInfo.version = atoi(versionNum.c_str()); + } Common::String gameDescription = loadString(file); - Common::String gameDataLength = loadString(file); - curSavegameInfo.gamedataLength = atoi(gameDataLength.c_str()); + Common::String gamedataLength = loadString(file); + curSavegameInfo.gamedataLength = atoi(gamedataLength.c_str()); Common::String gamedataUncompressedLength = loadString(file); curSavegameInfo.gamedataUncompressedLength = atoi(gamedataUncompressedLength.c_str()); @@ -158,7 +167,7 @@ struct PersistenceService::Impl { // The slot is marked as occupied. curSavegameInfo.isOccupied = true; // Check if the saved game is compatible with the current engine version. - curSavegameInfo.isCompatible = (storedVersionID == Common::String(VERSIONID)); + curSavegameInfo.isCompatible = (curSavegameInfo.version <= VERSIONNUM); // Load the save game description. curSavegameInfo.description = gameDescription; // The offset to the stored save game data within the file. @@ -242,6 +251,12 @@ Common::String &PersistenceService::getSavegameFilename(uint slotID) { return result; } +int PersistenceService::getSavegameVersion(uint slotID) { + if (!checkslotID(slotID)) + return -1; + return _impl->_savegameInformations[slotID].version; +} + bool PersistenceService::saveGame(uint slotID, const Common::String &screenshotFilename) { // FIXME: This code is a hack which bypasses the savefile API, // and should eventually be removed. @@ -264,6 +279,11 @@ bool PersistenceService::saveGame(uint slotID, const Common::String &screenshotF file->writeString(VERSIONID); file->writeByte(0); + char buf[20]; + snprintf(buf, 20, "%d", VERSIONNUM); + file->writeString(buf); + file->writeByte(0); + TimeDate dt; g_system->getTimeAndDate(dt); file->writeString(formatTimestamp(dt)); @@ -385,7 +405,7 @@ bool PersistenceService::loadGame(uint slotID) { memcpy(uncompressedDataBuffer, compressedDataBuffer, uncompressedBufferSize); } - InputPersistenceBlock reader(&uncompressedDataBuffer[0], curSavegameInfo.gamedataUncompressedLength); + InputPersistenceBlock reader(&uncompressedDataBuffer[0], curSavegameInfo.gamedataUncompressedLength, curSavegameInfo.version); // Einzelne Engine-Module depersistieren. bool success = true; diff --git a/engines/sword25/kernel/persistenceservice.h b/engines/sword25/kernel/persistenceservice.h index f73962892c..59e0a3661d 100644 --- a/engines/sword25/kernel/persistenceservice.h +++ b/engines/sword25/kernel/persistenceservice.h @@ -57,6 +57,7 @@ public: void reloadSlots(); bool isSlotOccupied(uint slotID); bool isSavegameCompatible(uint slotID); + int getSavegameVersion(uint slotID); Common::String &getSavegameDescription(uint slotID); Common::String &getSavegameFilename(uint slotID); diff --git a/engines/sword25/math/regionregistry.cpp b/engines/sword25/math/regionregistry.cpp index dff8560205..68c360a5ee 100644 --- a/engines/sword25/math/regionregistry.cpp +++ b/engines/sword25/math/regionregistry.cpp @@ -34,7 +34,9 @@ #include "sword25/math/regionregistry.h" #include "sword25/math/region.h" +namespace Common { DECLARE_SINGLETON(Sword25::RegionRegistry); +} namespace Sword25 { diff --git a/engines/sword25/sfx/soundengine.cpp b/engines/sword25/sfx/soundengine.cpp index 7c8a6593aa..1b424dac65 100644 --- a/engines/sword25/sfx/soundengine.cpp +++ b/engines/sword25/sfx/soundengine.cpp @@ -33,6 +33,8 @@ #include "sword25/sfx/soundengine.h" #include "sword25/package/packagemanager.h" #include "sword25/kernel/resource.h" +#include "sword25/kernel/inputpersistenceblock.h" +#include "sword25/kernel/outputpersistenceblock.h" #include "audio/decoders/vorbis.h" @@ -202,17 +204,29 @@ bool SoundEngine::playSound(const Common::String &fileName, SOUND_TYPES type, fl return true; } -uint SoundEngine::playSoundEx(const Common::String &fileName, SOUND_TYPES type, float volume, float pan, bool loop, int loopStart, int loopEnd, uint layer) { +uint SoundEngine::playSoundEx(const Common::String &fileName, SOUND_TYPES type, float volume, float pan, bool loop, int loopStart, int loopEnd, uint layer, uint handleId) { Common::SeekableReadStream *in = Kernel::getInstance()->getPackage()->getStream(fileName); #ifdef USE_VORBIS Audio::SeekableAudioStream *stream = Audio::makeVorbisStream(in, DisposeAfterUse::YES); #endif uint id; - SndHandle *handle = getHandle(&id); + SndHandle *handle; - debugC(1, kDebugSound, "SoundEngine::playSoundEx(%s, %d, %f, %f, %d, %d, %d, %d)", fileName.c_str(), type, volume, pan, loop, loopStart, loopEnd, layer); + if (handleId == 0x1337) + handle = getHandle(&id); + else + handle = &_handles[handleId]; - handle->type = kAllocatedHandle; + handle->fileName = fileName; + handle->sndType = type; + handle->volume = volume; + handle->pan = pan; + handle->loop = loop; + handle->loopStart = loopStart; + handle->loopEnd = loopEnd; + handle->layer = layer; + + debugC(1, kDebugSound, "SoundEngine::playSoundEx(%s, %d, %f, %f, %d, %d, %d, %d)", fileName.c_str(), type, volume, pan, loop, loopStart, loopEnd, layer); #ifdef USE_VORBIS _mixer->playStream(getType(type), &(handle->handle), stream, -1, (byte)(volume * 255), (int8)(pan * 127)); @@ -311,16 +325,61 @@ bool SoundEngine::canLoadResource(const Common::String &fileName) { } -bool SoundEngine::persist(OutputPersistenceBlock &writer) { - warning("STUB: SoundEngine::persist()"); + bool SoundEngine::persist(OutputPersistenceBlock &writer) { + writer.write(_maxHandleId); + + for (uint i = 0; i < SOUND_HANDLES; i++) { + writer.write(_handles[i].id); + + writer.writeString(_handles[i].fileName); + writer.write((int)_handles[i].sndType); + writer.write(_handles[i].volume); + writer.write(_handles[i].pan); + writer.write(_handles[i].loop); + writer.write(_handles[i].loopStart); + writer.write(_handles[i].loopEnd); + writer.write(_handles[i].layer); + } return true; } bool SoundEngine::unpersist(InputPersistenceBlock &reader) { - warning("STUB: SoundEngine::unpersist()"); + _mixer->stopAll(); - return true; + if (reader.getVersion() < 2) + return true; + + reader.read(_maxHandleId); + + for (uint i = 0; i < SOUND_HANDLES; i++) { + reader.read(_handles[i].id); + + Common::String fileName; + int sndType; + float volume; + float pan; + bool loop; + int loopStart; + int loopEnd; + uint layer; + + reader.readString(fileName); + reader.read(sndType); + reader.read(volume); + reader.read(pan); + reader.read(loop); + reader.read(loopStart); + reader.read(loopEnd); + reader.read(layer); + + if (reader.isGood()) { + playSoundEx(fileName, (SOUND_TYPES)sndType, volume, pan, loop, loopStart, loopEnd, layer, i); + } else + return false; + } + + return reader.isGood(); } diff --git a/engines/sword25/sfx/soundengine.h b/engines/sword25/sfx/soundengine.h index 71f1602484..8132ec556e 100644 --- a/engines/sword25/sfx/soundengine.h +++ b/engines/sword25/sfx/soundengine.h @@ -65,6 +65,15 @@ struct SndHandle { Audio::SoundHandle handle; sndHandleType type; uint32 id; + + Common::String fileName; + int sndType; + float volume; + float pan; + bool loop; + int loopStart; + int loopEnd; + uint layer; }; @@ -176,7 +185,7 @@ public: * @remark If more control is needed over the playing, eg. changing the sound parameters * for Volume and Panning, then PlaySoundEx should be used. */ - uint playSoundEx(const Common::String &fileName, SOUND_TYPES type, float volume = 1.0f, float pan = 0.0f, bool loop = false, int loopStart = -1, int loopEnd = -1, uint layer = 0); + uint playSoundEx(const Common::String &fileName, SOUND_TYPES type, float volume = 1.0f, float pan = 0.0f, bool loop = false, int loopStart = -1, int loopEnd = -1, uint layer = 0, uint handleId = 0x1337); /** * Sets the volume of a playing sound diff --git a/engines/sword25/sword25.cpp b/engines/sword25/sword25.cpp index b111746c32..2201188052 100644 --- a/engines/sword25/sword25.cpp +++ b/engines/sword25/sword25.cpp @@ -50,7 +50,9 @@ #include "sword25/gfx/animationtemplateregistry.h" // Needed so we can destroy the singleton #include "sword25/gfx/renderobjectregistry.h" // Needed so we can destroy the singleton +namespace Common { DECLARE_SINGLETON(Sword25::RenderObjectRegistry); +} #include "sword25/math/regionregistry.h" // Needed so we can destroy the singleton namespace Sword25 { diff --git a/engines/testbed/config-params.cpp b/engines/testbed/config-params.cpp index 9a5062185b..d7ead48f63 100644 --- a/engines/testbed/config-params.cpp +++ b/engines/testbed/config-params.cpp @@ -24,7 +24,9 @@ #include "testbed/config-params.h" +namespace Common { DECLARE_SINGLETON(Testbed::ConfigParams); +} namespace Testbed { diff --git a/engines/tsage/ringworld_scenes1.cpp b/engines/tsage/ringworld_scenes1.cpp index 7fe2610fd7..8299a05967 100644 --- a/engines/tsage/ringworld_scenes1.cpp +++ b/engines/tsage/ringworld_scenes1.cpp @@ -3105,10 +3105,10 @@ void Scene6100::Object::synchronize(Serializer &s) { SceneObject::synchronize(s); // Save the double fields of the FloatSet - s.syncBytes((byte *)&_floats._float1, sizeof(double)); - s.syncBytes((byte *)&_floats._float2, sizeof(double)); - s.syncBytes((byte *)&_floats._float3, sizeof(double)); - s.syncBytes((byte *)&_floats._float4, sizeof(double)); + s.syncAsDouble(_floats._float1); + s.syncAsDouble(_floats._float2); + s.syncAsDouble(_floats._float3); + s.syncAsDouble(_floats._float4); } /*--------------------------------------------------------------------------*/ diff --git a/engines/tsage/saveload.cpp b/engines/tsage/saveload.cpp index b184e59c9e..40444cd630 100644 --- a/engines/tsage/saveload.cpp +++ b/engines/tsage/saveload.cpp @@ -103,6 +103,19 @@ void Serializer::validate(int v, Common::Serializer::Version minVersion, error("Savegame is corrupt"); } +#define DOUBLE_PRECISION 1000000000 + +void Serializer::syncAsDouble(double &v) { + int32 num = (int32)(v); + uint32 fraction = (uint32)((v - (int32)v) * DOUBLE_PRECISION); + + syncAsSint32LE(num); + syncAsUint32LE(fraction); + + if (isLoading()) + v = num + (double)fraction / DOUBLE_PRECISION; +} + /*--------------------------------------------------------------------------*/ Common::Error Saver::save(int slot, const Common::String &saveName) { diff --git a/engines/tsage/saveload.h b/engines/tsage/saveload.h index 0382e4a1fc..ce181cbc8f 100644 --- a/engines/tsage/saveload.h +++ b/engines/tsage/saveload.h @@ -77,6 +77,7 @@ public: Common::Serializer::Version maxVersion = kLastVersion); void validate(int v, Common::Serializer::Version minVersion = 0, Common::Serializer::Version maxVersion = kLastVersion); + void syncAsDouble(double &v); }; /*--------------------------------------------------------------------------*/ diff --git a/engines/tsage/sound.cpp b/engines/tsage/sound.cpp index 01e770a77a..e26b3d1544 100644 --- a/engines/tsage/sound.cpp +++ b/engines/tsage/sound.cpp @@ -126,7 +126,10 @@ Common::List<SoundDriverEntry> &SoundManager::buildDriverList(bool detectFlag) { assert(__sndmgrReady); _availableDrivers.clear(); - // Build up a list of available drivers. Currently we only implement an Adlib driver + // Build up a list of available drivers. Currently we only implement an Adlib music + // and SoundBlaster FX driver + + // Adlib driver SoundDriverEntry sd; sd.driverNum = ADLIB_DRIVER_NUM; sd.status = detectFlag ? SNDSTATUS_DETECTED : SNDSTATUS_SKIPPED; @@ -136,12 +139,25 @@ Common::List<SoundDriverEntry> &SoundManager::buildDriverList(bool detectFlag) { sd.longDescription = "3812fm"; _availableDrivers.push_back(sd); + // SoundBlaster entry + SoundDriverEntry sdFx; + sdFx.driverNum = SBLASTER_DRIVER_NUM; + sdFx.status = detectFlag ? SNDSTATUS_DETECTED : SNDSTATUS_SKIPPED; + sdFx.field2 = 0; + sdFx.field6 = 15000; + sdFx.shortDescription = "SndBlast"; + sdFx.longDescription = "SoundBlaster"; + _availableDrivers.push_back(sdFx); + _driversDetected = true; return _availableDrivers; } void SoundManager::installConfigDrivers() { installDriver(ADLIB_DRIVER_NUM); +#ifdef DEBUG + installDriver(SBLASTER_DRIVER_NUM); +#endif } Common::List<SoundDriverEntry> &SoundManager::getDriverList(bool detectFlag) { @@ -206,8 +222,14 @@ void SoundManager::installDriver(int driverNum) { * Instantiate a driver class for the specified driver number */ SoundDriver *SoundManager::instantiateDriver(int driverNum) { - assert(driverNum == ADLIB_DRIVER_NUM); - return new AdlibSoundDriver(); + switch (driverNum) { + case ADLIB_DRIVER_NUM: + return new AdlibSoundDriver(); + case SBLASTER_DRIVER_NUM: + return new AdlibFxSoundDriver(); + default: + error("Unknown sound driver - %d", driverNum); + } } /** @@ -2125,7 +2147,7 @@ void Sound::_soProc32(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voice vtStruct->_entries[entryIndex]._type1._field4 = v0; vtStruct->_entries[entryIndex]._type1._field5 = 0; - driver->proc32(vtStruct->_entries[entryIndex]._voiceNum, _chProgram[channelNum], v0, v1); + driver->proc32(this, vtStruct->_entries[entryIndex]._voiceNum, _chProgram[channelNum], v0, v1); } } @@ -2143,8 +2165,9 @@ void Sound::_soProc42(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voice vtStruct->_entries[entryIndex]._type1._field4 = v0; vtStruct->_entries[entryIndex]._type1._field5 = 0; - driver->proc32(vtStruct->_entries[entryIndex]._voiceNum, -1, v0, 0x7F); - driver->proc42(vtStruct->_entries[entryIndex]._voiceNum, voiceType, 0); + int v1, v2; + driver->proc32(this, vtStruct->_entries[entryIndex]._voiceNum, -1, v0, 0x7F); + driver->proc42(vtStruct->_entries[entryIndex]._voiceNum, voiceType, 0, &v1, &v2); } break; } @@ -2271,11 +2294,32 @@ void Sound::_soServiceTrackType1(int trackIndex, const byte *channelData) { vtStruct->_entries[entryIndex]._type1._field4 = *(channelData + 1); vtStruct->_entries[entryIndex]._type1._field5 = 0; - driver->proc32(vtStruct->_entries[entryIndex]._voiceNum, -1, *(channelData + 1), 0x7f); + int v1, v2; + driver->proc32(this, vtStruct->_entries[entryIndex]._voiceNum, -1, *(channelData + 1), 0x7f); + driver->proc42(vtStruct->_entries[entryIndex]._voiceNum, *(channelData + 1), _loop ? 1 : 0, + &v1, &v2); } } else { + for (uint entryIndex = 0; entryIndex < vtStruct->_entries.size(); ++entryIndex) { + VoiceStructEntry &vte = vtStruct->_entries[entryIndex]; + VoiceStructEntryType1 &vse = vte._type1; + if ((vse._sound == this) && (vse._channelNum == channel) && (vse._field4 == vtStruct->_total)) { + SoundDriver *driver = vte._driver; + + int v1, v2; + driver->proc42(vte._voiceNum, vtStruct->_total, _loop ? 1 : 0, &v1, &v2); + if (v2) { + _trkState[trackIndex] = 0; + } else if (vtStruct->_total) { + _timer = 0; + } + } + } + _trkState[trackIndex] = 0; } + } else { + _trkState[trackIndex] = 0; } } } @@ -2441,7 +2485,10 @@ AdlibSoundDriver::AdlibSoundDriver(): SoundDriver() { _mixer = _vm->_mixer; _sampleRate = _mixer->getOutputRate(); - _opl = makeAdLibOPL(_sampleRate); + _opl = OPL::Config::create(); + assert(_opl); + _opl->init(_sampleRate); + _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); Common::set_to(_channelVoiced, _channelVoiced + ADLIB_CHANNEL_COUNT, false); @@ -2460,7 +2507,7 @@ AdlibSoundDriver::AdlibSoundDriver(): SoundDriver() { AdlibSoundDriver::~AdlibSoundDriver() { DEALLOCATE(_patchData); _mixer->stopHandle(_soundHandle); - OPLDestroy(_opl); + delete _opl; } bool AdlibSoundDriver::open() { @@ -2511,7 +2558,7 @@ int AdlibSoundDriver::setMasterVolume(int volume) { return oldVolume; } -void AdlibSoundDriver::proc32(int channel, int program, int v0, int v1) { +void AdlibSoundDriver::proc32(Sound *sound, int channel, int program, int v0, int v1) { if (program == -1) return; @@ -2578,7 +2625,7 @@ void AdlibSoundDriver::flush() { while (!_queue.empty()) { RegisterValue v = _queue.pop(); - OPLWriteReg(_opl, v._regNum, v._value); + _opl->writeReg(v._regNum, v._value); } } @@ -2716,7 +2763,7 @@ void AdlibSoundDriver::update(int16 *buf, int len) { } samplesLeft -= count; len -= count; - YM3812UpdateOne(_opl, buf, count); + _opl->readBuffer(buf, count); if (samplesLeft == 0) { flush(); samplesLeft = _sampleRate / 50; @@ -2735,14 +2782,13 @@ AdlibFxSoundDriver::AdlibFxSoundDriver(): SoundDriver() { _maxVersion = 0x10A; _masterVolume = 0; - _groupData.groupMask = 9; + _groupData.groupMask = 1; _groupData.v1 = 0x3E; _groupData.v2 = 0; _groupData.pData = &adlib_group_data[0]; _mixer = _vm->_mixer; _sampleRate = _mixer->getOutputRate(); - _opl = makeAdLibOPL(_sampleRate); _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); /* Common::set_to(_channelVoiced, _channelVoiced + ADLIB_CHANNEL_COUNT, false); @@ -2761,35 +2807,28 @@ AdlibFxSoundDriver::AdlibFxSoundDriver(): SoundDriver() { AdlibFxSoundDriver::~AdlibFxSoundDriver() { _mixer->stopHandle(_soundHandle); - OPLDestroy(_opl); } bool AdlibFxSoundDriver::open() { + write209(); + write(64); + write(165); + // for (int idx = 0; idx < 5000 * 16; ++idx) al = port[21h] - write(1, 0x20); - if (!reset()) - return false; - - write(8, 0); - for (int idx = 0x20; idx < 0xF6; ++idx) - write(idx, 0); +// _v45071 = 1; +// _v4506F = 0; - write(0xBD, 0); return true; } void AdlibFxSoundDriver::close() { - for (int idx = 0xB0; idx < 0xB8; ++idx) - write(idx, _portContents[idx] & 0xDF); - for (int idx = 0x40; idx < 0x55; ++idx) - write(idx, 0x3F); - reset(); + write(208); + write211(); + } bool AdlibFxSoundDriver::reset() { - write(1, 0x20); - write(1, 0x20); return true; } @@ -2798,209 +2837,81 @@ const GroupData *AdlibFxSoundDriver::getGroupData() { return &_groupData; } +void AdlibFxSoundDriver::poll() { + if (!_masterVolume || !_channelVolume) { + if (_v45046) + write211(); + } else { + if (!_v45046) + write209(); + } +} + int AdlibFxSoundDriver::setMasterVolume(int volume) { int oldVolume = _masterVolume; _masterVolume = volume; - for (int channelNum = 0; channelNum < ADLIB_CHANNEL_COUNT; ++channelNum) - updateChannelVolume(channelNum); - return oldVolume; } -void AdlibFxSoundDriver::proc32(int channel, int program, int v0, int v1) { +void AdlibFxSoundDriver::proc32(Sound *sound, int channel, int program, int v0, int v1) { if (program == -1) return; -/* - int offset = READ_LE_UINT16(_patchData + program * 2); - if (offset) { - const byte *dataP = _patchData + offset; - int id; - for (offset = 2, id = 0; id != READ_LE_UINT16(dataP); offset += 30, ++id) { - if ((dataP[offset] <= v0) && (dataP[offset + 1] >= v0)) { - if (dataP[offset + 2] != 0xff) - v0 = dataP[offset + 2]; + if (_sound) + updateVoice(channel); - _v4409E[channel] = dataP + offset - _patchData; + // TODO: Stuff - // Set sustain/release - int portNum = v440C2[v440B0[channel]] + 0x80; - write(portNum, (_portContents[portNum] & 0xF0) | 0xF); - portNum = v440C2[v440B9[channel]] + 0x80; - write(portNum, (_portContents[portNum] & 0xF0) | 0xF); - if (_channelVoiced[channel]) - clearVoice(channel); - - _v44067[channel] = v0; - _v4405E[channel] = v1; - - updateChannel(channel); - setFrequency(channel); - updateChannelVolume(channel); - setVoice(channel); - break; - } - } - } - */ } void AdlibFxSoundDriver::updateVoice(int channel) { - if (_channelVoiced[channel]) - clearVoice(channel); + if (_sound) { + write(208); + + _sound = NULL; + _v45062 = 0; + _v45066 = 0; + _v45068 = 0; + } } void AdlibFxSoundDriver::proc38(int channel, int cmd, int value) { if (cmd == 7) { // Set channel volume - _channelVolume[channel] = value; - updateChannelVolume(channel); + _channelVolume = value; } } -void AdlibFxSoundDriver::setPitch(int channel, int pitchBlend) { - _pitchBlend[channel] = pitchBlend; - setFrequency(channel); -} +void AdlibFxSoundDriver::proc42(int channel, int cmd, int value, int *v1, int *v2) { + _v4506A = value; + *v1 = _v4506B; + *v2 = 0; + _v4506B = 0; -void AdlibFxSoundDriver::write(byte reg, byte value) { - _portContents[reg] = value; - _queue.push(RegisterValue(reg, value)); + if (!_sound) + *v2 = 1; } -void AdlibFxSoundDriver::flush() { - Common::StackLock slock(SoundManager::sfManager()._serverDisabledMutex); - - while (!_queue.empty()) { - RegisterValue v = _queue.pop(); - OPLWriteReg(_opl, v._regNum, v._value); +void AdlibFxSoundDriver::write(int v) { + /* + port[adlib_port + 12] = v; + for (int i = 0; i < 100; ++i) { + if (!port[adlib_port + 12] & 0x80) + break; } -} - -void AdlibFxSoundDriver::updateChannelVolume(int channelNum) { - int volume = (_masterVolume * _channelVolume[channelNum] / 127 * _v4405E[channelNum] / 127) / 2; - int level2 = 63 - v44134[volume * _v44079[channelNum] / 63]; - int level1 = !_v44082[channelNum] ? 63 - _v44070[channelNum] : - 63 - v44134[volume * _v44070[channelNum] / 63]; - - int portNum = v440C2[v440B0[channelNum]] + 0x40; - write(portNum, (_portContents[portNum] & 0x80) | level1); - - portNum = v440C2[v440B9[channelNum]] + 0x40; - write(portNum, (_portContents[portNum] & 0x80) | level2); -} - -void AdlibFxSoundDriver::setVoice(int channel) { - int portNum = 0xB0 + channel; - write(portNum, _portContents[portNum] | 0x20); - _channelVoiced[channel] = true; -} - -void AdlibFxSoundDriver::clearVoice(int channel) { - write(0xB0 + channel, _portContents[0xB0 + channel] & ~0x20); - _channelVoiced[channel] = false; -} - -void AdlibFxSoundDriver::updateChannel(int channel) { -/* - const byte *dataP = _patchData + _v4409E[channel]; - int portOffset = v440C2[v440B0[channel]]; - - int portNum = portOffset + 0x20; - int portValue = 0; - if (*(dataP + 4)) - portValue |= 0x80; - if (*(dataP + 5)) - portValue |= 0x40; - if (*(dataP + 8)) - portValue |= 0x20; - if (*(dataP + 6)) - portValue |= 0x10; - portValue |= *(dataP + 7); - write(portNum, portValue); - - portValue = (_portContents[0x40 + portOffset] & 0x3F) | (*(dataP + 9) << 6); - write(0x40 + portOffset, portValue); - - _v44070[channel] = 63 - *(dataP + 10); - write(0x60 + portOffset, *(dataP + 12) | (*(dataP + 11) << 4)); - write(0x80 + portOffset, *(dataP + 14) | (*(dataP + 13) << 4)); - write(0xE0 + portOffset, (_portContents[0xE0 + portOffset] & 0xFC) | *(dataP + 15)); - - portOffset = v440C2[v440B9[channel]]; - portNum = portOffset + 0x20; - portValue = 0; - if (*(dataP + 17)) - portValue |= 0x80; - if (*(dataP + 18)) - portValue |= 0x40; - if (*(dataP + 21)) - portValue |= 0x20; - if (*(dataP + 19)) - portValue |= 0x10; - portValue |= *(dataP + 20); - write(portNum, portValue); - - write(0x40 + portOffset, (_portContents[0x40 + portOffset] & 0x3f) | (*(dataP + 22) << 6)); - _v44079[channel] = 0x3F - *(dataP + 23); - write(0x60 + portOffset, *(dataP + 25) | (*(dataP + 24) << 4)); - write(0x80 + portOffset, *(dataP + 27) | (*(dataP + 26) << 4)); - write(0xE0 + portOffset, (_portContents[0xE0 + portOffset] & 0xFC) | *(dataP + 28)); - - write(0xC0 + channel, (_portContents[0xC0 + channel] & 0xF0) - | (*(dataP + 16) << 1) | *(dataP + 3)); - - _v44082[channel] = *(dataP + 3); */ } -void AdlibFxSoundDriver::setFrequency(int channel) { - int offset, ch; - - int v = _pitchBlend[channel]; - if (v == 0x2000) { - offset = 0; - ch = _v44067[channel]; - } else if (v > 0x2000) { - ch = _v44067[channel]; - v -= 0x2000; - if (v == 0x1fff) - v = 0x2000; - - offset = (v / 170) & 3; - ch += (v / 170) >> 2; - - if (ch >= 128) - ch = 127; - } else { - ch = _v44067[channel]; - int tempVal = (0x2000 - v) / 170; - int tempVal2 = 4 - (tempVal & 3); - - if (tempVal2 == 4) - offset = 0; - else { - offset = tempVal2; - --ch; - } +void AdlibFxSoundDriver::flush() { + Common::StackLock slock(SoundManager::sfManager()._serverDisabledMutex); - ch -= tempVal >> 2; - if (ch < 0) - ch = 0; - } + // No data output yet +} - int var2 = ch / 12; - if (var2) - --var2; - int dataWord = v440D4[((ch % 12) << 2) + offset]; - write(0xA0 + channel, dataWord & 0xff); - write(0xB0 + channel, (_portContents[0xB0 + channel] & 0xE0) | - ((dataWord >> 8) & 3) | (var2 << 2)); -} int AdlibFxSoundDriver::readBuffer(int16 *buffer, const int numSamples) { update(buffer, numSamples); @@ -3008,6 +2919,7 @@ int AdlibFxSoundDriver::readBuffer(int16 *buffer, const int numSamples) { } void AdlibFxSoundDriver::update(int16 *buf, int len) { +/* static int samplesLeft = 0; while (len != 0) { int count = samplesLeft; @@ -3023,6 +2935,17 @@ void AdlibFxSoundDriver::update(int16 *buf, int len) { } buf += count; } +*/ +} + +void AdlibFxSoundDriver::write209() { + write(209); + _v45046 = true; +} + +void AdlibFxSoundDriver::write211() { + write(211); + _v45046 = false; } } // End of namespace tSage diff --git a/engines/tsage/sound.h b/engines/tsage/sound.h index 27f30b9b08..6a47a1aaf5 100644 --- a/engines/tsage/sound.h +++ b/engines/tsage/sound.h @@ -40,6 +40,7 @@ class Sound; #define SOUND_ARR_SIZE 16 #define ROLAND_DRIVER_NUM 2 #define ADLIB_DRIVER_NUM 3 +#define SBLASTER_DRIVER_NUM 4 struct trackInfoStruct { int _numTracks; @@ -106,12 +107,12 @@ public: virtual void setProgram(int channel, int program) {} // Method #13 virtual void setVolume1(int channel, int v2, int v3, int volume) {} virtual void setPitchBlend(int channel, int pitchBlend) {} // Method #15 - virtual void proc32(int channel, int program, int v0, int v1) {}// Method #16 + virtual void proc32(Sound *sound, int channel, int program, int v0, int v1) {}// Method #16 virtual void updateVoice(int channel) {} // Method #17 virtual void proc36() {} // Method #18 virtual void proc38(int channel, int cmd, int value) {} // Method #19 virtual void setPitch(int channel, int pitchBlend) {} // Method #20 - virtual void proc42(int channel, int v0, int v1) {} // Method #21 + virtual void proc42(int channel, int cmd, int value, int *v1, int *v2) {} // Method #21 }; struct VoiceStructEntryType0 { @@ -439,7 +440,7 @@ public: virtual const GroupData *getGroupData(); virtual void installPatch(const byte *data, int size); virtual int setMasterVolume(int volume); - virtual void proc32(int channel, int program, int v0, int v1); + virtual void proc32(Sound *sound, int channel, int program, int v0, int v1); virtual void updateVoice(int channel); virtual void proc38(int channel, int cmd, int value); virtual void setPitch(int channel, int pitchBlend); @@ -455,33 +456,27 @@ public: class AdlibFxSoundDriver: public SoundDriver, Audio::AudioStream { private: + Common::Queue<RegisterValue> _queue; GroupData _groupData; Audio::Mixer *_mixer; - FM_OPL *_opl; Audio::SoundHandle _soundHandle; int _sampleRate; - byte _portContents[256]; - int _masterVolume; - Common::Queue<RegisterValue> _queue; - - bool _channelVoiced[ADLIB_CHANNEL_COUNT]; - int _channelVolume[ADLIB_CHANNEL_COUNT]; - int _v4405E[ADLIB_CHANNEL_COUNT]; - int _v44067[ADLIB_CHANNEL_COUNT]; - int _v44070[ADLIB_CHANNEL_COUNT]; - int _v44079[ADLIB_CHANNEL_COUNT]; - int _v44082[ADLIB_CHANNEL_COUNT + 1]; - int _pitchBlend[ADLIB_CHANNEL_COUNT]; - int _v4409E[ADLIB_CHANNEL_COUNT]; + int _v45062; + int _v45066; + int _v45068; + int _v4506A; + int _v4506B; + bool _v45046; + byte _masterVolume; + byte _channelVolume; + Sound *_sound; - void write(byte reg, byte value); + void write(int v); void flush(); - void updateChannelVolume(int channel); - void setVoice(int channel); - void clearVoice(int channel); - void updateChannel(int channel); - void setFrequency(int channel); + void sub_4556E(); + void write209(); + void write211(); public: AdlibFxSoundDriver(); virtual ~AdlibFxSoundDriver(); @@ -490,12 +485,12 @@ public: virtual void close(); virtual bool reset(); virtual const GroupData *getGroupData(); - virtual void installPatch(const byte *data, int size) {} + virtual void poll(); virtual int setMasterVolume(int volume); - virtual void proc32(int channel, int program, int v0, int v1); + virtual void proc32(Sound *sound, int channel, int program, int v0, int v1); virtual void updateVoice(int channel); virtual void proc38(int channel, int cmd, int value); - virtual void setPitch(int channel, int pitchBlend); + virtual void proc42(int channel, int cmd, int value, int *v1, int *v2); // AudioStream interface virtual int readBuffer(int16 *buffer, const int numSamples); |
