mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-04 17:29:11 +00:00
parent
b0b12b60ed
commit
bd91c1129d
@ -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;
|
||||
}
|
||||
|
@ -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];
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user