mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 00:20:47 +01:00
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:
parent
0541b579cb
commit
040a5a0648
@ -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,"lpcm")) 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,"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("LPCM Audio File (*.LPCM)", lpcm);
|
||||
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("MATX Audio File (*.MATX)", matx);
|
||||
|
@ -240,11 +240,12 @@ etc:
|
||||
- .ahx (MPEG-2 Layer II)
|
||||
- .aix (CRI ADX ADPCM)
|
||||
- .baf (Blur ADPCM)
|
||||
- .bgw (FFXI PS-like ADPCM)
|
||||
- .bnsf (G.722.1)
|
||||
- .caf (Apple IMA4 ADPCM)
|
||||
- .bgw (FFXI PS-like ADPCM)
|
||||
- .de2 (MS ADPCM)
|
||||
- .kcey (EACS IMA ADPCM)
|
||||
- .lsf (LSF ADPCM)
|
||||
- .mwv (Level-5 0x555 ADPCM)
|
||||
- .ogg, .logg (Ogg Vorbis)
|
||||
- .p3d (Radical ADPCM)
|
||||
|
@ -19,7 +19,8 @@ CODING_OBJS=coding/adx_decoder.o \
|
||||
coding/nds_procyon_decoder.o \
|
||||
coding/l5_555_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/blocked.o \
|
||||
@ -270,7 +271,8 @@ META_OBJS=meta/adx_header.o \
|
||||
meta/ps2_mtaf.o \
|
||||
meta/x360_tra.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)
|
||||
|
||||
|
@ -27,5 +27,6 @@ libcoding_la_SOURCES += nds_procyon_decoder.c
|
||||
libcoding_la_SOURCES += l5_555_decoder.c
|
||||
libcoding_la_SOURCES += SASSC_decoder.c
|
||||
libcoding_la_SOURCES += g7221_decoder.c
|
||||
libcoding_la_SOURCES += lsf_decoder.c
|
||||
|
||||
EXTRA_DIST = coding.h g72x_state.h
|
||||
|
@ -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_lsf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
#endif
|
||||
|
52
src/coding/lsf_decoder.c
Normal file
52
src/coding/lsf_decoder.c
Normal 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;
|
||||
}
|
@ -380,6 +380,10 @@
|
||||
RelativePath=".\meta\kraw.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\lsf.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\maxis_xa.c"
|
||||
>
|
||||
@ -1134,6 +1138,10 @@
|
||||
RelativePath=".\coding\l5_555_decoder.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\lsf_decoder.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\mpeg_decoder.c"
|
||||
>
|
||||
|
@ -219,5 +219,6 @@ libmeta_la_SOURCES += ps2_mtaf.c
|
||||
libmeta_la_SOURCES += x360_tra.c
|
||||
libmeta_la_SOURCES += ps2_iab.c
|
||||
libmeta_la_SOURCES += ps2_strlr.c
|
||||
libmeta_la_SOURCES += lsf.c
|
||||
|
||||
EXTRA_DIST = meta.h
|
||||
|
59
src/meta/lsf.c
Normal file
59
src/meta/lsf.c
Normal 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;
|
||||
}
|
||||
|
@ -553,4 +553,6 @@ VGMSTREAM * init_vgmstream_ps2_iab(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_lsf_n1nj4n(STREAMFILE* streamFile);
|
||||
|
||||
#endif
|
||||
|
@ -298,6 +298,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_x360_tra,
|
||||
init_vgmstream_ps2_iab,
|
||||
init_vgmstream_ps2_strlr,
|
||||
init_vgmstream_lsf_n1nj4n,
|
||||
};
|
||||
|
||||
#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:
|
||||
return 16000/50;
|
||||
#endif
|
||||
case coding_LSF:
|
||||
return 54;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -944,6 +947,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
||||
return 34;
|
||||
case coding_BAF_ADPCM:
|
||||
return 33;
|
||||
case coding_LSF:
|
||||
return 28;
|
||||
#ifdef VGM_USE_G7221
|
||||
case coding_G7221C:
|
||||
case coding_G7221:
|
||||
@ -1376,6 +1381,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -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");
|
||||
break;
|
||||
case coding_L5_555:
|
||||
snprintf(temp,TEMPSIZE,"Level-5 0x555 ADPCM");
|
||||
snprintf(temp,TEMPSIZE,"Level-5 0x555 4-bit ADPCM");
|
||||
break;
|
||||
case coding_SASSC:
|
||||
snprintf(temp,TEMPSIZE,"Activision / EXAKT SASSC 8-bit DPCM");
|
||||
break;
|
||||
case coding_LSF:
|
||||
snprintf(temp,TEMPSIZE,"lsf 4-bit ADPCM");
|
||||
break;
|
||||
default:
|
||||
snprintf(temp,TEMPSIZE,"CANNOT DECODE");
|
||||
}
|
||||
@ -2761,6 +2776,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
||||
break;
|
||||
case meta_PS2_STRLR:
|
||||
snprintf(temp,TEMPSIZE,"STR L/R header");
|
||||
break;
|
||||
case meta_LSF_N1NJ4N:
|
||||
snprintf(temp,TEMPSIZE,".lsf !n1nj4n header");
|
||||
break;
|
||||
default:
|
||||
snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET");
|
||||
|
@ -122,6 +122,7 @@ typedef enum {
|
||||
coding_L5_555, /* Level-5 0x555 */
|
||||
coding_SASSC, /* Activision EXAKT SASSC DPCM */
|
||||
coding_PCM16LE_XOR_int, /* sample-level xor */
|
||||
coding_LSF, /* lsf ADPCM */
|
||||
} coding_t;
|
||||
|
||||
/* 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_IAB, // Ueki no Housoku - Taosu ze Robert Juudan!! (PS2)
|
||||
meta_PS2_STRLR,
|
||||
meta_LSF_N1NJ4N, /* .lsf n1nj4n Fastlane Street Racing (iPhone) */
|
||||
} meta_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -116,6 +116,7 @@ gchar *vgmstream_exts [] = {
|
||||
"logg",
|
||||
"lpcm",
|
||||
"lps",
|
||||
"lsf",
|
||||
"lwav",
|
||||
|
||||
"matx",
|
||||
|
@ -182,6 +182,7 @@ char * extension_list[] = {
|
||||
"logg\0LOGG Audio File (*.LOGG)\0",
|
||||
"lpcm\0LPCM Audio File (*.LPCM)\0",
|
||||
"lps\0LPS Audio File (*.LPS)\0",
|
||||
"lsf\0LSF Audio File (*.LSF)\0",
|
||||
"lwav\0LWAV Audio File (*.LWAV)\0",
|
||||
|
||||
"matx\0MATX Audio File (*.MATX)\0",
|
||||
|
Loading…
Reference in New Issue
Block a user