[Scummvm-cvs-logs] scummvm-tools master -> 4160509b36fbbe09052a6c8d00457c2f6f6bfb36

criezy criezy at scummvm.org
Thu Sep 11 23:02:38 CEST 2014


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm-tools' repo located at https://github.com/scummvm/scummvm-tools .

Summary:
4160509b36 SWORD1: Fix detection and decoding of big endian speech data


Commit: 4160509b36fbbe09052a6c8d00457c2f6f6bfb36
    https://github.com/scummvm/scummvm-tools/commit/4160509b36fbbe09052a6c8d00457c2f6f6bfb36
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2014-09-11T22:01:28+01:00

Commit Message:
SWORD1: Fix detection and decoding of big endian speech data

This brings the endianness heuristic in line with the code in ScummVM.
This also fix the decoding of the big endian data (a number of samples
was read with the wrong endianness).

Changed paths:
    NEWS
    engines/sword1/compress_sword1.cpp
    engines/sword1/compress_sword1.h



diff --git a/NEWS b/NEWS
index 5ee2d7e..0e45648 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,9 @@
 For a more comprehensive changelog of the latest experimental code, see:
         https://github.com/scummvm/scummvm-tools/commits/
 
+1.8.0 (XXXX-XX-XX)
+ - Fix detection and decoding of BS1 big endian speech data in compress_sword1.
+
 1.7.0 (2014-07-21)
  - Add support for CGE 2 (Sfinx) in extract_cge and pack_cge tools.
  - Add option to run some of the tools in the GUI  on all the files with the same
diff --git a/engines/sword1/compress_sword1.cpp b/engines/sword1/compress_sword1.cpp
index b422c49..ef8bd73 100644
--- a/engines/sword1/compress_sword1.cpp
+++ b/engines/sword1/compress_sword1.cpp
@@ -312,6 +312,33 @@ MusicFile musicNames[TOTAL_TUNES] = {
 };
 
 int16 *CompressSword1::uncompressSpeech(Common::File &clu, uint32 idx, uint32 cSize, uint32 *returnSize) {
+	if (_speechEndianness == UnknownEndian) {
+		uint32 leSize, beSize;
+		_speechEndianness = LittleEndian;
+		int16* leData = uncompressSpeech(clu, idx, cSize, &leSize);
+		_speechEndianness = BigEndian;
+		int16* beData = uncompressSpeech(clu, idx, cSize, &beSize);
+		_speechEndianness = guessEndianness(leData, leSize / 2, beData, beSize / 2);
+		switch (_speechEndianness) {
+		case LittleEndian:
+			free(beData);
+			setRawAudioType(true, false, 16);
+			*returnSize = leSize;
+			return leData;
+		case BigEndian:
+			free(leData);
+			setRawAudioType(false, false, 16);
+			*returnSize = beSize;
+			return beData;
+		case UnknownEndian:
+			free(leData);
+			free(beData);
+			error("Sound::uncompressSpeech(): cannot determine data endianness");
+			*returnSize = 0;
+			return NULL;
+		}
+	}
+	
 	uint32 resSize, srcPos;
 	int16 *srcData, *dstData, *dstPos;
 	uint32 headerPos = 0;
@@ -330,7 +357,10 @@ int16 *CompressSword1::uncompressSpeech(Common::File &clu, uint32 idx, uint32 cS
 		dstPos = dstData;
 		cSize = (cSize - (headerPos + 8)) / 2;
 		while (srcPos < cSize) {
-			length = (int16)READ_LE_UINT16(srcData + srcPos);
+			if (_speechEndianness == LittleEndian)
+				length = (int16)READ_LE_UINT16(srcData + srcPos);
+			else
+				length = (int16)READ_BE_UINT16(srcData + srcPos);
 			srcPos++;
 			if (length < 0) {
 				length = -length;
@@ -345,8 +375,6 @@ int16 *CompressSword1::uncompressSpeech(Common::File &clu, uint32 idx, uint32 cS
 		}
 		free(fBuf);
 		*returnSize = resSize * 2;
-		if (_speechEndianness == UnknownEndian)
-			guessEndianness(dstData, length);
 		return dstData;
 	} else {
 		free(fBuf);
@@ -356,26 +384,44 @@ int16 *CompressSword1::uncompressSpeech(Common::File &clu, uint32 idx, uint32 cS
 	}
 }
 
-void CompressSword1::guessEndianness(int16 *data, int16 length) {
+CompressSword1::Endianness CompressSword1::guessEndianness(int16 *leData, uint32 leSize, int16 *beData, uint32 beSize) {
+	if (leData == NULL && beData == NULL)
+		return UnknownEndian;
+	else if (leData == NULL)
+		return BigEndian;
+	else if (beData == NULL)
+		return LittleEndian;
+	
 	// Compute average of difference between two consecutive samples for both the given
 	// data array and the byte swapped array.
-	double bs_diff_sum = 0., diff_sum = 0.;
+	uint32 length = leSize > beSize ? beSize : leSize;
 	if (length > 2000)
 		length = 2000;
+	double le_diff = endiannessHeuristicValue(leData, leSize, length, LittleEndian);
+	double be_diff = endiannessHeuristicValue(beData, beSize, length, BigEndian);
+	print("Speech endianness heuristic: average = %f for BE and %f for LE (%d samples)", be_diff, le_diff, length);
+	if (be_diff < le_diff)
+		return BigEndian;
+	else if (le_diff < be_diff)
+		return LittleEndian;
+	return UnknownEndian;
+}
 
-	int16 prev_bs_value = (int16)SWAP_16(*((uint16*)data));
-	for (int16 i = 1 ; i < length ; ++i) {
-		diff_sum += data[i] > data[i-1] ? data[i] - data[i-1] : data[i-1] - data[i];
-		int16 bs_value = (int16)SWAP_16(*((uint16*)(data + i)));
-		bs_diff_sum += bs_value > prev_bs_value ? bs_value - prev_bs_value : prev_bs_value - bs_value;
-		prev_bs_value = bs_value;
+double CompressSword1::endiannessHeuristicValue(int16* data, uint32 dataSize, uint32 maxSamples, Endianness dataEndianness) {
+	double diff_sum = 0.;
+	uint32 cpt = 0;
+	int16 prev_value = dataEndianness == BigEndian ? (int16)READ_BE_UINT16(data) : (int16)READ_LE_UINT16(data);
+	for (uint32 i = 1; i < dataSize && cpt < maxSamples; ++i) {
+		int16 value = dataEndianness == BigEndian ? (int16)READ_BE_UINT16(data + i) : (int16)READ_LE_UINT16(data + i);
+		if (value != prev_value) {
+			diff_sum += fabs((double)(value - prev_value));
+			++cpt;
+			prev_value = value;
+		}
 	}
-	// Set the little/big endian flags
-	if (diff_sum < bs_diff_sum)
-		_speechEndianness = LittleEndian;
-	else
-		_speechEndianness = BigEndian;
-	setRawAudioType(_speechEndianness == LittleEndian, false, 16);
+	if (cpt == 0)
+		return 50000.;
+	return diff_sum / cpt;
 }
 
 uint8 *CompressSword1::convertData(uint8 *rawData, uint32 rawSize, uint32 *resSize) {
diff --git a/engines/sword1/compress_sword1.h b/engines/sword1/compress_sword1.h
index cd7dfe3..7321d50 100644
--- a/engines/sword1/compress_sword1.h
+++ b/engines/sword1/compress_sword1.h
@@ -48,14 +48,16 @@ protected:
 	void compressSpeech(const Common::Filename *inpath, const Common::Filename *outpath);
 	void compressMusic(const Common::Filename *inpath, const Common::Filename *outpath);
 	void checkFilesExist(bool checkSpeech, bool checkMusic, const Common::Filename *inpath);
-	void guessEndianness(int16 *data, int16 length);
+
+	enum Endianness { BigEndian , LittleEndian , UnknownEndian } ;
+	Endianness guessEndianness(int16 *leData, uint32 leSize, int16 *beData, uint32 beSize);
+	double endiannessHeuristicValue(int16* data, uint32 dataSize, uint32 maxSamples, Endianness dataEndianness);
 
 private:
 	bool _useOutputMusicSubdir;
 
 	bool _macVersion;
 
-	enum Endianness { BigEndian , LittleEndian , UnknownEndian } ;
 	Endianness _speechEndianness;
 };
 






More information about the Scummvm-git-logs mailing list