diff --git a/src/coding/coding.h b/src/coding/coding.h index c6bb854d..2e48f1c8 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -116,7 +116,7 @@ void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_s long msadpcm_bytes_to_samples(long bytes, int block_size, int channels); /* yamaha_decoder */ -void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); +void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo); void decode_yamaha(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_yamaha_nxap(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); size_t yamaha_bytes_to_samples(size_t bytes, int channels); diff --git a/src/coding/yamaha_decoder.c b/src/coding/yamaha_decoder.c index 9ee92b97..e6b2b165 100644 --- a/src/coding/yamaha_decoder.c +++ b/src/coding/yamaha_decoder.c @@ -15,8 +15,8 @@ static const int scale_delta[16] = { }; -/* Yamaha AICA ADPCM, as seen in Dreamcast. Possibly like RIFF codec 0x20 or used in older arcade sound chips. */ -void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +/* Yamaha AICA ADPCM, as seen in Naomi/Dreamcast. Possibly like RIFF codec 0x20 or used in older arcade sound chips. */ +void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo) { int i, sample_count; int32_t hist1 = stream->adpcm_history1_16; @@ -28,8 +28,12 @@ void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, for (i=first_sample,sample_count=0; ioffset) + i/2; - int nibble_shift = (i&1?4:0); /* low nibble first */ + 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_stereo ? + (!(channel&1) ? 0:4) : /* even = low/L, odd = high/R */ + (!(i&1) ? 0:4); /* low nibble first */ /* Yamaha/AICA expand, but same result as IMA's (((delta * 2 + 1) * step) >> 3) */ sample_nibble = ((read_8bit(byte_offset,stream->streamfile) >> nibble_shift))&0xf; diff --git a/src/formats.c b/src/formats.c index 3959597b..ee8c1ebc 100644 --- a/src/formats.c +++ b/src/formats.c @@ -497,6 +497,7 @@ static const coding_info coding_info_list[] = { {coding_MSADPCM, "Microsoft 4-bit ADPCM"}, {coding_WS, "Westwood Studios VBR ADPCM"}, + {coding_AICA, "Yamaha AICA 4-bit ADPCM"}, {coding_AICA_int, "Yamaha AICA 4-bit ADPCM (mono/interleave)"}, {coding_YAMAHA, "Yamaha 4-bit ADPCM"}, {coding_YAMAHA_NXAP, "Yamaha NXAP 4-bit ADPCM"}, diff --git a/src/meta/genh.c b/src/meta/genh.c index ae902cfc..70cac106 100644 --- a/src/meta/genh.c +++ b/src/meta/genh.c @@ -95,7 +95,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) { case MPEG: coding = coding_MPEG_layer3; break; /* we later find out exactly which */ #endif case IMA: coding = coding_IMA; break; - case AICA: coding = coding_AICA_int; break; + case AICA: coding = coding_AICA; break; case MSADPCM: coding = coding_MSADPCM; break; case NGC_DSP: coding = coding_NGC_DSP; break; case PCM8_U_int: coding = coding_PCM8_U_int; break; @@ -139,7 +139,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) { case coding_PSX_badflags: case coding_DVI_IMA: case coding_IMA: - case coding_AICA_int: + case coding_AICA: case coding_APPLE_IMA4: vgmstream->interleave_block_size = genh.interleave; if (vgmstream->channels > 1) @@ -157,6 +157,8 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) { coding = coding_DVI_IMA_int; if (coding == coding_IMA) coding = coding_IMA_int; + if (coding == coding_AICA) + coding = coding_AICA_int; } /* to avoid endless loops */ @@ -173,7 +175,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) { } /* setup adpcm */ - if (coding == coding_AICA_int) { + if (coding == coding_AICA || coding == coding_AICA_int) { int i; for (i=0;ichannels;i++) { vgmstream->ch[i].adpcm_step_index = 0x7f; diff --git a/src/meta/txth.c b/src/meta/txth.c index 078b36c1..030ca461 100644 --- a/src/meta/txth.c +++ b/src/meta/txth.c @@ -106,7 +106,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) { case MPEG: coding = coding_MPEG_layer3; break; /* we later find out exactly which */ #endif case IMA: coding = coding_IMA; break; - case AICA: coding = coding_AICA_int; break; + case AICA: coding = coding_AICA; break; case MSADPCM: coding = coding_MSADPCM; break; case NGC_DSP: coding = coding_NGC_DSP; break; case PCM8_U_int: coding = coding_PCM8_U_int; break; @@ -150,7 +150,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) { case coding_PSX_badflags: case coding_DVI_IMA: case coding_IMA: - case coding_AICA_int: + case coding_AICA: case coding_APPLE_IMA4: vgmstream->interleave_block_size = txth.interleave; if (vgmstream->channels > 1) @@ -168,6 +168,8 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) { coding = coding_DVI_IMA_int; if (coding == coding_IMA) coding = coding_IMA_int; + if (coding == coding_AICA) + coding = coding_AICA_int; } /* to avoid endless loops */ @@ -176,7 +178,8 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) { coding == coding_PSX_badflags || coding == coding_IMA_int || coding == coding_DVI_IMA_int || - coding == coding_SDX2_int) ) { + coding == coding_SDX2_int || + coding == coding_AICA_int) ) { goto fail; } } else { @@ -184,7 +187,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) { } /* setup adpcm */ - if (coding == coding_AICA_int) { + if (coding == coding_AICA || coding == coding_AICA_int) { int i; for (i=0;ichannels;i++) { vgmstream->ch[i].adpcm_step_index = 0x7f; diff --git a/src/vgmstream.c b/src/vgmstream.c index 2a97b2a6..ae0e2c34 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -1045,6 +1045,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { return (vgmstream->interleave_block_size-(7-1)*vgmstream->channels)*2/vgmstream->channels; case coding_WS: /* only works if output sample size is 8 bit, which always is for WS ADPCM */ return vgmstream->ws_output_size; + case coding_AICA: + return 1; case coding_AICA_int: return 2; case coding_YAMAHA: @@ -1209,6 +1211,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { return vgmstream->interleave_block_size; case coding_WS: return vgmstream->current_block_size; + case coding_AICA: case coding_AICA_int: return 0x01; case coding_YAMAHA: @@ -1791,11 +1794,14 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do); } break; + case coding_AICA: case coding_AICA_int: for (chan=0;chanchannels;chan++) { + int is_stereo = (vgmstream->channels > 1 && vgmstream->coding_type == coding_AICA); + decode_aica(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); + samples_to_do, chan, is_stereo); } break; case coding_YAMAHA: diff --git a/src/vgmstream.h b/src/vgmstream.h index e341442b..ebb4a3ff 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -143,6 +143,7 @@ typedef enum { coding_MSADPCM, /* Microsoft ADPCM */ coding_WS, /* Westwood Studios VBR ADPCM */ + coding_AICA, /* Yamaha AICA ADPCM (stereo) */ coding_AICA_int, /* Yamaha AICA ADPCM (mono/interleave) */ coding_YAMAHA, /* Yamaha ADPCM */ coding_YAMAHA_NXAP, /* Yamaha ADPCM (NXAP variation) */