Add ALP IMA decoder [Lego Racers (PC)]

This commit is contained in:
bnnm 2018-09-06 20:25:04 +02:00
parent 800ebfc007
commit 19f69e14b7
6 changed files with 60 additions and 7 deletions

View File

@ -20,6 +20,7 @@ void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_wv6_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_alp_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);

View File

@ -188,6 +188,25 @@ static void wv6_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset,
if (*step_index > 88) *step_index=88;
}
/* Lego Racers (PC) .TUN variation, reverse engineered from the .exe */
static void alp_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) {
int sample_nibble, sample_decoded, step, delta;
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
sample_decoded = *hist1;
step = ADPCMTable[*step_index];
delta = (sample_nibble & 0x7);
delta = (delta * step) >> 2;
if (sample_nibble & 8) delta = -delta;
sample_decoded += delta;
*hist1 = clamp16(sample_decoded);
*step_index += IMA_IndexTable[sample_nibble];
if (*step_index < 0) *step_index=0;
if (*step_index > 88) *step_index=88;
}
/* ************************************ */
/* DVI/IMA */
/* ************************************ */
@ -310,6 +329,28 @@ void decode_wv6_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
stream->adpcm_step_index = step_index;
}
/* ALT IMA, DVI IMA with custom nibble expand */
void decode_alp_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
//external interleave
//no header
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
off_t byte_offset = stream->offset + i/2;
int nibble_shift = (i&1?0:4); //high nibble first
alp_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
outbuf[sample_count] = (short)(hist1);
}
stream->adpcm_history1_32 = hist1;
stream->adpcm_step_index = step_index;
}
/* ************************************ */
/* MS-IMA */
/* ************************************ */

View File

@ -539,6 +539,7 @@ static const coding_info coding_info_list[] = {
{coding_SNDS_IMA, "Heavy Iron .snds 4-bit IMA ADPCM"},
{coding_OTNS_IMA, "Omikron: The Nomad Soul 4-bit IMA ADPCM"},
{coding_WV6_IMA, "Gorilla Systems WV6 4-bit IMA ADPCM"},
{coding_ALP_IMA, "High Voltage ALP 4-bit IMA ADPCM"},
{coding_MS_IMA, "Microsoft 4-bit IMA ADPCM"},
{coding_XBOX_IMA, "XBOX 4-bit IMA ADPCM"},

View File

@ -7,11 +7,9 @@ VGMSTREAM * init_vgmstream_tun(STREAMFILE *streamFile) {
off_t start_offset;
int loop_flag, channel_count;
/* check extension */
/* checks */
if ( !check_extensions(streamFile,"tun") )
goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x414C5020) /* "ALP " */
goto fail;
@ -28,12 +26,11 @@ VGMSTREAM * init_vgmstream_tun(STREAMFILE *streamFile) {
vgmstream->sample_rate = 22050;
vgmstream->num_samples = ima_bytes_to_samples(get_streamfile_size(streamFile) - 0x10, channel_count);
vgmstream->coding_type = coding_DVI_IMA_int;
vgmstream->coding_type = coding_ALP_IMA;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x01;
vgmstream->meta_type = meta_TUN;
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;

View File

@ -1112,6 +1112,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_DVI_IMA_int:
case coding_3DS_IMA:
case coding_WV6_IMA:
case coding_ALP_IMA:
return 2;
case coding_XBOX_IMA:
case coding_XBOX_IMA_mch:
@ -1283,6 +1284,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
case coding_DVI_IMA_int:
case coding_3DS_IMA:
case coding_WV6_IMA:
case coding_ALP_IMA:
return 0x01;
case coding_MS_IMA:
case coding_RAD_IMA:
@ -1745,6 +1747,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
vgmstream->channels,vgmstream->samples_into_block,samples_to_do);
}
break;
case coding_ALP_IMA:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_alp_ima(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
vgmstream->channels,vgmstream->samples_into_block,samples_to_do);
}
break;
case coding_APPLE_IMA4:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_apple_ima4(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,

View File

@ -118,6 +118,7 @@ typedef enum {
coding_SNDS_IMA, /* Heavy Iron Studios .snds IMA ADPCM */
coding_OTNS_IMA, /* Omikron The Nomad Soul IMA ADPCM */
coding_WV6_IMA, /* Gorilla Systems WV6 4-bit IMA ADPCM */
coding_ALP_IMA, /* High Voltage ALP 4-bit IMA ADPCM */
coding_MS_IMA, /* Microsoft IMA ADPCM */
coding_XBOX_IMA, /* XBOX IMA ADPCM */
@ -768,15 +769,18 @@ typedef struct {
layout_t layout_type; /* type of layout for data */
meta_t meta_type; /* how we know the metadata */
/* subsongs and internal config */
/* subsongs */
int num_streams; /* for multi-stream formats (0=not set/one stream, 1=one stream) */
int stream_index; /* selected stream (also 1-based) */
char stream_name[STREAM_NAME_SIZE]; /* name of the current stream (info), if the file stores it and it's filled */
size_t stream_size; /* info to properly calculate bitrate in case of subsongs */
/* config */
int allow_dual_stereo; /* search for dual stereo (file_L.ext + file_R.ext = single stereo file) */
uint32_t channel_mask; /* to silence crossfading subsongs/layers */
int channel_mappings_on; /* channel mappings are active */
int channel_mappings[32]; /* swap channel "i" with "[i]" */
int allow_dual_stereo; /* search for dual stereo (file_L.ext + file_R.ext = single stereo file) */
double config_loops; /* appropriate number of loops (config request for players) */
int config_nofade; /* continue normally after target loop count (config request for players) */
/* looping */
int loop_flag; /* is this stream looped? */