| 70 | void Sound::checkSpeechFileEndianness() { |
| 71 | // Some mac versions (not all of them) use big endian waw, although |
| 72 | // the waw header doesn't indicate it. |
| 73 | // Use heuristic to determine endianness of speech. |
| 74 | // The heuristic consist in computing the sum of the absolute difference for |
| 75 | // every two consecutive samples. This is done both with a big endian and a |
| 76 | // little endian assumption. The one with the smallest sum should be the |
| 77 | // correct one (the sound wave is supposed to be relatively smooth). |
| 78 | // It needs at least 1000 samples to get stable result (the code below is |
| 79 | // using the first 2000 samples of the waw sound. |
| 80 | |
| 81 | // Init speach file if not already done. |
| 82 | if (!_currentCowFile) { |
| 83 | // Open one of the speech file. It uses SwordEngine::_systemVars.currentCD |
| 84 | // to decide which file to open, therefore if it is currently set to zero |
| 85 | // we have to set it to either 1 or 2 (I decided to set it to 1 as this is |
| 86 | // more likely to be the first file that will be needed). |
| 87 | bool no_current_cd = false; |
| 88 | if (SwordEngine::_systemVars.currentCD == 0) { |
| 89 | SwordEngine::_systemVars.currentCD = 1; |
| 90 | no_current_cd = true; |
| 91 | } |
| 92 | initCowSystem(); |
| 93 | if (no_current_cd) { |
| 94 | // In case it fails with CD1 retyr with CD2 |
| 95 | if (!_currentCowFile) { |
| 96 | SwordEngine::_systemVars.currentCD = 2; |
| 97 | initCowSystem(); |
| 98 | } |
| 99 | // Reset curentCD flag |
| 100 | SwordEngine::_systemVars.currentCD = 0; |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | // Testing for endianness makes sense only if using the nom compressed files. |
| 105 | if (_cowHeader == NULL || (_cowMode != CowWave && _cowMode != CowDemo)) |
| 106 | return; |
| 107 | |
| 108 | // I picked the sample to use randomly (I just made sure it is long enough so that there is |
| 109 | // a fair change of the heuristic to have a stable result and work for every languages). |
| 110 | int roomNo = _currentCowFile == 1 ? 1 : 129; |
| 111 | int localNo = _currentCowFile == 1 ? 2 : 933; |
| 112 | // Get the speech data and apply the heuristic |
| 113 | uint32 locIndex = _cowHeader[roomNo] >> 2; |
| 114 | uint32 sampleSize = _cowHeader[locIndex + (localNo * 2)]; |
| 115 | uint32 index = _cowHeader[locIndex + (localNo * 2) - 1]; |
| 116 | if (sampleSize) { |
| 117 | uint32 size; |
| 118 | double be_diff_sum = 0., le_diff_sum = 0.; |
| 119 | _bigEndianSpeech = false; |
| 120 | int16 *data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size); |
| 121 | // Compute average of differecen between two consecutive samples for both BE and LE |
| 122 | if (data) { |
| 123 | if (size > 4000) |
| 124 | size = 2000; |
| 125 | else |
| 126 | size /= 2; |
| 127 | int16 prev_be_value = (int16)SWAP_BYTES_16(*((uint16*)(data))); |
| 128 | for (uint32 i = 1 ; i < size ; ++i) { |
| 129 | le_diff_sum += fabs(data[i] - data[i-1]); |
| 130 | int16 be_value = (int16)SWAP_BYTES_16(*((uint16*)(data + i))); |
| 131 | be_diff_sum += fabs(be_value - prev_be_value); |
| 132 | prev_be_value = be_value; |
| 133 | } |
| 134 | delete [] data; |
| 135 | } |
| 136 | // Set the big endian flag |
| 137 | _bigEndianSpeech = (be_diff_sum < le_diff_sum); |
| 138 | if (_bigEndianSpeech) |
| 139 | debug(6, "Mac version: using big endian speech file"); |
| 140 | else |
| 141 | debug(6, "Mac version: using little endian speech file"); |
| 142 | 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); |
| 143 | } |
| 144 | } |
| 145 | |