Add Cricket Audio .cks/ckb [Part Time UFO, Mega Man 1-6 (Android)]

Includes Cricket Audio's MSADPCM variation, also cleaned up MSADPCM code
This commit is contained in:
bnnm 2018-08-02 17:15:09 +02:00
parent 094d95e4de
commit a4f67bf077
10 changed files with 380 additions and 110 deletions

View File

@ -114,7 +114,8 @@ void decode_nwa(NWAData *nwa, sample *outbuf, int32_t samples_to_do);
/* msadpcm_decoder */
void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do);
void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do);
void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
void decode_msadpcm_ck(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
long msadpcm_bytes_to_samples(long bytes, int block_size, int channels);
/* yamaha_decoder */

View File

@ -1,17 +1,15 @@
#include "../util.h"
#include "coding.h"
/* used to compute next scale */
static const int ADPCMTable[16] =
{
static const int msadpcm_steps[16] = {
230, 230, 230, 230,
307, 409, 512, 614,
768, 614, 512, 409,
307, 230, 230, 230
};
static const int ADPCMCoeffs[7][2] =
{
static const int msadpcm_coefs[7][2] = {
{ 256, 0 },
{ 512, -256 },
{ 0, 0 },
@ -23,138 +21,203 @@ static const int ADPCMCoeffs[7][2] =
void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do) {
VGMSTREAMCHANNEL *ch1,*ch2;
int i;
int framesin;
STREAMFILE *streamfile;
off_t offset;
framesin = first_sample/get_vgmstream_samples_per_frame(vgmstream);
first_sample = first_sample%get_vgmstream_samples_per_frame(vgmstream);
int i, frames_in;
size_t bytes_per_frame, samples_per_frame;
off_t frame_offset;
ch1 = &vgmstream->ch[0];
ch2 = &vgmstream->ch[1];
streamfile = ch1->streamfile;
offset = ch1->offset+framesin*get_vgmstream_frame_size(vgmstream);
/* external interleave (variable size), stereo */
bytes_per_frame = get_vgmstream_frame_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
frames_in = first_sample / samples_per_frame;
first_sample = first_sample % samples_per_frame;
frame_offset = ch1->offset + frames_in*bytes_per_frame;
/* parse frame header */
if (first_sample == 0) {
ch1->adpcm_coef[0] = msadpcm_coefs[read_8bit(frame_offset+0x00,streamfile) & 0x07][0];
ch1->adpcm_coef[1] = msadpcm_coefs[read_8bit(frame_offset+0x00,streamfile) & 0x07][1];
ch2->adpcm_coef[0] = msadpcm_coefs[read_8bit(frame_offset+0x01,streamfile)][0];
ch2->adpcm_coef[1] = msadpcm_coefs[read_8bit(frame_offset+0x01,streamfile)][1];
ch1->adpcm_scale = read_16bitLE(frame_offset+0x02,streamfile);
ch2->adpcm_scale = read_16bitLE(frame_offset+0x04,streamfile);
ch1->adpcm_history1_16 = read_16bitLE(frame_offset+0x06,streamfile);
ch2->adpcm_history1_16 = read_16bitLE(frame_offset+0x08,streamfile);
ch1->adpcm_history2_16 = read_16bitLE(frame_offset+0x0a,streamfile);
ch2->adpcm_history2_16 = read_16bitLE(frame_offset+0x0c,streamfile);
}
/* write header samples (needed) */
if (first_sample==0) {
ch1->adpcm_coef[0] = ADPCMCoeffs[read_8bit(offset,streamfile)][0];
ch1->adpcm_coef[1] = ADPCMCoeffs[read_8bit(offset,streamfile)][1];
ch2->adpcm_coef[0] = ADPCMCoeffs[read_8bit(offset+1,streamfile)][0];
ch2->adpcm_coef[1] = ADPCMCoeffs[read_8bit(offset+1,streamfile)][1];
ch1->adpcm_scale = read_16bitLE(offset+2,streamfile);
ch2->adpcm_scale = read_16bitLE(offset+4,streamfile);
ch1->adpcm_history1_16 = read_16bitLE(offset+6,streamfile);
ch2->adpcm_history1_16 = read_16bitLE(offset+8,streamfile);
ch1->adpcm_history2_16 = read_16bitLE(offset+10,streamfile);
ch2->adpcm_history2_16 = read_16bitLE(offset+12,streamfile);
outbuf[0] = ch1->adpcm_history2_16;
outbuf[1] = ch2->adpcm_history2_16;
outbuf+=2;
outbuf += 2;
first_sample++;
samples_to_do--;
}
if (first_sample==1 && samples_to_do > 0) {
if (first_sample == 1 && samples_to_do > 0) {
outbuf[0] = ch1->adpcm_history1_16;
outbuf[1] = ch2->adpcm_history1_16;
outbuf+=2;
outbuf += 2;
first_sample++;
samples_to_do--;
}
for (i=first_sample; i<first_sample+samples_to_do; i++) {
int j;
/* decode nibbles */
for (i = first_sample; i < first_sample+samples_to_do; i++) {
int ch;
for (j=0;j<2;j++)
{
VGMSTREAMCHANNEL *ch = &vgmstream->ch[j];
int sample_nibble =
(j == 0 ?
get_high_nibble_signed(read_8bit(offset+14+i-2,streamfile)) :
get_low_nibble_signed(read_8bit(offset+14+i-2,streamfile))
);
int32_t hist1,hist2;
int32_t predicted;
for (ch = 0; ch < 2; ch++) {
VGMSTREAMCHANNEL *stream = &vgmstream->ch[ch];
int32_t hist1,hist2, predicted;
int sample_nibble = (ch == 0) ? /* L = high nibble first */
get_high_nibble_signed(read_8bit(frame_offset+0x07*2+(i-2),streamfile)) :
get_low_nibble_signed (read_8bit(frame_offset+0x07*2+(i-2),streamfile));
hist1 = ch->adpcm_history1_16;
hist2 = ch->adpcm_history2_16;
predicted = hist1 * ch->adpcm_coef[0] + hist2 * ch->adpcm_coef[1];
predicted /= 256;
predicted += sample_nibble*ch->adpcm_scale;
hist1 = stream->adpcm_history1_16;
hist2 = stream->adpcm_history2_16;
predicted = hist1*stream->adpcm_coef[0] + hist2*stream->adpcm_coef[1];
predicted = predicted / 256;
predicted = predicted + sample_nibble*stream->adpcm_scale;
outbuf[0] = clamp16(predicted);
ch->adpcm_history2_16 = ch->adpcm_history1_16;
ch->adpcm_history1_16 = outbuf[0];
ch->adpcm_scale = (ADPCMTable[sample_nibble&0xf] *
ch->adpcm_scale) / 256;
if (ch->adpcm_scale < 0x10) ch->adpcm_scale = 0x10;
stream->adpcm_history2_16 = stream->adpcm_history1_16;
stream->adpcm_history1_16 = outbuf[0];
stream->adpcm_scale = (msadpcm_steps[sample_nibble & 0xf] * stream->adpcm_scale) / 256;
if (stream->adpcm_scale < 0x10)
stream->adpcm_scale = 0x10;
outbuf++;
}
}
}
void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do) {
VGMSTREAMCHANNEL *ch1;
int i;
int framesin;
STREAMFILE *streamfile;
off_t offset;
void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
VGMSTREAMCHANNEL *stream = &vgmstream->ch[channel];
int i, frames_in;
size_t bytes_per_frame, samples_per_frame;
off_t frame_offset;
framesin = first_sample/get_vgmstream_samples_per_frame(vgmstream);
first_sample = first_sample%get_vgmstream_samples_per_frame(vgmstream);
/* external interleave (variable size), mono */
bytes_per_frame = get_vgmstream_frame_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
frames_in = first_sample / samples_per_frame;
first_sample = first_sample % samples_per_frame;
ch1 = &vgmstream->ch[0];
streamfile = ch1->streamfile;
offset = ch1->offset+framesin*get_vgmstream_frame_size(vgmstream);
frame_offset = stream->offset + frames_in*bytes_per_frame;
if (first_sample==0) {
ch1->adpcm_coef[0] = ADPCMCoeffs[read_8bit(offset,streamfile)][0];
ch1->adpcm_coef[1] = ADPCMCoeffs[read_8bit(offset,streamfile)][1];
ch1->adpcm_scale = read_16bitLE(offset+1,streamfile);
ch1->adpcm_history1_16 = read_16bitLE(offset+3,streamfile);
ch1->adpcm_history2_16 = read_16bitLE(offset+5,streamfile);
/* parse frame header */
if (first_sample == 0) {
stream->adpcm_coef[0] = msadpcm_coefs[read_8bit(frame_offset+0x00,stream->streamfile) & 0x07][0];
stream->adpcm_coef[1] = msadpcm_coefs[read_8bit(frame_offset+0x00,stream->streamfile) & 0x07][1];
stream->adpcm_scale = read_16bitLE(frame_offset+0x01,stream->streamfile);
stream->adpcm_history1_16 = read_16bitLE(frame_offset+0x03,stream->streamfile);
stream->adpcm_history2_16 = read_16bitLE(frame_offset+0x05,stream->streamfile);
}
outbuf[0] = ch1->adpcm_history2_16;
outbuf++;
/* write header samples (needed) */
if (first_sample == 0) {
outbuf[0] = stream->adpcm_history2_16;
outbuf += channelspacing;
first_sample++;
samples_to_do--;
}
if (first_sample==1 && samples_to_do > 0) {
outbuf[0] = ch1->adpcm_history1_16;
outbuf++;
if (first_sample == 1 && samples_to_do > 0) {
outbuf[0] = stream->adpcm_history1_16;
outbuf += channelspacing;
first_sample++;
samples_to_do--;
}
for (i=first_sample; i<first_sample+samples_to_do; i++) {
{
VGMSTREAMCHANNEL *ch = &vgmstream->ch[0];
int sample_nibble =
(i & 1 ?
get_low_nibble_signed(read_8bit(offset+7+(i-2)/2,streamfile)) :
get_high_nibble_signed(read_8bit(offset+7+(i-2)/2,streamfile))
);
int32_t hist1,hist2;
int32_t predicted;
/* decode nibbles */
for (i = first_sample; i < first_sample+samples_to_do; i++) {
int32_t hist1,hist2, predicted;
int sample_nibble = (i & 1) ? /* high nibble first */
get_low_nibble_signed (read_8bit(frame_offset+0x07+(i-2)/2,stream->streamfile)) :
get_high_nibble_signed(read_8bit(frame_offset+0x07+(i-2)/2,stream->streamfile));
hist1 = ch->adpcm_history1_16;
hist2 = ch->adpcm_history2_16;
predicted = hist1 * ch->adpcm_coef[0] + hist2 * ch->adpcm_coef[1];
predicted /= 256;
predicted += sample_nibble*ch->adpcm_scale;
outbuf[0] = clamp16(predicted);
ch->adpcm_history2_16 = ch->adpcm_history1_16;
ch->adpcm_history1_16 = outbuf[0];
ch->adpcm_scale = (ADPCMTable[sample_nibble&0xf] *
ch->adpcm_scale) / 256;
if (ch->adpcm_scale < 0x10) ch->adpcm_scale = 0x10;
hist1 = stream->adpcm_history1_16;
hist2 = stream->adpcm_history2_16;
predicted = hist1*stream->adpcm_coef[0] + hist2*stream->adpcm_coef[1];
predicted = predicted / 256;
predicted = predicted + sample_nibble*stream->adpcm_scale;
outbuf[0] = clamp16(predicted);
outbuf++;
}
stream->adpcm_history2_16 = stream->adpcm_history1_16;
stream->adpcm_history1_16 = outbuf[0];
stream->adpcm_scale = (msadpcm_steps[sample_nibble & 0xf] * stream->adpcm_scale) / 256;
if (stream->adpcm_scale < 0x10)
stream->adpcm_scale = 0x10;
outbuf += channelspacing;
}
}
/* Cricket Audio's MSADPCM, same thing with reversed hist and nibble order
* (their tools may convert to float/others but internally it's all PCM16, from debugging). */
void decode_msadpcm_ck(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
VGMSTREAMCHANNEL *stream = &vgmstream->ch[channel];
int i, frames_in;
size_t bytes_per_frame, samples_per_frame;
off_t frame_offset;
/* external interleave (variable size), mono */
bytes_per_frame = get_vgmstream_frame_size(vgmstream);
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
frames_in = first_sample / samples_per_frame;
first_sample = first_sample % samples_per_frame;
frame_offset = stream->offset + frames_in*bytes_per_frame;
/* parse frame header */
if (first_sample == 0) {
stream->adpcm_coef[0] = msadpcm_coefs[read_8bit(frame_offset+0x00,stream->streamfile) & 0x07][0];
stream->adpcm_coef[1] = msadpcm_coefs[read_8bit(frame_offset+0x00,stream->streamfile) & 0x07][1];
stream->adpcm_scale = read_16bitLE(frame_offset+0x01,stream->streamfile);
stream->adpcm_history2_16 = read_16bitLE(frame_offset+0x03,stream->streamfile); /* hist2 first, unlike normal MSADPCM */
stream->adpcm_history1_16 = read_16bitLE(frame_offset+0x05,stream->streamfile);
}
/* write header samples (needed) */
if (first_sample == 0) {
outbuf[0] = stream->adpcm_history2_16;
outbuf += channelspacing;
first_sample++;
samples_to_do--;
}
if (first_sample == 1 && samples_to_do > 0) {
outbuf[0] = stream->adpcm_history1_16;
outbuf += channelspacing;
first_sample++;
samples_to_do--;
}
/* decode nibbles */
for (i = first_sample; i < first_sample+samples_to_do; i++) {
int32_t hist1,hist2, predicted;
int sample_nibble = (i & 1) ? /* low nibble first, unlike normal MSADPCM */
get_high_nibble_signed (read_8bit(frame_offset+0x07+(i-2)/2,stream->streamfile)) :
get_low_nibble_signed(read_8bit(frame_offset+0x07+(i-2)/2,stream->streamfile));
hist1 = stream->adpcm_history1_16;
hist2 = stream->adpcm_history2_16;
predicted = hist1*stream->adpcm_coef[0] + hist2*stream->adpcm_coef[1];
predicted = predicted >> 8; /* probably no difference vs MSADPCM */
predicted = predicted + sample_nibble*stream->adpcm_scale;
outbuf[0] = clamp16(predicted);
stream->adpcm_history2_16 = stream->adpcm_history1_16;
stream->adpcm_history1_16 = outbuf[0];
stream->adpcm_scale = (msadpcm_steps[sample_nibble & 0xf] * stream->adpcm_scale) >> 8;
if (stream->adpcm_scale < 0x10)
stream->adpcm_scale = 0x10;
outbuf += channelspacing;
}
}

View File

@ -4,7 +4,7 @@
/* 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. */
/* some extensions require external libraries and could be #ifdef, no really needed */
/* some extensions require external libraries and could be #ifdef, not really needed */
/* some formats marked as "not parsed" mean they'll go through FFmpeg, the header/extension is not parsed */
@ -98,7 +98,9 @@ static const char* extension_list[] = {
"ccc",
"cd",
"cfn", //fake extension/header id for .caf (to be removed)
"ckb",
"ckd",
"cks",
"cnk",
"cps",
"cvs",
@ -543,6 +545,7 @@ static const coding_info coding_info_list[] = {
{coding_UBI_IMA, "Ubisoft 4-bit IMA ADPCM"},
{coding_MSADPCM, "Microsoft 4-bit ADPCM"},
{coding_MSADPCM_ck, "Microsoft 4-bit ADPCM (Cricket Audio)"},
{coding_WS, "Westwood Studios VBR ADPCM"},
{coding_AICA, "Yamaha AICA 4-bit ADPCM"},
{coding_AICA_int, "Yamaha AICA 4-bit ADPCM (mono/interleave)"},
@ -1045,6 +1048,8 @@ static const meta_info meta_info_list[] = {
{meta_OGG_MUS, "Ogg Vorbis (MUS header)"},
{meta_ASF, "Argonaut ASF header"},
{meta_XMD, "Konami XMD header"},
{meta_CKS, "Cricket Audio CKS header"},
{meta_CKB, "Cricket Audio CKB header"},
#ifdef VGM_USE_FFMPEG
{meta_FFmpeg, "FFmpeg supported file format"},

View File

@ -356,6 +356,10 @@
RelativePath=".\meta\capdsp.c"
>
</File>
<File
RelativePath=".\meta\ck.c"
>
</File>
<File
RelativePath=".\meta\cstr.c"
>

View File

@ -207,6 +207,7 @@
<ClCompile Include="meta\brstm.c" />
<ClCompile Include="meta\btsnd.c" />
<ClCompile Include="meta\capdsp.c" />
<ClCompile Include="meta\ck.c" />
<ClCompile Include="meta\cstr.c" />
<ClCompile Include="meta\dc_asd.c" />
<ClCompile Include="meta\dc_dcsw_dcs.c" />

View File

@ -214,6 +214,9 @@
<ClCompile Include="meta\capdsp.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ck.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\cstr.c">
<Filter>meta\Source Files</Filter>
</ClCompile>

177
src/meta/ck.c Normal file
View File

@ -0,0 +1,177 @@
#include "meta.h"
/* .cks - Cricket Audio stream [Part Time UFO (Android), Mega Man 1-6 (Android)] */
VGMSTREAM * init_vgmstream_cks(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, codec, sample_rate;
int32_t num_samples, loop_start, loop_end;
size_t block_size;
/* checks */
if (!check_extensions(streamFile, "cks"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x636B6D6B) /* "ckmk" */
goto fail;
/* 0x04(4): platform bitflags (from LSB: iOS, Android, OS X, Windows, WP8, Linux, tvOS, undefined/ignored) */
if (read_32bitLE(0x08,streamFile) != 0x00) /* expected file type (0x00: stream, 0x01: bank, 0x02+: unknown) */
goto fail;
if (read_32bitLE(0x0c,streamFile) != 0x02) /* file version (always 0x02) */
goto fail;
codec = read_8bit(0x10,streamFile);
channel_count = read_8bit(0x11,streamFile);
sample_rate = (uint16_t)read_16bitLE(0x12,streamFile);
num_samples = read_32bitLE(0x14,streamFile) * read_16bitLE(0x1a,streamFile); /* number_of_blocks * samples_per_frame */
block_size = read_16bitLE(0x18,streamFile);
/* 0x1c(2): volume */
/* 0x1e(2): pan */
loop_start = read_32bitLE(0x20,streamFile);
loop_end = read_32bitLE(0x24,streamFile);
loop_flag = read_16bitLE(0x28,streamFile) != 0; /* loop count (-1 = forever) */
/* 0x2a(2): unused? */
start_offset = 0x2c;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->meta_type = meta_CKS;
switch(codec) {
case 0x00: /* pcm16 [from tests] */
vgmstream->coding_type = coding_PCM16LE;
break;
case 0x01: /* pcm8 [from tests] */
vgmstream->coding_type = coding_PCM8;
break;
case 0x02: /* adpcm [Part Time UFO (Android), Mega Man 1-6 (Android)] */
vgmstream->coding_type = coding_MSADPCM_ck;
/* frame_size is always 0x18 */
break;
default:
goto fail;
}
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = block_size / channel_count;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* .ckb - Cricket Audio bank [Fire Emblem Heroes (Android), Mega Man 1-6 (Android)] */
VGMSTREAM * init_vgmstream_ckb(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, name_offset = 0;
int loop_flag, channel_count, codec, sample_rate;
int32_t num_samples, loop_start, loop_end;
size_t block_size, stream_size;
int total_subsongs, target_subsong = streamFile->stream_index;
/* checks */
if (!check_extensions(streamFile, "ckb"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x636B6D6B) /* "ckmk" */
goto fail;
/* 0x04(4): platform bitflags (from LSB: iOS, Android, OS X, Windows, WP8, Linux, tvOS, undefined/ignored) */
if (read_32bitLE(0x08,streamFile) != 0x01) /* expected file type (0x00: stream, 0x01: bank, 0x02+: unknown) */
goto fail;
if (read_32bitLE(0x0c,streamFile) != 0x02) /* file version (always 0x02) */
goto fail;
/* 0x10: bank name (size 0x1c+1) */
/* 0x30/34: reserved? */
total_subsongs = read_32bitLE(0x38,streamFile);
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
/* 0x3c: total_subsongs again? (ignored) */
/* 0x40/44: unknown (ignored) */
/* get subsong (stream offset isn't given so must calc manually) */
{
int i;
off_t header_offset = 0x48;
off_t stream_offset = 0x48 + total_subsongs*0x48;
for (i = 0; i < total_subsongs; i++) {
name_offset = header_offset+0x00; /* stream name (size 0x1c+1) */
codec = read_8bit(header_offset+0x20,streamFile);
channel_count = read_8bit(header_offset+0x21,streamFile);
sample_rate = (uint16_t)read_16bitLE(header_offset+0x22,streamFile);
num_samples = read_32bitLE(header_offset+0x24,streamFile) * read_16bitLE(header_offset+0x2a,streamFile); /* number_of_blocks * samples_per_frame */
block_size = read_16bitLE(header_offset+0x28,streamFile);
/* 0x2c(2): volume */
/* 0x2e(2): pan */
loop_start = read_32bitLE(header_offset+0x30,streamFile);
loop_end = read_32bitLE(header_offset+0x34,streamFile);
loop_flag = read_16bitLE(header_offset+0x38,streamFile) != 0; /* loop count (-1 = forever) */
/* 0x3a(2): unused? */
stream_size = read_32bitLE(header_offset+0x3c,streamFile);
/* 0x40/44(4): unused? */
if (target_subsong == (i+1))
break;
header_offset += 0x48;
stream_offset += stream_size;
}
start_offset = stream_offset;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
read_string(vgmstream->stream_name,0x1c+1, name_offset,streamFile);
vgmstream->meta_type = meta_CKB;
switch(codec) {
case 0x00: /* pcm16 [Mega Man 1-6 (Android)] */
vgmstream->coding_type = coding_PCM16LE;
break;
case 0x01: /* pcm8 */
vgmstream->coding_type = coding_PCM8;
break;
case 0x02: /* adpcm [Fire Emblem Heroes (Android)] */
vgmstream->coding_type = coding_MSADPCM_ck;
/* frame_size is always 0x18 */
break;
default:
goto fail;
}
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = block_size / channel_count;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -767,4 +767,7 @@ VGMSTREAM * init_vgmstream_asf(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_xmd(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_cks(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ckb(STREAMFILE *streamFile);
#endif /*_META_H*/

View File

@ -420,10 +420,12 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_ps2_ads_container,
init_vgmstream_asf,
init_vgmstream_xmd,
init_vgmstream_cks,
init_vgmstream_ckb,
init_vgmstream_txth, /* should go at the end (lower priority) */
#ifdef VGM_USE_FFMPEG
init_vgmstream_ffmpeg, /* should go at the end */
init_vgmstream_ffmpeg, /* should go at the end (lowest priority) */
#endif
};
@ -1099,7 +1101,9 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
return 128;
case coding_MSADPCM:
return (vgmstream->interleave_block_size-(7-1)*vgmstream->channels)*2/vgmstream->channels;
return (vgmstream->interleave_block_size - 0x07*vgmstream->channels)*2 / vgmstream->channels + 2;
case coding_MSADPCM_ck:
return (vgmstream->interleave_block_size - 0x07)*2 + 2;
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:
@ -1269,6 +1273,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
return 0x4c*vgmstream->channels;
case coding_MSADPCM:
case coding_MSADPCM_ck:
return vgmstream->interleave_block_size;
case coding_WS:
return vgmstream->current_block_size;
@ -1846,17 +1851,21 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
break;
case coding_MSADPCM:
if (vgmstream->channels == 2) {
decode_msadpcm_stereo(vgmstream,
buffer+samples_written*vgmstream->channels,
decode_msadpcm_stereo(vgmstream,buffer+samples_written*vgmstream->channels,
vgmstream->samples_into_block,
samples_to_do);
}
else if (vgmstream->channels == 1)
{
decode_msadpcm_mono(vgmstream,
buffer+samples_written*vgmstream->channels,
vgmstream->samples_into_block,
samples_to_do);
else if (vgmstream->channels == 1) {
decode_msadpcm_mono(vgmstream,buffer+samples_written*vgmstream->channels,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do,0);
}
break;
case coding_MSADPCM_ck:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_msadpcm_ck(vgmstream,buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do, chan);
}
break;
case coding_AICA:
@ -2224,6 +2233,7 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
if (vgmstream->layout_type == layout_none && vgmstream->interleave_block_size > 0) {
switch (vgmstream->coding_type) {
case coding_MSADPCM:
case coding_MSADPCM_ck:
case coding_MS_IMA:
case coding_MC3:
case coding_WWISE_IMA:

View File

@ -141,7 +141,8 @@ typedef enum {
coding_AWC_IMA, /* Rockstar AWC IMA ADPCM */
coding_UBI_IMA, /* Ubisoft IMA ADPCM */
coding_MSADPCM, /* Microsoft ADPCM */
coding_MSADPCM, /* Microsoft ADPCM (stereo/mono) */
coding_MSADPCM_ck, /* Microsoft ADPCM (Cricket Audio variation) */
coding_WS, /* Westwood Studios VBR ADPCM */
coding_AICA, /* Yamaha AICA ADPCM (stereo) */
coding_AICA_int, /* Yamaha AICA ADPCM (mono/interleave) */
@ -685,6 +686,8 @@ typedef enum {
meta_OGG_MUS, /* Ogg Vorbis with encryption [Redux - Dark Matters (PC)] */
meta_ASF, /* Argonaut ASF [Croc 2 (PC)] */
meta_XMD, /* Konami XMD [Silent Hill 4 (Xbox), Castlevania: Curse of Darkness (Xbox)] */
meta_CKS, /* Cricket Audio stream [Part Time UFO (Android), Mega Man 1-6 (Android)] */
meta_CKB, /* Cricket Audio bank [Fire Emblem Heroes (Android), Mega Man 1-6 (Android)] */
#ifdef VGM_USE_FFMPEG
meta_FFmpeg,