// NOTE: Functions in these module are somewhat different from what can be seen // in IDA because of two new helper functions that deal with incoming bits. I // bet something like these were implemented via function-like macro in the // same manner zlib deals with bits. The pattern is so common in this module so // I made an exception and extracted it into separate functions to increase // readability. #include "sound_decoder.h" #include #include #include namespace fallout { #define SOUND_DECODER_IN_BUFFER_SIZE (512) typedef int (*ReadBandFunc)(SoundDecoder* soundDecoder, int offset, int bits); static bool soundDecoderPrepare(SoundDecoder* soundDecoder, SoundDecoderReadProc* readProc, void* data); static unsigned char soundDecoderReadNextChunk(SoundDecoder* soundDecoder); static void init_pack_tables(); static int ReadBand_Fail(SoundDecoder* soundDecoder, int offset, int bits); static int ReadBand_Fmt0(SoundDecoder* soundDecoder, int offset, int bits); static int ReadBand_Fmt3_16(SoundDecoder* soundDecoder, int offset, int bits); static int ReadBand_Fmt17(SoundDecoder* soundDecoder, int offset, int bits); static int ReadBand_Fmt18(SoundDecoder* soundDecoder, int offset, int bits); static int ReadBand_Fmt19(SoundDecoder* soundDecoder, int offset, int bits); static int ReadBand_Fmt20(SoundDecoder* soundDecoder, int offset, int bits); static int ReadBand_Fmt21(SoundDecoder* soundDecoder, int offset, int bits); static int ReadBand_Fmt22(SoundDecoder* soundDecoder, int offset, int bits); static int ReadBand_Fmt23(SoundDecoder* soundDecoder, int offset, int bits); static int ReadBand_Fmt24(SoundDecoder* soundDecoder, int offset, int bits); static int ReadBand_Fmt26(SoundDecoder* soundDecoder, int offset, int bits); static int ReadBand_Fmt27(SoundDecoder* soundDecoder, int offset, int bits); static int ReadBand_Fmt29(SoundDecoder* soundDecoder, int offset, int bits); static bool ReadBands(SoundDecoder* soundDecoder); static void untransform_subband0(unsigned char* a1, unsigned char* a2, int a3, int a4); static void untransform_subband(unsigned char* a1, unsigned char* a2, int a3, int a4); static void untransform_all(SoundDecoder* soundDecoder); static bool soundDecoderFill(SoundDecoder* soundDecoder); static inline void soundDecoderRequireBits(SoundDecoder* soundDecoder, int bits); static inline void soundDecoderDropBits(SoundDecoder* soundDecoder, int bits); static int ReadBand_Fmt31(SoundDecoder* soundDecoder, int offset, int bits); // 0x51E328 static int gSoundDecodersCount = 0; // 0x51E330 static ReadBandFunc _ReadBand_tbl[32] = { ReadBand_Fmt0, ReadBand_Fail, ReadBand_Fail, ReadBand_Fmt3_16, ReadBand_Fmt3_16, ReadBand_Fmt3_16, ReadBand_Fmt3_16, ReadBand_Fmt3_16, ReadBand_Fmt3_16, ReadBand_Fmt3_16, ReadBand_Fmt3_16, ReadBand_Fmt3_16, ReadBand_Fmt3_16, ReadBand_Fmt3_16, ReadBand_Fmt3_16, ReadBand_Fmt3_16, ReadBand_Fmt3_16, ReadBand_Fmt17, ReadBand_Fmt18, ReadBand_Fmt19, ReadBand_Fmt20, ReadBand_Fmt21, ReadBand_Fmt22, ReadBand_Fmt23, ReadBand_Fmt24, ReadBand_Fail, ReadBand_Fmt26, ReadBand_Fmt27, ReadBand_Fail, ReadBand_Fmt29, ReadBand_Fail, ReadBand_Fmt31, }; // 0x6AD960 static unsigned char pack11_2[128]; // 0x6AD9E0 static unsigned char pack3_3[32]; // 0x6ADA00 static unsigned short pack5_3[128]; // 0x6ADB00 static unsigned char* _AudioDecoder_scale0; // 0x6ADB04 static unsigned char* _AudioDecoder_scale_tbl; // 0x4D3BB0 static bool soundDecoderPrepare(SoundDecoder* soundDecoder, SoundDecoderReadProc* readProc, void* data) { soundDecoder->readProc = readProc; soundDecoder->data = data; soundDecoder->bufferIn = (unsigned char*)malloc(SOUND_DECODER_IN_BUFFER_SIZE); if (soundDecoder->bufferIn == NULL) { return false; } soundDecoder->bufferInSize = SOUND_DECODER_IN_BUFFER_SIZE; soundDecoder->remainingInSize = 0; return true; } // 0x4D3BE0 static unsigned char soundDecoderReadNextChunk(SoundDecoder* soundDecoder) { soundDecoder->remainingInSize = soundDecoder->readProc(soundDecoder->data, soundDecoder->bufferIn, soundDecoder->bufferInSize); if (soundDecoder->remainingInSize == 0) { memset(soundDecoder->bufferIn, 0, soundDecoder->bufferInSize); soundDecoder->remainingInSize = soundDecoder->bufferInSize; } soundDecoder->nextIn = soundDecoder->bufferIn; soundDecoder->remainingInSize -= 1; return *soundDecoder->nextIn++; } // 0x4D3C78 static void init_pack_tables() { // 0x51E32C static bool inited = false; int i; int j; int m; if (inited) { return; } for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { for (m = 0; m < 3; m++) { pack3_3[i + j * 3 + m * 9] = i + j * 4 + m * 16; } } } for (i = 0; i < 5; i++) { for (j = 0; j < 5; j++) { for (m = 0; m < 5; m++) { pack5_3[i + j * 5 + m * 25] = i + j * 8 + m * 64; } } } for (i = 0; i < 11; i++) { for (j = 0; j < 11; j++) { pack11_2[i + j * 11] = i + j * 16; } } inited = true; } // 0x4D3D9C static int ReadBand_Fail(SoundDecoder* soundDecoder, int offset, int bits) { return 0; } // 0x4D3DA0 static int ReadBand_Fmt0(SoundDecoder* soundDecoder, int offset, int bits) { int* p = (int*)soundDecoder->samples; p += offset; int i = soundDecoder->samples_per_subband; while (i != 0) { *p = 0; p += soundDecoder->subbands; i--; } return 1; } // 0x4D3DC8 static int ReadBand_Fmt3_16(SoundDecoder* soundDecoder, int offset, int bits) { int value; int v14; short* base = (short*)_AudioDecoder_scale0; base += (int)(UINT_MAX << (bits - 1)); int* p = (int*)soundDecoder->samples; p += offset; v14 = (1 << bits) - 1; int i = soundDecoder->samples_per_subband; while (i != 0) { soundDecoderRequireBits(soundDecoder, bits); value = soundDecoder->hold; soundDecoderDropBits(soundDecoder, bits); *p = base[v14 & value]; p += soundDecoder->subbands; i--; } return 1; } // 0x4D3E90 static int ReadBand_Fmt17(SoundDecoder* soundDecoder, int offset, int bits) { short* base = (short*)_AudioDecoder_scale0; int* p = (int*)soundDecoder->samples; p += offset; int i = soundDecoder->samples_per_subband; while (i != 0) { soundDecoderRequireBits(soundDecoder, 3); int value = soundDecoder->hold & 0xFF; if (!(value & 0x01)) { soundDecoderDropBits(soundDecoder, 1); *p = 0; p += soundDecoder->subbands; if (--i == 0) { break; } *p = 0; p += soundDecoder->subbands; if (--i == 0) { break; } } else if (!(value & 0x02)) { soundDecoderDropBits(soundDecoder, 2); *p = 0; p += soundDecoder->subbands; if (--i == 0) { break; } } else { soundDecoderDropBits(soundDecoder, 3); if (value & 0x04) { *p = base[1]; } else { *p = base[-1]; } p += soundDecoder->subbands; i--; } } return 1; } // 0x4D3F98 static int ReadBand_Fmt18(SoundDecoder* soundDecoder, int offset, int bits) { short* base = (short*)_AudioDecoder_scale0; int* p = (int*)soundDecoder->samples; p += offset; int i = soundDecoder->samples_per_subband; while (i != 0) { soundDecoderRequireBits(soundDecoder, 2); int value = soundDecoder->hold; if (!(value & 0x01)) { soundDecoderDropBits(soundDecoder, 1); *p = 0; p += soundDecoder->subbands; if (--i == 0) { return 1; } } else { soundDecoderDropBits(soundDecoder, 2); if (value & 0x02) { *p = base[1]; } else { *p = base[-1]; } p += soundDecoder->subbands; i--; } } return 1; } // 0x4D4068 static int ReadBand_Fmt19(SoundDecoder* soundDecoder, int offset, int bits) { short* base = (short*)_AudioDecoder_scale0; base -= 1; int* p = (int*)soundDecoder->samples; p += offset; int i = soundDecoder->samples_per_subband; while (i != 0) { soundDecoderRequireBits(soundDecoder, 5); int value = soundDecoder->hold & 0x1F; soundDecoderDropBits(soundDecoder, 5); value = pack3_3[value]; *p = base[value & 0x03]; p += soundDecoder->subbands; if (--i == 0) { break; } *p = base[(value >> 2) & 0x03]; p += soundDecoder->subbands; if (--i == 0) { break; } *p = base[value >> 4]; p += soundDecoder->subbands; i--; } return 1; } // 0x4D4158 static int ReadBand_Fmt20(SoundDecoder* soundDecoder, int offset, int bits) { short* base = (short*)_AudioDecoder_scale0; int* p = (int*)soundDecoder->samples; p += offset; int i = soundDecoder->samples_per_subband; while (i != 0) { soundDecoderRequireBits(soundDecoder, 4); int value = soundDecoder->hold & 0xFF; if (!(value & 0x01)) { soundDecoderDropBits(soundDecoder, 1); *p = 0; p += soundDecoder->subbands; if (--i == 0) { break; } *p = 0; p += soundDecoder->subbands; if (--i == 0) { break; } } else if (!(value & 0x02)) { soundDecoderDropBits(soundDecoder, 2); *p = 0; p += soundDecoder->subbands; if (--i == 0) { break; } } else { soundDecoderDropBits(soundDecoder, 4); if (value & 0x08) { if (value & 0x04) { *p = base[2]; } else { *p = base[1]; } } else { if (value & 0x04) { *p = base[-1]; } else { *p = base[-2]; } } p += soundDecoder->subbands; i--; } } return 1; } // 0x4D4254 static int ReadBand_Fmt21(SoundDecoder* soundDecoder, int offset, int bits) { short* base = (short*)_AudioDecoder_scale0; int* p = (int*)soundDecoder->samples; p += offset; int i = soundDecoder->samples_per_subband; while (i != 0) { soundDecoderRequireBits(soundDecoder, 3); int value = soundDecoder->hold & 0xFF; if (!(value & 0x01)) { soundDecoderDropBits(soundDecoder, 1); *p = 0; p += soundDecoder->subbands; if (--i == 0) { break; } } else { soundDecoderDropBits(soundDecoder, 3); if (value & 0x04) { if (value & 0x02) { *p = base[2]; } else { *p = base[1]; } } else { if (value & 0x02) { *p = base[-1]; } else { *p = base[-2]; } } p += soundDecoder->subbands; i--; } } return 1; } // 0x4D4338 static int ReadBand_Fmt22(SoundDecoder* soundDecoder, int offset, int bits) { short* base = (short*)_AudioDecoder_scale0; base -= 2; int* p = (int*)soundDecoder->samples; p += offset; int i = soundDecoder->samples_per_subband; while (i != 0) { soundDecoderRequireBits(soundDecoder, 7); int value = soundDecoder->hold & 0x7F; soundDecoderDropBits(soundDecoder, 7); value = pack5_3[value]; *p = base[value & 7]; p += soundDecoder->subbands; if (--i == 0) { break; } *p = base[((value >> 3) & 7)]; p += soundDecoder->subbands; if (--i == 0) { break; } *p = base[value >> 6]; p += soundDecoder->subbands; if (--i == 0) { break; } } return 1; } // 0x4D4434 static int ReadBand_Fmt23(SoundDecoder* soundDecoder, int offset, int bits) { short* base = (short*)_AudioDecoder_scale0; int* p = (int*)soundDecoder->samples; p += offset; int i = soundDecoder->samples_per_subband; while (i != 0) { soundDecoderRequireBits(soundDecoder, 5); int value = soundDecoder->hold; if (!(value & 0x01)) { soundDecoderDropBits(soundDecoder, 1); *p = 0; p += soundDecoder->subbands; if (--i == 0) { break; } *p = 0; p += soundDecoder->subbands; if (--i == 0) { break; } } else if (!(value & 0x02)) { soundDecoderDropBits(soundDecoder, 2); *p = 0; p += soundDecoder->subbands; if (--i == 0) { break; } } else if (!(value & 0x04)) { soundDecoderDropBits(soundDecoder, 4); if (value & 0x08) { *p = base[1]; } else { *p = base[-1]; } p += soundDecoder->subbands; if (--i == 0) { break; } } else { soundDecoderDropBits(soundDecoder, 5); value >>= 3; value &= 0x03; if (value >= 2) { value += 3; } *p = base[value - 3]; p += soundDecoder->subbands; i--; } } return 1; } // 0x4D4584 static int ReadBand_Fmt24(SoundDecoder* soundDecoder, int offset, int bits) { short* base = (short*)_AudioDecoder_scale0; int* p = (int*)soundDecoder->samples; p += offset; int i = soundDecoder->samples_per_subband; while (i != 0) { soundDecoderRequireBits(soundDecoder, 4); int value = soundDecoder->hold & 0xFF; if (!(value & 0x01)) { soundDecoderDropBits(soundDecoder, 1); *p = 0; p += soundDecoder->subbands; if (--i == 0) { break; } } else if (!(value & 0x02)) { soundDecoderDropBits(soundDecoder, 3); if (value & 0x04) { *p = base[1]; } else { *p = base[-1]; } p += soundDecoder->subbands; if (--i == 0) { break; } } else { soundDecoderDropBits(soundDecoder, 4); value >>= 2; value &= 0x03; if (value >= 2) { value += 3; } *p = base[value - 3]; p += soundDecoder->subbands; i--; } } return 1; } // 0x4D4698 static int ReadBand_Fmt26(SoundDecoder* soundDecoder, int offset, int bits) { short* base = (short*)_AudioDecoder_scale0; int* p = (int*)soundDecoder->samples; p += offset; int i = soundDecoder->samples_per_subband; while (i != 0) { soundDecoderRequireBits(soundDecoder, 5); int value = soundDecoder->hold; if (!(value & 0x01)) { soundDecoderDropBits(soundDecoder, 1); *p = 0; p += soundDecoder->subbands; if (--i == 0) { break; } *p = 0; p += soundDecoder->subbands; if (--i == 0) { break; } } else if (!(value & 0x02)) { soundDecoderDropBits(soundDecoder, 2); *p = 0; p += soundDecoder->subbands; if (--i == 0) { break; } } else { soundDecoderDropBits(soundDecoder, 5); value >>= 2; value &= 0x07; if (value >= 4) { value += 1; } *p = base[value - 4]; p += soundDecoder->subbands; i--; } } return 1; } // 0x4D47A4 static int ReadBand_Fmt27(SoundDecoder* soundDecoder, int offset, int bits) { short* base = (short*)_AudioDecoder_scale0; int* p = (int*)soundDecoder->samples; p += offset; int i = soundDecoder->samples_per_subband; while (i != 0) { soundDecoderRequireBits(soundDecoder, 4); int value = soundDecoder->hold; if (!(value & 0x01)) { soundDecoderDropBits(soundDecoder, 1); *p = 0; p += soundDecoder->subbands; if (--i == 0) { break; } } else { soundDecoderDropBits(soundDecoder, 4); value >>= 1; value &= 0x07; if (value >= 4) { value += 1; } *p = base[value - 4]; p += soundDecoder->subbands; i--; } } return 1; } // 0x4D4870 static int ReadBand_Fmt29(SoundDecoder* soundDecoder, int offset, int bits) { short* base = (short*)_AudioDecoder_scale0; int* p = (int*)soundDecoder->samples; p += offset; int i = soundDecoder->samples_per_subband; while (i != 0) { soundDecoderRequireBits(soundDecoder, 7); int value = soundDecoder->hold & 0x7F; soundDecoderDropBits(soundDecoder, 7); value = pack11_2[value]; *p = base[(value & 0x0F) - 5]; p += soundDecoder->subbands; if (--i == 0) { break; } *p = base[(value >> 4) - 5]; p += soundDecoder->subbands; if (--i == 0) { break; } } return 1; } // 0x4D493C static bool ReadBands(SoundDecoder* soundDecoder) { int v9; int v15; int v17; int v19; unsigned short* v18; int v21; ReadBandFunc fn; soundDecoderRequireBits(soundDecoder, 4); v9 = soundDecoder->hold & 0xF; soundDecoderDropBits(soundDecoder, 4); soundDecoderRequireBits(soundDecoder, 16); v15 = soundDecoder->hold & 0xFFFF; soundDecoderDropBits(soundDecoder, 16); v17 = 1 << v9; v18 = (unsigned short*)_AudioDecoder_scale0; v19 = v17; v21 = 0; while (v19--) { *v18++ = v21; v21 += v15; } v18 = (unsigned short*)_AudioDecoder_scale0; v19 = v17; v21 = -v15; while (v19--) { v18--; *v18 = v21; v21 -= v15; } init_pack_tables(); for (int index = 0; index < soundDecoder->subbands; index++) { soundDecoderRequireBits(soundDecoder, 5); int bits = soundDecoder->hold & 0x1F; soundDecoderDropBits(soundDecoder, 5); fn = _ReadBand_tbl[bits]; if (!fn(soundDecoder, index, bits)) { return false; } } return true; } // 0x4D4ADC static void untransform_subband0(unsigned char* a1, unsigned char* a2, int a3, int a4) { short* p; p = (short*)a2; p += a3; if (a4 == 2) { int i = a3; while (i != 0) { i--; } } else if (a4 == 4) { int v31 = a3; int* v9 = (int*)a2; v9 += a3; int* v10 = (int*)a2; v10 += a3 * 3; int* v11 = (int*)a2; v11 += a3 * 2; while (v31 != 0) { int* v33 = (int*)a2; int* v34 = (int*)a1; int v12 = *v34 >> 16; int v13 = *v33; *v33 = (int)(*(short*)v34) + 2 * v12 + v13; int v14 = *v9; *v9 = 2 * v13 - v12 - v14; int v15 = *v11; *v11 = 2 * v14 + v15 + v13; int v16 = *v10; *v10 = 2 * v15 - v14 - v16; v10++; v11++; v9++; *(short*)a1 = v15 & 0xFFFF; *(short*)(a1 + 2) = v16 & 0xFFFF; a1 += 4; a2 += 4; v31--; } } else { int v30 = a4 >> 1; int v32 = a3; while (v32 != 0) { int* v19 = (int*)a2; int v20; int v22; if (v30 & 0x01) { } else { v20 = (int)*(short*)a1; v22 = *(int*)a1 >> 16; } int v23 = v30 >> 1; while (--v23 != -1) { int v24 = *v19; *v19 += 2 * v22 + v20; v19 += a3; int v26 = *v19; *v19 = 2 * v24 - v22 - v26; v19 += a3; v20 = *v19; *v19 += 2 * v26 + v24; v19 += a3; v22 = *v19; *v19 = 2 * v20 - v26 - v22; v19 += a3; } *(short*)a1 = v20 & 0xFFFF; *(short*)(a1 + 2) = v22 & 0xFFFF; a1 += 4; a2 += 4; v32--; } } } // 0x4D4D1C static void untransform_subband(unsigned char* a1, unsigned char* a2, int a3, int a4) { int v13; int* v14; int* v25; int* v26; int v15; int v16; int v17; int* v18; int v19; int* v20; int* v21; v26 = (int*)a1; v25 = (int*)a2; if (a4 == 4) { unsigned char* v4 = a2 + 4 * a3; unsigned char* v5 = a2 + 3 * a3; unsigned char* v6 = a2 + 2 * a3; int v7; int v8; int v9; int v10; int v11; while (a3--) { v7 = *(unsigned int*)(v26 + 4); v8 = *(unsigned int*)v25; *(unsigned int*)v25 = *(unsigned int*)v26 + 2 * v7; v9 = *(unsigned int*)v4; *(unsigned int*)v4 = 2 * v8 - v7 - v9; v10 = *(unsigned int*)v6; v5 += 4; *v6 += 2 * v9 + v8; v11 = *(unsigned int*)(v5 - 4); v6 += 4; *(unsigned int*)(v5 - 4) = 2 * v10 - v9 - v11; v4 += 4; *(unsigned int*)v26 = v10; *(unsigned int*)(v26 + 4) = v11; v26 += 2; v25 += 1; } } else { int v24 = a3; while (v24 != 0) { v13 = a4 >> 2; v14 = v25; v15 = v26[0]; v16 = v26[1]; while (--v13 != -1) { v17 = *v14; *v14 += 2 * v16 + v15; v18 = v14 + a3; v19 = *v18; *v18 = 2 * v17 - v16 - v19; v20 = v18 + a3; v15 = *v20; *v20 += 2 * v19 + v17; v21 = v20 + a3; v16 = *v21; *v21 = 2 * v15 - v19 - v16; v14 = v21 + a3; } v26[0] = v15; v26[1] = v16; v26 += 2; v25 += 1; v24--; } } } // 0x4D4E80 static void untransform_all(SoundDecoder* soundDecoder) { int v8; unsigned char* ptr; int v3; int v4; unsigned char* j; int v6; int* v5; if (!soundDecoder->levels) { return; } ptr = soundDecoder->samples; v8 = soundDecoder->samples_per_subband; while (v8 > 0) { v3 = soundDecoder->subbands >> 1; v4 = soundDecoder->block_samples_per_subband; if (v4 > v8) { v4 = v8; } v4 *= 2; untransform_subband0(soundDecoder->prev_samples, ptr, v3, v4); v5 = (int*)ptr; for (v6 = 0; v6 < v4; v6++) { *v5 += 1; v5 += v3; } j = 4 * v3 + soundDecoder->prev_samples; while (1) { v3 >>= 1; v4 *= 2; if (v3 == 0) { break; } untransform_subband(j, ptr, v3, v4); j += 8 * v3; } ptr += soundDecoder->block_total_samples * 4; v8 -= soundDecoder->block_samples_per_subband; } } // NOTE: Inlined. // // 0x4D4F58 static bool soundDecoderFill(SoundDecoder* soundDecoder) { // CE: Implementation is slightly different. `ReadBands` now handles new // Fmt31 used in some Russian localizations. The appropriate handler acts as // both decoder and transformer, so there is no need to untransform bands // once again. This approach assumes band 31 is never used by standard acms // and mods. if (ReadBands(soundDecoder)) { untransform_all(soundDecoder); } soundDecoder->file_cnt -= soundDecoder->total_samples; soundDecoder->samp_ptr = soundDecoder->samples; soundDecoder->samp_cnt = soundDecoder->total_samples; if (soundDecoder->file_cnt < 0) { soundDecoder->samp_cnt += soundDecoder->file_cnt; soundDecoder->file_cnt = 0; } return true; } // 0x4D4FA0 size_t soundDecoderDecode(SoundDecoder* soundDecoder, void* buffer, size_t size) { unsigned char* dest; unsigned char* samp_ptr; int samp_cnt; dest = (unsigned char*)buffer; samp_ptr = soundDecoder->samp_ptr; samp_cnt = soundDecoder->samp_cnt; size_t bytesRead; for (bytesRead = 0; bytesRead < size; bytesRead += 2) { if (samp_cnt == 0) { if (soundDecoder->file_cnt == 0) { break; } // NOTE: Uninline. if (!soundDecoderFill(soundDecoder)) { break; } samp_ptr = soundDecoder->samp_ptr; samp_cnt = soundDecoder->samp_cnt; } int sample = *(int*)samp_ptr; samp_ptr += 4; *(unsigned short*)(dest + bytesRead) = (sample >> soundDecoder->levels) & 0xFFFF; samp_cnt--; } soundDecoder->samp_ptr = samp_ptr; soundDecoder->samp_cnt = samp_cnt; return bytesRead; } // 0x4D5048 void soundDecoderFree(SoundDecoder* soundDecoder) { if (soundDecoder->bufferIn != NULL) { free(soundDecoder->bufferIn); } if (soundDecoder->prev_samples != NULL) { free(soundDecoder->prev_samples); } if (soundDecoder->samples != NULL) { free(soundDecoder->samples); } free(soundDecoder); gSoundDecodersCount--; if (gSoundDecodersCount == 0) { if (_AudioDecoder_scale_tbl != NULL) { free(_AudioDecoder_scale_tbl); _AudioDecoder_scale_tbl = NULL; } } } // 0x4D50A8 SoundDecoder* soundDecoderInit(SoundDecoderReadProc* readProc, void* data, int* channelsPtr, int* sampleRatePtr, int* sampleCountPtr) { int v14; int v20; int v73; SoundDecoder* soundDecoder = (SoundDecoder*)malloc(sizeof(*soundDecoder)); if (soundDecoder == NULL) { return NULL; } memset(soundDecoder, 0, sizeof(*soundDecoder)); gSoundDecodersCount++; if (!soundDecoderPrepare(soundDecoder, readProc, data)) { goto L66; } soundDecoder->hold = 0; soundDecoder->bits = 0; soundDecoderRequireBits(soundDecoder, 24); v14 = soundDecoder->hold; soundDecoderDropBits(soundDecoder, 24); if ((v14 & 0xFFFFFF) != 0x32897) { goto L66; } soundDecoderRequireBits(soundDecoder, 8); v20 = soundDecoder->hold; soundDecoderDropBits(soundDecoder, 8); if (v20 != 1) { goto L66; } soundDecoderRequireBits(soundDecoder, 16); soundDecoder->file_cnt = soundDecoder->hold & 0xFFFF; soundDecoderDropBits(soundDecoder, 16); soundDecoderRequireBits(soundDecoder, 16); soundDecoder->file_cnt |= (soundDecoder->hold & 0xFFFF) << 16; soundDecoderDropBits(soundDecoder, 16); soundDecoderRequireBits(soundDecoder, 16); soundDecoder->channels = soundDecoder->hold & 0xFFFF; soundDecoderDropBits(soundDecoder, 16); soundDecoderRequireBits(soundDecoder, 16); soundDecoder->rate = soundDecoder->hold & 0xFFFF; soundDecoderDropBits(soundDecoder, 16); soundDecoderRequireBits(soundDecoder, 4); soundDecoder->levels = soundDecoder->hold & 0x0F; soundDecoderDropBits(soundDecoder, 4); soundDecoderRequireBits(soundDecoder, 12); soundDecoder->subbands = 1 << soundDecoder->levels; soundDecoder->samples_per_subband = soundDecoder->hold & 0x0FFF; soundDecoder->total_samples = soundDecoder->samples_per_subband * soundDecoder->subbands; soundDecoderDropBits(soundDecoder, 12); if (soundDecoder->levels != 0) { v73 = 3 * soundDecoder->subbands / 2 - 2; } else { v73 = 0; } soundDecoder->block_samples_per_subband = 2048 / soundDecoder->subbands - 2; if (soundDecoder->block_samples_per_subband < 1) { soundDecoder->block_samples_per_subband = 1; } soundDecoder->block_total_samples = soundDecoder->block_samples_per_subband * soundDecoder->subbands; if (v73 != 0) { soundDecoder->prev_samples = (unsigned char*)malloc(sizeof(unsigned char*) * v73); if (soundDecoder->prev_samples == NULL) { goto L66; } memset(soundDecoder->prev_samples, 0, sizeof(unsigned char*) * v73); } soundDecoder->samples = (unsigned char*)malloc(sizeof(unsigned char*) * soundDecoder->total_samples); if (soundDecoder->samples == NULL) { goto L66; } soundDecoder->samp_cnt = 0; if (gSoundDecodersCount == 1) { _AudioDecoder_scale_tbl = (unsigned char*)malloc(0x20000); _AudioDecoder_scale0 = _AudioDecoder_scale_tbl + 0x10000; } *channelsPtr = soundDecoder->channels; *sampleRatePtr = soundDecoder->rate; *sampleCountPtr = soundDecoder->file_cnt; return soundDecoder; L66: soundDecoderFree(soundDecoder); *channelsPtr = 0; *sampleRatePtr = 0; *sampleCountPtr = 0; return 0; } static inline void soundDecoderRequireBits(SoundDecoder* soundDecoder, int bits) { while (soundDecoder->bits < bits) { soundDecoder->remainingInSize--; unsigned char ch; if (soundDecoder->remainingInSize < 0) { ch = soundDecoderReadNextChunk(soundDecoder); } else { ch = *soundDecoder->nextIn++; } soundDecoder->hold |= ch << soundDecoder->bits; soundDecoder->bits += 8; } } static inline void soundDecoderDropBits(SoundDecoder* soundDecoder, int bits) { soundDecoder->hold >>= bits; soundDecoder->bits -= bits; } static int ReadBand_Fmt31(SoundDecoder* soundDecoder, int offset, int bits) { int* samples = (int*)soundDecoder->samples; int remaining_samples = soundDecoder->total_samples; while (remaining_samples != 0) { soundDecoderRequireBits(soundDecoder, 16); int value = soundDecoder->hold & 0xFFFF; soundDecoderDropBits(soundDecoder, 16); *samples++ = (value << 16) >> (16 - soundDecoder->levels); remaining_samples--; } return 0; } } // namespace fallout