From e98bb44bb5b42352c7647192deaffbd45ea1f006 Mon Sep 17 00:00:00 2001 From: halleyscometsw Date: Fri, 10 Sep 2010 23:56:39 +0000 Subject: [PATCH] .scd (FFXIII and FFXIV, MPEG, MS ADPCM, and PCM) git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@834 51a99a44-fe44-0410-b1ba-c3e57ba2b86b --- fb2k/in_vgmstream.cpp | 2 + readme.txt | 1 + src/Makefile | 3 +- src/coding/coding.h | 2 + src/coding/mpeg_decoder.c | 4 + src/coding/msadpcm_decoder.c | 4 + src/libvgmstream.vcproj | 4 + src/meta/Makefile.unix.am | 1 + src/meta/meta.h | 1 + src/meta/se_scd.c | 143 +++++++++++++++++++++++++++++++++++ src/vgmstream.c | 4 + src/vgmstream.h | 1 + unix/data.c | 1 + winamp/in_vgmstream.c | 1 + 14 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 src/meta/se_scd.c diff --git a/fb2k/in_vgmstream.cpp b/fb2k/in_vgmstream.cpp index 809033f4..98dfb0e8 100644 --- a/fb2k/in_vgmstream.cpp +++ b/fb2k/in_vgmstream.cpp @@ -408,6 +408,7 @@ bool input_vgmstream::g_is_our_path(const char * p_path,const char * p_extension if(!stricmp_utf8(p_extension,"sad")) return 1; if(!stricmp_utf8(p_extension,"sap")) return 1; if(!stricmp_utf8(p_extension,"sc")) return 1; + if(!stricmp_utf8(p_extension,"scd")) return 1; if(!stricmp_utf8(p_extension,"sck")) return 1; if(!stricmp_utf8(p_extension,"sd9")) return 1; if(!stricmp_utf8(p_extension,"sdt")) return 1; @@ -689,6 +690,7 @@ DECLARE_MULTIPLE_FILE_TYPE("SAB Audio File (*.SAB)", sab); DECLARE_MULTIPLE_FILE_TYPE("SAD Audio File (*.SAD)", sad); DECLARE_MULTIPLE_FILE_TYPE("SAP Audio File (*.SAP)", sap); DECLARE_MULTIPLE_FILE_TYPE("SC Audio File (*.SC)", sc); +DECLARE_MULTIPLE_FILE_TYPE("SCD Audio File (*.SCD)", scd); DECLARE_MULTIPLE_FILE_TYPE("SCK Audio File (*.SCK)", sck); DECLARE_MULTIPLE_FILE_TYPE("SD9 Audio File (*.SD9)", sd9); DECLARE_MULTIPLE_FILE_TYPE("SDT Audio File (*.SDT)", sdt); diff --git a/readme.txt b/readme.txt index 1f49ceae..6fd5b13f 100644 --- a/readme.txt +++ b/readme.txt @@ -251,6 +251,7 @@ etc: - .sab (Worms 4 soundpacks) - .s14/.sss (G.722.1) - .sc (Activision EXAKT SASSC DPCM) +- .scd (MS ADPCM, MPEG Audio, 16 bit PCM) - .sd9 (MS ADPCM) - .smp (MS ADPCM) - .spw (FFXI PS-like ADPCM) diff --git a/src/Makefile b/src/Makefile index 450e2027..c11dfc74 100644 --- a/src/Makefile +++ b/src/Makefile @@ -252,7 +252,8 @@ META_OBJS=meta/adx_header.o \ meta/ffw.o \ meta/ps2_jstm.o \ meta/ps3_xvag.o \ - meta/ps3_cps.o + meta/ps3_cps.o \ + meta/se_scd.o OBJECTS=vgmstream.o streamfile.o util.o $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS) diff --git a/src/coding/coding.h b/src/coding/coding.h index 62665694..f6635c09 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -79,6 +79,7 @@ void decode_fake_mpeg2_l2(VGMSTREAMCHANNEL * stream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do); mpeg_codec_data *init_mpeg_codec_data(STREAMFILE *streamfile, off_t start_offset, long given_sample_rate, int given_channels, coding_t *coding_type); +long mpeg_bytes_to_samples(long bytes, const struct mpg123_frameinfo *mi); void decode_mpeg(VGMSTREAMCHANNEL * stream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels); @@ -94,6 +95,7 @@ void decode_acm(ACMStream * acm, sample * outbuf, void decode_nwa(NWAData *nwa, sample *outbuf, int32_t samples_to_do); +long msadpcm_bytes_to_samples(long bytes, int block_size, int channels); void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do); void decode_msadpcm_mono(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do); diff --git a/src/coding/mpeg_decoder.c b/src/coding/mpeg_decoder.c index d16edf90..0a0c1a11 100644 --- a/src/coding/mpeg_decoder.c +++ b/src/coding/mpeg_decoder.c @@ -214,4 +214,8 @@ void decode_mpeg(VGMSTREAMCHANNEL *stream, } } +long mpeg_bytes_to_samples(long bytes, const struct mpg123_frameinfo *mi) { + return bytes * mi->rate * 8 / (mi->bitrate * 1000); +} + #endif diff --git a/src/coding/msadpcm_decoder.c b/src/coding/msadpcm_decoder.c index f7365316..04a9add0 100644 --- a/src/coding/msadpcm_decoder.c +++ b/src/coding/msadpcm_decoder.c @@ -21,6 +21,10 @@ static const int ADPCMCoeffs[7][2] = { 392, -232 } }; +long msadpcm_bytes_to_samples(long bytes, int block_size, int channels) { + return bytes/block_size*((block_size-(7-1)*channels)*2/channels); +} + void decode_msadpcm_stereo(VGMSTREAM * vgmstream, sample * outbuf, int32_t first_sample, int32_t samples_to_do) { VGMSTREAMCHANNEL *ch1,*ch2; int i; diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index ff032998..e1c01672 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -890,6 +890,10 @@ RelativePath=".\meta\sdt.c" > + + diff --git a/src/meta/Makefile.unix.am b/src/meta/Makefile.unix.am index a3d24d81..8bed5ea5 100644 --- a/src/meta/Makefile.unix.am +++ b/src/meta/Makefile.unix.am @@ -205,5 +205,6 @@ libmeta_la_SOURCES += ffw.c libmeta_la_SOURCES += ps2_jstm.c libmeta_la_SOURCES += ps3_xvag.c libmeta_la_SOURCES += ps3_cps.c +libmeta_la_SOURCES += se_scd.c EXTRA_DIST = meta.h diff --git a/src/meta/meta.h b/src/meta/meta.h index ad8606cf..e315513c 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -521,5 +521,6 @@ VGMSTREAM * init_vgmstream_ps3_xvag(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_ps3_cps(STREAMFILE* streamFile); +VGMSTREAM * init_vgmstream_se_scd(STREAMFILE* streamFile); #endif diff --git a/src/meta/se_scd.c b/src/meta/se_scd.c new file mode 100644 index 00000000..2925ea9d --- /dev/null +++ b/src/meta/se_scd.c @@ -0,0 +1,143 @@ +#include "meta.h" +#include "../coding/coding.h" +#include "../util.h" + +/* Square-Enix SCD (FF XIII, XIV) */ +VGMSTREAM * init_vgmstream_se_scd(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + off_t start_offset, meta_offset_offset, meta_offset, size_offset; + int32_t loop_start, loop_end; + + int loop_flag = 0; + int channel_count; + int codec_id; + + int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; + int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("scd",filename_extension(filename))) goto fail; + + /* SEDB */ + if (read_32bitBE(0,streamFile) != 0x53454442) goto fail; + /* SSCF */ + if (read_32bitBE(4,streamFile) != 0x53534346) goto fail; + if (read_32bitBE(8,streamFile) == 2) { + /* version 2 BE, as seen in FFXIII for PS3 */ + read_32bit = read_32bitBE; + read_16bit = read_16bitBE; + size_offset = 0x14; + meta_offset_offset = 0x70; + } else if (read_32bitLE(8,streamFile) == 3 || + read_32bitLE(8,streamFile) == 2) { + /* version 2/3 LE, as seen in FFXIV for ?? */ + read_32bit = read_32bitLE; + read_16bit = read_16bitLE; + size_offset = 0x10; + meta_offset_offset = 0x70; + } else goto fail; + + /* check file size with header value */ + if (read_32bit(size_offset,streamFile) != get_streamfile_size(streamFile)) + goto fail; + + /* this is probably some kind of chunk offset (?) */ + meta_offset = read_32bit(0x70,streamFile); + + /* check that chunk size equals stream size (?) */ + loop_start = read_32bit(meta_offset+0x10,streamFile); + loop_end = read_32bit(meta_offset+0x14,streamFile); + loop_flag = (loop_end > 0); + + channel_count = read_32bit(meta_offset+4,streamFile); + codec_id = read_32bit(meta_offset+0xc,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->channels = channel_count; + vgmstream->sample_rate = read_32bit(meta_offset+8,streamFile); + start_offset = meta_offset + 0x20 + read_32bit(meta_offset+0x18,streamFile); + + switch (codec_id) { + case 0x1: + /* PCM */ + vgmstream->coding_type = coding_PCM16LE_int; + vgmstream->layout_type = layout_none; + vgmstream->num_samples = read_32bit(meta_offset+0,streamFile) / 2 / channel_count; + + if (loop_flag) { + vgmstream->loop_start_sample = loop_start / 2 / channel_count; + vgmstream->loop_end_sample = loop_end / 2 / channel_count; + } + break; +#ifdef VGM_USE_MPEG + case 0x7: + /* MPEG */ + { + mpeg_codec_data *mpeg_data = NULL; + struct mpg123_frameinfo mi; + coding_t ct; + + mpeg_data = init_mpeg_codec_data(streamFile, start_offset, vgmstream->sample_rate, vgmstream->channels, &ct); + if (!mpeg_data) goto fail; + vgmstream->codec_data = mpeg_data; + + if (MPG123_OK != mpg123_info(mpeg_data->m, &mi)) goto fail; + + vgmstream->coding_type = ct; + vgmstream->layout_type = layout_mpeg; + if (mi.vbr != MPG123_CBR) goto fail; + vgmstream->num_samples = mpeg_bytes_to_samples(read_32bit(meta_offset+0,streamFile), &mi); + if (loop_flag) { + vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, &mi); + vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, &mi); + } + vgmstream->interleave_block_size = 0; + } + break; +#endif + case 0xC: + /* MS ADPCM */ + vgmstream->coding_type = coding_MSADPCM; + vgmstream->layout_type = layout_none; + vgmstream->interleave_block_size = read_16bit(meta_offset+0x2c,streamFile); + vgmstream->num_samples = msadpcm_bytes_to_samples(read_32bit(meta_offset+0,streamFile), vgmstream->interleave_block_size, vgmstream->channels); + + if (loop_flag) { + vgmstream->loop_start_sample = msadpcm_bytes_to_samples(loop_start, vgmstream->interleave_block_size, vgmstream->channels); + vgmstream->loop_end_sample = msadpcm_bytes_to_samples(loop_end, vgmstream->interleave_block_size, vgmstream->channels); + } + break; + default: + goto fail; + } + + vgmstream->meta_type = meta_SE_SCD; + + /* open the file for reading */ + { + int i; + STREAMFILE * file; + file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!file) goto fail; + for (i=0;ich[i].streamfile = file; + + vgmstream->ch[i].channel_start_offset= + vgmstream->ch[i].offset=start_offset; + + } + } + + return vgmstream; + + /* clean up anything we may have opened */ +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/src/vgmstream.c b/src/vgmstream.c index 9f843258..310aa3bf 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -283,6 +283,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_ps2_jstm, init_vgmstream_ps3_xvag, init_vgmstream_ps3_cps, + init_vgmstream_se_scd, }; #define INIT_VGMSTREAM_FCNS (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0])) @@ -2664,6 +2665,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { break; case meta_PS3_CPS: snprintf(temp,TEMPSIZE,"CPS Header"); + break; + case meta_SE_SCD: + snprintf(temp,TEMPSIZE,"Square-Enix SCD"); break; default: snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET"); diff --git a/src/vgmstream.h b/src/vgmstream.h index b058bf57..7d2b8208 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -484,6 +484,7 @@ typedef enum { meta_PS2_JSTM, /* Tantei Jinguji Saburo - Kind of Blue (PS2) */ meta_PS3_XVAG, /* Ratchet & Clank Future: Quest for Booty (PS3) */ meta_PS3_CPS, /* Eternal Sonata (PS3) */ + meta_SE_SCD, /* Square-Enix SCD */ } meta_t; typedef struct { diff --git a/unix/data.c b/unix/data.c index b086de1b..5c7b1dad 100644 --- a/unix/data.c +++ b/unix/data.c @@ -169,6 +169,7 @@ gchar *vgmstream_exts [] = { "sad", "sap", "sc", + "scd", "sck", "sd9", "sdt", diff --git a/winamp/in_vgmstream.c b/winamp/in_vgmstream.c index 09913bb6..181489f9 100644 --- a/winamp/in_vgmstream.c +++ b/winamp/in_vgmstream.c @@ -235,6 +235,7 @@ char * extension_list[] = { "sad\0SAD Audio File (*.SAD)\0", "sap\0SAP Audio File (*.SAP)\0", "sc\0SC Audio File (*.SC)\0", + "scd\0SCD Audio File (*.SCD)\0", "sck\0SCK Audio File (*.SCK)\0", "sd9\0SD9 Audio File (*.SD9)\0", "sdt\0SDT Audio File (*.SDT)\0",