diff --git a/readme.txt b/readme.txt index ef58b46f..9144be1f 100644 --- a/readme.txt +++ b/readme.txt @@ -92,6 +92,7 @@ File types supported by this version of vgmstream: - .wsi (Wii DSP ADPCM) - .aifc (SDX2 DPCM, DVI IMA ADPCM) - .aiff (8/16 bit PCM) +- .str (SDX2 DPCM) Enjoy! -hcs diff --git a/src/Makefile b/src/Makefile index 43af9e19..d281d6b8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -19,7 +19,8 @@ LAYOUT_OBJS=layout/ast_blocked.o \ layout/xa_blocked.o \ layout/caf_blocked.o \ layout/ea_block.o \ - layout/wsi_blocked.o + layout/wsi_blocked.o \ + layout/str_ctrl_blocked.o META_OBJS=meta/adx_header.o \ meta/afc_header.o \ @@ -58,7 +59,8 @@ META_OBJS=meta/adx_header.o \ meta/genh.o \ meta/ogg_vorbis_file.o \ meta/ps2_bmdx.o \ - meta/aifc.o + meta/aifc.o \ + meta/str_ctrl.o OBJECTS=vgmstream.o streamfile.o util.o $(CODING_OBJS) $(LAYOUT_OBJS) $(META_OBJS) diff --git a/src/layout/Makefile.unix.am b/src/layout/Makefile.unix.am index 3165f4f6..d936c6e6 100644 --- a/src/layout/Makefile.unix.am +++ b/src/layout/Makefile.unix.am @@ -4,6 +4,6 @@ AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir) AM_MAKEFLAGS=-f Makefile.unix liblayout_la_LDFLAGS = -liblayout_la_SOURCES = ast_blocked.c blocked.c caf_blocked.c ea_block.c halpst_blocked.c interleave.c nolayout.c xa_blocked.c wsi_blocked.c +liblayout_la_SOURCES = ast_blocked.c blocked.c caf_blocked.c ea_block.c halpst_blocked.c interleave.c nolayout.c xa_blocked.c wsi_blocked.c str_ctrl_blocked.c EXTRA_DIST = layout.h diff --git a/src/layout/blocked.c b/src/layout/blocked.c index a6ad0e37..ba6feb89 100644 --- a/src/layout/blocked.c +++ b/src/layout/blocked.c @@ -60,6 +60,9 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * case layout_wsi_blocked: wsi_block_update(vgmstream->next_block_offset,vgmstream); break; + case layout_str_ctrl_blocked: + str_ctrl_block_update(vgmstream->next_block_offset,vgmstream); + break; default: break; } diff --git a/src/layout/layout.h b/src/layout/layout.h index 9b3f9e29..559b8fba 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -18,6 +18,8 @@ void caf_block_update(off_t block_offset, VGMSTREAM * vgmstream); void wsi_block_update(off_t block_offset, VGMSTREAM * vgmstream); +void str_ctrl_block_update(off_t block_offset, VGMSTREAM * vgmstream); + void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); void render_vgmstream_nolayout(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream); diff --git a/src/layout/str_ctrl_blocked.c b/src/layout/str_ctrl_blocked.c new file mode 100644 index 00000000..cdd7f927 --- /dev/null +++ b/src/layout/str_ctrl_blocked.c @@ -0,0 +1,54 @@ +#include "layout.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void str_ctrl_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + off_t current_chunk; + size_t file_size; + int i; + STREAMFILE *streamfile; + int FoundSSMP = 0; + off_t SSMP_offset = -1; + + current_chunk = block_offset; + streamfile = vgmstream->ch[0].streamfile; + file_size = get_streamfile_size(streamfile); + + /* we may have to skip some chunks */ + while (!FoundSSMP && current_chunk < file_size) { + if (current_chunk+read_32bitBE(current_chunk+4,streamfile)>=file_size) + break; + switch (read_32bitBE(current_chunk,streamfile)) { + case 0x534e4453: /* SNDS */ + /* SSMP */ + if (read_32bitBE(current_chunk+0x10,streamfile)==0x53534d50) { + FoundSSMP = 1; + SSMP_offset = current_chunk; + } + break; + case 0x46494c4c: /* FILL, the main culprit */ + default: + break; + } + + current_chunk += read_32bitBE(current_chunk+4,streamfile); + } + + if (!FoundSSMP) { + /* if we couldn't find it all we can do is try playing the current + * block, which is going to suck */ + vgmstream->current_block_offset = block_offset; + } + + vgmstream->current_block_offset = SSMP_offset; + vgmstream->current_block_size = (read_32bitBE( + vgmstream->current_block_offset+4, + vgmstream->ch[0].streamfile) - 0x18) * vgmstream->channels; + vgmstream->next_block_offset = vgmstream->current_block_offset + + read_32bitBE(vgmstream->current_block_offset+4, + vgmstream->ch[0].streamfile); + + for (i=0;ichannels;i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset + 0x18; + } +} diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 9f8a0268..cb054b64 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -346,6 +346,10 @@ RelativePath=".\meta\aifc.c" > + + + + diff --git a/src/meta/Makefile.unix.am b/src/meta/Makefile.unix.am index 357d3ec5..5ce8b549 100644 --- a/src/meta/Makefile.unix.am +++ b/src/meta/Makefile.unix.am @@ -4,6 +4,6 @@ AM_CFLAGS = -Wall @CFLAGS@ -I$(top_builddir) -I$(top_srcdir) AM_MAKEFLAGS=-f Makefile.unix libmeta_la_LDFLAGS = -libmeta_la_SOURCES = Cstr.c adx_header.c afc_header.c agsc.c ast.c brstm.c ea_header.c gcsw.c halpst.c nds_strm.c ngc_adpdtk.c ngc_caf.c ngc_dsp_std.c ps2_ads.c ps2_exst.c ps2_ild.c ps2_int.c ps2_mib.c ps2_mic.c ps2_npsf.c ps2_pnb.c ps2_rxw.c ps2_str.c ps2_svag.c ps2_vag.c ps2_vpk.c psx_cdxa.c raw.c rs03.c rsf.c rwsd.c psx_gms.c xbox_xwav.c xbox_wavm.c genh.c ogg_vorbis_file.c ps2_bmdx.c aifc.c +libmeta_la_SOURCES = Cstr.c adx_header.c afc_header.c agsc.c ast.c brstm.c ea_header.c gcsw.c halpst.c nds_strm.c ngc_adpdtk.c ngc_caf.c ngc_dsp_std.c ps2_ads.c ps2_exst.c ps2_ild.c ps2_int.c ps2_mib.c ps2_mic.c ps2_npsf.c ps2_pnb.c ps2_rxw.c ps2_str.c ps2_svag.c ps2_vag.c ps2_vpk.c psx_cdxa.c raw.c rs03.c rsf.c rwsd.c psx_gms.c xbox_xwav.c xbox_wavm.c genh.c ogg_vorbis_file.c ps2_bmdx.c aifc.c str_ctrl.c EXTRA_DIST = meta.h diff --git a/src/meta/meta.h b/src/meta/meta.h index 8514e1bc..130ddf1b 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -93,4 +93,6 @@ VGMSTREAM * init_vgmstream_wsi(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_aifc(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_str_ctrl(STREAMFILE * streamFile); + #endif diff --git a/src/meta/str_ctrl.c b/src/meta/str_ctrl.c new file mode 100644 index 00000000..7187b1c6 --- /dev/null +++ b/src/meta/str_ctrl.c @@ -0,0 +1,115 @@ +#include "meta.h" +#include "../coding/coding.h" +#include "../layout/layout.h" +#include "../util.h" + +/* 3DO format, .str extension and CTRL header, blocks and AIFF-C style + * format specifier. Blocks are not IFF-compliant. */ + +VGMSTREAM * init_vgmstream_str_ctrl(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + char filename[260]; + + int channel_count; + int loop_flag = 0; + off_t SHDR_offset = -1; + int FoundSHDR = 0; + + size_t file_size; + + /* check extension, case insensitive */ + streamFile->get_name(streamFile,filename,sizeof(filename)); + if (strcasecmp("str",filename_extension(filename))) goto fail; + + /* check for opening CTRL chunk */ + if (read_32bitBE(0x0,streamFile) != 0x4354524c) /* CTRL */ + goto fail; + + file_size = get_streamfile_size(streamFile); + + /* scan chunks until we find a SNDS containing a SHDR */ + { + off_t current_chunk; + + current_chunk = read_32bitBE(0x4,streamFile) + 0; + + while (!FoundSHDR && current_chunk < file_size) { + if (current_chunk < 0) goto fail; + + if (current_chunk+read_32bitBE(current_chunk+4,streamFile) >= + file_size) goto fail; + + switch (read_32bitBE(current_chunk,streamFile)) { + case 0x534e4453: /* SNDS */ + switch (read_32bitBE(current_chunk+16,streamFile)) { + case 0x53484452: /* SHDR */ + FoundSHDR = 1; + SHDR_offset = current_chunk+16; + break; + default: + break; + } + break; + default: + /* ignore others for now */ + break; + } + + current_chunk += read_32bitBE(current_chunk+4,streamFile); + } + } + + if (!FoundSHDR) goto fail; + + /* details */ + channel_count = read_32bitBE(SHDR_offset+0x20,streamFile); + loop_flag = 0; + + /* build the VGMSTREAM */ + + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->num_samples = + read_32bitBE(SHDR_offset+0x2c,streamFile) * /* frame count? */ + read_32bitBE(SHDR_offset+0x18,streamFile); /* frame size? */ + vgmstream->sample_rate = read_32bitBE(SHDR_offset+0x1c,streamFile); + /* channels and loop flag are set by allocate_vgmstream */ + if (loop_flag) { + vgmstream->loop_start_sample = 0; + vgmstream->loop_end_sample = vgmstream->num_samples; + } + + switch (read_32bitBE(SHDR_offset+0x24,streamFile)) { + case 0x53445832: /* SDX2 */ + vgmstream->coding_type = coding_SDX2; + vgmstream->interleave_block_size = 1; + break; + default: + goto fail; + } + vgmstream->layout_type = layout_str_ctrl_blocked; + vgmstream->meta_type = meta_STR_CTRL; + + /* open the file for reading by each channel */ + { + int i; + vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename, + STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!vgmstream->ch[0].streamfile) goto fail; + for (i=0;ich[i].streamfile = vgmstream->ch[0].streamfile; + } + } + + /* start me up */ + str_ctrl_block_update(0,vgmstream); + + 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 83336459..f6cf0304 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -62,6 +62,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_ps2_bmdx, init_vgmstream_wsi, init_vgmstream_aifc, + init_vgmstream_str_ctrl, }; #define INIT_VGMSTREAM_FCNS (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0])) @@ -271,6 +272,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre case layout_ea_blocked: case layout_caf_blocked: case layout_wsi_blocked: + case layout_str_ctrl_blocked: render_vgmstream_blocked(buffer,sample_count,vgmstream); break; } @@ -725,6 +727,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { snprintf(temp,TEMPSIZE,"Ogg"); break; #endif + case layout_str_ctrl_blocked: + snprintf(temp,TEMPSIZE,".str CTRL blocked"); + break; default: snprintf(temp,TEMPSIZE,"INCONCEIVABLE"); } @@ -922,6 +927,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { case meta_AIFF: snprintf(temp,TEMPSIZE,"Audio Interchange File Format"); break; + case meta_STR_CTRL: + snprintf(temp,TEMPSIZE,".str CTRL SHDR chunk"); + break; default: snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET"); } diff --git a/src/vgmstream.h b/src/vgmstream.h index 5c995132..3bfb9cd3 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -56,6 +56,7 @@ typedef enum { layout_ea_blocked, layout_caf_blocked, layout_wsi_blocked, + layout_str_ctrl_blocked, #if 0 layout_strm_blocked, /* */ #endif @@ -142,6 +143,7 @@ typedef enum { meta_AIFC, /* Audio Interchange File Format AIFF-C */ meta_AIFF, /* Audio Interchange File Format */ + meta_STR_CTRL, /* .str with CTRL header */ } meta_t; typedef struct {