Procyon Studio Digital Sound Elements NDS ADPCM (as seen in .sad) decoder added

extended .sad support


git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@541 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
halleyscometsw 2008-12-28 06:29:43 +00:00
parent 3e63969795
commit a9ee80dc59
9 changed files with 133 additions and 11 deletions

View File

@ -189,7 +189,7 @@ multi:
- .rwar (GC DSP ADPCM, 8/16 bit PCM)
- .rwsd (GC DSP ADPCM, 8/16 bit PCM)
- .rsd (PSX ADPCM, 16 bit PCM, GC DSP ADPCM, Xbox IMA ADPCM)
- .sad (GC DSP ADPCM, NDS IMA ADPCM)
- .sad (GC DSP ADPCM, NDS IMA ADPCM, Procyon Studios NDS ADPCM)
- .sng, .asf, .str, .eam (EA/XA ADPCM or PSX ADPCM)
- .strm (STRM: NDS IMA ADPCM, 8/16 bit PCM)
- .ss7 (EACS IMA ADPCM, IMA ADPCM)

View File

@ -15,7 +15,8 @@ CODING_OBJS=coding/adx_decoder.o \
coding/acm_decoder.o \
coding/nwa_decoder.o \
coding/msadpcm_decoder.o \
coding/aica_decoder.o
coding/aica_decoder.o \
coding/nds_procyon_decoder.o
LAYOUT_OBJS=layout/ast_blocked.o \
layout/blocked.o \

View File

@ -23,5 +23,6 @@ libcoding_la_SOURCES += acm_decoder.c
libcoding_la_SOURCES += nwa_decoder.c
libcoding_la_SOURCES += aica_decoder.c
libcoding_la_SOURCES += msadpcm_decoder.c
libcoding_la_SOURCES += nds_procyon_decoder.c
EXTRA_DIST = coding.h g72x_state.h

View File

@ -76,4 +76,6 @@ void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample * outbuf, int32_t first
void decode_aica(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_nds_procyon(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
#endif

View File

@ -0,0 +1,60 @@
#include "coding.h"
#include "../util.h"
/* ADPCM found in NDS games using Procyon Studio Digital Sound Elements */
static const int8_t proc_coef[5][2] =
{
{0x00,0x00},
{0x3C,0x00},
{0x73,0xCC},
{0x62,0xC9},
{0x7A,0xC4},
};
void decode_nds_procyon(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i=first_sample;
int32_t sample_count;
int framesin = first_sample/30;
uint8_t header = read_8bit(framesin*16+15+stream->offset,stream->streamfile) ^ 0x80;
int scale = 12 - (header & 0xf);
int coef_index = (header >> 4) & 0xf;
int32_t hist1 = stream->adpcm_history1_32;
int32_t hist2 = stream->adpcm_history2_32;
int32_t coef1;
int32_t coef2;
if (coef_index > 4) coef_index = 0;
coef1 = proc_coef[coef_index][0];
coef2 = proc_coef[coef_index][1];
first_sample = first_sample%30;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int sample_byte = read_8bit(framesin*16+stream->offset+i/2,stream->streamfile) ^ 0x80;
int32_t sample =
(int32_t)
(i&1?
get_high_nibble_signed(sample_byte):
get_low_nibble_signed(sample_byte)
) * 64 * 64;
if (scale < 0)
{
sample <<= -scale;
}
else
sample >>= scale;
sample = (hist1 * coef1 + hist2 * coef2 + 32) / 64 + (sample * 64);
hist2 = hist1;
hist1 = sample;
outbuf[sample_count] = clamp16((sample + 32) / 64) / 64 * 64;
}
stream->adpcm_history1_32 = hist1;
stream->adpcm_history2_32 = hist2;
}

View File

@ -794,6 +794,9 @@
RelativePath=".\coding\msadpcm_decoder.c"
>
</File>
<File
RelativePath=".\coding\nds_procyon_decoder.c"
>
<File
RelativePath=".\coding\ngc_afc_decoder.c"
>

View File

@ -9,6 +9,7 @@ VGMSTREAM * init_vgmstream_sadl(STREAMFILE *streamFile) {
int loop_flag;
int channel_count;
int coding_type;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
@ -22,12 +23,21 @@ VGMSTREAM * init_vgmstream_sadl(STREAMFILE *streamFile) {
if (read_32bitLE(0x40,streamFile) != get_streamfile_size(streamFile) )
goto fail;
/* check for the simple IMA type that we can handle */
if (read_8bit(0xc,streamFile) != 0x11)
goto fail;
/* check coding type */
switch (read_8bit(0x33,streamFile)&0xf0)
{
case 0x70:
coding_type = coding_INT_IMA;
break;
case 0xb0:
coding_type = coding_NDS_PROCYON;
break;
default:
goto fail;
}
loop_flag = 0;
channel_count = 2;
loop_flag = read_8bit(0x31,streamFile);
channel_count = read_8bit(0x32,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
@ -36,12 +46,43 @@ VGMSTREAM * init_vgmstream_sadl(STREAMFILE *streamFile) {
/* fill in the vital statistics */
start_offset = 0x100;
vgmstream->channels = channel_count;
vgmstream->sample_rate = 16364;
vgmstream->coding_type = coding_INT_IMA;
vgmstream->num_samples = read_32bitLE(0x50,streamFile);;
switch (read_8bit(0x33,streamFile) & 6)
{
case 4:
vgmstream->sample_rate = 32728;
break;
case 2:
vgmstream->sample_rate = 16364;
break;
default:
goto fail;
}
vgmstream->coding_type = coding_type;
if (coding_type == coding_INT_IMA)
vgmstream->num_samples =
(read_32bitLE(0x40,streamFile)-start_offset)/channel_count*2;
else if (coding_type == coding_NDS_PROCYON)
vgmstream->num_samples =
(read_32bitLE(0x40,streamFile)-start_offset)/channel_count/16*30;
vgmstream->interleave_block_size=0x10;
vgmstream->layout_type = layout_interleave;
if (loop_flag)
{
if (coding_type == coding_INT_IMA)
vgmstream->loop_start_sample = (read_32bitLE(0x54,streamFile)-start_offset)/channel_count*2;
else
vgmstream->loop_start_sample = (read_32bitLE(0x54,streamFile)-start_offset)/channel_count/16*30;
vgmstream->loop_end_sample = vgmstream->num_samples;
}
if (channel_count > 1)
vgmstream->layout_type = layout_interleave;
else
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_SADL;
/* open the file for reading */

View File

@ -627,6 +627,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
return vgmstream->ws_output_size;
case coding_MSADPCM:
return (vgmstream->interleave_block_size-(7-1)*vgmstream->channels)*2/vgmstream->channels;
case coding_NDS_PROCYON:
return 30;
default:
return 0;
}
@ -681,6 +683,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
case coding_PSX:
case coding_PSX_badflags:
case coding_invert_PSX:
case coding_NDS_PROCYON:
return 16;
case coding_XA:
return 14*vgmstream->channels;
@ -989,6 +992,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
samples_to_do);
}
break;
case coding_NDS_PROCYON:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_nds_procyon(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do);
}
break;
}
}
@ -1309,6 +1319,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
case coding_AICA:
snprintf(temp,TEMPSIZE,"Yamaha AICA 4-bit ADPCM");
break;
case coding_NDS_PROCYON:
snprintf(temp,TEMPSIZE,"Procyon Studio Digital Sound Elements NDS 4-bit APDCM");
break;
default:
snprintf(temp,TEMPSIZE,"CANNOT DECODE");
}

View File

@ -56,6 +56,7 @@ typedef enum {
coding_XBOX, /* XBOX IMA */
coding_EAXA, /* EA/XA ADPCM */
coding_EA_ADPCM, /* EA ADPCM */
coding_NDS_PROCYON, /* NDS Procyon Studio ADPCM */
#ifdef VGM_USE_VORBIS
coding_ogg_vorbis, /* vorbis */