[Scummvm-cvs-logs] SF.net SVN: scummvm:[46991] tools/trunk
sev at users.sourceforge.net
sev at users.sourceforge.net
Mon Jan 4 22:23:02 CET 2010
Revision: 46991
http://scummvm.svn.sourceforge.net/scummvm/?rev=46991&view=rev
Author: sev
Date: 2010-01-04 21:23:02 +0000 (Mon, 04 Jan 2010)
Log Message:
-----------
Patch #2925828: "Tools: add BS1 mac compression in compress_sword1"
Modified Paths:
--------------
tools/trunk/compress.cpp
tools/trunk/compress.h
tools/trunk/engines/sword1/compress_sword1.cpp
tools/trunk/engines/sword1/compress_sword1.h
Modified: tools/trunk/compress.cpp
===================================================================
--- tools/trunk/compress.cpp 2010-01-04 20:58:31 UTC (rev 46990)
+++ tools/trunk/compress.cpp 2010-01-04 21:23:02 UTC (rev 46991)
@@ -31,6 +31,7 @@
#endif /* HAVE_CONFIG_H */
#include "compress.h"
+#include "common/endian.h"
#ifdef USE_VORBIS
#include <vorbis/vorbisenc.h>
@@ -596,6 +597,95 @@
encodeAudio(outName, false, -1, tempEncoded, compMode);
}
+void CompressionTool::encodeAIF(const char *inName, const char *outName, AudioFormat compmode) {
+ // Get sound definition (length, frequency, stereo, ...)
+ char buf[4];
+ Common::File inFile(inName, "rb");
+ inFile.read_throwsOnError(buf, 4);
+ if (memcmp(buf, "FORM", 4) != 0)
+ error("Error: AIFF file has no 'FORM' header");
+ inFile.readUint32BE();
+ // Only AIFF (uncompressed) is supported, not AIFC
+ inFile.read_throwsOnError(buf, 4);
+ if (memcmp(buf, "AIFF", 4) != 0)
+ error("Error: AIFF file has no 'AIFF' header");
+
+ bool foundCOMM = false;
+ bool foundSSND = false;
+ uint16 numChannels = 0, bitsPerSample = 0;
+ uint32 numSampleFrames = 0, offset = 0, blockSize = 0, soundOffset = 0;
+ uint32 sampleRate = 0;
+
+ while ((!foundCOMM || !foundSSND) && !inFile.err() && !inFile.eos()) {
+
+ inFile.read_throwsOnError(buf, 4);
+ uint32 length = inFile.readUint32BE();
+ uint32 pos = inFile.pos();
+
+ if (memcmp(buf, "COMM", 4) == 0) {
+ foundCOMM = true;
+ numChannels = inFile.readUint16BE();
+ numSampleFrames = inFile.readUint32BE();
+ bitsPerSample = inFile.readUint16BE();
+ // The sample rate is stored as an "80 bit IEEE Standard 754 floating
+ // point number (Standard Apple Numeric Environment [SANE] data type
+ // Extended).
+ byte rate_buf[10];
+ uint32 last = 0;
+ inFile.read_throwsOnError(rate_buf, 10);
+ sampleRate = READ_BE_UINT32(rate_buf + 2);
+ byte exp = 30 - rate_buf[1];
+
+ while (exp--) {
+ last = sampleRate;
+ sampleRate >>= 1;
+ }
+
+ if (last & 0x00000001)
+ sampleRate++;
+ } else if (memcmp(buf, "SSND", 4) == 0) {
+ foundSSND = true;
+ offset = inFile.readUint32BE();
+ blockSize = inFile.readUint32BE();
+ soundOffset = inFile.pos();
+ }
+
+ inFile.seek(pos + length, SEEK_SET);
+ }
+ if (!foundCOMM)
+ error("Error: AIFF file has no 'COMM' chunk in 'AIFF' header");
+
+ if (!foundSSND)
+ error("Error: AIFF file has no 'COMM' chunk in 'SSND' header");
+
+ // Only a subset of the AIFF format is supported
+ if (numChannels < 1 || numChannels > 2)
+ error("Error: AIFF file has an unsupported number of channels");
+
+ if (bitsPerSample != 8 && bitsPerSample != 16)
+ error("Error: AIFF file has an unsupported number of bits per sample");
+
+ if (offset != 0 || blockSize != 0)
+ error("Error: AIFF file has block-aligned data, which is not supported");
+
+ // Get data and write to temporary file
+ uint32 size = numSampleFrames * numChannels * (bitsPerSample / 8);
+ inFile.seek(soundOffset, SEEK_SET);
+ char *aifData = (char *)malloc(size);
+ inFile.read_throwsOnError(aifData, size);
+ Common::File tmpFile(TEMP_RAW, "wb");
+ tmpFile.write(aifData, size);
+ tmpFile.close();
+
+ // Convert the temporary raw file to MP3/OGG/FLAC
+ // Samples are always signed, and big endian.
+ setRawAudioType(false, numChannels == 2, bitsPerSample);
+ encodeAudio(TEMP_RAW, true, sampleRate, outName, compmode);
+
+ // Delete temporary file
+ unlink(TEMP_RAW);
+}
+
void CompressionTool::extractAndEncodeVOC(const char *outName, Common::File &input, AudioFormat compMode) {
int bits;
int blocktype;
Modified: tools/trunk/compress.h
===================================================================
--- tools/trunk/compress.h 2010-01-04 20:58:31 UTC (rev 46990)
+++ tools/trunk/compress.h 2010-01-04 21:23:02 UTC (rev 46991)
@@ -115,6 +115,8 @@
void extractAndEncodeVOC(const char *outName, Common::File &input, AudioFormat compMode);
void extractAndEncodeWAV(const char *outName, Common::File &input, AudioFormat compMode);
+ void encodeAIF(const char *inName, const char *outName, AudioFormat compMode);
+
void encodeAudio(const char *inname, bool rawInput, int rawSamplerate, const char *outname, AudioFormat compmode);
void setRawAudioType(bool isLittleEndian, bool isStereo, uint8 bitsPerSample);
Modified: tools/trunk/engines/sword1/compress_sword1.cpp
===================================================================
--- tools/trunk/engines/sword1/compress_sword1.cpp 2010-01-04 20:58:31 UTC (rev 46990)
+++ tools/trunk/engines/sword1/compress_sword1.cpp 2010-01-04 21:23:02 UTC (rev 46991)
@@ -343,6 +343,8 @@
}
free(fBuf);
*returnSize = resSize * 2;
+ if (_speechEndianness == UnknownEndian)
+ guessEndianness(dstData, length);
return dstData;
} else {
free(fBuf);
@@ -352,6 +354,28 @@
}
}
+void CompressSword1::guessEndianness(int16 *data, int16 length) {
+ // 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.;
+ if (length > 2000)
+ length = 2000;
+
+ 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;
+ }
+ // Set the little/big endian flags
+ if (diff_sum < bs_diff_sum)
+ _speechEndianness = LittleEndian;
+ else
+ _speechEndianness = BigEndian;
+ setRawAudioType(_speechEndianness == LittleEndian, false, 16);
+}
+
uint8 *CompressSword1::convertData(uint8 *rawData, uint32 rawSize, uint32 *resSize) {
uint8 *resBuf;
@@ -441,7 +465,8 @@
int i;
char cluName[256], outName[256];
- setRawAudioType(true, false, 16);
+ if (_speechEndianness != UnknownEndian)
+ setRawAudioType(_speechEndianness == LittleEndian, false, 16);
for (i = 1; i <= 2; i++) {
// Updates the progress bar, add music files if we compress those too
@@ -491,7 +516,10 @@
// Update the progress bar, we add 2 if we compress speech to, for those files
updateProgress(i, TOTAL_TUNES +(_compSpeech? 2 : 0));
- sprintf(fNameIn, "%s/MUSIC/%s.WAV", inpath->getPath().c_str(), musicNames[i].fileName);
+ if (!_macVersion)
+ sprintf(fNameIn, "%s/MUSIC/%s.WAV", inpath->getPath().c_str(), musicNames[i].fileName);
+ else
+ sprintf(fNameIn, "%s/MUSIC/%s.AIF", inpath->getPath().c_str(), musicNames[i].fileName);
try {
Common::File inf(fNameIn, "rb");
@@ -510,7 +538,10 @@
}
print("encoding file (%3d/%d) %s -> %s\n", i + 1, TOTAL_TUNES, musicNames[i].fileName, fNameOut);
- encodeAudio(fNameIn, false, -1, fNameOut, _format);
+ if (!_macVersion)
+ encodeAudio(fNameIn, false, -1, fNameOut, _format);
+ else
+ encodeAIF(fNameIn, fNameOut, _format);
} catch (Common::FileException& err) {
print(err.what());
}
@@ -544,15 +575,35 @@
}
}
+ /* The PC Version uses LittleEndian speech files.
+ The Mac version can be either with little endian speech files or big endian speech files.
+ We detect if we have a PC or Mac version with the music files (WAV for PC and AIF for Mac).
+ If we have the Mac version or if we don't check the music files, an heuristic will be used
+ when first accessing the speech file to detect if it is little endian or big endian */
+
if (checkMusic) {
for (i = 0; i < 20; i++) { /* Check the first 20 music files */
+ // Check WAV file
sprintf(fileName, "%s/MUSIC/%s.WAV", inpath->getPath().c_str(), musicNames[i].fileName);
testFile = fopen(fileName, "rb");
if (testFile) {
musicFound = true;
fclose(testFile);
+ break;
}
+
+ // Check AIF file
+ sprintf(fileName, "%s/MUSIC/%s.AIF", inpath->getPath().c_str(), musicNames[i].fileName);
+ testFile = fopen(fileName, "rb");
+
+ if (testFile) {
+ musicFound = true;
+ _macVersion = true;
+ _speechEndianness = UnknownEndian;
+ fclose(testFile);
+ break;
+ }
}
if (!musicFound) {
@@ -562,6 +613,8 @@
print("If your OS is case-sensitive, make sure the filenames\n");
print("and directorynames are all upper-case.\n");
}
+ } else {
+ _speechEndianness = UnknownEndian;
}
if ((checkSpeech && (!speechFound)) || (checkMusic && (!musicFound))) {
@@ -569,14 +622,28 @@
}
}
+InspectionMatch CompressSword1::inspectInput(const Common::Filename &filename) {
+ // Wildcard matching as implemented in Tools is too restrictive (e.g. it doesn't
+ // work with *.cl? or even *.cl*).
+ // This is the reason why this function is reimplemented there.
+ if (
+ scumm_stricmp(filename.getExtension().c_str(), "clu") == 0 ||
+ scumm_stricmp(filename.getExtension().c_str(), "clm") == 0
+ )
+ return IMATCH_PERFECT;
+ return IMATCH_AWFUL;
+}
+
CompressSword1::CompressSword1(const std::string &name) : CompressionTool(name, TOOLTYPE_COMPRESSION) {
_compSpeech = true;
_compMusic = true;
+ _macVersion = false;
+ _speechEndianness = LittleEndian;
_supportsProgressBar = true;
ToolInput input;
- input.format = "*.clu";
+ input.format = "*.*";
_inputPaths.push_back(input);
_shorthelp = "Used to compress the Broken Sword 1 data files.";
Modified: tools/trunk/engines/sword1/compress_sword1.h
===================================================================
--- tools/trunk/engines/sword1/compress_sword1.h 2010-01-04 20:58:31 UTC (rev 46990)
+++ tools/trunk/engines/sword1/compress_sword1.h 2010-01-04 21:23:02 UTC (rev 46991)
@@ -30,6 +30,8 @@
CompressSword1(const std::string &name = "compress_sword1");
virtual void execute();
+
+ virtual InspectionMatch inspectInput(const Common::Filename &filename);
bool _compSpeech;
bool _compMusic;
@@ -45,6 +47,13 @@
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);
+
+private:
+ bool _macVersion;
+
+ enum Endianness { BigEndian , LittleEndian , UnknownEndian } ;
+ Endianness _speechEndianness;
};
#endif
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