Fuse EACS and DVI IMA decoder into a configurable IMA decoder

EACS was just DVI (high nibble first) with stereo and mono modes, while
old DVI was mono only.
This unifies both decoders, so DVI_IMA (not interleaved) works with mono
and stereo while DVI_IMA_int (interleaved) forces mono.
Some metas needed to explicitly set DVI_IMA_int but others work with no
change.
This commit is contained in:
bnnm 2017-11-17 17:18:17 +01:00
parent 4dfbc3cf6a
commit 4a2cf9dd91
11 changed files with 29 additions and 60 deletions

View File

@ -19,9 +19,8 @@ void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_dvi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_eacs_ima(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first);
void decode_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);

View File

@ -426,8 +426,11 @@ void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel
stream->adpcm_step_index = step_index;
}
void decode_dvi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_count;
/* Standard DVI/IMA ADPCM (as in, ADPCM recommended by the IMA using Intel/DVI's implementation).
* Configurable: stereo or mono/interleave nibbles, and high or low nibble first.
* For vgmstream, low nibble is called "IMA ADPCM" and high nibble is "DVI IMA ADPCM" (same thing though). */
void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first) {
int i, sample_count = 0;
int32_t hist1 = stream->adpcm_history1_32;
int step_index = stream->adpcm_step_index;
@ -436,37 +439,13 @@ void decode_dvi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
//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 (old-style DVI)
ms_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;
}
/* basically DVI stereo (high=L + low=R nibbles) and DVI mono (high=L, low=L) all-in-one, can be simplified/removed */
void decode_eacs_ima(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
VGMSTREAMCHANNEL * stream = &(vgmstream->ch[channel]);//todo pass externally for consistency
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 = channelspacing == 1 ?
stream->offset + i/2 : /* mono mode */
stream->offset + i; /* stereo mode */
int nibble_shift = channelspacing == 1 ?
(!(i%2) ? 4:0) : /* mono mode (high first) */
(channel==0 ? 4:0); /* stereo mode (high=L,low=R) */
for (i = first_sample; i < first_sample + samples_to_do; i++, sample_count += channelspacing) {
off_t byte_offset = is_stereo ?
stream->offset + i : /* stereo: one nibble per channel */
stream->offset + i/2; /* mono: consecutive nibbles */
int nibble_shift = is_high_first ?
is_stereo ? (!(channel&1) ? 4:0) : (!(i&1) ? 4:0) : /* even = high, odd = low */
is_stereo ? (!(channel&1) ? 0:4) : (!(i&1) ? 0:4); /* even = low, odd = high */
ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
outbuf[sample_count] = (short)(hist1);

View File

@ -440,7 +440,6 @@ static const coding_info coding_info_list[] = {
{coding_CBD2_int, "Cuberoot-delta-exact (CBD2) 8-bit DPCM with 1 byte interleave"},
{coding_DVI_IMA, "Intel DVI 4-bit IMA ADPCM"},
{coding_DVI_IMA_int, "Intel DVI 4-bit IMA ADPCM (interleaved)"},
{coding_EACS_IMA, "EACS 4-bit IMA ADPCM"},
{coding_IMA_int, "IMA 4-bit ADPCM (interleaved)"},
{coding_IMA, "IMA 4-bit ADPCM"},
{coding_MS_IMA, "Microsoft 4-bit IMA ADPCM"},

View File

@ -91,7 +91,7 @@ void ea_schl_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
break;
/* id, size, IMA hist, stereo/mono data */
case coding_EACS_IMA:
case coding_DVI_IMA:
for(i = 0; i < vgmstream->channels; i++) {
off_t header_offset = block_offset + 0xc + i*4;
vgmstream->ch[i].adpcm_history1_32 = read_16bitLE(header_offset+0x00, vgmstream->ch[i].streamfile);
@ -196,7 +196,7 @@ void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
vgmstream->current_block_size=block_size-8;
if(vgmstream->coding_type==coding_EACS_IMA) {
if(vgmstream->coding_type==coding_DVI_IMA) {
vgmstream->current_block_size=read_32bitLE(block_offset,vgmstream->ch[0].streamfile);
for(i=0;i<vgmstream->channels;i++) {

View File

@ -27,7 +27,7 @@ VGMSTREAM * init_vgmstream_dc_kcey(STREAMFILE *streamFile) {
vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile);
vgmstream->loop_end_sample = read_32bitBE(0x0C,streamFile);
vgmstream->coding_type = coding_EACS_IMA;
vgmstream->coding_type = coding_DVI_IMA;
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_DC_KCEY;

View File

@ -65,7 +65,7 @@ VGMSTREAM * init_vgmstream_eacs(STREAMFILE *streamFile) {
vgmstream->coding_type = coding_PCM8_int;
}
else
vgmstream->coding_type = coding_EACS_IMA;
vgmstream->coding_type = coding_DVI_IMA;
vgmstream->layout_type = layout_eacs_blocked;
vgmstream->meta_type = meta_EACS_PC;

View File

@ -66,7 +66,7 @@ VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE *streamFile) {
break;
case EA_CODEC_IMA:
vgmstream->coding_type = coding_EACS_IMA;
vgmstream->coding_type = coding_DVI_IMA;
break;
default:

View File

@ -28,10 +28,10 @@ VGMSTREAM * init_vgmstream_tun(STREAMFILE *streamFile) {
start_offset = 0x10;
vgmstream->channels = channel_count;
vgmstream->sample_rate = 22050;
vgmstream->coding_type = coding_DVI_IMA;
vgmstream->coding_type = coding_DVI_IMA_int;
vgmstream->num_samples = (get_streamfile_size(streamFile)) - 0x10;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 1;
vgmstream->interleave_block_size = 0x01;
vgmstream->meta_type = meta_TUN;
/* open the file for reading */

View File

@ -36,7 +36,7 @@ VGMSTREAM * init_vgmstream_x360_tra(STREAMFILE *streamFile) {
vgmstream->channels = 2;
vgmstream->sample_rate = 24000;
vgmstream->coding_type = coding_DVI_IMA;
vgmstream->coding_type = coding_DVI_IMA_int;
vgmstream->num_samples = (int32_t)(get_streamfile_size(streamFile) - ((get_streamfile_size(streamFile)/0x204)*4));
vgmstream->layout_type = layout_tra_blocked;

View File

@ -1019,7 +1019,6 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
return 28;
case coding_G721:
case coding_DVI_IMA:
case coding_EACS_IMA:
case coding_SNDS_IMA:
case coding_IMA:
case coding_OTNS_IMA:
@ -1175,9 +1174,6 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
return 0x14;
case coding_NGC_DTK:
return 32;
case coding_EACS_IMA:
return 1;
case coding_DVI_IMA:
case coding_IMA:
case coding_G721:
case coding_SNDS_IMA:
@ -1213,6 +1209,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
case coding_WS:
return vgmstream->current_block_size;
case coding_IMA_int:
case coding_DVI_IMA:
case coding_DVI_IMA_int:
case coding_AICA:
return 1;
@ -1614,16 +1611,12 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
case coding_DVI_IMA:
case coding_DVI_IMA_int:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_dvi_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
int is_stereo = vgmstream->channels > 1 && vgmstream->coding_type == coding_DVI_IMA;
int is_high_first = vgmstream->coding_type == coding_DVI_IMA || vgmstream->coding_type == coding_DVI_IMA_int;
decode_standard_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do);
}
break;
case coding_EACS_IMA:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_eacs_ima(vgmstream,buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do,chan);
samples_to_do, chan, is_stereo, is_high_first);
}
break;
case coding_IMA:

View File

@ -120,10 +120,9 @@ typedef enum {
coding_XBOX_int, /* XBOX IMA ADPCM (interleaved) */
coding_IMA, /* IMA ADPCM (low nibble first) */
coding_IMA_int, /* IMA ADPCM (interleaved) */
coding_DVI_IMA, /* DVI IMA ADPCM (high nibble first), aka ADP4 */
coding_DVI_IMA_int, /* DVI IMA ADPCM (Interleaved) */
coding_DVI_IMA, /* DVI IMA ADPCM (stereo or mono, high nibble first) */
coding_DVI_IMA_int, /* DVI IMA ADPCM (mono/interleave, high nibble first) */
coding_NDS_IMA, /* IMA ADPCM w/ NDS layout */
coding_EACS_IMA, /* Electronic Arts IMA ADPCM */
coding_MS_IMA, /* Microsoft IMA ADPCM */
coding_RAD_IMA, /* Radical IMA ADPCM */
coding_RAD_IMA_mono, /* Radical IMA ADPCM, mono (for interleave) */