From 17da12f324a30f5aff222ed7eeafde0dea898b60 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 23 Nov 2017 22:32:31 +0100 Subject: [PATCH 01/17] Add Namco AAC (.naac) [Ace Combat: Assault Horizon Legacy (3DS)] --- src/formats.c | 10 +++-- src/libvgmstream.vcproj | 4 ++ src/libvgmstream.vcxproj | 1 + src/libvgmstream.vcxproj.filters | 3 ++ src/meta/meta.h | 2 + src/meta/naac.c | 66 ++++++++++++++++++++++++++++++++ src/vgmstream.c | 1 + src/vgmstream.h | 3 +- 8 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 src/meta/naac.c diff --git a/src/formats.c b/src/formats.c index 3a9822e9..96b290c1 100644 --- a/src/formats.c +++ b/src/formats.c @@ -192,6 +192,7 @@ static const char* extension_list[] = { "mxst", "myspd", + "naac", "ndp", "ngca", "nps", @@ -265,7 +266,7 @@ static const char* extension_list[] = { "sl3", "sli", "smp", - "smpl", + "smpl", //fake extension (to be removed) "snd", "snds", "sng", @@ -681,7 +682,7 @@ static const meta_info meta_info_list[] = { {meta_XBOX_WVS, "Metal Arms WVS Header (XBOX)"}, {meta_NGC_WVS, "Metal Arms WVS Header (GameCube)"}, {meta_XBOX_MATX, "assumed Matrix file by .matx extension"}, - {meta_DE2, "gurumin .de2 with embedded funky RIFF"}, + {meta_DE2, "Falcom DEC/DE2 RIFF header"}, {meta_VS, "Men in Black VS Header"}, {meta_DC_STR, "Sega Stream Asset Builder header"}, {meta_DC_STR_V2, "variant of Sega Stream Asset Builder header"}, @@ -796,12 +797,12 @@ static const meta_info meta_info_list[] = { {meta_S14, "Namco .S14 raw header"}, {meta_SSS, "Namco .SSS raw header"}, {meta_PS2_GCM, "GCM 'MCG' Header"}, - {meta_PS2_SMPL, "Homura 'SMPL' Header"}, + {meta_PS2_SMPL, "Homura SMPL header"}, {meta_PS2_MSA, "Psyvariar -Complete Edition- MSA header"}, {meta_PC_SMP, "Ghostbusters .smp Header"}, {meta_NGC_PDT, "PDT DSP header"}, {meta_NGC_BO2, "Blood Omen 2 DSP header"}, - {meta_P3D, "Radical P3D Header"}, + {meta_P3D, "Radical P3D header"}, {meta_PS2_TK1, "Tekken TK5STRM1 Header"}, {meta_PS2_ADSC, "ADSC Header"}, {meta_NGC_DSP_MPDS, "MPDS DSP header"}, @@ -900,6 +901,7 @@ static const meta_info meta_info_list[] = { {meta_PC_AL2, "Illwinter Game Design AL2 raw header"}, {meta_PC_AST, "Capcom AST (PC) header"}, {meta_UBI_SB, "Ubisoft SBx header"}, + {meta_NAAC, "Namco NAAC header"}, #ifdef VGM_USE_VORBIS {meta_OGG_VORBIS, "Ogg Vorbis"}, diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 0783f67b..9b3157f3 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -514,6 +514,10 @@ RelativePath=".\meta\myspd.c" > + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 64d57727..ba16f101 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -259,6 +259,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 137aeaba..dcb65287 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -295,6 +295,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files diff --git a/src/meta/meta.h b/src/meta/meta.h index fcb64f80..86fa5ee8 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -687,6 +687,8 @@ VGMSTREAM * init_vgmstream_pc_al2(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_pc_ast(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_naac(STREAMFILE * streamFile); + VGMSTREAM * init_vgmstream_ubi_sb(STREAMFILE * streamFile); #endif /*_META_H*/ diff --git a/src/meta/naac.c b/src/meta/naac.c new file mode 100644 index 00000000..b657e598 --- /dev/null +++ b/src/meta/naac.c @@ -0,0 +1,66 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* .NAAC - from Namco 3DS games (Ace Combat - Assault Horizon Legacy, Taiko no Tatsujin Don to Katsu no Jikuu Daibouken) */ +VGMSTREAM * init_vgmstream_naac(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int loop_flag, channel_count; + size_t data_size; + + /* check extension */ + if ( !check_extensions(streamFile,"naac") ) + goto fail; + + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x41414320) /* "AAC " */ + goto fail; + if (read_32bitLE(0x04,streamFile) != 0x01) /* version? */ + goto fail; + + start_offset = 0x1000; + loop_flag = (read_32bitLE(0x18,streamFile) != 0); + channel_count = read_32bitLE(0x08,streamFile); + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = read_32bitLE(0x0c,streamFile); + vgmstream->num_samples = read_32bitLE(0x10,streamFile); /* without skip_samples */ + vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile); /* with skip_samples */ + vgmstream->loop_end_sample = read_32bitLE(0x18,streamFile); + /* 0x1c: loop start offset, 0x20: loop end offset (within data) */ + data_size = read_32bitLE(0x24,streamFile); + /* 0x28: unknown; 0x2c: table start offset?; 0x30: seek table (always 0xFD0, padded) */ + + vgmstream->meta_type = meta_NAAC; + +#ifdef VGM_USE_FFMPEG + { + ffmpeg_codec_data *ffmpeg_data = NULL; + + ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,data_size); + if (!ffmpeg_data) goto fail; + vgmstream->codec_data = ffmpeg_data; + vgmstream->coding_type = coding_FFmpeg; + vgmstream->layout_type = layout_none; + + /* observed default, some files start without silence though seems correct when loop_start=0 */ + if (!ffmpeg_data->skipSamples) /* FFmpeg doesn't seem to use not report it */ + ffmpeg_set_skip_samples(ffmpeg_data, 1024); + vgmstream->num_samples -= 1024; + } +#else + goto fail; +#endif + + /* open the file for reading */ + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/src/vgmstream.c b/src/vgmstream.c index 7c6c4ef7..f3b7fa7f 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -368,6 +368,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_nsw_opus, init_vgmstream_pc_al2, init_vgmstream_pc_ast, + init_vgmstream_naac, init_vgmstream_ubi_sb, init_vgmstream_txth, /* should go at the end (lower priority) */ diff --git a/src/vgmstream.h b/src/vgmstream.h index 5c749af4..e13fbbe8 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -239,7 +239,7 @@ typedef enum { layout_hwas_blocked, layout_ea_sns_blocked, /* newest Electronic Arts blocks, found in SNS/SNU/SPS/etc formats */ layout_blocked_awc, /* Rockstar AWC */ - layout_blocked_vgs, /* Guitar Hero II */ + layout_blocked_vgs, /* Guitar Hero II (PS2) */ /* otherwise odd */ layout_acm, /* libacm layout */ @@ -627,6 +627,7 @@ typedef enum { meta_NSW_OPUS, /* Lego City Undercover (Switch) */ meta_PC_AL2, /* Conquest of Elysium 3 (PC) */ meta_PC_AST, /* Dead Rising (PC) */ + meta_NAAC, /* Namco AAC (3DS) */ meta_UBI_SB, /* Ubisoft banks */ #ifdef VGM_USE_VORBIS From 6d80168879c00bbb16feccf891e09483568b19a3 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 23 Nov 2017 22:33:46 +0100 Subject: [PATCH 02/17] Fix Homura (PS2) stereo and add .v0 --- fb2k/foo_filetypes.h | 3 ++ src/formats.c | 1 + src/meta/ps2_smpl.c | 72 ++++++++++++++++++++++++-------------------- 3 files changed, 44 insertions(+), 32 deletions(-) diff --git a/fb2k/foo_filetypes.h b/fb2k/foo_filetypes.h index 6e15da73..ffca17de 100644 --- a/fb2k/foo_filetypes.h +++ b/fb2k/foo_filetypes.h @@ -100,6 +100,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("DBM", dbm); VGMSTREAM_DECLARE_FILE_TYPE("DCS", dcs); VGMSTREAM_DECLARE_FILE_TYPE("DDSP", ddsp); VGMSTREAM_DECLARE_FILE_TYPE("DE2", de2); +VGMSTREAM_DECLARE_FILE_TYPE("DEC", dec); VGMSTREAM_DECLARE_FILE_TYPE("DMSG", dmsg); VGMSTREAM_DECLARE_FILE_TYPE("DSP", dsp); VGMSTREAM_DECLARE_FILE_TYPE("DSPW", dspw); @@ -199,6 +200,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("MWV", mwv); VGMSTREAM_DECLARE_FILE_TYPE("MxSt", mxst); VGMSTREAM_DECLARE_FILE_TYPE("MYSPD", myspd); +VGMSTREAM_DECLARE_FILE_TYPE("NAAC", naac); VGMSTREAM_DECLARE_FILE_TYPE("NDP", ndp); VGMSTREAM_DECLARE_FILE_TYPE("NGCA", ngca); VGMSTREAM_DECLARE_FILE_TYPE("NPS", nps); @@ -363,6 +365,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("XWMA", xwma); VGMSTREAM_DECLARE_FILE_TYPE("XWS", xws); VGMSTREAM_DECLARE_FILE_TYPE("XWV", xwv); +VGMSTREAM_DECLARE_FILE_TYPE("V0", v0); VGMSTREAM_DECLARE_FILE_TYPE("YDSP", ydsp); VGMSTREAM_DECLARE_FILE_TYPE("YMF", ymf); diff --git a/src/formats.c b/src/formats.c index 96b290c1..981291fb 100644 --- a/src/formats.c +++ b/src/formats.c @@ -308,6 +308,7 @@ static const char* extension_list[] = { "ulw", "um3", + "v0", "vag", "vas", "vawx", diff --git a/src/meta/ps2_smpl.c b/src/meta/ps2_smpl.c index 0c4b76f5..57e2ec5b 100644 --- a/src/meta/ps2_smpl.c +++ b/src/meta/ps2_smpl.c @@ -1,63 +1,71 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -/* SMPL (from Homura) */ +/* SMPL - from Homura */ VGMSTREAM * init_vgmstream_ps2_smpl(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; + STREAMFILE * streamRch = NULL; off_t start_offset; + int loop_flag, channel_count; + size_t channel_size; - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("smpl",filename_extension(filename))) goto fail; + /* check extension (.v0: left channel, .v1: right channel, .smpl: header id) */ + if ( !check_extensions(streamFile,"v0,smpl") ) + goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x534D504C) /* "SMPL" */ goto fail; - loop_flag = 1; - channel_count = 1; + /* right channel is in .V1 and doesn't have loop points; manually parse as dual_stereo would fail */ + streamRch = open_stream_ext(streamFile, "V1"); + channel_count = streamRch != NULL ? 2 : 1; + loop_flag = (read_32bitLE(0x30,streamFile) != 0); + start_offset = 0x40; + channel_size = read_32bitBE(0x0c,streamFile) - 0x10; - /* build the VGMSTREAM */ + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - start_offset = 0x40; - vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitBE(0x10,streamFile); - vgmstream->coding_type = coding_PSX_badflags; - vgmstream->num_samples = read_32bitBE(0xc,streamFile)*56/32; - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitLE(0x30,streamFile); - vgmstream->loop_end_sample = vgmstream->num_samples; - } - vgmstream->layout_type = layout_none; + vgmstream->num_samples = ps_bytes_to_samples(channel_size*channel_count, channel_count); + vgmstream->loop_start_sample = read_32bitLE(0x30,streamFile); + vgmstream->loop_end_sample = vgmstream->num_samples; + vgmstream->meta_type = meta_PS2_SMPL; + vgmstream->coding_type = coding_PSX; + vgmstream->layout_type = layout_none; + + /* always, but can be null or used as special string */ + read_string(vgmstream->stream_name,0x10+1, 0x20,streamFile); /* open the file for reading */ + //if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + // goto fail; + + /* custom dual channel */ // todo improve dual_stereo { int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; + char filename[PATH_LIMIT]; - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; + streamFile->get_name(streamFile,filename,sizeof(filename)); + vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename, STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!vgmstream->ch[0].streamfile) goto fail; + if (channel_count == 2) + vgmstream->ch[1].streamfile = streamRch; + + for (i = 0; i < channel_count; i++) { + 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); + if (streamRch) close_streamfile(streamRch); + close_vgmstream(vgmstream); return NULL; } From 162ec1fb9cfa11b1dd43f67db75f0561f04d9585 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 23 Nov 2017 22:36:49 +0100 Subject: [PATCH 03/17] Add/fix Falcom RIFF (.dec/de2) + looping [Xanadu Next, Gurumin (PC)] --- src/formats.c | 1 + src/layout/de2_blocked.c | 25 +++-- src/meta/de2.c | 216 +++++++++++++++++++++++++++------------ 3 files changed, 164 insertions(+), 78 deletions(-) diff --git a/src/formats.c b/src/formats.c index 981291fb..b8d14284 100644 --- a/src/formats.c +++ b/src/formats.c @@ -93,6 +93,7 @@ static const char* extension_list[] = { "dcs", "ddsp", "de2", + "dec", "dmsg", "dsp", "dspw", diff --git a/src/layout/de2_blocked.c b/src/layout/de2_blocked.c index a89ddbaf..52d65a32 100644 --- a/src/layout/de2_blocked.c +++ b/src/layout/de2_blocked.c @@ -1,18 +1,21 @@ #include "layout.h" -#include "../vgmstream.h" -/* set up for the block at the given offset */ +/* Falcom RIFF blocks (.DEC/DE2) */ void de2_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + STREAMFILE* streamFile = vgmstream->ch[0].streamfile; + size_t block_size, header_size; int i; - vgmstream->current_block_offset = block_offset; - vgmstream->current_block_size = read_32bitLE( - vgmstream->current_block_offset, - vgmstream->ch[0].streamfile); - vgmstream->next_block_offset = block_offset+8+read_32bitLE( - vgmstream->current_block_offset, - vgmstream->ch[0].streamfile); - for (i=0;ichannels;i++) { - vgmstream->ch[i].offset = vgmstream->current_block_offset + 8; + header_size = 0x08; + block_size = read_32bitLE(block_offset,streamFile); + /* 0x04: PCM size? */ + + vgmstream->current_block_offset = block_offset; + vgmstream->current_block_size = block_size; + vgmstream->next_block_offset = block_offset + block_size + header_size; + + /* MSADPCM = same offset per channel */ + for (i = 0; i < vgmstream->channels; i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset + header_size; } } diff --git a/src/meta/de2.c b/src/meta/de2.c index 83f004a7..6b457bb4 100644 --- a/src/meta/de2.c +++ b/src/meta/de2.c @@ -1,101 +1,183 @@ #include "meta.h" #include "../layout/layout.h" -#include "../util.h" -/* Gurumin .de2 */ -/* A ways into the file we have a fake RIFF header wrapping MS ADPCM */ +#define TXT_LINE_MAX 0x1000 +static int get_falcom_looping(STREAMFILE *streamFile, int *out_loop_start, int *out_loop_end); +/* .DEC/DE2 - from Falcom PC games (Xanadu Next, Zwei!!, VM Japan, Gurumin) */ VGMSTREAM * init_vgmstream_de2(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - - off_t riff_off; - int channel_count; - int sample_count; - int sample_rate; off_t start_offset; + off_t riff_off = 0x00; + size_t pcm_size = 0; + int loop_flag, channel_count, sample_rate, loop_start = 0, loop_end = 0; - int loop_flag = 0; - uint32_t data_size; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("de2",filename_extension(filename))) goto fail; - - /* still not sure what this is for, but consistently 0xb */ - if (read_32bitLE(0x04,streamFile)!=0xb) goto fail; - - /* legitimate! really! */ - riff_off = 0x10 + - (read_32bitLE(0x0c,streamFile) ^ read_32bitLE(0x04,streamFile)); - - /* check header */ - if ((uint32_t)read_32bitBE(riff_off+0,streamFile)!=0x52494646) /* "RIFF" */ + /* check extension (.dec: main, .de2: Gurumin) */ + if ( !check_extensions(streamFile,"dec,de2") ) goto fail; - /* check for WAVE form */ - if ((uint32_t)read_32bitBE(riff_off+8,streamFile)!=0x57415645) /* "WAVE" */ + + /* Gurumin has extra data, maybe related to rhythm (~0x50000) */ + if (check_extensions(streamFile,"de2")) { + /* still not sure what this is for, but consistently 0xb */ + if (read_32bitLE(0x04,streamFile) != 0xb) goto fail; + + /* legitimate! really! */ + riff_off = 0x10 + (read_32bitLE(0x0c,streamFile) ^ read_32bitLE(0x04,streamFile)); + } + + + /* fake PCM RIFF header (the original WAV's) wrapping MS-ADPCM */ + if (read_32bitBE(riff_off+0x00,streamFile) != 0x52494646 || /* "RIFF" */ + read_32bitBE(riff_off+0x08,streamFile) != 0x57415645) /* "WAVE" */ goto fail; - /* check for "fmt " */ - if ((uint32_t)read_32bitBE(riff_off+12,streamFile)!=0x666d7420) /* "fmt " */ + + if (read_32bitBE(riff_off+0x0c,streamFile) == 0x50414420) { /* "PAD " (Zwei!!), blank with wrong chunk size */ + sample_rate = 44100; + channel_count = 2; + pcm_size = read_32bitLE(riff_off+0x04,streamFile) - 0x24; + /* somehow there is garbage at the beginning of some tracks */ + } + else if (read_32bitBE(riff_off+0x0c,streamFile) == 0x666D7420) { /* "fmt " (rest) */ + //if (read_32bitLE(riff_off+0x10,streamFile) != 0x12) goto fail; /* 0x10 in some */ + if (read_16bitLE(riff_off+0x14,streamFile) != 0x01) goto fail; /* PCM (actually MS-ADPCM) */ + if (read_16bitLE(riff_off+0x20,streamFile) != 4 || + read_16bitLE(riff_off+0x22,streamFile) != 16) goto fail; /* 16-bit */ + + channel_count = read_16bitLE(riff_off+0x16,streamFile); + sample_rate = read_32bitLE(riff_off+0x18,streamFile); + if (read_32bitBE(riff_off+0x24,streamFile) == 0x64617461) { /* "data" size except in some Zwei!! */ + pcm_size = read_32bitLE(riff_off+0x28,streamFile); + } else { + pcm_size = read_32bitLE(riff_off+0x04,streamFile) - 0x24; + } + } + else { goto fail; - /* check for "data" */ - if ((uint32_t)read_32bitBE(riff_off+0x24,streamFile)!=0x64617461) /* "data" */ + } + + if (channel_count != 2) goto fail; - /* check for bad fmt chunk size */ - if (read_32bitLE(riff_off+0x10,streamFile)!=0x12) goto fail; - - sample_rate = read_32bitLE(riff_off+0x18,streamFile); - - channel_count = read_16bitLE(riff_off+0x16,streamFile); - if (channel_count != 2) goto fail; - - /* PCM */ - if (read_16bitLE(riff_off+0x14,streamFile) != 1) goto fail; - - /* 16-bit */ - if (read_16bitLE(riff_off+0x20,streamFile) != 4 || - read_16bitLE(riff_off+0x22,streamFile) != 16) goto fail; start_offset = riff_off + 0x2c; - data_size = read_32bitLE(riff_off+0x28,streamFile); + loop_flag = get_falcom_looping(streamFile, &loop_start, &loop_end); - sample_count = data_size/2/channel_count; /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - vgmstream->num_samples = sample_count; vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = pcm_size / 2 / channel_count; + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; vgmstream->coding_type = coding_MSADPCM; - vgmstream->layout_type = layout_de2_blocked; vgmstream->interleave_block_size = 0x800; + vgmstream->layout_type = layout_de2_blocked; - vgmstream->meta_type = meta_DE2; + vgmstream->meta_type = meta_DE2;//todo - /* open the file, set up each channel */ - { - int i; + /* open the file for reading */ + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; - 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 */ - de2_block_update(start_offset,vgmstream); + de2_block_update(start_offset, vgmstream); return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } + + +/* Falcom loves loop points in external text files, here we parse them */ +typedef enum { XANADU_NEXT, ZWEI, DINOSAUR_RESURRECTION, GURUMIN } falcom_loop_t; +static int get_falcom_looping(STREAMFILE *streamFile, int *out_loop_start, int *out_loop_end) { + STREAMFILE *streamText; + off_t txt_offset = 0x00; + falcom_loop_t type; + int loop_start = 0, loop_end = 0, loop_flag = 0; + char filename[TXT_LINE_MAX]; + + + /* try one of the many loop files */ + if ((streamText = open_stream_name(streamFile,"bgm.tbl")) != NULL) { + type = XANADU_NEXT; + } + else if ((streamText = open_stream_name(streamFile,"bgm.scr")) != NULL) { + type = ZWEI; + } + else if ((streamText = open_stream_name(streamFile,"loop.txt")) != NULL) { /* actual name in Shift JIS, 0x838B815B8376 */ + type = DINOSAUR_RESURRECTION; + } + else if ((streamText = open_stream_name(streamFile,"map.itm")) != NULL) { + type = GURUMIN; + } + else { + goto end; + } + + get_streamfile_name(streamFile,filename,TXT_LINE_MAX); + + /* read line by line */ + while (txt_offset < get_streamfile_size(streamText)) { + char line[TXT_LINE_MAX]; + char name[TXT_LINE_MAX]; + int ok, line_done, loop, bytes_read; + + bytes_read = get_streamfile_dos_line(TXT_LINE_MAX,line, txt_offset,streamText, &line_done); + if (!line_done) goto end; + + txt_offset += bytes_read; + + if (line[0]=='/' || line[0]=='#' || line[0]=='[' || line[0]=='\0') /* comment/empty */ + continue; + + /* each game changes line format, wee */ + switch(type) { + case XANADU_NEXT: /* "XANA000", 0, 0,99999990,0 */ + ok = sscanf(line,"\"%[^\"]\", %*d, %d, %d, %d", name,&loop_start,&loop_end,&loop); + if (ok == 4 && strncasecmp(filename,name,strlen(name)) == 0) { + loop_flag = (loop && loop_end != 0); + goto end; + } + break; + + case ZWEI: /* 1,.\wav\bgm01.wav,497010,7386720;//comment */ + ok = sscanf(line,"%*i,.\\wav\\%[^.].dec,%d,%d;%*s", name,&loop_start,&loop_end); + if (ok == 3 && strncasecmp(filename,name,strlen(name)) == 0) { + loop_flag = (loop_end != 9000000); + goto end; + } + break; + + case DINOSAUR_RESURRECTION: /* 01 970809 - 8015852 */ + strcpy(name,"dinow_"); /* for easier comparison */ + ok = sscanf(line,"%[^ ] %d - %d", (name+6), &loop_start,&loop_end); + if (ok == 3 && strncasecmp(filename,name,strlen(name)) == 0) { + loop_flag = 1; + goto end; + } + break; + + case GURUMIN: /* 0003 BGM03 dec 00211049 02479133 00022050 00000084 //comment */ + ok = sscanf(line,"%*i %[^ \t] %*[^ \t] %d %d %*d %*d %*s", name,&loop_start,&loop_end); + if (ok == 3 && strncasecmp(filename,name,strlen(name)) == 0) { + loop_flag = (loop_end != 99999999 && loop_end != 10000000); + goto end; + } + break; + } + } + +end: + if (loop_flag) { + *out_loop_start = loop_start; + *out_loop_end = loop_end; + } + + if (streamText) close_streamfile(streamText); + return loop_flag; +} From 7c7af0bf18f72998720a72cd023f6892e6352029 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 23 Nov 2017 22:48:11 +0100 Subject: [PATCH 04/17] Rename *_DE2 to _*DEC for consistency and since it was first --- README.md | 2 +- src/formats.c | 4 ++-- src/layout/blocked.c | 4 ++-- src/layout/{de2_blocked.c => blocked_dec.c} | 2 +- src/layout/layout.h | 2 +- src/libvgmstream.vcproj | 4 ++-- src/libvgmstream.vcxproj | 4 ++-- src/libvgmstream.vcxproj.filters | 4 ++-- src/meta/{de2.c => dec.c} | 8 ++++---- src/meta/meta.h | 2 +- src/vgmstream.c | 4 ++-- src/vgmstream.h | 4 ++-- 12 files changed, 22 insertions(+), 22 deletions(-) rename src/layout/{de2_blocked.c => blocked_dec.c} (90%) rename src/meta/{de2.c => dec.c} (97%) diff --git a/README.md b/README.md index 0dccce26..e0d322f5 100644 --- a/README.md +++ b/README.md @@ -277,7 +277,7 @@ This list is not complete and many other files are supported. - .bgw (PSX configurable ADPCM) - .bnsf (G.722.1) - .caf (Apple IMA4 ADPCM, others) - - .de2 (MS ADPCM) + - .dec/de2 (MS ADPCM) - .hca (CRI High Compression Audio) - .pcm/kcey (DVI IMA ADPCM) - .lsf (LSF ADPCM) diff --git a/src/formats.c b/src/formats.c index b8d14284..59700de6 100644 --- a/src/formats.c +++ b/src/formats.c @@ -528,7 +528,7 @@ static const layout_info layout_info_list[] = { {layout_str_snds_blocked, ".str SNDS blocked"}, {layout_ws_aud_blocked, "Westwood Studios .aud blocked"}, {layout_matx_blocked, "Matrix .matx blocked"}, - {layout_de2_blocked, "de2 blocked"}, + {layout_blocked_dec, "blocked (DEC)"}, {layout_vs_blocked, "vs blocked"}, {layout_emff_ps2_blocked, "EMFF (PS2) blocked"}, {layout_emff_ngc_blocked, "EMFF (NGC/WII) blocked"}, @@ -684,7 +684,7 @@ static const meta_info meta_info_list[] = { {meta_XBOX_WVS, "Metal Arms WVS Header (XBOX)"}, {meta_NGC_WVS, "Metal Arms WVS Header (GameCube)"}, {meta_XBOX_MATX, "assumed Matrix file by .matx extension"}, - {meta_DE2, "Falcom DEC/DE2 RIFF header"}, + {meta_DEC, "Falcom DEC RIFF header"}, {meta_VS, "Men in Black VS Header"}, {meta_DC_STR, "Sega Stream Asset Builder header"}, {meta_DC_STR_V2, "variant of Sega Stream Asset Builder header"}, diff --git a/src/layout/blocked.c b/src/layout/blocked.c index e0e73b76..923bce67 100644 --- a/src/layout/blocked.c +++ b/src/layout/blocked.c @@ -101,8 +101,8 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * case layout_matx_blocked: matx_block_update(vgmstream->next_block_offset,vgmstream); break; - case layout_de2_blocked: - de2_block_update(vgmstream->next_block_offset,vgmstream); + case layout_blocked_dec: + block_update_dec(vgmstream->next_block_offset,vgmstream); break; case layout_emff_ps2_blocked: emff_ps2_block_update(vgmstream->next_block_offset,vgmstream); diff --git a/src/layout/de2_blocked.c b/src/layout/blocked_dec.c similarity index 90% rename from src/layout/de2_blocked.c rename to src/layout/blocked_dec.c index 52d65a32..3a7809dc 100644 --- a/src/layout/de2_blocked.c +++ b/src/layout/blocked_dec.c @@ -1,7 +1,7 @@ #include "layout.h" /* Falcom RIFF blocks (.DEC/DE2) */ -void de2_block_update(off_t block_offset, VGMSTREAM * vgmstream) { +void block_update_dec(off_t block_offset, VGMSTREAM * vgmstream) { STREAMFILE* streamFile = vgmstream->ch[0].streamfile; size_t block_size, header_size; int i; diff --git a/src/layout/layout.h b/src/layout/layout.h index d0ab95ed..b794919b 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -29,7 +29,7 @@ void ws_aud_block_update(off_t block_offset, VGMSTREAM * vgmstream); void matx_block_update(off_t block_offset, VGMSTREAM * vgmstream); -void de2_block_update(off_t block_offset, VGMSTREAM * vgmstream); +void block_update_dec(off_t block_offset, VGMSTREAM * vgmstream); void vs_block_update(off_t block_offset, VGMSTREAM * vgmstream); diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 9b3157f3..76e1c5e9 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -325,7 +325,7 @@ > - + @@ -475,7 +475,7 @@ - + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index dcb65287..5235ed94 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -190,7 +190,7 @@ meta\Source Files - + meta\Source Files @@ -937,7 +937,7 @@ layout\Source Files - + layout\Source Files diff --git a/src/meta/de2.c b/src/meta/dec.c similarity index 97% rename from src/meta/de2.c rename to src/meta/dec.c index 6b457bb4..61a55f82 100644 --- a/src/meta/de2.c +++ b/src/meta/dec.c @@ -5,7 +5,7 @@ static int get_falcom_looping(STREAMFILE *streamFile, int *out_loop_start, int *out_loop_end); /* .DEC/DE2 - from Falcom PC games (Xanadu Next, Zwei!!, VM Japan, Gurumin) */ -VGMSTREAM * init_vgmstream_de2(STREAMFILE *streamFile) { +VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset; off_t riff_off = 0x00; @@ -74,15 +74,15 @@ VGMSTREAM * init_vgmstream_de2(STREAMFILE *streamFile) { vgmstream->coding_type = coding_MSADPCM; vgmstream->interleave_block_size = 0x800; - vgmstream->layout_type = layout_de2_blocked; + vgmstream->layout_type = layout_blocked_dec; - vgmstream->meta_type = meta_DE2;//todo + vgmstream->meta_type = meta_DEC; /* open the file for reading */ if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; - de2_block_update(start_offset, vgmstream); + block_update_dec(start_offset, vgmstream); return vgmstream; diff --git a/src/meta/meta.h b/src/meta/meta.h index 86fa5ee8..120247ba 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -252,7 +252,7 @@ VGMSTREAM * init_vgmstream_dc_str_v2(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_xbox_matx(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_de2(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_dec(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_vs(STREAMFILE *streamFile); diff --git a/src/vgmstream.c b/src/vgmstream.c index f3b7fa7f..087097c3 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -138,7 +138,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_dc_str, init_vgmstream_dc_str_v2, init_vgmstream_xbox_matx, - init_vgmstream_de2, + init_vgmstream_dec, init_vgmstream_vs, init_vgmstream_dc_str, init_vgmstream_dc_str_v2, @@ -921,7 +921,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre case layout_str_snds_blocked: case layout_ws_aud_blocked: case layout_matx_blocked: - case layout_de2_blocked: + case layout_blocked_dec: case layout_vs_blocked: case layout_emff_ps2_blocked: case layout_emff_ngc_blocked: diff --git a/src/vgmstream.h b/src/vgmstream.h index e13fbbe8..fe72dabb 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -219,7 +219,7 @@ typedef enum { layout_str_snds_blocked, layout_ws_aud_blocked, layout_matx_blocked, - layout_de2_blocked, + layout_blocked_dec, layout_xvas_blocked, layout_vs_blocked, layout_emff_ps2_blocked, @@ -487,7 +487,7 @@ typedef enum { meta_DC_KCEY, /* Konami KCE Yokohama KCEYCOMP (DC games) */ meta_ACM, /* InterPlay ACM header */ meta_MUS_ACM, /* MUS playlist of InterPlay ACM files */ - meta_DE2, /* Falcom (Gurumin) .de2 */ + meta_DEC, /* Falcom PC games (Xanadu Next, Gurumin) */ meta_VS, /* Men in Black .vs */ meta_FFXI_BGW, /* FFXI (PC) BGW */ meta_FFXI_SPW, /* FFXI (PC) SPW */ From dbbbfcc9f5cd6969df7e93ccc442c811b2c763f9 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 23 Nov 2017 22:53:43 +0100 Subject: [PATCH 05/17] Make get_streamfile_dos_line read CR/LF too and rename accordingly CR used in some Falcom looping files as separator --- src/meta/dec.c | 2 +- src/meta/mus_acm.c | 6 ++--- src/meta/sli.c | 2 +- src/streamfile.c | 66 +++++++++++++++++++++------------------------- src/streamfile.h | 2 +- 5 files changed, 36 insertions(+), 42 deletions(-) diff --git a/src/meta/dec.c b/src/meta/dec.c index 61a55f82..0d562b7a 100644 --- a/src/meta/dec.c +++ b/src/meta/dec.c @@ -127,7 +127,7 @@ static int get_falcom_looping(STREAMFILE *streamFile, int *out_loop_start, int * char name[TXT_LINE_MAX]; int ok, line_done, loop, bytes_read; - bytes_read = get_streamfile_dos_line(TXT_LINE_MAX,line, txt_offset,streamText, &line_done); + bytes_read = get_streamfile_text_line(TXT_LINE_MAX,line, txt_offset,streamText, &line_done); if (!line_done) goto end; txt_offset += bytes_read; diff --git a/src/meta/mus_acm.c b/src/meta/mus_acm.c index 85301b7f..185e2936 100644 --- a/src/meta/mus_acm.c +++ b/src/meta/mus_acm.c @@ -125,7 +125,7 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) { if (strcasecmp("mus",filename_extension(filename))) goto fail; /* read file name base */ - line_bytes = get_streamfile_dos_line(sizeof(line_buffer),line_buffer, + line_bytes = get_streamfile_text_line(sizeof(line_buffer),line_buffer, mus_offset, streamFile, &whole_line_read); if (!whole_line_read) goto fail; mus_offset += line_bytes; @@ -140,7 +140,7 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) { /*printf("name base: %s\n",name_base);*/ /* read track entry count */ - line_bytes = get_streamfile_dos_line(sizeof(line_buffer),line_buffer, + line_bytes = get_streamfile_text_line(sizeof(line_buffer),line_buffer, mus_offset, streamFile, &whole_line_read); if (!whole_line_read) goto fail; if (line_buffer[0] == '\0') goto fail; @@ -184,7 +184,7 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) { { int fields_matched; line_bytes = - get_streamfile_dos_line(sizeof(line_buffer),line_buffer, + get_streamfile_text_line(sizeof(line_buffer),line_buffer, mus_offset, streamFile, &whole_line_read); if (!whole_line_read) goto fail; mus_offset += line_bytes; diff --git a/src/meta/sli.c b/src/meta/sli.c index 78d2950d..a2852667 100644 --- a/src/meta/sli.c +++ b/src/meta/sli.c @@ -54,7 +54,7 @@ VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE *streamFile) { while ((loop_start == -1 || loop_length == -1) && sli_offset < get_streamfile_size(streamFile)) { char *endptr; char *foundptr; - bytes_read=get_streamfile_dos_line(sizeof(linebuffer),linebuffer,sli_offset,streamFile,&done); + bytes_read=get_streamfile_text_line(sizeof(linebuffer),linebuffer,sli_offset,streamFile,&done); if (!done) goto fail; if (!memcmp("LoopStart=",linebuffer,10) && linebuffer[10]!='\0') { diff --git a/src/streamfile.c b/src/streamfile.c index f1d4d07e..1545ae6c 100644 --- a/src/streamfile.c +++ b/src/streamfile.c @@ -298,63 +298,59 @@ STREAMFILE * open_stdio_streamfile_by_file(FILE * file, const char * filename) { /* **************************************************** */ -/* Read a line into dst. The source files are MS-DOS style, - * separated (not terminated) by CRLF. Return 1 if the full line was - * retrieved (if it could fit in dst), 0 otherwise. In any case the result - * will be properly terminated. The CRLF will be removed if there is one. - * Return the number of bytes read (including CRLF line ending). Note that - * this is not the length of the string, and could be larger than the buffer. - * *line_done_ptr is set to 1 if the complete line was read into dst, - * otherwise it is set to 0. line_done_ptr can be NULL if you aren't - * interested in this info. +/* Read a line into dst. The source files are lines separated by CRLF (Windows) / LF (Unux) / CR (Mac). + * The line will be null-terminated and CR/LF removed if found. + * + * Returns the number of bytes read (including CR/LF), note that this is not the string length. + * line_done_ptr is set to 1 if the complete line was read into dst; NULL can be passed to ignore. */ -size_t get_streamfile_dos_line(int dst_length, char * dst, off_t offset, - STREAMFILE * infile, int *line_done_ptr) -{ +size_t get_streamfile_text_line(int dst_length, char * dst, off_t offset, STREAMFILE * streamfile, int *line_done_ptr) { int i; - off_t file_length = get_streamfile_size(infile); - /* how many bytes over those put in the buffer were read */ - int extra_bytes = 0; + off_t file_length = get_streamfile_size(streamfile); + int extra_bytes = 0; /* how many bytes over those put in the buffer were read */ if (line_done_ptr) *line_done_ptr = 0; - for (i=0;iopen(streamFile,filename_ext,STREAMFILE_DEFAULT_BUFFER_SIZE); } -/* Opens an stream in the same folder */ +/* Opens an stream using the passed name (in the same folder) */ STREAMFILE * open_stream_name(STREAMFILE *streamFile, const char * name) { char foldername[PATH_LIMIT]; char filename[PATH_LIMIT]; diff --git a/src/streamfile.h b/src/streamfile.h index 914f2917..0398b5ae 100644 --- a/src/streamfile.h +++ b/src/streamfile.h @@ -156,7 +156,7 @@ static inline int8_t read_8bit(off_t offset, STREAMFILE * streamfile) { /* various STREAMFILE helpers functions */ -size_t get_streamfile_dos_line(int dst_length, char * dst, off_t offset, STREAMFILE * infile, int *line_done_ptr); +size_t get_streamfile_text_line(int dst_length, char * dst, off_t offset, STREAMFILE * streamfile, int *line_done_ptr); STREAMFILE * open_stream_ext(STREAMFILE *streamFile, const char * ext); STREAMFILE * open_stream_name(STREAMFILE *streamFile, const char * ext); From c2ef5f8694f1f6154dd0c1395c912134c41a5f44 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 23 Nov 2017 23:03:55 +0100 Subject: [PATCH 06/17] Use get_streamfile_text_line in TXTH (cleanup) --- src/meta/txth.c | 38 +++++++++++--------------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/src/meta/txth.c b/src/meta/txth.c index 1e7850a8..b7e4630d 100644 --- a/src/meta/txth.c +++ b/src/meta/txth.c @@ -3,7 +3,7 @@ #include "../layout/layout.h" #include "../util.h" -#define TXTH_LINE_MAX 0x2000 +#define TXT_LINE_MAX 0x2000 /* known TXTH types */ typedef enum { @@ -83,7 +83,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) { int i, j; /* no need for ID or ext checks -- if a .TXTH exists all is good - * (player still needs to accept the ext, so at worst rename to .vgmstream) */ + * (player still needs to accept the streamfile's ext, so at worst rename to .vgmstream) */ streamText = open_txth(streamFile); if (!streamText) goto fail; @@ -401,44 +401,28 @@ fail: /* Simple text parser of "key = value" lines. * The code is meh and error handling not exactly the best. */ static int parse_txth(STREAMFILE * streamFile, STREAMFILE * streamText, txth_header * txth) { - off_t off = 0; + off_t txt_offset = 0x00; off_t file_size = get_streamfile_size(streamText); txth->data_size = get_streamfile_size(streamFile); /* for later use */ /* skip BOM if needed */ if (read_16bitLE(0x00, streamText) == 0xFFFE || read_16bitLE(0x00, streamText) == 0xFEFF) - off = 0x02; + txt_offset = 0x02; /* read lines */ - while (off < file_size) { - char line[TXTH_LINE_MAX]; - char key[TXTH_LINE_MAX]; - char val[TXTH_LINE_MAX]; /* at least as big as a line to avoid overflows (I hope) */ - int ok; - off_t line_start = off, line_end = 0; - line[0] = key[0] = val[0] = 0; - - /* find line end */ - while (line_end == 0 && off - line_start < TXTH_LINE_MAX) { - char c = (char)read_8bit(off, streamText); - if (c == '\n') - line_end = off; - else if (off >= file_size) - line_end = off-1; + while (txt_offset < file_size) { + char line[TXT_LINE_MAX] = {0}; + char key[TXT_LINE_MAX] = {0}, val[TXT_LINE_MAX] = {0}; /* at least as big as a line to avoid overflows (I hope) */ + int ok, bytes_read, line_done; - off++; - } + bytes_read = get_streamfile_text_line(TXT_LINE_MAX,line, txt_offset,streamText, &line_done); + if (!line_done) goto fail; - if (line_end == 0) - goto fail; /* bad file / line too long */ + txt_offset += bytes_read; /* get key/val (ignores lead/trail spaces, stops at space/comment/separator) */ - read_streamfile((uint8_t*)line,line_start,line_end, streamText); - line[line_end - line_start + 1] = '\0'; ok = sscanf(line, " %[^ \t#=] = %[^ \t#\r\n] ", key,val); - //VGM_LOG("TXTH: ok=%i, key=\"%s\", val=\"%s\" from 0x%lx to 0x%lx\n", ok, key, val, line_start, line_end); - if (ok != 2) /* ignore line if no key=val (comment or garbage) */ continue; From e1bb468bd57e5c4d5fa69b0bd41c65d5b7e8ac9f Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 23 Nov 2017 23:11:11 +0100 Subject: [PATCH 07/17] Remove unnecessary check_sample_rate --- src/meta/aix.c | 2 +- src/util.c | 4 ---- src/util.h | 3 --- src/vgmstream.c | 4 ++-- 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/meta/aix.c b/src/meta/aix.c index 840af854..7ac2704a 100644 --- a/src/meta/aix.c +++ b/src/meta/aix.c @@ -61,7 +61,7 @@ VGMSTREAM * init_vgmstream_aix(STREAMFILE *streamFile) { goto fail; sample_rate = read_32bitBE(stream_list_offset+8,streamFile); - if (!check_sample_rate(sample_rate)) + if (sample_rate < 300 || sample_rate > 96000) goto fail; samples_in_segment = calloc(segment_count,sizeof(int32_t)); diff --git a/src/util.c b/src/util.c index 5d457d1c..badb2c97 100644 --- a/src/util.c +++ b/src/util.c @@ -2,10 +2,6 @@ #include "util.h" #include "streamtypes.h" -int check_sample_rate(int32_t sr) { - return !(sr<300 || sr>96000); -} - const char * filename_extension(const char * filename) { const char * ext; diff --git a/src/util.h b/src/util.h index 0062e6ac..75b59078 100644 --- a/src/util.h +++ b/src/util.h @@ -61,9 +61,6 @@ static inline int get_low_nibble_signed(uint8_t n) { return nibble_to_int[n&0xf]; } -/* return true for a good sample rate */ -int check_sample_rate(int32_t sr); - /* return a file's extension (a pointer to the first character of the * extension in the original filename or the ending null byte if no extension */ diff --git a/src/vgmstream.c b/src/vgmstream.c index 087097c3..a3e65cb2 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -400,8 +400,8 @@ static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) { continue; } - /* everything should have a reasonable sample rate (a verification of the metadata) */ - if (!check_sample_rate(vgmstream->sample_rate)) { + /* everything should have a reasonable sample rate (300 is Wwise min) */ + if (vgmstream->sample_rate < 300 || vgmstream->sample_rate > 96000) { VGM_LOG("VGMSTREAM: wrong sample rate (sr=%i)\n", vgmstream->sample_rate); close_vgmstream(vgmstream); continue; From 5c4351aa86b8f485c0df2e39f093446b12ba2d8f Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 23 Nov 2017 23:46:33 +0100 Subject: [PATCH 08/17] Add VGM_LOG/ASSERT_ONCE macro for useful-but-repetitive error logging --- src/streamfile.c | 19 ++----------------- src/util.h | 8 +++++++- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/streamfile.c b/src/streamfile.c index 1545ae6c..97e54992 100644 --- a/src/streamfile.c +++ b/src/streamfile.c @@ -22,9 +22,6 @@ typedef struct { uint8_t * buffer; /* data buffer */ size_t buffersize; /* max buffer size */ size_t filesize; /* cached file size (max offset) */ -#ifdef VGM_DEBUG_OUTPUT - int error_notified; -#endif #ifdef PROFILE_STREAMFILE size_t bytes_read; int error_count; @@ -67,13 +64,7 @@ static size_t read_the_rest(uint8_t * dest, off_t offset, size_t length, STDIOST /* request outside file: ignore to avoid seek/read */ if (offset > streamfile->filesize) { streamfile->offset = streamfile->filesize; - -#ifdef VGM_DEBUG_OUTPUT - if (!streamfile->error_notified) { - VGM_LOG("ERROR: reading over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length); - streamfile->error_notified = 1; - } -#endif + VGM_LOG_ONCE("ERROR: reading over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length); #if STREAMFILE_IGNORE_EOF memset(dest,0,length); /* dest is already shifted */ @@ -143,13 +134,7 @@ static size_t read_stdio(STDIOSTREAMFILE *streamfile,uint8_t * dest, off_t offse /* request outside file: ignore to avoid seek/read in read_the_rest() */ if (offset > streamfile->filesize) { streamfile->offset = streamfile->filesize; - -#ifdef VGM_DEBUG_OUTPUT - if (!streamfile->error_notified) { - VGM_LOG("ERROR: offset over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length); - streamfile->error_notified = 1; - } -#endif + VGM_LOG_ONCE("ERROR: offset over filesize 0x%x @ 0x%lx + 0x%x (buggy meta?)\n", streamfile->filesize, offset, length); #if STREAMFILE_IGNORE_EOF memset(dest,0,length); diff --git a/src/util.h b/src/util.h index 75b59078..0325743f 100644 --- a/src/util.h +++ b/src/util.h @@ -78,15 +78,19 @@ void concatn(int length, char * dst, const char * src); /* Simple stdout logging for debugging and regression testing purposes. - * Needs C99 variadic macros. */ + * Needs C99 variadic macros, uses do..while to force ; as statement */ #ifdef VGM_DEBUG_OUTPUT /* equivalent to printf when condition is true */ #define VGM_ASSERT(condition, ...) \ do { if (condition) printf(__VA_ARGS__); } while (0) +#define VGM_ASSERT_ONCE(condition, ...) \ + do { static int written; if (!written) { if (condition) printf(__VA_ARGS__); written = 1; } } while (0) /* equivalent to printf */ #define VGM_LOG(...) \ do { printf(__VA_ARGS__); } while (0) +#define VGM_LOG_ONCE(...) \ + do { static int written; if (!written) { printf(__VA_ARGS__); written = 1; } } while (0) /* prints file/line/func */ #define VGM_LOGF() \ do { printf("%s:%i '%s'\n", __FILE__, __LINE__, __func__); } while (0) @@ -108,10 +112,12 @@ void concatn(int length, char * dst, const char * src); #define VGM_ASSERT(condition, ...) /* nothing */ #define VGM_LOG(...) /* nothing */ +#define VGM_LOG_ONCE(...) /* nothing */ #define VGM_LOGF() /* nothing */ #define VGM_LOGT() /* nothing */ #define VGM_LOGB(buf, buf_size, bytes_per_line) /* nothing */ + #endif/*VGM_DEBUG_OUTPUT*/ #endif From 084c3075e4d4f485a87a868ca0673439c0593b60 Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 24 Nov 2017 20:15:23 +0100 Subject: [PATCH 09/17] Improve try_dual_file_stereo and cleanup To test dual stereo it was trying all metas, but only the meta that opened the first file can be accepted (as validated), so pass its function pointer and try only that instead. --- src/vgmstream.c | 205 ++++++++++++++++++++++-------------------------- 1 file changed, 94 insertions(+), 111 deletions(-) diff --git a/src/vgmstream.c b/src/vgmstream.c index a3e65cb2..dca68f29 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -10,16 +10,11 @@ #include "layout/layout.h" #include "coding/coding.h" -/* See if there is a second file which may be the second channel, given - * already opened mono opened_stream which was opened from filename. - * If a suitable file is found, open it and change opened_stream to a stereo stream. */ -static void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFile); +static void try_dual_file_stereo(VGMSTREAM * opened_vgmstream, STREAMFILE *streamFile, VGMSTREAM* (*init_vgmstream_function)(STREAMFILE*)); -/* - * List of functions that will recognize files. - */ -VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { +/* List of functions that will recognize files */ +VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_adx, init_vgmstream_brstm, init_vgmstream_bfwav, @@ -379,18 +374,21 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { /* internal version with all parameters */ -static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) { +static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile) { int i, fcns_size; if (!streamFile) return NULL; - fcns_size = (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0])); + fcns_size = (sizeof(init_vgmstream_functions)/sizeof(init_vgmstream_functions[0])); /* try a series of formats, see which works */ for (i=0; i < fcns_size; i++) { /* call init function and see if valid VGMSTREAM was returned */ - VGMSTREAM * vgmstream = (init_vgmstream_fcns[i])(streamFile); - if (vgmstream) { + VGMSTREAM * vgmstream = (init_vgmstream_functions[i])(streamFile); + if (!vgmstream) + continue; + + { /* these are little hacky checks */ /* fail if there is nothing to play (without this check vgmstream can generate empty files) */ @@ -418,10 +416,11 @@ static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) { } /* dual file stereo */ - if (do_dfs && ( + if (vgmstream->channels == 1 && ( (vgmstream->meta_type == meta_DSP_STD) || (vgmstream->meta_type == meta_PS2_VAGp) || (vgmstream->meta_type == meta_GENH) || + (vgmstream->meta_type == meta_TXTH) || (vgmstream->meta_type == meta_KRAW) || (vgmstream->meta_type == meta_PS2_MIB) || (vgmstream->meta_type == meta_NGC_LPS) || @@ -433,8 +432,8 @@ static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) { (vgmstream->meta_type == meta_SPT_SPD) || (vgmstream->meta_type == meta_EB_SFX) || (vgmstream->meta_type == meta_CWAV) - ) && vgmstream->channels == 1) { - try_dual_file_stereo(vgmstream, streamFile); + )) { + try_dual_file_stereo(vgmstream, streamFile, init_vgmstream_functions[i]); } #ifdef VGM_USE_FFMPEG @@ -475,7 +474,7 @@ VGMSTREAM * init_vgmstream(const char * const filename) { } VGMSTREAM * init_vgmstream_from_STREAMFILE(STREAMFILE *streamFile) { - return init_vgmstream_internal(streamFile,1); + return init_vgmstream_internal(streamFile); } /* Reset a VGMSTREAM to its state at the start of playback. @@ -2137,103 +2136,88 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { } } -/* filename search pairs for dual file stereo */ -const char * const dfs_pairs[][2] = { - {"L","R"}, - {"l","r"}, - {"_0","_1"}, - {"left","right"}, - {"Left","Right"}, -}; -#define DFS_PAIR_COUNT (sizeof(dfs_pairs)/sizeof(dfs_pairs[0])) -static void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFile) { - char filename[PATH_LIMIT]; - char filename2[PATH_LIMIT]; +/* See if there is a second file which may be the second channel, given an already opened mono vgmstream. + * If a suitable file is found, open it and change opened_vgmstream to a stereo vgmstream. */ +static void try_dual_file_stereo(VGMSTREAM * opened_vgmstream, STREAMFILE *streamFile, VGMSTREAM*(*init_vgmstream_function)(STREAMFILE *)) { + /* filename search pairs for dual file stereo */ + static const char * const dfs_pairs[][2] = { + {"L","R"}, + {"l","r"}, + {"_0","_1"}, + {"left","right"}, + {"Left","Right"}, + }; + char new_filename[PATH_LIMIT]; char * ext; - int dfs_name= -1; /*-1=no stereo, 0=opened_stream is left, 1=opened_stream is right */ - VGMSTREAM * new_stream = NULL; - STREAMFILE *dual_stream = NULL; - int i,j; + int dfs_pair = -1; /* -1=no stereo, 0=opened_vgmstream is left, 1=opened_vgmstream is right */ + VGMSTREAM *new_vgmstream = NULL; + STREAMFILE *dual_streamFile = NULL; + int i,j, dfs_pair_count; - if (opened_stream->channels != 1) return; - - streamFile->get_name(streamFile,filename,sizeof(filename)); + if (opened_vgmstream->channels != 1) + return; /* vgmstream's layout stuff currently assumes a single file */ // fastelbja : no need ... this one works ok with dual file - //if (opened_stream->layout != layout_none) return; + //if (opened_vgmstream->layout != layout_none) return; + //todo force layout_none if layout_interleave? - /* we need at least a base and a name ending to replace */ - if (strlen(filename)<2) return; + streamFile->get_name(streamFile,new_filename,sizeof(new_filename)); + if (strlen(new_filename)<2) return; /* we need at least a base and a name ending to replace */ + + ext = (char *)filename_extension(new_filename); + if (ext-new_filename >= 1 && ext[-1]=='.') ext--; /* excluding "." */ - strcpy(filename2,filename); + /* find pair from base name and modify new_filename with the opposite */ + dfs_pair_count = (sizeof(dfs_pairs)/sizeof(dfs_pairs[0])); + for (i = 0; dfs_pair == -1 && i< dfs_pair_count; i++) { + for (j=0; dfs_pair==-1 && j<2; j++) { + const char * this_suffix = dfs_pairs[i][j]; + size_t this_suffix_len = strlen(dfs_pairs[i][j]); - /* look relative to the extension; */ - ext = (char *)filename_extension(filename2); + /* if suffix matches copy opposite to ext pointer (thus to new_filename) */ + if ( !memcmp(ext - this_suffix_len,this_suffix,this_suffix_len) ) { + const char * other_suffix = dfs_pairs[i][j^1]; + size_t other_suffix_len = strlen(dfs_pairs[i][j^1]); - /* we treat the . as part of the extension */ - if (ext-filename2 >= 1 && ext[-1]=='.') ext--; - - for (i=0; dfs_name==-1 && iopen(streamFile,new_filename,STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!dual_streamFile) goto fail; - dual_stream = streamFile->open(streamFile,filename2,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!dual_stream) goto fail; - - new_stream = init_vgmstream_internal(dual_stream, - 0 /* don't do dual file on this, to prevent recursion */ - ); - close_streamfile(dual_stream); + new_vgmstream = init_vgmstream_function(dual_streamFile); /* use the init that just worked, no other should work */ + close_streamfile(dual_streamFile); /* see if we were able to open the file, and if everything matched nicely */ - if (new_stream && - new_stream->channels == 1 && - /* we have seen legitimate pairs where these are off by one... */ - /* but leaving it commented out until I can find those and recheck */ - /* abs(new_stream->num_samples-opened_stream->num_samples <= 1) && */ - new_stream->num_samples == opened_stream->num_samples && - new_stream->sample_rate == opened_stream->sample_rate && - new_stream->meta_type == opened_stream->meta_type && - new_stream->coding_type == opened_stream->coding_type && - new_stream->layout_type == opened_stream->layout_type && - new_stream->loop_flag == opened_stream->loop_flag && - /* check these even if there is no loop, because they should then - * be zero in both */ - new_stream->loop_start_sample == opened_stream->loop_start_sample && - new_stream->loop_end_sample == opened_stream->loop_end_sample && + if (new_vgmstream && + new_vgmstream->channels == 1 && + /* we have seen legitimate pairs where these are off by one... + * but leaving it commented out until I can find those and recheck */ + /* abs(new_vgmstream->num_samples-opened_vgmstream->num_samples <= 1) && */ + new_vgmstream->num_samples == opened_vgmstream->num_samples && + new_vgmstream->sample_rate == opened_vgmstream->sample_rate && + new_vgmstream->meta_type == opened_vgmstream->meta_type && + new_vgmstream->coding_type == opened_vgmstream->coding_type && + new_vgmstream->layout_type == opened_vgmstream->layout_type && + new_vgmstream->loop_flag == opened_vgmstream->loop_flag && + /* check these even if there is no loop, because they should then be zero in both */ + new_vgmstream->loop_start_sample == opened_vgmstream->loop_start_sample && + new_vgmstream->loop_end_sample == opened_vgmstream->loop_end_sample && /* check even if the layout doesn't use them, because it is - * difficult to determine when it does, and they should be zero - * otherwise, anyway */ - new_stream->interleave_block_size == opened_stream->interleave_block_size && - new_stream->interleave_smallblock_size == opened_stream->interleave_smallblock_size) { + * difficult to determine when it does, and they should be zero otherwise, anyway */ + new_vgmstream->interleave_block_size == opened_vgmstream->interleave_block_size && + new_vgmstream->interleave_smallblock_size == opened_vgmstream->interleave_smallblock_size) { /* We seem to have a usable, matching file. Merge in the second channel. */ VGMSTREAMCHANNEL * new_chans; VGMSTREAMCHANNEL * new_loop_chans = NULL; @@ -2243,18 +2227,17 @@ static void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFi new_chans = calloc(2,sizeof(VGMSTREAMCHANNEL)); if (!new_chans) goto fail; - memcpy(&new_chans[dfs_name],&opened_stream->ch[0],sizeof(VGMSTREAMCHANNEL)); - memcpy(&new_chans[dfs_name^1],&new_stream->ch[0],sizeof(VGMSTREAMCHANNEL)); + memcpy(&new_chans[dfs_pair],&opened_vgmstream->ch[0],sizeof(VGMSTREAMCHANNEL)); + memcpy(&new_chans[dfs_pair^1],&new_vgmstream->ch[0],sizeof(VGMSTREAMCHANNEL)); - /* loop and start will be initialized later, we just need to - * allocate them here */ + /* loop and start will be initialized later, we just need to allocate them here */ new_start_chans = calloc(2,sizeof(VGMSTREAMCHANNEL)); if (!new_start_chans) { free(new_chans); goto fail; } - if (opened_stream->loop_ch) { + if (opened_vgmstream->loop_ch) { new_loop_chans = calloc(2,sizeof(VGMSTREAMCHANNEL)); if (!new_loop_chans) { free(new_chans); @@ -2265,27 +2248,27 @@ static void try_dual_file_stereo(VGMSTREAM * opened_stream, STREAMFILE *streamFi /* remove the existing structures */ /* not using close_vgmstream as that would close the file */ - free(opened_stream->ch); - free(new_stream->ch); + free(opened_vgmstream->ch); + free(new_vgmstream->ch); - free(opened_stream->start_ch); - free(new_stream->start_ch); + free(opened_vgmstream->start_ch); + free(new_vgmstream->start_ch); - if (opened_stream->loop_ch) { - free(opened_stream->loop_ch); - free(new_stream->loop_ch); + if (opened_vgmstream->loop_ch) { + free(opened_vgmstream->loop_ch); + free(new_vgmstream->loop_ch); } /* fill in the new structures */ - opened_stream->ch = new_chans; - opened_stream->start_ch = new_start_chans; - opened_stream->loop_ch = new_loop_chans; + opened_vgmstream->ch = new_chans; + opened_vgmstream->start_ch = new_start_chans; + opened_vgmstream->loop_ch = new_loop_chans; /* stereo! */ - opened_stream->channels = 2; + opened_vgmstream->channels = 2; /* discard the second VGMSTREAM */ - free(new_stream); + free(new_vgmstream); } fail: return; From eb5e9066c389870bd007a5b1b38d1b148ff090d2 Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 24 Nov 2017 21:01:28 +0100 Subject: [PATCH 10/17] Update readme a bit with supported codecs --- README.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e0d322f5..898b09d8 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,10 @@ There are multiple end-user bits: - an XMPlay plugin called "xmp-vgmstream" - an Audacious plugin called "libvgmstream" -## IMPORTANT!! -### Needed files (for Windows) -Since Ogg Vorbis, MPEG audio, and other formats are now supported, you will -need to have certain DLL files.
+## Needed files (for Windows) +Since Ogg Vorbis, MPEG audio, and other external formats are supported, you +will need to have certain DLL files. + In the case of the foobar2000 component they are all bundled for convenience, or you can get them from here: https://github.com/kode54/vgmstream (also here: https://f.losno.co/vgmstream-win32-deps.zip, may not be latest). @@ -22,13 +22,13 @@ Put ```libvorbis.dll```, ```libmpg123-0.dll```, ```libg7221_decode.dll```, ```li ```at3plusdecoder.dll```, ```avcodec-vgmstream-58.dll```, ```avformat-vgmstream-58.dll```, ```avutil-vgmstream-56.dll``` and ```swresample-vgmstream-3.dll``` somewhere Windows can find them. -For Winamp/XMPlay/```test.exe``` this means in the directory with the .exe, or in a + +For Winamp/XMPlay/test.exe this means in the directory with the .exe, or in a system directory, or any other directory in the PATH variable. -### ```test.exe``` +### test.exe ``` -Usage: ./test [-o outfile.wav] [-l loop count] - [-f fade time] [-d fade delay] [-ipcmxeE] infile +Usage: test.exe [-o outfile.wav] [options] infile Options: -o outfile.wav: name of output .wav file, default is dump.wav -l loop count: loop count, default 2.0 @@ -73,8 +73,50 @@ Every file should be installed automatically by the .fb2k-component bundle. ### Audacious plugin Needs to be manually built. Instructions can be found in the source files. -### File types supported by this version of vgmstream +## Supported codec types +Quick list of codecs vgmstream supports, including many obscure ones that +are used in few games. +- PCM 16-bit +- PCM 8-bit (signed/unsigned) +- PCM 32-bit float +- u-Law/a-LAW +- CRI ADX (standard, fixed, exponential, encrypted) +- Nintendo DSP ADPCM a.k.a GC ADPCM +- Nintendo DTK ADPCM +- Nintendo AFC ADPCM +- ITU-T G.721 +- CD-ROM XA ADPCM +- Sony PSX ADPCM a.k.a VAG (badflags, bmdx, configurable) +- Sony HEVAG +- Electronic Arts EA-XA (stereo, mono, Maxis) +- Electronic Arts EA-XAS +- DVI/IMA ADPCM (stereo/mono + high/low nibble, 3DS, Omikron, SNDS, etc) +- Microsoft MS IMA ADPCM (standard, Xbox, NDS, Radical, Wwise, FSB, etc) +- Microsoft MS ADPCM +- Westwood VBR ADPCM +- Yamaha AICA ADPCM +- Procyon Studio ADPCM +- Level-5 0x555 ADPCM +- Activision EXAKT SASSC DPCM +- lsf ADPCM +- Konami MTAF ADPCM +- Konami MTA2 ADPCM +- Paradigm MC3 ADPCM +- SDX2 2:1 Squareroot-Delta-Exact compression DPCM +- CBD2 2:1 Cuberoot-Delta-Exact compression DPCM +- InterPlay ACM +- Visual Art's NWA +- CRI HCA +- Xiph Vorbis (Ogg, FSB5, Wwise, OGL, Silicon Knights) +- MPEG MP1/2/3 (standard, AHX, XVAG, FSB, AWC, P3D, etc) +- Electronic Arts EALayer3 v1 +- ITU-T G.722.1 (Polycom Siren 7) +- ITU-T G.722.1 annex C (Polycom Siren 14) +- ITU G.719 annex B (Polycom Siren 22) +- FFmpeg codecs (ATRAC3, ATRAC3plus, XMA, WMA/XWMA, AAC, BINK, AC3, FLAC, etc) + +## Supported file types As manakoAT likes to say, the extension doesn't really mean anything, but it's the most obvious way to identify files. From b371f1de73f9c330fcf8a6c30f2ec41d1eec34e3 Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 24 Nov 2017 21:23:01 +0100 Subject: [PATCH 11/17] Reorder IMA code a bit so it's easier to simplify in the future --- src/coding/ima_decoder.c | 396 ++++++++++++++++++++------------------- 1 file changed, 202 insertions(+), 194 deletions(-) diff --git a/src/coding/ima_decoder.c b/src/coding/ima_decoder.c index 10d45f7b..8b68bb6a 100644 --- a/src/coding/ima_decoder.c +++ b/src/coding/ima_decoder.c @@ -41,28 +41,6 @@ static const int IMA_IndexTable[16] = }; -/* 3DS IMA (Mario Golf, Mario Tennis; maybe other Camelot games) */ -static void n3ds_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) { - int sample_nibble, sample_decoded, step, delta; - - sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf; - sample_decoded = *hist1; - - sample_decoded = sample_decoded << 3; - step = ADPCMTable[*step_index]; - delta = step * (sample_nibble & 7) * 2 + step; - if (sample_nibble & 8) - sample_decoded -= delta; - else - sample_decoded += delta; - sample_decoded = sample_decoded >> 3; - - *hist1 = clamp16(sample_decoded); - *step_index += IMA_IndexTable[sample_nibble]; - if (*step_index < 0) *step_index=0; - if (*step_index > 88) *step_index=88; -} - /* Standard IMA (most common) */ static void ms_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) { int sample_nibble, sample_decoded, step, delta; @@ -107,6 +85,28 @@ static void ms_ima_expand_nibble_16(VGMSTREAMCHANNEL * stream, off_t byte_offset if (*step_index > 88) *step_index=88; } +/* 3DS IMA (Mario Golf, Mario Tennis; maybe other Camelot games) */ +static void n3ds_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) { + int sample_nibble, sample_decoded, step, delta; + + sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf; + sample_decoded = *hist1; + + sample_decoded = sample_decoded << 3; + step = ADPCMTable[*step_index]; + delta = step * (sample_nibble & 7) * 2 + step; + if (sample_nibble & 8) + sample_decoded -= delta; + else + sample_decoded += delta; + sample_decoded = sample_decoded >> 3; + + *hist1 = clamp16(sample_decoded); + *step_index += IMA_IndexTable[sample_nibble]; + if (*step_index < 0) *step_index=0; + if (*step_index > 88) *step_index=88; +} + /* update step_index before doing current sample */ static void snds_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) { int sample_nibble, sample_decoded, step, delta; @@ -168,68 +168,115 @@ static void ubi_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, *hist1 = clamp16(sample_decoded); } -/* *** */ +/* ************************************ */ +/* DVI/IMA */ +/* ************************************ */ -void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { - int i, sample_count; +/* Standard DVI/IMA ADPCM (as in, ADPCM recommended by the IMA using Intel/DVI's implementation). + * Configurable: stereo or mono/interleave nibbles, and high or low nibble first. + * For vgmstream, low nibble is called "IMA ADPCM" and high nibble is "DVI IMA ADPCM" (same thing though). */ +void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first) { + int i, sample_count = 0; - int32_t hist1 = stream->adpcm_history1_16;//todo unneeded 16? + int32_t hist1 = stream->adpcm_history1_32; int step_index = stream->adpcm_step_index; - //external interleave + /* external interleave */ - //normal header - if (first_sample == 0) { - off_t header_offset = stream->offset; + /* no header (external setup), pre-clamp for wrong values */ + if (step_index < 0) step_index=0; + if (step_index > 88) step_index=88; - hist1 = read_16bitLE(header_offset,stream->streamfile); - step_index = read_16bitLE(header_offset+2,stream->streamfile); - - //todo clip step_index? - } - - for (i=first_sample,sample_count=0; ioffset + 4 + i/2; - int nibble_shift = (i&1?4:0); //low nibble first + /* decode nibbles */ + for (i = first_sample; i < first_sample + samples_to_do; i++, sample_count += channelspacing) { + off_t byte_offset = is_stereo ? + stream->offset + i : /* stereo: one nibble per channel */ + stream->offset + i/2; /* mono: consecutive nibbles */ + int nibble_shift = is_high_first ? + is_stereo ? (!(channel&1) ? 4:0) : (!(i&1) ? 4:0) : /* even = high, odd = low */ + is_stereo ? (!(channel&1) ? 0:4) : (!(i&1) ? 0:4); /* even = low, odd = high */ ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } - stream->adpcm_history1_16 = hist1; + stream->adpcm_history1_32 = hist1; stream->adpcm_step_index = step_index; } -void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i, sample_count; - int32_t hist1 = stream->adpcm_history1_16;//todo unneeded 16? + int32_t hist1 = stream->adpcm_history1_32; int step_index = stream->adpcm_step_index; //external interleave - //normal header - if (first_sample == 0) { - off_t header_offset = stream->offset; - - hist1 = read_16bitLE(header_offset,stream->streamfile); - step_index = read_8bit(header_offset+2,stream->streamfile); - - //todo clip step_index? - } + //no header for (i=first_sample,sample_count=0; ioffset + 4 + i/2; - int nibble_shift = (i&1?0:4); //high nibble first + off_t byte_offset = stream->offset + i/2; + int nibble_shift = (i&1?4:0); //low nibble order - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + n3ds_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } - stream->adpcm_history1_16 = hist1; + stream->adpcm_history1_32 = hist1; stream->adpcm_step_index = step_index; } +void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { + int i, sample_count; + + int32_t hist1 = stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + + //external interleave + + //no header + + for (i=first_sample,sample_count=0; ioffset + i;//one nibble per channel + int nibble_shift = (channel==0?0:4); //high nibble first, based on channel + + snds_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + outbuf[sample_count] = (short)(hist1); + } + + stream->adpcm_history1_32 = hist1; + stream->adpcm_step_index = step_index; +} + +void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { + int i, sample_count; + + int32_t hist1 = stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + + //internal/byte interleave + + //no header + + for (i=first_sample,sample_count=0; ioffset + (vgmstream->channels==1 ? i/2 : i); //one nibble per channel if stereo + int nibble_shift = (vgmstream->channels==1) ? //todo simplify + (i&1?0:4) : //high nibble first(?) + (channel==0?4:0); //low=ch0, high=ch1 (this is correct compared to vids) + + otns_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + outbuf[sample_count] = (short)(hist1); + } + + stream->adpcm_history1_32 = hist1; + stream->adpcm_step_index = step_index; +} + +/* ************************************ */ +/* MS IMA */ +/* ************************************ */ + +/* IMA with frames with header and custom sizes */ void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { int i, sample_count; @@ -265,74 +312,8 @@ void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * out stream->adpcm_step_index = step_index; } -void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { - int i, sample_count; - - int32_t hist1 = stream->adpcm_history1_32; - int step_index = stream->adpcm_step_index; - - //internal interleave (configurable size), mixed channels (4 byte per ch) - int block_samples = (vgmstream->interleave_block_size - 4*vgmstream->channels) * 2 / vgmstream->channels; - first_sample = first_sample % block_samples; - - //inverted header (per channel) - if (first_sample == 0) { - off_t header_offset = stream->offset + 4*channel; - - step_index = read_16bitLE(header_offset,stream->streamfile); - hist1 = read_16bitLE(header_offset+2,stream->streamfile); - if (step_index < 0) step_index=0; - if (step_index > 88) step_index=88; - } - - for (i=first_sample,sample_count=0; ioffset + 4*vgmstream->channels + channel + i/2*vgmstream->channels; - int nibble_shift = (i&1?4:0); //low nibble first - - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); - outbuf[sample_count] = (short)(hist1); - } - - //internal interleave: increment offset on complete frame - if (i == block_samples) stream->offset += vgmstream->interleave_block_size; - - stream->adpcm_history1_32 = hist1; - stream->adpcm_step_index = step_index; -} - -void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { - int i, sample_count; - - int32_t hist1 = stream->adpcm_history1_32; - int step_index = stream->adpcm_step_index; - - //semi-external interleave? - int block_samples = 0x14 * 2; - first_sample = first_sample % block_samples; - - //inverted header - if (first_sample == 0) { - off_t header_offset = stream->offset; - - step_index = read_16bitLE(header_offset,stream->streamfile); - hist1 = read_16bitLE(header_offset+2,stream->streamfile); - if (step_index < 0) step_index=0; - if (step_index > 88) step_index=88; - } - - for (i=first_sample,sample_count=0; ioffset + 4 + i/2; - int nibble_shift = (i&1?4:0); //low nibble first - - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); - outbuf[sample_count] = (short)(hist1); - } - - stream->adpcm_history1_32 = hist1; - stream->adpcm_step_index = step_index; -} - -/* For multichannel the internal layout is (I think) mixed stereo channels (ex. 6ch: 2ch + 2ch + 2ch) */ +/* MS IMA with fixed frame size and custom multichannel nibble layout. + * For multichannel the layout is (I think) mixed stereo channels (ex. 6ch: 2ch + 2ch + 2ch) */ void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { int i, sample_count; @@ -426,53 +407,126 @@ void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel stream->adpcm_step_index = step_index; } -/* Standard DVI/IMA ADPCM (as in, ADPCM recommended by the IMA using Intel/DVI's implementation). - * Configurable: stereo or mono/interleave nibbles, and high or low nibble first. - * For vgmstream, low nibble is called "IMA ADPCM" and high nibble is "DVI IMA ADPCM" (same thing though). */ -void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first) { - int i, sample_count = 0; +void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i, sample_count; - int32_t hist1 = stream->adpcm_history1_32; + int32_t hist1 = stream->adpcm_history1_16;//todo unneeded 16? int step_index = stream->adpcm_step_index; - /* external interleave */ + //external interleave - /* no header (external setup), pre-clamp for wrong values */ - if (step_index < 0) step_index=0; - if (step_index > 88) step_index=88; + //normal header + if (first_sample == 0) { + off_t header_offset = stream->offset; - /* decode nibbles */ - for (i = first_sample; i < first_sample + samples_to_do; i++, sample_count += channelspacing) { - off_t byte_offset = is_stereo ? - stream->offset + i : /* stereo: one nibble per channel */ - stream->offset + i/2; /* mono: consecutive nibbles */ - int nibble_shift = is_high_first ? - is_stereo ? (!(channel&1) ? 4:0) : (!(i&1) ? 4:0) : /* even = high, odd = low */ - is_stereo ? (!(channel&1) ? 0:4) : (!(i&1) ? 0:4); /* even = low, odd = high */ + hist1 = read_16bitLE(header_offset,stream->streamfile); + step_index = read_16bitLE(header_offset+2,stream->streamfile); + + //todo clip step_index? + } + + for (i=first_sample,sample_count=0; ioffset + 4 + i/2; + int nibble_shift = (i&1?4:0); //low nibble first ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } - stream->adpcm_history1_32 = hist1; + stream->adpcm_history1_16 = hist1; stream->adpcm_step_index = step_index; } -void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { +void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i, sample_count; + + int32_t hist1 = stream->adpcm_history1_16;//todo unneeded 16? + int step_index = stream->adpcm_step_index; + + //external interleave + + //normal header + if (first_sample == 0) { + off_t header_offset = stream->offset; + + hist1 = read_16bitLE(header_offset,stream->streamfile); + step_index = read_8bit(header_offset+2,stream->streamfile); + + //todo clip step_index? + } + + for (i=first_sample,sample_count=0; ioffset + 4 + i/2; + int nibble_shift = (i&1?0:4); //high nibble first + + ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + outbuf[sample_count] = (short)(hist1); + } + + stream->adpcm_history1_16 = hist1; + stream->adpcm_step_index = step_index; +} + +void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { int i, sample_count; int32_t hist1 = stream->adpcm_history1_32; int step_index = stream->adpcm_step_index; - //external interleave + //internal interleave (configurable size), mixed channels (4 byte per ch) + int block_samples = (vgmstream->interleave_block_size - 4*vgmstream->channels) * 2 / vgmstream->channels; + first_sample = first_sample % block_samples; - //no header + //inverted header (per channel) + if (first_sample == 0) { + off_t header_offset = stream->offset + 4*channel; + + step_index = read_16bitLE(header_offset,stream->streamfile); + hist1 = read_16bitLE(header_offset+2,stream->streamfile); + if (step_index < 0) step_index=0; + if (step_index > 88) step_index=88; + } for (i=first_sample,sample_count=0; ioffset + i/2; - int nibble_shift = (i&1?4:0); //low nibble order + off_t byte_offset = stream->offset + 4*vgmstream->channels + channel + i/2*vgmstream->channels; + int nibble_shift = (i&1?4:0); //low nibble first - n3ds_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + outbuf[sample_count] = (short)(hist1); + } + + //internal interleave: increment offset on complete frame + if (i == block_samples) stream->offset += vgmstream->interleave_block_size; + + stream->adpcm_history1_32 = hist1; + stream->adpcm_step_index = step_index; +} + +void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { + int i, sample_count; + + int32_t hist1 = stream->adpcm_history1_32; + int step_index = stream->adpcm_step_index; + + //semi-external interleave? + int block_samples = 0x14 * 2; + first_sample = first_sample % block_samples; + + //inverted header + if (first_sample == 0) { + off_t header_offset = stream->offset; + + step_index = read_16bitLE(header_offset,stream->streamfile); + hist1 = read_16bitLE(header_offset+2,stream->streamfile); + if (step_index < 0) step_index=0; + if (step_index > 88) step_index=88; + } + + for (i=first_sample,sample_count=0; ioffset + 4 + i/2; + int nibble_shift = (i&1?4:0); //low nibble first + + ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } @@ -512,52 +566,6 @@ void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelsp stream->adpcm_step_index = step_index; } -void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { - int i, sample_count; - - int32_t hist1 = stream->adpcm_history1_32; - int step_index = stream->adpcm_step_index; - - //external interleave - - //no header - - for (i=first_sample,sample_count=0; ioffset + i;//one nibble per channel - int nibble_shift = (channel==0?0:4); //high nibble first, based on channel - - snds_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); - outbuf[sample_count] = (short)(hist1); - } - - stream->adpcm_history1_32 = hist1; - stream->adpcm_step_index = step_index; -} - -void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { - int i, sample_count; - - int32_t hist1 = stream->adpcm_history1_32; - int step_index = stream->adpcm_step_index; - - //internal/byte interleave - - //no header - - for (i=first_sample,sample_count=0; ioffset + (vgmstream->channels==1 ? i/2 : i); //one nibble per channel if stereo - int nibble_shift = (vgmstream->channels==1) ? //todo simplify - (i&1?0:4) : //high nibble first(?) - (channel==0?4:0); //low=ch0, high=ch1 (this is correct compared to vids) - - otns_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); - outbuf[sample_count] = (short)(hist1); - } - - stream->adpcm_history1_32 = hist1; - stream->adpcm_step_index = step_index; -} - void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { int i, sample_count; From a974c756b083a860211683570c9db1ecfdc26c4e Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 24 Nov 2017 22:43:33 +0100 Subject: [PATCH 12/17] Update readme codecs some more --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 898b09d8..ea127731 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,17 @@ are used in few games. - ITU-T G.722.1 (Polycom Siren 7) - ITU-T G.722.1 annex C (Polycom Siren 14) - ITU G.719 annex B (Polycom Siren 22) -- FFmpeg codecs (ATRAC3, ATRAC3plus, XMA, WMA/XWMA, AAC, BINK, AC3, FLAC, etc) +- FFmpeg codecs: + - ATRAC3, ATRAC3plus + - XMA + - WMA v1, WMA v2, WMAPro + - AAC + - Bink + - AC3/SPDIF + - Opus (Ogg, Switch) + - FLAC + - Others + ## Supported file types As manakoAT likes to say, the extension doesn't really mean anything, but it's From 2a312e856223845adfcf3e8773602c44c03401d9 Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 24 Nov 2017 23:42:11 +0100 Subject: [PATCH 13/17] Fix memset not memsetting all channels on failure --- src/coding/mpeg_decoder.c | 2 +- src/coding/vorbis_custom_decoder.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coding/mpeg_decoder.c b/src/coding/mpeg_decoder.c index c08145d3..b0bf45a8 100644 --- a/src/coding/mpeg_decoder.c +++ b/src/coding/mpeg_decoder.c @@ -238,7 +238,7 @@ static void decode_mpeg_standard(VGMSTREAMCHANNEL *stream, mpeg_codec_data * dat /* end of stream, fill rest with 0s */ if (!data->bytes_in_buffer) { - memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample)); + memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * channels * sizeof(sample)); break; } diff --git a/src/coding/vorbis_custom_decoder.c b/src/coding/vorbis_custom_decoder.c index 1fd256f2..ee25bb11 100644 --- a/src/coding/vorbis_custom_decoder.c +++ b/src/coding/vorbis_custom_decoder.c @@ -164,7 +164,7 @@ void decode_vorbis_custom(VGMSTREAM * vgmstream, sample * outbuf, int32_t sample decode_fail: /* on error just put some 0 samples */ - memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample)); + memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * channels * sizeof(sample)); } /* converts from internal Vorbis format to standard PCM (mostly from Xiph's decoder_example.c) */ From d0be7e0c3633a2ef011f5d31a2bdfadd165f7e3a Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Nov 2017 00:43:18 +0100 Subject: [PATCH 14/17] Minor tweaks/comments/renames/etc --- fb2k/foo_vgmstream.cpp | 1 + src/coding/ima_decoder.c | 30 ++++---- src/formats.c | 5 +- src/libvgmstream.vcproj | 2 +- src/libvgmstream.vcxproj | 2 +- src/libvgmstream.vcxproj.filters | 2 +- src/meta/{Cstr.c => cstr.c} | 3 +- src/meta/genh.c | 10 +-- src/meta/meta.h | 2 +- src/vgmstream.c | 126 +++++++++++++++++-------------- src/vgmstream.h | 9 +-- 11 files changed, 101 insertions(+), 91 deletions(-) rename src/meta/{Cstr.c => cstr.c} (99%) diff --git a/fb2k/foo_vgmstream.cpp b/fb2k/foo_vgmstream.cpp index c6ad17d7..78ab802c 100644 --- a/fb2k/foo_vgmstream.cpp +++ b/fb2k/foo_vgmstream.cpp @@ -413,6 +413,7 @@ bool input_vgmstream::get_description_tag(pfc::string_base & temp, pfc::string_b eos = description.find_first(delimiter, pos); if (eos == pfc::infinite_size) eos = description.length(); temp.set_string(description + pos, eos - pos); + //console::formatter() << "tag=" << tag << ", delim=" << delimiter << "temp=" << temp << ", pos=" << pos << "" << eos; return true; } return false; diff --git a/src/coding/ima_decoder.c b/src/coding/ima_decoder.c index 8b68bb6a..94a6b318 100644 --- a/src/coding/ima_decoder.c +++ b/src/coding/ima_decoder.c @@ -42,7 +42,7 @@ static const int IMA_IndexTable[16] = /* Standard IMA (most common) */ -static void ms_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) { +static void std_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) { int sample_nibble, sample_decoded, step, delta; sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf; @@ -64,7 +64,7 @@ static void ms_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, i } /* Apple's IMA variation. Exactly the same except it uses 16b history (probably more sensitive to overflow/sign extend) */ -static void ms_ima_expand_nibble_16(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int16_t * hist1, int32_t * step_index) { +static void std_ima_expand_nibble_16(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int16_t * hist1, int32_t * step_index) { int sample_nibble, sample_decoded, step, delta; sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf; @@ -196,7 +196,7 @@ void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel is_stereo ? (!(channel&1) ? 4:0) : (!(i&1) ? 4:0) : /* even = high, odd = low */ is_stereo ? (!(channel&1) ? 0:4) : (!(i&1) ? 0:4); /* even = low, odd = high */ - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } @@ -301,7 +301,7 @@ void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * out off_t byte_offset = stream->offset + 4*channel + 4*vgmstream->channels + i/8*4*vgmstream->channels + (i%8)/2; int nibble_shift = (i&1?4:0); //low nibble first - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } @@ -347,7 +347,7 @@ void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * o stream->offset + 4*(channel%2) + 4*2 + i/8*4*2 + (i%8)/2; nibble_shift = (i&1?4:0); //low nibble first - ms_ima_expand_nibble(stream, offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble(stream, offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } @@ -397,7 +397,7 @@ void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel //last nibble/sample in block is ignored (next header sample contains it) if (i < block_samples) { - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); sample_count += channelspacing; } @@ -429,7 +429,7 @@ void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci off_t byte_offset = stream->offset + 4 + i/2; int nibble_shift = (i&1?4:0); //low nibble first - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } @@ -459,7 +459,7 @@ void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac off_t byte_offset = stream->offset + 4 + i/2; int nibble_shift = (i&1?0:4); //high nibble first - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } @@ -491,7 +491,7 @@ void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * ou off_t byte_offset = stream->offset + 4*vgmstream->channels + channel + i/2*vgmstream->channels; int nibble_shift = (i&1?4:0); //low nibble first - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } @@ -526,7 +526,7 @@ void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel off_t byte_offset = stream->offset + 4 + i/2; int nibble_shift = (i&1?4:0); //low nibble first - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } @@ -558,7 +558,7 @@ void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelsp off_t byte_offset = (stream->offset + 0x22*num_frame + 0x2) + i/2; int nibble_shift = (i&1?4:0); //low nibble first - ms_ima_expand_nibble_16(stream, byte_offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble_16(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } @@ -591,7 +591,7 @@ void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * o off_t byte_offset = stream->offset + 4*vgmstream->channels + 2*channel + i/4*2*vgmstream->channels + (i%4)/2;//2-byte per channel int nibble_shift = (i&1?4:0); //low nibble first - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } @@ -636,7 +636,7 @@ void decode_wwise_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * //last nibble/sample in block is ignored (next header sample contains it) if (i < block_samples) { - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); sample_count+=channelspacing; //todo atenuation: apparently from hcs's analysis Wwise IMA decodes nibbles slightly different, reducing dbs @@ -677,7 +677,7 @@ void decode_ref_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * ou off_t byte_offset = stream->offset + 4*vgmstream->channels + block_channel_size*channel + i/2; int nibble_shift = (i&1?4:0); //low nibble first - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } @@ -712,7 +712,7 @@ void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci off_t byte_offset = stream->offset + 4 + i/2; int nibble_shift = (i&1?4:0); //low nibble first - ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); + std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); outbuf[sample_count] = (short)(hist1); } diff --git a/src/formats.c b/src/formats.c index 59700de6..e40627ac 100644 --- a/src/formats.c +++ b/src/formats.c @@ -571,8 +571,8 @@ static const meta_info meta_info_list[] = { {meta_UTF_DSP, "CRI ADPCM_WII header"}, {meta_DSP_AGSC, "Retro Studios AGSC header"}, {meta_DSP_CSMP, "Retro Studios CSMP header"}, - {meta_NGC_ADPDTK, "assumed Nintendo ADP by .adp extension and valid first frame"}, - {meta_RSF, "assumed Retro Studios RSF by .rsf extension and valid first bytes"}, + {meta_NGC_ADPDTK, "Nintendo ADP raw header"}, + {meta_RSF, "Retro Studios RSF raw header"}, {meta_AFC, "Nintendo AFC header"}, {meta_AST, "Nintendo AST header"}, {meta_HALPST, "HAL Laboratory HALPST header"}, @@ -692,6 +692,7 @@ static const meta_info meta_info_list[] = { {meta_XBOX_XVAS, "assumed TMNT file by .xvas extension"}, {meta_PS2_XA2, "Acclaim XA2 Header"}, {meta_DC_IDVI, "Capcom IDVI header"}, + {meta_KRAW, "Geometry Wars: Galaxies KRAW header"}, {meta_NGC_YMF, "YMF DSP Header"}, {meta_PS2_CCC, "CCC Header"}, {meta_PSX_FAG, "FAG Header"}, diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 76e1c5e9..12e40405 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -301,7 +301,7 @@ >
- + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 5235ed94..b556d5fb 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -172,7 +172,7 @@ meta\Source Files - + meta\Source Files diff --git a/src/meta/Cstr.c b/src/meta/cstr.c similarity index 99% rename from src/meta/Cstr.c rename to src/meta/cstr.c index 39d5d5e0..54218e20 100644 --- a/src/meta/Cstr.c +++ b/src/meta/cstr.c @@ -3,8 +3,7 @@ #include "../util.h" /* .dsp w/ Cstr header, seen in Star Fox Assault and Donkey Konga */ - -VGMSTREAM * init_vgmstream_Cstr(STREAMFILE *streamFile) { +VGMSTREAM * init_vgmstream_cstr(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; diff --git a/src/meta/genh.c b/src/meta/genh.c index b4a7e36b..787ba868 100644 --- a/src/meta/genh.c +++ b/src/meta/genh.c @@ -220,13 +220,13 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) { for (i=0;ichannels;i++) { int16_t (*read_16bit)(off_t , STREAMFILE*) = genh.coef_big_endian ? read_16bitBE : read_16bitLE; - /* normal/split coefs */ - if ((genh.coef_type & 1) == 0) { /* bit 0 - split coefs (2 arrays) */ + /* normal/split coefs bit flag */ + if ((genh.coef_type & 1) == 0) { /* not set: normal coefs, all 16 interleaved into one array */ for (j=0;j<16;j++) { vgmstream->ch[i].adpcm_coef[j] = read_16bit(genh.coef[i]+j*2,streamFile); } } - else { + else { /* set: split coefs, 8 coefs in the main array, additional offset to 2nd array given at 0x34 for left, 0x38 for right */ for (j=0;j<8;j++) { vgmstream->ch[i].adpcm_coef[j*2]=read_16bit(genh.coef[i]+j*2,streamFile); vgmstream->ch[i].adpcm_coef[j*2+1]=read_16bit(genh.coef_splitted[i]+j*2,streamFile); @@ -353,8 +353,8 @@ static int parse_genh(STREAMFILE * streamFile, genh_header * genh) { genh->coef_interleave_type = read_32bitLE(0x2C,streamFile); /* DSP coefficient variants */ - /* bit 0 - split coefs (2 arrays) */ - /* bit 1 - little endian coefs */ + /* bit 0 flag - split coefs (2 arrays) */ + /* bit 1 flag - little endian coefs (for some 3DS) */ genh->coef_type = read_32bitLE(0x30,streamFile); genh->coef_big_endian = ((genh->coef_type & 2) == 0); diff --git a/src/meta/meta.h b/src/meta/meta.h index 120247ba..13d504e4 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -15,7 +15,7 @@ VGMSTREAM * init_vgmstream_ast(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_brstm(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_Cstr(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_cstr(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_gcsw(STREAMFILE *streamFile); diff --git a/src/vgmstream.c b/src/vgmstream.c index dca68f29..7d42c515 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -32,7 +32,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_ngc_dsp_std, init_vgmstream_ngc_mdsp_std, init_vgmstream_ngc_dsp_csmp, - init_vgmstream_Cstr, + init_vgmstream_cstr, init_vgmstream_gcsw, init_vgmstream_ps2_ads, init_vgmstream_ps2_npsf, @@ -388,77 +388,87 @@ static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile) { if (!vgmstream) continue; - { - /* these are little hacky checks */ + /* fail if there is nothing to play (without this check vgmstream can generate empty files) */ + if (vgmstream->num_samples <= 0) { + VGM_LOG("VGMSTREAM: wrong num_samples (ns=%i / 0x%08x)\n", vgmstream->num_samples, vgmstream->num_samples); + close_vgmstream(vgmstream); + continue; + } - /* fail if there is nothing to play (without this check vgmstream can generate empty files) */ - if (vgmstream->num_samples <= 0) { - VGM_LOG("VGMSTREAM: wrong num_samples (ns=%i / 0x%08x)\n", vgmstream->num_samples, vgmstream->num_samples); - close_vgmstream(vgmstream); - continue; - } - - /* everything should have a reasonable sample rate (300 is Wwise min) */ - if (vgmstream->sample_rate < 300 || vgmstream->sample_rate > 96000) { - VGM_LOG("VGMSTREAM: wrong sample rate (sr=%i)\n", vgmstream->sample_rate); - close_vgmstream(vgmstream); - continue; - } + /* everything should have a reasonable sample rate (300 is Wwise min) */ + if (vgmstream->sample_rate < 300 || vgmstream->sample_rate > 96000) { + VGM_LOG("VGMSTREAM: wrong sample rate (sr=%i)\n", vgmstream->sample_rate); + close_vgmstream(vgmstream); + continue; + } - /* Sanify loops! */ - if (vgmstream->loop_flag) { - if ((vgmstream->loop_end_sample <= vgmstream->loop_start_sample) - || (vgmstream->loop_end_sample > vgmstream->num_samples) - || (vgmstream->loop_start_sample < 0) ) { - vgmstream->loop_flag = 0; - VGM_LOG("VGMSTREAM: wrong loops ignored (lss=%i, lse=%i, ns=%i)\n", vgmstream->loop_start_sample, vgmstream->loop_end_sample, vgmstream->num_samples); - } + /* Sanify loops! */ + if (vgmstream->loop_flag) { + if ((vgmstream->loop_end_sample <= vgmstream->loop_start_sample) + || (vgmstream->loop_end_sample > vgmstream->num_samples) + || (vgmstream->loop_start_sample < 0) ) { + vgmstream->loop_flag = 0; + VGM_LOG("VGMSTREAM: wrong loops ignored (lss=%i, lse=%i, ns=%i)\n", vgmstream->loop_start_sample, vgmstream->loop_end_sample, vgmstream->num_samples); } + } - /* dual file stereo */ - if (vgmstream->channels == 1 && ( - (vgmstream->meta_type == meta_DSP_STD) || - (vgmstream->meta_type == meta_PS2_VAGp) || - (vgmstream->meta_type == meta_GENH) || - (vgmstream->meta_type == meta_TXTH) || - (vgmstream->meta_type == meta_KRAW) || - (vgmstream->meta_type == meta_PS2_MIB) || - (vgmstream->meta_type == meta_NGC_LPS) || - (vgmstream->meta_type == meta_DSP_YGO) || - (vgmstream->meta_type == meta_DSP_AGSC) || - (vgmstream->meta_type == meta_PS2_SMPL) || - (vgmstream->meta_type == meta_NGCA) || - (vgmstream->meta_type == meta_NUB_VAG) || - (vgmstream->meta_type == meta_SPT_SPD) || - (vgmstream->meta_type == meta_EB_SFX) || - (vgmstream->meta_type == meta_CWAV) - )) { - try_dual_file_stereo(vgmstream, streamFile, init_vgmstream_functions[i]); + /* test if candidate for dual stereo */ + if (vgmstream->channels == 1 && ( + (vgmstream->meta_type == meta_DSP_STD) || + (vgmstream->meta_type == meta_PS2_VAGp) || + (vgmstream->meta_type == meta_GENH) || + (vgmstream->meta_type == meta_TXTH) || + (vgmstream->meta_type == meta_KRAW) || + (vgmstream->meta_type == meta_PS2_MIB) || + (vgmstream->meta_type == meta_NGC_LPS) || + (vgmstream->meta_type == meta_DSP_YGO) || + (vgmstream->meta_type == meta_DSP_AGSC) || + (vgmstream->meta_type == meta_PS2_SMPL) || + (vgmstream->meta_type == meta_NGCA) || + (vgmstream->meta_type == meta_NUB_VAG) || + (vgmstream->meta_type == meta_SPT_SPD) || + (vgmstream->meta_type == meta_EB_SFX) || + (vgmstream->meta_type == meta_CWAV) + )) { + try_dual_file_stereo(vgmstream, streamFile, init_vgmstream_functions[i]); + } + + +#ifdef VGM_DEBUG_OUTPUT + /* debug fun */ + { + int i = 0; + + /* probable segfault but some layouts/codecs could ignore these */ + for (i = 0; i < vgmstream->channels; i++) { + VGM_ASSERT(vgmstream->ch[i].streamfile == NULL, "VGMSTREAM: null streamfile in ch%i\n",i); } + } + +#endif/*VGM_DEBUG_OUTPUT*/ + #ifdef VGM_USE_FFMPEG - /* check FFmpeg streams here, for lack of a better place */ - if (vgmstream->coding_type == coding_FFmpeg) { - ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data; - if (data->streamCount && !vgmstream->num_streams) { - vgmstream->num_streams = data->streamCount; - } + /* check FFmpeg streams here, for lack of a better place */ + if (vgmstream->coding_type == coding_FFmpeg) { + ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data; + if (data->streamCount && !vgmstream->num_streams) { + vgmstream->num_streams = data->streamCount; } + } #endif - /* save info */ - vgmstream->stream_index = streamFile->stream_index; + /* save info */ + vgmstream->stream_index = streamFile->stream_index; - /* save start things so we can restart for seeking */ - /* copy the channels */ - memcpy(vgmstream->start_ch,vgmstream->ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels); - /* copy the whole VGMSTREAM */ - memcpy(vgmstream->start_vgmstream,vgmstream,sizeof(VGMSTREAM)); + /* save start things so we can restart for seeking */ + memcpy(vgmstream->start_ch,vgmstream->ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels); + memcpy(vgmstream->start_vgmstream,vgmstream,sizeof(VGMSTREAM)); - return vgmstream; - } + return vgmstream; } + /* not supported */ return NULL; } diff --git a/src/vgmstream.h b/src/vgmstream.h index fe72dabb..652c4c97 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -281,7 +281,7 @@ typedef enum { /* Nintendo */ meta_STRM, /* Nintendo STRM */ - meta_RSTM, /* Nintendo RSTM (similar to STRM) */ + meta_RSTM, /* Nintendo RSTM (Revolution Stream, similar to STRM) */ meta_AFC, /* AFC */ meta_AST, /* AST */ meta_RWSD, /* single-stream RWSD */ @@ -306,7 +306,6 @@ typedef enum { meta_UTF_DSP, /* CRI ADPCM_WII, like AAX with DSP */ meta_NGC_ADPDTK, /* NGC DTK/ADP (.adp/dkt DTK) [no header_id] */ - meta_kRAW, /* almost headerless PCM */ meta_RSF, /* Retro Studios RSF (Metroid Prime .rsf) [no header_id] */ meta_HALPST, /* HAL Labs HALPST */ meta_GCSW, /* GCSW (PCM) */ @@ -470,7 +469,7 @@ typedef enum { meta_WS_AUD, /* Westwood Studios .aud */ meta_WS_AUD_old, /* Westwood Studios .aud, old style */ meta_RIFF_WAVE, /* RIFF, for WAVs */ - meta_RIFF_WAVE_POS, /* .wav + .pos for looping */ + meta_RIFF_WAVE_POS, /* .wav + .pos for looping (Ys Complete PC) */ meta_RIFF_WAVE_labl, /* RIFF w/ loop Markers in LIST-adtl-labl */ meta_RIFF_WAVE_smpl, /* RIFF w/ loop data in smpl chunk */ meta_RIFF_WAVE_MWV, /* .mwv RIFF w/ loop data in ctrl chunk pflt */ @@ -590,8 +589,8 @@ typedef enum { meta_PS2_2PFS, // Konami: Mahoromatic: Moetto - KiraKira Maid-San, GANTZ (PS2) meta_PS2_VBK, // Disney's Stitch - Experiment 626 meta_OTM, // Otomedius (Arcade) - meta_CSTM, // Nintendo 3DS CSTM - meta_FSTM, // Nintendo Wii U FSTM + meta_CSTM, // Nintendo 3DS CSTM (Century Stream) + meta_FSTM, // Nintendo Wii U FSTM (caFe? Stream) meta_3DS_IDSP, // Nintendo 3DS/Wii U IDSP meta_KT_WIIBGM, // Koei Tecmo WiiBGM meta_MCA, /* Capcom MCA "MADP" */ From db3af4d407148217986257f9451e68450d0139b0 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 25 Nov 2017 01:18:27 +0100 Subject: [PATCH 15/17] Rename some blocked layouts for clarity (hopefully) --- src/formats.c | 6 +++--- src/layout/blocked.c | 12 ++++++------ src/layout/{ea_block.c => blocked_ea_schl.c} | 2 +- src/layout/{ea_sns_blocked.c => blocked_ea_sns.c} | 2 +- src/layout/{ivaud_layout.c => blocked_ivaud.c} | 2 +- src/layout/layout.h | 7 +++---- src/libvgmstream.vcproj | 6 +++--- src/libvgmstream.vcxproj | 6 +++--- src/libvgmstream.vcxproj.filters | 6 +++--- src/meta/ea_schl.c | 4 ++-- src/meta/ea_schl_fixed.c | 4 ++-- src/meta/ea_snu.c | 8 ++++---- src/meta/ivaud.c | 4 ++-- src/vgmstream.c | 6 +++--- src/vgmstream.h | 6 +++--- 15 files changed, 40 insertions(+), 41 deletions(-) rename src/layout/{ea_block.c => blocked_ea_schl.c} (97%) rename src/layout/{ea_sns_blocked.c => blocked_ea_sns.c} (92%) rename src/layout/{ivaud_layout.c => blocked_ivaud.c} (92%) diff --git a/src/formats.c b/src/formats.c index e40627ac..7f44b732 100644 --- a/src/formats.c +++ b/src/formats.c @@ -520,7 +520,7 @@ static const layout_info layout_info_list[] = { {layout_ast_blocked, "AST blocked"}, {layout_halpst_blocked, "HALPST blocked"}, {layout_xa_blocked, "CD-ROM XA"}, - {layout_ea_blocked, "blocked (EA SCHl)"}, + {layout_blocked_ea_schl, "blocked (EA SCHl)"}, {layout_blocked_ea_1snh, "blocked (EA 1SNh)"}, {layout_caf_blocked, "CAF blocked"}, {layout_wsi_blocked, ".wsi blocked"}, @@ -538,7 +538,7 @@ static const layout_info layout_info_list[] = { {layout_psx_mgav_blocked, "MGAV blocked"}, {layout_ps2_adm_blocked, "ADM blocked"}, {layout_dsp_bdsp_blocked, "DSP blocked"}, - {layout_ivaud_blocked, "GTA IV blocked"}, + {layout_blocked_ivaud, "blocked (IVAUD)"}, {layout_ps2_iab_blocked, "IAB blocked"}, {layout_ps2_strlr_blocked, "The Bouncer STR blocked"}, {layout_rws_blocked, "RWS blocked"}, @@ -549,7 +549,7 @@ static const layout_info layout_info_list[] = { {layout_aix, "AIX interleave, internally 18-byte interleaved"}, {layout_aax, "AAX blocked, 18-byte interleaved"}, {layout_scd_int, "SCD multistream interleave"}, - {layout_ea_sns_blocked, "Electronic Arts SNS blocked"}, + {layout_blocked_ea_sns, "blocked (EA SNS)"}, {layout_blocked_awc, "blocked (AWC)"}, {layout_blocked_vgs, "blocked (VGS)"}, #ifdef VGM_USE_VORBIS diff --git a/src/layout/blocked.c b/src/layout/blocked.c index 923bce67..e9e0793d 100644 --- a/src/layout/blocked.c +++ b/src/layout/blocked.c @@ -80,8 +80,8 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * case layout_xa_blocked: xa_block_update(vgmstream->next_block_offset,vgmstream); break; - case layout_ea_blocked: - ea_schl_block_update(vgmstream->next_block_offset,vgmstream); + case layout_blocked_ea_schl: + block_update_ea_schl(vgmstream->next_block_offset,vgmstream); break; case layout_blocked_ea_1snh: block_update_ea_1snh(vgmstream->next_block_offset,vgmstream); @@ -125,8 +125,8 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * case layout_filp_blocked: filp_block_update(vgmstream->next_block_offset,vgmstream); break; - case layout_ivaud_blocked: - ivaud_block_update(vgmstream->next_block_offset,vgmstream); + case layout_blocked_ivaud: + block_update_ivaud(vgmstream->next_block_offset,vgmstream); break; case layout_psx_mgav_blocked: psx_mgav_block_update(vgmstream->next_block_offset,vgmstream); @@ -152,8 +152,8 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * case layout_hwas_blocked: hwas_block_update(vgmstream->next_block_offset,vgmstream); break; - case layout_ea_sns_blocked: - ea_sns_block_update(vgmstream->next_block_offset,vgmstream); + case layout_blocked_ea_sns: + block_update_ea_sns(vgmstream->next_block_offset,vgmstream); break; case layout_blocked_awc: block_update_awc(vgmstream->next_block_offset,vgmstream); diff --git a/src/layout/ea_block.c b/src/layout/blocked_ea_schl.c similarity index 97% rename from src/layout/ea_block.c rename to src/layout/blocked_ea_schl.c index 375889aa..dc35e087 100644 --- a/src/layout/ea_block.c +++ b/src/layout/blocked_ea_schl.c @@ -3,7 +3,7 @@ #include "../vgmstream.h" /* set up for the block at the given offset */ -void ea_schl_block_update(off_t block_offset, VGMSTREAM * vgmstream) { +void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream) { int i; int new_schl = 0; STREAMFILE* streamFile = vgmstream->ch[0].streamfile; diff --git a/src/layout/ea_sns_blocked.c b/src/layout/blocked_ea_sns.c similarity index 92% rename from src/layout/ea_sns_blocked.c rename to src/layout/blocked_ea_sns.c index 6e8c41e2..d74dcdc4 100644 --- a/src/layout/ea_sns_blocked.c +++ b/src/layout/blocked_ea_sns.c @@ -3,7 +3,7 @@ #include "../vgmstream.h" /* EA "SNS "blocks (most common in .SNS) */ -void ea_sns_block_update(off_t block_offset, VGMSTREAM * vgmstream) { +void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream) { STREAMFILE* streamFile = vgmstream->ch[0].streamfile; uint32_t block_size, block_samples; size_t file_size = get_streamfile_size(streamFile); diff --git a/src/layout/ivaud_layout.c b/src/layout/blocked_ivaud.c similarity index 92% rename from src/layout/ivaud_layout.c rename to src/layout/blocked_ivaud.c index f5df3c7b..3a950e31 100644 --- a/src/layout/ivaud_layout.c +++ b/src/layout/blocked_ivaud.c @@ -2,7 +2,7 @@ #include "../vgmstream.h" /* set up for the block at the given offset */ -void ivaud_block_update(off_t block_offset, VGMSTREAM * vgmstream) { +void block_update_ivaud(off_t block_offset, VGMSTREAM * vgmstream) { int i; off_t start_offset; off_t interleave_size; diff --git a/src/layout/layout.h b/src/layout/layout.h index b794919b..bc206ea4 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -15,7 +15,7 @@ void halpst_block_update(off_t block_ofset, VGMSTREAM * vgmstream); void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream); -void ea_schl_block_update(off_t block_offset, VGMSTREAM * vgmstream); +void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream); void block_update_ea_1snh(off_t block_offset, VGMSTREAM * vgmstream); @@ -45,7 +45,7 @@ void thp_block_update(off_t block_offset, VGMSTREAM * vgmstream); void filp_block_update(off_t block_offset, VGMSTREAM * vgmstream); -void ivaud_block_update(off_t block_offset, VGMSTREAM * vgmstream); +void block_update_ivaud(off_t block_offset, VGMSTREAM * vgmstream); void psx_mgav_block_update(off_t block_offset, VGMSTREAM * vgmstream); @@ -63,8 +63,7 @@ void rws_block_update(off_t block_offset, VGMSTREAM * vgmstream); void hwas_block_update(off_t block_offset, VGMSTREAM * vgmstream); -void ea_sns_block_update(off_t block_offset, VGMSTREAM * vgmstream); - +void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream); void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream); void block_update_vgs(off_t block_offset, VGMSTREAM * vgmstream); diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 12e40405..11fc016b 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -1611,11 +1611,11 @@ > - - + + @@ -485,7 +485,7 @@ - + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index b556d5fb..935efb30 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -940,10 +940,10 @@ layout\Source Files - + layout\Source Files - + layout\Source Files @@ -970,7 +970,7 @@ layout\Source Files - + layout\Source Files diff --git a/src/meta/ea_schl.c b/src/meta/ea_schl.c index 2d41606b..ae23cc02 100644 --- a/src/meta/ea_schl.c +++ b/src/meta/ea_schl.c @@ -250,7 +250,7 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_ } } else { - vgmstream->layout_type = layout_ea_blocked; + vgmstream->layout_type = layout_blocked_ea_schl; } if (is_bnk) @@ -413,7 +413,7 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_ } else { /* setup first block to update offsets */ - ea_schl_block_update(start_offset,vgmstream); + block_update_ea_schl(start_offset,vgmstream); } diff --git a/src/meta/ea_schl_fixed.c b/src/meta/ea_schl_fixed.c index 42f25c55..1b56893e 100644 --- a/src/meta/ea_schl_fixed.c +++ b/src/meta/ea_schl_fixed.c @@ -58,7 +58,7 @@ VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE *streamFile) { vgmstream->meta_type = meta_EA_SCHL_fixed; - vgmstream->layout_type = layout_ea_blocked; + vgmstream->layout_type = layout_blocked_ea_schl; switch (ea.codec) { case EA_CODEC_PCM: @@ -80,7 +80,7 @@ VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE *streamFile) { goto fail; /* setup first block to update offsets */ - ea_schl_block_update(start_offset,vgmstream); + block_update_ea_schl(start_offset,vgmstream); return vgmstream; diff --git a/src/meta/ea_snu.c b/src/meta/ea_snu.c index 31fd41eb..364c3487 100644 --- a/src/meta/ea_snu.c +++ b/src/meta/ea_snu.c @@ -84,7 +84,7 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { switch(codec) { case 0x04: /* "Xas1": EA-XAS (Dead Space PC/PS3) */ vgmstream->coding_type = coding_EA_XAS; - vgmstream->layout_type = layout_ea_sns_blocked; + vgmstream->layout_type = layout_blocked_ea_sns; break; #if 0 @@ -99,7 +99,7 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, mpeg_start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_EAL32S, &cfg); if (!vgmstream->codec_data) goto fail; - vgmstream->layout_type = layout_ea_sns_blocked; + vgmstream->layout_type = layout_blocked_ea_sns; break; } #endif @@ -154,8 +154,8 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; - if (vgmstream->layout_type == layout_ea_sns_blocked) - ea_sns_block_update(start_offset, vgmstream); + if (vgmstream->layout_type == layout_blocked_ea_sns) + block_update_ea_sns(start_offset, vgmstream); return vgmstream; diff --git a/src/meta/ivaud.c b/src/meta/ivaud.c index 0d585207..5584dc31 100644 --- a/src/meta/ivaud.c +++ b/src/meta/ivaud.c @@ -38,7 +38,7 @@ VGMSTREAM * init_vgmstream_ivaud(STREAMFILE *streamFile) { vgmstream->sample_rate = read_32bitLE(block_table_offset + 0x04,streamFile); vgmstream->coding_type = coding_IMA_int; - vgmstream->layout_type = layout_ivaud_blocked; + vgmstream->layout_type = layout_blocked_ivaud; vgmstream->meta_type = meta_PC_IVAUD; /* open the file for reading */ @@ -57,7 +57,7 @@ VGMSTREAM * init_vgmstream_ivaud(STREAMFILE *streamFile) { // to avoid troubles with "extra" samples vgmstream->num_samples=((read_32bitLE(0x60,streamFile)/2)*2); - ivaud_block_update(start_offset,vgmstream); + block_update_ivaud(start_offset,vgmstream); return vgmstream; diff --git a/src/vgmstream.c b/src/vgmstream.c index 7d42c515..6e794d10 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -923,7 +923,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre case layout_ast_blocked: case layout_halpst_blocked: case layout_xa_blocked: - case layout_ea_blocked: + case layout_blocked_ea_schl: case layout_blocked_ea_1snh: case layout_caf_blocked: case layout_wsi_blocked: @@ -938,7 +938,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre case layout_xvas_blocked: case layout_thp_blocked: case layout_filp_blocked: - case layout_ivaud_blocked: + case layout_blocked_ivaud: case layout_psx_mgav_blocked: case layout_ps2_adm_blocked: case layout_dsp_bdsp_blocked: @@ -947,7 +947,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre case layout_ps2_strlr_blocked: case layout_rws_blocked: case layout_hwas_blocked: - case layout_ea_sns_blocked: + case layout_blocked_ea_sns: case layout_blocked_awc: case layout_blocked_vgs: render_vgmstream_blocked(buffer,sample_count,vgmstream); diff --git a/src/vgmstream.h b/src/vgmstream.h index 652c4c97..ad4c81d3 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -212,7 +212,7 @@ typedef enum { layout_ast_blocked, layout_halpst_blocked, layout_xa_blocked, - layout_ea_blocked, + layout_blocked_ea_schl, layout_blocked_ea_1snh, layout_caf_blocked, layout_wsi_blocked, @@ -231,13 +231,13 @@ typedef enum { layout_ps2_adm_blocked, layout_dsp_bdsp_blocked, layout_mxch_blocked, - layout_ivaud_blocked, /* GTA IV .ivaud blocks */ + layout_blocked_ivaud, /* GTA IV .ivaud blocks */ layout_tra_blocked, /* DefJam Rapstar .tra blocks */ layout_ps2_iab_blocked, layout_ps2_strlr_blocked, layout_rws_blocked, layout_hwas_blocked, - layout_ea_sns_blocked, /* newest Electronic Arts blocks, found in SNS/SNU/SPS/etc formats */ + layout_blocked_ea_sns, /* newest Electronic Arts blocks, found in SNS/SNU/SPS/etc formats */ layout_blocked_awc, /* Rockstar AWC */ layout_blocked_vgs, /* Guitar Hero II (PS2) */ From 2889765c5c9c2c0d43d9b159e3df7e3f3caf187f Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Nov 2017 01:25:27 +0100 Subject: [PATCH 16/17] Fix EA SNU looping not properly saving block state --- src/meta/ea_snu.c | 83 +++++++++++++++++++++++++++++------------------ src/vgmstream.c | 9 +++-- src/vgmstream.h | 30 ++++++++--------- 3 files changed, 71 insertions(+), 51 deletions(-) diff --git a/src/meta/ea_snu.c b/src/meta/ea_snu.c index 364c3487..5c4708ac 100644 --- a/src/meta/ea_snu.c +++ b/src/meta/ea_snu.c @@ -6,9 +6,9 @@ /* .SNU - from EA Redwood Shores/Visceral games (Dead Space, Dante's Inferno, The Godfather 2) */ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - int channel_count, loop_flag = 0, channel_config, codec, sample_rate, flags; + int channel_count, loop_flag = 0, version, codec, channel_config, sample_rate, flags; uint32_t num_samples, loop_start = 0, loop_end = 0; - off_t start_offset; + off_t start_offset, header_offset; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; @@ -16,7 +16,7 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { if (!check_extensions(streamFile,"snu")) goto fail; - /* check header (the first 0x10 are BE/LE depending on platform) */ + /* EA SNU header (BE/LE depending on platform) */ /* 0x00(1): related to sample rate? (03=48000) * 0x01(1): flags/count? (when set has extra block data before start_offset) * 0x02(1): always 0? @@ -32,32 +32,48 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { read_32bit = read_32bitLE; } - start_offset = read_32bit(0x08,streamFile); + header_offset = 0x10; /* points to EA SNH/SPH header */ + start_offset = read_32bit(0x08,streamFile); /* points to EA SNS/SPS blocks */ - codec = read_8bit(0x10,streamFile); - channel_config = read_8bit(0x11,streamFile); - sample_rate = (uint16_t)read_16bitBE(0x12,streamFile); - flags = (uint8_t)read_8bit(0x14,streamFile); /* upper nibble only? */ - num_samples = (uint32_t)read_32bitBE(0x14,streamFile) & 0x00FFFFFF; - /* 0x18: null?, 0x1c: null? */ - if (flags != 0x60 && flags != 0x40) { - VGM_LOG("EA SNS: unknown flag\n"); + /* Beyond is the newest EA header (from EAAudioCore library) still generated by sx.exe. + * Its audio "assets" come in separate RAM headers (.SNR/SPH) and raw blocked streams (.SNS/SPS), + * or together in pseudoformats (.SNU, .SBR+.SBS banks, .AEMS, .MUS, etc). + * Some .SNR include stream data, while most (all?) .SPS have headers so .SPH is optional. */ + + /* EA SNR header */ + version = (read_8bit(header_offset + 0x00,streamFile) >> 4) & 0xf; + codec = (read_8bit(header_offset + 0x00,streamFile) >> 0) & 0xf; + channel_config = read_8bit(header_offset + 0x01,streamFile); + sample_rate = (uint16_t)read_16bitBE(header_offset + 0x02,streamFile); + flags = (uint8_t)read_8bit(header_offset + 0x04,streamFile); /* upper nibble only? */ + num_samples = (uint32_t)read_32bitBE(header_offset + 0x04,streamFile) & 0x00FFFFFF; + /* optional, in some headers: + * 0x08: null? + * 0x0c: varies (ex. null, full size) */ + /* headered .SPS start with an id of 0x480000xx (not present in .SPH = not part of the header) */ + + /* V0: SNR+SNS, V1: SPR+SPS (not apparent differences) */ + if (version != 0 && version != 1) { + VGM_LOG("EA SNS/SPS: unknown version\n"); goto fail; } -#if 0 - //todo not working ok with blocks in XAS - //todo check if EA-XMA loops (Dante's Inferno doesn't) - if (flags & 0x60) { /* full loop, seen in ambient tracks */ + /* & 0x40: stream asset?, 0x20: full loop?, 0x00: RAM asset?, 0x01: loop? */ + if (flags != 0x60 && flags != 0x40) { + VGM_LOG("EA SNS/SPS: unknown flag 0x%02x\n", flags); + } + + /* full loop seen in Dead Space ambient tracks */ + if (flags == 0x60) { + VGM_LOG("flg=%x\n",flags); loop_flag = 1; loop_start = 0; loop_end = num_samples; } -#endif - //channel_count = (channel_config >> 2) + 1; //todo test - /* 01/02/03 = 1 ch?, 05/06/07 = 2/3 ch?, 0d/0e/0f = 4/5 ch?, 15/16/17 = 6/7 ch?, 1d/1e/1f = 8 ch? */ + /* accepted channel configs only seem to be mono/stereo/quad/5.1/7.1 */ + //channel_count = ((channel_config >> 2) & 0xf) + 1; switch(channel_config) { case 0x00: channel_count = 1; break; case 0x04: channel_count = 2; break; @@ -65,7 +81,7 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { case 0x14: channel_count = 6; break; case 0x1c: channel_count = 8; break; default: - VGM_LOG("EA SNU: unknown channel config 0x%02x\n", channel_config); + VGM_LOG("EA SNS/SPS: unknown channel config 0x%02x\n", channel_config); goto fail; } @@ -81,6 +97,7 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { vgmstream->meta_type = meta_EA_SNU; + /* EA decoder list and known internal FourCCs */ switch(codec) { case 0x04: /* "Xas1": EA-XAS (Dead Space PC/PS3) */ vgmstream->coding_type = coding_EA_XAS; @@ -89,7 +106,7 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { #if 0 #ifdef VGM_USE_MPEG - case 0x07: { /* "EL32S": EALayer3 v2 "S" (Dante's Inferno PS3) */ + case 0x07: { /* "L32S": EALayer3 v2 "S" (Dante's Inferno PS3) */ mpeg_custom_config cfg; off_t mpeg_start_offset = start_offset + 0x08; @@ -133,19 +150,23 @@ VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE *streamFile) { break; } #endif - case 0x00: /* "NONE" */ - case 0x01: /* not used? */ - case 0x02: /* "P6B0": PCM16BE */ + case 0x00: /* "NONE" (internal codec not set flag) */ + case 0x01: /* not used/reserved? MP30/P6L0/P2B0/P2L0/P8S0/P8U0/PFN0? */ + case 0x02: /* "P6B0": PCM16BE */ case 0x05: /* "EL31": EALayer3 v1 b (with PCM blocks in normal EA-frames?) */ - case 0x06: /* "EL32P": EALayer3 v2 "P" */ - case 0x09: /* EASpeex? */ - case 0x0c: /* EAOpus? */ - case 0x0e: /* XAS variant? */ - case 0x0f: /* EALayer3 variant? */ - /* also 0x1n variations, used in other headers */ + case 0x06: /* "L32P": EALayer3 v2 "P" */ + + case 0x08: /* ? */ + case 0x09: /* EASpeex? "Esp0" (libspeex variant) */ + case 0x0a: /* EATrax (ATRAC9 variant, deflated frames) */ + case 0x0b: /* ? */ + case 0x0c: /* EAOpus (inside each SNS/SPS block is 16b frame size + Opus standard? packet) */ + case 0x0d: /* ? */ + case 0x0e: /* ? */ + case 0x0f: /* ? */ default: - VGM_LOG("EA SNU: unknown codec 0x%02x\n", codec); + VGM_LOG("EA SNS/SPS: unknown codec 0x%02x\n", codec); goto fail; } diff --git a/src/vgmstream.c b/src/vgmstream.c index 6e794d10..b27b52b5 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -435,16 +435,17 @@ static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile) { #ifdef VGM_DEBUG_OUTPUT +#ifdef VGM_USE_FFMPEG /* debug fun */ - { + if (vgmstream->coding_type != coding_FFmpeg){ int i = 0; - /* probable segfault but some layouts/codecs could ignore these */ + /* probable segfault but some layouts/codecs can ignore these */ for (i = 0; i < vgmstream->channels; i++) { VGM_ASSERT(vgmstream->ch[i].streamfile == NULL, "VGMSTREAM: null streamfile in ch%i\n",i); } } - +#endif #endif/*VGM_DEBUG_OUTPUT*/ @@ -1970,6 +1971,7 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) { vgmstream->current_sample = vgmstream->loop_sample; vgmstream->samples_into_block = vgmstream->loop_samples_into_block; vgmstream->current_block_size = vgmstream->loop_block_size; + vgmstream->current_block_samples = vgmstream->loop_block_samples; vgmstream->current_block_offset = vgmstream->loop_block_offset; vgmstream->next_block_offset = vgmstream->loop_next_block_offset; @@ -1985,6 +1987,7 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) { vgmstream->loop_sample = vgmstream->current_sample; vgmstream->loop_samples_into_block = vgmstream->samples_into_block; vgmstream->loop_block_size = vgmstream->current_block_size; + vgmstream->loop_block_samples = vgmstream->current_block_samples; vgmstream->loop_block_offset = vgmstream->current_block_offset; vgmstream->loop_next_block_offset = vgmstream->next_block_offset; vgmstream->hit_loop = 1; diff --git a/src/vgmstream.h b/src/vgmstream.h index ad4c81d3..80fe526c 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -717,40 +717,36 @@ typedef struct { char stream_name[STREAM_NAME_SIZE]; /* name of the current stream (info), if the file stores it and it's filled */ /* looping */ - int loop_flag; /* is this stream looped? */ - int32_t loop_start_sample; /* first sample of the loop (included in the loop) */ - int32_t loop_end_sample; /* last sample of the loop (not included in the loop) */ + int loop_flag; /* is this stream looped? */ + int32_t loop_start_sample; /* first sample of the loop (included in the loop) */ + int32_t loop_end_sample; /* last sample of the loop (not included in the loop) */ - /* channels */ - VGMSTREAMCHANNEL * ch; /* pointer to array of channels */ + /* layouts/block */ + size_t interleave_block_size; /* interleave for this file */ + size_t interleave_smallblock_size; /* smaller interleave for last block */ + size_t full_block_size; /* fixed data size, from header (may include padding and other unusable data) */ - /* channel copies */ + /* channel state */ + VGMSTREAMCHANNEL * ch; /* pointer to array of channels */ VGMSTREAMCHANNEL * start_ch; /* copies of channel status as they were at the beginning of the stream */ VGMSTREAMCHANNEL * loop_ch; /* copies of channel status as they were at the loop point */ - /* layout-specific */ + /* layout/block state */ int32_t current_sample; /* number of samples we've passed */ int32_t samples_into_block; /* number of samples into the current block */ - /* interleave */ - size_t interleave_block_size; /* interleave for this file */ - size_t interleave_smallblock_size; /* smaller interleave for last block */ - /* headered blocks */ off_t current_block_offset; /* start of this block (offset of block header) */ size_t current_block_size; /* size in usable bytes of the block we're in now (used to calculate num_samples per block) */ size_t current_block_samples; /* size in samples of the block we're in now (used over current_block_size if possible) */ - size_t full_block_size; /* size including padding and other unusable data */ off_t next_block_offset; /* offset of header of the next block */ - int block_count; /* count of "semi" block in total block */ - - - /* loop layout (saved values) */ + /* layout/block loop state */ int32_t loop_sample; /* saved from current_sample, should be loop_start_sample... */ int32_t loop_samples_into_block;/* saved from samples_into_block */ off_t loop_block_offset; /* saved from current_block_offset */ size_t loop_block_size; /* saved from current_block_size */ + size_t loop_block_samples; /* saved from current_block_samples */ off_t loop_next_block_offset; /* saved from next_block_offset */ - /* loop internals */ + /* loop state */ int hit_loop; /* have we seen the loop yet? */ /* counters for "loop + play end of the stream instead of fading" (not used/needed otherwise) */ int loop_count; /* number of complete loops (1=looped once) */ From 770a27d0b41c58bfd57ebe6d17f5939887eed795 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 26 Nov 2017 01:54:33 +0100 Subject: [PATCH 17/17] Add dual extension in try_dual_file_stereo for Homura (PS2) --- src/formats.c | 1 + src/meta/ps2_smpl.c | 35 ++++++------------------------ src/vgmstream.c | 52 +++++++++++++++++++++++++++++++-------------- 3 files changed, 43 insertions(+), 45 deletions(-) diff --git a/src/formats.c b/src/formats.c index 7f44b732..cf77b8ce 100644 --- a/src/formats.c +++ b/src/formats.c @@ -310,6 +310,7 @@ static const char* extension_list[] = { "um3", "v0", + //"v1", //dual channel with v0 "vag", "vas", "vawx", diff --git a/src/meta/ps2_smpl.c b/src/meta/ps2_smpl.c index 57e2ec5b..e44bd7ed 100644 --- a/src/meta/ps2_smpl.c +++ b/src/meta/ps2_smpl.c @@ -1,26 +1,23 @@ #include "meta.h" #include "../coding/coding.h" -/* SMPL - from Homura */ +/* SMPL - from Homura (PS2) */ VGMSTREAM * init_vgmstream_ps2_smpl(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - STREAMFILE * streamRch = NULL; off_t start_offset; int loop_flag, channel_count; size_t channel_size; /* check extension (.v0: left channel, .v1: right channel, .smpl: header id) */ - if ( !check_extensions(streamFile,"v0,smpl") ) + if ( !check_extensions(streamFile,"v0,v1,smpl") ) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x534D504C) /* "SMPL" */ goto fail; - /* right channel is in .V1 and doesn't have loop points; manually parse as dual_stereo would fail */ - streamRch = open_stream_ext(streamFile, "V1"); - channel_count = streamRch != NULL ? 2 : 1; - loop_flag = (read_32bitLE(0x30,streamFile) != 0); + channel_count = 1; + loop_flag = (read_32bitLE(0x30,streamFile) != 0); /* .v1 doesn't have loop points */ start_offset = 0x40; channel_size = read_32bitBE(0x0c,streamFile) - 0x10; @@ -41,31 +38,11 @@ VGMSTREAM * init_vgmstream_ps2_smpl(STREAMFILE *streamFile) { read_string(vgmstream->stream_name,0x10+1, 0x20,streamFile); /* open the file for reading */ - //if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) - // goto fail; - - /* custom dual channel */ // todo improve dual_stereo - { - int i; - char filename[PATH_LIMIT]; - - streamFile->get_name(streamFile,filename,sizeof(filename)); - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename, STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) goto fail; - - if (channel_count == 2) - vgmstream->ch[1].streamfile = streamRch; - - for (i = 0; i < channel_count; i++) { - vgmstream->ch[i].channel_start_offset = - vgmstream->ch[i].offset = start_offset; - } - } - + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; return vgmstream; fail: - if (streamRch) close_streamfile(streamRch); close_vgmstream(vgmstream); return NULL; } diff --git a/src/vgmstream.c b/src/vgmstream.c index b27b52b5..a09dd3c8 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -2157,9 +2157,10 @@ static void try_dual_file_stereo(VGMSTREAM * opened_vgmstream, STREAMFILE *strea static const char * const dfs_pairs[][2] = { {"L","R"}, {"l","r"}, - {"_0","_1"}, {"left","right"}, {"Left","Right"}, + {".V0",".V1"}, + {"_0","_1"}, //unneeded? }; char new_filename[PATH_LIMIT]; char * ext; @@ -2180,7 +2181,7 @@ static void try_dual_file_stereo(VGMSTREAM * opened_vgmstream, STREAMFILE *strea if (strlen(new_filename)<2) return; /* we need at least a base and a name ending to replace */ ext = (char *)filename_extension(new_filename); - if (ext-new_filename >= 1 && ext[-1]=='.') ext--; /* excluding "." */ + if (ext-new_filename >= 1 && ext[-1]=='.') ext--; /* including "." */ /* find pair from base name and modify new_filename with the opposite */ dfs_pair_count = (sizeof(dfs_pairs)/sizeof(dfs_pairs[0])); @@ -2188,16 +2189,24 @@ static void try_dual_file_stereo(VGMSTREAM * opened_vgmstream, STREAMFILE *strea for (j=0; dfs_pair==-1 && j<2; j++) { const char * this_suffix = dfs_pairs[i][j]; size_t this_suffix_len = strlen(dfs_pairs[i][j]); + const char * other_suffix = dfs_pairs[i][j^1]; + size_t other_suffix_len = strlen(dfs_pairs[i][j^1]); /* if suffix matches copy opposite to ext pointer (thus to new_filename) */ - if ( !memcmp(ext - this_suffix_len,this_suffix,this_suffix_len) ) { - const char * other_suffix = dfs_pairs[i][j^1]; - size_t other_suffix_len = strlen(dfs_pairs[i][j^1]); - - dfs_pair = j; - memmove(ext + other_suffix_len - this_suffix_len, ext,strlen(ext)+1); /* move the extension and terminator, too */ - memcpy (ext - this_suffix_len, other_suffix,other_suffix_len); /* make the new name */ + if (this_suffix[0] == '.' && strlen(ext) == this_suffix_len) { /* dual extension (ex. Homura PS2) */ + if ( !memcmp(ext,this_suffix,this_suffix_len) ) { + dfs_pair = j; + memcpy (ext, other_suffix,other_suffix_len); /* overwrite with new extension */ + } } + else { /* dual suffix */ + if ( !memcmp(ext - this_suffix_len,this_suffix,this_suffix_len) ) { + dfs_pair = j; + memmove(ext + other_suffix_len - this_suffix_len, ext,strlen(ext)+1); /* move the extension and terminator, too */ + memcpy (ext - this_suffix_len, other_suffix,other_suffix_len); /* overwrite with new suffix */ + } + } + } } @@ -2205,6 +2214,7 @@ static void try_dual_file_stereo(VGMSTREAM * opened_vgmstream, STREAMFILE *strea if (dfs_pair == -1) goto fail; + /* try to init other channel (new_filename now has the opposite name) */ dual_streamFile = streamFile->open(streamFile,new_filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!dual_streamFile) goto fail; @@ -2213,7 +2223,7 @@ static void try_dual_file_stereo(VGMSTREAM * opened_vgmstream, STREAMFILE *strea close_streamfile(dual_streamFile); /* see if we were able to open the file, and if everything matched nicely */ - if (new_vgmstream && + if (!(new_vgmstream && new_vgmstream->channels == 1 && /* we have seen legitimate pairs where these are off by one... * but leaving it commented out until I can find those and recheck */ @@ -2223,15 +2233,24 @@ static void try_dual_file_stereo(VGMSTREAM * opened_vgmstream, STREAMFILE *strea new_vgmstream->meta_type == opened_vgmstream->meta_type && new_vgmstream->coding_type == opened_vgmstream->coding_type && new_vgmstream->layout_type == opened_vgmstream->layout_type && - new_vgmstream->loop_flag == opened_vgmstream->loop_flag && - /* check these even if there is no loop, because they should then be zero in both */ - new_vgmstream->loop_start_sample == opened_vgmstream->loop_start_sample && - new_vgmstream->loop_end_sample == opened_vgmstream->loop_end_sample && /* check even if the layout doesn't use them, because it is * difficult to determine when it does, and they should be zero otherwise, anyway */ new_vgmstream->interleave_block_size == opened_vgmstream->interleave_block_size && - new_vgmstream->interleave_smallblock_size == opened_vgmstream->interleave_smallblock_size) { - /* We seem to have a usable, matching file. Merge in the second channel. */ + new_vgmstream->interleave_smallblock_size == opened_vgmstream->interleave_smallblock_size)) { + goto fail; + } + + /* check these even if there is no loop, because they should then be zero in both + * Homura PS2 right channel doesn't have loop points so it's ignored */ + if (new_vgmstream->meta_type != meta_PS2_SMPL && + !(new_vgmstream->loop_flag == opened_vgmstream->loop_flag && + new_vgmstream->loop_start_sample== opened_vgmstream->loop_start_sample && + new_vgmstream->loop_end_sample == opened_vgmstream->loop_end_sample)) { + goto fail; + } + + /* We seem to have a usable, matching file. Merge in the second channel. */ + { VGMSTREAMCHANNEL * new_chans; VGMSTREAMCHANNEL * new_loop_chans = NULL; VGMSTREAMCHANNEL * new_start_chans = NULL; @@ -2283,6 +2302,7 @@ static void try_dual_file_stereo(VGMSTREAM * opened_vgmstream, STREAMFILE *strea /* discard the second VGMSTREAM */ free(new_vgmstream); } + fail: return; }