mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-31 04:13:47 +01:00
Add VADPCM for AIFC + .n64 SDK/src samples
This commit is contained in:
parent
12c0908667
commit
60b2ecc21d
@ -61,6 +61,11 @@ void decode_ngc_dtk(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspaci
|
||||
/* ngc_afc_decoder */
|
||||
void decode_ngc_afc(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
/* vadpcm_decoder */
|
||||
void decode_vadpcm(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int order);
|
||||
//int32_t vadpcm_bytes_to_samples(size_t bytes, int channels);
|
||||
void vadpcm_read_coefs_be(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t offset, int order, int entries, int ch);
|
||||
|
||||
/* pcm_decoder */
|
||||
void decode_pcm16le(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm16be(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
155
src/coding/vadpcm_decoder.c
Normal file
155
src/coding/vadpcm_decoder.c
Normal file
@ -0,0 +1,155 @@
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
|
||||
/* Decodes Silicon Graphics' N64 VADPCM, big brother of GC ADPCM.
|
||||
* Has external coefs like DSP, but allows tables up to 8 groups of 8 coefs (code book) and also
|
||||
* up to 8 history samples (order). In practice order must be 2, while files use 2~4 tables, so it
|
||||
* ends up being an overcomplex XA. Code respects this quirky configurable hist for doc purposes though.
|
||||
*
|
||||
* This code is based on N64SoundListTool decoding (by Ice Mario), with bits of the official SDK vadpcm tool
|
||||
* decompilation. I can't get proper sound from the later though, so not too sure about accuracy of this
|
||||
* implementation. Output sounds correct though.
|
||||
*/
|
||||
|
||||
void decode_vadpcm(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int order) {
|
||||
uint8_t frame[0x09] = {0};
|
||||
off_t frame_offset;
|
||||
int frames_in, sample_count = 0;
|
||||
size_t bytes_per_frame, samples_per_frame;
|
||||
int i, j, k, o;
|
||||
int scale, index;
|
||||
|
||||
int codes[16]; /* AKA ix */
|
||||
int16_t hist[8] = {0};
|
||||
int16_t out[16];
|
||||
int16_t* coefs;
|
||||
|
||||
|
||||
VGM_ASSERT_ONCE(order != 2, "VADPCM: wrong order=%i\n", order);
|
||||
if (order != 2) /* only 2 allowed "in the current implementation" */
|
||||
order = 2;
|
||||
|
||||
/* up to 8 (hist[0]=oldest) but only uses latest 2 (order=2), so we don't save the whole thing ATM */
|
||||
hist[6] = stream->adpcm_history2_16;
|
||||
hist[7] = stream->adpcm_history1_16;
|
||||
|
||||
|
||||
/* external interleave (fixed size), mono */
|
||||
bytes_per_frame = 0x09;
|
||||
samples_per_frame = (bytes_per_frame - 0x01) * 2; /* always 16 */
|
||||
frames_in = first_sample / samples_per_frame;
|
||||
first_sample = first_sample % samples_per_frame;
|
||||
|
||||
/* parse frame header */
|
||||
frame_offset = stream->offset + bytes_per_frame * frames_in;
|
||||
read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */
|
||||
scale = (frame[0] >> 4) & 0xF;
|
||||
index = (frame[0] >> 0) & 0xF;
|
||||
|
||||
scale = 1 << scale;
|
||||
|
||||
VGM_ASSERT_ONCE(index > 8, "DSP: incorrect index at %x\n", (uint32_t)frame_offset);
|
||||
if (index > 8) /* assumed */
|
||||
index = 8;
|
||||
coefs = &stream->vadpcm_coefs[index * (order*8) + 0];
|
||||
|
||||
|
||||
/* read and pre-scale all nibbles, since groups of 8 are needed */
|
||||
for (i = 0, j = 0; i < 16; i += 2, j++) {
|
||||
int n0 = (frame[j+1] >> 4) & 0xF;
|
||||
int n1 = (frame[j+1] >> 0) & 0xF;
|
||||
|
||||
/* sign extend */
|
||||
if (n0 & 8)
|
||||
n0 = n0 - 16;
|
||||
if (n1 & 8)
|
||||
n1 = n1 - 16;
|
||||
|
||||
codes[i+0] = n0 * scale;
|
||||
codes[i+1] = n1 * scale;
|
||||
}
|
||||
|
||||
/* decode 2 sub-frames of 8 samples (maybe like this since N64 MIPS has registers to spare?) */
|
||||
for (j = 0; j < 2; j++) {
|
||||
/* SDK dec code and N64ST copy 8 codes to a tmp buf and has some complex logic to move out buf
|
||||
* around, but since that's useless N64 asm would be much more optimized... hopefully */
|
||||
int* sf_codes = &codes[j*8];
|
||||
int16_t* sf_out = &out[j*8];
|
||||
|
||||
/* works with 8 samples at a time, related in twisted ways */
|
||||
for( i = 0; i < 8; i++) {
|
||||
int sample, delta = 0;
|
||||
|
||||
/* in practice: delta = coefs[0][i] * hist[6] + coefs[1][i] * hist[7],
|
||||
* much like XA's coef1*hist1 + coef2*hist2 but with multi coefs */
|
||||
for (o = 0; o < order; o++) {
|
||||
delta += coefs[o*8 + i] * hist[(8 - order) + o];
|
||||
}
|
||||
|
||||
/* adds all previous samples */
|
||||
for (k = i-1; k > -1; k--) {
|
||||
for (o = 1; o < order; o++) { /* assumed, since only goes coefs[1][k] */
|
||||
delta += sf_codes[(i-1) - k] * coefs[(o*8) + k];
|
||||
}
|
||||
}
|
||||
|
||||
/* scale-filter thing (also seen in DSP) */
|
||||
sample = (sf_codes[i] << 11);
|
||||
sample = (sample + delta) >> 11;
|
||||
if (sample > 32767)
|
||||
sample = 32767;
|
||||
else if (sample < -32768)
|
||||
sample = -32768;
|
||||
|
||||
sf_out[i] = sample;
|
||||
}
|
||||
|
||||
/* save subframe hist */
|
||||
for (i = 8 - order; i < 8; i++) {
|
||||
hist[i] = sf_out[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* copy samples last, since the whole thing is kinda complex to worry about half copying and stuff */
|
||||
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
||||
outbuf[sample_count] = out[i];
|
||||
sample_count += channelspacing;
|
||||
}
|
||||
|
||||
/* update hist once all frame is actually copied */
|
||||
if (first_sample + sample_count == samples_per_frame) {
|
||||
stream->adpcm_history2_16 = hist[6];
|
||||
stream->adpcm_history1_16 = hist[7];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
int32_t vadpcm_bytes_to_samples(size_t bytes, int channels) {
|
||||
if (channels <= 0) return 0;
|
||||
return bytes / channels / 0x09 * 16;
|
||||
}
|
||||
*/
|
||||
|
||||
/* Reads code book, linearly unlike original SDK, that does some strange reordering and pre-scaling
|
||||
* to reduce some loops. Format is 8 coefs per 'order' per 'entries' (max 8, but order is always 2). So:
|
||||
* - i: table index (selectable filter tables on every decoded frame)
|
||||
* - j: order index (coefs for prev N hist samples)
|
||||
* - k: coef index (multiplication coefficient for 8 samples in a sub-frame)
|
||||
* coefs[i * (order*8) + j * 8 + k * order] = coefs[i][j][k] */
|
||||
void vadpcm_read_coefs_be(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t offset, int order, int entries, int ch) {
|
||||
int i;
|
||||
|
||||
if (entries > 8)
|
||||
entries = 8;
|
||||
VGM_ASSERT(order != 2, "VADPCM: wrong order %i found\n", order);
|
||||
if (order != 2)
|
||||
order = 2;
|
||||
|
||||
/* assumes all channels use same coefs, never seen non-mono files */
|
||||
for (i = 0; i < entries * order * 8; i++) {
|
||||
vgmstream->ch[ch].vadpcm_coefs[i] = read_s16be(offset + i*2, sf);
|
||||
}
|
||||
vgmstream->codec_config = order;
|
||||
}
|
@ -330,6 +330,7 @@ static const char* extension_list[] = {
|
||||
"mxst",
|
||||
"myspd",
|
||||
|
||||
"n64",
|
||||
"naac",
|
||||
"ndp",
|
||||
"ngca",
|
||||
@ -685,6 +686,7 @@ static const coding_info coding_info_list[] = {
|
||||
{coding_NGC_DSP_subint, "Nintendo DSP 4-bit ADPCM (subinterleave)"},
|
||||
{coding_NGC_DTK, "Nintendo DTK 4-bit ADPCM"},
|
||||
{coding_NGC_AFC, "Nintendo AFC 4-bit ADPCM"},
|
||||
{coding_VADPCM, "Silicon Graphics VADPCM 4-bit ADPCM"},
|
||||
|
||||
{coding_G721, "CCITT G.721 4-bit ADPCM"},
|
||||
|
||||
|
@ -2197,6 +2197,10 @@
|
||||
<File
|
||||
RelativePath=".\coding\ubi_adpcm_decoder.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\vadpcm_decoder.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\ws_decoder.c"
|
||||
|
@ -605,6 +605,7 @@
|
||||
<ClCompile Include="coding\sassc_decoder.c" />
|
||||
<ClCompile Include="coding\sdx2_decoder.c" />
|
||||
<ClCompile Include="coding\ubi_adpcm_decoder.c" />
|
||||
<ClCompile Include="coding\vadpcm_decoder.c" />
|
||||
<ClCompile Include="coding\vorbis_custom_decoder.c" />
|
||||
<ClCompile Include="coding\vorbis_custom_utils_fsb.c" />
|
||||
<ClCompile Include="coding\vorbis_custom_utils_ogl.c" />
|
||||
|
@ -1309,6 +1309,9 @@
|
||||
<ClCompile Include="coding\ubi_adpcm_decoder.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\vadpcm_decoder.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\ws_decoder.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
121
src/meta/aifc.c
121
src/meta/aifc.c
@ -3,7 +3,8 @@
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* for reading integers inexplicably packed into 80-bit ('double extended') floats */
|
||||
/* for reading integers inexplicably packed into 80-bit ('double extended') floats, AKA:
|
||||
* "80 bit IEEE Standard 754 floating point number (Standard AppleNumeric Environment [SANE] data type Extended)" */
|
||||
static uint32_t read_f80be(off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[0x0a];
|
||||
int32_t exponent;
|
||||
@ -49,14 +50,27 @@ static uint32_t find_marker(STREAMFILE* sf, off_t mark_offset, int marker_id) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int is_str(const char* str, int len, off_t offset, STREAMFILE* sf) {
|
||||
uint8_t buf[0x100];
|
||||
|
||||
/* AIFF/AIFF-C (Audio Interchange File Format) - Apple format, from Mac/3DO/other games */
|
||||
if (len == 0)
|
||||
len = strlen(str);
|
||||
|
||||
if (len > sizeof(buf))
|
||||
return 0;
|
||||
if (read_streamfile(buf, offset, len, sf) != len)
|
||||
return 0;
|
||||
return memcmp(buf, str, len) == 0; /* memcmp to allow "AB\0\0" */
|
||||
}
|
||||
|
||||
|
||||
/* AIFF/AIFF-C (Audio Interchange File Format - Compressed) - Apple format, from Mac/3DO/other games */
|
||||
VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset = 0;
|
||||
off_t start_offset = 0, coef_offset = 0;
|
||||
size_t file_size;
|
||||
coding_t coding_type = 0;
|
||||
int channel_count = 0, sample_count = 0, sample_size = 0, sample_rate = 0;
|
||||
int channels = 0, sample_count = 0, sample_size = 0, sample_rate = 0;
|
||||
int interleave = 0;
|
||||
int loop_flag = 0;
|
||||
int32_t loop_start = 0, loop_end = 0;
|
||||
@ -76,12 +90,13 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
|
||||
* .adp: Sonic Jam (SAT)
|
||||
* .ai: Dragon Force (SAT)
|
||||
* (extensionless: Doom (3DO)
|
||||
* .fda: Homeworld 2 (PC) */
|
||||
* .fda: Homeworld 2 (PC)
|
||||
* .n64: Turok (N64) src */
|
||||
if (check_extensions(sf, "aif,laif,")) {
|
||||
is_aifc_ext = 1;
|
||||
is_aiff_ext = 1;
|
||||
}
|
||||
else if (check_extensions(sf, "aifc,laifc,aifcl,afc,cbd2,bgm,fda")) {
|
||||
else if (check_extensions(sf, "aifc,laifc,aifcl,afc,cbd2,bgm,fda,n64")) {
|
||||
is_aifc_ext = 1;
|
||||
}
|
||||
else if (check_extensions(sf, "aiff,laiff,acm,adp,ai,aiffl")) {
|
||||
@ -96,6 +111,8 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
|
||||
read_u32be(0x04,sf)+0x08 != file_size)
|
||||
goto fail;
|
||||
|
||||
/* AIFF originally allowed only PCM (non-compressed) audio, so newer AIFC was added,
|
||||
* though some AIFF with other codecs exist */
|
||||
if (read_u32be(0x08,sf) == 0x41494643) { /* "AIFC" */
|
||||
if (!is_aifc_ext) goto fail;
|
||||
is_aifc = 1;
|
||||
@ -127,14 +144,13 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
|
||||
goto fail;
|
||||
|
||||
switch(chunk_type) {
|
||||
case 0x46564552: /* "FVER" (version info) */
|
||||
case 0x46564552: /* "FVER" (version info, required) */
|
||||
if (fver_found) goto fail;
|
||||
if (is_aiff) goto fail; /* plain AIFF shouldn't have */
|
||||
fver_found = 1;
|
||||
|
||||
/* specific size */
|
||||
if (chunk_size != 4) goto fail;
|
||||
|
||||
if (chunk_size != 4)
|
||||
goto fail;
|
||||
/* Version 1 of AIFF-C spec timestamp */
|
||||
if (read_u32be(offset + 0x00,sf) != 0xA2805140)
|
||||
goto fail;
|
||||
@ -144,44 +160,46 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
|
||||
if (comm_found) goto fail;
|
||||
comm_found = 1;
|
||||
|
||||
channel_count = read_u16be(offset + 0x00,sf);
|
||||
if (channel_count <= 0) goto fail;
|
||||
channels = read_u16be(offset + 0x00,sf);
|
||||
if (channels <= 0) goto fail;
|
||||
|
||||
sample_count = read_u32be(offset + 0x02,sf); /* sometimes number of blocks */
|
||||
sample_count = read_u32be(offset + 0x02,sf); /* sample_frames in theory, depends on codec */
|
||||
sample_size = read_u16be(offset + 0x06,sf);
|
||||
sample_rate = read_f80be(offset + 0x08,sf);
|
||||
|
||||
if (is_aifc) {
|
||||
uint32_t codec = read_u32be(offset + 0x12,sf);
|
||||
/* followed by "pascal string": name size + human-readable name (full count padded to even size) */
|
||||
|
||||
switch (codec) {
|
||||
case 0x53445832: /* "SDX2" [3DO games: Super Street Fighter II Turbo (3DO), etc] */
|
||||
/* "2:1 Squareroot-Delta-Exact compression" */
|
||||
coding_type = coding_SDX2;
|
||||
interleave = 0x01;
|
||||
break;
|
||||
|
||||
case 0x43424432: /* "CBD2" [M2 (arcade 3DO) games: IMSA Racing (M2), etc] */
|
||||
/* "2:1 Cuberoot-Delta-Exact compression" */
|
||||
coding_type = coding_CBD2;
|
||||
interleave = 0x01;
|
||||
break;
|
||||
|
||||
case 0x41445034: /* "ADP4" */
|
||||
coding_type = coding_DVI_IMA_int;
|
||||
if (channel_count != 1) break; /* don't know how stereo DVI is laid out */
|
||||
if (channels != 1) break; /* don't know how stereo DVI is laid out */
|
||||
break;
|
||||
|
||||
case 0x696D6134: /* "ima4" [Alida (PC), Lunar SSS (iOS)] */
|
||||
/* "IMA 4:1FLLR" */
|
||||
coding_type = coding_APPLE_IMA4;
|
||||
interleave = 0x22;
|
||||
sample_count = sample_count * ((interleave-0x2)*2);
|
||||
break;
|
||||
|
||||
case 0x434F4D50: { /* "COMP" (generic compression) */
|
||||
uint8_t comp_name[255] = {0};
|
||||
uint8_t comp_size = read_u8(offset + 0x16, sf);
|
||||
if (comp_size >= sizeof(comp_name) - 1) goto fail;
|
||||
|
||||
read_streamfile(comp_name, offset + 0x17, comp_size, sf);
|
||||
if (memcmp(comp_name, "Relic Codec v1.6", comp_size) == 0) { /* Homeworld 2 (PC) */
|
||||
uint8_t name_size = read_u8(offset + 0x16, sf);
|
||||
|
||||
if (is_str("Relic Codec v1.6", name_size, offset + 0x17, sf)) {
|
||||
coding_type = coding_RELIC;
|
||||
sample_count = sample_count * 512;
|
||||
}
|
||||
@ -191,11 +209,19 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x56415043: { /* "VAPC" [N64 (SDK mainly but apparently may exist in ROMs)] */
|
||||
/* "VADPCM ~4-1" */
|
||||
coding_type = coding_VADPCM;
|
||||
|
||||
/* N64 tools don't create FVER, but it's required by the spec (could skip the check though) */
|
||||
fver_found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
VGM_LOG("AIFC: unknown codec\n");
|
||||
goto fail;
|
||||
}
|
||||
/* string size and human-readable AIFF-C codec follows */
|
||||
}
|
||||
else if (is_aiff) {
|
||||
switch (sample_size) {
|
||||
@ -222,8 +248,9 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
|
||||
if (data_found) goto fail;
|
||||
data_found = 1;
|
||||
|
||||
/* 00: offset (for aligment, usually 0)
|
||||
* 04: block size (ex. XA: 0x914) */
|
||||
start_offset = offset + 0x08 + read_u32be(offset + 0x00,sf);
|
||||
/* when "APCM" XA frame size is at 0x0c, fixed to 0x914 */
|
||||
break;
|
||||
|
||||
case 0x4D41524B: /* "MARK" (loops) */
|
||||
@ -234,6 +261,33 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
|
||||
inst_offset = offset;
|
||||
break;
|
||||
|
||||
case 0x4150504C: /* "APPL" (application specific) */
|
||||
if (is_str("stoc", 0, offset + 0x00, sf)) {
|
||||
uint8_t name_size = read_u8(offset + 0x4, sf);
|
||||
off_t next_offset = offset + 0x04 + align_size_to_block(0x1 + name_size, 0x02);
|
||||
|
||||
/* chunks appears multiple times per substring */
|
||||
if (is_str("VADPCMCODES", name_size, offset + 0x05, sf)) {
|
||||
coef_offset = next_offset;
|
||||
}
|
||||
else if (is_str("VADPCMLOOPS", name_size, offset + 0x05, sf)) {
|
||||
/* goes with inst (spec says app chunks have less priority than inst+mark loops) */
|
||||
int version = read_u16be(next_offset + 0x00, sf);
|
||||
int loops = read_u16be(next_offset + 0x02, sf);
|
||||
if (version != 1 || loops != 1) goto fail;
|
||||
|
||||
loop_start = read_u32be(next_offset + 0x04, sf);
|
||||
loop_end = read_u32be(next_offset + 0x08, sf);
|
||||
loop_flag = read_s32be(next_offset + 0x08, sf) != 0; /*-1 = infinite */
|
||||
/* 0x10: ADPCM state[16] (hists?) */
|
||||
}
|
||||
else {
|
||||
VGM_LOG("AIFC: unknown APPL chunk\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -282,7 +336,7 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
@ -302,7 +356,7 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
|
||||
int bitrate = read_u16be(start_offset, sf);
|
||||
start_offset += 0x02;
|
||||
|
||||
vgmstream->codec_data = init_relic(channel_count, bitrate, sample_rate);
|
||||
vgmstream->codec_data = init_relic(channels, bitrate, sample_rate);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
@ -310,8 +364,25 @@ VGMSTREAM* init_vgmstream_aifc(STREAMFILE* sf) {
|
||||
break;
|
||||
}
|
||||
|
||||
case coding_VADPCM:
|
||||
if (channels > 1) goto fail; /* unknown layout */
|
||||
if (coef_offset == 0) goto fail;
|
||||
|
||||
vgmstream->layout_type = layout_none;
|
||||
{
|
||||
int version = read_u16be(coef_offset + 0x00, sf);
|
||||
int order = read_u16be(coef_offset + 0x02, sf);
|
||||
int entries = read_u16be(coef_offset + 0x04, sf);
|
||||
if (version != 1) goto fail;
|
||||
|
||||
vadpcm_read_coefs_be(vgmstream, sf, coef_offset + 0x06, order, entries, 0);
|
||||
}
|
||||
|
||||
//vgmstream->num_samples = vadpcm_bytes_to_samples(data_size, channels); /* unneeded */
|
||||
break;
|
||||
|
||||
default:
|
||||
vgmstream->layout_type = (channel_count > 1) ? layout_interleave : layout_none;
|
||||
vgmstream->layout_type = (channels > 1) ? layout_interleave : layout_none;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
break;
|
||||
}
|
||||
|
@ -1156,6 +1156,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
||||
case coding_NGC_DSP_subint:
|
||||
return 14;
|
||||
case coding_NGC_AFC:
|
||||
case coding_VADPCM:
|
||||
return 16;
|
||||
case coding_NGC_DTK:
|
||||
return 28;
|
||||
@ -1357,6 +1358,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
||||
case coding_NGC_DSP_subint:
|
||||
return 0x08 * vgmstream->channels;
|
||||
case coding_NGC_AFC:
|
||||
case coding_VADPCM:
|
||||
return 0x09;
|
||||
case coding_NGC_DTK:
|
||||
return 0x20;
|
||||
@ -1722,6 +1724,14 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do);
|
||||
}
|
||||
break;
|
||||
case coding_VADPCM: {
|
||||
int order = vgmstream->codec_config;
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_vadpcm(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do, order);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case coding_PSX:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_psx(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
|
@ -95,6 +95,7 @@ typedef enum {
|
||||
coding_NGC_DSP_subint, /* Nintendo DSP ADPCM with frame subinterframe */
|
||||
coding_NGC_DTK, /* Nintendo DTK ADPCM (hardware disc), also called TRK or ADP */
|
||||
coding_NGC_AFC, /* Nintendo AFC ADPCM */
|
||||
coding_VADPCM, /* Silicon Graphics VADPCM */
|
||||
|
||||
coding_G721, /* CCITT G.721 */
|
||||
|
||||
@ -786,14 +787,15 @@ typedef struct {
|
||||
/* format specific */
|
||||
|
||||
/* adpcm */
|
||||
int16_t adpcm_coef[16]; /* for formats with decode coefficients built in */
|
||||
int32_t adpcm_coef_3by32[0x60]; /* for Level-5 0x555 */
|
||||
int16_t adpcm_coef[16]; /* formats with decode coefficients built in (DSP, some ADX) */
|
||||
int32_t adpcm_coef_3by32[0x60]; /* Level-5 0x555 */
|
||||
int16_t vadpcm_coefs[8*2*8]; /* VADPCM: max 8 groups * max 2 order * fixed 8 subframe coefs */
|
||||
union {
|
||||
int16_t adpcm_history1_16; /* previous sample */
|
||||
int16_t adpcm_history1_16; /* previous sample */
|
||||
int32_t adpcm_history1_32;
|
||||
};
|
||||
union {
|
||||
int16_t adpcm_history2_16; /* previous previous sample */
|
||||
int16_t adpcm_history2_16; /* previous previous sample */
|
||||
int32_t adpcm_history2_32;
|
||||
};
|
||||
union {
|
||||
@ -808,8 +810,8 @@ typedef struct {
|
||||
double adpcm_history1_double;
|
||||
double adpcm_history2_double;
|
||||
|
||||
int adpcm_step_index; /* for IMA */
|
||||
int adpcm_scale; /* for MS ADPCM */
|
||||
int adpcm_step_index; /* for IMA */
|
||||
int adpcm_scale; /* for MS ADPCM */
|
||||
|
||||
/* state for G.721 decoder, sort of big but we might as well keep it around */
|
||||
struct g72x_state g72x_state;
|
||||
|
Loading…
x
Reference in New Issue
Block a user