[Scummvm-cvs-logs] SF.net SVN: scummvm: [23136] tools/trunk

h00ligan at users.sourceforge.net h00ligan at users.sourceforge.net
Thu Jun 15 16:37:56 CEST 2006


Revision: 23136
Author:   h00ligan
Date:     2006-06-15 07:34:46 -0700 (Thu, 15 Jun 2006)
ViewCVS:  http://svn.sourceforge.net/scummvm/?rev=23136&view=rev

Log Message:
-----------
compress SAGA WIP #2

Modified Paths:
--------------
    tools/trunk/compress.c
    tools/trunk/compress_saga.cpp
    tools/trunk/util.c
    tools/trunk/util.h

Added Paths:
-----------
    tools/trunk/utils/
    tools/trunk/utils/adpcm.cpp
    tools/trunk/utils/adpcm.h
    tools/trunk/utils/audiostream.cpp
    tools/trunk/utils/audiostream.h
    tools/trunk/utils/file.cpp
    tools/trunk/utils/file.h
    tools/trunk/utils/md5.cpp
    tools/trunk/utils/md5.h
    tools/trunk/utils/stream.h
    tools/trunk/utils/util.h
    tools/trunk/utils/voc.cpp
    tools/trunk/utils/voc.h
    tools/trunk/utils/wave.cpp
    tools/trunk/utils/wave.h
Modified: tools/trunk/compress.c
===================================================================
--- tools/trunk/compress.c	2006-06-15 14:28:19 UTC (rev 23135)
+++ tools/trunk/compress.c	2006-06-15 14:34:46 UTC (rev 23136)
@@ -225,8 +225,6 @@
 	}
 	fclose(f);
 
-	/* TODO: setRawAudioType(false, false, 8); */
-
 	/* Convert the WAV temp file to OGG/MP3 */
 	encodeAudio(outName, false, -1, tempEncoded, compMode);
 }

Modified: tools/trunk/compress_saga.cpp
===================================================================
--- tools/trunk/compress_saga.cpp	2006-06-15 14:28:19 UTC (rev 23135)
+++ tools/trunk/compress_saga.cpp	2006-06-15 14:34:46 UTC (rev 23136)
@@ -24,312 +24,15 @@
 
 #include <stdio.h>
 #include "compress.h"
+#include "utils/md5.h"
+#include "utils/util.h"
+#include "utils/AudioStream.h"
+#include "utils/File.h"
+#include "utils/voc.h"
+#include "utils/wave.h"
+#include "utils/adpcm.h"
 
-namespace Common {
 
-// <!-- taken from common\util.h
-
-/**
- * List of game language.
- */
-enum Language {
-	EN_ANY,     // Generic English (when only one game version exist)
-	EN_USA,
-	EN_GRB,
-
-	DE_DEU,
-	FR_FRA,
-	IT_ITA,
-	PT_BRA,
-	ES_ESP,
-	JA_JPN,
-	ZH_TWN,
-	KO_KOR,
-	SE_SWE,
-	HB_ISR,
-	RU_RUS,
-	CZ_CZE,
-	NL_NLD,
-	NB_NOR,
-	PL_POL,
-
-	UNK_LANG = -1	// Use default language (i.e. none specified)
-};
-
-/**
- * List of game platforms. Specifying a platform for a target can be used to
- * give the game engines a hint for which platform the game data file are.
- * This may be optional or required, depending on the game engine and the
- * game in question.
- */
-enum Platform {
-	kPlatformPC,
-	kPlatformAmiga,
-	kPlatformAtariST,
-	kPlatformMacintosh,
-	kPlatformFMTowns,
-	kPlatformWindows,
-	kPlatformNES,
-	kPlatformC64,
-	kPlatformLinux,
-	kPlatformAcorn,
-	kPlatformSegaCD,
-	kPlatform3DO,
-//	kPlatformPCEngine,
-
-	kPlatformUnknown = -1
-};
-//  taken from common\util.h -->
-
-// <!-- taken from common/md5.c
-
-typedef struct {
-	uint32 total[2];
-	uint32 state[4];
-	uint8 buffer[64];
-} md5_context;
-
-#define GET_UINT32(n, b, i)	(n) = READ_LE_UINT32(b + i)
-#define PUT_UINT32(n, b, i)	WRITE_LE_UINT32(b + i, n)
-
-void md5_starts(md5_context *ctx) {
-	ctx->total[0] = 0;
-	ctx->total[1] = 0;
-
-	ctx->state[0] = 0x67452301;
-	ctx->state[1] = 0xEFCDAB89;
-	ctx->state[2] = 0x98BADCFE;
-	ctx->state[3] = 0x10325476;
-}
-
-static void md5_process(md5_context *ctx, const uint8 data[64]) {
-	uint32 X[16], A, B, C, D;
-
-	GET_UINT32(X[0],  data,  0);
-	GET_UINT32(X[1],  data,  4);
-	GET_UINT32(X[2],  data,  8);
-	GET_UINT32(X[3],  data, 12);
-	GET_UINT32(X[4],  data, 16);
-	GET_UINT32(X[5],  data, 20);
-	GET_UINT32(X[6],  data, 24);
-	GET_UINT32(X[7],  data, 28);
-	GET_UINT32(X[8],  data, 32);
-	GET_UINT32(X[9],  data, 36);
-	GET_UINT32(X[10], data, 40);
-	GET_UINT32(X[11], data, 44);
-	GET_UINT32(X[12], data, 48);
-	GET_UINT32(X[13], data, 52);
-	GET_UINT32(X[14], data, 56);
-	GET_UINT32(X[15], data, 60);
-
-#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
-
-#define P(a, b, c, d, k, s, t)                    \
-{                                                 \
-	a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
-}
-
-	A = ctx->state[0];
-	B = ctx->state[1];
-	C = ctx->state[2];
-	D = ctx->state[3];
-
-#define F(x, y, z) (z ^ (x & (y ^ z)))
-
-	P(A, B, C, D,  0,  7, 0xD76AA478);
-	P(D, A, B, C,  1, 12, 0xE8C7B756);
-	P(C, D, A, B,  2, 17, 0x242070DB);
-	P(B, C, D, A,  3, 22, 0xC1BDCEEE);
-	P(A, B, C, D,  4,  7, 0xF57C0FAF);
-	P(D, A, B, C,  5, 12, 0x4787C62A);
-	P(C, D, A, B,  6, 17, 0xA8304613);
-	P(B, C, D, A,  7, 22, 0xFD469501);
-	P(A, B, C, D,  8,  7, 0x698098D8);
-	P(D, A, B, C,  9, 12, 0x8B44F7AF);
-	P(C, D, A, B, 10, 17, 0xFFFF5BB1);
-	P(B, C, D, A, 11, 22, 0x895CD7BE);
-	P(A, B, C, D, 12,  7, 0x6B901122);
-	P(D, A, B, C, 13, 12, 0xFD987193);
-	P(C, D, A, B, 14, 17, 0xA679438E);
-	P(B, C, D, A, 15, 22, 0x49B40821);
-
-#undef F
-
-#define F(x, y, z) (y ^ (z & (x ^ y)))
-
-	P(A, B, C, D,  1,  5, 0xF61E2562);
-	P(D, A, B, C,  6,  9, 0xC040B340);
-	P(C, D, A, B, 11, 14, 0x265E5A51);
-	P(B, C, D, A,  0, 20, 0xE9B6C7AA);
-	P(A, B, C, D,  5,  5, 0xD62F105D);
-	P(D, A, B, C, 10,  9, 0x02441453);
-	P(C, D, A, B, 15, 14, 0xD8A1E681);
-	P(B, C, D, A,  4, 20, 0xE7D3FBC8);
-	P(A, B, C, D,  9,  5, 0x21E1CDE6);
-	P(D, A, B, C, 14,  9, 0xC33707D6);
-	P(C, D, A, B,  3, 14, 0xF4D50D87);
-	P(B, C, D, A,  8, 20, 0x455A14ED);
-	P(A, B, C, D, 13,  5, 0xA9E3E905);
-	P(D, A, B, C,  2,  9, 0xFCEFA3F8);
-	P(C, D, A, B,  7, 14, 0x676F02D9);
-	P(B, C, D, A, 12, 20, 0x8D2A4C8A);
-
-#undef F
-
-#define F(x, y, z) (x ^ y ^ z)
-
-	P(A, B, C, D,  5,  4, 0xFFFA3942);
-	P(D, A, B, C,  8, 11, 0x8771F681);
-	P(C, D, A, B, 11, 16, 0x6D9D6122);
-	P(B, C, D, A, 14, 23, 0xFDE5380C);
-	P(A, B, C, D,  1,  4, 0xA4BEEA44);
-	P(D, A, B, C,  4, 11, 0x4BDECFA9);
-	P(C, D, A, B,  7, 16, 0xF6BB4B60);
-	P(B, C, D, A, 10, 23, 0xBEBFBC70);
-	P(A, B, C, D, 13,  4, 0x289B7EC6);
-	P(D, A, B, C,  0, 11, 0xEAA127FA);
-	P(C, D, A, B,  3, 16, 0xD4EF3085);
-	P(B, C, D, A,  6, 23, 0x04881D05);
-	P(A, B, C, D,  9,  4, 0xD9D4D039);
-	P(D, A, B, C, 12, 11, 0xE6DB99E5);
-	P(C, D, A, B, 15, 16, 0x1FA27CF8);
-	P(B, C, D, A,  2, 23, 0xC4AC5665);
-
-#undef F
-
-#define F(x, y, z) (y ^ (x | ~z))
-
-	P(A, B, C, D,  0,  6, 0xF4292244);
-	P(D, A, B, C,  7, 10, 0x432AFF97);
-	P(C, D, A, B, 14, 15, 0xAB9423A7);
-	P(B, C, D, A,  5, 21, 0xFC93A039);
-	P(A, B, C, D, 12,  6, 0x655B59C3);
-	P(D, A, B, C,  3, 10, 0x8F0CCC92);
-	P(C, D, A, B, 10, 15, 0xFFEFF47D);
-	P(B, C, D, A,  1, 21, 0x85845DD1);
-	P(A, B, C, D,  8,  6, 0x6FA87E4F);
-	P(D, A, B, C, 15, 10, 0xFE2CE6E0);
-	P(C, D, A, B,  6, 15, 0xA3014314);
-	P(B, C, D, A, 13, 21, 0x4E0811A1);
-	P(A, B, C, D,  4,  6, 0xF7537E82);
-	P(D, A, B, C, 11, 10, 0xBD3AF235);
-	P(C, D, A, B,  2, 15, 0x2AD7D2BB);
-	P(B, C, D, A,  9, 21, 0xEB86D391);
-
-#undef F
-
-	ctx->state[0] += A;
-	ctx->state[1] += B;
-	ctx->state[2] += C;
-	ctx->state[3] += D;
-}
-
-void md5_update(md5_context *ctx, const uint8 *input, uint32 length) {
-	uint32 left, fill;
-
-	if (!length)
-		return;
-
-	left = ctx->total[0] & 0x3F;
-	fill = 64 - left;
-
-	ctx->total[0] += length;
-	ctx->total[0] &= 0xFFFFFFFF;
-
-	if (ctx->total[0] < length)
-		ctx->total[1]++;
-
-	if (left && length >= fill) {
-		memcpy((void *)(ctx->buffer + left), (const void *)input, fill);
-		md5_process(ctx, ctx->buffer);
-		length -= fill;
-		input  += fill;
-		left = 0;
-	}
-
-	while (length >= 64) {
-		md5_process(ctx, input);
-		length -= 64;
-		input  += 64;
-	}
-
-	if (length) {
-		memcpy((void *)(ctx->buffer + left), (const void *)input, length);
-	}
-}
-
-static const uint8 md5_padding[64] = {
-	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-void md5_finish(md5_context *ctx, uint8 digest[16]) {
-	uint32 last, padn;
-	uint32 high, low;
-	uint8 msglen[8];
-
-	high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
-	low  = (ctx->total[0] <<  3);
-
-	PUT_UINT32(low,  msglen, 0);
-	PUT_UINT32(high, msglen, 4);
-
-	last = ctx->total[0] & 0x3F;
-	padn = (last < 56) ? (56 - last) : (120 - last);
-
-	md5_update(ctx, md5_padding, padn);
-	md5_update(ctx, msglen, 8);
-
-	PUT_UINT32(ctx->state[0], digest,  0);
-	PUT_UINT32(ctx->state[1], digest,  4);
-	PUT_UINT32(ctx->state[2], digest,  8);
-	PUT_UINT32(ctx->state[3], digest, 12);
-}
-
-bool md5_file(const char *name, uint8 digest[16], uint32 length) {
-	FILE *f;
-
-	f = fopen(name, "rb");
-	if (f == NULL) {
-		printf("md5_file couldn't open '%s'", name);
-		return false;
-	}
-
-	md5_context ctx;
-	uint32 i;
-	unsigned char buf[1000];
-	bool restricted = (length != 0);
-	int readlen;
-
-	if (!restricted || sizeof(buf) <= length)
-		readlen = sizeof(buf);
-	else
-		readlen = length;
-
-	md5_starts(&ctx);
-
-	
-	while ((i = (uint32)fread(buf, 1, readlen, f)) > 0) {
-		md5_update(&ctx, buf, i);
-
-		length -= i;
-		if (restricted && length == 0)
-			break;
-
-		if (restricted && sizeof(buf) > length)
-			readlen = length;
-	}
-
-	md5_finish(&ctx, digest);
-	fclose(f);
-	return true;
-}
-
-}
-// taken from common/md5.c -->
-
 #include "sagagame.h"
 #include "sagaresnames.h"
 #include "sagagame.cpp"
@@ -343,6 +46,7 @@
 
 GameDescription *currentGameDescription = NULL;
 int currentFileIndex = -1;
+bool isBigEndian = false;
 
 bool detectFile(const char *inFileName) {
 	int gamesCount = ARRAYSIZE(gameDescriptions);
@@ -410,23 +114,120 @@
 	fclose(tempf);
 }
 
+void writeBufferToFile(uint8* data, uint32 inputSize, const char* toFileName) {
+	FILE * tempf;
+	
+	tempf = fopen(toFileName, "wb");
+	if (tempf == NULL)
+		error("unable to open %s\n", toFileName);
+	fwrite(data, 1, inputSize, tempf);
+	fclose(tempf);
+}
+
+#define HEADER_SIZE 9
+
+uint16 sampleRate;
+uint32 sampleSize;
+uint8 sampleBits;
+uint8 sampleStereo;
+
+void writeHeader(FILE* outputFile) {
+	writeByte(outputFile, gCompMode);
+	writeUint16LE(outputFile, sampleRate);
+	writeUint32LE(outputFile, sampleSize);
+	writeByte(outputFile, sampleBits);
+	writeByte(outputFile, sampleStereo);
+}
+/*
+case kSoundVOX:
+        buffer.frequency = soundInfo->frequency;
+        buffer.isSigned = soundInfo->isSigned;
+        buffer.sampleBits = soundInfo->sampleBits;
+        buffer.stereo = soundInfo->stereo;
+        buffer.size = soundResourceLength * 4;
+        if (onlyHeader) {
+                buffer.buffer = NULL;
+                free(soundResource);
+        } else {
+                voxStream = Audio::makeADPCMStream(&readS, soundResourceLength, Audio::kADPCMOki);
+                buffer.buffer = (byte *)malloc(buffer.size);
+                voxSize = voxStream->readBuffer((int16*)buffer.buffer, soundResourceLength * 2);
+                if (voxSize != soundResourceLength * 2) {
+                        error("SndRes::load() wrong VOX output size");
+                }
+                delete voxStream;
+        }
+        result = true;
+        break;
+*/
 uint32 encodeEntry(GameSoundInfo *soundInfo, FILE* inputFile, uint32 inputSize, FILE* outputFile) {
+	Audio::AudioStream *inStream;
+	uint8 *inputData;
+	Common::File inputFileStream(inputFile);
+	int rate, size;
+	byte flags;
+	
+	if (soundInfo->resourceType == kSoundVOX) {
+		sampleSize = inputSize * 4;
+		sampleRate = (uint16)soundInfo->frequency;
+		sampleBits = soundInfo->sampleBits;
+		sampleStereo = soundInfo->stereo;
+		writeHeader(outputFile);
 
+		inStream = Audio::makeADPCMStream(&inputFileStream, inputSize, Audio::kADPCMOki);
+        inputData = (byte *)malloc(sampleSize);
+		inStream->readBuffer((int16*)inputData, inputSize * 2);
+		delete inStream;
+		writeBufferToFile(inputData, sampleSize, TEMP_RAW);
+		free(inputData);
+
+		setRawAudioType( true, sampleStereo != 0, sampleBits);
+		encodeAudio(TEMP_RAW, true, sampleRate, tempEncoded, gCompMode);
+		return copyFile(tempEncoded, outputFile) + HEADER_SIZE;
+	}
 	if (soundInfo->resourceType == kSoundVOC) {
-		fseek(inputFile, 26, SEEK_CUR); //skip header, assume it's OK
-		extractAndEncodeVOC(TEMP_RAW, inputFile, gCompMode);
-		return copyFile(tempEncoded, outputFile);
+		inputData = Audio::loadVOCFromStream(inputFileStream, size, rate);
+		sampleSize = size;
+		sampleRate = rate;
+		sampleBits = 8;
+		sampleStereo = 0;
+		writeBufferToFile(inputData, sampleSize, TEMP_RAW);
+		free(inputData);
+		writeHeader(outputFile);
+
+		setRawAudioType( true, false, 8);
+		encodeAudio(TEMP_RAW, true, sampleRate, tempEncoded, gCompMode);
+		return copyFile(tempEncoded, outputFile) + HEADER_SIZE;
 	}
 	if (soundInfo->resourceType == kSoundPCM) {
 		copyFile(inputFile, inputSize, TEMP_RAW);
+		sampleSize = inputSize;
+		sampleRate = (uint16)soundInfo->frequency;
+		sampleBits = soundInfo->sampleBits;
+		sampleStereo = soundInfo->stereo;
+		writeHeader(outputFile);
 
-		//BUG-BUG: bool(c++) -> bool(c) cause bug in al->eax conversion
 		setRawAudioType( !soundInfo->isBigEndian, soundInfo->stereo, soundInfo->sampleBits);
 		encodeAudio(TEMP_RAW, true, soundInfo->frequency, tempEncoded, gCompMode);
-		return copyFile(tempEncoded, outputFile);
+		return copyFile(tempEncoded, outputFile) + HEADER_SIZE;
 	}
+	if (soundInfo->resourceType == kSoundWAV) {
+		if (!Audio::loadWAVFromStream(inputFileStream, size, rate, flags))
+			error("Unable to read WAV");
 
+		sampleSize = size;
+		sampleRate = rate;
+		sampleBits = ((flags & Audio::Mixer::FLAG_16BITS) != 0) ? 16 : 8;
+		sampleStereo = ((flags & Audio::Mixer::FLAG_STEREO) != 0);
+		writeHeader(outputFile);
 
+		copyFile(inputFile, size, TEMP_RAW);
+
+		setRawAudioType( true, sampleStereo != 0, sampleBits);
+		encodeAudio(TEMP_RAW, true, sampleRate, tempEncoded, gCompMode);
+		return copyFile(tempEncoded, outputFile) + HEADER_SIZE;
+	}
+
 	error("sorry - unsupported resourceType %ul\n", soundInfo->resourceType);
 }
 
@@ -446,6 +247,14 @@
 	GameFileDescription *currentFileDescription;
 	GameSoundInfo *soundInfo;
 
+	currentFileDescription = &currentGameDescription->filesDescriptions[currentFileIndex];
+	
+	isBigEndian = ((currentGameDescription->features & GF_BIG_ENDIAN_DATA) != 0);
+
+	if (currentFileDescription->fileType & GAME_SWAPENDIAN)
+		isBigEndian = !isBigEndian;
+	///isBigEndian = false;
+
 	inputFile = fopen(inputFileName, "rb");
 	inputFileSize = fileSize(inputFile);
 	printf("filesize: %ul\n", inputFileSize);
@@ -456,8 +265,13 @@
 	 */
 	fseek(inputFile, inputFileSize - RSC_TABLEINFO_SIZE, SEEK_SET);
 
-	resTableOffset = readUint32LE(inputFile);
-	resTableCount = readUint32LE(inputFile);
+	if (!isBigEndian) {
+		resTableOffset = readUint32LE(inputFile);
+		resTableCount = readUint32LE(inputFile);
+	} else {
+		resTableOffset = readUint32BE(inputFile);
+		resTableCount = readUint32BE(inputFile);
+	}
 
 	printf("table offset: %ul\nnumber of records: %ul\n", resTableOffset, resTableCount);
 	if (resTableOffset != inputFileSize - RSC_TABLEINFO_SIZE - RSC_TABLEENTRY_SIZE * resTableCount) {
@@ -472,8 +286,13 @@
 	// Put offsets of all the records in a table 
 	for (i = 0; i < resTableCount; i++) {
 
+	if (!isBigEndian) {
 		inputTable[i].offset = readUint32LE(inputFile);
 		inputTable[i].size = readUint32LE(inputFile);
+	} else {
+		inputTable[i].offset = readUint32BE(inputFile);
+		inputTable[i].size = readUint32BE(inputFile);
+	}
 
 		 printf("record: %ul, offset: %ul, size: %ul\n", i, inputTable[i].offset, inputTable[i].size);
 	
@@ -483,7 +302,6 @@
 		}
 
 	}
-	currentFileDescription = &currentGameDescription->filesDescriptions[currentFileIndex];
 	outputTable = (Record*)malloc(resTableCount * sizeof(Record));
 	
 	outputFile = fopen("out.res", "wb");

Modified: tools/trunk/util.c
===================================================================
--- tools/trunk/util.c	2006-06-15 14:28:19 UTC (rev 23135)
+++ tools/trunk/util.c	2006-06-15 14:34:46 UTC (rev 23136)
@@ -51,6 +51,17 @@
 	fprintf(stderr, "WARNING: %s!\n", buf);
 }
 
+void debug(int level, const char *s, ...) {
+	char buf[1024];
+	va_list va;
+
+	va_start(va, s);
+	vsnprintf(buf, 1024, s, va);
+	va_end(va);
+
+	fprintf(stderr, "DEBUG: %s!\n", buf);
+}
+
 uint8 readByte(FILE *fp) {
 	return fgetc(fp);
 }

Modified: tools/trunk/util.h
===================================================================
--- tools/trunk/util.h	2006-06-15 14:28:19 UTC (rev 23135)
+++ tools/trunk/util.h	2006-06-15 14:34:46 UTC (rev 23136)
@@ -53,7 +53,9 @@
 typedef signed int int32;
 
 #if !defined(__cplusplus)
-typedef enum { false = 0, true = 1 } bool;
+typedef uint8 bool;
+#define false 0
+#define true 1
 
 /* If your C compiler doesn't support 'inline', please add a check for it. */
 #if defined(_MSC_VER)
@@ -67,6 +69,82 @@
  * Various utility macros
  */
 
+#if defined(_MSC_VER)
+
+	#define scumm_stricmp stricmp
+	#define scumm_strnicmp _strnicmp
+	#define snprintf _snprintf
+
+	#define SCUMM_LITTLE_ENDIAN
+
+	#define START_PACK_STRUCTS pack(push, 1)
+	#define END_PACK_STRUCTS   pack(pop)
+
+	
+#elif defined(__MINGW32__)
+
+	#define scumm_stricmp stricmp
+	#define scumm_strnicmp strnicmp
+
+	#define SCUMM_LITTLE_ENDIAN
+
+	#define START_PACK_STRUCTS pack(push, 1)
+	#define END_PACK_STRUCTS   pack(pop)
+
+
+	#ifndef _HEAPOK
+	#define _HEAPOK	(-2)
+	#endif
+
+#elif defined(UNIX)
+
+	#define scumm_stricmp strcasecmp
+	#define scumm_strnicmp strncasecmp
+
+	#if defined(__DECCXX) // Assume alpha architecture
+	#define INVERSE_MKID
+	#define SCUMM_NEED_ALIGNMENT
+	#endif
+
+	#if !defined(__GNUC__)
+	#define START_PACK_STRUCTS pack (1)
+	#define END_PACK_STRUCTS   pack ()
+	#endif
+
+#else
+
+	#error No system type defined
+
+#endif
+
+
+//
+// GCC specific stuff
+//
+#if defined(__GNUC__)
+        #define GCC_PACK __attribute__((packed))
+        #define NORETURN __attribute__((__noreturn__))
+        #define GCC_PRINTF(x,y) __attribute__((format(printf, x, y)))
+#else
+        #define GCC_PACK
+        #define GCC_PRINTF(x,y)
+#endif
+
+#define READ_UINT16(a) READ_LE_UINT16(a)
+#define READ_UINT32(a) READ_LE_UINT32(a)
+
+#define WRITE_UINT16(a, v) WRITE_LE_UINT16(a, v)
+#define WRITE_UINT32(a, v) WRITE_LE_UINT32(a, v)
+
+#define FROM_LE_32(a) ((uint32)(a))
+#define FROM_LE_16(a) ((uint16)(a))
+
+#define TO_LE_32(a) ((uint32)(a))
+#define TO_LE_16(a) ((uint16)(a))
+
+#define TO_BE_32(a) SWAP_BYTES_32(a)
+#define TO_BE_16(a) SWAP_BYTES_16(a)
+
 #define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(x[0])))
 
 static inline uint32 SWAP_32(uint32 a) {
@@ -154,6 +232,7 @@
 /* Misc stuff */
 void NORETURN_PRE error(const char *s, ...) NORETURN_POST;
 void warning(const char *s, ...);
+void debug(int level, const char *s, ...);
 
 #if defined(__cplusplus)
 }

Added: tools/trunk/utils/adpcm.cpp
===================================================================
--- tools/trunk/utils/adpcm.cpp	                        (rev 0)
+++ tools/trunk/utils/adpcm.cpp	2006-06-15 14:34:46 UTC (rev 23136)
@@ -0,0 +1,332 @@
+#include "adpcm.h"
+#include "util.h"
+
+namespace Audio {
+
+// TODO: Switch from a SeekableReadStream to a plain ReadStream. This requires
+// some internal refactoring but is definitely possible and will increase the
+// flexibility of this code.
+class ADPCMInputStream : public AudioStream {
+private:
+	Common::SeekableReadStream *_stream;
+	uint32 _endpos;
+	int _channels;
+	typesADPCM _type;
+	uint32 _blockAlign;
+	uint32 _blockPos;
+	int _blockLen;
+	int _rate;
+
+	struct ADPCMChannelStatus {
+		byte predictor;
+		int16 delta;
+		int16 coeff1;
+		int16 coeff2;
+		int16 sample1;
+		int16 sample2;
+	};
+
+	struct adpcmStatus {
+		// IMA
+		int32 last;
+		int32 stepIndex;
+
+		// MS ADPCM
+		ADPCMChannelStatus ch[2];
+	} _status;
+
+	int16 stepAdjust(byte);
+	int16 decodeOKI(byte);
+	int16 decodeMSIMA(byte);
+	int16 decodeMS(ADPCMChannelStatus *c, byte);
+
+public:
+	ADPCMInputStream(Common::SeekableReadStream *stream, uint32 size, typesADPCM type, int rate, int channels = 2, uint32 blockAlign = 0);
+	~ADPCMInputStream() {};
+
+	int readBuffer(int16 *buffer, const int numSamples);
+	int readBufferOKI(int16 *buffer, const int numSamples);
+	int readBufferMSIMA1(int16 *buffer, const int numSamples);
+	int readBufferMSIMA2(int16 *buffer, const int numSamples);
+	int readBufferMS(int channels, int16 *buffer, const int numSamples);
+
+	bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos); }
+	bool isStereo() const	{ return false; }
+	int getRate() const	{ return _rate; }
+};
+
+// Routines to convert 12 bit linear samples to the
+// Dialogic or Oki ADPCM coding format aka VOX.
+// See also <http://www.comptek.ru/telephony/tnotes/tt1-13.html>
+//
+// In addition, also MS IMA ADPCM is supported. See
+//   <http://wiki.multimedia.cx/index.php?title=Microsoft_IMA_ADPCM>.
+
+ADPCMInputStream::ADPCMInputStream(Common::SeekableReadStream *stream, uint32 size, typesADPCM type, int rate, int channels, uint32 blockAlign)
+	: _stream(stream), _channels(channels), _type(type), _blockAlign(blockAlign), _rate(rate) {
+
+	_status.last = 0;
+	_status.stepIndex = 0;
+	memset(_status.ch, 0, sizeof(_status.ch));
+	_endpos = stream->pos() + size;
+	_blockPos = _blockLen = 0;
+
+	if (type == kADPCMMSIma && blockAlign == 0)
+		error("ADPCMInputStream(): blockAlign isn't specifiled for MS IMA ADPCM");
+	if (type == kADPCMMS && blockAlign == 0)
+		error("ADPCMInputStream(): blockAlign isn't specifiled for MS ADPCM");
+}
+
+int ADPCMInputStream::readBuffer(int16 *buffer, const int numSamples) {
+	switch (_type) {
+	case kADPCMOki:
+		return readBufferOKI(buffer, numSamples);
+		break;
+	case kADPCMMSIma:
+		if (_channels == 1)
+			return readBufferMSIMA1(buffer, numSamples);
+		else
+			return readBufferMSIMA2(buffer, numSamples);
+		break;
+	case kADPCMMS:
+		return readBufferMS(_channels, buffer, numSamples);
+		break;
+	default:
+		error("Unsupported ADPCM encoding");
+		break;
+	}
+	return 0;
+}
+
+int ADPCMInputStream::readBufferOKI(int16 *buffer, const int numSamples) {
+	int samples;
+	byte data;
+
+	assert(numSamples % 2 == 0);
+
+	for (samples = 0; samples < numSamples && !_stream->eos() && _stream->pos() < _endpos; samples += 2) {
+		data = _stream->readByte();
+		buffer[samples] = TO_LE_16(decodeOKI((data >> 4) & 0x0f));
+		buffer[samples + 1] = TO_LE_16(decodeOKI(data & 0x0f));
+	}
+	return samples;
+}
+
+
+int ADPCMInputStream::readBufferMSIMA1(int16 *buffer, const int numSamples) {
+	int samples;
+	byte data;
+
+	assert(numSamples % 2 == 0);
+
+	samples = 0;
+
+	while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
+		if (_blockPos == _blockAlign) {
+			// read block header
+			_status.last = _stream->readSint16LE();
+			_status.stepIndex = _stream->readSint16LE();
+			_blockPos = 4;
+		}
+
+		for (; samples < numSamples && _blockPos < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2) {
+			data = _stream->readByte();
+			_blockPos++;
+			buffer[samples] = TO_LE_16(decodeMSIMA(data & 0x0f));
+			buffer[samples + 1] = TO_LE_16(decodeMSIMA((data >> 4) & 0x0f));
+		}
+	}
+	return samples;
+}
+
+
+// Microsoft as usual tries to implement it differently. This method
+// is used for stereo data.
+int ADPCMInputStream::readBufferMSIMA2(int16 *buffer, const int numSamples) {
+	int samples;
+	uint32 data;
+	int nibble;
+
+	for (samples = 0; samples < numSamples && !_stream->eos() && _stream->pos() < _endpos;) {
+		for (int channel = 0; channel < 2; channel++) {
+			data = _stream->readUint32LE();
+			
+			for (nibble = 0; nibble < 8; nibble++) {
+				byte k = ((data & 0xf0000000) >> 28);
+				buffer[samples + channel + nibble * 2] = TO_LE_16(decodeMSIMA(k));
+				data <<= 4;
+			}
+		}
+		samples += 16;
+	}
+	return samples;
+}
+
+static const int MSADPCMAdaptCoeff1[] = {
+	256, 512, 0, 192, 240, 460, 392
+};
+
+static const int MSADPCMAdaptCoeff2[] = {
+	0, -256, 0, 64, 0, -208, -232
+};
+
+int ADPCMInputStream::readBufferMS(int channels, int16 *buffer, const int numSamples) {
+	int samples;
+	byte data;
+	int stereo = channels - 1; // We use it in index
+
+	samples = 0;
+
+	while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
+		if (_blockPos == _blockAlign) {
+			// read block header
+			_status.ch[0].predictor = Common::CLIP(_stream->readByte(), (byte)0, (byte)6);
+			_status.ch[0].coeff1 = MSADPCMAdaptCoeff1[_status.ch[0].predictor];
+			_status.ch[0].coeff2 = MSADPCMAdaptCoeff2[_status.ch[0].predictor];
+			if (stereo) {
+				_status.ch[1].predictor = Common::CLIP(_stream->readByte(), (byte)0, (byte)6);
+				_status.ch[1].coeff1 = MSADPCMAdaptCoeff1[_status.ch[1].predictor];
+				_status.ch[1].coeff2 = MSADPCMAdaptCoeff2[_status.ch[1].predictor];
+			}
+
+			_status.ch[0].delta = _stream->readSint16LE();
+			if (stereo)
+				_status.ch[1].delta = _stream->readSint16LE();
+
+			buffer[samples++] = _status.ch[0].sample1 = _stream->readSint16LE();
+			if (stereo)
+				buffer[samples++] = _status.ch[1].sample1 = _stream->readSint16LE();
+
+			buffer[samples++] = _status.ch[0].sample2 = _stream->readSint16LE();
+			if (stereo)
+				buffer[samples++] = _status.ch[1].sample2 = _stream->readSint16LE();
+
+			_blockPos = channels * 7;
+		}
+
+
+		for (; samples < numSamples && _blockPos < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2) {
+			data = _stream->readByte();
+			_blockPos++;
+			buffer[samples] = TO_LE_16(decodeMS(&_status.ch[0], (data >> 4) & 0x0f));
+			buffer[samples + 1] = TO_LE_16(decodeMS(&_status.ch[stereo], data & 0x0f));
+		}
+	}
+
+	return samples;
+}
+
+
+// adjust the step for use on the next sample.
+int16 ADPCMInputStream::stepAdjust(byte code) {
+	static const int16 adjusts[] = {-1, -1, -1, -1, 2, 4, 6, 8};
+
+	return adjusts[code & 0x07];
+}
+
+static const int16 okiStepSize[49] = {
+	  16,   17,   19,   21,   23,   25,   28,   31,
+	  34,   37,   41,   45,   50,   55,   60,   66,
+	  73,   80,   88,   97,  107,  118,  130,  143,
+	 157,  173,  190,  209,  230,  253,  279,  307,
+	 337,  371,  408,  449,  494,  544,  598,  658,
+	 724,  796,  876,  963, 1060, 1166, 1282, 1411,
+	1552
+};
+
+// Decode Linear to ADPCM
+int16 ADPCMInputStream::decodeOKI(byte code) {
+	int16 diff, E, samp;
+
+	E = (2 * (code & 0x7) + 1) * okiStepSize[_status.stepIndex] / 8;
+	diff = (code & 0x08) ? -E : E;
+	samp = _status.last + diff;
+
+    // Clip the values to +/- 2^11 (supposed to be 12 bits)
+	if (samp > 2048)
+		samp = 2048;
+	if (samp < -2048)
+		samp = -2048;
+
+	_status.last = samp;
+	_status.stepIndex += stepAdjust(code);
+	if (_status.stepIndex < 0)
+		_status.stepIndex = 0;
+	if (_status.stepIndex > ARRAYSIZE(okiStepSize) - 1)
+		_status.stepIndex = ARRAYSIZE(okiStepSize) - 1;
+
+	// * 16 effectively converts 12-bit input to 16-bit output
+	return samp * 16;
+}
+
+
+static const uint16 imaStepTable[89] = {
+		7,	  8,	9,	 10,   11,	 12,   13,	 14,
+	   16,	 17,   19,	 21,   23,	 25,   28,	 31,
+	   34,	 37,   41,	 45,   50,	 55,   60,	 66,
+	   73,	 80,   88,	 97,  107,	118,  130,	143,
+	  157,	173,  190,	209,  230,	253,  279,	307,
+	  337,	371,  408,	449,  494,	544,  598,	658,
+	  724,	796,  876,	963, 1060, 1166, 1282, 1411,
+	 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
+	 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
+	 7132, 7845, 8630, 9493,10442,11487,12635,13899,
+	15289,16818,18500,20350,22385,24623,27086,29794,
+	32767
+};
+
+int16 ADPCMInputStream::decodeMSIMA(byte code) {
+	int32 diff, E, samp;
+
+	E = (2 * (code & 0x7) + 1) * imaStepTable[_status.stepIndex] / 8;
+	diff = (code & 0x08) ? -E : E;
+	samp = _status.last + diff;
+
+	if (samp < -0x8000)
+		samp = -0x8000;
+	else if (samp > 0x7fff)
+		samp = 0x7fff;
+
+	_status.last = samp;
+
+	_status.stepIndex += stepAdjust(code);
+	if (_status.stepIndex < 0)
+		_status.stepIndex = 0;
+	if (_status.stepIndex > ARRAYSIZE(imaStepTable) - 1)
+		_status.stepIndex = ARRAYSIZE(imaStepTable) - 1;
+
+	return samp;
+}
+
+static const int MSADPCMAdaptationTable[] = {
+	230, 230, 230, 230, 307, 409, 512, 614,
+	768, 614, 512, 409, 307, 230, 230, 230
+};
+
+
+int16 ADPCMInputStream::decodeMS(ADPCMChannelStatus *c, byte code) {
+	int32 predictor;
+
+	predictor = (((c->sample1) * (c->coeff1)) + ((c->sample2) * (c->coeff2))) / 256;
+	predictor += (signed)((code & 0x08) ? (code - 0x10) : (code)) * c->delta;
+
+	if (predictor < -0x8000)
+		predictor = -0x8000;
+	else if (predictor > 0x7fff)
+		predictor = 0x7fff;
+
+	c->sample2 = c->sample1;
+	c->sample1 = predictor;
+	c->delta = (MSADPCMAdaptationTable[(int)code] * c->delta) >> 8;
+
+	if (c->delta < 16)
+		c->delta = 16;
+
+	return (int16)predictor;
+}
+
+AudioStream *makeADPCMStream(Common::SeekableReadStream *stream, uint32 size, typesADPCM type, int rate, int channels, uint32 blockAlign) {
+	return new ADPCMInputStream(stream, size, type, rate, channels, blockAlign);
+}
+
+} // End of namespace Audio


Property changes on: tools/trunk/utils/adpcm.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: tools/trunk/utils/adpcm.h
===================================================================
--- tools/trunk/utils/adpcm.h	                        (rev 0)
+++ tools/trunk/utils/adpcm.h	2006-06-15 14:34:46 UTC (rev 23136)
@@ -0,0 +1,21 @@
+#ifndef SOUND_ADPCM_H
+#define SOUND_ADPCM_H
+
+#include "audiostream.h"
+#include "stream.h"
+
+namespace Audio {
+
+class AudioStream;
+
+enum typesADPCM {
+	kADPCMOki,
+	kADPCMMSIma,
+	kADPCMMS
+};
+
+AudioStream *makeADPCMStream(Common::SeekableReadStream *stream, uint32 size, typesADPCM type, int rate = 22050, int channels = 2, uint32 blockAlign = 0);
+
+} // End of namespace Audio
+
+#endif


Property changes on: tools/trunk/utils/adpcm.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: tools/trunk/utils/audiostream.cpp
===================================================================
--- tools/trunk/utils/audiostream.cpp	                        (rev 0)
+++ tools/trunk/utils/audiostream.cpp	2006-06-15 14:34:46 UTC (rev 23136)
@@ -0,0 +1,140 @@
+#include "audiostream.h"
+
+
+namespace Audio {
+
+struct StreamFileFormat {
+	/** Decodername */
+	const char* decoderName;
+	const char* fileExtension;
+	/**
+	 * Pointer to a function which tries to open a file of type StreamFormat.
+	 * Return NULL in case of an error (invalid/nonexisting file).
+	 */
+	AudioStream* (*openStreamFile)(FILE *file, uint32 size);
+};
+
+
+#pragma mark -
+#pragma mark --- LinearMemoryStream ---
+#pragma mark -
+
+
+/**
+ * A simple raw audio stream, purely memory based. It operates on a single
+ * block of data, which is passed to it upon creation.
+ * Optionally supports looping the sound.
+ *
+ * Design note: This code tries to be as optimized as possible (without
+ * resorting to assembly, that is). To this end, it is written as a template
+ * class. This way the compiler can actually create optimized code for each
+ * special code. This results in a total of 12 versions of the code being
+ * generated.
+ */
+template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
+class LinearMemoryStream : public AudioStream {
+protected:
+	const byte *_ptr;
+	const byte *_end;
+	const byte *_loopPtr;
+	const byte *_loopEnd;
+	const int _rate;
+	const byte *_origPtr;
+
+	inline bool eosIntern() const	{ return _ptr >= _end; };
+public:
+	LinearMemoryStream(int rate, const byte *ptr, uint32 len, uint32 loopOffset, uint32 loopLen, bool autoFreeMemory)
+		: _ptr(ptr), _end(ptr+len), _loopPtr(0), _loopEnd(0), _rate(rate) {
+
+		// Verify the buffer sizes are sane
+		if (is16Bit && stereo)
+			assert((len & 3) == 0 && (loopLen & 3) == 0);
+		else if (is16Bit || stereo)
+			assert((len & 1) == 0 && (loopLen & 1) == 0);
+
+		if (loopLen) {
+			_loopPtr = _ptr + loopOffset;
+			_loopEnd = _loopPtr + loopLen;
+		}
+		if (stereo)	// Stereo requires even sized data
+			assert(len % 2 == 0);
+
+		_origPtr = autoFreeMemory ? ptr : 0;
+	}
+	~LinearMemoryStream() {
+		free(const_cast<byte *>(_origPtr));
+	}
+	int readBuffer(int16 *buffer, const int numSamples);
+
+	bool isStereo() const		{ return stereo; }
+	bool endOfData() const		{ return eosIntern(); }
+
+	int getRate() const			{ return _rate; }
+};
+
+template<bool stereo, bool is16Bit, bool isUnsigned, bool isLE>
+int LinearMemoryStream<stereo, is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) {
+	int samples = 0;
+	while (samples < numSamples && !eosIntern()) {
+		const int len = Common::MIN(numSamples, samples + (int)(_end - _ptr) / (is16Bit ? 2 : 1));
+		while (samples < len) {
+			*buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, _ptr, isLE);
+			_ptr += (is16Bit ? 2 : 1);
+			samples++;
+		}
+		// Loop, if looping was specified
+		if (_loopPtr && eosIntern()) {
+			_ptr = _loopPtr;
+			_end = _loopEnd;
+		}
+	}
+	return samples;
+}
+
+
+#pragma mark -
+#pragma mark --- Input stream factory ---
+#pragma mark -
+
+/* In the following, we use preprocessor / macro tricks to simplify the code
+ * which instantiates the input streams. We used to use template functions for
+ * this, but MSVC6 / EVC 3-4 (used for WinCE builds) are extremely buggy when it
+ * comes to this feature of C++... so as a compromise we use macros to cut down
+ * on the (source) code duplication a bit.
+ * So while normally macro tricks are said to make maintenance harder, in this
+ * particular case it should actually help it :-)
+ */
+
+#define MAKE_LINEAR(STEREO, UNSIGNED) \
+		if (is16Bit) { \
+			if (isLE) \
+				return new LinearMemoryStream<STEREO, true, UNSIGNED, true>(rate, ptr, len, loopOffset, loopLen, autoFree); \
+			else  \
+				return new LinearMemoryStream<STEREO, true, UNSIGNED, false>(rate, ptr, len, loopOffset, loopLen, autoFree); \
+		} else \
+			return new LinearMemoryStream<STEREO, false, UNSIGNED, false>(rate, ptr, len, loopOffset, loopLen, autoFree)
+
+AudioStream *makeLinearInputStream(int rate, byte flags, const byte *ptr, uint32 len, uint32 loopOffset, uint32 loopLen) {
+	const bool isStereo   = (flags & Audio::Mixer::FLAG_STEREO) != 0;
+	const bool is16Bit    = (flags & Audio::Mixer::FLAG_16BITS) != 0;
+	const bool isUnsigned = (flags & Audio::Mixer::FLAG_UNSIGNED) != 0;
+	const bool isLE       = (flags & Audio::Mixer::FLAG_LITTLE_ENDIAN) != 0;
+	const bool autoFree   = (flags & Audio::Mixer::FLAG_AUTOFREE) != 0;
+
+	if (isStereo) {
+		if (isUnsigned) {
+			MAKE_LINEAR(true, true);
+		} else {
+			MAKE_LINEAR(true, false);
+		}
+	} else {
+		if (isUnsigned) {
+			MAKE_LINEAR(false, true);
+		} else {
+			MAKE_LINEAR(false, false);
+		}
+	}
+}
+
+
+} // End of namespace Audio


Property changes on: tools/trunk/utils/audiostream.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: tools/trunk/utils/audiostream.h
===================================================================
--- tools/trunk/utils/audiostream.h	                        (rev 0)
+++ tools/trunk/utils/audiostream.h	2006-06-15 14:34:46 UTC (rev 23136)
@@ -0,0 +1,131 @@
+#ifndef SOUND_AUDIOSTREAM_H
+#define SOUND_AUDIOSTREAM_H
+
+#include "../util.h"
+#include "util.h"
+
+namespace Audio {
+
+class Mixer {
+public:
+	enum {
+		/** unsigned samples (default: signed) */
+		FLAG_UNSIGNED = 1 << 0,
+
+		/** sound is 16 bits wide (default: 8bit) */
+		FLAG_16BITS = 1 << 1,
+
+		/** sample is little endian (default: big endian) */
+		FLAG_LITTLE_ENDIAN = 1 << 2,
+
+		/** sound is in stereo (default: mono) */
+		FLAG_STEREO = 1 << 3,
+
+		/** reverse the left and right stereo channel */
+		FLAG_REVERSE_STEREO = 1 << 4,
+
+		/** sound buffer is freed automagically at the end of playing */
+		FLAG_AUTOFREE = 1 << 5,
+
+		/** loop the audio */
+		FLAG_LOOP = 1 << 6
+	};
+};
+
+/**
+ * Generic input stream for the resampling code.
+ */
+class AudioStream {
+public:
+	virtual ~AudioStream() {}
+
+	/**
+	 * Fill the given buffer with up to numSamples samples.
+	 * Returns the actual number of samples read, or -1 if
+	 * a critical error occured (note: you *must* check if
+	 * this value is less than what you requested, this can
+	 * happen when the stream is fully used up).
+	 *
+	 * Data has to be in native endianess, 16 bit per sample, signed.
+	 * For stereo stream, buffer will be filled with interleaved
+	 * left and right channel samples, starting with a left sample.
+	 * Furthermore, the samples in the left and right are summed up.
+	 * So if you request 4 samples from a stereo stream, you will get
+	 * a total of two left channel and two right channel samples.
+	 */
+	virtual int readBuffer(int16 *buffer, const int numSamples) = 0;
+
+	/** Is this a stereo stream? */
+	virtual bool isStereo() const = 0;
+
+	/**
+	 * End of data reached? If this returns true, it means that at this
+	 * time there is no data available in the stream. However there may be
+	 * more data in the future.
+	 * This is used by e.g. a rate converter to decide whether to keep on
+	 * converting data or stop.
+	 */
+	virtual bool endOfData() const = 0;
+
+	/**
+	 * End of stream reached? If this returns true, it means that all data
+	 * in this stream is used up and no additional data will appear in it
+	 * in the future.
+	 * This is used by the mixer to decide whether a given stream shall be
+	 * removed from the list of active streams (and thus be destroyed).
+	 * By default this maps to endOfData()
+	 */
+	virtual bool endOfStream() const { return endOfData(); }
+
+	/** Sample rate of the stream. */
+	virtual int getRate() const = 0;
+};
+
+/**
+ * A simple AudioStream which represents a 'silent' stream,
+ * containing the specified number of zero samples.
+ */
+class ZeroInputStream : public AudioStream {
+private:
+	int _len;
+public:
+	ZeroInputStream(uint32 len) : _len(len) { }
+	int readBuffer(int16 *buffer, const int numSamples) {
+		int samples = Common::MIN(_len, numSamples);
+		memset(buffer, 0, samples * 2);
+		_len -= samples;
+		return samples;
+	}
+	bool isStereo() const { return false; }
+	bool eos() const { return _len <= 0; }
+
+	int getRate() const { return -1; }
+};
+
+AudioStream *makeLinearInputStream(int rate, byte flags, const byte *ptr, uint32 len, uint32 loopOffset, uint32 loopLen);
+
+/**
+ * An audio stream to which additional data can be appended on-the-fly.
+ * Used by SMUSH, iMuseDigital, and the Kyrandia 3 VQA player.
+ */
+class AppendableAudioStream : public Audio::AudioStream {
+public:
+	virtual void append(const byte *data, uint32 len) = 0;
+	virtual void finish() = 0;
+};
+
+AppendableAudioStream *makeAppendableAudioStream(int rate, byte _flags, uint32 len);
+
+
+// This used to be an inline template function, but
+// buggy template function handling in MSVC6 forced
+// us to go with the macro approach. So far this is
+// the only template function that MSVC6 seemed to
+// compile incorrectly. Knock on wood.
+#define READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, ptr, isLE) \
+	((is16Bit ? (isLE ? READ_LE_UINT16(ptr) : READ_BE_UINT16(ptr)) : (*ptr << 8)) ^ (isUnsigned ? 0x8000 : 0))
+
+
+} // End of namespace Audio
+
+#endif


Property changes on: tools/trunk/utils/audiostream.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: tools/trunk/utils/file.cpp
===================================================================
--- tools/trunk/utils/file.cpp	                        (rev 0)
+++ tools/trunk/utils/file.cpp	2006-06-15 14:34:46 UTC (rev 23136)
@@ -0,0 +1,94 @@
+#include "file.h"
+
+
+namespace Common {
+
+
+File::File(FILE*file)
+	: _handle(file), _ioFailed(false) {
+}
+
+
+File::~File() {
+	close();
+}
+
+void File::close() {
+	_handle = NULL;
+}
+
+bool File::isOpen() const {
+	return _handle != NULL;
+}
+
+bool File::ioFailed() const {
+	return _ioFailed != 0;
+}
+
+void File::clearIOFailed() {
+	_ioFailed = false;
+}
+
+bool File::eof() const {
+	if (_handle == NULL) {
+		error("File::eof: File is not open!");
+		return false;
+	}
+
+	return feof(_handle) != 0;
+}
+
+uint32 File::pos() const {
+	if (_handle == NULL) {
+		error("File::pos: File is not open!");
+		return 0;
+	}
+
+	return ftell(_handle);
+}
+
+uint32 File::size() const {
+	if (_handle == NULL) {
+		error("File::size: File is not open!");
+		return 0;
+	}
+
+	uint32 oldPos = ftell(_handle);
+	fseek(_handle, 0, SEEK_END);
+	uint32 length = ftell(_handle);
+	fseek(_handle, oldPos, SEEK_SET);
+
+	return length;
+}
+
+void File::seek(int32 offs, int whence) {
+	if (_handle == NULL) {
+		error("File::seek: File is not open!");
+		return;
+	}
+
+	if (fseek(_handle, offs, whence) != 0)
+		clearerr(_handle);
+}
+
+uint32 File::read(void *ptr, uint32 len) {
+	byte *ptr2 = (byte *)ptr;
+	size_t real_len;
+
+	if (_handle == NULL) {
+		error("File::read: File is not open!");
+		return 0;
+	}
+
+	if (len == 0)
+		return 0;
+
+	real_len = fread(ptr2, 1, len, _handle);
+	if (real_len < len) {
+		_ioFailed = true;
+	}
+
+	return (uint32)real_len;
+}
+
+}	// End of namespace Common


Property changes on: tools/trunk/utils/file.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: tools/trunk/utils/file.h
===================================================================
--- tools/trunk/utils/file.h	                        (rev 0)
+++ tools/trunk/utils/file.h	2006-06-15 14:34:46 UTC (rev 23136)
@@ -0,0 +1,43 @@
+#ifndef COMMON_FILE_H
+#define COMMON_FILE_H
+
+#include "stream.h"
+
+namespace Common {
+
+class File : public SeekableReadStream {
+protected:
+	/** POSIX file handle to the actual file; 0 if no file is open. */
+	FILE *_handle;
+
+	/** Status flag which tells about recent I/O failures. */
+	bool _ioFailed;
+
+private:
+	// Disallow copying File objects. There is not strict reason for this,
+	// except that so far we never had real need for such a feature, and
+	// code that accidentally copied File objects tended to break in strange
+	// ways.
+	File(const File &f);
+	File &operator  =(const File &f);
+
+public:
+
+	File(FILE*file);
+	virtual ~File();
+
+	virtual void close();
+	bool isOpen() const;
+	bool ioFailed() const;
+	void clearIOFailed();
+	bool eos() const { return eof(); }
+	bool eof() const;
+	uint32 pos() const;
+	uint32 size() const;
+	void seek(int32 offs, int whence = SEEK_SET);
+	uint32 read(void *dataPtr, uint32 dataSize);
+};
+
+} // End of namespace Common
+
+#endif


Property changes on: tools/trunk/utils/file.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: tools/trunk/utils/md5.cpp
===================================================================
--- tools/trunk/utils/md5.cpp	                        (rev 0)
+++ tools/trunk/utils/md5.cpp	2006-06-15 14:34:46 UTC (rev 23136)
@@ -0,0 +1,243 @@
+#include "md5.h"
+
+namespace Common {
+
+#define GET_UINT32(n, b, i)	(n) = READ_LE_UINT32(b + i)
+#define PUT_UINT32(n, b, i)	WRITE_LE_UINT32(b + i, n)
+
+void md5_starts(md5_context *ctx) {
+	ctx->total[0] = 0;
+	ctx->total[1] = 0;
+
+	ctx->state[0] = 0x67452301;
+	ctx->state[1] = 0xEFCDAB89;
+	ctx->state[2] = 0x98BADCFE;
+	ctx->state[3] = 0x10325476;
+}
+
+static void md5_process(md5_context *ctx, const uint8 data[64]) {
+	uint32 X[16], A, B, C, D;
+
+	GET_UINT32(X[0],  data,  0);
+	GET_UINT32(X[1],  data,  4);
+	GET_UINT32(X[2],  data,  8);
+	GET_UINT32(X[3],  data, 12);
+	GET_UINT32(X[4],  data, 16);
+	GET_UINT32(X[5],  data, 20);
+	GET_UINT32(X[6],  data, 24);
+	GET_UINT32(X[7],  data, 28);
+	GET_UINT32(X[8],  data, 32);
+	GET_UINT32(X[9],  data, 36);
+	GET_UINT32(X[10], data, 40);
+	GET_UINT32(X[11], data, 44);
+	GET_UINT32(X[12], data, 48);
+	GET_UINT32(X[13], data, 52);
+	GET_UINT32(X[14], data, 56);
+	GET_UINT32(X[15], data, 60);
+
+#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define P(a, b, c, d, k, s, t)                    \
+{                                                 \
+	a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
+}
+
+	A = ctx->state[0];
+	B = ctx->state[1];
+	C = ctx->state[2];
+	D = ctx->state[3];
+
+#define F(x, y, z) (z ^ (x & (y ^ z)))
+
+	P(A, B, C, D,  0,  7, 0xD76AA478);
+	P(D, A, B, C,  1, 12, 0xE8C7B756);
+	P(C, D, A, B,  2, 17, 0x242070DB);
+	P(B, C, D, A,  3, 22, 0xC1BDCEEE);
+	P(A, B, C, D,  4,  7, 0xF57C0FAF);
+	P(D, A, B, C,  5, 12, 0x4787C62A);
+	P(C, D, A, B,  6, 17, 0xA8304613);
+	P(B, C, D, A,  7, 22, 0xFD469501);
+	P(A, B, C, D,  8,  7, 0x698098D8);
+	P(D, A, B, C,  9, 12, 0x8B44F7AF);
+	P(C, D, A, B, 10, 17, 0xFFFF5BB1);
+	P(B, C, D, A, 11, 22, 0x895CD7BE);
+	P(A, B, C, D, 12,  7, 0x6B901122);
+	P(D, A, B, C, 13, 12, 0xFD987193);
+	P(C, D, A, B, 14, 17, 0xA679438E);
+	P(B, C, D, A, 15, 22, 0x49B40821);
+
+#undef F
+
+#define F(x, y, z) (y ^ (z & (x ^ y)))
+
+	P(A, B, C, D,  1,  5, 0xF61E2562);
+	P(D, A, B, C,  6,  9, 0xC040B340);
+	P(C, D, A, B, 11, 14, 0x265E5A51);
+	P(B, C, D, A,  0, 20, 0xE9B6C7AA);
+	P(A, B, C, D,  5,  5, 0xD62F105D);
+	P(D, A, B, C, 10,  9, 0x02441453);
+	P(C, D, A, B, 15, 14, 0xD8A1E681);
+	P(B, C, D, A,  4, 20, 0xE7D3FBC8);
+	P(A, B, C, D,  9,  5, 0x21E1CDE6);
+	P(D, A, B, C, 14,  9, 0xC33707D6);
+	P(C, D, A, B,  3, 14, 0xF4D50D87);
+	P(B, C, D, A,  8, 20, 0x455A14ED);
+	P(A, B, C, D, 13,  5, 0xA9E3E905);
+	P(D, A, B, C,  2,  9, 0xFCEFA3F8);
+	P(C, D, A, B,  7, 14, 0x676F02D9);
+	P(B, C, D, A, 12, 20, 0x8D2A4C8A);
+
+#undef F
+
+#define F(x, y, z) (x ^ y ^ z)
+
+	P(A, B, C, D,  5,  4, 0xFFFA3942);
+	P(D, A, B, C,  8, 11, 0x8771F681);
+	P(C, D, A, B, 11, 16, 0x6D9D6122);
+	P(B, C, D, A, 14, 23, 0xFDE5380C);
+	P(A, B, C, D,  1,  4, 0xA4BEEA44);
+	P(D, A, B, C,  4, 11, 0x4BDECFA9);
+	P(C, D, A, B,  7, 16, 0xF6BB4B60);
+	P(B, C, D, A, 10, 23, 0xBEBFBC70);
+	P(A, B, C, D, 13,  4, 0x289B7EC6);
+	P(D, A, B, C,  0, 11, 0xEAA127FA);
+	P(C, D, A, B,  3, 16, 0xD4EF3085);
+	P(B, C, D, A,  6, 23, 0x04881D05);
+	P(A, B, C, D,  9,  4, 0xD9D4D039);
+	P(D, A, B, C, 12, 11, 0xE6DB99E5);
+	P(C, D, A, B, 15, 16, 0x1FA27CF8);
+	P(B, C, D, A,  2, 23, 0xC4AC5665);
+
+#undef F
+
+#define F(x, y, z) (y ^ (x | ~z))
+
+	P(A, B, C, D,  0,  6, 0xF4292244);
+	P(D, A, B, C,  7, 10, 0x432AFF97);
+	P(C, D, A, B, 14, 15, 0xAB9423A7);
+	P(B, C, D, A,  5, 21, 0xFC93A039);
+	P(A, B, C, D, 12,  6, 0x655B59C3);
+	P(D, A, B, C,  3, 10, 0x8F0CCC92);
+	P(C, D, A, B, 10, 15, 0xFFEFF47D);
+	P(B, C, D, A,  1, 21, 0x85845DD1);
+	P(A, B, C, D,  8,  6, 0x6FA87E4F);
+	P(D, A, B, C, 15, 10, 0xFE2CE6E0);
+	P(C, D, A, B,  6, 15, 0xA3014314);
+	P(B, C, D, A, 13, 21, 0x4E0811A1);
+	P(A, B, C, D,  4,  6, 0xF7537E82);
+	P(D, A, B, C, 11, 10, 0xBD3AF235);
+	P(C, D, A, B,  2, 15, 0x2AD7D2BB);
+	P(B, C, D, A,  9, 21, 0xEB86D391);
+
+#undef F
+
+	ctx->state[0] += A;
+	ctx->state[1] += B;
+	ctx->state[2] += C;
+	ctx->state[3] += D;
+}
+
+void md5_update(md5_context *ctx, const uint8 *input, uint32 length) {
+	uint32 left, fill;
+
+	if (!length)
+		return;
+
+	left = ctx->total[0] & 0x3F;
+	fill = 64 - left;
+
+	ctx->total[0] += length;
+	ctx->total[0] &= 0xFFFFFFFF;
+
+	if (ctx->total[0] < length)
+		ctx->total[1]++;
+
+	if (left && length >= fill) {
+		memcpy((void *)(ctx->buffer + left), (const void *)input, fill);
+		md5_process(ctx, ctx->buffer);
+		length -= fill;
+		input  += fill;
+		left = 0;
+	}
+
+	while (length >= 64) {
+		md5_process(ctx, input);
+		length -= 64;
+		input  += 64;
+	}
+
+	if (length) {
+		memcpy((void *)(ctx->buffer + left), (const void *)input, length);
+	}
+}
+
+static const uint8 md5_padding[64] = {
+	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+void md5_finish(md5_context *ctx, uint8 digest[16]) {
+	uint32 last, padn;
+	uint32 high, low;
+	uint8 msglen[8];
+
+	high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
+	low  = (ctx->total[0] <<  3);
+
+	PUT_UINT32(low,  msglen, 0);
+	PUT_UINT32(high, msglen, 4);
+
+	last = ctx->total[0] & 0x3F;
+	padn = (last < 56) ? (56 - last) : (120 - last);
+
+	md5_update(ctx, md5_padding, padn);
+	md5_update(ctx, msglen, 8);
+
+	PUT_UINT32(ctx->state[0], digest,  0);
+	PUT_UINT32(ctx->state[1], digest,  4);
+	PUT_UINT32(ctx->state[2], digest,  8);
+	PUT_UINT32(ctx->state[3], digest, 12);
+}
+
+bool md5_file(const char *name, uint8 digest[16], uint32 length) {
+	FILE *f;
+
+	f = fopen(name, "rb");
+	if (f == NULL) {
+		printf("md5_file couldn't open '%s'", name);
+		return false;
+	}
+
+	md5_context ctx;
+	uint32 i;
+	unsigned char buf[1000];
+	bool restricted = (length != 0);
+	int readlen;
+
+	if (!restricted || sizeof(buf) <= length)
+		readlen = sizeof(buf);
+	else
+		readlen = length;
+
+	md5_starts(&ctx);
+
+	
+	while ((i = (uint32)fread(buf, 1, readlen, f)) > 0) {
+		md5_update(&ctx, buf, i);
+
+		length -= i;
+		if (restricted && length == 0)
+			break;
+
+		if (restricted && sizeof(buf) > length)
+			readlen = length;
+	}
+
+	md5_finish(&ctx, digest);
+	fclose(f);
+	return true;
+}
+
+}


Property changes on: tools/trunk/utils/md5.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: tools/trunk/utils/md5.h
===================================================================
--- tools/trunk/utils/md5.h	                        (rev 0)
+++ tools/trunk/utils/md5.h	2006-06-15 14:34:46 UTC (rev 23136)
@@ -0,0 +1,22 @@
+#ifndef COMMON_MD5_H
+#define COMMON_MD5_H
+
+#include "../util.h"
+
+namespace Common {
+
+typedef struct {
+	uint32 total[2];
+	uint32 state[4];
+	uint8 buffer[64];
+} md5_context;
+
+void md5_starts(md5_context *ctx);
+void md5_update(md5_context *ctx, const uint8 *input, uint32 length);
+void md5_finish(md5_context *ctx, uint8 digest[16]);
+
+bool md5_file(const char *name, uint8 digest[16], uint32 length = 0);
+
+} // End of namespace Common
+
+#endif


Property changes on: tools/trunk/utils/md5.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: tools/trunk/utils/stream.h
===================================================================
--- tools/trunk/utils/stream.h	                        (rev 0)
+++ tools/trunk/utils/stream.h	2006-06-15 14:34:46 UTC (rev 23136)
@@ -0,0 +1,130 @@
+#ifndef COMMON_STREAM_H
+#define COMMON_STREAM_H
+
+#include "../util.h"
+
+namespace Common {
+
+/**
+ * Virtual base class for both ReadStream and WriteStream.
+ */
+class Stream {
+public:
+	virtual ~Stream() {}
+
+	/**
+	 * Returns true if any I/O failure occured.
+	 * This flag is never cleared automatically. In order to clear it,
+	 * client code has to call clearIOFailed() explicitly.
+	 *
+	 * @todo Instead of returning a plain bool, maybe we should define
+	 *       a list of error codes which can be returned here.
+	 */
+	virtual bool ioFailed() const { return false; }
+
+	/**
+	 * Reset the I/O error status.
+	 */
+	virtual void clearIOFailed() {}
+};
+
+
+/**
+ * Generic interface for a readable data stream.
+ */
+class ReadStream : virtual public Stream {
+public:
+	/**
+	 * Returns true if the end of the stream has been reached.
+	 */
+	virtual bool eos() const = 0;
+
+	/**
+	 * Read data from the stream. Subclasses must implement this
+	 * method; all other read methods are implemented using it.
+	 *
+	 * @param dataPtr	pointer to a buffer into which the data is read
+	 * @param dataSize	number of bytes to be read
+	 * @return the number of bytes which were actually read.
+	 */
+	virtual uint32 read(void *dataPtr, uint32 dataSize) = 0;
+
+
+	// The remaining methods all have default implementations; subclasses
+	// need not (and should not) overload them.
+
+	byte readByte() {
+		byte b = 0;
+		read(&b, 1);
+		return b;
+	}
+
+	int8 readSByte() {
+		int8 b = 0;
+		read(&b, 1);
+		return b;
+	}
+
+	uint16 readUint16LE() {
+		uint16 a = readByte();
+		uint16 b = readByte();
+		return a | (b << 8);
+	}
+
+	uint32 readUint32LE() {
+		uint32 a = readUint16LE();
+		uint32 b = readUint16LE();
+		return (b << 16) | a;
+	}
+
+	uint16 readUint16BE() {
+		uint16 b = readByte();
+		uint16 a = readByte();
+		return a | (b << 8);
+	}
+
+	uint32 readUint32BE() {
+		uint32 b = readUint16BE();
+		uint32 a = readUint16BE();
+		return (b << 16) | a;
+	}
+
+	int16 readSint16LE() {
+		return (int16)readUint16LE();
+	}
+
+	int32 readSint32LE() {
+		return (int32)readUint32LE();
+	}
+
+	int16 readSint16BE() {
+		return (int16)readUint16BE();
+	}
+
+	int32 readSint32BE() {
+		return (int32)readUint32BE();
+	}
+};
+
+
+/**
+ * Interface for a seekable & readable data stream.
+ *
+ * @todo We really need better error handling here!
+ *       Like seek should somehow indicate whether it failed.
+ */
+class SeekableReadStream : public ReadStream {
+public:
+
+	virtual uint32 pos() const = 0;
+	virtual uint32 size() const = 0;
+
+	virtual void seek(int32 offset, int whence = SEEK_SET) = 0;
+	
+	void skip(uint32 offset) { seek(offset, SEEK_CUR); }
+};
+
+
+}	// End of namespace Common
+
+#endif


Property changes on: tools/trunk/utils/stream.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: tools/trunk/utils/util.h
===================================================================
--- tools/trunk/utils/util.h	                        (rev 0)
+++ tools/trunk/utils/util.h	2006-06-15 14:34:46 UTC (rev 23136)
@@ -0,0 +1,73 @@
+#ifndef COMMON_UTIL_H
+#define COMMON_UTIL_H
+
+namespace Common {
+
+
+#ifdef MIN
+#undef MIN
+#endif
+
+#ifdef MAX
+#undef MAX
+#endif
+
+template<typename T> inline T ABS (T x)			{ return (x>=0) ? x : -x; }
+template<typename T> inline T MIN (T a, T b)	{ return (a<b) ? a : b; }
+template<typename T> inline T MAX (T a, T b)	{ return (a>b) ? a : b; }
+template<typename T> inline T CLIP (T v, T amin, T amax) 
+		{ if (v < amin) return amin; else if (v > amax) return amax; else return v; }
+
+/**
+ * List of game language.
+ */
+enum Language {
+	EN_ANY,     // Generic English (when only one game version exist)
+	EN_USA,
+	EN_GRB,
+
+	DE_DEU,
+	FR_FRA,
+	IT_ITA,
+	PT_BRA,
+	ES_ESP,
+	JA_JPN,
+	ZH_TWN,
+	KO_KOR,
+	SE_SWE,
+	HB_ISR,
+	RU_RUS,
+	CZ_CZE,
+	NL_NLD,
+	NB_NOR,
+	PL_POL,
+
+	UNK_LANG = -1	// Use default language (i.e. none specified)
+};
+
+/**
+ * List of game platforms. Specifying a platform for a target can be used to
+ * give the game engines a hint for which platform the game data file are.
+ * This may be optional or required, depending on the game engine and the
+ * game in question.
+ */
+enum Platform {
+	kPlatformPC,
+	kPlatformAmiga,
+	kPlatformAtariST,
+	kPlatformMacintosh,
+	kPlatformFMTowns,
+	kPlatformWindows,
+	kPlatformNES,
+	kPlatformC64,
+	kPlatformLinux,
+	kPlatformAcorn,
+	kPlatformSegaCD,
+	kPlatform3DO,
+//	kPlatformPCEngine,
+
+	kPlatformUnknown = -1
+};
+}
+
+#endif


Property changes on: tools/trunk/utils/util.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: tools/trunk/utils/voc.cpp
===================================================================
--- tools/trunk/utils/voc.cpp	                        (rev 0)
+++ tools/trunk/utils/voc.cpp	2006-06-15 14:34:46 UTC (rev 23136)
@@ -0,0 +1,118 @@
+#include "voc.h"
+#include "stream.h"
+#include "audiostream.h"
+
+
+namespace Audio {
+
+int getSampleRateFromVOCRate(int vocSR) {
+	if (vocSR == 0xa5 || vocSR == 0xa6) {
+		return 11025;
+	} else if (vocSR == 0xd2 || vocSR == 0xd3) {
+		return 22050;
+	} else {
+		int sr = 1000000L / (256L - vocSR);
+		// inexact sampling rates occur e.g. in the kitchen in Monkey Island,
+		// very easy to reach right from the start of the game.
+		//warning("inexact sample rate used: %i (0x%x)", sr, vocSR);
+		return sr;
+	}
+}
+
+byte *loadVOCFromStream(Common::ReadStream &stream, int &size, int &rate, int &loops, int &begin_loop, int &end_loop) {
+	VocFileHeader fileHeader;
+
+	if (stream.read(&fileHeader, 8) != 8)
+		goto invalid;
+
+	if (!memcmp(&fileHeader, "VTLK", 4)) {
+		if (stream.read(&fileHeader, sizeof(VocFileHeader)) != sizeof(VocFileHeader))
+			goto invalid;
+	} else if (!memcmp(&fileHeader, "Creative", 8)) {
+		if (stream.read(((byte *)&fileHeader) + 8, sizeof(VocFileHeader) - 8) != sizeof(VocFileHeader) - 8)
+			goto invalid;
+	} else {
+	invalid:;
+		warning("loadVOCFromStream: Invalid header");
+		return NULL;
+	}
+
+	if (memcmp(fileHeader.desc, "Creative Voice File", 19) != 0)
+		error("loadVOCFromStream: Invalid header");
+	if (fileHeader.desc[19] != 0x1A)
+		debug(3, "loadVOCFromStream: Partially invalid header");
+
+	int32 offset = FROM_LE_16(fileHeader.datablock_offset);
+	int16 version = FROM_LE_16(fileHeader.version);
+	int16 code = FROM_LE_16(fileHeader.id);
+	assert(offset == sizeof(VocFileHeader));
+	// 0x100 is an invalid VOC version used by German version of DOTT (Disk) and
+	// French version of Simon the Sorcerer 2 (CD)
+	assert(version == 0x010A || version == 0x0114 || version == 0x0100);
+	assert(code == ~version + 0x1234);
+
+	int len;
+	byte *ret_sound = 0;
+	size = 0;
+	begin_loop = 0;
+	end_loop = 0;
+
+	while ((code = stream.readByte())) {
+		len = stream.readByte();
+		len |= stream.readByte() << 8;
+		len |= stream.readByte() << 16;
+
+		switch(code) {
+		case 1: {
+			int time_constant = stream.readByte();
+			int packing = stream.readByte();
+			len -= 2;
+			rate = getSampleRateFromVOCRate(time_constant);
+			debug(9, "VOC Data Block: %d, %d, %d", rate, packing, len);
+			if (packing == 0) {
+				if (size) {
+					ret_sound = (byte *)realloc(ret_sound, size + len);
+				} else {
+					ret_sound = (byte *)malloc(len);
+				}
+				stream.read(ret_sound + size, len);
+				size += len;
+				begin_loop = size;
+				end_loop = size;
+			} else {
+				warning("VOC file packing %d unsupported", packing);
+			}
+			} break;
+		case 6:	// begin of loop
+			assert(len == 2);
+			loops = stream.readUint16LE();
+			break;
+		case 7:	// end of loop
+			assert(len == 0);
+			break;
+		default:
+			warning("Invalid code in VOC file : %d", code);
+			return ret_sound;
+		}
+	}
+	debug(4, "VOC Data Size : %d", size);
+	return ret_sound;
+}
+
+byte *loadVOCFromStream(Common::ReadStream &stream, int &size, int &rate) {
+	int loops, begin_loop, end_loop;
+	return loadVOCFromStream(stream, size, rate, loops, begin_loop, end_loop);
+}
+
+AudioStream *makeVOCStream(Common::ReadStream &stream) {
+	int size, rate;
+	byte *data = loadVOCFromStream(stream, size, rate);
+
+	if (!data)
+		return 0;
+
+	return makeLinearInputStream(rate, Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_UNSIGNED, data, size, 0, 0);
+}
+
+
+} // End of namespace Audio


Property changes on: tools/trunk/utils/voc.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: tools/trunk/utils/voc.h
===================================================================
--- tools/trunk/utils/voc.h	                        (rev 0)
+++ tools/trunk/utils/voc.h	2006-06-15 14:34:46 UTC (rev 23136)
@@ -0,0 +1,66 @@
+#ifndef SOUND_VOC_H
+#define SOUND_VOC_H
+
+#include "../util.h"
+
+namespace Common { class ReadStream; }
+
+namespace Audio {
+
+class AudioStream;
+
+
+#if !defined(__GNUC__)
+#pragma START_PACK_STRUCTS
+#endif
+
+struct VocFileHeader {
+	uint8 desc[20];
+	uint16 datablock_offset;
+	uint16 version;
+	uint16 id;
+} GCC_PACK;
+
+struct VocBlockHeader {
+	uint8 blocktype;
+	uint8 size[3];
+	uint8 sr;
+	uint8 pack;
+} GCC_PACK;
+
+#if !defined(__GNUC__)
+#pragma END_PACK_STRUCTS
+#endif
+
+/**
+ * Take a sample rate parameter as it occurs in a VOC sound header, and
+ * return the corresponding sample frequency.
+ *
+ * This method has special cases for the standard rates of 11025 and 22050 kHz,
+ * which due to limitations of the format, cannot be encoded exactly in a VOC
+ * file. As a consequence, many game files have sound data sampled with those
+ * rates, but the VOC marks them incorrectly as 11111 or 22222 kHz. This code
+ * works around that and "unrounds" the sampling rates.
+ */
+extern int getSampleRateFromVOCRate(int vocSR);
+
+/**
+ * Try to load a VOC from the given seekable stream. Returns a pointer to memory
+ * containing the PCM sample data (allocated with malloc). It is the callers
+ * responsibility to dellocate that data again later on! Currently this
+ * function only supports uncompressed raw PCM data.
+ */
+extern byte *loadVOCFromStream(Common::ReadStream &stream, int &size, int &rate);
+
+/**
+ * Try to load a VOC from the given seekable stream and create an AudioStream
+ * from that data. Currently this function only supports uncompressed raw PCM
+ * data. Looping is not supported.
+ *
+ * This function uses loadVOCFromStream() internally.
+ */
+AudioStream *makeVOCStream(Common::ReadStream &stream);
+
+} // End of namespace Audio
+
+#endif


Property changes on: tools/trunk/utils/voc.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: tools/trunk/utils/wave.cpp
===================================================================
--- tools/trunk/utils/wave.cpp	                        (rev 0)
+++ tools/trunk/utils/wave.cpp	2006-06-15 14:34:46 UTC (rev 23136)
@@ -0,0 +1,160 @@
+#include "stream.h"
+#include "AudioStream.h"
+#include "adpcm.h"
+
+namespace Audio {
+
+bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags, uint16 *wavType, int *blockAlign_) {
+	const uint32 initialPos = stream.pos();
+	byte buf[4+1];
+
+	buf[4] = 0;
+
+	stream.read(buf, 4);
+	if (memcmp(buf, "RIFF", 4) != 0) {
+		warning("getWavInfo: No 'RIFF' header");
+		return false;
+	}
+
+	uint32 wavLength = stream.readUint32LE();
+
+	stream.read(buf, 4);
+	if (memcmp(buf, "WAVE", 4) != 0) {
+		warning("getWavInfo: No 'WAVE' header");
+		return false;
+	}
+
+	stream.read(buf, 4);
+	if (memcmp(buf, "fmt ", 4) != 0) {
+		warning("getWavInfo: No 'fmt' header");
+		return false;
+	}
+
+	uint32 fmtLength = stream.readUint32LE();
+	if (fmtLength < 16) {
+		// A valid fmt chunk always contains at least 16 bytes
+		warning("getWavInfo: 'fmt' header is too short");
+		return false;
+	}
+
+	// Next comes the "type" field of the fmt header. Some typical
+	// values for it:
+	// 1  -> uncompressed PCM
+	// 17 -> IMA ADPCM compressed WAVE
+	// See <http://www.saettler.com/RIFFNEW/RIFFNEW.htm> for a more complete
+	// list of common WAVE compression formats...
+	uint16 type = stream.readUint16LE();	// == 1 for PCM data
+	uint16 numChannels = stream.readUint16LE();	// 1 for mono, 2 for stereo
+	uint32 samplesPerSec = stream.readUint32LE();	// in Hz
+	uint32 avgBytesPerSec = stream.readUint32LE();	// == SampleRate * NumChannels * BitsPerSample/8
+
+	uint16 blockAlign = stream.readUint16LE();	// == NumChannels * BitsPerSample/8
+	uint16 bitsPerSample = stream.readUint16LE();	// 8, 16 ...
+	// 8 bit data is unsigned, 16 bit data signed
+
+
+	if (wavType != 0)
+		*wavType = type;
+
+	if (blockAlign_ != 0)
+		*blockAlign_ = blockAlign;
+#if 0
+	printf("WAVE information:\n");
+	printf("  total size: %d\n", wavLength);
+	printf("  fmt size: %d\n", fmtLength);
+	printf("  type: %d\n", type);
+	printf("  numChannels: %d\n", numChannels);
+	printf("  samplesPerSec: %d\n", samplesPerSec);
+	printf("  avgBytesPerSec: %d\n", avgBytesPerSec);
+	printf("  blockAlign: %d\n", blockAlign);
+	printf("  bitsPerSample: %d\n", bitsPerSample);
+#endif
+
+	if (type != 1 && type != 2 && type != 17) {
+		warning("getWavInfo: only PCM, MS ADPCM or IMA ADPCM data is supported (type %d)", type);
+		return false;
+	}
+
+	if (blockAlign != numChannels * bitsPerSample / 8 && type != 2) {
+		debug(0, "getWavInfo: blockAlign is invalid");
+	}
+
+	if (avgBytesPerSec != samplesPerSec * blockAlign && type != 2) {
+		debug(0, "getWavInfo: avgBytesPerSec is invalid");
+	}
+
+	// Prepare the return values.
+	rate = samplesPerSec;
+
+	flags = 0;
+	if (bitsPerSample == 8)		// 8 bit data is unsigned
+		flags |= Audio::Mixer::FLAG_UNSIGNED;
+	else if (bitsPerSample == 16)	// 16 bit data is signed little endian
+		flags |= (Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN);
+	else if (bitsPerSample == 4 && type == 17)	// MS IMA ADPCM compressed. We decompress it
+		flags |= (Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN);
+	else if (bitsPerSample == 4 && type == 2)	// MS ADPCM compressed. We decompress it
+		flags |= (Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN);
+	else {
+		warning("getWavInfo: unsupported bitsPerSample %d", bitsPerSample);
+		return false;
+	}
+
+	if (numChannels == 2)
+		flags |= Audio::Mixer::FLAG_STEREO;
+	else if (numChannels != 1) {
+		warning("getWavInfo: unsupported number of channels %d", numChannels);
+		return false;
+	}
+
+	// It's almost certainly a WAV file, but we still need to find its
+	// 'data' chunk.
+
+	// Skip over the rest of the fmt chunk.
+	int offset = fmtLength - 16;
+
+	do {
+		stream.seek(offset, SEEK_CUR);
+		if (stream.pos() >= initialPos + wavLength + 8) {
+			warning("getWavInfo: Can't find 'data' chunk");
+			return false;
+		}
+		stream.read(buf, 4);
+		offset = stream.readUint32LE();
+
+#if 0
+		printf("  found a '%s' tag of size %d\n", buf, offset);
+#endif
+	} while (memcmp(buf, "data", 4) != 0);
+
+	// Stream now points at 'offset' bytes of sample data...
+	size = offset;
+
+	return true;
+}
+
+AudioStream *makeWAVStream(Common::SeekableReadStream &stream) {
+	int size, rate;
+	byte flags;
+	uint16 type;
+	int blockAlign;
+
+	if (!loadWAVFromStream(stream, size, rate, flags, &type, &blockAlign))
+		return 0;
+
+	if (type == 17) // MS IMA ADPCM
+		return makeADPCMStream(&stream, size, kADPCMMSIma, rate, (flags & Audio::Mixer::FLAG_STEREO) ? 2 : 1);
+	if (type == 2) // MS ADPCM
+		return makeADPCMStream(&stream, size, kADPCMMS, rate, (flags & Audio::Mixer::FLAG_STEREO) ? 2 : 1, blockAlign);
+
+	byte *data = (byte *)malloc(size);
+	assert(data);
+	stream.read(data, size);
+
+	// Since we allocated our own buffer for the data, we must set the autofree flag.
+	flags |= Audio::Mixer::FLAG_AUTOFREE;
+
+	return makeLinearInputStream(rate, flags, data, size, 0, 0);
+}
+
+} // End of namespace Audio


Property changes on: tools/trunk/utils/wave.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: tools/trunk/utils/wave.h
===================================================================
--- tools/trunk/utils/wave.h	                        (rev 0)
+++ tools/trunk/utils/wave.h	2006-06-15 14:34:46 UTC (rev 23136)
@@ -0,0 +1,31 @@
+#ifndef SOUND_WAVE_H
+#define SOUND_WAVE_H
+
+
+namespace Common { class SeekableReadStream; }
+
+namespace Audio {
+
+class AudioStream;
+
+/**
+ * Try to load a WAVE from the given seekable stream. Returns true if
+ * successful. In that case, the stream's seek position will be set to the
+ * start of the audio data, and size, rate and flags contain information
+ * necessary for playback. Currently this function only supports uncompressed
+ * raw PCM data as well as IMA ADPCM.
+ */
+extern bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags, uint16 *wavType = 0, int *blockAlign = 0);
+
+/**
+ * Try to load a WAVE from the given seekable stream and create an AudioStream
+ * from that data. Currently this function only supports uncompressed raw PCM
+ * data as well as IMA ADPCM.
+ *
+ * This function uses loadWAVFromStream() internally.
+ */
+AudioStream *makeWAVStream(Common::SeekableReadStream &stream);
+
+} // End of namespace Audio
+
+#endif


Property changes on: tools/trunk/utils/wave.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.





More information about the Scummvm-git-logs mailing list