add Cstr (lots of checking), add company names to metadata formats, some dsp looping debugging stuff (with DEBUG defined)

git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@62 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
halleyscometsw 2008-04-02 16:11:53 +00:00
parent 67f6550ea3
commit 2d04ecf01a
6 changed files with 281 additions and 25 deletions

View File

@ -22,12 +22,13 @@ META_OBJS=meta/adx_header.o \
meta/ngc_adpdtk.o \
meta/rsf.o \
meta/rs03.o \
meta/ngc_dsp_std.o
meta/ngc_dsp_std.o \
meta/Cstr.o
OBJECTS=vgmstream.o streamfile.o util.o $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS)
libvgmstream.a: $(OBJECTS)
$(AR) crsv libvgmstream.a $(OBJECTS)
$(AR) crs libvgmstream.a $(OBJECTS)
vgmstream-deps:
$(CC) $(CFLAGS) -M -o vgmstream-deps

View File

@ -20,6 +20,11 @@ void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int sample_byte = read_8bit(framesin*8+stream->offset+1+i/2,stream->streamfile);
#if DEBUG
if (hist1==stream->loop_history1 && hist2==stream->loop_history2) fprintf(stderr,"yo! %#x (start %#x) %d\n",stream->offset+framesin*8+i/2,stream->channel_start_offset,stream->samples_done);
stream->samples_done++;
#endif
outbuf[sample_count] = clamp16((
(((i&1?
get_low_nibble_signed(sample_byte):

228
src/meta/Cstr.c Normal file
View File

@ -0,0 +1,228 @@
#include "Cstr.h"
#include "../coding/ngc_dsp_decoder.h"
#include "../util.h"
/* .dsp w/ Cstr header, seen in Star Fox Assault and Donkey Konga */
VGMSTREAM * init_vgmstream_Cstr(const char * const filename) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * infile = NULL;
int loop_flag;
off_t start_offset;
off_t first_data;
off_t loop_offset;
size_t interleave;
int loop_adjust;
/* check extension, case insensitive */
if (strcasecmp("dsp",filename_extension(filename))) goto fail;
/* try to open the file for header reading */
infile = open_streamfile(filename);
if (!infile) goto fail;
/* check header */
if ((uint32_t)read_32bitBE(0,infile)!=0x43737472) /* "Cstr" */
goto fail;
#ifdef DEBUG
fprintf(stderr,"header ok\n");
#endif
interleave = read_16bitBE(0x06,infile);
start_offset = 0xe0;
first_data = start_offset+read_32bitBE(0x0c,infile);
loop_flag = read_16bitBE(0x2c,infile);
if (!loop_flag) {
/* Nonlooped tracks seem to follow no discernable pattern
* with where they actually start.
* But! with the magic of initial p/s redundancy, we can guess.
*/
while (first_data<start_offset+0x800 &&
(read_16bitBE(0x5e,infile) != (uint8_t)read_8bit(first_data,infile) ||
read_16bitBE(0xbe,infile) != (uint8_t)read_8bit(first_data+interleave,infile)))
first_data+=8;
#ifdef DEBUG
fprintf(stderr,"guessed first_data at %#x\n",first_data);
#endif
}
/* check initial predictor/scale */
if (read_16bitBE(0x5e,infile) != (uint8_t)read_8bit(first_data,infile))
goto fail;
if (read_16bitBE(0xbe,infile) != (uint8_t)read_8bit(first_data+interleave,infile))
goto fail;
#ifdef DEBUG
fprintf(stderr,"p/s ok\n");
#endif
/* check type==0 and gain==0 */
if (read_16bitBE(0x2e,infile) || read_16bitBE(0x5c,infile))
goto fail;
if (read_16bitBE(0x8e,infile) || read_16bitBE(0xbc,infile))
goto fail;
#ifdef DEBUG
fprintf(stderr,"type & gain ok\n");
#endif
/* check for loop flag agreement */
if (read_16bitBE(0x2c,infile) != read_16bitBE(0x8c,infile))
goto fail;
#ifdef DEBUG
fprintf(stderr,"loop flags agree\n");
#endif
loop_offset = start_offset+read_32bitBE(0x10,infile)*2;
if (loop_flag) {
int loops_ok=0;
/* check loop predictor/scale */
/* some fuzz allowed */
for (loop_adjust=0;loop_adjust>=-0x10;loop_adjust-=8) {
#ifdef DEBUG
fprintf(stderr,"looking for loop p/s at %#x,%#x\n",loop_offset-interleave+loop_adjust,loop_offset+loop_adjust);
#endif
if (read_16bitBE(0x64,infile) == (uint8_t)read_8bit(loop_offset-interleave+loop_adjust,infile) &&
read_16bitBE(0xc4,infile) == (uint8_t)read_8bit(loop_offset+loop_adjust,infile)) {
loops_ok=1;
break;
}
}
if (!loops_ok)
for (loop_adjust=interleave;loop_adjust<=interleave+0x10;loop_adjust+=8) {
#ifdef DEBUG
fprintf(stderr,"looking for loop p/s at %#x,%#x\n",loop_offset-interleave+loop_adjust,loop_offset+loop_adjust);
#endif
if (read_16bitBE(0x64,infile) == (uint8_t)read_8bit(loop_offset-interleave+loop_adjust,infile) &&
read_16bitBE(0xc4,infile) == (uint8_t)read_8bit(loop_offset+loop_adjust,infile)) {
loops_ok=1;
break;
}
}
if (!loops_ok) goto fail;
#ifdef DEBUG
fprintf(stderr,"loop p/s ok (with %#4x adjust)\n",loop_adjust);
#endif
/* check for agreement */
/* loop end (channel 1 & 2 headers) */
if (read_32bitBE(0x34,infile) != read_32bitBE(0x94,infile))
goto fail;
/* loop start (Cstr header and channel 1 header) */
if (read_32bitBE(0x30,infile) != read_32bitBE(0x10,infile)
#if 0
/* this particular glitch only true for SFA, though it
* seems like something similar happens in Donkey Konga */
/* loop start (Cstr, channel 1 & 2 headers) */
|| (read_32bitBE(0x0c,infile)+read_32bitLE(0x30,infile)) != read_32bitBE(0x90,infile)
#endif
)
/* alternatively (Donkey Konga) the header loop is 0x0c+0x10 */
if (
/* loop start (Cstr header and channel 1 header) */
read_32bitBE(0x30,infile) != read_32bitBE(0x10,infile)+read_32bitBE(0x0c,infile))
/* further alternatively (Donkey Konga), if we loop back to
* the very first frame 0x30 might be 0x00000002 (which
* is a *valid* std dsp loop start, imagine that) while 0x10
* is 0x00000000 */
if (read_32bitBE(0x30,infile) != 2 || read_32bitBE(0x10,infile) != 0)
goto fail;
#ifdef DEBUG
fprintf(stderr,"loop points agree\n");
#endif
}
/* assure that sample counts, sample rates agree */
if (
/* sample count (channel 1 & 2 headers) */
read_32bitBE(0x20,infile) != read_32bitBE(0x80,infile) ||
/* sample rate (channel 1 & 2 headers) */
read_32bitBE(0x28,infile) != read_32bitBE(0x88,infile) ||
/* sample count (Cstr header and channel 1 header) */
read_32bitLE(0x14,infile) != read_32bitBE(0x20,infile) ||
/* sample rate (Cstr header and channel 1 header) */
(uint16_t)read_16bitLE(0x18,infile) != read_32bitBE(0x28,infile))
goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(2,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->sample_rate = read_32bitBE(0x28,infile);
/* This is a slight hack to counteract their hack.
* All the data is ofset by first_data so that the loop
* point occurs at a block boundary. However, I always begin decoding
* right after the header, as that is the start of the first block and
* my interleave code relies on starting at the beginning of a block.
* So we decode a few silent samples at the beginning, and here we make up
* for it by lengthening the track by that much.
*/
vgmstream->num_samples = read_32bitBE(0x20,infile) +
(first_data-start_offset)/8*14;
if (loop_flag) {
off_t loop_start_bytes = loop_offset-start_offset-interleave;
vgmstream->loop_start_sample = dsp_nibbles_to_samples((loop_start_bytes/(2*interleave)*interleave+loop_start_bytes%(interleave*2))*2);
/*dsp_nibbles_to_samples(loop_start_bytes);*/
/*dsp_nibbles_to_samples(read_32bitBE(0x30,infile)*2-inter);*/
vgmstream->loop_end_sample = dsp_nibbles_to_samples(
read_32bitBE(0x34,infile))+1;
if (vgmstream->loop_end_sample > vgmstream->num_samples) {
#ifdef DEBUG
fprintf(stderr,"loop_end_sample > num_samples, adjusting\n");
#endif
vgmstream->loop_end_sample = vgmstream->num_samples;
}
}
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
vgmstream->meta_type = meta_DSP_CSTR;
{
int i;
for (i=0;i<16;i++)
vgmstream->ch[0].adpcm_coef[i]=read_16bitBE(0x3c+i*2,infile);
for (i=0;i<16;i++)
vgmstream->ch[1].adpcm_coef[i]=read_16bitBE(0x9c+i*2,infile);
}
#ifdef DEBUG
vgmstream->ch[0].loop_history1 = read_16bitBE(0x66,infile);
vgmstream->ch[0].loop_history2 = read_16bitBE(0x68,infile);
vgmstream->ch[1].loop_history1 = read_16bitBE(0xc6,infile);
vgmstream->ch[1].loop_history2 = read_16bitBE(0xc8,infile);
#endif
close_streamfile(infile); infile=NULL;
/* open the file for reading by each channel */
{
int i;
for (i=0;i<2;i++) {
vgmstream->ch[i].streamfile = open_streamfile_buffer(filename,interleave);
if (!vgmstream->ch[i].streamfile) goto fail;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=
start_offset+interleave*i;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (infile) close_streamfile(infile);
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

8
src/meta/Cstr.h Normal file
View File

@ -0,0 +1,8 @@
#include "../vgmstream.h"
#ifndef _CSTR_H
#define _CSTR_H
VGMSTREAM * init_vgmstream_Cstr(const char * const filename);
#endif

View File

@ -13,6 +13,7 @@
#include "meta/halpst.h"
#include "meta/rs03.h"
#include "meta/ngc_dsp_std.h"
#include "meta/Cstr.h"
#include "layout/interleave.h"
#include "layout/nolayout.h"
#include "layout/blocked.h"
@ -28,7 +29,7 @@
* List of functions that will recognize files. These should correspond pretty
* directly to the metadata types
*/
#define INIT_VGMSTREAM_FCNS 11
#define INIT_VGMSTREAM_FCNS 12
VGMSTREAM * (*init_vgmstream_fcns[INIT_VGMSTREAM_FCNS])(const char * const) = {
init_vgmstream_adx,
init_vgmstream_brstm,
@ -41,6 +42,7 @@ VGMSTREAM * (*init_vgmstream_fcns[INIT_VGMSTREAM_FCNS])(const char * const) = {
init_vgmstream_halpst,
init_vgmstream_rs03,
init_vgmstream_ngc_dsp_std,
init_vgmstream_Cstr,
};
@ -335,26 +337,30 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) {
/* if (vgmstream->loop_flag) {*/
/* is this the loop end? */
if (vgmstream->current_sample==vgmstream->loop_end_sample) {
/* RS03 and the Metroid Prime standard DSP files are
* apparently built with the assumption that the history
* is preserved through looping
*/
/* against everything I hold sacred, preserve adpcm
* history through loop for certain types */
if (vgmstream->meta_type == meta_DSP_STD ||
vgmstream->meta_type == meta_DSP_RS03) {
vgmstream->meta_type == meta_DSP_RS03 ||
vgmstream->meta_type == meta_DSP_CSTR) {
int i;
for (i=0;i<vgmstream->channels;i++) {
vgmstream->loop_ch[i].adpcm_history1_16 = vgmstream->ch[i].adpcm_history1_16;
vgmstream->loop_ch[i].adpcm_history2_16 = vgmstream->ch[i].adpcm_history2_16;
}
}
/*
#if DEBUG
{
int i;
for (i=0;i<vgmstream->channels;i++) {
fprintf(stderr,"ch%d hist: %04x %04x loop hist: %04x %04x\n",i,
vgmstream->ch[i].adpcm_history1_16,vgmstream->ch[i].adpcm_history2_16,
vgmstream->loop_ch[i].adpcm_history1_16,vgmstream->loop_ch[i].adpcm_history2_16);
fprintf(stderr,"ch%d hist: %04x %04x loop hist: %04x %04x\n",i,
vgmstream->ch[i].adpcm_history1_16,vgmstream->ch[i].adpcm_history2_16,
vgmstream->loop_ch[i].adpcm_history1_16,vgmstream->loop_ch[i].adpcm_history2_16);
fprintf(stderr,"ch%d offset: %x loop offset: %x\n",i,
vgmstream->ch[i].offset,
vgmstream->loop_ch[i].offset);
}
*/
}
#endif
/* restore! */
memcpy(vgmstream->ch,vgmstream->loop_ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels);
vgmstream->current_sample=vgmstream->loop_sample;
@ -464,7 +470,7 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
snprintf(temp,TEMPSIZE,"interleave with short last block");
break;
case layout_dtk_interleave:
snprintf(temp,TEMPSIZE,"DTK nibble interleave");
snprintf(temp,TEMPSIZE,"ADP/DTK nibble interleave");
break;
case layout_ast_blocked:
snprintf(temp,TEMPSIZE,"AST blocked");
@ -497,40 +503,43 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
switch (vgmstream->meta_type) {
case meta_RSTM:
snprintf(temp,TEMPSIZE,"RSTM header");
snprintf(temp,TEMPSIZE,"Nintendo RSTM header");
break;
case meta_STRM:
snprintf(temp,TEMPSIZE,"NDS STRM header");
snprintf(temp,TEMPSIZE,"Nintendo STRM header");
break;
case meta_ADX_03:
snprintf(temp,TEMPSIZE,"ADX header type 03");
snprintf(temp,TEMPSIZE,"CRI ADX header type 03");
break;
case meta_ADX_04:
snprintf(temp,TEMPSIZE,"ADX header type 04");
snprintf(temp,TEMPSIZE,"CRI ADX header type 04");
break;
case meta_DSP_AGSC:
snprintf(temp,TEMPSIZE,"AGSC header");
snprintf(temp,TEMPSIZE,"Retro Studios AGSC header");
break;
case meta_NGC_ADPDTK:
snprintf(temp,TEMPSIZE,"assumed NGC DTK by .adp extension and valid first frame");
snprintf(temp,TEMPSIZE,"assumed Nintendo ADP by .adp extension and valid first frame");
break;
case meta_RSF:
snprintf(temp,TEMPSIZE,"assumed Retro Studios RSF by .rsf extension");
snprintf(temp,TEMPSIZE,"assumed Retro Studios RSF by .rsf extension and valid first bytes");
break;
case meta_AFC:
snprintf(temp,TEMPSIZE,"AFC header");
snprintf(temp,TEMPSIZE,"Nintendo AFC header");
break;
case meta_AST:
snprintf(temp,TEMPSIZE,"AST header");
snprintf(temp,TEMPSIZE,"Nintendo AST header");
break;
case meta_HALPST:
snprintf(temp,TEMPSIZE,"HALPST header");
snprintf(temp,TEMPSIZE,"HAL Laboratory HALPST header");
break;
case meta_DSP_RS03:
snprintf(temp,TEMPSIZE,"Retro Studios RS03 header");
break;
case meta_DSP_STD:
snprintf(temp,TEMPSIZE,"Standard NGC DSP header");
snprintf(temp,TEMPSIZE,"Standard Nintendo DSP header");
break;
case meta_DSP_CSTR:
snprintf(temp,TEMPSIZE,"Namco Cstr header");
break;
default:
snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET");

View File

@ -99,6 +99,11 @@ typedef struct {
struct g72x_state g72x_state; /* state for G.721 decoder, sort of big but we
might as well keep it around */
#ifdef DEBUG
int samples_done;
int16_t loop_history1,loop_history2;
#endif
} VGMSTREAMCHANNEL;
typedef struct {