diff --git a/src/coding/coding.h b/src/coding/coding.h index 223f42fb..671a849e 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -181,6 +181,7 @@ void decode_circus_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel /* oki_decoder */ void decode_pcfx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int mode); void decode_oki16(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); +void decode_oki4s(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); size_t oki_bytes_to_samples(size_t bytes, int channels); /* ptadpcm_decoder */ diff --git a/src/coding/oki_decoder.c b/src/coding/oki_decoder.c index 1fc07b34..2151c476 100644 --- a/src/coding/oki_decoder.c +++ b/src/coding/oki_decoder.c @@ -2,10 +2,13 @@ static const int step_sizes[49] = { /* OKI table (subsection of IMA's table) */ - 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, - 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, - 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, - 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552 + 16, 17, 19, 21, 23, 25, 28, 31, + 34, 37, 41, 45, 50, 55, 60, 66, + 73, 80, 88, 97, 107, 118, 130, 143, + 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, + 724, 796, 876, 963, 1060, 1166, 1282, 1411, + 1552 }; static const int stex_indexes[16] = { /* OKI table (also from IMA) */ @@ -60,8 +63,9 @@ static void oki16_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, in code = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift) & 0xf; step = step_sizes[*step_index]; + /* IMA 'mul' style (standard OKI uses 'shift-add') */ delta = (code & 0x7); - delta = (((delta * 2) + 1) * step) >> 3; /* IMA 'mul' style (standard OKI uses 'shift-add') */ + delta = (((delta * 2) + 1) * step) >> 3; if (code & 0x8) delta = -delta; *hist1 += delta; @@ -75,6 +79,31 @@ static void oki16_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, in *out_sample = *hist1; } +static void oki4s_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index, int16_t *out_sample) { + int code, step, delta; + + code = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift) & 0xf; + step = step_sizes[*step_index]; + + step = step << 4; /* original table has precomputed step_sizes so that this isn't done */ + + /* IMA 'shift-add' style (like standard OKI) */ + delta = step >> 3; + if (code & 1) delta += step >> 2; + if (code & 2) delta += step >> 1; + if (code & 4) delta += step; + if (code & 8) delta = -delta; + *hist1 += delta; + + *hist1 = clamp16(*hist1); /* standard OKI clamps hist to 2047,-2048 here */ + + *step_index += stex_indexes[code]; + if (*step_index < 0) *step_index = 0; + if (*step_index > 48) *step_index = 48; + + *out_sample = *hist1; +} + /* PC-FX ADPCM decoding, variation of OKI/Dialogic/VOX ADPCM. Based on mednafen/pcfx-music-dump. * Apparently most ADPCM was made with a buggy encoder, resulting in incorrect sound in real hardware * and sound clipped at half. Decoding can be controlled with modes: @@ -138,6 +167,37 @@ void decode_oki16(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspaci stream->adpcm_step_index = step_index; } +/* OKI variation with 16-bit output (vs standard's 12-bit) and pre-adjusted tables (shifted by 4), found in Jubeat Clan (AC). + * Reverse engineered from the DLLs. */ +void decode_oki4s(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { + int i, sample_count = 0; + int32_t hist1 = stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + int16_t out_sample; + int is_stereo = channelspacing > 1; + + + /* external interleave */ + + /* no header (external setup), pre-clamp for wrong values */ + if (step_index < 0) step_index=0; + if (step_index > 48) step_index=48; + + /* decode nibbles (layout: varies) */ + 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 (assumed) */ + int nibble_shift = + is_stereo ? (!(channel&1) ? 0:4) : (!(i&1) ? 0:4); /* even = low, odd = high */ + + oki4s_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index, &out_sample); + outbuf[sample_count] = (out_sample); + } + + stream->adpcm_history1_32 = hist1; + stream->adpcm_step_index = step_index; +} size_t oki_bytes_to_samples(size_t bytes, int channels) { if (channels <= 0) return 0; diff --git a/src/formats.c b/src/formats.c index 90b68155..ef25a464 100644 --- a/src/formats.c +++ b/src/formats.c @@ -2,7 +2,8 @@ /* Defines the list of accepted extensions. vgmstream doesn't use it internally so it's here - * to inform plugins that need it. Common extensions are commented out to avoid stealing them. */ + * to inform plugins that need it. Common extensions are commented out to avoid stealing them + * and possibly adding an unwanted association to the player. */ /* Some extensions require external libraries and could be #ifdef, not worth. */ @@ -93,6 +94,7 @@ static const char* extension_list[] = { "bik", "bika", "bik2", + //"bin", //common "bk2", "bmdx", "bms", @@ -237,6 +239,7 @@ static const char* extension_list[] = { "laifc", //fake extension for .aifc "lac3", //fake extension for .ac3, FFmpeg/not parsed "lasf", //fake extension for .asf (various) + "lbin", //fake extension for .bin (various) "leg", "lflac", //fake extension for .flac, FFmpeg/not parsed "lin", @@ -688,6 +691,7 @@ static const coding_info coding_info_list[] = { {coding_XMD, "Konami XMD 4-bit ADPCM"}, {coding_PCFX, "PC-FX 4-bit ADPCM"}, {coding_OKI16, "OKI 4-bit ADPCM (16-bit output)"}, + {coding_OKI4S, "OKI 4-bit ADPCM (4-shift)"}, {coding_PTADPCM, "Platinum 4-bit ADPCM"}, {coding_SDX2, "Squareroot-delta-exact (SDX2) 8-bit DPCM"}, @@ -1205,6 +1209,7 @@ static const meta_info meta_info_list[] = { {meta_IMA, "Blitz Games .IMA header"}, {meta_XMV_VALVE, "Valve XMV header"}, {meta_UBI_HX, "Ubisoft HXx header"}, + {meta_BMP_KONAMI, "Konami BMP header"}, }; diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 45305963..405082f6 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -508,6 +508,10 @@ RelativePath=".\meta\bik.c" > + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 2ffb3f89..983f3681 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -256,6 +256,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index b7c91294..b5504418 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -1597,6 +1597,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files diff --git a/src/meta/bmp_konami.c b/src/meta/bmp_konami.c new file mode 100644 index 00000000..95347d3c --- /dev/null +++ b/src/meta/bmp_konami.c @@ -0,0 +1,45 @@ +#include "meta.h" + + +/* BMP - from Jubeat Clan (AC) */ +VGMSTREAM * init_vgmstream_bmp_konami(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int loop_flag, channel_count; + + + /* checks */ + /* .bin: actual extension + * .lbin: for plugins */ + if (!check_extensions(streamFile, "bin,lbin")) + goto fail; + + if (read_32bitBE(0x00,streamFile) != 0x424D5000) /* "BMP\0" "*/ + goto fail; + + channel_count = read_8bit(0x10,streamFile); /* assumed */ + if (channel_count != 2) goto fail; + loop_flag = 0; + start_offset = 0x20; + + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count, loop_flag); + if (!vgmstream) goto fail; + + vgmstream->meta_type = meta_BMP_KONAMI; + + vgmstream->num_samples = read_32bitBE(0x04,streamFile); + vgmstream->sample_rate = read_32bitBE(0x14, streamFile); + + vgmstream->coding_type = coding_OKI4S; + vgmstream->layout_type = layout_none; + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/src/meta/meta.h b/src/meta/meta.h index ebc3fb14..ea962817 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -866,4 +866,6 @@ VGMSTREAM * init_vgmstream_xmv_valve(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ubi_hx(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_bmp_konami(STREAMFILE * streamFile); + #endif /*_META_H*/ diff --git a/src/vgmstream.c b/src/vgmstream.c index 88c7cf50..6b728908 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -478,6 +478,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_nub_is14, init_vgmstream_xmv_valve, init_vgmstream_ubi_hx, + init_vgmstream_bmp_konami, /* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */ init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */ @@ -1150,6 +1151,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_OTNS_IMA: case coding_UBI_IMA: case coding_OKI16: + case coding_OKI4S: return 1; case coding_PCM4: case coding_PCM4_U: @@ -1348,6 +1350,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_BLITZ_IMA: case coding_PCFX: case coding_OKI16: + case coding_OKI4S: return 0x01; case coding_MS_IMA: case coding_RAD_IMA: @@ -2117,6 +2120,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to } break; + case coding_OKI4S: + for (ch = 0; ch < vgmstream->channels; ch++) { + decode_oki4s(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch, + vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch); + } + break; + case coding_UBI_ADPCM: decode_ubi_adpcm(vgmstream, buffer+samples_written*vgmstream->channels, samples_to_do); break; diff --git a/src/vgmstream.h b/src/vgmstream.h index 823a86d2..7b79d3ed 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -164,7 +164,8 @@ typedef enum { coding_DSA, /* Ocean DSA 4-bit ADPCM */ coding_XMD, /* Konami XMD 4-bit ADPCM */ coding_PCFX, /* PC-FX 4-bit ADPCM */ - coding_OKI16, /* OKI 4-bit ADPCM with 16-bit output */ + coding_OKI16, /* OKI 4-bit ADPCM with 16-bit output and modified expand */ + coding_OKI4S, /* OKI 4-bit ADPCM with 16-bit output and cuadruple step */ coding_PTADPCM, /* Platinum 4-bit ADPCM */ /* others */ @@ -712,6 +713,7 @@ typedef enum { meta_IMA, meta_XMV_VALVE, meta_UBI_HX, + meta_BMP_KONAMI, } meta_t;