mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-14 18:47:39 +01:00
Fix .mul IMA decoding oddness [Tomb Raider Underworld (PC)]
This commit is contained in:
parent
477666a4f7
commit
799f5939b4
@ -322,11 +322,11 @@ static const int16_t mul_delta_table[16] = {
|
|||||||
|
|
||||||
|
|
||||||
/* Crystal Dynamics IMA, reverse engineered from the exe, also info: https://github.com/sephiroth99/MulDeMu */
|
/* Crystal Dynamics IMA, reverse engineered from the exe, also info: https://github.com/sephiroth99/MulDeMu */
|
||||||
static void cd_ima_expand_nibble(VGMSTREAMCHANNEL* stream, off_t byte_offset, int shift, int32_t* hist1, int32_t* index) {
|
static void cd_ima_expand_nibble(uint8_t byte, int shift, int32_t* hist1, int32_t* index) {
|
||||||
int code, sample, step, delta;
|
int code, sample, step, delta;
|
||||||
|
|
||||||
/* could do the above table calcs during decode too */
|
/* could do the above table calcs during decode too */
|
||||||
code = (read_8bit(byte_offset,stream->streamfile) >> shift) & 0xf;
|
code = (byte >> shift) & 0xf;
|
||||||
sample = *hist1;
|
sample = *hist1;
|
||||||
step = mul_adpcm_table[*index];
|
step = mul_adpcm_table[*index];
|
||||||
|
|
||||||
@ -1210,50 +1210,55 @@ void decode_h4m_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspa
|
|||||||
stream->adpcm_step_index = step_index;
|
stream->adpcm_step_index = step_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* test... */
|
||||||
|
static inline int _clamp_s32(int value, int min, int max) {
|
||||||
|
if (value < min)
|
||||||
|
return min;
|
||||||
|
else if (value > max)
|
||||||
|
return max;
|
||||||
|
else
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
/* Crystal Dynamics IMA. Original code uses mind-bending intrinsics, so this may not be fully accurate.
|
/* Crystal Dynamics IMA. Original code uses mind-bending intrinsics, so this may not be fully accurate.
|
||||||
* Has another table with delta_table MMX combos, and using header sample and clamps seems necessary. */
|
* Has another table with delta_table MMX combos, and uses header sample (first nibble is always 0). */
|
||||||
void decode_cd_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
void decode_cd_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||||
|
uint8_t frame[0x24] = {0};
|
||||||
int i, frames_in, sample_pos = 0, block_samples, frame_size;
|
int i, frames_in, sample_pos = 0, block_samples, frame_size;
|
||||||
int32_t hist1 = stream->adpcm_history1_32;
|
int32_t hist1 = stream->adpcm_history1_32;
|
||||||
int step_index = stream->adpcm_step_index;
|
int step_index = stream->adpcm_step_index;
|
||||||
off_t frame_offset;
|
off_t frame_offset;
|
||||||
|
|
||||||
/* external interleave (fixed size), mono */
|
/* external interleave (fixed size), mono */
|
||||||
block_samples = (0x24 - 0x4) * 2;
|
frame_size = 0x24;
|
||||||
|
block_samples = (frame_size - 0x4) * 2;
|
||||||
frames_in = first_sample / block_samples;
|
frames_in = first_sample / block_samples;
|
||||||
first_sample = first_sample % block_samples;
|
first_sample = first_sample % block_samples;
|
||||||
frame_size = 0x24;
|
|
||||||
|
|
||||||
frame_offset = stream->offset + frame_size*frames_in;
|
frame_offset = stream->offset + frame_size * frames_in;
|
||||||
|
read_streamfile(frame, frame_offset, frame_size, stream->streamfile); /* ignore EOF errors */
|
||||||
|
|
||||||
/* normal header (hist+step+reserved), mono */
|
/* normal header (hist+step+reserved), mono */
|
||||||
if (first_sample == 0) {
|
if (first_sample == 0) {
|
||||||
off_t header_offset = frame_offset + 0x00;
|
hist1 = get_s16le(frame + 0x00);
|
||||||
|
step_index = get_u8(frame + 0x02);
|
||||||
|
step_index = _clamp_s32(step_index, 0, 88);
|
||||||
|
|
||||||
hist1 = read_16bitLE(header_offset+0x00,stream->streamfile);
|
/* write header sample (even samples per block, skips first nibble) */
|
||||||
step_index = read_8bit(header_offset+0x02,stream->streamfile);
|
|
||||||
if (step_index < 0) step_index=0;
|
|
||||||
if (step_index > 88) step_index=88;
|
|
||||||
|
|
||||||
/* write header sample (even samples per block, skips last nibble) */
|
|
||||||
outbuf[sample_pos] = (short)(hist1);
|
outbuf[sample_pos] = (short)(hist1);
|
||||||
sample_pos += channelspacing;
|
sample_pos += channelspacing;
|
||||||
first_sample += 1;
|
first_sample += 1;
|
||||||
samples_to_do -= 1;
|
samples_to_do -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* decode nibbles (layout: straight in mono ) */
|
/* decode nibbles (layout: straight in mono) */
|
||||||
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
||||||
off_t byte_offset = frame_offset + 0x04 + (i-1)/2;
|
int pos = 0x04 + (i/2);
|
||||||
int nibble_shift = (!((i-1)&1) ? 0:4); /* low first */
|
int shift = (i&1 ? 4:0); /* low first, but first low nibble is skipped */
|
||||||
|
|
||||||
/* must skip last nibble per spec, rarely needed though (ex. Gauntlet Dark Legacy) */
|
cd_ima_expand_nibble(frame[pos], shift, &hist1, &step_index);
|
||||||
if (i < block_samples) {
|
outbuf[sample_pos] = (short)(hist1);
|
||||||
cd_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
|
sample_pos += channelspacing;
|
||||||
outbuf[sample_pos] = (short)(hist1);
|
|
||||||
sample_pos += channelspacing;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stream->adpcm_history1_32 = hist1;
|
stream->adpcm_history1_32 = hist1;
|
||||||
|
Loading…
Reference in New Issue
Block a user