diff options
| author | Norbert Lange | 2009-07-17 21:23:54 +0000 |
|---|---|---|
| committer | Norbert Lange | 2009-07-17 21:23:54 +0000 |
| commit | bb64bf008d03e01760a468d0df8cacb164725d41 (patch) | |
| tree | d73710df5b07f3fa1ca30e719c1c1f58ebe0b107 /engines/tinsel | |
| parent | 81ac29ebca30c352646a5b21de512087cb96a672 (diff) | |
| parent | 53756ef1d022a959b24c041e18f55eef34e60dd3 (diff) | |
| download | scummvm-rg350-bb64bf008d03e01760a468d0df8cacb164725d41.tar.gz scummvm-rg350-bb64bf008d03e01760a468d0df8cacb164725d41.tar.bz2 scummvm-rg350-bb64bf008d03e01760a468d0df8cacb164725d41.zip | |
merge with trunk
svn-id: r42574
Diffstat (limited to 'engines/tinsel')
| -rw-r--r-- | engines/tinsel/actors.h | 4 | ||||
| -rw-r--r-- | engines/tinsel/detection.cpp | 25 | ||||
| -rw-r--r-- | engines/tinsel/handle.cpp | 4 | ||||
| -rw-r--r-- | engines/tinsel/music.cpp | 4 | ||||
| -rw-r--r-- | engines/tinsel/pcode.cpp | 147 | ||||
| -rw-r--r-- | engines/tinsel/pcode.h | 14 | ||||
| -rw-r--r-- | engines/tinsel/pdisplay.cpp | 8 | ||||
| -rw-r--r-- | engines/tinsel/polygons.h | 6 | ||||
| -rw-r--r-- | engines/tinsel/sound.cpp | 96 | ||||
| -rw-r--r-- | engines/tinsel/sound.h | 10 | ||||
| -rw-r--r-- | engines/tinsel/tinlib.cpp | 3 | ||||
| -rw-r--r-- | engines/tinsel/tinsel.cpp | 4 |
12 files changed, 261 insertions, 64 deletions
diff --git a/engines/tinsel/actors.h b/engines/tinsel/actors.h index 74a5ba4185..bda0e8bbb3 100644 --- a/engines/tinsel/actors.h +++ b/engines/tinsel/actors.h @@ -137,8 +137,6 @@ int GetActorFilmNumber(int ano); void StoreActorReel(int actor, int column, OBJECT *pObj); void NotPlayingReel(int actor, int filmNumber, int column); bool ActorReelPlaying(int actor, int column); -void SetActorPlayFilm(int ano, SCNHANDLE hFilm); -SCNHANDLE GetActorPlayFilm(int ano); /*----------------------------------------------------------------------*/ @@ -161,8 +159,6 @@ struct Z_POSITIONS { int z; }; -int SaveActors(SAVED_ACTOR *sActorInfo); - void RestoreActorProcess(int id, INT_CONTEXT *pic); int SaveActors(PSAVED_ACTOR sActorInfo); diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp index a3cd0bc7b7..a3f921505a 100644 --- a/engines/tinsel/detection.cpp +++ b/engines/tinsel/detection.cpp @@ -163,6 +163,28 @@ static const TinselGameDescription gameDescriptions[] = { TINSEL_V1, }, + { // Italian CD with english speech and *.gra files. + // Note: It contains only italian subtitles, but inside english.txt + { + "dw", + "CD", + { + {"dw.gra", 0, "c8808ccd988d603dd35dff42013ae7fd", 781656}, + {"english.txt", 0, "15f0703f85477d7fab4280bf938b61c1", 237774}, + {"english.smp", 0, NULL, -1}, + {NULL, 0, NULL, 0} + }, + Common::IT_ITA, + Common::kPlatformPC, + ADGF_DROPLANGUAGE, + GUIO_NONE + }, + GID_DW1, + 0, + GF_CD | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, + TINSEL_V1, + }, + { // Multilingual CD with english speech and *.gra files. // Note: It contains no english subtitles. { @@ -187,6 +209,7 @@ static const TinselGameDescription gameDescriptions[] = { GF_CD | GF_USE_4FLAGS | GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, + { { "dw", @@ -505,7 +528,7 @@ static const TinselGameDescription gameDescriptions[] = { "CD", { {"dw2.scn", 0, "c6d15ce9720a9d8fef06e6582dcf3f34", 103593}, - {"english1.smp", 0, "aa8d05f6fade11e6f066d42c302c8e89", 250926923}, + {"english1.smp", 0, NULL, -1}, {"english1.txt", 0, "b522e19d7b2cd7b85e50e36fe48e36a9", 274444}, {NULL, 0, NULL, 0} }, diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp index 9a0e1f37f8..5ef5bea702 100644 --- a/engines/tinsel/handle.cpp +++ b/engines/tinsel/handle.cpp @@ -207,9 +207,7 @@ void OpenCDGraphFile(void) { // As the theory goes, the right CD will be in there! - cdGraphStream.clearIOFailed(); - cdGraphStream.open(szCdPlayFile); - if (cdGraphStream.ioFailed()) + if (!cdGraphStream.open(szCdPlayFile)) error(CANNOT_FIND_FILE, szCdPlayFile); } diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp index f80217b4f4..12d9f0393a 100644 --- a/engines/tinsel/music.cpp +++ b/engines/tinsel/music.cpp @@ -207,6 +207,10 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) { if (track > 0) { StopMidi(); + // StopMidi resets these fields, so set them again + currentMidi = dwFileOffset; + currentLoop = bLoop; + // try to play track, but don't fall back to a true CD AudioCD.play(track, bLoop ? -1 : 1, 0, 0, true); diff --git a/engines/tinsel/pcode.cpp b/engines/tinsel/pcode.cpp index a9c6f43d85..1d73411e13 100644 --- a/engines/tinsel/pcode.cpp +++ b/engines/tinsel/pcode.cpp @@ -112,6 +112,43 @@ static INT_CONTEXT *icList = 0; static uint32 hMasterScript; +//----------------- SCRIPT BUGS WORKAROUNDS -------------- + +const byte fragment1[] = {OP_ZERO, OP_GSTORE | OPSIZE16, 206, 0}; +const int fragment1_size = 4; +const byte fragment2[] = {OP_LIBCALL | OPSIZE8, 110}; +const int fragment2_size = 2; +const byte fragment3[] = {OP_ZERO, OP_GSTORE | OPSIZE16, 490 % 256, 490 / 256}; +const int fragment3_size = 4; + +const WorkaroundEntry workaroundList[] = { + // DW1-SCN: Global 206 is whether Rincewind is trying to take the book back to the present. + // In the GRA version, it was global 373, and was reset when he is returned to the past, but + // was forgotten in the SCN version, so this ensures the flag is properly reset + {TINSEL_V1, true, 427942095, 1, fragment1_size, fragment1}, + + // DW1-GRA: Rincewind exiting the Inn is blocked by the luggage. Whilst you can then move + // into walkable areas, saving and restoring the game, it will error if you try to move. + // This fragment turns off NPC blocking for the Outside Inn rooms so that the luggage won't block + // Past Outside Inn + {TINSEL_V1, false, 444622076, 0, fragment2_size, fragment2}, + // Present Outside Inn + {TINSEL_V1, false, 352600876, 0, fragment2_size, fragment2}, + + // DW2: In the garden, global #490 is set when the bees begin their 'out of hive' animation, and reset when done. + // But if the game is saved/restored during it, the animation sequence is reset without the global being cleared. + // This causes bugs in several actions which try to disable the bees animation, since they wait indefinitely for + // the global to be cleared, incorrectly believing the animation is currently playing. This includes + // * Giving the brochure to the beekeeper + // * Stealing the mallets from the wizards + // This fix ensures that the global is reset when the Garden scene is loaded (both entering and restoring a game) + {TINSEL_V2, true, 2888147476U, 0, fragment3_size, fragment3}, + + {TINSEL_V0, false, 0, 0, 0, NULL} +}; + +//----------------- LOCAL GLOBAL DATA -------------------- + /** * Keeps the code array pointer up to date. */ @@ -398,38 +435,93 @@ void SaveInterpretContexts(INT_CONTEXT *sICInfo) { } /** - * Fetch (and sign extend, if necessary) a 8/16/32 bit value from the code - * stream and advance the instruction pointer accordingly. + * Fetches up to 4 bytes from the code script */ -static int32 Fetch(byte opcode, byte *code, int &ip) { - int32 tmp; - if (TinselV0) { - // Fetch a 32 bit value. - tmp = (int32)READ_LE_UINT32(code + ip++ * 4); - } else if (opcode & OPSIZE8) { +static int32 GetBytes(const byte *scriptCode, const WorkaroundEntry* &wkEntry, int &ip, uint numBytes) { + assert(numBytes <= 4 && numBytes != 3); + const byte *code = scriptCode; + + if (wkEntry != NULL) { + if (ip >= wkEntry->numBytes) { + // Finished the workaround + ip = wkEntry->ip; + wkEntry = NULL; + } else { + code = wkEntry->script; + } + } + + uint32 tmp; + switch (numBytes) { + case 0: + // Instruction byte + tmp = code[ip++ * (TinselV0 ? 4 : 1)]; + break; + case 1: // Fetch and sign extend a 8 bit value to 32 bits. - tmp = *(int8 *)(code + ip); - ip += 1; - } else if (opcode & OPSIZE16) { + tmp = (int8)code[ip++]; + break; + case 2: // Fetch and sign extend a 16 bit value to 32 bits. tmp = (int16)READ_LE_UINT16(code + ip); ip += 2; - } else { - // Fetch a 32 bit value. - tmp = (int32)READ_LE_UINT32(code + ip); - ip += 4; + break; + default: + if (TinselV0) + tmp = (int32)READ_LE_UINT32(code + ip++ * 4); + else { + tmp = (int32)READ_LE_UINT32(code + ip); + ip += 4; + } + break; } + return tmp; } /** + * Fetch (and sign extend, if necessary) a 8/16/32 bit value from the code + * stream and advance the instruction pointer accordingly. + */ +static int32 Fetch(byte opcode, const byte *code, const WorkaroundEntry* &wkEntry, int &ip) { + if (TinselV0) + // Fetch a 32 bit value. + return GetBytes(code, wkEntry, ip, 4); + else if (opcode & OPSIZE8) + // Fetch and sign extend a 8 bit value to 32 bits. + return GetBytes(code, wkEntry, ip, 1); + else if (opcode & OPSIZE16) + return GetBytes(code, wkEntry, ip, 2); + + return GetBytes(code, wkEntry, ip, 4); +} + +/** * Interprets the PCODE instructions in the code array. */ void Interpret(CORO_PARAM, INT_CONTEXT *ic) { do { int tmp, tmp2; int ip = ic->ip; - byte opcode = ic->code[ip++ * (TinselV0 ? 4 : 1)]; + const WorkaroundEntry *wkEntry = ic->fragmentPtr; + + if (wkEntry == NULL) { + // Check to see if a workaround fragment needs to be executed + for (wkEntry = workaroundList; wkEntry->script != NULL; ++wkEntry) { + if ((wkEntry->version == TinselVersion) && + (wkEntry->hCode == ic->hCode) && + (wkEntry->ip == ip) && + (!TinselV1 || (wkEntry->scnFlag == ((_vm->getFeatures() & GF_SCNFILES) != 0)))) { + // Point to start of workaround fragment + ip = 0; + break; + } + } + if (wkEntry->script == NULL) + wkEntry = NULL; + } + + byte opcode = (byte)GetBytes(ic->code, wkEntry, ip, 0); if (TinselV0 && ((opcode & OPMASK) > OP_IMM)) opcode += 3; @@ -447,7 +539,7 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) { case OP_FONT: // loads font handle onto stack case OP_PAL: // loads palette handle onto stack - ic->stack[++ic->sp] = Fetch(opcode, ic->code, ip); + ic->stack[++ic->sp] = Fetch(opcode, ic->code, wkEntry, ip); break; case OP_ZERO: // loads zero onto stack @@ -464,31 +556,31 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) { case OP_LOAD: // loads local variable onto stack - ic->stack[++ic->sp] = ic->stack[ic->bp + Fetch(opcode, ic->code, ip)]; + ic->stack[++ic->sp] = ic->stack[ic->bp + Fetch(opcode, ic->code, wkEntry, ip)]; break; case OP_GLOAD: // loads global variable onto stack - tmp = Fetch(opcode, ic->code, ip); + tmp = Fetch(opcode, ic->code, wkEntry, ip); assert(0 <= tmp && tmp < numGlobals); ic->stack[++ic->sp] = pGlobals[tmp]; break; case OP_STORE: // pops stack and stores in local variable - ic->stack[ic->bp + Fetch(opcode, ic->code, ip)] = ic->stack[ic->sp--]; + ic->stack[ic->bp + Fetch(opcode, ic->code, wkEntry, ip)] = ic->stack[ic->sp--]; break; case OP_GSTORE: // pops stack and stores in global variable - tmp = Fetch(opcode, ic->code, ip); + tmp = Fetch(opcode, ic->code, wkEntry, ip); assert(0 <= tmp && tmp < numGlobals); pGlobals[tmp] = ic->stack[ic->sp--]; break; case OP_CALL: // procedure call - tmp = Fetch(opcode, ic->code, ip); + tmp = Fetch(opcode, ic->code, wkEntry, ip); //assert(0 <= tmp && tmp < codeSize); // TODO: Verify jumps are not out of bounds ic->stack[ic->sp + 1] = 0; // static link ic->stack[ic->sp + 2] = ic->bp; // dynamic link @@ -499,7 +591,7 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) { case OP_LIBCALL: // library procedure or function call - tmp = Fetch(opcode, ic->code, ip); + tmp = Fetch(opcode, ic->code, wkEntry, ip); // NOTE: Interpret() itself is not using the coroutine facilities, // but still accepts a CORO_PARAM, so from the outside it looks // like a coroutine. In fact it may still acts as a kind of "proxy" @@ -538,17 +630,17 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) { case OP_ALLOC: // allocate storage on stack - ic->sp += (int32)Fetch(opcode, ic->code, ip); + ic->sp += (int32)Fetch(opcode, ic->code, wkEntry, ip); break; case OP_JUMP: // unconditional jump - ip = Fetch(opcode, ic->code, ip); + ip = Fetch(opcode, ic->code, wkEntry, ip); break; case OP_JMPFALSE: // conditional jump - tmp = Fetch(opcode, ic->code, ip); + tmp = Fetch(opcode, ic->code, wkEntry, ip); if (ic->stack[ic->sp--] == 0) { // condition satisfied - do the jump ip = tmp; @@ -557,7 +649,7 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) { case OP_JMPTRUE: // conditional jump - tmp = Fetch(opcode, ic->code, ip); + tmp = Fetch(opcode, ic->code, wkEntry, ip); if (ic->stack[ic->sp--] != 0) { // condition satisfied - do the jump ip = tmp; @@ -660,6 +752,7 @@ void Interpret(CORO_PARAM, INT_CONTEXT *ic) { // check for stack under-overflow assert(ic->sp >= 0 && ic->sp < PCODE_STACK_SIZE); ic->ip = ip; + ic->fragmentPtr = wkEntry; } while (!ic->bHalt); // make sure stack is unwound diff --git a/engines/tinsel/pcode.h b/engines/tinsel/pcode.h index 4bdfcf5626..fad50cdb9d 100644 --- a/engines/tinsel/pcode.h +++ b/engines/tinsel/pcode.h @@ -54,6 +54,17 @@ enum GSORT { enum RESCODE {RES_WAITING, RES_FINISHED, RES_CUTSHORT}; +// The following structure is used to introduce bug fixes into the scripts used by the games + +struct WorkaroundEntry { + TinselEngineVersion version; + bool scnFlag; // Only applicable for Tinsel 1 (DW 1) + SCNHANDLE hCode; // Script to apply fragment to + int ip; // Script offset to run this fragment before + int numBytes; // Number of bytes in the script + const byte *script; // Instruction(s) to execute +}; + struct INT_CONTEXT { // Elements for interpret context management @@ -82,6 +93,9 @@ struct INT_CONTEXT { RESCODE resumeCode; RESUME_STATE resumeState; + // Used to store execution state within a script workaround fragment + const WorkaroundEntry *fragmentPtr; + void syncWithSerializer(Common::Serializer &s); }; typedef INT_CONTEXT *PINT_CONTEXT; diff --git a/engines/tinsel/pdisplay.cpp b/engines/tinsel/pdisplay.cpp index e0262839a2..17e9a3a517 100644 --- a/engines/tinsel/pdisplay.cpp +++ b/engines/tinsel/pdisplay.cpp @@ -55,14 +55,6 @@ extern int newestString; // The overrun counter, in STRRES.C #endif -//----------------- EXTERNAL FUNCTIONS --------------------- - -// in BG.C -extern int BgWidth(void); -extern int BgHeight(void); - - - //----------------- LOCAL DEFINES -------------------- #define LPOSX 295 // X-co-ord of lead actor's position display diff --git a/engines/tinsel/polygons.h b/engines/tinsel/polygons.h index 62ec0422c6..7cb22a1b8a 100644 --- a/engines/tinsel/polygons.h +++ b/engines/tinsel/polygons.h @@ -92,7 +92,6 @@ bool IsPolyCorner(HPOLYGON hPath, int x, int y); int GetScale(HPOLYGON path, int y); int GetBrightness(HPOLYGON hPath, int y); void getNpathNode(HPOLYGON npath, int node, int *px, int *py); -void GetTagTag(HPOLYGON p, SCNHANDLE *hTagText, int *tagx, int *tagy); SCNHANDLE GetPolyFilm(HPOLYGON p); void GetPolyNode(HPOLYGON hp, int *pNodeX, int *pNodeY); SCNHANDLE GetPolyScript(HPOLYGON p); @@ -108,8 +107,6 @@ void DisablePath(int path); void EnablePath(int path); void DisableRefer(int refer); void EnableRefer(int refer); -void DisableBlock(int blockno); -void EnableBlock(int blockno); HPOLYGON GetTagHandle(int tagno); void DisableTag(CORO_PARAM, int tag); void EnableTag(CORO_PARAM, int tag); @@ -152,8 +149,7 @@ bool PolyTagIsWanted(HPOLYGON hp); bool PolyTagFollowsCursor(HPOLYGON hp); SCNHANDLE GetPolyTagHandle(HPOLYGON hp); bool IsTagPolygon(int tagno); -int GetTagPolyId(HPOLYGON hp); -void GetPolyMidBottom( HPOLYGON hp, int *pX, int *pY); +void GetPolyMidBottom(HPOLYGON hp, int *pX, int *pY); int PathCount(void); void MovePolygon(PTYPE ptype, int id, int x, int y); void MovePolygonTo(PTYPE ptype, int id, int x, int y); diff --git a/engines/tinsel/sound.cpp b/engines/tinsel/sound.cpp index a07a417723..c6d30fa222 100644 --- a/engines/tinsel/sound.cpp +++ b/engines/tinsel/sound.cpp @@ -41,6 +41,9 @@ #include "sound/mixer.h" #include "sound/adpcm.h" #include "sound/vag.h" +#include "sound/flac.h" +#include "sound/mp3.h" +#include "sound/vorbis.h" #include "gui/message.h" @@ -52,7 +55,9 @@ extern LANGUAGE sampleLanguage; SoundManager::SoundManager(TinselEngine *vm) : //_vm(vm), // TODO: Enable this once global _vm var is gone - _sampleIndex(0), _sampleIndexLen(0) { + _sampleIndex(0), _sampleIndexLen(0), + _soundMode(kVOCMode) + { for (int i = 0; i < kNumChannels; i++) _channels[i].sampleNum = _channels[i].subSample = -1; @@ -68,6 +73,7 @@ SoundManager::~SoundManager() { * @param type type of sound (voice or sfx) * @param handle sound handle */ +// playSample for DiscWorld 1 bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::SoundHandle *handle) { // Floppy version has no sample file if (_vm->getFeatures() & GF_FLOPPY) @@ -114,7 +120,7 @@ bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::Sound _vm->_mixer->playInputStream(type, &curChan.handle, vagStream); } else { // allocate a buffer - void *sampleBuf = malloc(sampleLen); + byte *sampleBuf = (byte *)malloc(sampleLen); assert(sampleBuf); // read all of the sample @@ -126,10 +132,35 @@ bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::Sound //_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundVolumeMusic); _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volVoice); + Common::MemoryReadStream *compressedStream = + new Common::MemoryReadStream(sampleBuf, sampleLen, true); + Audio::AudioStream *sampleStream = 0; // play it - _vm->_mixer->playRaw(type, &curChan.handle, sampleBuf, sampleLen, 22050, - Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_UNSIGNED); + switch (_soundMode) { + case kMP3Mode: + #ifdef USE_MAD + sampleStream = Audio::makeMP3Stream(compressedStream, true); + #endif + break; + case kVorbisMode: + #ifdef USE_VORBIS + sampleStream = Audio::makeVorbisStream(compressedStream, true); + #endif + break; + case kFlacMode: + #ifdef USE_FLAC + sampleStream = Audio::makeFlacStream(compressedStream, true); + #endif + break; + default: + _vm->_mixer->playRaw(type, &curChan.handle, sampleBuf, sampleLen, 22050, + Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_UNSIGNED); + break; + } + if (sampleStream) { + _vm->_mixer->playInputStream(type, &curChan.handle, sampleStream); + } } if (handle) @@ -138,6 +169,7 @@ bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::Sound return true; } +// playSample for DiscWorld 2 bool SoundManager::playSample(int id, int sub, bool bLooped, int x, int y, int priority, Audio::Mixer::SoundType type, Audio::SoundHandle *handle) { @@ -251,10 +283,30 @@ bool SoundManager::playSample(int id, int sub, bool bLooped, int x, int y, int p if (_sampleStream.read(sampleBuf, sampleLen) != sampleLen) error(FILE_IS_CORRUPT, _vm->getSampleFile(sampleLanguage)); - Common::MemoryReadStream *sampleStream = + Common::MemoryReadStream *compressedStream = new Common::MemoryReadStream(sampleBuf, sampleLen, true); - Audio::AudioStream *_stream = - makeADPCMStream(sampleStream, true, sampleLen, Audio::kADPCMTinsel6, 22050, 1, 24); + Audio::AudioStream *sampleStream = 0; + + switch (_soundMode) { + case kMP3Mode: + #ifdef USE_MAD + sampleStream = Audio::makeMP3Stream(compressedStream, true); + #endif + break; + case kVorbisMode: + #ifdef USE_VORBIS + sampleStream = Audio::makeVorbisStream(compressedStream, true); + #endif + break; + case kFlacMode: + #ifdef USE_FLAC + sampleStream = Audio::makeFlacStream(compressedStream, true); + #endif + break; + default: + sampleStream = Audio::makeADPCMStream(compressedStream, true, sampleLen, Audio::kADPCMTinsel6, 22050, 1, 24); + break; + } // FIXME: Should set this in a different place ;) _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volSound); @@ -269,10 +321,12 @@ bool SoundManager::playSample(int id, int sub, bool bLooped, int x, int y, int p curChan->priority = priority; curChan->lastStart = g_system->getMillis(); // /---Compression----\ Milis BytesPerSecond - curChan->timeDuration = (((sampleLen * 64) / 25) * 1000) / (22050 * 2); + // not needed and won't work when using MP3/OGG/FLAC anyway + //curChan->timeDuration = (((sampleLen * 64) / 25) * 1000) / (22050 * 2); // Play it - _vm->_mixer->playInputStream(type, &curChan->handle, _stream); + _vm->_mixer->playInputStream(type, &curChan->handle, sampleStream); + _vm->_mixer->setChannelVolume(curChan->handle, sndVol); _vm->_mixer->setChannelBalance(curChan->handle, getPan(x)); @@ -455,6 +509,30 @@ void SoundManager::openSampleFiles(void) { // convert file size to size in DWORDs _sampleIndexLen /= sizeof(uint32); + + // Detect format of soundfile by looking at 1st sample-index + switch (_sampleIndex[0]) { + case MKID_BE(' 3PM'): + debugC(DEBUG_DETAILED, kTinselDebugSound, "Detected MP3 sound-data"); + _soundMode = kMP3Mode; + break; + + case MKID_BE(' GGO'): + debugC(DEBUG_DETAILED, kTinselDebugSound, "Detected OGG sound-data"); + _soundMode = kVorbisMode; + break; + + case MKID_BE('CLAF'): + debugC(DEBUG_DETAILED, kTinselDebugSound, "Detected FLAC sound-data"); + _soundMode = kFlacMode; + break; + + default: + debugC(DEBUG_DETAILED, kTinselDebugSound, "Detected original sound-data"); + break; + } + // Normally the 1st sample-index points to nothing at all + _sampleIndex[0] = 0; } else { char buf[50]; sprintf(buf, CANNOT_FIND_FILE, _vm->getSampleIndex(sampleLanguage)); diff --git a/engines/tinsel/sound.h b/engines/tinsel/sound.h index 15919f8ec5..9bdd037ff0 100644 --- a/engines/tinsel/sound.h +++ b/engines/tinsel/sound.h @@ -58,6 +58,13 @@ protected: }; static const int kNumChannels = kChannelSFX + kNumSFX; + enum SoundMode { + kVOCMode, + kMP3Mode, + kVorbisMode, + kFlacMode + }; + struct Channel { // Sample handle Audio::SoundHandle handle; @@ -87,6 +94,9 @@ protected: /** Number of entries in the sample index */ long _sampleIndexLen; + /** Specifies if the sample-data is compressed and if yes, how */ + SoundMode _soundMode; + /** file stream for sample file */ TinselFile _sampleStream; diff --git a/engines/tinsel/tinlib.cpp b/engines/tinsel/tinlib.cpp index b73a66b6d3..4b5e0ce450 100644 --- a/engines/tinsel/tinlib.cpp +++ b/engines/tinsel/tinlib.cpp @@ -89,8 +89,6 @@ int clRunMode = 0; // in BG.CPP extern void ChangePalette(SCNHANDLE hPal); -extern int BgWidth(void); -extern int BgHeight(void); // in BMV.CPP void PlayBMV(CORO_PARAM, SCNHANDLE hFileStem, int myEscape); @@ -278,7 +276,6 @@ static COLORREF s_talkfontColor = 0; //----------------- FORWARD REFERENCES -------------------- static int HeldObject(void); -void Offset(EXTREME extreme, int x, int y); static void PostTag(CORO_PARAM, int tagno, TINSEL_EVENT event, HPOLYGON hp, int myEscape); void ResetIdleTime(void); static void SendTag(CORO_PARAM, int tagno, TINSEL_EVENT event, HPOLYGON hp, int myEscape, bool *result); diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp index 1a08fd2420..95541e3287 100644 --- a/engines/tinsel/tinsel.cpp +++ b/engines/tinsel/tinsel.cpp @@ -93,10 +93,6 @@ extern void InventoryProcess(CORO_PARAM, const void *); extern void PrimeBackground(); extern SCNHANDLE GetSceneHandle(void); -// In TIMER.CPP -extern void FettleTimers(void); -extern void RebootTimers(void); - //----------------- FORWARD DECLARATIONS --------------------- void SetNewScene(SCNHANDLE scene, int entrance, int transition); |
