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;