From 6c141a6582de6dcb66adcfefb2ab5e1ce64649e5 Mon Sep 17 00:00:00 2001 From: bnnm Date: Wed, 15 Nov 2017 23:26:38 +0100 Subject: [PATCH 01/23] Clean .dvi/.kcey and add proper .PCM extension --- src/formats.c | 8 +++--- src/meta/dc_kcey.c | 61 ++++++++++++++------------------------------ src/meta/meta.h | 4 +-- src/meta/sat_dvi.c | 63 +++++++++++++++------------------------------- src/vgmstream.c | 4 +-- src/vgmstream.h | 6 ++--- 6 files changed, 50 insertions(+), 96 deletions(-) diff --git a/src/formats.c b/src/formats.c index 747337ea..75f4f2cb 100644 --- a/src/formats.c +++ b/src/formats.c @@ -97,7 +97,7 @@ static const char* extension_list[] = { "dsp", "dspw", "dtk", - "dvi", + "dvi", //fake extension (to be removed) "dxh", "eam", @@ -148,7 +148,7 @@ static const char* extension_list[] = { "jstm", "kces", - "kcey", + "kcey", //fake extension (to be removed) "khv", "kovs", "kraw", @@ -651,8 +651,8 @@ static const meta_info meta_info_list[] = { {meta_FILP, "Bio Hazard - Gun Survivor FILp Header"}, {meta_IKM, "Zwei!! IKM Header"}, {meta_SFS, "Baroque SFS Header"}, - {meta_DVI, "DVI Header"}, - {meta_KCEY, "KCEYCOMP Header"}, + {meta_SAT_DVI, "Konami KCEN DVI. header"}, + {meta_DC_KCEY, "Konami KCEY KCEYCOMP header"}, {meta_BG00, "Falcom BG00 Header"}, {meta_PS2_RSTM, "Rockstar Games RSTM Header"}, {meta_ACM, "InterPlay ACM Header"}, diff --git a/src/meta/dc_kcey.c b/src/meta/dc_kcey.c index abf9f663..e68018e1 100644 --- a/src/meta/dc_kcey.c +++ b/src/meta/dc_kcey.c @@ -1,65 +1,42 @@ #include "meta.h" -#include "../coding/coding.h" -#include "../util.h" -VGMSTREAM * init_vgmstream_kcey(STREAMFILE *streamFile) { +/* DVI - from Konami KCE Yokohama DC games (Pop'n Music series) */ +VGMSTREAM * init_vgmstream_dc_kcey(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; off_t start_offset; + int loop_flag, channel_count; - int loop_flag = 0; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("kcey",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x4B434559) /* "DVI." */ + /* check extension (.pcm: original, .kcey: renamed to header id) */ + if ( !check_extensions(streamFile,"pcm,kcey") ) goto fail; - loop_flag = (read_32bitBE(0x14,streamFile)!=0xFFFFFFFF); + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x4B434559) /* "KCEY" (also "COMP") */ + goto fail; + + start_offset = read_32bitBE(0x10,streamFile); + loop_flag = (read_32bitBE(0x14,streamFile) != 0xFFFFFFFF); channel_count = read_32bitBE(0x08,streamFile); - /* build the VGMSTREAM */ + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - vgmstream->channels = channel_count; - start_offset = read_32bitBE(0x10,streamFile); vgmstream->sample_rate = 37800; - vgmstream->coding_type = coding_EACS_IMA; - vgmstream->num_samples = read_32bitBE(0x0C,streamFile); - - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile); - vgmstream->loop_end_sample = read_32bitBE(0x0C,streamFile); - } + vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile); + vgmstream->loop_end_sample = read_32bitBE(0x0C,streamFile); + vgmstream->coding_type = coding_EACS_IMA; vgmstream->layout_type = layout_none; - vgmstream->meta_type = meta_KCEY; - vgmstream->get_high_nibble=1; + vgmstream->meta_type = meta_DC_KCEY; - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+(i*vgmstream->interleave_block_size); - vgmstream->ch[i].adpcm_history1_32=0; - vgmstream->ch[i].adpcm_step_index=0; - } - } + /* open the file for reading */ + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; diff --git a/src/meta/meta.h b/src/meta/meta.h index fe194a95..121b51e5 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -200,11 +200,11 @@ VGMSTREAM * init_vgmstream_ikm(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_sfs(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_dvi(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_sat_dvi(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_bg00(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_kcey(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_dc_kcey(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ps2_rstm(STREAMFILE * streamFile); diff --git a/src/meta/sat_dvi.c b/src/meta/sat_dvi.c index 4c5f4529..5bc57366 100644 --- a/src/meta/sat_dvi.c +++ b/src/meta/sat_dvi.c @@ -1,67 +1,44 @@ #include "meta.h" -#include "../util.h" -/* DVI (Castlevania Symphony of the Night) */ -VGMSTREAM * init_vgmstream_dvi(STREAMFILE *streamFile) { +/* DVI - from Konami KCE Nayoga SAT games (Castlevania Symphony of the Night, Jikkyou Oshaberi Parodius - Forever with Me) */ +VGMSTREAM * init_vgmstream_sat_dvi(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; off_t start_offset; + int loop_flag, channel_count; - int loop_flag = 0; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("dvi",filename_extension(filename))) goto fail; + /* check extension (.pcm: original, .dvi: renamed to header id) */ + if ( !check_extensions(streamFile,"pcm,dvi") ) + goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x4456492E) /* "DVI." */ goto fail; - loop_flag = (read_32bitBE(0x0C,streamFile)!=0xFFFFFFFF); - channel_count = 2; - - /* build the VGMSTREAM */ + start_offset = read_32bitBE(0x04,streamFile); + loop_flag = (read_32bitBE(0x0C,streamFile) != 0xFFFFFFFF); + channel_count = 2; /* no mono files seem to exists */ + + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - vgmstream->channels = channel_count; - start_offset = read_32bitBE(0x04,streamFile); vgmstream->sample_rate = 44100; - vgmstream->coding_type = coding_DVI_IMA_int; - vgmstream->num_samples = read_32bitBE(0x08,streamFile); - - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitBE(0x0C,streamFile); - vgmstream->loop_end_sample = read_32bitBE(0x08,streamFile); - } + vgmstream->loop_start_sample = read_32bitBE(0x0C,streamFile); + vgmstream->loop_end_sample = read_32bitBE(0x08,streamFile); + vgmstream->coding_type = coding_DVI_IMA_int; vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 4; - vgmstream->meta_type = meta_DVI; - vgmstream->get_high_nibble=1; + vgmstream->interleave_block_size = 4; + vgmstream->meta_type = meta_SAT_DVI; + /* at 0x10 (L) / 0x20 (R): probably ADPCM loop history @+0x00 and step @+0x17 (not init values) */ - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+(i*vgmstream->interleave_block_size); - vgmstream->ch[i].adpcm_history1_32=0; - vgmstream->ch[i].adpcm_step_index=0; - } - } - + /* open the file for reading */ + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; diff --git a/src/vgmstream.c b/src/vgmstream.c index 52098270..f0b7209c 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -113,8 +113,8 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_ikm, init_vgmstream_sfs, init_vgmstream_bg00, - init_vgmstream_dvi, - init_vgmstream_kcey, + init_vgmstream_sat_dvi, + init_vgmstream_dc_kcey, init_vgmstream_ps2_rstm, init_vgmstream_acm, init_vgmstream_mus_acm, diff --git a/src/vgmstream.h b/src/vgmstream.h index 794963b7..f10fba06 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -317,7 +317,7 @@ typedef enum { meta_HIS, /* Her Ineractive .his */ meta_BNSF, /* Bandai Namco Sound Format */ - meta_PSX_XA, /* CD-ROM XA with RIFF header */ + meta_PSX_XA, /* CD-ROM XA */ meta_PS2_SShd, /* .ADS with SShd header */ meta_PS2_NPSF, /* Namco Production Sound File */ meta_PS2_RXWS, /* Sony games (Genji, Okage Shadow King, Arc The Lad Twilight of Spirits) */ @@ -487,8 +487,8 @@ typedef enum { meta_NWA, /* Visual Art's NWA */ meta_NWA_NWAINFOINI, /* Visual Art's NWA w/ NWAINFO.INI for looping */ meta_NWA_GAMEEXEINI, /* Visual Art's NWA w/ Gameexe.ini for looping */ - meta_DVI, /* DVI Interleaved */ - meta_KCEY, /* KCEYCOMP */ + meta_SAT_DVI, /* Konami KCE Nagoya DVI (SAT games) */ + 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 */ From a68e567fc26893fd2bbd8afee9924992a2d90db3 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 16 Nov 2017 00:26:05 +0100 Subject: [PATCH 02/23] Remove unneeded function --- src/meta/ea_old.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/meta/ea_old.c b/src/meta/ea_old.c index d32878be..45631e40 100644 --- a/src/meta/ea_old.c +++ b/src/meta/ea_old.c @@ -56,8 +56,7 @@ VGMSTREAM * init_vgmstream_eacs(STREAMFILE *streamFile) { if (!vgmstream) goto fail; /* fill in the vital statistics */ - init_get_high_nibble(vgmstream); - + vgmstream->sample_rate = ea_header->dwSampleRate; if(ea_header->bCompression==0) { From 0cf96007917c733023ed83120a4cc5b0e114bf3e Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 16 Nov 2017 00:32:22 +0100 Subject: [PATCH 03/23] Clean/separate PS2 .PCM and fix looping in some cases --- src/formats.c | 2 +- src/libvgmstream.vcproj | 4 ++ src/libvgmstream.vcxproj | 1 + src/libvgmstream.vcxproj.filters | 3 ++ src/meta/pcm.c | 65 -------------------------------- src/meta/ps2_pcm.c | 48 +++++++++++++++++++++++ src/vgmstream.h | 2 +- 7 files changed, 58 insertions(+), 67 deletions(-) create mode 100644 src/meta/ps2_pcm.c diff --git a/src/formats.c b/src/formats.c index 75f4f2cb..44595229 100644 --- a/src/formats.c +++ b/src/formats.c @@ -666,7 +666,7 @@ static const meta_info meta_info_list[] = { {meta_RIFX_WAVE_smpl, "RIFX WAVE header with sample looping info"}, {meta_XNB, "Microsoft XNA Game Studio 4.0 header"}, {meta_PCM_SCD, "PCM file with custom header (SCD)"}, - {meta_PCM_PS2, "PCM file with custom header (PS2)"}, + {meta_PS2_PCM, "Konami KCEJ East .PCM header"}, {meta_PS2_RKV, "Legacy of Kain - Blood Omen 2 RKV Header"}, {meta_PS2_PSW, "Rayman Raving Rabbids Riff Container File"}, {meta_PS2_VAS, "Pro Baseball Spirits 5 VAS Header"}, diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index e90ca7d1..64a74c1d 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -858,6 +858,10 @@ RelativePath=".\meta\ps2_p2bt.c" > + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index bcebddb0..c6bf8d17 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -333,6 +333,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index fc39f79e..de9b1c5f 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -517,6 +517,9 @@ meta\Source Files + + meta\Source Files + meta\Source Files diff --git a/src/meta/pcm.c b/src/meta/pcm.c index 30ca247e..ddd47eca 100644 --- a/src/meta/pcm.c +++ b/src/meta/pcm.c @@ -61,68 +61,3 @@ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; } - - -/* PCM - Custom header from Konami, which contains only loop infos... - found in: Ephemeral Fantasia [Reiselied] - Yu-Gi-Oh! The Duelists of the Roses [Yu-Gi-Oh! Shin Duel Monsters II] -*/ -VGMSTREAM * init_vgmstream_pcm_ps2(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - off_t start_offset; - int loop_flag = 0; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("pcm",filename_extension(filename))) goto fail; - - // if ((read_32bitLE(0x00,streamFile)+0x800) != (get_streamfile_size(streamFile))) - // goto fail; - if ((read_32bitLE(0x00,streamFile)) != (read_32bitLE(0x04,streamFile)*4)) - goto fail; - - loop_flag = (read_32bitLE(0x08,streamFile) != 0x0); - channel_count = 2; - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - start_offset = 0x800; - vgmstream->channels = channel_count; - vgmstream->sample_rate = 24000; - vgmstream->coding_type = coding_PCM16LE; - vgmstream->num_samples = read_32bitLE(0x0,streamFile)/2/channel_count; - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile); - vgmstream->loop_end_sample = read_32bitLE(0x0C,streamFile); - } - - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x2; - vgmstream->meta_type = meta_PCM_PS2; - - /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - } - } - - return vgmstream; - - /* clean up anything we may have opened */ -fail: - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} diff --git a/src/meta/ps2_pcm.c b/src/meta/ps2_pcm.c new file mode 100644 index 00000000..1564a3f0 --- /dev/null +++ b/src/meta/ps2_pcm.c @@ -0,0 +1,48 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* .PCM - KCE Japan East PS2 games (Ephemeral Fantasia, Yu-Gi-Oh! The Duelists of the Roses, 7 Blades) */ +VGMSTREAM * init_vgmstream_pcm_ps2(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset; + int loop_flag, channel_count; + + /* check extension */ + if ( !check_extensions(streamFile,"pcm") ) + goto fail; + + /* check header (data_size vs num_samples) */ + if (pcm_bytes_to_samples(read_32bitLE(0x00,streamFile), 2, 16) != read_32bitLE(0x04,streamFile)) + goto fail; + /* should work too */ + //if (read_32bitLE(0x00,streamFile)+0x800 != get_streamfile_size(streamFile)) + // goto fail; + + loop_flag = (read_32bitLE(0x0C,streamFile) != 0x00); + channel_count = 2; + start_offset = 0x800; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; + + vgmstream->channels = channel_count; + vgmstream->sample_rate = 24000; + vgmstream->num_samples = read_32bitLE(0x04,streamFile); + vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile); + vgmstream->loop_end_sample = read_32bitLE(0x0C,streamFile); + + vgmstream->coding_type = coding_PCM16LE; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x2; + vgmstream->meta_type = meta_PS2_PCM; + + /* open the file for reading */ + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; + return vgmstream; + +fail: + if (vgmstream) close_vgmstream(vgmstream); + return NULL; +} diff --git a/src/vgmstream.h b/src/vgmstream.h index f10fba06..44776433 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -370,7 +370,7 @@ typedef enum { meta_PS2_DXH, /* Tokobot Plus - Myteries of the Karakuri */ meta_PS2_PSH, /* Dawn of Mana - Seiken Densetsu 4 */ meta_PCM_SCD, /* Lunar - Eternal Blue */ - meta_PCM_PS2, /* Konami: Ephemeral Fantasia, Yu-Gi-Oh! The Duelists of the Roses */ + meta_PS2_PCM, /* Konami KCEJ East: Ephemeral Fantasia, Yu-Gi-Oh! The Duelists of the Roses, 7 Blades */ meta_PS2_RKV, /* Legacy of Kain - Blood Omen 2 */ meta_PS2_PSW, /* Rayman Raving Rabbids */ meta_PS2_VAS, /* Pro Baseball Spirits 5 */ From 2ad3d432f169782ba9cdd2f1d5bdf33bf31cbdcf Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 16 Nov 2017 00:41:06 +0100 Subject: [PATCH 04/23] Rename pcm.c > scd_pcm.c (cleanup) --- src/formats.c | 2 +- src/libvgmstream.vcproj | 2 +- src/libvgmstream.vcxproj | 2 +- src/libvgmstream.vcxproj.filters | 2 +- src/meta/meta.h | 4 ++-- src/meta/ps2_pcm.c | 2 +- src/meta/{pcm.c => scd_pcm.c} | 4 ++-- src/vgmstream.c | 4 ++-- src/vgmstream.h | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) rename src/meta/{pcm.c => scd_pcm.c} (91%) diff --git a/src/formats.c b/src/formats.c index 44595229..12c7fe0d 100644 --- a/src/formats.c +++ b/src/formats.c @@ -665,7 +665,7 @@ static const meta_info meta_info_list[] = { {meta_RIFX_WAVE, "RIFX WAVE header"}, {meta_RIFX_WAVE_smpl, "RIFX WAVE header with sample looping info"}, {meta_XNB, "Microsoft XNA Game Studio 4.0 header"}, - {meta_PCM_SCD, "PCM file with custom header (SCD)"}, + {meta_SCD_PCM, "Lunar: Eternal Blue .PCM header"}, {meta_PS2_PCM, "Konami KCEJ East .PCM header"}, {meta_PS2_RKV, "Legacy of Kain - Blood Omen 2 RKV Header"}, {meta_PS2_PSW, "Rayman Raving Rabbids Riff Container File"}, diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 64a74c1d..a8adc1ac 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -691,7 +691,7 @@ > - + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index de9b1c5f..8e1f0aa6 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -406,7 +406,7 @@ meta\Source Files - + meta\Source Files diff --git a/src/meta/meta.h b/src/meta/meta.h index 121b51e5..34b25b19 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -218,9 +218,9 @@ VGMSTREAM * init_vgmstream_ps2_psh(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_pcm_scd(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_scd_pcm(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_pcm_ps2(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_ps2_pcm(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ps2_rkv(STREAMFILE * streamFile); diff --git a/src/meta/ps2_pcm.c b/src/meta/ps2_pcm.c index 1564a3f0..07d1fbfc 100644 --- a/src/meta/ps2_pcm.c +++ b/src/meta/ps2_pcm.c @@ -2,7 +2,7 @@ #include "../coding/coding.h" /* .PCM - KCE Japan East PS2 games (Ephemeral Fantasia, Yu-Gi-Oh! The Duelists of the Roses, 7 Blades) */ -VGMSTREAM * init_vgmstream_pcm_ps2(STREAMFILE *streamFile) { +VGMSTREAM * init_vgmstream_ps2_pcm(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset; int loop_flag, channel_count; diff --git a/src/meta/pcm.c b/src/meta/scd_pcm.c similarity index 91% rename from src/meta/pcm.c rename to src/meta/scd_pcm.c index ddd47eca..1e374bed 100644 --- a/src/meta/pcm.c +++ b/src/meta/scd_pcm.c @@ -2,7 +2,7 @@ #include "../util.h" /* PCM (from Lunar: Eternal Blue (Sega CD) */ -VGMSTREAM * init_vgmstream_pcm_scd(STREAMFILE *streamFile) { +VGMSTREAM * init_vgmstream_scd_pcm(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; @@ -38,7 +38,7 @@ VGMSTREAM * init_vgmstream_pcm_scd(STREAMFILE *streamFile) { } vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x1; - vgmstream->meta_type = meta_PCM_SCD; + vgmstream->meta_type = meta_SCD_PCM; /* open the file for reading */ { diff --git a/src/vgmstream.c b/src/vgmstream.c index f0b7209c..52591fb7 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -121,8 +121,8 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_ps2_kces, init_vgmstream_ps2_dxh, init_vgmstream_ps2_psh, - init_vgmstream_pcm_scd, - init_vgmstream_pcm_ps2, + init_vgmstream_scd_pcm, + init_vgmstream_ps2_pcm, init_vgmstream_ps2_rkv, init_vgmstream_ps2_psw, init_vgmstream_ps2_vas, diff --git a/src/vgmstream.h b/src/vgmstream.h index 44776433..9ea12de3 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -369,7 +369,7 @@ typedef enum { meta_PS2_KCES, /* Dance Dance Revolution */ meta_PS2_DXH, /* Tokobot Plus - Myteries of the Karakuri */ meta_PS2_PSH, /* Dawn of Mana - Seiken Densetsu 4 */ - meta_PCM_SCD, /* Lunar - Eternal Blue */ + meta_SCD_PCM, /* Lunar - Eternal Blue */ meta_PS2_PCM, /* Konami KCEJ East: Ephemeral Fantasia, Yu-Gi-Oh! The Duelists of the Roses, 7 Blades */ meta_PS2_RKV, /* Legacy of Kain - Blood Omen 2 */ meta_PS2_PSW, /* Rayman Raving Rabbids */ From 66a3e7ed884bb51316891a878863c5e5492ae969 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 16 Nov 2017 00:42:09 +0100 Subject: [PATCH 05/23] Add some HCA keys --- src/meta/hca.c | 3 +-- src/meta/hca_keys.h | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/meta/hca.c b/src/meta/hca.c index 2f99ab2e..10261460 100644 --- a/src/meta/hca.c +++ b/src/meta/hca.c @@ -155,7 +155,6 @@ static void find_hca_key(hca_codec_data * hca_data, clHCA * hca, uint8_t * buffe f++; } - //;VGM_LOG("HCA: key %08x%08x clip_count=%i\n", ciphKey2,ciphKey1, clip_count); if (min_clip_count < 0 || clip_count < min_clip_count) { min_clip_count = clip_count; best_key2 = key2; @@ -176,7 +175,7 @@ static void find_hca_key(hca_codec_data * hca_data, clHCA * hca, uint8_t * buffe read_streamfile(buffer, hca_data->start, header_size, hca_data->streamfile); end: - VGM_LOG("HCA: best key=%08x%08x (clips=%i)\n", best_key2,best_key1, min_clip_count); + VGM_ASSERT(min_clip_count > 0, "HCA: best key=%08x%08x (clips=%i)\n", best_key2,best_key1, min_clip_count); *out_key2 = best_key2; *out_key1 = best_key1; free(testbuf);//free(temp); diff --git a/src/meta/hca_keys.h b/src/meta/hca_keys.h index 7af9432b..21c9ef92 100644 --- a/src/meta/hca_keys.h +++ b/src/meta/hca_keys.h @@ -12,7 +12,7 @@ typedef struct { */ static const hcakey_info hcakey_list[] = { - // HCA Decoder default + // CRI HCA decoder default {9621963164387704}, // CF222F1FE0748978 // Phantasy Star Online 2 (multi?) @@ -28,7 +28,13 @@ static const hcakey_info hcakey_list[] = { // Ro-Kyu-Bu! Himitsu no Otoshimono (PSP) {2012082716}, // 0000000077EDF21C - // Ro-Kyu-Bu! Naisho no Shutter Chance (PSV) + // VRIDGE Inc. games: + // - HatsuKare * Renai Debut Sengen! (PSP) + // - Seitokai no Ichizon Lv. 2 Portable (PSP) + // - Koi wa Kousoku ni Shibararenai! (PSP) + // - StormLover 2nd (PSP) + // - Prince of Stride (PSVita) + // - Ro-Kyu-Bu! Naisho no Shutter Chance (PSVita) {1234253142}, // 0000000049913556 // Idolm@ster Cinderella Stage (iOS/Android) @@ -123,6 +129,21 @@ static const hcakey_info hcakey_list[] = { // Schoolgirl Strikers ~Twinkle Melodies~ (iOS/Android) {0xDB5B61B8343D0000}, // DB5B61B8343D0000 + // Bad Apple Wars (PSVita) + {241352432}, // 000000000E62BEF0 + + // Koi to Senkyo to Chocolate Portable (PSP) + {243812156}, // 000000000E88473C + + // Custom Drive (PSP) + {2012062010}, // 0000000077EDA13A + + // Root Letter (PSVita) + {1547531215412131}, // 00057F78B05F9BA3 + + // Pro Evolution Soccer 2018 / Winning Eleven 2018 (Android) + {14121473}, // 0000000000D77A01 + }; From 6d7d6dcd54a9376bb97973accbb3631e238db812 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 16 Nov 2017 00:42:35 +0100 Subject: [PATCH 06/23] Update makefile for latest FFmpeg libs --- ext_libs/Makefile.mingw | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ext_libs/Makefile.mingw b/ext_libs/Makefile.mingw index 1f35aade..16a4d46f 100644 --- a/ext_libs/Makefile.mingw +++ b/ext_libs/Makefile.mingw @@ -17,17 +17,17 @@ libg719_decode.a: libg719_decode.def libat3plusdecoder.a: at3plusdecoder.def $(DLLTOOL) -d at3plusdecoder.def -l libat3plusdecoder.a -libavcodec.a: avcodec-vgmstream-57.dll avcodec-vgmstream-57.def - $(DLLTOOL) -D avcodec-vgmstream-57.dll -d avcodec-vgmstream-57.def -l libavcodec.a +libavcodec.a: avcodec-vgmstream-58.dll avcodec-vgmstream-58.def + $(DLLTOOL) -D avcodec-vgmstream-58.dll -d avcodec-vgmstream-58.def -l libavcodec.a -libavformat.a: avformat-vgmstream-57.dll avformat-vgmstream-57.def - $(DLLTOOL) -D avformat-vgmstream-57.dll -d avformat-vgmstream-57.def -l libavformat.a +libavformat.a: avformat-vgmstream-58.dll avformat-vgmstream-58.def + $(DLLTOOL) -D avformat-vgmstream-58.dll -d avformat-vgmstream-58.def -l libavformat.a -libavutil.a: avutil-vgmstream-55.dll avutil-vgmstream-55.def - $(DLLTOOL) -D avutil-vgmstream-55.dll -d avutil-vgmstream-55.def -l libavutil.a +libavutil.a: avutil-vgmstream-56.dll avutil-vgmstream-56.def + $(DLLTOOL) -D avutil-vgmstream-56.dll -d avutil-vgmstream-56.def -l libavutil.a -libswresample.a: swresample-vgmstream-2.dll swresample-vgmstream-2.def - $(DLLTOOL) -D swresample-vgmstream-2.dll -d swresample-vgmstream-2.def -l libswresample.a +libswresample.a: swresample-vgmstream-3.dll swresample-vgmstream-3.def + $(DLLTOOL) -D swresample-vgmstream-3.dll -d swresample-vgmstream-3.def -l libswresample.a clean: rm -f libvorbis.a libmpg123-0.a libg7221_decode.a libg719_decode.a libat3plusdecoder.a libavcodec.a libavformat.a libavutil.a libswresample.a From 4dfbc3cf6ad1e8b0c3926c902aff11226996a971 Mon Sep 17 00:00:00 2001 From: bnnm Date: Thu, 16 Nov 2017 19:47:42 +0100 Subject: [PATCH 07/23] Improve CD-XA detection and RIFF-less support; minor XA code cleanup --- src/coding/coding.h | 3 +- src/coding/xa_decoder.c | 24 +++-- src/layout/xa_blocked.c | 93 +++++++++++-------- src/meta/psx_cdxa.c | 193 ++++++++++++++++++---------------------- src/vgmstream.h | 16 ++-- 5 files changed, 171 insertions(+), 158 deletions(-) diff --git a/src/coding/coding.h b/src/coding/coding.h index 2fbb7479..a21b17d2 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -80,7 +80,8 @@ size_t ps_bytes_to_samples(size_t bytes, int channels); /* xa_decoder */ void decode_xa(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); -void init_get_high_nibble(VGMSTREAM * vgmstream); +void xa_init_get_high_nibble(VGMSTREAM * vgmstream); +size_t xa_bytes_to_samples(size_t bytes, int channels, int is_blocked); /* ea_xa_decoder */ void decode_ea_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); diff --git a/src/coding/xa_decoder.c b/src/coding/xa_decoder.c index 12b61e48..deeada36 100644 --- a/src/coding/xa_decoder.c +++ b/src/coding/xa_decoder.c @@ -20,8 +20,8 @@ static int CLAMP(int value, int Minim, int Maxim) return value; } -void init_get_high_nibble(VGMSTREAM *vgmstream) { - vgmstream->get_high_nibble=1; +void xa_init_get_high_nibble(VGMSTREAM *vgmstream) { + vgmstream->xa_get_high_nibble=1; } void decode_xa(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { @@ -41,18 +41,18 @@ void decode_xa(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32 first_sample = first_sample % 28; - vgmstream->get_high_nibble=!vgmstream->get_high_nibble; + vgmstream->xa_get_high_nibble=!vgmstream->xa_get_high_nibble; if((first_sample) && (channelspacing==1)) - vgmstream->get_high_nibble=!vgmstream->get_high_nibble; + vgmstream->xa_get_high_nibble=!vgmstream->xa_get_high_nibble; - predict_nr = read_8bit(stream->offset+HeadTable[framesin]+vgmstream->get_high_nibble,stream->streamfile) >> 4; - shift_factor = read_8bit(stream->offset+HeadTable[framesin]+vgmstream->get_high_nibble,stream->streamfile) & 0xf; + predict_nr = read_8bit(stream->offset+HeadTable[framesin]+vgmstream->xa_get_high_nibble,stream->streamfile) >> 4; + shift_factor = read_8bit(stream->offset+HeadTable[framesin]+vgmstream->xa_get_high_nibble,stream->streamfile) & 0xf; for (i=first_sample,sample_count=0; ioffset+16+framesin+(i*4),stream->streamfile); - scale = ((vgmstream->get_high_nibble ? + scale = ((vgmstream->xa_get_high_nibble ? sample_byte >> 4 : sample_byte & 0x0f)<<12); @@ -70,3 +70,13 @@ void decode_xa(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32 stream->adpcm_history1_32=hist1; stream->adpcm_history2_32=hist2; } + +size_t xa_bytes_to_samples(size_t bytes, int channels, int is_blocked) { + if (is_blocked) { + //todo with -0x10 misses the last sector, not sure if bug or feature + return ((bytes - 0x10) / 0x930) * (0x900 - 18*0x10) * 2 / channels; + } + else { + return ((bytes / 0x80)*0xE0) / 2; + } +} diff --git a/src/layout/xa_blocked.c b/src/layout/xa_blocked.c index e84cb15b..b8bdd4f1 100644 --- a/src/layout/xa_blocked.c +++ b/src/layout/xa_blocked.c @@ -4,48 +4,69 @@ /* set up for the block at the given offset */ void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i; + int8_t currentChannel=0; + int8_t subAudio=0; - int i; - int8_t currentChannel=0; - int8_t subAudio=0; - - init_get_high_nibble(vgmstream); + xa_init_get_high_nibble(vgmstream); - if(vgmstream->samples_into_block!=0) - // don't change this variable in the init process - vgmstream->xa_sector_length+=128; + /* don't change this variable in the init process */ + if (vgmstream->samples_into_block != 0) + vgmstream->xa_sector_length += 0x80; - // We get to the end of a sector ? - if(vgmstream->xa_sector_length==(18*128)) { - vgmstream->xa_sector_length=0; + /* XA mode2/form2 sector + * 0x00: sync word + * 0x0c: header = minute, second, sector, mode (always 0x02) + * 0x10: subheader = file, channel (marker), submode flags, xa header + * 0x14: subheader again + * 0x18: data + * 0x918: unused + * 0x92c: EDC/checksum or null + * 0x930: end + */ - // 0x30 of unused bytes/sector :( - if (!vgmstream->xa_headerless) { - block_offset+=0x30; + /* submode flags (typical audio value = 0x64) + * - 7: end of file + * - 6: real time mode + * - 5: sector form (0=form1, 1=form2) + * - 4: trigger (for application) + * - 3: data sector + * - 2: audio sector + * - 1: video sector + * - 0: end of audio + */ + + // We get to the end of a sector ? + if (vgmstream->xa_sector_length == (18*0x80)) { + vgmstream->xa_sector_length = 0; + + // 0x30 of unused bytes/sector :( + if (!vgmstream->xa_headerless) { + block_offset += 0x30; begin: - // Search for selected channel & valid audio - currentChannel=read_8bit(block_offset-7,vgmstream->ch[0].streamfile); - subAudio=read_8bit(block_offset-6,vgmstream->ch[0].streamfile); + // Search for selected channel & valid audio + currentChannel = read_8bit(block_offset-0x07,vgmstream->ch[0].streamfile); + subAudio = read_8bit(block_offset-0x06,vgmstream->ch[0].streamfile); - // audio is coded as 0x64 - if(!((subAudio==0x64) && (currentChannel==vgmstream->xa_channel))) { - // go to next sector - block_offset+=2352; - if(currentChannel!=-1) goto begin; - } - } - } + // audio is coded as 0x64 + if (!((subAudio==0x64) && (currentChannel==vgmstream->xa_channel))) { + // go to next sector + block_offset += 0x930; + if (currentChannel!=-1) goto begin; + } + } + } - vgmstream->current_block_offset = block_offset; + vgmstream->current_block_offset = block_offset; - // Quid : how to stop the current channel ??? - // i set up 0 to current_block_size to make vgmstream not playing bad samples - // another way to do it ??? - // (as the number of samples can be false in cd-xa due to multi-channels) - vgmstream->current_block_size = (currentChannel==-1?0:112); - - vgmstream->next_block_offset = vgmstream->current_block_offset+128; - for (i=0;ichannels;i++) { - vgmstream->ch[i].offset = vgmstream->current_block_offset; - } + // Quid : how to stop the current channel ??? + // i set up 0 to current_block_size to make vgmstream not playing bad samples + // another way to do it ??? + // (as the number of samples can be false in cd-xa due to multi-channels) + vgmstream->current_block_size = (currentChannel==-1 ? 0 : 0x70); + + vgmstream->next_block_offset = vgmstream->current_block_offset + 0x80; + for (i=0;ichannels;i++) { + vgmstream->ch[i].offset = vgmstream->current_block_offset; + } } diff --git a/src/meta/psx_cdxa.c b/src/meta/psx_cdxa.c index c6ab39ca..6e612c09 100644 --- a/src/meta/psx_cdxa.c +++ b/src/meta/psx_cdxa.c @@ -1,135 +1,118 @@ #include "meta.h" #include "../layout/layout.h" -#include "../util.h" - -/* Sony PSX CD-XA */ -/* No looped file ! */ - -static off_t init_xa_channel(int *channel,STREAMFILE *streamFile); - -static uint8_t AUDIO_CODING_GET_STEREO(uint8_t value) { - return (uint8_t)(value & 3); -} - -static uint8_t AUDIO_CODING_GET_FREQ(uint8_t value) { - return (uint8_t)((value >> 2) & 3); -} +#include "../coding/coding.h" +/* CD-XA - from Sony PS1 CDs */ VGMSTREAM * init_vgmstream_cdxa(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; + off_t start_offset; + int loop_flag = 0, channel_count, sample_rate; + int xa_channel=0; + int is_blocked; + size_t file_size = get_streamfile_size(streamFile); - int channel_count; - int headerless=0; - int xa_channel=0; - uint8_t bCoding; - off_t start_offset; + /* check extension (.xa: common, .str: sometimes used) */ + if ( !check_extensions(streamFile,"xa,str") ) + goto fail; - int i; + /* Proper XA comes in raw (BIN 2352 mode2/form2) CD sectors, that contain XA subheaders. + * This also has minimal support for headerless (ISO 2048 mode1/data) mode. */ - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("xa",filename_extension(filename))) goto fail; + /* check RIFF header = raw (optional, added when ripping and not part of the CD data) */ + if (read_32bitBE(0x00,streamFile) == 0x52494646 && /* "RIFF" */ + read_32bitBE(0x08,streamFile) == 0x43445841 && /* "CDXA" */ + read_32bitBE(0x0C,streamFile) == 0x666D7420) { /* "fmt " */ + is_blocked = 1; + start_offset = 0x2c; /* after "data" (chunk size tends to be a bit off) */ + } + else { + /* sector sync word = raw */ + if (read_32bitBE(0x00,streamFile) == 0x00FFFFFF && + read_32bitBE(0x04,streamFile) == 0xFFFFFFFF && + read_32bitBE(0x08,streamFile) == 0xFFFFFF00) { + is_blocked = 1; + start_offset = 0x00; + } + else { /* headerless */ + is_blocked = 0; + start_offset = 0x00; + } + } - /* check RIFF Header */ - if (!((read_32bitBE(0x00,streamFile) == 0x52494646) && - (read_32bitBE(0x08,streamFile) == 0x43445841) && - (read_32bitBE(0x0C,streamFile) == 0x666D7420))) - headerless=1; + /* test first block (except when RIFF) */ + if (start_offset == 0) { + int i, j; - /* don't misdetect Reflections' XA ("XA30" / "04SW") */ - if (read_32bitBE(0x00,streamFile) == 0x58413330 || read_32bitBE(0x00,streamFile) == 0x30345357) goto fail; - /* don't misdetect Maxis XA ("XAI\0" / "XAJ\0") */ - if (read_32bitBE(0x00,streamFile) == 0x58414900 || read_32bitBE(0x00,streamFile) == 0x58414A00) goto fail; + /* 0x80 frames for 1 sector (max ~0x800 for ISO mode) */ + for (i = 0; i < (0x800/0x80); i++) { + off_t test_offset = start_offset + (is_blocked ? 0x18 : 0x00) + 0x80*i; - /* First init to have the correct info of the channel */ - if (!headerless) { - start_offset=init_xa_channel(&xa_channel,streamFile); + /* ADPCM predictors should be 0..3 index */ + for (j = 0; j < 16; j++) { + uint8_t header = read_8bit(test_offset + i, streamFile); + if (((header >> 4) & 0xF) > 3) + goto fail; + } + } + } - /* No sound ? */ - if(start_offset==0) - goto fail; - bCoding = read_8bit(start_offset-5,streamFile); + /* data is ok: parse header */ + if (is_blocked) { + uint8_t xa_header; - switch (AUDIO_CODING_GET_STEREO(bCoding)) { - case 0: channel_count = 1; break; - case 1: channel_count = 2; break; - default: channel_count = 0; break; - } + /* parse 0x18 sector header (also see xa_blocked.c) */ + xa_channel = read_8bit(start_offset + 0x11,streamFile); + xa_header = read_8bit(start_offset + 0x13,streamFile); - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,0); - if (!vgmstream) goto fail; + switch((xa_header >> 0) & 3) { /* 0..1: stereo */ + case 0: channel_count = 1; break; + case 1: channel_count = 2; break; + default: goto fail; + } + switch((xa_header >> 2) & 3) { /* 2..3: sample rate */ + case 0: sample_rate = 37800; break; + case 1: sample_rate = 18900; break; + default: goto fail; + } + VGM_ASSERT(((xa_header >> 4) & 3) == 1, /* 4..5: bits per sample (0=4, 1=8) */ + "XA: 8 bits per sample mode found\n"); /* spec only? */ + /* 6: emphasis (applies a filter but apparently not used by games) + * XA is also filtered when resampled to 44100 during output, differently from PS-ADPCM */ + /* 7: reserved */ + } + else { + /* headerless, probably will go wrong */ + channel_count = 2; + sample_rate = 44100; /* not 37800? */ + } - /* fill in the vital statistics */ - vgmstream->channels = channel_count; - vgmstream->xa_channel = xa_channel; - switch (AUDIO_CODING_GET_FREQ(bCoding)) { - case 0: vgmstream->sample_rate = 37800; break; - case 1: vgmstream->sample_rate = 18900; break; - default: vgmstream->sample_rate = 0; break; - } + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,loop_flag); + if (!vgmstream) goto fail; - /* Check for Compression Scheme */ - vgmstream->num_samples = (int32_t)((((get_streamfile_size(streamFile) - 0x3C)/2352)*0x1F80)/(2*channel_count)); - } else - { - channel_count=2; - vgmstream = allocate_vgmstream(2,0); - if (!vgmstream) goto fail; + vgmstream->sample_rate = sample_rate; + vgmstream->num_samples = xa_bytes_to_samples(file_size - start_offset, channel_count, is_blocked); + vgmstream->xa_headerless = !is_blocked; + vgmstream->xa_channel = xa_channel; - vgmstream->xa_headerless=1; - vgmstream->sample_rate=44100; - vgmstream->channels=2; - vgmstream->num_samples = (int32_t)(((get_streamfile_size(streamFile)/ 0x80)*0xE0)/2); - start_offset=0; - } - - vgmstream->coding_type = coding_XA; + vgmstream->coding_type = coding_XA; vgmstream->layout_type = layout_xa_blocked; vgmstream->meta_type = meta_PSX_XA; - /* open the file for reading by each channel */ - { - STREAMFILE *chstreamfile; - chstreamfile = streamFile->open(streamFile,filename,2352); + if (is_blocked) + start_offset += 0x18; /* move to first frame (hack for xa_blocked.c) */ - if (!chstreamfile) goto fail; + /* open the file for reading */ + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; - for (i=0;ich[i].streamfile = chstreamfile; - } - } - - xa_block_update(start_offset,vgmstream); + xa_block_update(start_offset,vgmstream); - return vgmstream; + return vgmstream; - /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; } - -off_t init_xa_channel(int* channel,STREAMFILE* streamFile) { - - off_t block_offset=0x44; - size_t filelength=get_streamfile_size(streamFile); - - int8_t currentChannel; - - // 0 can't be a correct value - if(block_offset>=(off_t)filelength) - return 0; - - currentChannel=read_8bit(block_offset-7,streamFile); - //subAudio=read_8bit(block_offset-6,streamFile); - *channel=currentChannel; - //if (!((currentChannel==channel) && (subAudio==0x64))) { - // block_offset+=2352; - // goto begin; - //} - return block_offset; -} diff --git a/src/vgmstream.h b/src/vgmstream.h index 9ea12de3..f5bc9c32 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -715,10 +715,10 @@ typedef struct { layout_t layout_type; /* type of layout for data */ meta_t meta_type; /* how we know the metadata */ - /* streams (info only) */ - int num_streams; /* for multi-stream formats (0=not set/one, 1=one stream) */ - int stream_index; /* current stream */ - char stream_name[STREAM_NAME_SIZE]; /* name of the current stream, if the file stores it and it's filled */ + /* subsongs */ + int num_streams; /* for multi-stream formats (0=not set/one stream, 1=one stream) */ + int stream_index; /* selected stream (also 1-based) */ + 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? */ @@ -766,12 +766,10 @@ typedef struct { uint8_t xa_channel; /* XA ADPCM: selected channel */ int32_t xa_sector_length; /* XA ADPCM: XA block */ - uint8_t xa_headerless; /* XA ADPCM: headerless XA block */ + uint8_t xa_headerless; /* XA ADPCM: headerless XA */ + int8_t xa_get_high_nibble; /* XA ADPCM: mono/stereo nibble selection (XA state could be simplified) */ - int8_t get_high_nibble; /* ADPCM: which nibble (XA, IMA, EA) */ - - uint8_t ea_big_endian; /* EA ADPCM stuff */ - uint8_t ea_platform; + uint8_t ea_platform; /* EA block */ int32_t ws_output_size; /* WS ADPCM: output bytes for this block */ From 4a2cf9dd91bf3a735e4c839f3b2579d997d30543 Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 17 Nov 2017 17:18:17 +0100 Subject: [PATCH 08/23] Fuse EACS and DVI IMA decoder into a configurable IMA decoder EACS was just DVI (high nibble first) with stereo and mono modes, while old DVI was mono only. This unifies both decoders, so DVI_IMA (not interleaved) works with mono and stereo while DVI_IMA_int (interleaved) forces mono. Some metas needed to explicitly set DVI_IMA_int but others work with no change. --- src/coding/coding.h | 3 +-- src/coding/ima_decoder.c | 45 +++++++++++----------------------------- src/formats.c | 1 - src/layout/ea_block.c | 4 ++-- src/meta/dc_kcey.c | 2 +- src/meta/ea_old.c | 2 +- src/meta/ea_schl_fixed.c | 2 +- src/meta/tun.c | 4 ++-- src/meta/x360_tra.c | 2 +- src/vgmstream.c | 19 ++++++----------- src/vgmstream.h | 5 ++--- 11 files changed, 29 insertions(+), 60 deletions(-) diff --git a/src/coding/coding.h b/src/coding/coding.h index a21b17d2..e31dc1d3 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -19,9 +19,8 @@ void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); -void decode_dvi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); -void decode_eacs_ima(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); +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); void decode_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); diff --git a/src/coding/ima_decoder.c b/src/coding/ima_decoder.c index 38cf43eb..8fbbf254 100644 --- a/src/coding/ima_decoder.c +++ b/src/coding/ima_decoder.c @@ -426,8 +426,11 @@ void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel stream->adpcm_step_index = step_index; } -void decode_dvi_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_32; int step_index = stream->adpcm_step_index; @@ -436,37 +439,13 @@ void decode_dvi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci //no header - for (i=first_sample,sample_count=0; ioffset + i/2; - int nibble_shift = (i&1?0:4); //high nibble first (old-style DVI) - - 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; -} - -/* basically DVI stereo (high=L + low=R nibbles) and DVI mono (high=L, low=L) all-in-one, can be simplified/removed */ -void decode_eacs_ima(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { - VGMSTREAMCHANNEL * stream = &(vgmstream->ch[channel]);//todo pass externally for consistency - 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/2 : /* mono mode */ - stream->offset + i; /* stereo mode */ - int nibble_shift = channelspacing == 1 ? - (!(i%2) ? 4:0) : /* mono mode (high first) */ - (channel==0 ? 4:0); /* stereo mode (high=L,low=R) */ + 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); diff --git a/src/formats.c b/src/formats.c index 12c7fe0d..7641ad55 100644 --- a/src/formats.c +++ b/src/formats.c @@ -440,7 +440,6 @@ static const coding_info coding_info_list[] = { {coding_CBD2_int, "Cuberoot-delta-exact (CBD2) 8-bit DPCM with 1 byte interleave"}, {coding_DVI_IMA, "Intel DVI 4-bit IMA ADPCM"}, {coding_DVI_IMA_int, "Intel DVI 4-bit IMA ADPCM (interleaved)"}, - {coding_EACS_IMA, "EACS 4-bit IMA ADPCM"}, {coding_IMA_int, "IMA 4-bit ADPCM (interleaved)"}, {coding_IMA, "IMA 4-bit ADPCM"}, {coding_MS_IMA, "Microsoft 4-bit IMA ADPCM"}, diff --git a/src/layout/ea_block.c b/src/layout/ea_block.c index 244aad6d..c2e4a775 100644 --- a/src/layout/ea_block.c +++ b/src/layout/ea_block.c @@ -91,7 +91,7 @@ void ea_schl_block_update(off_t block_offset, VGMSTREAM * vgmstream) { break; /* id, size, IMA hist, stereo/mono data */ - case coding_EACS_IMA: + case coding_DVI_IMA: for(i = 0; i < vgmstream->channels; i++) { off_t header_offset = block_offset + 0xc + i*4; vgmstream->ch[i].adpcm_history1_32 = read_16bitLE(header_offset+0x00, vgmstream->ch[i].streamfile); @@ -196,7 +196,7 @@ void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream) { vgmstream->current_block_size=block_size-8; - if(vgmstream->coding_type==coding_EACS_IMA) { + if(vgmstream->coding_type==coding_DVI_IMA) { vgmstream->current_block_size=read_32bitLE(block_offset,vgmstream->ch[0].streamfile); for(i=0;ichannels;i++) { diff --git a/src/meta/dc_kcey.c b/src/meta/dc_kcey.c index e68018e1..95d26fdf 100644 --- a/src/meta/dc_kcey.c +++ b/src/meta/dc_kcey.c @@ -27,7 +27,7 @@ VGMSTREAM * init_vgmstream_dc_kcey(STREAMFILE *streamFile) { vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile); vgmstream->loop_end_sample = read_32bitBE(0x0C,streamFile); - vgmstream->coding_type = coding_EACS_IMA; + vgmstream->coding_type = coding_DVI_IMA; vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_DC_KCEY; diff --git a/src/meta/ea_old.c b/src/meta/ea_old.c index 45631e40..867e6a09 100644 --- a/src/meta/ea_old.c +++ b/src/meta/ea_old.c @@ -65,7 +65,7 @@ VGMSTREAM * init_vgmstream_eacs(STREAMFILE *streamFile) { vgmstream->coding_type = coding_PCM8_int; } else - vgmstream->coding_type = coding_EACS_IMA; + vgmstream->coding_type = coding_DVI_IMA; vgmstream->layout_type = layout_eacs_blocked; vgmstream->meta_type = meta_EACS_PC; diff --git a/src/meta/ea_schl_fixed.c b/src/meta/ea_schl_fixed.c index 434f237b..59ff3276 100644 --- a/src/meta/ea_schl_fixed.c +++ b/src/meta/ea_schl_fixed.c @@ -66,7 +66,7 @@ VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE *streamFile) { break; case EA_CODEC_IMA: - vgmstream->coding_type = coding_EACS_IMA; + vgmstream->coding_type = coding_DVI_IMA; break; default: diff --git a/src/meta/tun.c b/src/meta/tun.c index 8402c1ec..76e36b4b 100644 --- a/src/meta/tun.c +++ b/src/meta/tun.c @@ -28,10 +28,10 @@ VGMSTREAM * init_vgmstream_tun(STREAMFILE *streamFile) { start_offset = 0x10; vgmstream->channels = channel_count; vgmstream->sample_rate = 22050; - vgmstream->coding_type = coding_DVI_IMA; + vgmstream->coding_type = coding_DVI_IMA_int; vgmstream->num_samples = (get_streamfile_size(streamFile)) - 0x10; vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 1; + vgmstream->interleave_block_size = 0x01; vgmstream->meta_type = meta_TUN; /* open the file for reading */ diff --git a/src/meta/x360_tra.c b/src/meta/x360_tra.c index 44bb321e..b9418911 100644 --- a/src/meta/x360_tra.c +++ b/src/meta/x360_tra.c @@ -36,7 +36,7 @@ VGMSTREAM * init_vgmstream_x360_tra(STREAMFILE *streamFile) { vgmstream->channels = 2; vgmstream->sample_rate = 24000; - vgmstream->coding_type = coding_DVI_IMA; + vgmstream->coding_type = coding_DVI_IMA_int; vgmstream->num_samples = (int32_t)(get_streamfile_size(streamFile) - ((get_streamfile_size(streamFile)/0x204)*4)); vgmstream->layout_type = layout_tra_blocked; diff --git a/src/vgmstream.c b/src/vgmstream.c index 52591fb7..dde5bb1c 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -1019,7 +1019,6 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { return 28; case coding_G721: case coding_DVI_IMA: - case coding_EACS_IMA: case coding_SNDS_IMA: case coding_IMA: case coding_OTNS_IMA: @@ -1175,9 +1174,6 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { return 0x14; case coding_NGC_DTK: return 32; - case coding_EACS_IMA: - return 1; - case coding_DVI_IMA: case coding_IMA: case coding_G721: case coding_SNDS_IMA: @@ -1213,6 +1209,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_WS: return vgmstream->current_block_size; case coding_IMA_int: + case coding_DVI_IMA: case coding_DVI_IMA_int: case coding_AICA: return 1; @@ -1614,16 +1611,12 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to case coding_DVI_IMA: case coding_DVI_IMA_int: for (chan=0;chanchannels;chan++) { - decode_dvi_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + int is_stereo = vgmstream->channels > 1 && vgmstream->coding_type == coding_DVI_IMA; + int is_high_first = vgmstream->coding_type == coding_DVI_IMA || vgmstream->coding_type == coding_DVI_IMA_int; + + decode_standard_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); - } - break; - case coding_EACS_IMA: - for (chan=0;chanchannels;chan++) { - decode_eacs_ima(vgmstream,buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do,chan); + samples_to_do, chan, is_stereo, is_high_first); } break; case coding_IMA: diff --git a/src/vgmstream.h b/src/vgmstream.h index f5bc9c32..172942c9 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -120,10 +120,9 @@ typedef enum { coding_XBOX_int, /* XBOX IMA ADPCM (interleaved) */ coding_IMA, /* IMA ADPCM (low nibble first) */ coding_IMA_int, /* IMA ADPCM (interleaved) */ - coding_DVI_IMA, /* DVI IMA ADPCM (high nibble first), aka ADP4 */ - coding_DVI_IMA_int, /* DVI IMA ADPCM (Interleaved) */ + coding_DVI_IMA, /* DVI IMA ADPCM (stereo or mono, high nibble first) */ + coding_DVI_IMA_int, /* DVI IMA ADPCM (mono/interleave, high nibble first) */ coding_NDS_IMA, /* IMA ADPCM w/ NDS layout */ - coding_EACS_IMA, /* Electronic Arts IMA ADPCM */ coding_MS_IMA, /* Microsoft IMA ADPCM */ coding_RAD_IMA, /* Radical IMA ADPCM */ coding_RAD_IMA_mono, /* Radical IMA ADPCM, mono (for interleave) */ From 8ec00fb0ea824089b0b0c0a1fe7071660a63453a Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 17 Nov 2017 18:51:43 +0100 Subject: [PATCH 09/23] Cleanup --- src/meta/tun.c | 43 ++++++++++++++----------------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/src/meta/tun.c b/src/meta/tun.c index 76e36b4b..cf270679 100644 --- a/src/meta/tun.c +++ b/src/meta/tun.c @@ -1,58 +1,43 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -/* TUN (from LEGO Racers (PC)) */ +/* ALP - from LEGO Racers (PC) */ VGMSTREAM * init_vgmstream_tun(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; off_t start_offset; - int channel_count; - int loop_flag; + int loop_flag, channel_count; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("tun",filename_extension(filename))) goto fail; + /* check extension */ + if ( !check_extensions(streamFile,"tun") ) + goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x414C5020) /* "ALP " */ goto fail; - channel_count = 2; + channel_count = 2; /* probably at 0x0F */ loop_flag = 0; + start_offset = 0x10; + /* also "ADPCM" at 0x08 */ - /* build the VGMSTREAM */ + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - start_offset = 0x10; vgmstream->channels = channel_count; vgmstream->sample_rate = 22050; + vgmstream->num_samples = ima_bytes_to_samples(get_streamfile_size(streamFile) - 0x10, channel_count); + vgmstream->coding_type = coding_DVI_IMA_int; - vgmstream->num_samples = (get_streamfile_size(streamFile)) - 0x10; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x01; vgmstream->meta_type = meta_TUN; /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; From 304d39d80b47eb37fb321de6269ca582ea2189d7 Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 17 Nov 2017 18:53:34 +0100 Subject: [PATCH 10/23] Clean .idvi and add proper .DVI extension --- src/formats.c | 10 ++++----- src/meta/dc_idvi.c | 55 +++++++++++++++------------------------------- 2 files changed, 23 insertions(+), 42 deletions(-) diff --git a/src/formats.c b/src/formats.c index 7641ad55..09a857b8 100644 --- a/src/formats.c +++ b/src/formats.c @@ -97,7 +97,7 @@ static const char* extension_list[] = { "dsp", "dspw", "dtk", - "dvi", //fake extension (to be removed) + "dvi", "dxh", "eam", @@ -133,7 +133,7 @@ static const char* extension_list[] = { "iab", "iadp", "idsp", - "idvi", + "idvi", //fake extension (to be removed) "ikm", "ild", "int", @@ -680,7 +680,7 @@ static const meta_info meta_info_list[] = { {meta_XBOX_XMU, "XMU header"}, {meta_XBOX_XVAS, "assumed TMNT file by .xvas extension"}, {meta_PS2_XA2, "Acclaim XA2 Header"}, - {meta_DC_IDVI, "IDVI Header"}, + {meta_DC_IDVI, "Capcom IDVI header"}, {meta_NGC_YMF, "YMF DSP Header"}, {meta_PS2_CCC, "CCC Header"}, {meta_PSX_FAG, "FAG Header"}, @@ -823,7 +823,7 @@ static const meta_info meta_info_list[] = { {meta_NGCA, "NGCA header"}, {meta_WII_RAS, "RAS header"}, {meta_PS2_SPM, "SPM header"}, - {meta_X360_TRA, "assumed DefJam Rapstar Audio File by .tra extension"}, + {meta_X360_TRA, "Terminal Reality .TRA raw header"}, {meta_PS2_VGS, "Princess Soft VGS header"}, {meta_PS2_IAB, "IAB header"}, {meta_PS2_STRLR, "STR L/R header"}, @@ -841,7 +841,7 @@ static const meta_info meta_info_list[] = { {meta_PS2_MTAF, "Konami MTAF header"}, {meta_PS2_VAG1, "Konami VAG Mono header (VAG1)"}, {meta_PS2_VAG2, "Konami VAG Stereo header (VAG2)"}, - {meta_TUN, "TUN 'ALP' header"}, + {meta_TUN, "Lego Racers ALP header"}, {meta_WPD, "WPD 'DPW' header"}, {meta_MN_STR, "Mini Ninjas 'STR' header"}, {meta_MSS, "Guerilla MCSS header"}, diff --git a/src/meta/dc_idvi.c b/src/meta/dc_idvi.c index a3962d5f..0200f8cd 100644 --- a/src/meta/dc_idvi.c +++ b/src/meta/dc_idvi.c @@ -1,40 +1,35 @@ #include "meta.h" -#include "../util.h" +#include "../coding/coding.h" -/* IDVI (Eldorado Gate Volume 1-7) */ +/* IDVI - from Capcom's Eldorado Gate Volume 1-7 (DC) */ VGMSTREAM * init_vgmstream_dc_idvi(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; off_t start_offset; + int loop_flag, channel_count; - int loop_flag; - int channel_count; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("idvi",filename_extension(filename))) goto fail; - - /* check header */ - if (read_32bitBE(0x00,streamFile) != 0x49445649) /* "IDVI." */ + /* check extension (.dvi: original, .idvi: renamed to header id) */ + if ( !check_extensions(streamFile,"dvi,idvi") ) goto fail; - loop_flag = read_32bitLE(0x0C,streamFile); - channel_count = read_32bitLE(0x04,streamFile); + /* check header */ + if (read_32bitBE(0x00,streamFile) != 0x49445649) /* "IDVI" */ + goto fail; + + loop_flag = (read_32bitLE(0x0C,streamFile) != 0); + channel_count = read_32bitLE(0x04,streamFile); /* always 2? */ + start_offset = 0x800; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ vgmstream->channels = channel_count; - start_offset = 0x800; vgmstream->sample_rate = read_32bitLE(0x08,streamFile); + vgmstream->num_samples = ima_bytes_to_samples(get_streamfile_size(streamFile) - start_offset, channel_count); + vgmstream->loop_start_sample = read_32bitLE(0x0C,streamFile); + vgmstream->loop_end_sample = ima_bytes_to_samples(get_streamfile_size(streamFile) - start_offset, channel_count); + vgmstream->coding_type = coding_DVI_IMA_int; - vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset); - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitLE(0x0C,streamFile); - vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset); - } vgmstream->meta_type = meta_DC_IDVI; /* Calculating the short block... */ @@ -47,24 +42,10 @@ VGMSTREAM * init_vgmstream_dc_idvi(STREAMFILE *streamFile) { } /* open the file for reading */ - { - int i; - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - for (i=0;ich[i].streamfile = file; - - vgmstream->ch[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+ - vgmstream->interleave_block_size*i; - - } - } - + if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; From 1af4e37f6ffd26c334f1891dbde9cffe49bfb15e Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 17 Nov 2017 19:12:28 +0100 Subject: [PATCH 11/23] Fix DVI .PCM channels being swapped [Castlevania SOTN (SAT)] --- src/meta/sat_dvi.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/meta/sat_dvi.c b/src/meta/sat_dvi.c index 5bc57366..68a483d2 100644 --- a/src/meta/sat_dvi.c +++ b/src/meta/sat_dvi.c @@ -29,7 +29,7 @@ VGMSTREAM * init_vgmstream_sat_dvi(STREAMFILE *streamFile) { vgmstream->coding_type = coding_DVI_IMA_int; vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 4; + vgmstream->interleave_block_size = 0x4; vgmstream->meta_type = meta_SAT_DVI; /* at 0x10 (L) / 0x20 (R): probably ADPCM loop history @+0x00 and step @+0x17 (not init values) */ @@ -37,6 +37,16 @@ VGMSTREAM * init_vgmstream_sat_dvi(STREAMFILE *streamFile) { /* open the file for reading */ if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; + + /* for some reason right channel goes first (tested in SOTN vs emu and PS/OST version), swap offsets */ + if (channel_count == 2) { + off_t temp = vgmstream->ch[0].offset; + vgmstream->ch[0].channel_start_offset = + vgmstream->ch[0].offset = vgmstream->ch[1].offset; + vgmstream->ch[1].channel_start_offset = + vgmstream->ch[1].offset = temp; + } + return vgmstream; fail: From 624b4ead0e458251855d52db2378361331d96502 Mon Sep 17 00:00:00 2001 From: bnnm Date: Fri, 17 Nov 2017 20:46:51 +0100 Subject: [PATCH 12/23] Move eacs_block_update to its own file --- src/layout/blocked_ea_1snh.c | 54 ++++++++++++++++++++++++++++++++ src/layout/ea_block.c | 50 ----------------------------- src/libvgmstream.vcproj | 4 +++ src/libvgmstream.vcxproj | 1 + src/libvgmstream.vcxproj.filters | 3 ++ 5 files changed, 62 insertions(+), 50 deletions(-) create mode 100644 src/layout/blocked_ea_1snh.c diff --git a/src/layout/blocked_ea_1snh.c b/src/layout/blocked_ea_1snh.c new file mode 100644 index 00000000..2f128455 --- /dev/null +++ b/src/layout/blocked_ea_1snh.c @@ -0,0 +1,54 @@ +#include "layout.h" +#include "../coding/coding.h" +#include "../vgmstream.h" + +/* set up for the block at the given offset */ +void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream) { + int i; + off_t block_size=vgmstream->current_block_size; + + if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E6C) { + block_offset+=0x0C; + } + + vgmstream->current_block_offset = block_offset; + + if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E64) { /* 1Snd */ + block_offset+=4; + if(vgmstream->ea_platform==0) + block_size=read_32bitLE(vgmstream->current_block_offset+0x04, + vgmstream->ch[0].streamfile); + else + block_size=read_32bitBE(vgmstream->current_block_offset+0x04, + vgmstream->ch[0].streamfile); + block_offset+=4; + } + + vgmstream->current_block_size=block_size-8; + + if(vgmstream->coding_type==coding_DVI_IMA) { + vgmstream->current_block_size=read_32bitLE(block_offset,vgmstream->ch[0].streamfile); + + for(i=0;ichannels;i++) { + vgmstream->ch[i].adpcm_step_index = read_32bitLE(block_offset+0x04+i*4,vgmstream->ch[0].streamfile); + vgmstream->ch[i].adpcm_history1_32 = read_32bitLE(block_offset+0x04+i*4+(4*vgmstream->channels),vgmstream->ch[0].streamfile); + vgmstream->ch[i].offset = block_offset+0x14; + } + } else { + if(vgmstream->coding_type==coding_PSX) { + for (i=0;ichannels;i++) + vgmstream->ch[i].offset = vgmstream->current_block_offset+8+(i*(vgmstream->current_block_size/2)); + } else { + + for (i=0;ichannels;i++) { + if(vgmstream->coding_type==coding_PCM16_int) + vgmstream->ch[i].offset = block_offset+(i*2); + else + vgmstream->ch[i].offset = block_offset+i; + } + } + vgmstream->current_block_size/=vgmstream->channels; + } + vgmstream->next_block_offset = vgmstream->current_block_offset + + (off_t)block_size; +} diff --git a/src/layout/ea_block.c b/src/layout/ea_block.c index c2e4a775..375889aa 100644 --- a/src/layout/ea_block.c +++ b/src/layout/ea_block.c @@ -172,53 +172,3 @@ void ea_schl_block_update(off_t block_offset, VGMSTREAM * vgmstream) { } } } - -void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream) { - int i; - off_t block_size=vgmstream->current_block_size; - - if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E6C) { - block_offset+=0x0C; - } - - vgmstream->current_block_offset = block_offset; - - if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E64) { /* 1Snd */ - block_offset+=4; - if(vgmstream->ea_platform==0) - block_size=read_32bitLE(vgmstream->current_block_offset+0x04, - vgmstream->ch[0].streamfile); - else - block_size=read_32bitBE(vgmstream->current_block_offset+0x04, - vgmstream->ch[0].streamfile); - block_offset+=4; - } - - vgmstream->current_block_size=block_size-8; - - if(vgmstream->coding_type==coding_DVI_IMA) { - vgmstream->current_block_size=read_32bitLE(block_offset,vgmstream->ch[0].streamfile); - - for(i=0;ichannels;i++) { - vgmstream->ch[i].adpcm_step_index = read_32bitLE(block_offset+0x04+i*4,vgmstream->ch[0].streamfile); - vgmstream->ch[i].adpcm_history1_32 = read_32bitLE(block_offset+0x04+i*4+(4*vgmstream->channels),vgmstream->ch[0].streamfile); - vgmstream->ch[i].offset = block_offset+0x14; - } - } else { - if(vgmstream->coding_type==coding_PSX) { - for (i=0;ichannels;i++) - vgmstream->ch[i].offset = vgmstream->current_block_offset+8+(i*(vgmstream->current_block_size/2)); - } else { - - for (i=0;ichannels;i++) { - if(vgmstream->coding_type==coding_PCM16_int) - vgmstream->ch[i].offset = block_offset+(i*2); - else - vgmstream->ch[i].offset = block_offset+i; - } - } - vgmstream->current_block_size/=vgmstream->channels; - } - vgmstream->next_block_offset = vgmstream->current_block_offset + - (off_t)block_size; -} diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index a8adc1ac..11b894fd 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -1590,6 +1590,10 @@ RelativePath=".\layout\blocked_awc.c" > + + diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index 94f08046..1e95007d 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -471,6 +471,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 8e1f0aa6..8bdf28d6 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -925,6 +925,9 @@ layout\Source Files + + layout\Source Files + layout\Source Files From 8f6c76364c0a6462608fc862970269a687e5a39a Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 18 Nov 2017 02:06:51 +0100 Subject: [PATCH 13/23] Fix standard IMA segfault when external init is wrong --- src/coding/ima_decoder.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/coding/ima_decoder.c b/src/coding/ima_decoder.c index 8fbbf254..b6f8b25a 100644 --- a/src/coding/ima_decoder.c +++ b/src/coding/ima_decoder.c @@ -435,10 +435,13 @@ void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel int32_t hist1 = stream->adpcm_history1_32; int step_index = stream->adpcm_step_index; - //external interleave + /* external interleave */ - //no header + /* no header (external setup), pre-clamp for wrong values */ + if (step_index < 0) step_index=0; + if (step_index > 88) step_index=88; + /* 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 */ From 79c5cfab49685baa7b86d1e8cc21f06c298c4ef9 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 18 Nov 2017 02:20:52 +0100 Subject: [PATCH 14/23] Clean EA 1SNh/EACS (ea_old) and fix some bugs/looping --- README.md | 10 +- src/formats.c | 8 +- src/layout/blocked_ea_1snh.c | 105 +++++++++----- src/layout/layout.h | 2 +- src/meta/ea_old.c | 272 ++++++++++++++++++----------------- src/meta/meta.h | 2 +- src/vgmstream.c | 4 +- src/vgmstream.h | 18 +-- 8 files changed, 229 insertions(+), 192 deletions(-) diff --git a/README.md b/README.md index fd463622..0dccce26 100644 --- a/README.md +++ b/README.md @@ -224,15 +224,15 @@ This list is not complete and many other files are supported. - .spsd - IMA ADPCM: - .bar (IMA ADPCM) - - .dvi (DVI IMA ADPCM) + - .pcm/dvi (DVI IMA ADPCM) - .hwas (IMA ADPCM) - - .idvi (DVI IMA ADPCM) + - .dvi/idvi (DVI IMA ADPCM) - .ivaud (IMA ADPCM) - .myspd (IMA ADPCM) - .strm (IMA ADPCM) - multi: - .aifc (SDX2 DPCM, DVI IMA ADPCM) - - .asf/as4 (8/16 bit PCM, EACS IMA ADPCM) + - .asf/as4 (8/16 bit PCM, DVI IMA ADPCM) - .ast (GC AFC ADPCM, 16 bit PCM) - .aud (IMA ADPCM, WS DPCM) - .aus (PSX ADPCM, Xbox IMA ADPCM) @@ -256,7 +256,7 @@ This list is not complete and many other files are supported. - .seg (Xbox IMA ADPCM, PS2 ADPCM) - .sng/asf/str/eam/aud (8/16 bit PCM, EA-XA ADPCM, PSX ADPCM, GC DSP ADPCM, XBOX IMA ADPCM, MPEG audio, EALayer3) - .strm (NDS IMA ADPCM, 8/16 bit PCM) - - .ss7 (EACS IMA ADPCM, IMA ADPCM) + - .sb0..7 (Ubi IMA ADPCM, GC DSP ADPCM, PSX ADPCM, Xbox IMA ADPCM, ATRAC3) - .swav (NDS IMA ADPCM, 8/16 bit PCM) - .xwb (PCM, Xbox IMA ADPCM, MS ADPCM, XMA, XWMA, ATRAC3) - .xwb+xwh (PCM, PSX ADPCM, ATRAC3) @@ -279,7 +279,7 @@ This list is not complete and many other files are supported. - .caf (Apple IMA4 ADPCM, others) - .de2 (MS ADPCM) - .hca (CRI High Compression Audio) - - .kcey (EACS IMA ADPCM) + - .pcm/kcey (DVI IMA ADPCM) - .lsf (LSF ADPCM) - .mc3 (Paradigm MC3 ADPCM) - .mp4/lmp4 (AAC) diff --git a/src/formats.c b/src/formats.c index 09a857b8..889a2c42 100644 --- a/src/formats.c +++ b/src/formats.c @@ -507,8 +507,8 @@ 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, "Electronic Arts SCxx blocked"}, - {layout_eacs_blocked, "Electronic Arts EACS blocked"}, + {layout_ea_blocked, "blocked (EA SCHl)"}, + {layout_blocked_ea_1snh, "blocked (EA 1SNh)"}, {layout_caf_blocked, "CAF blocked"}, {layout_wsi_blocked, ".wsi blocked"}, {layout_xvas_blocked, ".xvas blocked"}, @@ -628,9 +628,7 @@ static const meta_info meta_info_list[] = { {meta_HGC1, "Knights of the Temple 2 hgC1 Header"}, {meta_AUS, "Capcom AUS Header"}, {meta_RWS, "RenderWare RWS header"}, - {meta_EACS_PC, "Electronic Arts EACS header (PC)"}, - {meta_EACS_PSX, "Electronic Arts EACS header (PSX)"}, - {meta_EACS_SAT, "Electronic Arts EACS header (SATURN)"}, + {meta_EA_1SNH, "Electronic Arts 1SNh/EACS header"}, {meta_SL3, "SL3 Header"}, {meta_FSB1, "FMOD Sample Bank (FSB1) Header"}, {meta_FSB2, "FMOD Sample Bank (FSB2) Header"}, diff --git a/src/layout/blocked_ea_1snh.c b/src/layout/blocked_ea_1snh.c index 2f128455..bcb8e673 100644 --- a/src/layout/blocked_ea_1snh.c +++ b/src/layout/blocked_ea_1snh.c @@ -3,52 +3,81 @@ #include "../vgmstream.h" /* set up for the block at the given offset */ -void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream) { +void block_update_ea_1snh(off_t block_offset, VGMSTREAM * vgmstream) { int i; - off_t block_size=vgmstream->current_block_size; + STREAMFILE* streamFile = vgmstream->ch[0].streamfile; + uint32_t id; + size_t file_size, block_size = 0, block_header = 0; + int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE; - if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E6C) { - block_offset+=0x0C; + + /* find target block ID and skip the rest */ + file_size = get_streamfile_size(streamFile); + while (block_offset < file_size) { + id = read_32bitBE(block_offset+0x00,streamFile); + block_size = read_32bit(block_offset+0x04,streamFile); /* includes id/size */ + block_header = 0x0; + + if (id == 0x31534E68) { /* "1SNh" header block found */ + block_header = read_32bitBE(block_offset+0x08, streamFile) == 0x45414353 ? 0x28 : 0x2c; /* "EACS" */ + if (block_header < block_size) /* sometimes has data */ + break; + } + + if (id == 0x31534E64) { /* "1SNd" data block found */ + block_header = 0x08; + break; + } + + if (id == 0x00000000 || id == 0xFFFFFFFF) { /* EOF: possible? */ + break; + } + + /* any other blocks "1SNl" "1SNe" etc */ //todo parse movie blocks + block_offset += block_size; } vgmstream->current_block_offset = block_offset; + vgmstream->next_block_offset = block_offset + block_size; + vgmstream->current_block_size = block_size - block_header; - if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E64) { /* 1Snd */ - block_offset+=4; - if(vgmstream->ea_platform==0) - block_size=read_32bitLE(vgmstream->current_block_offset+0x04, - vgmstream->ch[0].streamfile); - else - block_size=read_32bitBE(vgmstream->current_block_offset+0x04, - vgmstream->ch[0].streamfile); - block_offset+=4; - } - - vgmstream->current_block_size=block_size-8; - - if(vgmstream->coding_type==coding_DVI_IMA) { - vgmstream->current_block_size=read_32bitLE(block_offset,vgmstream->ch[0].streamfile); - - for(i=0;ichannels;i++) { - vgmstream->ch[i].adpcm_step_index = read_32bitLE(block_offset+0x04+i*4,vgmstream->ch[0].streamfile); - vgmstream->ch[i].adpcm_history1_32 = read_32bitLE(block_offset+0x04+i*4+(4*vgmstream->channels),vgmstream->ch[0].streamfile); - vgmstream->ch[i].offset = block_offset+0x14; - } - } else { - if(vgmstream->coding_type==coding_PSX) { - for (i=0;ichannels;i++) - vgmstream->ch[i].offset = vgmstream->current_block_offset+8+(i*(vgmstream->current_block_size/2)); - } else { + /* set new channel offsets and block sizes */ + switch(vgmstream->coding_type) { + case coding_PCM8_int: + vgmstream->current_block_size /= vgmstream->channels; for (i=0;ichannels;i++) { - if(vgmstream->coding_type==coding_PCM16_int) - vgmstream->ch[i].offset = block_offset+(i*2); - else - vgmstream->ch[i].offset = block_offset+i; + vgmstream->ch[i].offset = block_offset + block_header + i; } - } - vgmstream->current_block_size/=vgmstream->channels; + break; + + case coding_PCM16_int: + vgmstream->current_block_size /= vgmstream->channels; + for (i=0;ichannels;i++) { + vgmstream->ch[i].offset = block_offset + block_header + (i*2); + } + break; + + case coding_PSX: + vgmstream->current_block_size /= vgmstream->channels; + for (i=0;ichannels;i++) { + vgmstream->ch[i].offset = block_offset + block_header + i*vgmstream->current_block_size; + } + break; + + case coding_DVI_IMA: + vgmstream->current_block_size -= 0x14; + for(i = 0; i < vgmstream->channels; i++) { + off_t adpcm_offset = block_offset + block_header + 0x04; + vgmstream->ch[i].adpcm_step_index = read_32bit(adpcm_offset + i*0x04, streamFile); + vgmstream->ch[i].adpcm_history1_32 = read_32bit(adpcm_offset + 0x04*vgmstream->channels + i*0x04, streamFile); + // todo some demuxed vids don't have ADPCM hist? not sure how to correctly detect + vgmstream->ch[i].offset = block_offset + block_header + 0x14; + } + break; + + default: + break; } - vgmstream->next_block_offset = vgmstream->current_block_offset + - (off_t)block_size; + } diff --git a/src/layout/layout.h b/src/layout/layout.h index b3af1efc..d0ab95ed 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -17,7 +17,7 @@ void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream); void ea_schl_block_update(off_t block_offset, VGMSTREAM * vgmstream); -void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream); +void block_update_ea_1snh(off_t block_offset, VGMSTREAM * vgmstream); void caf_block_update(off_t block_offset, VGMSTREAM * vgmstream); diff --git a/src/meta/ea_old.c b/src/meta/ea_old.c index 867e6a09..c2216b91 100644 --- a/src/meta/ea_old.c +++ b/src/meta/ea_old.c @@ -1,159 +1,173 @@ #include "meta.h" #include "../coding/coding.h" #include "../layout/layout.h" -#include "../util.h" -typedef struct -{ - char szID[4]; - int dwSampleRate; - char bBits; - char bChannels; - char bCompression; - char bType; - int dwNumSamples; - int dwLoopStart; - int dwLoopLength; - int dwDataStart; - int dwUnknown; -} EACSHeader; +#define EA_CODEC_PCM 0x00 +//#define EA_CODEC_??? 0x01 //used in SAT videos +#define EA_CODEC_IMA 0x02 +#define EA_CODEC_PSX 0xFF //fake value -VGMSTREAM * init_vgmstream_eacs(STREAMFILE *streamFile) { +typedef struct { + int32_t sample_rate; + uint8_t bits; + uint8_t channels; + uint8_t codec; + uint8_t type; + int32_t num_samples; + int32_t loop_start; + int32_t loop_end; + int32_t loop_start_offset; + + int big_endian; + int loop_flag; +} ea_header; + +static int parse_header(STREAMFILE* streamFile, ea_header* ea, off_t begin_offset); +static void set_ea_1snh_psx_samples(STREAMFILE* streamFile, off_t start_offset, ea_header* ea); + +/* EA 1SNh - from early EA games (~1996, ex. Need for Speed) */ +VGMSTREAM * init_vgmstream_ea_1snh(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - int channel_count; - int loop_flag=0; - char little_endian=0; - EACSHeader *ea_header = NULL; - int32_t samples_count=0; - int i; + off_t start_offset; + ea_header ea = {0}; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("cnk",filename_extension(filename)) && - strcasecmp("as4",filename_extension(filename)) && - strcasecmp("asf",filename_extension(filename))) goto fail; - ea_header=(EACSHeader *)malloc(sizeof(EACSHeader)); - - /* check header */ - if ((uint32_t)read_32bitBE(0,streamFile)!=0x31534E68) /* "1SNh" */ + /* check extension (.asf/as4: common, cnk: some PS games) */ + if (!check_extensions(streamFile,"asf,as4,cnk")) goto fail; - /* check if we are little or big endian */ - if ((uint32_t)read_32bitBE(4,streamFile)<0x40) - little_endian=1; + /* check header (first block) */ + if (read_32bitBE(0,streamFile)!=0x31534E68) /* "1SNh" */ + goto fail; - /* check type details */ + /* use block size as endian marker (Saturn = BE) */ + ea.big_endian = !(read_32bitLE(0x04,streamFile) < 0x0000FFFF); - if((uint32_t)read_32bitBE(0x08,streamFile)==0x45414353) { /* EACS */ - read_streamfile((uint8_t*)ea_header,0x08,sizeof(EACSHeader),streamFile); - loop_flag = 0; //(ea_header->dwLoopStart!=0); - channel_count = (ea_header->bChannels); - /* build the VGMSTREAM */ + if (!parse_header(streamFile,&ea, 0x08)) + goto fail; - vgmstream = allocate_vgmstream(channel_count,0); - if (!vgmstream) goto fail; + start_offset = 0x00; - /* fill in the vital statistics */ - vgmstream->sample_rate = ea_header->dwSampleRate; - - if(ea_header->bCompression==0) { - vgmstream->coding_type = coding_PCM16_int; - if(ea_header->bBits==1) - vgmstream->coding_type = coding_PCM8_int; - } - else - vgmstream->coding_type = coding_DVI_IMA; - - vgmstream->layout_type = layout_eacs_blocked; - vgmstream->meta_type = meta_EACS_PC; + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(ea.channels, ea.loop_flag); + if (!vgmstream) goto fail; - if(little_endian) - vgmstream->meta_type = meta_EACS_SAT; + vgmstream->sample_rate = ea.sample_rate; + vgmstream->num_samples = ea.num_samples; + vgmstream->loop_start_sample = ea.loop_start; + vgmstream->loop_end_sample = ea.loop_end; - } else { - channel_count=read_32bitLE(0x20,streamFile); - - vgmstream = allocate_vgmstream(channel_count,0); - if (!vgmstream) goto fail; + vgmstream->codec_endian = ea.big_endian; + vgmstream->layout_type = layout_blocked_ea_1snh; + vgmstream->meta_type = meta_EA_1SNH; - vgmstream->sample_rate = read_32bitLE(0x08,streamFile); - vgmstream->coding_type = coding_PSX; - vgmstream->layout_type=layout_eacs_blocked; - vgmstream->meta_type=meta_EACS_PSX; - } + switch (ea.codec) { + case EA_CODEC_PCM: + vgmstream->coding_type = ea.bits==1 ? coding_PCM8_int : coding_PCM16_int; + break; - vgmstream->ea_platform=little_endian; + case EA_CODEC_IMA: + if (ea.bits!=2) goto fail; + vgmstream->coding_type = coding_DVI_IMA; /* high nibble first */ + break; - /* open the file for reading by each channel */ - { - for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,0x8000); - if (!vgmstream->ch[i].streamfile) goto fail; - } + case EA_CODEC_PSX: + vgmstream->coding_type = coding_PSX; + break; + + default: + VGM_LOG("EA: unknown codec 0x%02x\n", ea.codec); + goto fail; } - // calc the samples length ... - if(little_endian) - vgmstream->next_block_offset=read_32bitBE(0x04,streamFile); - else - vgmstream->next_block_offset=read_32bitLE(0x04,streamFile); + /* open files; channel offsets are updated below */ + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; - if(vgmstream->next_block_offset>0x30) { - vgmstream->current_block_size=vgmstream->next_block_offset-sizeof(EACSHeader); - samples_count=(int32_t)vgmstream->current_block_size/get_vgmstream_frame_size(vgmstream)*get_vgmstream_samples_per_frame(vgmstream); - samples_count/=vgmstream->channels; - } - - do { - if(read_32bitBE(vgmstream->next_block_offset,vgmstream->ch[0].streamfile)==0x31534E6C) { - ea_header->dwLoopStart=read_32bitLE(vgmstream->next_block_offset+0x08,vgmstream->ch[0].streamfile); - vgmstream->next_block_offset+=0x0C; - } - - if(read_32bitBE(vgmstream->next_block_offset,vgmstream->ch[0].streamfile)==0x31534E65) - break; - - eacs_block_update(vgmstream->next_block_offset,vgmstream); - samples_count+=vgmstream->current_block_size/get_vgmstream_frame_size(vgmstream)*get_vgmstream_samples_per_frame(vgmstream); - } while(vgmstream->next_block_offsetnext_block_offset=read_32bitBE(0x04,streamFile); - else - vgmstream->next_block_offset=read_32bitLE(0x04,streamFile); - - vgmstream->current_block_size=vgmstream->next_block_offset-sizeof(EACSHeader); - - if(vgmstream->coding_type!=coding_PSX) - vgmstream->current_block_size-=8; - - if(vgmstream->coding_type==coding_PSX) - eacs_block_update(0x2C,vgmstream); - else - eacs_block_update(0x28,vgmstream); - - // re-allocate the sample count - vgmstream->num_samples=samples_count; - - if(loop_flag) { - vgmstream->loop_start_sample = ea_header->dwLoopStart; - vgmstream->loop_end_sample = vgmstream->num_samples; - } - - if(ea_header) - free(ea_header); + block_update_ea_1snh(start_offset,vgmstream); return vgmstream; - /* clean up anything we may have opened */ fail: - if(ea_header) - free(ea_header); if (vgmstream) close_vgmstream(vgmstream); return NULL; } + +static int parse_header(STREAMFILE* streamFile, ea_header* ea, off_t offset) { + int32_t (*read_32bit)(off_t,STREAMFILE*) = ea->big_endian ? read_32bitBE : read_32bitLE; + + if (read_32bitBE(offset+0x00, streamFile) == 0x45414353) { /* "EACS" */ + /* PC/SAT EACS subheader */ + ea->sample_rate = read_32bit(offset+0x04, streamFile); + ea->bits = read_8bit(offset+0x08, streamFile); + ea->channels = read_8bit(offset+0x09, streamFile); + ea->codec = read_8bit(offset+0x0a, streamFile); + ea->type = read_8bit(offset+0x0b, streamFile); + ea->num_samples = read_32bit(offset+0x0c, streamFile); + ea->loop_start = read_32bit(offset+0x10, streamFile); + ea->loop_end = read_32bit(offset+0x14, streamFile) + ea->loop_start; /* loop length */ + /* 0x18: data start? (0x00), 0x1c: pan/volume/etc? (0x7F), rest can be padding/garbage */ + VGM_ASSERT(ea->type != 0, "EA EACS: unknown type\n"); /* block type? */ + } + else { + /* PS subheader */ + ea->sample_rate = read_32bit(offset+0x00, streamFile); + ea->channels = read_8bit(offset+0x18, streamFile); + ea->codec = EA_CODEC_PSX; + set_ea_1snh_psx_samples(streamFile, 0x00, ea); + if (ea->loop_start_offset)/* found offset, now find sample start */ + set_ea_1snh_psx_samples(streamFile, 0x00, ea); + } + + ea->loop_flag = (ea->loop_end > 0); + + return 1; +} + +/* get total samples by parsing block headers, needed when EACS isn't present */ +static void set_ea_1snh_psx_samples(STREAMFILE* streamFile, off_t start_offset, ea_header* ea) { + int num_samples = 0, loop_start = 0, loop_end = 0, loop_start_offset = 0; + off_t block_offset = start_offset; + size_t file_size = get_streamfile_size(streamFile); + int32_t (*read_32bit)(off_t,STREAMFILE*) = ea->big_endian ? read_32bitBE : read_32bitLE; + + while (block_offset < file_size) { + uint32_t id = read_32bitBE(block_offset+0x00,streamFile); + size_t block_size = read_32bit(block_offset+0x04,streamFile); /* includes id/size */ + + if (id == 0x31534E68) { /* "1SNh" header block found */ + size_t block_header = read_32bitBE(block_offset+0x08, streamFile) == 0x45414353 ? 0x28 : 0x2c; /* "EACS" */ + if (block_header < block_size) /* sometimes has data */ + num_samples += ps_bytes_to_samples(block_size - block_header, ea->channels); + } + + if (id == 0x31534E64) { /* "1SNd" data block found */ + num_samples += ps_bytes_to_samples(block_size - 0x08, ea->channels); + } + + if (id == 0x31534E6C) { /* "1SNl" loop point found */ + loop_start_offset = read_32bit(block_offset+0x08,streamFile); + loop_end = num_samples; + } + + if (id == 0x00000000 || id == 0xFFFFFFFF) { /* EOF: possible? */ + break; + } + + /* if there is a loop start offset this was called again just to find it */ + if (ea->loop_start_offset && ea->loop_start_offset == block_offset) { + ea->loop_start = num_samples; + return; + } + + /* any other blocks "1SNl" "1SNe" etc */ //todo parse movie blocks + block_offset += block_size; + } + + + ea->num_samples = num_samples; + ea->loop_start = loop_start; + ea->loop_end = loop_end; + ea->loop_start_offset = loop_start_offset; +} diff --git a/src/meta/meta.h b/src/meta/meta.h index 34b25b19..fcb64f80 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -160,7 +160,7 @@ VGMSTREAM * init_vgmstream_pos(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_nwa(STREAMFILE * streamFile); -VGMSTREAM * init_vgmstream_eacs(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_ea_1snh(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_xss(STREAMFILE * streamFile); diff --git a/src/vgmstream.c b/src/vgmstream.c index dde5bb1c..ec1a0a3b 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -90,7 +90,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_rifx, init_vgmstream_pos, init_vgmstream_nwa, - init_vgmstream_eacs, + init_vgmstream_ea_1snh, init_vgmstream_xss, init_vgmstream_sl3, init_vgmstream_hgc1, @@ -914,7 +914,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre case layout_halpst_blocked: case layout_xa_blocked: case layout_ea_blocked: - case layout_eacs_blocked: + case layout_blocked_ea_1snh: case layout_caf_blocked: case layout_wsi_blocked: case layout_str_snds_blocked: diff --git a/src/vgmstream.h b/src/vgmstream.h index 172942c9..a1917cdb 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -75,15 +75,15 @@ enum { STREAM_NAME_SIZE = 255 }; /* reasonable max */ typedef enum { /* PCM */ coding_PCM16LE, /* little endian 16-bit PCM */ - coding_PCM16LE_XOR_int, /* little endian 16-bit PCM with sample-level xor */ + coding_PCM16LE_XOR_int, /* little endian 16-bit PCM with sample-level xor (for blocks) */ coding_PCM16BE, /* big endian 16-bit PCM */ - coding_PCM16_int, /* 16-bit PCM with sample-level interleave */ + coding_PCM16_int, /* 16-bit PCM with sample-level interleave (for blocks) */ coding_PCM8, /* 8-bit PCM */ - coding_PCM8_int, /* 8-Bit PCM with sample-level interleave */ + coding_PCM8_int, /* 8-Bit PCM with sample-level interleave (for blocks) */ coding_PCM8_U, /* 8-bit PCM, unsigned (0x80 = 0) */ - coding_PCM8_U_int, /* 8-bit PCM, unsigned (0x80 = 0) with sample-level interleave */ - coding_PCM8_SB_int, /* 8-bit PCM, sign bit (others are 2's complement) with sample-level interleave */ + coding_PCM8_U_int, /* 8-bit PCM, unsigned (0x80 = 0) with sample-level interleave (for blocks) */ + coding_PCM8_SB_int, /* 8-bit PCM, sign bit (others are 2's complement) with sample-level interleave (for blocks) */ coding_ULAW, /* 8-bit u-Law (non-linear PCM) */ coding_ALAW, /* 8-bit a-Law (non-linear PCM) */ @@ -214,7 +214,7 @@ typedef enum { layout_halpst_blocked, layout_xa_blocked, layout_ea_blocked, - layout_eacs_blocked, + layout_blocked_ea_1snh, layout_caf_blocked, layout_wsi_blocked, layout_str_snds_blocked, @@ -459,9 +459,7 @@ typedef enum { meta_EA_SCHL, /* Electronic Arts SCHl with variable header */ meta_EA_SCHL_fixed, /* Electronic Arts SCHl with fixed header */ meta_EA_BNK, /* Electronic Arts BNK */ - meta_EACS_PC, /* Electronic Arts EACS PC */ - meta_EACS_PSX, /* Electronic Arts EACS PSX */ - meta_EACS_SAT, /* Electronic Arts EACS SATURN */ + meta_EA_1SNH, /* Electronic Arts 1SNh/EACS */ meta_RAW, /* RAW PCM file */ @@ -768,8 +766,6 @@ typedef struct { uint8_t xa_headerless; /* XA ADPCM: headerless XA */ int8_t xa_get_high_nibble; /* XA ADPCM: mono/stereo nibble selection (XA state could be simplified) */ - uint8_t ea_platform; /* EA block */ - int32_t ws_output_size; /* WS ADPCM: output bytes for this block */ int32_t thpNextFrameSize; /* THP */ From 5ce20a710e05b6626cb2d6c6b049f1f035f7acb9 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 18 Nov 2017 02:22:57 +0100 Subject: [PATCH 15/23] Fix segfaults when blocks functions set wrong samples/sizes; cleanup --- src/layout/blocked.c | 131 ++++++++++++++++++++++++------------------- 1 file changed, 72 insertions(+), 59 deletions(-) diff --git a/src/layout/blocked.c b/src/layout/blocked.c index c9d372e7..e0e73b76 100644 --- a/src/layout/blocked.c +++ b/src/layout/blocked.c @@ -8,23 +8,24 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); int samples_this_block; + /* get samples in the current block */ if (vgmstream->current_block_samples) { samples_this_block = vgmstream->current_block_samples; - } else if (frame_size == 0) { - /* assume 4 bit */ - /* TODO: get_vgmstream_frame_size() really should return bits... */ + } else if (frame_size == 0) { /* assume 4 bit */ //TODO: get_vgmstream_frame_size() really should return bits... */ samples_this_block = vgmstream->current_block_size * 2 * samples_per_frame; } else { samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame; } - while (samples_writtenloop_flag && vgmstream_do_loop(vgmstream)) { + /* on loop those values are changed */ if (vgmstream->current_block_samples) { samples_this_block = vgmstream->current_block_samples; - } else if (frame_size == 0) { + } else if (frame_size == 0) { /* assume 4 bit */ //TODO: get_vgmstream_frame_size() really should return bits... */ samples_this_block = vgmstream->current_block_size * 2 * samples_per_frame; } else { samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame; @@ -32,52 +33,62 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * continue; } + /* probably block bug or EOF, next calcs would give wrong values and buffer segfaults */ + if (samples_this_block <= 0) { + VGM_LOG("layout_blocked: empty/wrong block\n"); + memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample)); + break; + } + + samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream); + if (samples_written + samples_to_do > sample_count) + samples_to_do = sample_count - samples_written; - if (samples_written+samples_to_do > sample_count) - samples_to_do=sample_count-samples_written; - - if (vgmstream->current_block_offset>=0) + if (vgmstream->current_block_offset >= 0) { decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer); + } else { + /* block end signal (used below): partially 0-set buffer */ int i; - /* we've run off the end! */ - for (i=samples_written*vgmstream->channels; - i<(samples_written+samples_to_do)*vgmstream->channels;i++) - buffer[i]=0; + for (i = samples_written*vgmstream->channels; i < (samples_written+samples_to_do)*vgmstream->channels; i++) { + buffer[i]=0; + } } samples_written += samples_to_do; vgmstream->current_sample += samples_to_do; - vgmstream->samples_into_block+=samples_to_do; + vgmstream->samples_into_block += samples_to_do; + + /* move to next block when all samples are consumed */ if (vgmstream->samples_into_block==samples_this_block /*&& vgmstream->current_sample < vgmstream->num_samples*/) { /* don't go past last block */ switch (vgmstream->layout_type) { case layout_ast_blocked: ast_block_update(vgmstream->next_block_offset,vgmstream); break; - case layout_mxch_blocked: + case layout_mxch_blocked: mxch_block_update(vgmstream->next_block_offset,vgmstream); break; case layout_halpst_blocked: if (vgmstream->next_block_offset>=0) halpst_block_update(vgmstream->next_block_offset,vgmstream); else - vgmstream->current_block_offset=-1; + vgmstream->current_block_offset = -1; + break; + 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); + break; + case layout_blocked_ea_1snh: + block_update_ea_1snh(vgmstream->next_block_offset,vgmstream); + break; + case layout_caf_blocked: + caf_block_update(vgmstream->next_block_offset,vgmstream); break; - 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); - break; - case layout_eacs_blocked: - eacs_block_update(vgmstream->next_block_offset,vgmstream); - break; - case layout_caf_blocked: - caf_block_update(vgmstream->next_block_offset,vgmstream); - break; case layout_wsi_blocked: wsi_block_update(vgmstream->next_block_offset,vgmstream); break; @@ -105,33 +116,33 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * case layout_vs_blocked: vs_block_update(vgmstream->next_block_offset,vgmstream); break; - case layout_xvas_blocked: - xvas_block_update(vgmstream->next_block_offset,vgmstream); - break; - case layout_thp_blocked: - thp_block_update(vgmstream->next_block_offset,vgmstream); - break; - 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); - break; - case layout_psx_mgav_blocked: - psx_mgav_block_update(vgmstream->next_block_offset,vgmstream); - break; - case layout_ps2_adm_blocked: - ps2_adm_block_update(vgmstream->next_block_offset,vgmstream); - break; - case layout_dsp_bdsp_blocked: - dsp_bdsp_block_update(vgmstream->next_block_offset,vgmstream); - break; - case layout_tra_blocked: - tra_block_update(vgmstream->next_block_offset,vgmstream); - break; - case layout_ps2_iab_blocked: - ps2_iab_block_update(vgmstream->next_block_offset,vgmstream); - break; + case layout_xvas_blocked: + xvas_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_thp_blocked: + thp_block_update(vgmstream->next_block_offset,vgmstream); + break; + 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); + break; + case layout_psx_mgav_blocked: + psx_mgav_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_ps2_adm_blocked: + ps2_adm_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_dsp_bdsp_blocked: + dsp_bdsp_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_tra_blocked: + tra_block_update(vgmstream->next_block_offset,vgmstream); + break; + case layout_ps2_iab_blocked: + ps2_iab_block_update(vgmstream->next_block_offset,vgmstream); + break; case layout_ps2_strlr_blocked: ps2_strlr_block_update(vgmstream->next_block_offset,vgmstream); break; @@ -150,22 +161,24 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * case layout_blocked_vgs: block_update_vgs(vgmstream->next_block_offset,vgmstream); break; - default: + default: break; } /* for VBR these may change */ - frame_size = get_vgmstream_frame_size(vgmstream); + frame_size = get_vgmstream_frame_size(vgmstream); /* for VBR these may change */ samples_per_frame = get_vgmstream_samples_per_frame(vgmstream); + /* get samples in the current block */ if (vgmstream->current_block_samples) { samples_this_block = vgmstream->current_block_samples; - } else if (frame_size == 0) { + } else if (frame_size == 0) { /* assume 4 bit */ //TODO: get_vgmstream_frame_size() really should return bits... */ samples_this_block = vgmstream->current_block_size * 2 * samples_per_frame; } else { samples_this_block = vgmstream->current_block_size / frame_size * samples_per_frame; } - vgmstream->samples_into_block=0; + + vgmstream->samples_into_block = 0; } } From d37deb8d80fee0065304457cc8f553c5a3722bfd Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 18 Nov 2017 02:39:21 +0100 Subject: [PATCH 16/23] Rename ea_old.c to ea_1snh.c for consistency --- src/libvgmstream.vcproj | 2 +- src/libvgmstream.vcxproj | 2 +- src/libvgmstream.vcxproj.filters | 2 +- src/meta/{ea_old.c => ea_1snh.c} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename src/meta/{ea_old.c => ea_1snh.c} (100%) diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 11b894fd..0783f67b 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -353,7 +353,7 @@ > - + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 8bdf28d6..137aeaba 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -208,7 +208,7 @@ meta\Source Files - + meta\Source Files diff --git a/src/meta/ea_old.c b/src/meta/ea_1snh.c similarity index 100% rename from src/meta/ea_old.c rename to src/meta/ea_1snh.c From ea634ad4730b820d8e11f8d10e425173b743a3e4 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 18 Nov 2017 22:25:44 +0100 Subject: [PATCH 17/23] Add 3DS IMA for BCSTM and fix old IMA regression (HWAS/SWAV/SAD/AUD/etc) Standard IMA algorithm was changed for BCSTM, subtly altering regular IMA's waveforms (not too audible). Now this 3DS variation is separate. --- src/coding/coding.h | 1 + src/coding/ima_decoder.c | 32 +++++++++++++++++++++++++++----- src/formats.c | 1 + src/meta/bcstm.c | 2 +- src/vgmstream.c | 9 +++++++++ src/vgmstream.h | 1 + 6 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/coding/coding.h b/src/coding/coding.h index e31dc1d3..98cde6df 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -22,6 +22,7 @@ void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); 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); void decode_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); void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); diff --git a/src/coding/ima_decoder.c b/src/coding/ima_decoder.c index b6f8b25a..2be5c5c1 100644 --- a/src/coding/ima_decoder.c +++ b/src/coding/ima_decoder.c @@ -41,8 +41,8 @@ static const int IMA_IndexTable[16] = }; -/* Alt IMA */ -static void ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) { +/* 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; //"original" ima nibble expansion @@ -64,7 +64,7 @@ static void ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int if (*step_index > 88) *step_index=88; } -/* Microsoft's IMA (most common) */ +/* 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; @@ -86,7 +86,7 @@ static void ms_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, i if (*step_index > 88) *step_index=88; } -/* Apple's MS IMA variation. Exactly the same except it uses 16b history (probably more sensitive to overflow/sign extend) */ +/* 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) { int sample_nibble, sample_decoded, step, delta; @@ -472,7 +472,29 @@ void decode_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, off_t byte_offset = stream->offset + i/2; int nibble_shift = (i&1?4:0); //low nibble order - 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); + } + + stream->adpcm_history1_32 = 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) { + 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/2; + int nibble_shift = (i&1?4:0); //low nibble order + + n3ds_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 889a2c42..e734f446 100644 --- a/src/formats.c +++ b/src/formats.c @@ -442,6 +442,7 @@ static const coding_info coding_info_list[] = { {coding_DVI_IMA_int, "Intel DVI 4-bit IMA ADPCM (interleaved)"}, {coding_IMA_int, "IMA 4-bit ADPCM (interleaved)"}, {coding_IMA, "IMA 4-bit ADPCM"}, + {coding_3DS_IMA, "3DS IMA 4-bit ADPCM"}, {coding_MS_IMA, "Microsoft 4-bit IMA ADPCM"}, {coding_RAD_IMA, "Radical 4-bit IMA ADPCM"}, {coding_RAD_IMA_mono, "Radical 4-bit IMA ADPCM (mono)"}, diff --git a/src/meta/bcstm.c b/src/meta/bcstm.c index 399e1f59..2d8c8365 100644 --- a/src/meta/bcstm.c +++ b/src/meta/bcstm.c @@ -75,7 +75,7 @@ VGMSTREAM * init_vgmstream_bcstm(STREAMFILE *streamFile) { if (seek_offset == 0) goto fail; if ((uint32_t)read_32bitBE(seek_offset, streamFile) != 0x5345454B) { /* "SEEK" If this header doesn't exist, assuming that the file is IMA */ ima = 1; - coding_type = coding_IMA_int; + coding_type = coding_3DS_IMA; } else coding_type = coding_NGC_DSP; diff --git a/src/vgmstream.c b/src/vgmstream.c index ec1a0a3b..b3e736fb 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -1026,6 +1026,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { return 1; case coding_IMA_int: case coding_DVI_IMA_int: + case coding_3DS_IMA: case coding_AICA: return 2; case coding_NGC_AFC: @@ -1211,6 +1212,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_IMA_int: case coding_DVI_IMA: case coding_DVI_IMA_int: + case coding_3DS_IMA: case coding_AICA: return 1; case coding_APPLE_IMA4: @@ -1627,6 +1629,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do); } break; + case coding_3DS_IMA: + for (chan=0;chanchannels;chan++) { + decode_3ds_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, + vgmstream->channels,vgmstream->samples_into_block, + samples_to_do); + } + break; case coding_APPLE_IMA4: for (chan=0;chanchannels;chan++) { decode_apple_ima4(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, diff --git a/src/vgmstream.h b/src/vgmstream.h index a1917cdb..8e5b277f 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -135,6 +135,7 @@ typedef enum { coding_REF_IMA, /* Reflections IMA ADPCM */ coding_AWC_IMA, /* Rockstar AWC IMA ADPCM */ coding_UBI_IMA, /* Ubisoft IMA ADPCM */ + coding_3DS_IMA, /* 3DS IMA ADPCM */ coding_MSADPCM, /* Microsoft ADPCM */ coding_WS, /* Westwood Studios VBR ADPCM */ From bf043d4e5b4f425ef9137472979f6a9357e595dc Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 18 Nov 2017 22:27:14 +0100 Subject: [PATCH 18/23] Add 3DS IMA for BCWAV --- src/meta/rwsd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meta/rwsd.c b/src/meta/rwsd.c index 7192d229..b5641c50 100644 --- a/src/meta/rwsd.c +++ b/src/meta/rwsd.c @@ -245,7 +245,7 @@ VGMSTREAM * init_vgmstream_rwsd(STREAMFILE *streamFile) { coding_type = coding_NGC_DSP; break; case 3: - coding_type = coding_IMA; + coding_type = coding_3DS_IMA; break; default: goto fail; From 36d4f69420499dc183a0ac56fe6288b5643d33a8 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 18 Nov 2017 22:49:18 +0100 Subject: [PATCH 19/23] Fix STRM FFTA2 using the wrong IMA, making output slightly incorrect --- src/meta/nds_strm_ffta2.c | 16 +++++++--------- src/vgmstream.c | 1 - 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/meta/nds_strm_ffta2.c b/src/meta/nds_strm_ffta2.c index 9f1e0e2e..fcb0fa33 100644 --- a/src/meta/nds_strm_ffta2.c +++ b/src/meta/nds_strm_ffta2.c @@ -1,5 +1,4 @@ #include "meta.h" -#include "../util.h" /* STRM - from Final Fantasy Tactics A2 (NDS) */ VGMSTREAM * init_vgmstream_nds_strm_ffta2(STREAMFILE *streamFile) { @@ -18,25 +17,24 @@ VGMSTREAM * init_vgmstream_nds_strm_ffta2(STREAMFILE *streamFile) { loop_flag = (read_32bitLE(0x20,streamFile) !=0); channel_count = read_32bitLE(0x24,streamFile); + start_offset = 0x2C; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - start_offset = 0x2C; vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitLE(0x0C,streamFile); - vgmstream->coding_type = coding_IMA_int; //todo: seems it has some diffs vs regular IMA vgmstream->num_samples = (read_32bitLE(0x04,streamFile)-start_offset); - if (loop_flag) { - vgmstream->loop_start_sample = read_32bitLE(0x20,streamFile); - vgmstream->loop_end_sample = read_32bitLE(0x28,streamFile); - } + vgmstream->loop_start_sample = read_32bitLE(0x20,streamFile); + vgmstream->loop_end_sample = read_32bitLE(0x28,streamFile); - vgmstream->interleave_block_size = 0x80; - vgmstream->layout_type = layout_interleave; vgmstream->meta_type = meta_NDS_STRM_FFTA2; + vgmstream->coding_type = coding_DVI_IMA_int; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = 0x80; + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; diff --git a/src/vgmstream.c b/src/vgmstream.c index b3e736fb..8bfcc422 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -1891,7 +1891,6 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) { if (vgmstream->meta_type == meta_DSP_STD || vgmstream->meta_type == meta_DSP_RS03 || vgmstream->meta_type == meta_DSP_CSTR || - vgmstream->meta_type == meta_NDS_STRM_FFTA2 || /* clicks in some files otherwise */ vgmstream->coding_type == coding_PSX || vgmstream->coding_type == coding_PSX_bmdx || vgmstream->coding_type == coding_PSX_badflags) { From 3ce9e2c8abcd175072d403f417abc51a2e2c41d8 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 18 Nov 2017 22:52:42 +0100 Subject: [PATCH 20/23] Fix 3DS IMA hist --- src/meta/rwsd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meta/rwsd.c b/src/meta/rwsd.c index b5641c50..44cb6a50 100644 --- a/src/meta/rwsd.c +++ b/src/meta/rwsd.c @@ -343,7 +343,7 @@ VGMSTREAM * init_vgmstream_rwsd(STREAMFILE *streamFile) { } } - if (vgmstream->coding_type == coding_IMA) { + if (vgmstream->coding_type == coding_3DS_IMA) { vgmstream->ch[j].adpcm_history1_16 = read_16bit(codec_info_offset,streamFile); vgmstream->ch[j].adpcm_step_index = read_16bit(codec_info_offset+2,streamFile); } From 8363e26b886041f45d46abd921714c58c3a5d51c Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 19 Nov 2017 03:32:21 +0100 Subject: [PATCH 21/23] Unify IMA/IMA_int with standard IMA decoder + add stereo IMA --- src/coding/coding.h | 1 - src/coding/ima_decoder.c | 24 +------------ src/formats.c | 75 ++++++++++++++++++++++------------------ src/vgmstream.c | 20 +++++------ src/vgmstream.h | 16 ++++----- 5 files changed, 58 insertions(+), 78 deletions(-) diff --git a/src/coding/coding.h b/src/coding/coding.h index 98cde6df..46c45fd1 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -21,7 +21,6 @@ void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * o void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel); 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); -void decode_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); void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel); void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do); diff --git a/src/coding/ima_decoder.c b/src/coding/ima_decoder.c index 2be5c5c1..10d45f7b 100644 --- a/src/coding/ima_decoder.c +++ b/src/coding/ima_decoder.c @@ -45,7 +45,6 @@ static const int IMA_IndexTable[16] = 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; - //"original" ima nibble expansion sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf; sample_decoded = *hist1; @@ -169,6 +168,7 @@ static void ubi_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, *hist1 = clamp16(sample_decoded); } +/* *** */ void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i, sample_count; @@ -458,28 +458,6 @@ void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel stream->adpcm_step_index = step_index; } -void decode_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; - int step_index = stream->adpcm_step_index; - - //external interleave - - //no header - - for (i=first_sample,sample_count=0; ioffset + i/2; - int nibble_shift = (i&1?4:0); //low nibble order - - 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; -} - void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i, sample_count; diff --git a/src/formats.c b/src/formats.c index e734f446..3a9822e9 100644 --- a/src/formats.c +++ b/src/formats.c @@ -401,51 +401,53 @@ static const coding_info coding_info_list[] = { {coding_PCM16LE, "Little Endian 16-bit PCM"}, {coding_PCM16LE_XOR_int, "Little Endian 16-bit PCM with 2 byte interleave and XOR obfuscation"}, {coding_PCM16BE, "Big Endian 16-bit PCM"}, - {coding_PCM16_int, "16-bit PCM with 2 byte interleave"}, + {coding_PCM16_int, "16-bit PCM with 2 byte interleave (block)"}, {coding_PCM8, "8-bit PCM"}, + {coding_PCM8_int, "8-bit PCM with 1 byte interleave (block)"}, {coding_PCM8_U, "8-bit unsigned PCM"}, - {coding_PCM8_U_int, "8-bit unsigned PCM with 1 byte interleave"}, - {coding_PCM8_int, "8-bit PCM with 1 byte interleave"}, - {coding_PCM8_SB_int, "8-bit PCM with sign bit, 1 byte interleave"}, + {coding_PCM8_U_int, "8-bit unsigned PCM with 1 byte interleave (block)"}, + {coding_PCM8_SB_int, "8-bit PCM with sign bit, 1 byte interleave (block)"}, {coding_ULAW, "8-bit u-Law"}, {coding_ALAW, "8-bit a-Law"}, {coding_PCMFLOAT, "32-bit float PCM"}, + {coding_CRI_ADX, "CRI ADX 4-bit ADPCM"}, - {coding_CRI_ADX_exp, "CRI ADX 4-bit ADPCM with exponential scale"}, - {coding_CRI_ADX_fixed, "CRI ADX 4-bit ADPCM with fixed coefficients"}, + {coding_CRI_ADX_fixed, "CRI ADX 4-bit ADPCM (fixed coefficients)"}, + {coding_CRI_ADX_exp, "CRI ADX 4-bit ADPCM (exponential scale)"}, {coding_CRI_ADX_enc_8, "CRI ADX 4-bit ADPCM (type 8 encryption)"}, {coding_CRI_ADX_enc_9, "CRI ADX 4-bit ADPCM (type 9 encryption)"}, + {coding_NGC_DSP, "Nintendo DSP 4-bit ADPCM"}, {coding_NGC_DTK, "Nintendo DTK 4-bit ADPCM"}, {coding_NGC_AFC, "Nintendo AFC 4-bit ADPCM"}, - {coding_CRI_HCA, "CRI HCA"}, - {coding_NDS_IMA, "NDS-style 4-bit IMA ADPCM"}, - {coding_DAT4_IMA, "Eurocom DAT4 4-bit IMA ADPCM"}, + {coding_G721, "CCITT G.721 4-bit ADPCM"}, + + {coding_XA, "CD-ROM XA 4-bit ADPCM"}, {coding_PSX, "Playstation 4-bit ADPCM"}, {coding_PSX_badflags, "Playstation 4-bit ADPCM (bad flags)"}, {coding_PSX_bmdx, "Playstation 4-bit ADPCM (BMDX encryption)"}, {coding_PSX_cfg, "Playstation 4-bit ADPCM (configurable)"}, {coding_HEVAG, "Playstation Vita HEVAG 4-bit ADPCM"}, - {coding_XA, "CD-ROM XA 4-bit ADPCM"}, - {coding_XBOX, "XBOX 4-bit IMA ADPCM"}, - {coding_XBOX_int, "XBOX 4-bit IMA ADPCM (interleaved)"}, - {coding_EA_XA, "Electronic Arts EA-XA 4-bit ADPCM (v1)"}, - {coding_EA_XA_int, "Electronic Arts EA-XA 4-bit ADPCM (v1) (interleaved)"}, - {coding_EA_XA_V2, "Electronic Arts EA-XA 4-bit ADPCM (v2)"}, + + {coding_EA_XA, "Electronic Arts EA-XA 4-bit ADPCM v1"}, + {coding_EA_XA_int, "Electronic Arts EA-XA 4-bit ADPCM v1 (mono/interleave)"}, + {coding_EA_XA_V2, "Electronic Arts EA-XA 4-bit ADPCM v2"}, {coding_MAXIS_XA, "Maxis EA-XA 4-bit ADPCM"}, - {coding_SDX2, "Squareroot-delta-exact (SDX2) 8-bit DPCM"}, - {coding_SDX2_int, "Squareroot-delta-exact (SDX2) 8-bit DPCM with 1 byte interleave"}, - {coding_CBD2, "Cuberoot-delta-exact (CBD2) 8-bit DPCM"}, - {coding_CBD2_int, "Cuberoot-delta-exact (CBD2) 8-bit DPCM with 1 byte interleave"}, - {coding_DVI_IMA, "Intel DVI 4-bit IMA ADPCM"}, - {coding_DVI_IMA_int, "Intel DVI 4-bit IMA ADPCM (interleaved)"}, - {coding_IMA_int, "IMA 4-bit ADPCM (interleaved)"}, + {coding_EA_XAS, "Electronic Arts EA-XAS 4-bit ADPCM"}, + {coding_IMA, "IMA 4-bit ADPCM"}, + {coding_IMA_int, "IMA 4-bit ADPCM (mono/interleave)"}, + {coding_DVI_IMA, "Intel DVI 4-bit IMA ADPCM"}, + {coding_DVI_IMA_int, "Intel DVI 4-bit IMA ADPCM (mono/interleave)"}, {coding_3DS_IMA, "3DS IMA 4-bit ADPCM"}, {coding_MS_IMA, "Microsoft 4-bit IMA ADPCM"}, + {coding_XBOX, "XBOX 4-bit IMA ADPCM"}, + {coding_XBOX_int, "XBOX 4-bit IMA ADPCM (mono/interleave)"}, + {coding_NDS_IMA, "NDS-style 4-bit IMA ADPCM"}, + {coding_DAT4_IMA, "Eurocom DAT4 4-bit IMA ADPCM"}, {coding_RAD_IMA, "Radical 4-bit IMA ADPCM"}, - {coding_RAD_IMA_mono, "Radical 4-bit IMA ADPCM (mono)"}, + {coding_RAD_IMA_mono, "Radical 4-bit IMA ADPCM (mono/interleave)"}, {coding_APPLE_IMA4, "Apple Quicktime 4-bit IMA ADPCM"}, {coding_SNDS_IMA, "Heavy Iron .snds 4-bit IMA ADPCM"}, {coding_OTNS_IMA, "Omikron: The Nomad Soul 4-bit IMA ADPCM"}, @@ -454,15 +456,9 @@ static const coding_info coding_info_list[] = { {coding_REF_IMA, "Reflections 4-bit IMA ADPCM"}, {coding_AWC_IMA, "Rockstar AWC 4-bit IMA ADPCM"}, {coding_UBI_IMA, "Ubisoft 4-bit IMA ADPCM"}, - {coding_WS, "Westwood Studios VBR ADPCM"}, - {coding_ACM, "InterPlay ACM"}, - {coding_NWA0, "NWA DPCM Level 0"}, - {coding_NWA1, "NWA DPCM Level 1"}, - {coding_NWA2, "NWA DPCM Level 2"}, - {coding_NWA3, "NWA DPCM Level 3"}, - {coding_NWA4, "NWA DPCM Level 4"}, - {coding_NWA5, "NWA DPCM Level 5"}, + {coding_MSADPCM, "Microsoft 4-bit ADPCM"}, + {coding_WS, "Westwood Studios VBR ADPCM"}, {coding_AICA, "Yamaha AICA 4-bit ADPCM"}, {coding_NDS_PROCYON, "Procyon Studio Digital Sound Elements NDS 4-bit APDCM"}, {coding_L5_555, "Level-5 0x555 4-bit ADPCM"}, @@ -471,7 +467,20 @@ static const coding_info coding_info_list[] = { {coding_MTAF, "Konami MTAF 4-bit ADPCM"}, {coding_MTA2, "Konami MTA2 4-bit ADPCM"}, {coding_MC3, "Paradigm MC3 3-bit ADPCM"}, - {coding_EA_XAS, "Electronic Arts EA-XAS 4-bit ADPCM"}, + + {coding_SDX2, "Squareroot-delta-exact (SDX2) 8-bit DPCM"}, + {coding_SDX2_int, "Squareroot-delta-exact (SDX2) 8-bit DPCM with 1 byte interleave"}, + {coding_CBD2, "Cuberoot-delta-exact (CBD2) 8-bit DPCM"}, + {coding_CBD2_int, "Cuberoot-delta-exact (CBD2) 8-bit DPCM with 1 byte interleave"}, + {coding_ACM, "InterPlay ACM"}, + {coding_NWA0, "NWA DPCM Level 0"}, + {coding_NWA1, "NWA DPCM Level 1"}, + {coding_NWA2, "NWA DPCM Level 2"}, + {coding_NWA3, "NWA DPCM Level 3"}, + {coding_NWA4, "NWA DPCM Level 4"}, + {coding_NWA5, "NWA DPCM Level 5"}, + + {coding_CRI_HCA, "CRI HCA"}, #ifdef VGM_USE_VORBIS {coding_ogg_vorbis, "Ogg Vorbis"}, @@ -772,7 +781,7 @@ static const meta_info meta_info_list[] = { {meta_WII_WAS, "WAS (iSWS) DSP header"}, {meta_XBOX_HLWAV, "Half Life 2 bgm header"}, {meta_STX, "Nintendo .stx header"}, - {meta_MYSPD, "U-Sing .myspd header"}, + {meta_MYSPD, "U-Sing .MYSPD header"}, {meta_HIS, "Her Interactive Sound header"}, {meta_PS2_AST, "KOEI AST header"}, {meta_CAPDSP, "Capcom DSP header"}, diff --git a/src/vgmstream.c b/src/vgmstream.c index 8bfcc422..7c6c4ef7 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -1018,9 +1018,9 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_NGC_DTK: return 28; case coding_G721: + case coding_IMA: case coding_DVI_IMA: case coding_SNDS_IMA: - case coding_IMA: case coding_OTNS_IMA: case coding_UBI_IMA: return 1; @@ -1175,7 +1175,6 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { return 0x14; case coding_NGC_DTK: return 32; - case coding_IMA: case coding_G721: case coding_SNDS_IMA: case coding_OTNS_IMA: @@ -1209,12 +1208,14 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { return 0x4c*vgmstream->channels; case coding_WS: return vgmstream->current_block_size; + case coding_IMA: case coding_IMA_int: case coding_DVI_IMA: case coding_DVI_IMA_int: case coding_3DS_IMA: + return 0x01; case coding_AICA: - return 1; + return 1; case coding_APPLE_IMA4: return 34; case coding_LSF: @@ -1610,10 +1611,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do); } break; + case coding_IMA: + case coding_IMA_int: case coding_DVI_IMA: case coding_DVI_IMA_int: for (chan=0;chanchannels;chan++) { - int is_stereo = vgmstream->channels > 1 && vgmstream->coding_type == coding_DVI_IMA; + int is_stereo = (vgmstream->channels > 1 && vgmstream->coding_type == coding_IMA) + || (vgmstream->channels > 1 && vgmstream->coding_type == coding_DVI_IMA); int is_high_first = vgmstream->coding_type == coding_DVI_IMA || vgmstream->coding_type == coding_DVI_IMA_int; decode_standard_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, @@ -1621,14 +1625,6 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to samples_to_do, chan, is_stereo, is_high_first); } break; - case coding_IMA: - case coding_IMA_int: - for (chan=0;chanchannels;chan++) { - decode_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, - vgmstream->channels,vgmstream->samples_into_block, - samples_to_do); - } - break; case coding_3DS_IMA: for (chan=0;chanchannels;chan++) { decode_3ds_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan, diff --git a/src/vgmstream.h b/src/vgmstream.h index 8e5b277f..5c749af4 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -116,18 +116,19 @@ typedef enum { coding_MAXIS_XA, /* Maxis EA-XA ADPCM */ coding_EA_XAS, /* Electronic Arts EA-XAS ADPCM */ - coding_XBOX, /* XBOX IMA ADPCM */ - coding_XBOX_int, /* XBOX IMA ADPCM (interleaved) */ - coding_IMA, /* IMA ADPCM (low nibble first) */ - coding_IMA_int, /* IMA ADPCM (interleaved) */ + coding_IMA, /* IMA ADPCM (stereo or mono, low nibble first) */ + coding_IMA_int, /* IMA ADPCM (mono/interleave, low nibble first) */ coding_DVI_IMA, /* DVI IMA ADPCM (stereo or mono, high nibble first) */ coding_DVI_IMA_int, /* DVI IMA ADPCM (mono/interleave, high nibble first) */ - coding_NDS_IMA, /* IMA ADPCM w/ NDS layout */ + coding_3DS_IMA, /* 3DS IMA ADPCM */ coding_MS_IMA, /* Microsoft IMA ADPCM */ + coding_XBOX, /* XBOX IMA ADPCM */ + coding_XBOX_int, /* XBOX IMA ADPCM (interleaved) */ + coding_NDS_IMA, /* IMA ADPCM w/ NDS layout */ + coding_DAT4_IMA, /* Eurocom 'DAT4' IMA ADPCM */ coding_RAD_IMA, /* Radical IMA ADPCM */ coding_RAD_IMA_mono, /* Radical IMA ADPCM, mono (for interleave) */ coding_APPLE_IMA4, /* Apple Quicktime IMA4 */ - coding_DAT4_IMA, /* Eurocom 'DAT4' IMA ADPCM */ coding_SNDS_IMA, /* Heavy Iron Studios .snds IMA ADPCM */ coding_OTNS_IMA, /* Omikron The Nomad Soul IMA ADPCM */ coding_FSB_IMA, /* FMOD's FSB multichannel IMA ADPCM */ @@ -135,7 +136,6 @@ typedef enum { coding_REF_IMA, /* Reflections IMA ADPCM */ coding_AWC_IMA, /* Rockstar AWC IMA ADPCM */ coding_UBI_IMA, /* Ubisoft IMA ADPCM */ - coding_3DS_IMA, /* 3DS IMA ADPCM */ coding_MSADPCM, /* Microsoft ADPCM */ coding_WS, /* Westwood Studios VBR ADPCM */ @@ -153,9 +153,7 @@ typedef enum { coding_SDX2_int, /* SDX2 2:1 Squareroot-Delta-Exact compression with sample-level interleave */ coding_CBD2, /* CBD2 2:1 Cuberoot-Delta-Exact compression DPCM */ coding_CBD2_int, /* CBD2 2:1 Cuberoot-Delta-Exact compression, with sample-level interleave */ - coding_ACM, /* InterPlay ACM */ - coding_NWA0, /* Visual Art's NWA (compressed at various levels) */ coding_NWA1, coding_NWA2, From 1c042b7784e504d3143e47f7985a7540c7f9c9e1 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 19 Nov 2017 03:34:25 +0100 Subject: [PATCH 22/23] Use IMA_int with mono files to clarify then IMA stereo is used Both IMA and IMA_int work the same then channels = 1, so this is just to signal when IMA stereo (nibble interleave) is actually used (ie. rarely) --- src/meta/aifc.c | 2 +- src/meta/dc_kcey.c | 2 +- src/meta/ea_1snh.c | 2 +- src/meta/ea_schl_fixed.c | 2 +- src/meta/myspd.c | 47 +++++++++++++--------------------------- src/meta/nds_hwas.c | 4 ++-- src/meta/nds_rrds.c | 4 ++-- src/meta/pc_adp.c | 2 +- src/meta/ws_aud.c | 2 +- 9 files changed, 25 insertions(+), 42 deletions(-) diff --git a/src/meta/aifc.c b/src/meta/aifc.c index bfa6695d..772dd181 100644 --- a/src/meta/aifc.c +++ b/src/meta/aifc.c @@ -173,7 +173,7 @@ VGMSTREAM * init_vgmstream_aifc(STREAMFILE *streamFile) { interleave = 1; break; case 0x41445034: /* ADP4 */ - coding_type = coding_DVI_IMA; + coding_type = coding_DVI_IMA_int; /* don't know how stereo DVI is laid out */ if (channel_count != 1) break; break; diff --git a/src/meta/dc_kcey.c b/src/meta/dc_kcey.c index 95d26fdf..2e5c48ae 100644 --- a/src/meta/dc_kcey.c +++ b/src/meta/dc_kcey.c @@ -27,7 +27,7 @@ VGMSTREAM * init_vgmstream_dc_kcey(STREAMFILE *streamFile) { vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile); vgmstream->loop_end_sample = read_32bitBE(0x0C,streamFile); - vgmstream->coding_type = coding_DVI_IMA; + vgmstream->coding_type = coding_DVI_IMA; /* stereo/mono, high nibble first */ vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_DC_KCEY; diff --git a/src/meta/ea_1snh.c b/src/meta/ea_1snh.c index c2216b91..bce32875 100644 --- a/src/meta/ea_1snh.c +++ b/src/meta/ea_1snh.c @@ -69,7 +69,7 @@ VGMSTREAM * init_vgmstream_ea_1snh(STREAMFILE *streamFile) { case EA_CODEC_IMA: if (ea.bits!=2) goto fail; - vgmstream->coding_type = coding_DVI_IMA; /* high nibble first */ + vgmstream->coding_type = coding_DVI_IMA; /* stereo/mono, high nibble first */ break; case EA_CODEC_PSX: diff --git a/src/meta/ea_schl_fixed.c b/src/meta/ea_schl_fixed.c index 59ff3276..42f25c55 100644 --- a/src/meta/ea_schl_fixed.c +++ b/src/meta/ea_schl_fixed.c @@ -66,7 +66,7 @@ VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE *streamFile) { break; case EA_CODEC_IMA: - vgmstream->coding_type = coding_DVI_IMA; + vgmstream->coding_type = coding_DVI_IMA; /* stereo/mono, high nibble first */ break; default: diff --git a/src/meta/myspd.c b/src/meta/myspd.c index cfcb6d44..373f2303 100644 --- a/src/meta/myspd.c +++ b/src/meta/myspd.c @@ -1,59 +1,42 @@ #include "meta.h" -#include "../util.h" - -/* U-Sing (Wii) .myspd */ +#include "../coding/coding.h" +/* .MYSPF - from U-Sing (Wii) */ VGMSTREAM * init_vgmstream_myspd(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - int channel_count; - int loop_flag = 0; + int loop_flag = 0, channel_count; off_t start_offset; + size_t channel_size; /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("myspd",filename_extension(filename))) goto fail; + if (!check_extensions(streamFile,"myspd")) + goto fail; channel_count = 2; start_offset = 0x20; + channel_size = read_32bitBE(0x00,streamFile); /* check size */ - if ((read_32bitBE(0x0,streamFile)*channel_count+start_offset) != get_streamfile_size(streamFile)) + if ((channel_size * channel_count + start_offset) != get_streamfile_size(streamFile)) goto fail; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - vgmstream->num_samples = read_32bitBE(0x0,streamFile) * 2; - vgmstream->sample_rate = read_32bitBE(0x4,streamFile); + vgmstream->num_samples = ima_bytes_to_samples(channel_size*channel_count, channel_count); + vgmstream->sample_rate = read_32bitBE(0x04,streamFile); - vgmstream->coding_type = coding_IMA; vgmstream->meta_type = meta_MYSPD; - vgmstream->layout_type = layout_none; + vgmstream->coding_type = coding_IMA_int; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = channel_size; - /* open the file for reading */ - { - STREAMFILE * file; - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - vgmstream->ch[0].streamfile = file; + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; - vgmstream->ch[0].channel_start_offset= - vgmstream->ch[0].offset=start_offset; - - file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!file) goto fail; - vgmstream->ch[1].streamfile = file; - - vgmstream->ch[0].channel_start_offset= - vgmstream->ch[1].offset=start_offset + read_32bitBE(0x0,streamFile); - } - return vgmstream; - /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; diff --git a/src/meta/nds_hwas.c b/src/meta/nds_hwas.c index f9b9d0de..e50e614e 100644 --- a/src/meta/nds_hwas.c +++ b/src/meta/nds_hwas.c @@ -8,7 +8,7 @@ VGMSTREAM * init_vgmstream_nds_hwas(STREAMFILE *streamFile) { off_t start_offset; int channel_count, loop_flag = 0; - /* check extension, case insensitive */ + /* check extension, case insensitive (made-up extension) */ if (!check_extensions(streamFile,"hwas")) goto fail; @@ -33,7 +33,7 @@ VGMSTREAM * init_vgmstream_nds_hwas(STREAMFILE *streamFile) { vgmstream->meta_type = meta_NDS_HWAS; - vgmstream->coding_type = coding_IMA; + vgmstream->coding_type = coding_IMA_int; vgmstream->layout_type = layout_hwas_blocked; vgmstream->full_block_size = read_32bitLE(0x04,streamFile); /* usually 0x2000, 0x4000 or 0x8000 */ diff --git a/src/meta/nds_rrds.c b/src/meta/nds_rrds.c index c38e9d64..ac28b64c 100644 --- a/src/meta/nds_rrds.c +++ b/src/meta/nds_rrds.c @@ -11,7 +11,7 @@ VGMSTREAM * init_vgmstream_nds_rrds(STREAMFILE *streamFile) { int loop_flag; off_t start_offset; - /* check extension, case insensitive */ + /* check extension, case insensitive (made-up extension) */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("rrds",filename_extension(filename))) goto fail; @@ -37,7 +37,7 @@ VGMSTREAM * init_vgmstream_nds_rrds(STREAMFILE *streamFile) { vgmstream->loop_end_sample = vgmstream->num_samples; } - vgmstream->coding_type = coding_IMA; + vgmstream->coding_type = coding_IMA_int; vgmstream->meta_type = meta_NDS_RRDS; vgmstream->layout_type = layout_none; diff --git a/src/meta/pc_adp.c b/src/meta/pc_adp.c index 3475a8bc..4ff7c07c 100644 --- a/src/meta/pc_adp.c +++ b/src/meta/pc_adp.c @@ -30,7 +30,7 @@ VGMSTREAM * init_vgmstream_pc_adp_bos(STREAMFILE *streamFile) { vgmstream->loop_end_sample = vgmstream->num_samples; } - vgmstream->coding_type = coding_DVI_IMA; + vgmstream->coding_type = coding_DVI_IMA_int; vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_BOS_ADP; diff --git a/src/meta/ws_aud.c b/src/meta/ws_aud.c index 01effa48..cd13606c 100644 --- a/src/meta/ws_aud.c +++ b/src/meta/ws_aud.c @@ -55,7 +55,7 @@ VGMSTREAM * init_vgmstream_ws_aud(STREAMFILE *streamFile) { if (bytes_per_sample != 1) goto fail; break; case 99: /* IMA ADPCM */ - coding_type = coding_IMA; + coding_type = coding_IMA_int; break; default: goto fail; From 689076c506fe7bbd4b1640d33b495f84e084e64c Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 19 Nov 2017 03:36:30 +0100 Subject: [PATCH 23/23] Add some extra dev info --- BUILD.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/BUILD.md b/BUILD.md index 7f863543..51bde5ea 100644 --- a/BUILD.md +++ b/BUILD.md @@ -149,22 +149,25 @@ C is restricted to features VS2010 can understand. This mainly means means decla ``` ### Overview -vgmstream works by parsing a music stream header (*meta/*), reading/demuxing data or looping (*layout/*) and decoding the compressed data into listenable PCM samples (*coding/*). +vgmstream works by parsing a music stream header (*meta/*), preparing/demuxing data (*layout/*) and decoding the compressed data into listenable PCM samples (*coding/*). Very simplified it goes like this: -- player (test.exe, plugin, etc) inits the stream *[main]* +- player (test.exe, plugin, etc) opens a file stream *[plugin's main/decode]* - init tries all parsers (metas) until one works *[init_vgmstream]* - parser reads header (channels, sample rate, loop points) and set ups a VGMSTREAM struct + layout/coding, if the format is correct *[init_vgmstream_(format-name)]* - player gets total_samples to play, based on the number of loops and other settings *[get_vgmstream_play_samples]* - player asks to fill a small sample buffer *[render_vgmstream]* -- layout prepares bytes to read from the stream *[render_vgmstream_(layout)]* -- decoder decodes bytes into PCM samples *[decode_vgmstream_(coding)]* -- player plays those samples, asks to fill sample buffer, repeats (until total_samples) -- layout moves back to loop_start when loop_end is reached *[vgmstream_do_loop]* +- layout prepares byte offsets to read from the stream *[render_vgmstream_(layout)]* +- decoder reads and decodes bytes into PCM samples *[decode_vgmstream_(coding)]* +- player plays those samples, asks to fill sample buffer again, repeats (until total_samples) +- layout moves offsets back to loop_start when loop_end is reached *[vgmstream_do_loop]* +- close the VGMSTREAM once the stream is finished + +The VGMSTREAM struct created during holds the stream's parameters and decoder state (such as file streams, or offsets per channel). ### Adding new formats For new simple formats, assuming existing layout/coding: -- *src/meta/(format-name).c*: create new init_vgmstream_(format-name) parser that reads all needed info from the stream header and inits VGMSTREAM +- *src/meta/(format-name).c*: create new init_vgmstream_(format-name) parser that tests the extension and header id, and reads all needed info from the stream header and inits the VGMSTREAM - *src/meta/meta.h*: define parser's init - *src/vgmstream.h*: define meta description in the meta_t list - *src/vgmstream.c*: add parser init to the init list @@ -173,6 +176,8 @@ For new simple formats, assuming existing layout/coding: - *src/libvgmstream.vcproj/vcxproj/filters*: add to compile new (format-name).c parser in VS - if the format needs an external library don't forget to mark optional parts with: *#ifdef VGM_USE_X ... #endif* +The new meta is usually named after the format's header id or main extension, possibly with prepended platform. Each file should parse one format (regardless of accepted extensions or decoders used) for consistency, but variations can be found as code evolved. Differents formats can use the same extension, this is not a problem as long as the header id or some other validation tells them apart. If the format is headerless and the extension isn't unique enough it may need a generic GENH/TXTH header instead of direct support. + A STREAMFILE is passed to init_vgmstream_(format-name) function, and I/O must be done using its functions and not STDIO/FILEs, as this lets plugins do their own I/O. This includes reading data from the header or opening other STREAMFILEs (if the header has companion files that need to be parsed). When a parser is successful (allocates VGMSTREAM and sets values) it also needs to open and assign to the VGMSTREAM one or several STREAMFILEs (usually reopens the one passed, but could be any other file) to do I/O during decode. The STREAMFILE passed to the meta will be discarded and must not be reused.