Add Ocean .DSF, .208 and DSA decoder [Last Rites (PC)]

This commit is contained in:
bnnm 2019-02-10 01:36:05 +01:00
parent 0dbe00d4b0
commit 4c038cb0ea
11 changed files with 206 additions and 4 deletions

View File

@ -161,6 +161,9 @@ void decode_fadpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacin
/* asf_decoder */
void decode_asf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* dsa_decoder */
void decode_dsa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* xmd_decoder */
void decode_xmd(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, size_t frame_size);

52
src/coding/dsa_decoder.c Normal file
View File

@ -0,0 +1,52 @@
#include "coding.h"
static const int dsa_coefs[16] = {
0x0, 0x1999, 0x3333, 0x4CCC,
0x6666, 0x8000, 0x9999, 0xB333,
0xCCCC, 0xE666, 0x10000, 0x11999,
0x13333, 0x18000, 0x1CCCC, 0x21999
};
/* Decodes Ocean DSA ADPCM codec from Last Rites (PC).
* Reverse engineered from daemon1's reverse engineering. */
void decode_dsa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
off_t frame_offset;
int i, frames_in, sample_count = 0;
size_t bytes_per_frame, samples_per_frame;
uint8_t header;
int shift, filter;
int32_t hist1 = stream->adpcm_history1_32;
/* external interleave (fixed size), mono */
bytes_per_frame = 0x08;
samples_per_frame = (bytes_per_frame - 0x01) * 2;
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;
header = (uint8_t)read_8bit(frame_offset+0x00,stream->streamfile);
shift = 0x0c - ((header >> 4) & 0xf);
filter = dsa_coefs[header & 0xf];
/* decode nibbles */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
int32_t new_sample;
uint8_t nibbles = (uint8_t)read_8bit(frame_offset+0x01 + i/2,stream->streamfile);
new_sample = i&1 ? /* high nibble first */
(nibbles >> 0) & 0xf :
(nibbles >> 4) & 0xf;
new_sample = ((int16_t)(new_sample << 0xC) >> shift); /* 16b sign extend + scale */
new_sample = new_sample + ((hist1 * filter) >> 0x10);
outbuf[sample_count] = (int16_t)(new_sample << 2);
sample_count += channelspacing;
hist1 = new_sample;
}
stream->adpcm_history1_32 = hist1;
}

View File

@ -14,6 +14,7 @@ static const char* extension_list[] = {
//"", /* vgmstream can play extensionless files too, but plugins must accept them manually */
"04sw",
"208",
"2dx9",
"2pfs",
"800",
@ -122,6 +123,7 @@ static const char* extension_list[] = {
"de2",
"dec",
"dmsg",
"dsf",
"dsp",
"dspw",
"dtk",
@ -639,6 +641,7 @@ static const coding_info coding_info_list[] = {
{coding_MC3, "Paradigm MC3 3-bit ADPCM"},
{coding_FADPCM, "FMOD FADPCM 4-bit ADPCM"},
{coding_ASF, "Argonaut ASF 4-bit ADPCM"},
{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 (16-bit output)"},
@ -1164,6 +1167,8 @@ static const meta_info meta_info_list[] = {
{meta_OGG_OPUS, "Ogg Opus header"},
{meta_IMC, "iNiS .IMC header"},
{meta_GIN, "Electronic Arts Gnsu header"},
{meta_DSF, "Ocean DSF header"},
{meta_208, "Ocean .208 header"},
};

View File

@ -296,6 +296,10 @@
<Filter
Name="Source Files"
>
<File
RelativePath=".\meta\208.c"
>
</File>
<File
RelativePath=".\meta\2dx9.c"
>
@ -496,10 +500,14 @@
RelativePath=".\meta\derf.c"
>
</File>
<File
RelativePath=".\meta\dmsg_segh.c"
>
</File>
<File
RelativePath=".\meta\dmsg_segh.c"
>
</File>
<File
RelativePath=".\meta\dsf.c"
>
</File>
<File
RelativePath=".\meta\dsp_adx.c"
>
@ -1774,6 +1782,10 @@
RelativePath=".\coding\derf_decoder.c"
>
</File>
<File
RelativePath=".\coding\dsa_decoder.c"
>
</File>
<File
RelativePath=".\coding\ea_mt_decoder.c"
>

View File

@ -201,6 +201,7 @@
<ClCompile Include="streamfile.c" />
<ClCompile Include="util.c" />
<ClCompile Include="vgmstream.c" />
<ClCompile Include="meta\208.c" />
<ClCompile Include="meta\2dx9.c" />
<ClCompile Include="meta\a2m.c" />
<ClCompile Include="meta\ahv.c" />
@ -248,6 +249,7 @@
<ClCompile Include="meta\dec.c" />
<ClCompile Include="meta\derf.c" />
<ClCompile Include="meta\dmsg_segh.c" />
<ClCompile Include="meta\dsf.c" />
<ClCompile Include="meta\dsp_adx.c" />
<ClCompile Include="meta\dsp_bdsp.c" />
<ClCompile Include="meta\ea_schl.c" />
@ -504,6 +506,7 @@
<ClCompile Include="coding\asf_decoder.c" />
<ClCompile Include="coding\yamaha_decoder.c" />
<ClCompile Include="coding\derf_decoder.c" />
<ClCompile Include="coding\dsa_decoder.c" />
<ClCompile Include="coding\ea_mt_decoder.c" />
<ClCompile Include="coding\ea_xa_decoder.c" />
<ClCompile Include="coding\ea_xas_decoder.c" />

View File

@ -184,6 +184,9 @@
<ClCompile Include="vgmstream.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\208.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\2dx9.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -319,6 +322,9 @@
<ClCompile Include="meta\dmsg_segh.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\dsf.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\dsp_bdsp.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -1054,6 +1060,9 @@
<ClCompile Include="coding\derf_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\dsa_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\ea_mt_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>

48
src/meta/208.c Normal file
View File

@ -0,0 +1,48 @@
#include "meta.h"
#include "../coding/coding.h"
/* .208 - from Ocean game(s?) [Last Rites (PC)] */
VGMSTREAM * init_vgmstream_208(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, sample_rate;
size_t data_size;
/* checks */
if (!check_extensions(streamFile, "208"))
goto fail;
/* possible validation: (0x04 == 0 and 0xcc == 0x1F7D984D) or 0x04 == 0xf0 and 0xcc == 0) */
if (!((read_32bitLE(0x04,streamFile) == 0x00 && read_32bitBE(0xcc,streamFile) == 0x1F7D984D) ||
(read_32bitLE(0x04,streamFile) == 0xF0 && read_32bitBE(0xcc,streamFile) == 0x00000000)))
goto fail;
start_offset = read_32bitLE(0x00,streamFile);
data_size = read_32bitLE(0x0c,streamFile);
sample_rate = read_32bitLE(0x34,streamFile);
channel_count = read_32bitLE(0x3C,streamFile); /* assumed */
loop_flag = 0;
if (start_offset + data_size != get_streamfile_size(streamFile))
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_208;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, 8);
vgmstream->coding_type = coding_PCM8_U;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x1;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

51
src/meta/dsf.c Normal file
View File

@ -0,0 +1,51 @@
#include "meta.h"
#include "../coding/coding.h"
/* .DSF - from Ocean game(s?) [Last Rites (PC)] */
VGMSTREAM * init_vgmstream_dsf(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, sample_rate;
size_t data_size;
/* checks */
if (!check_extensions(streamFile, "dsf"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4F434541 && /* "OCEA" */
read_32bitBE(0x00,streamFile) != 0x4E204453 && /* "N DS" */
read_32bitBE(0x00,streamFile) != 0x41000000) /* "A\0\0\0" */
goto fail;
/* 0x10(2): always 1? */
/* 0x12(4): total nibbles / 0x10? */
/* 0x16(4): always 0? */
start_offset = read_32bitLE(0x1a,streamFile);
sample_rate = read_32bitLE(0x1e,streamFile);
channel_count = read_32bitLE(0x22,streamFile) + 1;
data_size = get_streamfile_size(streamFile) - start_offset;
loop_flag = 0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_DSF;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = ((data_size / 0x08 / channel_count) * 14); /* bytes-to-samples */
vgmstream->coding_type = coding_DSA;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x08;
read_string(vgmstream->stream_name,0x20+1, 0x26,streamFile);
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -826,4 +826,8 @@ VGMSTREAM * init_vgmstream_smp(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_gin(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_dsf(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_208(STREAMFILE * streamFile);
#endif /*_META_H*/

View File

@ -463,6 +463,8 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_imc_container,
init_vgmstream_smp,
init_vgmstream_gin,
init_vgmstream_dsf,
init_vgmstream_208,
/* 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 */
@ -1248,6 +1250,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
return 256; /* (0x8c - 0xc) * 2 */
case coding_ASF:
return 32; /* (0x11 - 0x1) * 2 */
case coding_DSA:
return 14; /* (0x08 - 0x1) * 2 */
case coding_XMD:
return (vgmstream->interleave_block_size - 0x06)*2 + 2;
case coding_EA_MT:
@ -1424,6 +1428,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
return 0x8c;
case coding_ASF:
return 0x11;
case coding_DSA:
return 0x08;
case coding_XMD:
return vgmstream->interleave_block_size;
case coding_EA_MT:
@ -2047,6 +2053,12 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
vgmstream->channels,vgmstream->samples_into_block,samples_to_do);
}
break;
case coding_DSA:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_dsa(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
vgmstream->channels,vgmstream->samples_into_block,samples_to_do);
}
break;
case coding_XMD:
for (ch = 0; ch < vgmstream->channels; ch++) {
decode_xmd(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,

View File

@ -152,6 +152,7 @@ typedef enum {
coding_MC3, /* Paradigm MC3 3-bit ADPCM */
coding_FADPCM, /* FMOD FADPCM 4-bit ADPCM */
coding_ASF, /* Argonaut ASF 4-bit ADPCM */
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 */
@ -714,6 +715,8 @@ typedef enum {
meta_OGG_OPUS,
meta_IMC,
meta_GIN,
meta_DSF,
meta_208,
} meta_t;