aboutsummaryrefslogtreecommitdiff
path: root/engines/tinsel
diff options
context:
space:
mode:
authorNorbert Lange2009-07-17 21:23:54 +0000
committerNorbert Lange2009-07-17 21:23:54 +0000
commitbb64bf008d03e01760a468d0df8cacb164725d41 (patch)
treed73710df5b07f3fa1ca30e719c1c1f58ebe0b107 /engines/tinsel
parent81ac29ebca30c352646a5b21de512087cb96a672 (diff)
parent53756ef1d022a959b24c041e18f55eef34e60dd3 (diff)
downloadscummvm-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.h4
-rw-r--r--engines/tinsel/detection.cpp25
-rw-r--r--engines/tinsel/handle.cpp4
-rw-r--r--engines/tinsel/music.cpp4
-rw-r--r--engines/tinsel/pcode.cpp147
-rw-r--r--engines/tinsel/pcode.h14
-rw-r--r--engines/tinsel/pdisplay.cpp8
-rw-r--r--engines/tinsel/polygons.h6
-rw-r--r--engines/tinsel/sound.cpp96
-rw-r--r--engines/tinsel/sound.h10
-rw-r--r--engines/tinsel/tinlib.cpp3
-rw-r--r--engines/tinsel/tinsel.cpp4
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);