lsf meta and decoder, Fastlane Street Racing (iPhone)

git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@906 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
halleyscometsw 2011-01-13 08:11:58 +00:00
parent 0541b579cb
commit 040a5a0648
14 changed files with 156 additions and 4 deletions

View File

@ -359,6 +359,7 @@ bool input_vgmstream::g_is_our_path(const char * p_path,const char * p_extension
if(!stricmp_utf8(p_extension,"logg")) return 1; if(!stricmp_utf8(p_extension,"logg")) return 1;
if(!stricmp_utf8(p_extension,"lpcm")) return 1; if(!stricmp_utf8(p_extension,"lpcm")) return 1;
if(!stricmp_utf8(p_extension,"lps")) return 1; if(!stricmp_utf8(p_extension,"lps")) return 1;
if(!stricmp_utf8(p_extension,"lsf")) return 1;
if(!stricmp_utf8(p_extension,"lwav")) return 1; if(!stricmp_utf8(p_extension,"lwav")) return 1;
if(!stricmp_utf8(p_extension,"matx")) return 1; if(!stricmp_utf8(p_extension,"matx")) return 1;
@ -657,6 +658,7 @@ DECLARE_MULTIPLE_FILE_TYPE("LEG Audio File (*.LEG)", leg);
DECLARE_MULTIPLE_FILE_TYPE("LOGG Audio File (*.LOGG)", logg); DECLARE_MULTIPLE_FILE_TYPE("LOGG Audio File (*.LOGG)", logg);
DECLARE_MULTIPLE_FILE_TYPE("LPCM Audio File (*.LPCM)", lpcm); DECLARE_MULTIPLE_FILE_TYPE("LPCM Audio File (*.LPCM)", lpcm);
DECLARE_MULTIPLE_FILE_TYPE("LPS Audio File (*.LPS)", lps); DECLARE_MULTIPLE_FILE_TYPE("LPS Audio File (*.LPS)", lps);
DECLARE_MULTIPLE_FILE_TYPE("LSF Audio File (*.LSF)", lsf);
DECLARE_MULTIPLE_FILE_TYPE("LWAV Audio File (*.LWAV)", lwav); DECLARE_MULTIPLE_FILE_TYPE("LWAV Audio File (*.LWAV)", lwav);
DECLARE_MULTIPLE_FILE_TYPE("MATX Audio File (*.MATX)", matx); DECLARE_MULTIPLE_FILE_TYPE("MATX Audio File (*.MATX)", matx);

View File

@ -240,11 +240,12 @@ etc:
- .ahx (MPEG-2 Layer II) - .ahx (MPEG-2 Layer II)
- .aix (CRI ADX ADPCM) - .aix (CRI ADX ADPCM)
- .baf (Blur ADPCM) - .baf (Blur ADPCM)
- .bgw (FFXI PS-like ADPCM)
- .bnsf (G.722.1) - .bnsf (G.722.1)
- .caf (Apple IMA4 ADPCM) - .caf (Apple IMA4 ADPCM)
- .bgw (FFXI PS-like ADPCM)
- .de2 (MS ADPCM) - .de2 (MS ADPCM)
- .kcey (EACS IMA ADPCM) - .kcey (EACS IMA ADPCM)
- .lsf (LSF ADPCM)
- .mwv (Level-5 0x555 ADPCM) - .mwv (Level-5 0x555 ADPCM)
- .ogg, .logg (Ogg Vorbis) - .ogg, .logg (Ogg Vorbis)
- .p3d (Radical ADPCM) - .p3d (Radical ADPCM)

View File

@ -19,7 +19,8 @@ CODING_OBJS=coding/adx_decoder.o \
coding/nds_procyon_decoder.o \ coding/nds_procyon_decoder.o \
coding/l5_555_decoder.o \ coding/l5_555_decoder.o \
coding/SASSC_decoder.o \ coding/SASSC_decoder.o \
coding/g7221_decoder.o coding/g7221_decoder.o \
coding/lsf_decoder.o
LAYOUT_OBJS=layout/ast_blocked.o \ LAYOUT_OBJS=layout/ast_blocked.o \
layout/blocked.o \ layout/blocked.o \
@ -270,7 +271,8 @@ META_OBJS=meta/adx_header.o \
meta/ps2_mtaf.o \ meta/ps2_mtaf.o \
meta/x360_tra.o \ meta/x360_tra.o \
meta/ps2_iab.o \ meta/ps2_iab.o \
meta/ps2_strlr.o meta/ps2_strlr.o \
meta/lsf.o
OBJECTS=vgmstream.o streamfile.o util.o $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS) OBJECTS=vgmstream.o streamfile.o util.o $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS)

View File

@ -27,5 +27,6 @@ libcoding_la_SOURCES += nds_procyon_decoder.c
libcoding_la_SOURCES += l5_555_decoder.c libcoding_la_SOURCES += l5_555_decoder.c
libcoding_la_SOURCES += SASSC_decoder.c libcoding_la_SOURCES += SASSC_decoder.c
libcoding_la_SOURCES += g7221_decoder.c libcoding_la_SOURCES += g7221_decoder.c
libcoding_la_SOURCES += lsf_decoder.c
EXTRA_DIST = coding.h g72x_state.h EXTRA_DIST = coding.h g72x_state.h

View File

@ -110,4 +110,6 @@ void decode_l5_555(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacin
void decode_SASSC(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_SASSC(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
void decode_lsf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
#endif #endif

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

@ -0,0 +1,52 @@
#include "coding.h"
#include "../util.h"
/* lsf ADPCM, as seen in Fastlane Street Racing */
static const short lsf_coefs[5][2] = {
{0x73, -0x34},
{0, 0},
{0x62, -0x37},
{0x3C, 0},
{0x7A, -0x3c}
};
void decode_lsf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i=first_sample;
int32_t sample_count;
const int bytes_per_frame = 0x1c;
const int samples_per_frame = (bytes_per_frame-1)*2;
int framesin = first_sample/samples_per_frame;
uint8_t q = 0xFF - read_8bit(framesin*bytes_per_frame + stream->offset,stream->streamfile);
int scale = (q&0xF0)>>4;
int coef_idx = q&0x0F;
int32_t hist1 = stream->adpcm_history1_16;
int32_t hist2 = stream->adpcm_history2_16;
first_sample = first_sample%samples_per_frame;
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
int sample_byte = read_8bit(framesin*bytes_per_frame+stream->offset+1+i/2,stream->streamfile);
long prediction =
(hist1 * lsf_coefs[coef_idx][0] +
hist2 * lsf_coefs[coef_idx][1]) / 0x40;
prediction += (i&1?
get_high_nibble_signed(sample_byte):
get_low_nibble_signed(sample_byte)
) * (1 << (12-scale));
prediction = clamp16(prediction);
hist2 = hist1;
hist1 = prediction;
outbuf[sample_count] = prediction;
}
stream->adpcm_history1_16 = hist1;
stream->adpcm_history2_16 = hist2;
}

View File

@ -380,6 +380,10 @@
RelativePath=".\meta\kraw.c" RelativePath=".\meta\kraw.c"
> >
</File> </File>
<File
RelativePath=".\meta\lsf.c"
>
</File>
<File <File
RelativePath=".\meta\maxis_xa.c" RelativePath=".\meta\maxis_xa.c"
> >
@ -1134,6 +1138,10 @@
RelativePath=".\coding\l5_555_decoder.c" RelativePath=".\coding\l5_555_decoder.c"
> >
</File> </File>
<File
RelativePath=".\coding\lsf_decoder.c"
>
</File>
<File <File
RelativePath=".\coding\mpeg_decoder.c" RelativePath=".\coding\mpeg_decoder.c"
> >

View File

@ -219,5 +219,6 @@ libmeta_la_SOURCES += ps2_mtaf.c
libmeta_la_SOURCES += x360_tra.c libmeta_la_SOURCES += x360_tra.c
libmeta_la_SOURCES += ps2_iab.c libmeta_la_SOURCES += ps2_iab.c
libmeta_la_SOURCES += ps2_strlr.c libmeta_la_SOURCES += ps2_strlr.c
libmeta_la_SOURCES += lsf.c
EXTRA_DIST = meta.h EXTRA_DIST = meta.h

59
src/meta/lsf.c Normal file
View File

@ -0,0 +1,59 @@
#include "meta.h"
#include "../util.h"
/* .lsf - Fastlane Street Racing (iPhone) */
/* "!n1nj4n" */
VGMSTREAM * init_vgmstream_lsf_n1nj4n(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[260];
size_t file_size;
off_t start_offset;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("lsf",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x0, streamFile) != 0x216E316E || // "!n1n"
read_32bitBE(0x4, streamFile) != 0x6A346E00) // "j4n\0"
goto fail;
/* check size */
file_size = get_streamfile_size(streamFile);
if (read_32bitLE(0xC, streamFile) + 0x10 != file_size)
goto fail;
start_offset = 0x10;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(1,0);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->num_samples = (file_size-0x10)/0x1c*0x1b*2;
vgmstream->sample_rate = read_32bitLE(0x8, streamFile);
vgmstream->coding_type = coding_LSF;
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_LSF_N1NJ4N;
/* open the file for reading */
{
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!vgmstream->ch[0].streamfile) goto fail;
vgmstream->ch[0].channel_start_offset=
vgmstream->ch[0].offset=start_offset;
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -553,4 +553,6 @@ VGMSTREAM * init_vgmstream_ps2_iab(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_lsf_n1nj4n(STREAMFILE* streamFile);
#endif #endif

View File

@ -298,6 +298,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_x360_tra, init_vgmstream_x360_tra,
init_vgmstream_ps2_iab, init_vgmstream_ps2_iab,
init_vgmstream_ps2_strlr, init_vgmstream_ps2_strlr,
init_vgmstream_lsf_n1nj4n,
}; };
#define INIT_VGMSTREAM_FCNS (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0])) #define INIT_VGMSTREAM_FCNS (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0]))
@ -857,6 +858,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_G7221: case coding_G7221:
return 16000/50; return 16000/50;
#endif #endif
case coding_LSF:
return 54;
default: default:
return 0; return 0;
} }
@ -944,6 +947,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
return 34; return 34;
case coding_BAF_ADPCM: case coding_BAF_ADPCM:
return 33; return 33;
case coding_LSF:
return 28;
#ifdef VGM_USE_G7221 #ifdef VGM_USE_G7221
case coding_G7221C: case coding_G7221C:
case coding_G7221: case coding_G7221:
@ -1376,6 +1381,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
samples_to_do); samples_to_do);
} }
break;
case coding_LSF:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_lsf(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels,vgmstream->samples_into_block,
samples_to_do);
}
break; break;
} }
} }
@ -1745,11 +1757,14 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
snprintf(temp,TEMPSIZE,"Procyon Studio Digital Sound Elements NDS 4-bit APDCM"); snprintf(temp,TEMPSIZE,"Procyon Studio Digital Sound Elements NDS 4-bit APDCM");
break; break;
case coding_L5_555: case coding_L5_555:
snprintf(temp,TEMPSIZE,"Level-5 0x555 ADPCM"); snprintf(temp,TEMPSIZE,"Level-5 0x555 4-bit ADPCM");
break; break;
case coding_SASSC: case coding_SASSC:
snprintf(temp,TEMPSIZE,"Activision / EXAKT SASSC 8-bit DPCM"); snprintf(temp,TEMPSIZE,"Activision / EXAKT SASSC 8-bit DPCM");
break; break;
case coding_LSF:
snprintf(temp,TEMPSIZE,"lsf 4-bit ADPCM");
break;
default: default:
snprintf(temp,TEMPSIZE,"CANNOT DECODE"); snprintf(temp,TEMPSIZE,"CANNOT DECODE");
} }
@ -2761,6 +2776,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
break; break;
case meta_PS2_STRLR: case meta_PS2_STRLR:
snprintf(temp,TEMPSIZE,"STR L/R header"); snprintf(temp,TEMPSIZE,"STR L/R header");
break;
case meta_LSF_N1NJ4N:
snprintf(temp,TEMPSIZE,".lsf !n1nj4n header");
break; break;
default: default:
snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET"); snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET");

View File

@ -122,6 +122,7 @@ typedef enum {
coding_L5_555, /* Level-5 0x555 */ coding_L5_555, /* Level-5 0x555 */
coding_SASSC, /* Activision EXAKT SASSC DPCM */ coding_SASSC, /* Activision EXAKT SASSC DPCM */
coding_PCM16LE_XOR_int, /* sample-level xor */ coding_PCM16LE_XOR_int, /* sample-level xor */
coding_LSF, /* lsf ADPCM */
} coding_t; } coding_t;
/* The layout type specifies how the sound data is laid out in the file */ /* The layout type specifies how the sound data is laid out in the file */
@ -508,6 +509,7 @@ typedef enum {
meta_PS2_VGS, // Princess Soft PS2 games meta_PS2_VGS, // Princess Soft PS2 games
meta_PS2_IAB, // Ueki no Housoku - Taosu ze Robert Juudan!! (PS2) meta_PS2_IAB, // Ueki no Housoku - Taosu ze Robert Juudan!! (PS2)
meta_PS2_STRLR, meta_PS2_STRLR,
meta_LSF_N1NJ4N, /* .lsf n1nj4n Fastlane Street Racing (iPhone) */
} meta_t; } meta_t;
typedef struct { typedef struct {

View File

@ -116,6 +116,7 @@ gchar *vgmstream_exts [] = {
"logg", "logg",
"lpcm", "lpcm",
"lps", "lps",
"lsf",
"lwav", "lwav",
"matx", "matx",

View File

@ -182,6 +182,7 @@ char * extension_list[] = {
"logg\0LOGG Audio File (*.LOGG)\0", "logg\0LOGG Audio File (*.LOGG)\0",
"lpcm\0LPCM Audio File (*.LPCM)\0", "lpcm\0LPCM Audio File (*.LPCM)\0",
"lps\0LPS Audio File (*.LPS)\0", "lps\0LPS Audio File (*.LPS)\0",
"lsf\0LSF Audio File (*.LSF)\0",
"lwav\0LWAV Audio File (*.LWAV)\0", "lwav\0LWAV Audio File (*.LWAV)\0",
"matx\0MATX Audio File (*.MATX)\0", "matx\0MATX Audio File (*.MATX)\0",