Patch #1936137: "Speech for Mac BS1 english"

svn-id: r42423
This commit is contained in:
Eugene Sandulenko 2009-07-12 18:52:38 +00:00
parent b0b12b60ed
commit bd91c1129d
3 changed files with 101 additions and 5 deletions

View File

@ -51,6 +51,7 @@ Sound::Sound(const char *searchPath, Audio::Mixer *mixer, ResMan *pResMan) {
strcpy(_filePath, searchPath);
_mixer = mixer;
_resMan = pResMan;
_bigEndianSpeech = false;
_cowHeader = NULL;
_endOfQueue = 0;
_currentCowFile = 0;
@ -67,6 +68,83 @@ Sound::~Sound(void) {
closeCowSystem();
}
void Sound::checkSpeechFileEndianness() {
// Some mac versions (not all of them) use big endian wav, although
// the wav header doesn't indicate it.
// Use heuristic to determine endianness of speech.
// The heuristic consist in computing the sum of the absolute difference for
// every two consecutive samples. This is done both with a big endian and a
// little endian assumption. The one with the smallest sum should be the
// correct one (the sound wave is supposed to be relatively smooth).
// It needs at least 1000 samples to get stable result (the code below is
// using the first 2000 samples of the wav sound.
// Init speach file if not already done.
if (!_currentCowFile) {
// Open one of the speech file. It uses SwordEngine::_systemVars.currentCD
// to decide which file to open, therefore if it is currently set to zero
// we have to set it to either 1 or 2 (I decided to set it to 1 as this is
// more likely to be the first file that will be needed).
bool no_current_cd = false;
if (SwordEngine::_systemVars.currentCD == 0) {
SwordEngine::_systemVars.currentCD = 1;
no_current_cd = true;
}
initCowSystem();
if (no_current_cd) {
// In case it fails with CD1 retyr with CD2
if (!_currentCowFile) {
SwordEngine::_systemVars.currentCD = 2;
initCowSystem();
}
// Reset curentCD flag
SwordEngine::_systemVars.currentCD = 0;
}
}
// Testing for endianness makes sense only if using the nom compressed files.
if (_cowHeader == NULL || (_cowMode != CowWave && _cowMode != CowDemo))
return;
// I picked the sample to use randomly (I just made sure it is long enough so that there is
// a fair change of the heuristic to have a stable result and work for every languages).
int roomNo = _currentCowFile == 1 ? 1 : 129;
int localNo = _currentCowFile == 1 ? 2 : 933;
// Get the speech data and apply the heuristic
uint32 locIndex = _cowHeader[roomNo] >> 2;
uint32 sampleSize = _cowHeader[locIndex + (localNo * 2)];
uint32 index = _cowHeader[locIndex + (localNo * 2) - 1];
if (sampleSize) {
uint32 size;
double be_diff_sum = 0., le_diff_sum = 0.;
_bigEndianSpeech = false;
int16 *data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size);
// Compute average of differecen between two consecutive samples for both BE and LE
if (data) {
if (size > 4000)
size = 2000;
else
size /= 2;
int16 prev_be_value = (int16)SWAP_BYTES_16(*((uint16*)(data)));
for (uint32 i = 1 ; i < size ; ++i) {
le_diff_sum += fabs(data[i] - data[i-1]);
int16 be_value = (int16)SWAP_BYTES_16(*((uint16*)(data + i)));
be_diff_sum += fabs(be_value - prev_be_value);
prev_be_value = be_value;
}
delete [] data;
}
// Set the big endian flag
_bigEndianSpeech = (be_diff_sum < le_diff_sum);
if (_bigEndianSpeech)
debug(6, "Mac version: using big endian speech file");
else
debug(6, "Mac version: using little endian speech file");
debug(8, "Speech endianness heuristic: average = %f for BE and %f for LE, computed on %d samples)", be_diff_sum / (size - 1), le_diff_sum / (size - 1), size);
}
}
int Sound::addToQueue(int32 fxNo) {
bool alreadyInQueue = false;
for (uint8 cnt = 0; (cnt < _endOfQueue) && (!alreadyInQueue); cnt++)
@ -386,21 +464,32 @@ int16 *Sound::uncompressSpeech(uint32 index, uint32 cSize, uint32 *size) {
int16 *dstData = (int16*)malloc(resSize * 2);
int32 samplesLeft = resSize;
while (srcPos < cSize && samplesLeft > 0) {
length = (int16)READ_LE_UINT16(srcData + srcPos);
length = (int16)(_bigEndianSpeech ? READ_BE_UINT16(srcData + srcPos) : READ_LE_UINT16(srcData + srcPos));
srcPos++;
if (length < 0) {
length = -length;
if (length > samplesLeft)
length = samplesLeft;
int16 value;
if (_bigEndianSpeech) {
value = (int16)SWAP_BYTES_16(*((uint16*)(srcData + srcPos)));
} else {
value = srcData[srcPos];
}
for (uint16 cnt = 0; cnt < (uint16)length; cnt++)
dstData[dstPos++] = srcData[srcPos];
dstData[dstPos++] = value;
srcPos++;
} else {
if (length > samplesLeft)
length = samplesLeft;
memcpy(dstData + dstPos, srcData + srcPos, length * 2);
dstPos += length;
srcPos += length;
if (_bigEndianSpeech) {
for (uint16 cnt = 0; cnt < (uint16)length; cnt++)
dstData[dstPos++] = (int16)SWAP_BYTES_16(*((uint16*)(srcData + (srcPos++))));
} else {
memcpy(dstData + dstPos, srcData + srcPos, length * 2);
dstPos += length;
srcPos += length;
}
}
samplesLeft -= length;
}

View File

@ -95,6 +95,8 @@ public:
void engine(void);
void checkSpeechFileEndianness();
private:
uint8 _sfxVolL, _sfxVolR, _speechVolL, _speechVolR;
void playSample(QueueElement *elem);
@ -116,6 +118,7 @@ private:
uint8 _endOfQueue;
Audio::Mixer *_mixer;
ResMan *_resMan;
bool _bigEndianSpeech;
char _filePath[100];
static const char _musicList[270];
static const uint16 _roomsFixedFx[TOTAL_ROOMS][TOTAL_FX_PER_ROOM];

View File

@ -145,6 +145,10 @@ Common::Error SwordEngine::init() {
_systemVars.playSpeech = 1;
_mouseState = 0;
// Some Mac versions use big endian for the speech files but not all of them.
if (_systemVars.platform == Common::kPlatformMacintosh)
_sound->checkSpeechFileEndianness();
_logic->initialize();
_objectMan->initialize();