Merge pull request #93 from bnnm/mta2-xau-etc

MTA2, XAU, etc
This commit is contained in:
Christopher Snowhill 2017-05-20 15:58:23 -07:00 committed by GitHub
commit 3103029cca
34 changed files with 1671 additions and 1367 deletions

355
fb2k/foo_filetypes.h Normal file
View File

@ -0,0 +1,355 @@
#ifndef _FOO_FILETYPES_H_
#define _FOO_FILETYPES_H_
#define DECLARE_MULTIPLE_FILE_TYPE(NAME,EXTENSION) \
namespace { \
static input_file_type_impl g_filetype_instance_##EXTENSION(NAME,"*." #EXTENSION ,true); \
static service_factory_single_ref_t<input_file_type_impl> g_filetype_service##EXTENSION(g_filetype_instance_##EXTENSION); \
}
// Registered file types, to associate an extension with foobar2000 in Windows.
// Accepted file types go in formats.c and are checked in input_vgmstream::g_is_our_path.
// Both lists don't need to match, formats.c is what really matters
// (ie. we won't need to associate every single vgmstream format).
// these are declared statically, and if anyone has a better idea i'd like to hear it - josh.
DECLARE_MULTIPLE_FILE_TYPE("2DX9 Audio File (*.2DX9)", 2dx9);
DECLARE_MULTIPLE_FILE_TYPE("2PFS Audio File (*.2PFS)", 2pfs);
//"aac", //common, also tri-Ace's
DECLARE_MULTIPLE_FILE_TYPE("AA3 Audio File (*.AA3)", aa3);
DECLARE_MULTIPLE_FILE_TYPE("AAAP Audio File (*.AAAP)", aaap);
DECLARE_MULTIPLE_FILE_TYPE("AAX Audio File (*.AAX)", aax);
//"ac3", //FFmpeg, not parsed //common?
DECLARE_MULTIPLE_FILE_TYPE("ACE Audio File (*.ACE)", ace);
DECLARE_MULTIPLE_FILE_TYPE("ACM Audio File (*.ACM)", acm);
DECLARE_MULTIPLE_FILE_TYPE("ADM Audio File (*.ADM)", adm);
DECLARE_MULTIPLE_FILE_TYPE("ADP Audio File (*.ADP)", adp);
DECLARE_MULTIPLE_FILE_TYPE("ADPCM Audio File (*.ADPCM)", adpcm);
DECLARE_MULTIPLE_FILE_TYPE("ADS Audio File (*.ADS)", ads);
DECLARE_MULTIPLE_FILE_TYPE("ADX Audio File (*.ADX)", adx);
DECLARE_MULTIPLE_FILE_TYPE("AFC Audio File (*.AFC)", afc);
DECLARE_MULTIPLE_FILE_TYPE("AGSC Audio File (*.AGSC)", agsc);
DECLARE_MULTIPLE_FILE_TYPE("AHX Audio File (*.AHX)", ahx);
DECLARE_MULTIPLE_FILE_TYPE("AIFC Audio File (*.AIFC)", aifc);
DECLARE_MULTIPLE_FILE_TYPE("AIFCL Audio File (*.AIFCL)", aifcl);
//"aiff", //common
DECLARE_MULTIPLE_FILE_TYPE("AIX Audio File (*.AIX)", aix);
DECLARE_MULTIPLE_FILE_TYPE("AKB Audio File (*.AKB)", akb);
DECLARE_MULTIPLE_FILE_TYPE("AMTS Audio File (*.AMTS)", amts);
DECLARE_MULTIPLE_FILE_TYPE("AS4 Audio File (*.AS4)", as4);
DECLARE_MULTIPLE_FILE_TYPE("ASD Audio File (*.ASD)", asd);
DECLARE_MULTIPLE_FILE_TYPE("ASF Audio File (*.ASF)", asf);
DECLARE_MULTIPLE_FILE_TYPE("ASR Audio File (*.ASR)", asr);
DECLARE_MULTIPLE_FILE_TYPE("ASS Audio File (*.ASS)", ass);
DECLARE_MULTIPLE_FILE_TYPE("AST Audio File (*.AST)", ast);
DECLARE_MULTIPLE_FILE_TYPE("ATRAC3plus Audio File (*.AT3)", at3);
DECLARE_MULTIPLE_FILE_TYPE("AUD Audio File (*.AUD)", aud);
DECLARE_MULTIPLE_FILE_TYPE("AUS Audio File (*.AUS)", aus);
DECLARE_MULTIPLE_FILE_TYPE("B1S Audio File (*.B1S)", b1s);
DECLARE_MULTIPLE_FILE_TYPE("BAF Audio File (*.BAF)", baf);
DECLARE_MULTIPLE_FILE_TYPE("BAKA Audio File (*.BAKA)", baka);
DECLARE_MULTIPLE_FILE_TYPE("BAR Audio File (*.BAR)", bar);
DECLARE_MULTIPLE_FILE_TYPE("BCSTM Audio File (*.BCSTM)", bcstm);
DECLARE_MULTIPLE_FILE_TYPE("BCWAV Audio File (*.BCWAV)", bcwav);
DECLARE_MULTIPLE_FILE_TYPE("BDSP Audio File (*.BDSP)", bdsp);
DECLARE_MULTIPLE_FILE_TYPE("BFSTM Audio File (*.BFSTM)", bfstm);
DECLARE_MULTIPLE_FILE_TYPE("BFWAV Audio File (*.BFWAV)", bfwav);
DECLARE_MULTIPLE_FILE_TYPE("BFWAV Audio File [2] (*.BFWAV)", bfwavnsmbu);
DECLARE_MULTIPLE_FILE_TYPE("BG00 Audio File (*.BG00)", bg00);
DECLARE_MULTIPLE_FILE_TYPE("BGM Audio File (*.BGM)", bgm);
DECLARE_MULTIPLE_FILE_TYPE("BGW Audio File (*.BGW)", bgw);
DECLARE_MULTIPLE_FILE_TYPE("BH2PCM Audio File (*.BH2PCM)", bh2pcm);
DECLARE_MULTIPLE_FILE_TYPE("BIK Audio File (*.BIK)", bik);
DECLARE_MULTIPLE_FILE_TYPE("BIKA Audio File (*.BIKA)", bika);
DECLARE_MULTIPLE_FILE_TYPE("BIK2 Audio File (*.BIK2)", bik2);
DECLARE_MULTIPLE_FILE_TYPE("BIK2A Audio File (*.BIK2A)", bik2a);
DECLARE_MULTIPLE_FILE_TYPE("BK2 Audio File (*.BK2)", bk2);
DECLARE_MULTIPLE_FILE_TYPE("BK2A Audio File (*.BK2A)", bk2a);
DECLARE_MULTIPLE_FILE_TYPE("BMDX Audio File (*.BMDX)", bmdx);
DECLARE_MULTIPLE_FILE_TYPE("BMS Audio File (*.BMS)", bms);
DECLARE_MULTIPLE_FILE_TYPE("KLBS Audio File (*.BNK)", bnk);
DECLARE_MULTIPLE_FILE_TYPE("BNS Audio File (*.BNS)", bns);
DECLARE_MULTIPLE_FILE_TYPE("BNSF Audio File (*.BNSF)", bnsf);
DECLARE_MULTIPLE_FILE_TYPE("BO2 Audio File (*.BO2)", bo2);
DECLARE_MULTIPLE_FILE_TYPE("BRSTM Audio File (*.BRSTM)", brstm);
DECLARE_MULTIPLE_FILE_TYPE("BRSTM Audio File [2] (*.BRSTM)", brstmspm);
DECLARE_MULTIPLE_FILE_TYPE("BTSND Audio File (*.BTSND)", btsnd);
DECLARE_MULTIPLE_FILE_TYPE("BVG Audio File (*.BVG)", bvg);
DECLARE_MULTIPLE_FILE_TYPE("CAF Audio File (*.CAF)", caf);
DECLARE_MULTIPLE_FILE_TYPE("CAPDSP Audio File (*.CAPDSP)", capdsp);
DECLARE_MULTIPLE_FILE_TYPE("CBD2 Audio File (*.CBD2)", cbd2);
DECLARE_MULTIPLE_FILE_TYPE("CCC Audio File (*.CCC)", ccc);
DECLARE_MULTIPLE_FILE_TYPE("CFN Audio File (*.CFN)", cfn);
DECLARE_MULTIPLE_FILE_TYPE("CKD Audio File (*.CKD)", ckd);
DECLARE_MULTIPLE_FILE_TYPE("CNK Audio File (*.CNK)", cnk);
DECLARE_MULTIPLE_FILE_TYPE("CPS Audio File (*.CPS)", cps);
DECLARE_MULTIPLE_FILE_TYPE("CXS Audio File (*.CXS)", cxs);
DECLARE_MULTIPLE_FILE_TYPE("DBM Audio File (*.DBM)", dbm);
DECLARE_MULTIPLE_FILE_TYPE("DCS Audio File (*.DCS)", dcs);
DECLARE_MULTIPLE_FILE_TYPE("DDSP Audio File (*.DDSP)", ddsp);
DECLARE_MULTIPLE_FILE_TYPE("DE2 Audio File (*.DE2)", de2);
DECLARE_MULTIPLE_FILE_TYPE("DMSG Audio File (*.DMSG)", dmsg);
DECLARE_MULTIPLE_FILE_TYPE("DSP Audio File (*.DSP)", dsp);
DECLARE_MULTIPLE_FILE_TYPE("DSPW Audio File (*.DSPW)", dspw);
DECLARE_MULTIPLE_FILE_TYPE("DTK Audio File (*.DTK)", dtk);
DECLARE_MULTIPLE_FILE_TYPE("DVI Audio File (*.DVI)", dvi);
DECLARE_MULTIPLE_FILE_TYPE("DXH Audio File (*.DXH)", dxh);
DECLARE_MULTIPLE_FILE_TYPE("EAM Audio File (*.EAM)", eam);
DECLARE_MULTIPLE_FILE_TYPE("EMFF Audio File (*.EMFF)", emff);
DECLARE_MULTIPLE_FILE_TYPE("ENTH Audio File (*.ENTH)", enth);
DECLARE_MULTIPLE_FILE_TYPE("FAG Audio File (*.FAG)", fag);
DECLARE_MULTIPLE_FILE_TYPE("FFW Audio File (*.FFW)", ffw);
DECLARE_MULTIPLE_FILE_TYPE("FILP Audio File (*.FILP)", filp);
DECLARE_MULTIPLE_FILE_TYPE("FSB Audio File (*.FSB)", fsb);
DECLARE_MULTIPLE_FILE_TYPE("FWAV Audio File (*.FWAV)", fwav);
DECLARE_MULTIPLE_FILE_TYPE("G1L Audio File (*.G1L)", g1l);
DECLARE_MULTIPLE_FILE_TYPE("GBTS Audio File (*.GBTS)", gbts);
DECLARE_MULTIPLE_FILE_TYPE("GCA Audio File (*.GCA)", gca);
DECLARE_MULTIPLE_FILE_TYPE("GCM Audio File (*.GCM)", gcm);
DECLARE_MULTIPLE_FILE_TYPE("GCUB Audio File (*.GCUB)", gcub);
DECLARE_MULTIPLE_FILE_TYPE("GCW Audio File (*.GCW)", gcw);
DECLARE_MULTIPLE_FILE_TYPE("GENH Audio File (*.GENH)", genh);
DECLARE_MULTIPLE_FILE_TYPE("GMS Audio File (*.GMS)", gms);
DECLARE_MULTIPLE_FILE_TYPE("GSB Audio File (*.GSB)", gsb);
DECLARE_MULTIPLE_FILE_TYPE("GSB Audio File (*.GTD)", gtd);
DECLARE_MULTIPLE_FILE_TYPE("HCA Audio File (*.HCA)", hca);
DECLARE_MULTIPLE_FILE_TYPE("HGC1 Audio File (*.HGC1)", hgc1);
DECLARE_MULTIPLE_FILE_TYPE("HIS Audio File (*.HIS)", his);
DECLARE_MULTIPLE_FILE_TYPE("HLWAV Audio File (*.HLWAV)", hlwav);
DECLARE_MULTIPLE_FILE_TYPE("HALPST Audio File (*.HPS)", hps);
DECLARE_MULTIPLE_FILE_TYPE("HSF Audio File (*.HSF)", hsf);
DECLARE_MULTIPLE_FILE_TYPE("HWAS Audio File (*.HWAS)", hwas);
DECLARE_MULTIPLE_FILE_TYPE("IAB Audio File (*.IAB)", iab);
DECLARE_MULTIPLE_FILE_TYPE("IADP Audio File (*.IADP)", iadp);
DECLARE_MULTIPLE_FILE_TYPE("IDSP Audio File (*.IDSP)", idsp);
DECLARE_MULTIPLE_FILE_TYPE("IDVI Audio File (*.IDVI)", idvi);
DECLARE_MULTIPLE_FILE_TYPE("IKM Audio File (*.IKM)", ikm);
DECLARE_MULTIPLE_FILE_TYPE("ILD Audio File (*.ILD)", ild);
DECLARE_MULTIPLE_FILE_TYPE("INT Audio File (*.INT)", int);
DECLARE_MULTIPLE_FILE_TYPE("ISD Audio File (*.ISD)", isd);
DECLARE_MULTIPLE_FILE_TYPE("ISWS Audio File (*.ISWS)", isws);
DECLARE_MULTIPLE_FILE_TYPE("IVAUD Audio File (*.IVAUD)", ivaud);
DECLARE_MULTIPLE_FILE_TYPE("IVAG Audio File (*.IVAG)", ivag);
DECLARE_MULTIPLE_FILE_TYPE("IVB Audio File (*.IVB)", ivb);
DECLARE_MULTIPLE_FILE_TYPE("JOE Audio File (*.JOE)", joe);
DECLARE_MULTIPLE_FILE_TYPE("JSTM Audio File (*.JSTM)", jstm);
DECLARE_MULTIPLE_FILE_TYPE("KCES Audio File (*.KCES)", kces);
DECLARE_MULTIPLE_FILE_TYPE("KCEY Audio File (*.KCEY)", kcey);
DECLARE_MULTIPLE_FILE_TYPE("KHV Audio File (*.KHV)", khv);
DECLARE_MULTIPLE_FILE_TYPE("KOVS Audio File (*.KOVS)", kovs);
DECLARE_MULTIPLE_FILE_TYPE("KRAW Audio File (*.KRAW)", kraw);
DECLARE_MULTIPLE_FILE_TYPE("LAAC Audio File (*.LAAC)", laac);
DECLARE_MULTIPLE_FILE_TYPE("LEG Audio File (*.LEG)", leg);
DECLARE_MULTIPLE_FILE_TYPE("LMP4 Audio File (*.LMP4)", lmp4);
DECLARE_MULTIPLE_FILE_TYPE("LOGG Audio File (*.LOGG)", logg);
DECLARE_MULTIPLE_FILE_TYPE("LPCM Audio File (*.LPCM)", lpcm);
DECLARE_MULTIPLE_FILE_TYPE("LPS Audio File (*.LPS)", lps);
DECLARE_MULTIPLE_FILE_TYPE("LSF Audio File (*.LSF)", lsf);
DECLARE_MULTIPLE_FILE_TYPE("LWAV Audio File (*.LWAV)", lwav);
DECLARE_MULTIPLE_FILE_TYPE("MATX Audio File (*.MATX)", matx);
DECLARE_MULTIPLE_FILE_TYPE("MC3 Audio File (*.MC3)", mc3);
DECLARE_MULTIPLE_FILE_TYPE("MCA Audio File (*.MCA)", mca);
DECLARE_MULTIPLE_FILE_TYPE("MCG Audio File (*.MCG)", mcg);
DECLARE_MULTIPLE_FILE_TYPE("MDS Audio File (*.MDS)", mds);
DECLARE_MULTIPLE_FILE_TYPE("MDSP Audio File (*.MDSP)", mdsp);
DECLARE_MULTIPLE_FILE_TYPE("MI4 Audio File (*.MI4)", mi4);
DECLARE_MULTIPLE_FILE_TYPE("MIB Audio File (*.MIB)", mib);
DECLARE_MULTIPLE_FILE_TYPE("MIC Audio File (*.MIC)", mic);
DECLARE_MULTIPLE_FILE_TYPE("MIHB Audio File (*.MIHB)", mihb);
DECLARE_MULTIPLE_FILE_TYPE("MNSTR Audio File (*.MNSTR)", mnstr);
//"mp4", //common
DECLARE_MULTIPLE_FILE_TYPE("MPDSP Audio File (*.MPDSP)", mpdsp);
DECLARE_MULTIPLE_FILE_TYPE("MPDS Audio File (*.MPDS)", mpds);
DECLARE_MULTIPLE_FILE_TYPE("MSA Audio File (*.MSA)", msa);
DECLARE_MULTIPLE_FILE_TYPE("MSF Audio File (*.MSF)", msf);
DECLARE_MULTIPLE_FILE_TYPE("MSS Audio File (*.MSS)", mss);
DECLARE_MULTIPLE_FILE_TYPE("MSVP Audio File (*.MSVP)", msvp);
DECLARE_MULTIPLE_FILE_TYPE("MTA2 Audio File (*.MTA2)", mta2);
DECLARE_MULTIPLE_FILE_TYPE("MTAF Audio File (*.MTAF)", mtaf);
DECLARE_MULTIPLE_FILE_TYPE("MUS Playlist File (*.MUS)", mus);
DECLARE_MULTIPLE_FILE_TYPE("MUSC Audio File (*.MUSC)", musc);
DECLARE_MULTIPLE_FILE_TYPE("MUSX Audio File (*.MUSX)", musx);
DECLARE_MULTIPLE_FILE_TYPE("MWV Audio File (*.MWV)", mwv);
DECLARE_MULTIPLE_FILE_TYPE("MxSt Audio File (*.MxSt)", mxst);
DECLARE_MULTIPLE_FILE_TYPE("MYSPD Audio File (*.MYSPD)", myspd);
DECLARE_MULTIPLE_FILE_TYPE("NDP Audio File (*.NDP)", ndp);
DECLARE_MULTIPLE_FILE_TYPE("NGCA Audio File (*.NGCA)", ngca);
DECLARE_MULTIPLE_FILE_TYPE("NPS Audio File (*.NPS)", nps);
DECLARE_MULTIPLE_FILE_TYPE("NPSF Audio File (*.NPSF)", npsf);
DECLARE_MULTIPLE_FILE_TYPE("NUS3BANK Audio File (*.NUS3BANK)", nus3bank);
DECLARE_MULTIPLE_FILE_TYPE("NWA Audio File (*.NWA)", nwa);
//"ogg", //common
DECLARE_MULTIPLE_FILE_TYPE("OGL Audio File (*.OGL)", ogl);
DECLARE_MULTIPLE_FILE_TYPE("OMA Audio File (*.OMA)", oma);
DECLARE_MULTIPLE_FILE_TYPE("OMU Audio File (*.OMU)", omu);
DECLARE_MULTIPLE_FILE_TYPE("OTM Audio File (*.OTM)", otm);
DECLARE_MULTIPLE_FILE_TYPE("P2BT Audio File (*.P2BT)", p2bt);
DECLARE_MULTIPLE_FILE_TYPE("P3D Audio File (*.P3D)", p3d);
DECLARE_MULTIPLE_FILE_TYPE("PAST Audio File (*.PAST)", past);
DECLARE_MULTIPLE_FILE_TYPE("PCM Audio File (*.PCM)", pcm);
DECLARE_MULTIPLE_FILE_TYPE("PDT Audio File (*.PDT)", pdt);
DECLARE_MULTIPLE_FILE_TYPE("PNB Audio File (*.PNB)", pnb);
DECLARE_MULTIPLE_FILE_TYPE("PONA Audio File (*.PONA)", pona);
DECLARE_MULTIPLE_FILE_TYPE("POS Audio File (*.POS)", pos);
DECLARE_MULTIPLE_FILE_TYPE("PS2STM Audio File (*.PS2STM)", ps2stm);
DECLARE_MULTIPLE_FILE_TYPE("PSH Audio File (*.PSH)", psh);
DECLARE_MULTIPLE_FILE_TYPE("PSND Audio File (*.PSND)", psnd);
DECLARE_MULTIPLE_FILE_TYPE("PSW Audio File (*.PSW)", psw);
DECLARE_MULTIPLE_FILE_TYPE("RAK Audio File (*.RAK)", rak);
DECLARE_MULTIPLE_FILE_TYPE("RAS Audio File (*.RAS)", ras);
DECLARE_MULTIPLE_FILE_TYPE("RAW Audio File (*.RAW)", raw);
DECLARE_MULTIPLE_FILE_TYPE("RKV Audio File (*.RKV)", rkv);
DECLARE_MULTIPLE_FILE_TYPE("RND Audio File (*.RND)", rnd);
DECLARE_MULTIPLE_FILE_TYPE("RRDS Audio File (*.RRDS)", rrds);
DECLARE_MULTIPLE_FILE_TYPE("RSD Audio File (*.RSD)", rsd);
DECLARE_MULTIPLE_FILE_TYPE("RSF Audio File (*.RSF)", rsf);
DECLARE_MULTIPLE_FILE_TYPE("RSTM Audio File (*.RSTM)", rstm);
DECLARE_MULTIPLE_FILE_TYPE("RVWS Audio File (*.RSTM)", rvws);
DECLARE_MULTIPLE_FILE_TYPE("RWAR Audio File (*.RWSD)", rwar);
DECLARE_MULTIPLE_FILE_TYPE("RWAV Audio File (*.RWAV)", rwav);
DECLARE_MULTIPLE_FILE_TYPE("RWS Audio File (*.RWS)", rws);
DECLARE_MULTIPLE_FILE_TYPE("RWSD Audio File (*.RWSD)", rwsd);
DECLARE_MULTIPLE_FILE_TYPE("RWX Audio File (*.RWX)", rwx);
DECLARE_MULTIPLE_FILE_TYPE("RXWS File (*.RXW)", rxw);
DECLARE_MULTIPLE_FILE_TYPE("S14 Audio File (*.S14)", s14);
DECLARE_MULTIPLE_FILE_TYPE("SAB Audio File (*.SAB)", sab);
DECLARE_MULTIPLE_FILE_TYPE("SAD Audio File (*.SAD)", sad);
DECLARE_MULTIPLE_FILE_TYPE("SAP Audio File (*.SAP)", sap);
DECLARE_MULTIPLE_FILE_TYPE("SC Audio File (*.SC)", sc);
DECLARE_MULTIPLE_FILE_TYPE("SCD Audio File (*.SCD)", scd);
DECLARE_MULTIPLE_FILE_TYPE("SCK Audio File (*.SCK)", sck);
DECLARE_MULTIPLE_FILE_TYPE("SD9 Audio File (*.SD9)", sd9);
DECLARE_MULTIPLE_FILE_TYPE("SDT Audio File (*.SDT)", sdt);
DECLARE_MULTIPLE_FILE_TYPE("SEG Audio File (*.SEG)", seg);
DECLARE_MULTIPLE_FILE_TYPE("SF0 Audio File (*.SF0)", sf0);
DECLARE_MULTIPLE_FILE_TYPE("SFL Audio File (*.SFL)", sfl);
DECLARE_MULTIPLE_FILE_TYPE("SFS Audio File (*.SFS)", sfs);
DECLARE_MULTIPLE_FILE_TYPE("SFX Audio File (*.SFX)", sfx);
DECLARE_MULTIPLE_FILE_TYPE("SGB Audio File (*.SGB)", sgb);
DECLARE_MULTIPLE_FILE_TYPE("SGD Audio File (*.SGD)", sgd);
DECLARE_MULTIPLE_FILE_TYPE("SGX Audio File (*.SGX)", sgx);
DECLARE_MULTIPLE_FILE_TYPE("SL3 Audio File (*.SL3)", sl3);
DECLARE_MULTIPLE_FILE_TYPE("SLI Audio File (*.SLI)", sli);
DECLARE_MULTIPLE_FILE_TYPE("SMP Audio File (*.SMP)", smp);
DECLARE_MULTIPLE_FILE_TYPE("SMPL Audio File (*.SMPL)", smpl);
DECLARE_MULTIPLE_FILE_TYPE("SND Audio File (*.SND)", snd);
DECLARE_MULTIPLE_FILE_TYPE("SNDS Audio File (*.SNDS)", snds);
DECLARE_MULTIPLE_FILE_TYPE("SNG Audio File (*.SNG)", sng);
DECLARE_MULTIPLE_FILE_TYPE("SNS Audio File (*.SNS)", sns);
DECLARE_MULTIPLE_FILE_TYPE("SPD Audio File (*.SPD)", spd);
DECLARE_MULTIPLE_FILE_TYPE("SPM Audio File (*.SPM)", spm);
DECLARE_MULTIPLE_FILE_TYPE("SPS Audio File (*.SPS)", sps);
DECLARE_MULTIPLE_FILE_TYPE("SPSD Audio File (*.SPSD)", spsd);
DECLARE_MULTIPLE_FILE_TYPE("SPW Audio File (*.SPW)", spw);
DECLARE_MULTIPLE_FILE_TYPE("SS2 Audio File (*.SS2)", ss2);
DECLARE_MULTIPLE_FILE_TYPE("SS3 Audio File (*.SS3)", ss3);
DECLARE_MULTIPLE_FILE_TYPE("SS7 Audio File (*.SS7)", ss7);
DECLARE_MULTIPLE_FILE_TYPE("SSM Audio File (*.SSM)", ssm);
DECLARE_MULTIPLE_FILE_TYPE("SSS Audio File (*.SSS)", sss);
DECLARE_MULTIPLE_FILE_TYPE("STER Audio File (*.STER)", ster);
DECLARE_MULTIPLE_FILE_TYPE("STH Audio File (*.STH)", sth);
//"stm", //common
DECLARE_MULTIPLE_FILE_TYPE("STMA Audio File (*.STMA)", stma);
DECLARE_MULTIPLE_FILE_TYPE("STR Audio File (*.STR)", str);
DECLARE_MULTIPLE_FILE_TYPE("STRM Audio File (*.STRM)", strm);
DECLARE_MULTIPLE_FILE_TYPE("STS Audio File (*.STS)", sts);
DECLARE_MULTIPLE_FILE_TYPE("STX Audio File (*.STX)", stx);
DECLARE_MULTIPLE_FILE_TYPE("SVAG Audio File (*.SVAG)", svag);
DECLARE_MULTIPLE_FILE_TYPE("SVS Audio File (*.SVS)", svs);
DECLARE_MULTIPLE_FILE_TYPE("SWAG Audio File (*.SWAG)", swag);
DECLARE_MULTIPLE_FILE_TYPE("SWAV Audio File (*.SWAV)", swav);
DECLARE_MULTIPLE_FILE_TYPE("SWD Audio File (*.SWD)", swd);
DECLARE_MULTIPLE_FILE_TYPE("SXD Audio File (*.SXD)", sxd);
DECLARE_MULTIPLE_FILE_TYPE("SXD2 Audio File (*.SXD2)", sxd2);
DECLARE_MULTIPLE_FILE_TYPE("TEC Audio File (*.TEC)", tec);
DECLARE_MULTIPLE_FILE_TYPE("THP Audio File (*.THP)", thp);
DECLARE_MULTIPLE_FILE_TYPE("TK1 Audio File (*.TK1)", tk1);
DECLARE_MULTIPLE_FILE_TYPE("TK5 Audio File (*.TK5)", tk5);
DECLARE_MULTIPLE_FILE_TYPE("TRA Audio File (*.TRA)", tra);
DECLARE_MULTIPLE_FILE_TYPE("TUN Audio File (*.TUN)", tun);
DECLARE_MULTIPLE_FILE_TYPE("TYDSP Audio File (*.TYDSP)", tydsp);
DECLARE_MULTIPLE_FILE_TYPE("UM3 Audio File (*.UM3)", um3);
DECLARE_MULTIPLE_FILE_TYPE("VAG Audio File (*.VAG)", vag);
DECLARE_MULTIPLE_FILE_TYPE("VAS Audio File (*.VAS)", vas);
DECLARE_MULTIPLE_FILE_TYPE("VAS Audio File (*.VAS)", vawx);
DECLARE_MULTIPLE_FILE_TYPE("VB Audio File (*.VB)", vb);
DECLARE_MULTIPLE_FILE_TYPE("VBK Audio File (*.VBK)", vbk);
DECLARE_MULTIPLE_FILE_TYPE("VGS Audio File (*.VGS)", vgs);
DECLARE_MULTIPLE_FILE_TYPE("VGV Audio File (*.VGV)", vgv);
DECLARE_MULTIPLE_FILE_TYPE("VIG Audio File (*.VIG)", vig);
DECLARE_MULTIPLE_FILE_TYPE("VMS Audio File (*.VMS)", vms);
DECLARE_MULTIPLE_FILE_TYPE("VOI Audio File (*.VOI)", voi);
DECLARE_MULTIPLE_FILE_TYPE("VPK Audio File (*.VPK)", vpk);
DECLARE_MULTIPLE_FILE_TYPE("VS Audio File (*.VS)", vs);
DECLARE_MULTIPLE_FILE_TYPE("VSF Audio File (*.VSF)", vsf);
DECLARE_MULTIPLE_FILE_TYPE("WAA Audio File (*.WAA)", waa);
DECLARE_MULTIPLE_FILE_TYPE("WAC Audio File (*.WAC)", wac);
DECLARE_MULTIPLE_FILE_TYPE("WAD Audio File (*.WAD)", wad);
DECLARE_MULTIPLE_FILE_TYPE("WAM Audio File (*.WAM)", wam);
DECLARE_MULTIPLE_FILE_TYPE("WAS Audio File (*.WAS)", was);
//"wav", //common
DECLARE_MULTIPLE_FILE_TYPE("WAVM Audio File (*.WAVM)", wavm);
DECLARE_MULTIPLE_FILE_TYPE("WEM Audio File (*.WEM)", wem);
DECLARE_MULTIPLE_FILE_TYPE("WII Audio File (*.WII)", wii);
DECLARE_MULTIPLE_FILE_TYPE("WMUS Audio File (*.WMUS)", wmus);
DECLARE_MULTIPLE_FILE_TYPE("WP2 Audio File (*.WP2)", wp2);
DECLARE_MULTIPLE_FILE_TYPE("WPD Audio File (*.WPD)", wpd);
DECLARE_MULTIPLE_FILE_TYPE("WSD Audio File (*.WSD)", wsd);
DECLARE_MULTIPLE_FILE_TYPE("WSI Audio File (*.WSI)", wsi);
DECLARE_MULTIPLE_FILE_TYPE("WVS Audio File (*.WVS)", wvs);
DECLARE_MULTIPLE_FILE_TYPE("XA File (*.XA)", xa);
DECLARE_MULTIPLE_FILE_TYPE("XA2 Audio File (*.XA2)", xa2);
DECLARE_MULTIPLE_FILE_TYPE("XA30 Audio File (*.XA30)", xa30);
DECLARE_MULTIPLE_FILE_TYPE("XAG Audio File (*.XAG)", xag);
DECLARE_MULTIPLE_FILE_TYPE("XAU Audio File (*.XAU)", xau);
DECLARE_MULTIPLE_FILE_TYPE("XMA Audio File (*.XMA)", xma);
DECLARE_MULTIPLE_FILE_TYPE("XMA2 Audio File (*.XMA2)", xma2);
DECLARE_MULTIPLE_FILE_TYPE("XMU Audio File (*.XMU)", xmu);
DECLARE_MULTIPLE_FILE_TYPE("XNB Audio File (*.XNB)", xnb);
DECLARE_MULTIPLE_FILE_TYPE("XSF Audio File (*.XSF)", xsf);
DECLARE_MULTIPLE_FILE_TYPE("XSS Audio File (*.XSS)", xss);
DECLARE_MULTIPLE_FILE_TYPE("XVAG Audio File (*.XVAG)", xvag);
DECLARE_MULTIPLE_FILE_TYPE("XVAS Audio File (*.XVAS)", xvas);
DECLARE_MULTIPLE_FILE_TYPE("XWAV Audio File (*.XWAV)", xwav);
DECLARE_MULTIPLE_FILE_TYPE("XWB Audio File (*.XWB)", xwb);
DECLARE_MULTIPLE_FILE_TYPE("XWM Audio File (*.XWM)", xwm);
DECLARE_MULTIPLE_FILE_TYPE("XWMA Audio File (*.XWMA)", xwma);
DECLARE_MULTIPLE_FILE_TYPE("XWS Audio File (*.XWS)", xws);
DECLARE_MULTIPLE_FILE_TYPE("XWV Audio File (*.XWV)", xwv);
DECLARE_MULTIPLE_FILE_TYPE("YDSP Audio File (*.YDSP)", ydsp);
DECLARE_MULTIPLE_FILE_TYPE("YMF Audio File (*.YMF)", ymf);
DECLARE_MULTIPLE_FILE_TYPE("ZSD Audio File (*.ZSD)", zsd);
DECLARE_MULTIPLE_FILE_TYPE("ZWDSP Audio File (*.ZWDSP)", zwdsp);
DECLARE_MULTIPLE_FILE_TYPE("VGMSTREAM Audio File (*.VGMSTREAM)", vgmstream);
#endif /*_FOO_FILETYPES_H_ */

View File

@ -162,6 +162,7 @@
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="foo_filetypes.h" />
<ClInclude Include="foo_prefs.h" />
<ClInclude Include="foo_vgmstream.h" />
<ClInclude Include="resource.h" />

View File

@ -21,6 +21,9 @@
<ClInclude Include="foo_prefs.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="foo_filetypes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>

View File

@ -20,6 +20,7 @@ extern "C" {
#include "../src/vgmstream.h"
}
#include "foo_vgmstream.h"
#include "foo_filetypes.h"
#ifndef VERSION
#include "../version.h"
@ -187,6 +188,26 @@ void input_vgmstream::get_info(file_info & p_info,abort_callback & p_abort ) {
p_info.info_set("metadata source", temp);
}
pos = description.find_first("number of streams: ");
if (pos != pfc::infinite_size)
{
pos += strlen("number of streams: ");
eos = description.find_first('\n', pos);
if (eos == pfc::infinite_size) eos = description.length();
temp.set_string(description + pos, eos - pos);
p_info.info_set("number of streams", temp);
}
pos = description.find_first("block size: ");
if (pos != pfc::infinite_size)
{
pos += strlen("block size: ");
eos = description.find_first('\n', pos);
if (eos == pfc::infinite_size) eos = description.length();
temp.set_string(description + pos, eos - pos);
p_info.info_set("block size", temp);
}
p_info.set_length(((double)length_in_ms)/1000);
}
@ -398,311 +419,3 @@ static input_singletrack_factory_t<input_vgmstream> g_input_vgmstream_factory;
DECLARE_COMPONENT_VERSION(APP_NAME,PLUGIN_VERSION,PLUGIN_DESCRIPTION);
VALIDATE_COMPONENT_FILENAME("foo_input_vgmstream.dll");
// Registered file types, to associate an extension with foobar2000 in Windows.
// Accepted types go in input_vgmstream::g_is_our_path; both lists don't need to match.
// todo do we really want to associate every single vgmstream format?
//
// these are declared statically, and if anyone has a better idea i'd like to hear it - josh.
DECLARE_MULTIPLE_FILE_TYPE("2DX9 Audio File (*.2DX9)", 2dx9);
DECLARE_MULTIPLE_FILE_TYPE("2PFS Audio File (*.2PFS)", 2pfs);
DECLARE_MULTIPLE_FILE_TYPE("AAAP Audio File (*.AAAP)", aaap);
DECLARE_MULTIPLE_FILE_TYPE("AAX Audio File (*.AAX)", aax);
DECLARE_MULTIPLE_FILE_TYPE("ACM Audio File (*.ACM)", acm);
DECLARE_MULTIPLE_FILE_TYPE("ADPCM Audio File (*.ADPCM)", adpcm);
DECLARE_MULTIPLE_FILE_TYPE("ADM Audio File (*.ADM)", adm);
DECLARE_MULTIPLE_FILE_TYPE("ADP Audio File (*.ADP)", adp);
DECLARE_MULTIPLE_FILE_TYPE("PS2 ADS Audio File (*.ADS)", ads);
DECLARE_MULTIPLE_FILE_TYPE("ADX Audio File (*.ADX)", adx);
DECLARE_MULTIPLE_FILE_TYPE("AFC Audio File (*.AFC)", afc);
DECLARE_MULTIPLE_FILE_TYPE("AGSC Audio File (*.AGSC)", agsc);
DECLARE_MULTIPLE_FILE_TYPE("AHX Audio File (*.AHX)", ahx);
DECLARE_MULTIPLE_FILE_TYPE("AIFC Audio File (*.AIFC)", aifc);
DECLARE_MULTIPLE_FILE_TYPE("AIX Audio File (*.AIX)", aix);
DECLARE_MULTIPLE_FILE_TYPE("AKB Audio File (*.AKB)", akb);
DECLARE_MULTIPLE_FILE_TYPE("AMTS Audio File (*.AMTS)", amts);
DECLARE_MULTIPLE_FILE_TYPE("AS4 Audio File (*.AS4)", as4);
DECLARE_MULTIPLE_FILE_TYPE("ASD Audio File (*.ASD)", asd);
DECLARE_MULTIPLE_FILE_TYPE("ASF Audio File (*.ASF)", asf);
DECLARE_MULTIPLE_FILE_TYPE("AST Audio File (*.AST)", ast);
DECLARE_MULTIPLE_FILE_TYPE("ASR Audio File (*.ASR)", asr);
DECLARE_MULTIPLE_FILE_TYPE("ASS Audio File (*.ASS)", ass);
DECLARE_MULTIPLE_FILE_TYPE("ATRAC3plus Audio File (*.AT3)", at3);
DECLARE_MULTIPLE_FILE_TYPE("AUD Audio File (*.AUD)", aud);
DECLARE_MULTIPLE_FILE_TYPE("AUS Audio File (*.AUS)", aus);
DECLARE_MULTIPLE_FILE_TYPE("BAKA Audio File (*.BAKA)", baka);
DECLARE_MULTIPLE_FILE_TYPE("BAF Audio File (*.BAF)", baf);
DECLARE_MULTIPLE_FILE_TYPE("BAR Audio File (*.BAR)", bar);
DECLARE_MULTIPLE_FILE_TYPE("BCSTM Audio File (*.BCSTM)", bcstm);
DECLARE_MULTIPLE_FILE_TYPE("BCWAV Audio File (*.BCWAV)", bcwav);
DECLARE_MULTIPLE_FILE_TYPE("BFSTM Audio File (*.BFSTM)", bfstm);
DECLARE_MULTIPLE_FILE_TYPE("BFWAV Audio File (*.BFWAV)", bfwav);
DECLARE_MULTIPLE_FILE_TYPE("BFWAV Audio File [2] (*.BFWAV)", bfwavnsmbu);
DECLARE_MULTIPLE_FILE_TYPE("BG00 Audio File (*.BG00)", bg00);
DECLARE_MULTIPLE_FILE_TYPE("BGW Audio File (*.BGW)", bgw);
DECLARE_MULTIPLE_FILE_TYPE("BH2PCM Audio File (*.BH2PCM)", bh2pcm);
DECLARE_MULTIPLE_FILE_TYPE("BIK Audio File (*.BIK)", bik);
DECLARE_MULTIPLE_FILE_TYPE("BIKA Audio File (*.BIKA)", bika);
DECLARE_MULTIPLE_FILE_TYPE("BIK2 Audio File (*.BIK2)", bik2);
DECLARE_MULTIPLE_FILE_TYPE("BIK2A Audio File (*.BIK2A)", bik2a);
DECLARE_MULTIPLE_FILE_TYPE("BK2 Audio File (*.BK2)", bk2);
DECLARE_MULTIPLE_FILE_TYPE("BK2A Audio File (*.BK2A)", bk2a);
DECLARE_MULTIPLE_FILE_TYPE("BMDX Audio File (*.BMDX)", bmdx);
DECLARE_MULTIPLE_FILE_TYPE("BMS Audio File (*.BMS)", bms);
DECLARE_MULTIPLE_FILE_TYPE("KLBS Audio File (*.BNK)", bnk);
DECLARE_MULTIPLE_FILE_TYPE("BNS Audio File (*.BNS)", bns);
DECLARE_MULTIPLE_FILE_TYPE("BNSF Audio File (*.BNSF)", bnsf);
DECLARE_MULTIPLE_FILE_TYPE("BO2 Audio File (*.BO2)", bo2);
DECLARE_MULTIPLE_FILE_TYPE("BRSTM Audio File (*.BRSTM)", brstm);
DECLARE_MULTIPLE_FILE_TYPE("BRSTM Audio File [2] (*.BRSTM)", brstmspm);
DECLARE_MULTIPLE_FILE_TYPE("BTSND Audio File (*.BTSND)", btsnd);
DECLARE_MULTIPLE_FILE_TYPE("BVG Audio File (*.BVG)", bvg);
DECLARE_MULTIPLE_FILE_TYPE("CAF Audio File (*.CAF)", caf);
DECLARE_MULTIPLE_FILE_TYPE("CAPDSP Audio File (*.CAPDSP)", capdsp);
DECLARE_MULTIPLE_FILE_TYPE("CBD2 Audio File (*.CBD2)", cbd2);
DECLARE_MULTIPLE_FILE_TYPE("CCC Audio File (*.CCC)", ccc);
DECLARE_MULTIPLE_FILE_TYPE("CFN Audio File (*.CFN)", cfn);
DECLARE_MULTIPLE_FILE_TYPE("CKD Audio File (*.CKD)", ckd);
DECLARE_MULTIPLE_FILE_TYPE("CNK Audio File (*.CNK)", cnk);
DECLARE_MULTIPLE_FILE_TYPE("CPS Audio File (*.CPS)", cps);
DECLARE_MULTIPLE_FILE_TYPE("DCS Audio File (*.DCS)", dcs);
DECLARE_MULTIPLE_FILE_TYPE("DE2 Audio File (*.DE2)", de2);
DECLARE_MULTIPLE_FILE_TYPE("DDSP Audio File (*.DDSP)", ddsp);
DECLARE_MULTIPLE_FILE_TYPE("DMSG Audio File (*.DMSG)", dmsg);
DECLARE_MULTIPLE_FILE_TYPE("DSP Audio File (*.DSP)", dsp);
DECLARE_MULTIPLE_FILE_TYPE("DSPW Audio File (*.DSPW)", dspw);
DECLARE_MULTIPLE_FILE_TYPE("DTK Audio File (*.DTK)", dtk);
DECLARE_MULTIPLE_FILE_TYPE("DVI Audio File (*.DVI)", dvi);
DECLARE_MULTIPLE_FILE_TYPE("DXH Audio File (*.DXH)", dxh);
DECLARE_MULTIPLE_FILE_TYPE("EAM Audio File (*.EAM)", eam);
DECLARE_MULTIPLE_FILE_TYPE("EMFF Audio File (*.EMFF)", emff);
DECLARE_MULTIPLE_FILE_TYPE("ENTH Audio File (*.ENTH)", enth);
DECLARE_MULTIPLE_FILE_TYPE("FAG Audio File (*.FAG)", fag);
DECLARE_MULTIPLE_FILE_TYPE("FILP Audio File (*.FILP)", filp);
DECLARE_MULTIPLE_FILE_TYPE("FSB Audio File (*.FSB)", fsb);
DECLARE_MULTIPLE_FILE_TYPE("G1L Audio File (*.G1L)", g1l);
DECLARE_MULTIPLE_FILE_TYPE("GBTS Audio File (*.GBTS)", gbts);
DECLARE_MULTIPLE_FILE_TYPE("GCA Audio File (*.GCA)", gca);
DECLARE_MULTIPLE_FILE_TYPE("GCM Audio File (*.GCM)", gcm);
DECLARE_MULTIPLE_FILE_TYPE("GCUB Audio File (*.GCUB)", gcub);
DECLARE_MULTIPLE_FILE_TYPE("GCW Audio File (*.GCW)", gcw);
DECLARE_MULTIPLE_FILE_TYPE("GENH Audio File (*.GENH)", genh);
DECLARE_MULTIPLE_FILE_TYPE("GMS Audio File (*.GMS)", gms);
DECLARE_MULTIPLE_FILE_TYPE("GSB Audio File (*.GSB)", gsb);
DECLARE_MULTIPLE_FILE_TYPE("HCA Audio File (*.HCA)", hca);
DECLARE_MULTIPLE_FILE_TYPE("HGC1 Audio File (*.HGC1)", hgc1);
DECLARE_MULTIPLE_FILE_TYPE("HIS Audio File (*.HIS)", his);
DECLARE_MULTIPLE_FILE_TYPE("HLWAV Audio File (*.HLWAV)", hlwav);
DECLARE_MULTIPLE_FILE_TYPE("HALPST Audio File (*.HPS)", hps);
DECLARE_MULTIPLE_FILE_TYPE("HSF Audio File (*.HSF)", hsf);
DECLARE_MULTIPLE_FILE_TYPE("HWAS Audio File (*.HWAS)", hwas);
DECLARE_MULTIPLE_FILE_TYPE("IDSP Audio File (*.IDSP)", idsp);
DECLARE_MULTIPLE_FILE_TYPE("IDVI Audio File (*.IDVI)", idvi);
DECLARE_MULTIPLE_FILE_TYPE("IKM Audio File (*.IKM)", ikm);
DECLARE_MULTIPLE_FILE_TYPE("ILD Audio File (*.ILD)", ild);
DECLARE_MULTIPLE_FILE_TYPE("PS2 RAW Interleaved PCM (*.INT)", int);
DECLARE_MULTIPLE_FILE_TYPE("ISD Audio File (*.ISD)", isd);
DECLARE_MULTIPLE_FILE_TYPE("ISWS Audio File (*.ISWS)", isws);
DECLARE_MULTIPLE_FILE_TYPE("IVAUD Audio File (*.IVAUD)", ivaud);
DECLARE_MULTIPLE_FILE_TYPE("IVAG Audio File (*.IVAG)", ivag);
DECLARE_MULTIPLE_FILE_TYPE("IVB Audio File (*.IVB)", ivb);
DECLARE_MULTIPLE_FILE_TYPE("JOE Audio File (*.JOE)", joe);
DECLARE_MULTIPLE_FILE_TYPE("JSTM Audio File (*.JSTM)", jstm);
DECLARE_MULTIPLE_FILE_TYPE("KCES Audio File (*.KCES)", kces);
DECLARE_MULTIPLE_FILE_TYPE("KCEY Audio File (*.KCEY)", kcey);
DECLARE_MULTIPLE_FILE_TYPE("KHV Audio File (*.KHV)", khv);
DECLARE_MULTIPLE_FILE_TYPE("KOVS Audio File (*.KOVS)", kovs);
DECLARE_MULTIPLE_FILE_TYPE("KRAW Audio File (*.KRAW)", kraw);
DECLARE_MULTIPLE_FILE_TYPE("LEG Audio File (*.LEG)", leg);
DECLARE_MULTIPLE_FILE_TYPE("LOGG Audio File (*.LOGG)", logg);
DECLARE_MULTIPLE_FILE_TYPE("LMP4 Audio File (*.LMP4)", lmp4);
DECLARE_MULTIPLE_FILE_TYPE("LPCM Audio File (*.LPCM)", lpcm);
DECLARE_MULTIPLE_FILE_TYPE("LPS Audio File (*.LPS)", lps);
DECLARE_MULTIPLE_FILE_TYPE("LSF Audio File (*.LSF)", lsf);
DECLARE_MULTIPLE_FILE_TYPE("LWAV Audio File (*.LWAV)", lwav);
DECLARE_MULTIPLE_FILE_TYPE("MATX Audio File (*.MATX)", matx);
DECLARE_MULTIPLE_FILE_TYPE("MC3 Audio File (*.MC3)", mc3);
DECLARE_MULTIPLE_FILE_TYPE("MCA Audio File (*.MCA)", mca);
DECLARE_MULTIPLE_FILE_TYPE("MCG Audio File (*.MCG)", mcg);
DECLARE_MULTIPLE_FILE_TYPE("MDS Audio File (*.MDS)", mds);
DECLARE_MULTIPLE_FILE_TYPE("MDSP Audio File (*.MDSP)", mdsp);
DECLARE_MULTIPLE_FILE_TYPE("PS2 MI4 Audio File (*.MI4)", mi4);
DECLARE_MULTIPLE_FILE_TYPE("PS2 MIB Audio File (*.MIB)", mib);
DECLARE_MULTIPLE_FILE_TYPE("PS2 MIC Audio File (*.MIC)", mic);
DECLARE_MULTIPLE_FILE_TYPE("MIHB Audio File (*.MIHB)", mihb);
DECLARE_MULTIPLE_FILE_TYPE("MNSTR Audio File (*.MNSTR)", mnstr);
DECLARE_MULTIPLE_FILE_TYPE("MPDSP Audio File (*.MPDSP)", mpdsp);
DECLARE_MULTIPLE_FILE_TYPE("MPDS Audio File (*.MPDS)", mpds);
DECLARE_MULTIPLE_FILE_TYPE("MSA Audio File (*.MSA)", msa);
DECLARE_MULTIPLE_FILE_TYPE("MSF Audio File (*.MSF)", msf);
DECLARE_MULTIPLE_FILE_TYPE("MSS Audio File (*.MSS)", mss);
DECLARE_MULTIPLE_FILE_TYPE("MSVP Audio File (*.MSVP)", msvp);
DECLARE_MULTIPLE_FILE_TYPE("MTAF Audio File (*.MTAF)", mtaf);
DECLARE_MULTIPLE_FILE_TYPE("MUS Playlist File (*.MUS)", mus);
DECLARE_MULTIPLE_FILE_TYPE("MUSC Audio File (*.MUSC)", musc);
DECLARE_MULTIPLE_FILE_TYPE("MUSX Audio File (*.MUSX)", musx);
DECLARE_MULTIPLE_FILE_TYPE("MWV Audio File (*.MWV)", mwv);
DECLARE_MULTIPLE_FILE_TYPE("MxSt Audio File (*.MxSt)", mxst);
DECLARE_MULTIPLE_FILE_TYPE("MYSPD Audio File (*.MYSPD)", myspd);
DECLARE_MULTIPLE_FILE_TYPE("NDP Audio File (*.NDP)", ndp);
DECLARE_MULTIPLE_FILE_TYPE("NGCA Audio File (*.NGCA)", ngca);
DECLARE_MULTIPLE_FILE_TYPE("PS2 NPSF Audio File (*.NPSF)", npsf);
DECLARE_MULTIPLE_FILE_TYPE("NUS3BANK Audio File (*.NUS3BANK)", nus3bank);
DECLARE_MULTIPLE_FILE_TYPE("NWA Audio File (*.NWA)", nwa);
DECLARE_MULTIPLE_FILE_TYPE("OGL Audio File (*.OGL)", ogl);
DECLARE_MULTIPLE_FILE_TYPE("OMU Audio File (*.OMU)", omu);
DECLARE_MULTIPLE_FILE_TYPE("OTM Audio File (*.OTM)", otm);
DECLARE_MULTIPLE_FILE_TYPE("P2BT Audio File (*.P2BT)", p2bt);
DECLARE_MULTIPLE_FILE_TYPE("P3D Audio File (*.P3D)", p3d);
DECLARE_MULTIPLE_FILE_TYPE("PAST Audio File (*.PAST)", past);
DECLARE_MULTIPLE_FILE_TYPE("PCM Audio File (*.PCM)", pcm);
DECLARE_MULTIPLE_FILE_TYPE("PDT Audio File (*.PDT)", pdt);
DECLARE_MULTIPLE_FILE_TYPE("PNB Audio File (*.PNB)", pnb);
DECLARE_MULTIPLE_FILE_TYPE("PONA Audio File (*.PONA)", pona);
DECLARE_MULTIPLE_FILE_TYPE("POS Audio File (*.POS)", pos);
DECLARE_MULTIPLE_FILE_TYPE("PS2STM Audio File (*.PS2STM)", ps2stm);
DECLARE_MULTIPLE_FILE_TYPE("PSH Audio File (*.PSH)", psh);
DECLARE_MULTIPLE_FILE_TYPE("PSND Audio File (*.PSND)", psnd);
DECLARE_MULTIPLE_FILE_TYPE("PSW Audio File (*.PSW)", psw);
DECLARE_MULTIPLE_FILE_TYPE("RAK Audio File (*.RAK)", rak);
DECLARE_MULTIPLE_FILE_TYPE("RAS Audio File (*.RAS)", ras);
DECLARE_MULTIPLE_FILE_TYPE("RAW Audio File (*.RAW)", raw);
DECLARE_MULTIPLE_FILE_TYPE("RKV Audio File (*.RKV)", rkv);
DECLARE_MULTIPLE_FILE_TYPE("RND Audio File (*.RND)", rnd);
DECLARE_MULTIPLE_FILE_TYPE("RRDS Audio File (*.RRDS)", rrds);
DECLARE_MULTIPLE_FILE_TYPE("RSD Audio File (*.RSD)", rsd);
DECLARE_MULTIPLE_FILE_TYPE("RSF Audio File (*.RSF)", rsf);
DECLARE_MULTIPLE_FILE_TYPE("RSTM Audio File (*.RSTM)", rstm);
DECLARE_MULTIPLE_FILE_TYPE("RVWS Audio File (*.RSTM)", rvws);
DECLARE_MULTIPLE_FILE_TYPE("RWAR Audio File (*.RWSD)", rwar);
DECLARE_MULTIPLE_FILE_TYPE("RWAV Audio File (*.RWAV)", rwav);
DECLARE_MULTIPLE_FILE_TYPE("RWS Audio File (*.RWS)", rws);
DECLARE_MULTIPLE_FILE_TYPE("RWSD Audio File (*.RWSD)", rwsd);
DECLARE_MULTIPLE_FILE_TYPE("RWX Audio File (*.RWX)", rwx);
DECLARE_MULTIPLE_FILE_TYPE("PS2 RXWS File (*.RXW)", rxw);
DECLARE_MULTIPLE_FILE_TYPE("S14 Audio File (*.S14)", s14);
DECLARE_MULTIPLE_FILE_TYPE("SAB Audio File (*.SAB)", sab);
DECLARE_MULTIPLE_FILE_TYPE("SAD Audio File (*.SAD)", sad);
DECLARE_MULTIPLE_FILE_TYPE("SAP Audio File (*.SAP)", sap);
DECLARE_MULTIPLE_FILE_TYPE("SC Audio File (*.SC)", sc);
DECLARE_MULTIPLE_FILE_TYPE("SCD Audio File (*.SCD)", scd);
DECLARE_MULTIPLE_FILE_TYPE("SCK Audio File (*.SCK)", sck);
DECLARE_MULTIPLE_FILE_TYPE("SD9 Audio File (*.SD9)", sd9);
DECLARE_MULTIPLE_FILE_TYPE("SDT Audio File (*.SDT)", sdt);
DECLARE_MULTIPLE_FILE_TYPE("SEG Audio File (*.SEG)", seg);
DECLARE_MULTIPLE_FILE_TYPE("SF0 Audio File (*.SF0)", sf0);
DECLARE_MULTIPLE_FILE_TYPE("SFL Audio File (*.SFL)", sfl);
DECLARE_MULTIPLE_FILE_TYPE("SFS Audio File (*.SFS)", sfs);
DECLARE_MULTIPLE_FILE_TYPE("SFX Audio File (*.SFX)", sfx);
DECLARE_MULTIPLE_FILE_TYPE("SGB Audio File (*.SGB)", sgb);
DECLARE_MULTIPLE_FILE_TYPE("SGD Audio File (*.SGD)", sgd);
DECLARE_MULTIPLE_FILE_TYPE("SGX Audio File (*.SGX)", sgx);
DECLARE_MULTIPLE_FILE_TYPE("SL3 Audio File (*.SL3)", sl3);
DECLARE_MULTIPLE_FILE_TYPE("SLI Audio File (*.SLI)", sli);
DECLARE_MULTIPLE_FILE_TYPE("SMP Audio File (*.SMP)", smp);
DECLARE_MULTIPLE_FILE_TYPE("SMPL Audio File (*.SMPL)", smpl);
DECLARE_MULTIPLE_FILE_TYPE("SND Audio File (*.SND)", snd);
DECLARE_MULTIPLE_FILE_TYPE("SNDS Audio File (*.SNDS)", snds);
DECLARE_MULTIPLE_FILE_TYPE("SNG Audio File (*.SNG)", sng);
DECLARE_MULTIPLE_FILE_TYPE("SNS Audio File (*.SNS)", sns);
DECLARE_MULTIPLE_FILE_TYPE("SPD Audio File (*.SPD)", spd);
DECLARE_MULTIPLE_FILE_TYPE("SPM Audio File (*.SPM)", spm);
DECLARE_MULTIPLE_FILE_TYPE("SPS Audio File (*.SPS)", sps);
DECLARE_MULTIPLE_FILE_TYPE("SPSD Audio File (*.SPSD)", spsd);
DECLARE_MULTIPLE_FILE_TYPE("SPW Audio File (*.SPW)", spw);
DECLARE_MULTIPLE_FILE_TYPE("PS2 SS2 Audio File (*.SS2)", ss2);
DECLARE_MULTIPLE_FILE_TYPE("SS3 Audio File (*.SS3)", ss3);
DECLARE_MULTIPLE_FILE_TYPE("SS7 Audio File (*.SS7)", ss7);
DECLARE_MULTIPLE_FILE_TYPE("SSM Audio File (*.SSM)", ssm);
DECLARE_MULTIPLE_FILE_TYPE("SSS Audio File (*.SSS)", sss);
DECLARE_MULTIPLE_FILE_TYPE("STER Audio File (*.STER)", ster);
DECLARE_MULTIPLE_FILE_TYPE("STMA Audio File (*.STMA)", stma);
DECLARE_MULTIPLE_FILE_TYPE("STR Audio File (*.STR)", str);
DECLARE_MULTIPLE_FILE_TYPE("STRM Audio File (*.STRM)", strm);
DECLARE_MULTIPLE_FILE_TYPE("PS2 EXST Audio File (*.STS)", sts);
DECLARE_MULTIPLE_FILE_TYPE("STX Audio File (*.STX)", stx);
DECLARE_MULTIPLE_FILE_TYPE("PS2 SVAG Audio File (*.SVAG)", svag);
DECLARE_MULTIPLE_FILE_TYPE("SVS Audio File (*.SVS)", svs);
DECLARE_MULTIPLE_FILE_TYPE("SWAV Audio File (*.SWAV)", swav);
DECLARE_MULTIPLE_FILE_TYPE("SWD Audio File (*.SWD)", swd);
DECLARE_MULTIPLE_FILE_TYPE("SXD Audio File (*.SXD)", sxd);
DECLARE_MULTIPLE_FILE_TYPE("SXD2 Audio File (*.SXD2)", sxd2);
DECLARE_MULTIPLE_FILE_TYPE("TEC Audio File (*.TEC)", tec);
DECLARE_MULTIPLE_FILE_TYPE("THP Audio File (*.THP)", thp);
DECLARE_MULTIPLE_FILE_TYPE("TK1 Audio File (*.TK1)", tk1);
DECLARE_MULTIPLE_FILE_TYPE("TK5 Audio File (*.TK5)", tk5);
DECLARE_MULTIPLE_FILE_TYPE("TUN Audio File (*.TUN)", tun);
DECLARE_MULTIPLE_FILE_TYPE("TYDSP Audio File (*.TYDSP)", tydsp);
DECLARE_MULTIPLE_FILE_TYPE("UM3 Audio File (*.UM3)", um3);
DECLARE_MULTIPLE_FILE_TYPE("VAG Audio File (*.VAG)", vag);
DECLARE_MULTIPLE_FILE_TYPE("VAS Audio File (*.VAS)", vas);
DECLARE_MULTIPLE_FILE_TYPE("VB Audio File (*.VB)", vb);
DECLARE_MULTIPLE_FILE_TYPE("VBK Audio File (*.VBK)", vbk);
DECLARE_MULTIPLE_FILE_TYPE("VGS Audio File (*.VGS)", vgs);
DECLARE_MULTIPLE_FILE_TYPE("VGV Audio File (*.VGV)", vgv);
DECLARE_MULTIPLE_FILE_TYPE("VIG Audio File (*.VIG)", vig);
DECLARE_MULTIPLE_FILE_TYPE("VMS Audio File (*.VMS)", vms);
DECLARE_MULTIPLE_FILE_TYPE("VOI Audio File (*.VOI)", voi);
DECLARE_MULTIPLE_FILE_TYPE("VPK Audio File (*.VPK)", vpk);
DECLARE_MULTIPLE_FILE_TYPE("VS Audio File (*.VS)", vs);
DECLARE_MULTIPLE_FILE_TYPE("VSF Audio File (*.VSF)", vsf);
DECLARE_MULTIPLE_FILE_TYPE("WAA Audio File (*.WAA)", waa);
DECLARE_MULTIPLE_FILE_TYPE("WAC Audio File (*.WAC)", wac);
DECLARE_MULTIPLE_FILE_TYPE("WAD Audio File (*.WAD)", wad);
DECLARE_MULTIPLE_FILE_TYPE("WAM Audio File (*.WAM)", wam);
DECLARE_MULTIPLE_FILE_TYPE("WAVM Audio File (*.WAVM)", wavm);
DECLARE_MULTIPLE_FILE_TYPE("WAS Audio File (*.WAS)", was);
DECLARE_MULTIPLE_FILE_TYPE("WEM Audio File (*.WEM)", wem);
DECLARE_MULTIPLE_FILE_TYPE("WII Audio File (*.WII)", wii);
DECLARE_MULTIPLE_FILE_TYPE("WMUS Audio File (*.WMUS)", wmus);
DECLARE_MULTIPLE_FILE_TYPE("WP2 Audio File (*.WP2)", wp2);
DECLARE_MULTIPLE_FILE_TYPE("WPD Audio File (*.WPD)", wpd);
DECLARE_MULTIPLE_FILE_TYPE("WSD Audio File (*.WSD)", wsd);
DECLARE_MULTIPLE_FILE_TYPE("WSI Audio File (*.WSI)", wsi);
DECLARE_MULTIPLE_FILE_TYPE("WVS Audio File (*.WVS)", wvs);
DECLARE_MULTIPLE_FILE_TYPE("PSX CD-XA File (*.XA)", xa);
DECLARE_MULTIPLE_FILE_TYPE("XA2 Audio File (*.XA2)", xa2);
DECLARE_MULTIPLE_FILE_TYPE("XA30 Audio File (*.XA30)", xa30);
DECLARE_MULTIPLE_FILE_TYPE("XAU Audio File (*.XAU)", xau);
DECLARE_MULTIPLE_FILE_TYPE("XMA Audio File (*.XMA)", xma);
DECLARE_MULTIPLE_FILE_TYPE("XMA2 Audio File (*.XMA2)", xma2);
DECLARE_MULTIPLE_FILE_TYPE("XMU Audio File (*.XMU)", xmu);
DECLARE_MULTIPLE_FILE_TYPE("XNB Audio File (*.XNB)", xnb);
DECLARE_MULTIPLE_FILE_TYPE("XSF Audio File (*.XSF)", xsf);
DECLARE_MULTIPLE_FILE_TYPE("XSS Audio File (*.XSS)", xss);
DECLARE_MULTIPLE_FILE_TYPE("XVAG Audio File (*.XVAG)", xvag);
DECLARE_MULTIPLE_FILE_TYPE("XVAS Audio File (*.XVAS)", xvas);
DECLARE_MULTIPLE_FILE_TYPE("XWAV Audio File (*.XWAV)", xwav);
DECLARE_MULTIPLE_FILE_TYPE("XWB Audio File (*.XWB)", xwb);
DECLARE_MULTIPLE_FILE_TYPE("YDSP Audio File (*.YDSP)", ydsp);
DECLARE_MULTIPLE_FILE_TYPE("YMF Audio File (*.YMF)", ymf);
DECLARE_MULTIPLE_FILE_TYPE("ZSD Audio File (*.ZSD)", zsd);
DECLARE_MULTIPLE_FILE_TYPE("ZWDSP Audio File (*.ZWDSP)", zwdsp);
DECLARE_MULTIPLE_FILE_TYPE("vgmstream Audio File (*.VGMSTREAM)", vgmstream);

View File

@ -75,10 +75,4 @@ STREAMFILE * open_foo_streamfile_buffer_by_file(service_ptr_t<file> m_file,const
STREAMFILE * open_foo_streamfile_buffer(const char * const filename, size_t buffersize, abort_callback * p_abort, t_filestats * stats);
STREAMFILE * open_foo_streamfile(const char * const filename, abort_callback * p_abort, t_filestats * stats);
#define DECLARE_MULTIPLE_FILE_TYPE(NAME,EXTENSION) \
namespace { static input_file_type_impl g_filetype_instance_##EXTENSION(NAME,"*." #EXTENSION ,true); \
static service_factory_single_ref_t<input_file_type_impl> g_filetype_service##EXTENSION(g_filetype_instance_##EXTENSION); }
#endif
#endif /*_FOO_VGMSTREAM_*/

View File

@ -43,6 +43,7 @@ Options:
-E: force end-to-end looping even if file has real loop points
-r outfile2.wav: output a second time after resetting
-2 N: only output the Nth (first is 0) set of stereo channels
-F: don't fade after N loops and play the rest of the stream
Typical usage would be:
test -o happy.wav happy.adx

View File

@ -114,6 +114,9 @@ void decode_lsf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
/* mtaf_decoder */
void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int channels);
/* mta2_decoder */
void decode_mta2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
/* mc3_decoder */
void decode_mc3(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
@ -201,9 +204,13 @@ void free_at3plus(maiatrac3plus_codec_data *data);
#ifdef VGM_USE_FFMPEG
/* ffmpeg_decoder */
ffmpeg_codec_data * init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size);
ffmpeg_codec_data * init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size);
void decode_ffmpeg(VGMSTREAM *stream, sample * outbuf, int32_t samples_to_do, int channels);
void reset_ffmpeg(VGMSTREAM *vgmstream);
void seek_ffmpeg(VGMSTREAM *vgmstream, int32_t num_sample);
void free_ffmpeg(ffmpeg_codec_data *data);
void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples);
#endif

View File

@ -1,7 +1,34 @@
#include "../vgmstream.h"
#include "coding.h"
#ifdef VGM_USE_FFMPEG
/* internal sizes, can be any value */
#define FFMPEG_DEFAULT_BUFFER_SIZE 2048
#define FFMPEG_DEFAULT_IO_BUFFER_SIZE 128 * 1024
static volatile int g_ffmpeg_initialized = 0;
/* ******************************************** */
/* INTERNAL UTILS */
/* ******************************************** */
/* Global FFmpeg init */
static void g_init_ffmpeg() {
if (g_ffmpeg_initialized == 1) {
while (g_ffmpeg_initialized < 2); /* active wait for lack of a better way */
}
else if (g_ffmpeg_initialized == 0) {
g_ffmpeg_initialized = 1;
av_log_set_flags(AV_LOG_SKIP_REPEATED);
av_log_set_level(AV_LOG_ERROR);
av_register_all();
g_ffmpeg_initialized = 2;
}
}
/* converts codec's samples (can be in any format, ex. Ogg's float32) to PCM16 */
static void convert_audio(sample *outbuf, const uint8_t *inbuf, int sampleCount, int bitsPerSample, int floatingPoint) {
int s;
switch (bitsPerSample) {
@ -59,15 +86,390 @@ static void convert_audio(sample *outbuf, const uint8_t *inbuf, int sampleCount,
}
}
/**
* Special patching for FFmpeg's buggy seek code.
*
* To seek with avformat_seek_file/av_seek_frame, FFmpeg's demuxers can implement read_seek2 (newest API)
* or read_seek (older API), with various search modes. If none are available it will use seek_frame_generic,
* which manually reads frame by frame until the selected timestamp. However, the prev frame will be consumed
* (so after seeking to 0 next av_read_frame will actually give the second frame and so on).
*
* Fortunately seek_frame_generic can use an index to find the correct position. This function reads the
* first frame/packet and sets up index to timestamp 0. This ensures faulty demuxers will seek to 0 correctly.
* Some formats may not seek to 0 even with this, though.
*/
static int init_seek(ffmpeg_codec_data * data) {
int ret, ts_index, found_first = 0;
int64_t ts = 0;
int64_t pos = 0; /* offset */
int size = 0; /* coded size */
int distance = 0; /* always? */
AVStream * stream;
AVPacket * pkt;
stream = data->formatCtx->streams[data->streamIndex];
pkt = data->lastReadPacket;
/* read_seek shouldn't need this index, but direct access to FFmpeg's internals is no good */
/* if (data->formatCtx->iformat->read_seek || data->formatCtx->iformat->read_seek2)
return 0; */
/* some formats already have a proper index (e.g. M4A) */
ts_index = av_index_search_timestamp(stream, ts, AVSEEK_FLAG_ANY);
if (ts_index>=0)
goto test_seek;
/* find the first + second packets to get pos/size */
while (1) {
av_packet_unref(pkt);
ret = av_read_frame(data->formatCtx, pkt);
if (ret < 0)
break;
if (pkt->stream_index != data->streamIndex)
continue; /* ignore non-selected streams */
if (!found_first) { /* first found */
found_first = 1;
pos = pkt->pos;
ts = pkt->dts;
continue;
} else { /* second found */
size = pkt->pos - pos; /* coded, pkt->size is decoded size */
break;
}
}
if (!found_first)
goto fail;
/* in rare cases there is only one packet */
/* if (size == 0) { size = data_end - pos; } */ /* no easy way to know, ignore (most formats don's need size) */
/* some formats (XMA1) don't seem to have packet.dts, pretend it's 0 */
if (ts == INT64_MIN)
ts = 0;
/* Some streams start with negative DTS (observed in Ogg). For Ogg seeking to negative or 0 doesn't alter the output.
* It does seem seeking before decoding alters a bunch of (inaudible) +-1 lower bytes though. */
VGM_ASSERT(ts != 0, "FFMPEG: negative start_ts (%li)\n", (long)ts);
if (ts != 0)
ts = 0;
/* add index 0 */
ret = av_add_index_entry(stream, pos, ts, size, distance, AVINDEX_KEYFRAME);
if ( ret < 0 )
return ret;
test_seek:
/* seek to 0 test / move back to beginning, since we just consumed packets */
ret = avformat_seek_file(data->formatCtx, data->streamIndex, ts, ts, ts, AVSEEK_FLAG_ANY);
if ( ret < 0 )
return ret; /* we can't even reset_vgmstream the file */
avcodec_flush_buffers(data->codecCtx);
return 0;
fail:
return -1;
}
/* ******************************************** */
/* AVIO CALLBACKS */
/* ******************************************** */
/* AVIO callback: read stream, skipping external headers if needed */
static int ffmpeg_read(void *opaque, uint8_t *buf, int buf_size) {
ffmpeg_codec_data *data = (ffmpeg_codec_data *) opaque;
uint64_t offset = data->offset;
int max_to_copy = 0;
int ret;
if (data->header_insert_block) {
if (offset < data->header_size) {
max_to_copy = (int)(data->header_size - offset);
if (max_to_copy > buf_size) {
max_to_copy = buf_size;
}
memcpy(buf, data->header_insert_block + offset, max_to_copy);
buf += max_to_copy;
buf_size -= max_to_copy;
offset += max_to_copy;
if (!buf_size) {
data->offset = offset;
return max_to_copy;
}
}
offset -= data->header_size;
}
/* when "fake" size is smaller than "real" size we need to make sure bytes_read (ret) is clamped;
* it confuses FFmpeg in rare cases (STREAMFILE may have valid data after size) */
if (offset + buf_size > data->size + data->header_size) {
buf_size = data->size - offset; /* header "read" is manually inserted later */
}
ret = read_streamfile(buf, offset + data->start, buf_size, data->streamfile);
if (ret > 0) {
offset += ret;
if (data->header_insert_block) {
ret += max_to_copy;
}
}
if (data->header_insert_block) {
offset += data->header_size;
}
data->offset = offset;
return ret;
}
/* AVIO callback: write stream not needed */
static int ffmpeg_write(void *opaque, uint8_t *buf, int buf_size) {
return -1;
}
/* AVIO callback: seek stream, skipping external headers if needed */
static int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence) {
ffmpeg_codec_data *data = (ffmpeg_codec_data *) opaque;
int ret = 0;
if (whence & AVSEEK_SIZE) {
return data->size + data->header_size;
}
whence &= ~(AVSEEK_SIZE | AVSEEK_FORCE);
/* false offsets, on reads data->start will be added */
switch (whence) {
case SEEK_SET:
break;
case SEEK_CUR:
offset += data->offset;
break;
case SEEK_END:
offset += data->size;
if (data->header_insert_block)
offset += data->header_size;
break;
}
/* clamp offset; fseek returns 0 when offset > size, too */
if (offset > data->size + data->header_size) {
offset = data->size + data->header_size;
}
data->offset = offset;
return ret;
}
/* ******************************************** */
/* MAIN INIT/DECODER */
/* ******************************************** */
/**
* Manually init FFmpeg, from an offset.
* Used if the stream has internal data recognized by FFmpeg.
*/
ffmpeg_codec_data * init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size) {
return init_ffmpeg_header_offset(streamFile, NULL, 0, start, size);
}
/**
* Manually init FFmpeg, from a fake header / offset.
*
* Takes a fake header, to trick FFmpeg into demuxing/decoding the stream.
* This header will be seamlessly inserted before 'start' offset, and total filesize will be 'header_size' + 'size'.
* The header buffer will be copied and memory-managed internally.
*/
ffmpeg_codec_data * init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size) {
char filename[PATH_LIMIT];
ffmpeg_codec_data * data;
int errcode, i;
int streamIndex, streamCount;
AVStream *stream;
AVCodecParameters *codecPar;
AVRational tb;
/* basic setup */
g_init_ffmpeg();
data = ( ffmpeg_codec_data * ) calloc(1, sizeof(ffmpeg_codec_data));
if (!data) return NULL;
streamFile->get_name( streamFile, filename, sizeof(filename) );
data->streamfile = streamFile->open(streamFile, filename, STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!data->streamfile) goto fail;
data->start = start;
data->size = size;
/* insert fake header to trick FFmpeg into demuxing/decoding the stream */
if (header_size > 0) {
data->header_size = header_size;
data->header_insert_block = av_memdup(header, header_size);
if (!data->header_insert_block) goto fail;
}
/* setup IO, attempt to autodetect format and gather some info */
data->buffer = av_malloc(FFMPEG_DEFAULT_IO_BUFFER_SIZE);
if (!data->buffer) goto fail;
data->ioCtx = avio_alloc_context(data->buffer, FFMPEG_DEFAULT_IO_BUFFER_SIZE, 0, data, ffmpeg_read, ffmpeg_write, ffmpeg_seek);
if (!data->ioCtx) goto fail;
data->formatCtx = avformat_alloc_context();
if (!data->formatCtx) goto fail;
data->formatCtx->pb = data->ioCtx;
if ((errcode = avformat_open_input(&data->formatCtx, "", NULL, NULL)) < 0) goto fail; /* autodetect */
if ((errcode = avformat_find_stream_info(data->formatCtx, NULL)) < 0) goto fail;
/* find valid audio stream inside */
streamIndex = -1;
streamCount = 0; /* audio streams only */
for (i = 0; i < data->formatCtx->nb_streams; ++i) {
stream = data->formatCtx->streams[i];
codecPar = stream->codecpar;
if (streamIndex < 0 && codecPar->codec_type == AVMEDIA_TYPE_AUDIO) {
streamIndex = i; /* select first audio stream found */
} else {
stream->discard = AVDISCARD_ALL; /* disable demuxing unneded streams */
}
if (codecPar->codec_type == AVMEDIA_TYPE_AUDIO)
streamCount++;
}
if (streamIndex < 0) goto fail;
data->streamIndex = streamIndex;
stream = data->formatCtx->streams[streamIndex];
data->streamCount = streamCount;
/* prepare codec and frame/packet buffers */
data->codecCtx = avcodec_alloc_context3(NULL);
if (!data->codecCtx) goto fail;
if ((errcode = avcodec_parameters_to_context(data->codecCtx, codecPar)) < 0) goto fail;
av_codec_set_pkt_timebase(data->codecCtx, stream->time_base);
data->codec = avcodec_find_decoder(data->codecCtx->codec_id);
if (!data->codec) goto fail;
if ((errcode = avcodec_open2(data->codecCtx, data->codec, NULL)) < 0) goto fail;
data->lastDecodedFrame = av_frame_alloc();
if (!data->lastDecodedFrame) goto fail;
av_frame_unref(data->lastDecodedFrame);
data->lastReadPacket = malloc(sizeof(AVPacket));
if (!data->lastReadPacket) goto fail;
av_new_packet(data->lastReadPacket, 0);
data->readNextPacket = 1;
data->bytesConsumedFromDecodedFrame = INT_MAX;
/* other setup */
data->sampleRate = data->codecCtx->sample_rate;
data->channels = data->codecCtx->channels;
data->floatingPoint = 0;
switch (data->codecCtx->sample_fmt) {
case AV_SAMPLE_FMT_U8:
case AV_SAMPLE_FMT_U8P:
data->bitsPerSample = 8;
break;
case AV_SAMPLE_FMT_S16:
case AV_SAMPLE_FMT_S16P:
data->bitsPerSample = 16;
break;
case AV_SAMPLE_FMT_S32:
case AV_SAMPLE_FMT_S32P:
data->bitsPerSample = 32;
break;
case AV_SAMPLE_FMT_FLT:
case AV_SAMPLE_FMT_FLTP:
data->bitsPerSample = 32;
data->floatingPoint = 1;
break;
case AV_SAMPLE_FMT_DBL:
case AV_SAMPLE_FMT_DBLP:
data->bitsPerSample = 64;
data->floatingPoint = 1;
break;
default:
goto fail;
}
data->bitrate = (int)(data->codecCtx->bit_rate);
data->endOfStream = 0;
data->endOfAudio = 0;
/* try to guess frames/samples (duration isn't always set) */
tb.num = 1; tb.den = data->codecCtx->sample_rate;
data->totalSamples = av_rescale_q(stream->duration, stream->time_base, tb);
if (data->totalSamples < 0)
data->totalSamples = 0; /* caller must consider this */
data->blockAlign = data->codecCtx->block_align;
data->frameSize = data->codecCtx->frame_size;
if(data->frameSize == 0) /* some formats don't set frame_size but can get on request, and vice versa */
data->frameSize = av_get_audio_frame_duration(data->codecCtx,0);
/* setup decode buffer */
data->sampleBufferBlock = FFMPEG_DEFAULT_BUFFER_SIZE;
data->sampleBuffer = av_malloc( data->sampleBufferBlock * (data->bitsPerSample / 8) * data->channels );
if (!data->sampleBuffer)
goto fail;
/* setup decent seeking for faulty formats */
errcode = init_seek(data);
if (errcode < 0) goto fail;
/* expose start samples to be skipped (encoder delay, usually added by MDCT-based encoders like AAC/MP3/ATRAC3/XMA/etc)
* get after init_seek because some demuxers like AAC only fill skip_samples for the first packet */
if (stream->start_skip_samples) /* samples to skip in the first packet */
data->skipSamples = stream->start_skip_samples;
else if (stream->skip_samples) /* samples to skip in any packet (first in this case), used sometimes instead (ex. AAC) */
data->skipSamples = stream->skip_samples;
return data;
fail:
free_ffmpeg(data);
return NULL;
}
/* decode samples of any kind of FFmpeg format */
void decode_ffmpeg(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do, int channels) {
ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data;
int bytesPerSample;
int bytesPerFrame;
int frameSize;
int bytesToRead;
int bytesRead;
int bytesPerSample, bytesPerFrame, frameSize;
int bytesToRead, bytesRead;
uint8_t *targetBuf;
@ -78,10 +480,7 @@ void decode_ffmpeg(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do,
int bytesConsumedFromDecodedFrame;
int readNextPacket;
int endOfStream;
int endOfAudio;
int readNextPacket, endOfStream, endOfAudio;
int framesReadNow;
@ -114,12 +513,7 @@ void decode_ffmpeg(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do,
/* keep reading and decoding packets until the requested number of samples (in bytes) */
while (bytesRead < bytesToRead) {
int planeSize;
int planar;
int dataSize;
int toConsume;
int errcode;
int planeSize, planar, dataSize, toConsume, errcode;
/* size of previous frame */
dataSize = av_samples_get_buffer_size(&planeSize, codecCtx->channels, lastDecodedFrame->nb_samples, codecCtx->sample_fmt, 1);
@ -231,10 +625,10 @@ void decode_ffmpeg(VGMSTREAM *vgmstream, sample * outbuf, int32_t samples_to_do,
end:
framesReadNow = bytesRead / frameSize;
// Convert the audio
/* Convert the audio */
convert_audio(outbuf, data->sampleBuffer, framesReadNow * channels, data->bitsPerSample, data->floatingPoint);
// Output the state back to the structure
/* Output the state back to the structure */
data->bytesConsumedFromDecodedFrame = bytesConsumedFromDecodedFrame;
data->readNextPacket = readNextPacket;
data->endOfStream = endOfStream;
@ -242,6 +636,10 @@ end:
}
/* ******************************************** */
/* UTILS */
/* ******************************************** */
void reset_ffmpeg(VGMSTREAM *vgmstream) {
ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data;
@ -268,7 +666,6 @@ void reset_ffmpeg(VGMSTREAM *vgmstream) {
}
}
void seek_ffmpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data;
int64_t ts;
@ -297,6 +694,55 @@ void seek_ffmpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
}
}
void free_ffmpeg(ffmpeg_codec_data *data) {
if (data == NULL)
return;
if (data->lastReadPacket) {
av_packet_unref(data->lastReadPacket);
free(data->lastReadPacket);
data->lastReadPacket = NULL;
}
if (data->lastDecodedFrame) {
av_free(data->lastDecodedFrame);
data->lastDecodedFrame = NULL;
}
if (data->codecCtx) {
avcodec_close(data->codecCtx);
avcodec_free_context(&(data->codecCtx));
data->codecCtx = NULL;
}
if (data->formatCtx) {
avformat_close_input(&(data->formatCtx));
data->formatCtx = NULL;
}
if (data->ioCtx) {
// buffer passed in is occasionally freed and replaced.
// the replacement must be freed as well.
data->buffer = data->ioCtx->buffer;
av_free(data->ioCtx);
data->ioCtx = NULL;
}
if (data->buffer) {
av_free(data->buffer);
data->buffer = NULL;
}
if (data->sampleBuffer) {
av_free(data->sampleBuffer);
data->sampleBuffer = NULL;
}
if (data->header_insert_block) {
av_free(data->header_insert_block);
data->header_insert_block = NULL;
}
if (data->streamfile) {
close_streamfile(data->streamfile);
data->streamfile = NULL;
}
free(data);
}
/**
* Sets the number of samples to skip at the beginning of the stream, needed by some "gapless" formats.
* (encoder delay, usually added by MDCT-based encoders like AAC/MP3/ATRAC3/XMA/etc to "set up" the decoder).

186
src/coding/mta2_decoder.c Normal file
View File

@ -0,0 +1,186 @@
#include "coding.h"
#include "../util.h"
/* MTA2 (EA XAS variant?) decoder based on:
* - MGS Developer Wiki: https://www.mgsdevwiki.com/wiki/index.php/MTA2_(Codec) [codec by daemon1]
* - Solid4 tools: https://github.com/GHzGangster/Drebin
*
* MTA2 layout:
* - data is divided into N tracks of 0x10 header + 0x90 frame per track channel, forming N streams
* ex: 8ch: track0 4ch + track1 4ch + track0 4ch + track1 4ch ...; or 2ch = 1ch track0 + 1ch track1
* * up to 16 possible tracks, but max seen is 3 (ex. track0=sneaking, track1=action, track2=ambience)
* - each ch frame is divided into 4 headers + 4 vertical groups with nibbles (0x4*4 + 0x20*4)
* ex. group1 is 0x04(4) + 0x14(4) + 0x24(4) + 0x34(4) ... (vertically maybe for paralelism?)
* - in case of "macroblock" layout, there are also headers before N tracks (like other MGS games)
*
* Due to this vertical layout and multiple hist/indexes, it decodes everything in a block between calls
* but discards unwanted data, instead of trying to skip to the target nibble. Meaning no need to save hist, and
* expects samples_to_do to be block_samples at most (could be simplified, I guess).
*
* Because of how the macroblock/track and stream's offset per channel work, they are supported by
* autodetecting and skipping when needed (ideally should keep a special layout/count, but this is simpler).
*/
static const int c1[8] = { /* mod table 1 */
0, 240, 460, 392, 488, 460, 460, 240
};
static const int c2[8] = { /* mod table 2 */
0, 0, -208, -220, -240, -240, -220, -104
};
static const int c3[32] = { /* shift table */
256, 335, 438, 573, 749, 979, 1281, 1675,
2190, 2864, 3746, 4898, 6406, 8377, 10955, 14327,
18736, 24503, 32043, 41905, 54802, 71668, 93724, 122568,
160290, 209620, 274133, 358500, 468831, 613119, 801811, 1048576
};
/* expands nibble */
static short calculate_output(int nibble, short smp1, short smp2, int mod, int sh) {
int output;
if (nibble > 7) /* sign extend */
nibble = nibble - 16;
output = (smp1 * c1[mod] + smp2 * c2[mod] + (nibble * c3[sh]) + 128) >> 8;
output = clamp16(output);
return (short)output;
}
/* autodetect and skip "macroblocks" */
static void mta2_block_update(VGMSTREAMCHANNEL * stream) {
int block_type, block_size, block_tracks, repeat = 1;
/* may need to skip N empty blocks */
do {
block_type = read_32bitBE(stream->offset + 0x00, stream->streamfile);
block_size = read_32bitBE(stream->offset + 0x04, stream->streamfile); /* including this header */
/* 0x08: always null */
block_tracks = read_32bitBE(stream->offset + 0x0c, stream->streamfile); /* total tracks of variable size (can be 0) */
/* 0x10001: music, 0x20001: sfx?, 0xf0: loop control (goes at the end) */
if (block_type != 0x00010001 && block_type != 0x00020001 && block_type != 0x000000F0)
return; /* not a block */
/* frame=010001+00/etc can be mistaken as block_type, do extra checks */
{
int i, track_channels = 0;
uint16_t channel_layout = (block_size >> 16);
uint16_t track_size = (block_size & 0xFFFF);
/* has chanel layout == may be a track */
if (channel_layout > 0 && channel_layout <= 0xFF) {
for (i = 0; i < 8; i++) {
if ((channel_layout >> i) & 0x01)
track_channels++;
}
if (track_channels*0x90 == track_size)
return;
}
}
if (block_size <= 0 || block_tracks < 0) { /* nonsense block (maybe at EOF) */
VGM_LOG("MTA2: bad block @ %08lx\n", stream->offset);
stream->offset += 0x10;
repeat = 0;
}
else if (block_tracks == 0) { /* empty block (common), keep repeating */
stream->offset += block_size;
}
else { /* normal block, position into next track header */
stream->offset += 0x10;
repeat = 0;
}
} while (repeat);
}
/* decodes a block for a channel, skipping macroblocks/tracks if needed */
void decode_mta2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int samples_done = 0, sample_count = 0, channel_block_samples, channel_first_sample, frame_size = 0;
int i, group, row, col;
int num_track = 0, channel_layout, track_channels = 0, track_channel;
/* block/track skip */
do {
/* autodetect and skip macroblock header */
mta2_block_update(stream);
/* parse track header (0x10) and skip tracks that our current channel doesn't belong to */
num_track = read_8bit(stream->offset+0x00,stream->streamfile); /* 0=first */
/* 0x01(3): num_frame (0=first), 0x04(1): 0? */
channel_layout = read_8bit(stream->offset+0x05,stream->streamfile); /* bitmask, see mta2.c */
frame_size = read_16bitBE(stream->offset+0x06,stream->streamfile); /* not including this header */
/* 0x08(8): null */
if (num_track < 0)
break; /* EOF: whatever */
track_channels = 0;
for (i = 0; i < 8; i++) {
if ((channel_layout >> i) & 0x01)
track_channels++;
}
/* assumes tracks channels are divided evenly in all tracks (ex. not 2ch + 1ch + 1ch) */
if (channel / track_channels == num_track)
break; /* channel belongs to this track */
/* keep looping for our track */
stream->offset += 0x10 + frame_size;
}
while (1);
track_channel = channel % track_channels;
channel_block_samples = (0x80*2);
channel_first_sample = first_sample % (0x80*2);
/* parse channel frame (header 0x04*4 + data 0x20*4) */
for (group = 0; group < 4; group++) {
short smp2, smp1, mod, sh, output;
int group_header = read_32bitBE(stream->offset + 0x10 + track_channel*0x90 + group*0x4, stream->streamfile);
smp2 = (short) ((group_header >> 16) & 0xfff0); /* upper 16b discarding 4b */
smp1 = (short) ((group_header >> 4) & 0xfff0); /* lower 16b discarding 4b */
mod = (group_header >> 5) & 0x7; /* mid 3b */
sh = group_header & 0x1f; /* lower 5b */
/* write header samples (skips the last 2 group nibbles), like Drebin's decoder
* last 2 nibbles and next 2 header hist should match though */
if (sample_count >= channel_first_sample && samples_done < samples_to_do) {
outbuf[samples_done * channelspacing] = smp2;
samples_done++;
}
sample_count++;
if (sample_count >= channel_first_sample && samples_done < samples_to_do) {
outbuf[samples_done * channelspacing] = smp1;
samples_done++;
}
sample_count++;
for (row = 0; row < 8; row++) {
for (col = 0; col < 4*2; col++) {
uint8_t nibbles = read_8bit(stream->offset + 0x10 + 0x10 + track_channel*0x90 + group*0x4 + row*0x10 + col/2, stream->streamfile);
int nibble_shift = (!(col&1) ? 4 : 0); /* upper first */
output = calculate_output((nibbles >> nibble_shift) & 0xf, smp1, smp2, mod, sh);
/* ignore last 2 nibbles (uses first 2 header samples) */
if (row < 7 || col < 3*2) {
if (sample_count >= channel_first_sample && samples_done < samples_to_do) {
outbuf[samples_done * channelspacing] = output;
samples_done++;
}
sample_count++;
}
smp2 = smp1;
smp1 = output;
}
}
}
/* block fully done */
if (channel_first_sample + samples_done == channel_block_samples) {
stream->offset += 0x10 + frame_size;
}
}

View File

@ -1,142 +1,152 @@
//#include <stdlib.h>
//#include <stdio.h>
#include "coding.h"
#include "../util.h"
#define MTAF_BLOCK_SUPPORT 0
#define MTAF_BLOCK_SUPPORT
// A hybrid of IMA and Yamaha ADPCM found in Metal Gear Solid 3
// Thanks to X_Tra (http://metalgear.in/) for pointing me to the step size table.
int index_table[16] = {
/* A hybrid of IMA and Yamaha ADPCM found in Metal Gear Solid 3
* Thanks to X_Tra (http://metalgear.in/) for pointing me to the step size table.
*
* Layout: N tracks of 0x10 header + 0x80*2 (always 2ch; multichannels uses 4ch = 2ch track0 + 2ch track1 xN)
* "macroblocks" support is not really needed as the extractors should remove them but they are
* autodetected and skipped if found (ideally should keep a special layout/count, but this is simpler).
*/
static const int index_table[16] = {
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8
};
static int16_t step_size[32][16] = {
{ 1, 5, 9, 13, 16, 20, 24, 28,
-1, -5, -9, -13, -16, -20, -24, -28, },
{ 2, 6, 11, 15, 20, 24, 29, 33,
-2, -6, -11, -15, -20, -24, -29, -33, },
{ 2, 7, 13, 18, 23, 28, 34, 39,
-2, -7, -13, -18, -23, -28, -34, -39, },
{ 3, 9, 15, 21, 28, 34, 40, 46,
-3, -9, -15, -21, -28, -34, -40, -46, },
{ 3, 11, 18, 26, 33, 41, 48, 56,
-3, -11, -18, -26, -33, -41, -48, -56, },
{ 4, 13, 22, 31, 40, 49, 58, 67,
-4, -13, -22, -31, -40, -49, -58, -67, },
{ 5, 16, 26, 37, 48, 59, 69, 80,
-5, -16, -26, -37, -48, -59, -69, -80, },
{ 6, 19, 31, 44, 57, 70, 82, 95,
-6, -19, -31, -44, -57, -70, -82, -95, },
{ 7, 22, 38, 53, 68, 83, 99, 114,
-7, -22, -38, -53, -68, -83, -99, -114, },
{ 9, 27, 45, 63, 81, 99, 117, 135,
-9, -27, -45, -63, -81, -99, -117, -135, },
{ 10, 32, 53, 75, 96, 118, 139, 161,
-10, -32, -53, -75, -96, -118, -139, -161, },
{ 12, 38, 64, 90, 115, 141, 167, 193,
-12, -38, -64, -90, -115, -141, -167, -193, },
{ 15, 45, 76, 106, 137, 167, 198, 228,
-15, -45, -76, -106, -137, -167, -198, -228, },
{ 18, 54, 91, 127, 164, 200, 237, 273,
-18, -54, -91, -127, -164, -200, -237, -273, },
{ 21, 65, 108, 152, 195, 239, 282, 326,
-21, -65, -108, -152, -195, -239, -282, -326, },
{ 25, 77, 129, 181, 232, 284, 336, 388,
-25, -77, -129, -181, -232, -284, -336, -388, },
{ 30, 92, 153, 215, 276, 338, 399, 461,
-30, -92, -153, -215, -276, -338, -399, -461, },
{ 36, 109, 183, 256, 329, 402, 476, 549,
-36, -109, -183, -256, -329, -402, -476, -549, },
{ 43, 130, 218, 305, 392, 479, 567, 654,
-43, -130, -218, -305, -392, -479, -567, -654, },
{ 52, 156, 260, 364, 468, 572, 676, 780,
-52, -156, -260, -364, -468, -572, -676, -780, },
{ 62, 186, 310, 434, 558, 682, 806, 930,
-62, -186, -310, -434, -558, -682, -806, -930, },
{ 73, 221, 368, 516, 663, 811, 958, 1106,
-73, -221, -368, -516, -663, -811, -958, -1106, },
{ 87, 263, 439, 615, 790, 966, 1142, 1318,
-87, -263, -439, -615, -790, -966, -1142, -1318, },
{ 104, 314, 523, 733, 942, 1152, 1361, 1571,
-104, -314, -523, -733, -942, -1152, -1361, -1571, },
{ 124, 374, 623, 873, 1122, 1372, 1621, 1871,
-124, -374, -623, -873, -1122, -1372, -1621, -1871, },
{ 148, 445, 743, 1040, 1337, 1634, 1932, 2229,
-148, -445, -743, -1040, -1337, -1634, -1932, -2229, },
{ 177, 531, 885, 1239, 1593, 1947, 2301, 2655,
-177, -531, -885, -1239, -1593, -1947, -2301, -2655, },
{ 210, 632, 1053, 1475, 1896, 2318, 2739, 3161,
-210, -632, -1053, -1475, -1896, -2318, -2739, -3161, },
{ 251, 753, 1255, 1757, 2260, 2762, 3264, 3766,
-251, -753, -1255, -1757, -2260, -2762, -3264, -3766, },
{ 299, 897, 1495, 2093, 2692, 3290, 3888, 4486,
-299, -897, -1495, -2093, -2692, -3290, -3888, -4486, },
{ 356, 1068, 1781, 2493, 3206, 3918, 4631, 5343,
-356, -1068, -1781, -2493, -3206, -3918, -4631, -5343, },
{ 424, 1273, 2121, 2970, 3819, 4668, 5516, 6365,
-424, -1273, -2121, -2970, -3819, -4668, -5516, -6365, },
static const int16_t step_size[32][16] = {
{ 1, 5, 9, 13, 16, 20, 24, 28,
-1, -5, -9, -13, -16, -20, -24, -28, },
{ 2, 6, 11, 15, 20, 24, 29, 33,
-2, -6, -11, -15, -20, -24, -29, -33, },
{ 2, 7, 13, 18, 23, 28, 34, 39,
-2, -7, -13, -18, -23, -28, -34, -39, },
{ 3, 9, 15, 21, 28, 34, 40, 46,
-3, -9, -15, -21, -28, -34, -40, -46, },
{ 3, 11, 18, 26, 33, 41, 48, 56,
-3, -11, -18, -26, -33, -41, -48, -56, },
{ 4, 13, 22, 31, 40, 49, 58, 67,
-4, -13, -22, -31, -40, -49, -58, -67, },
{ 5, 16, 26, 37, 48, 59, 69, 80,
-5, -16, -26, -37, -48, -59, -69, -80, },
{ 6, 19, 31, 44, 57, 70, 82, 95,
-6, -19, -31, -44, -57, -70, -82, -95, },
{ 7, 22, 38, 53, 68, 83, 99, 114,
-7, -22, -38, -53, -68, -83, -99, -114, },
{ 9, 27, 45, 63, 81, 99, 117, 135,
-9, -27, -45, -63, -81, -99, -117, -135, },
{ 10, 32, 53, 75, 96, 118, 139, 161,
-10, -32, -53, -75, -96, -118, -139, -161, },
{ 12, 38, 64, 90, 115, 141, 167, 193,
-12, -38, -64, -90, -115, -141, -167, -193, },
{ 15, 45, 76, 106, 137, 167, 198, 228,
-15, -45, -76, -106, -137, -167, -198, -228, },
{ 18, 54, 91, 127, 164, 200, 237, 273,
-18, -54, -91, -127, -164, -200, -237, -273, },
{ 21, 65, 108, 152, 195, 239, 282, 326,
-21, -65, -108, -152, -195, -239, -282, -326, },
{ 25, 77, 129, 181, 232, 284, 336, 388,
-25, -77, -129, -181, -232, -284, -336, -388, },
{ 30, 92, 153, 215, 276, 338, 399, 461,
-30, -92, -153, -215, -276, -338, -399, -461, },
{ 36, 109, 183, 256, 329, 402, 476, 549,
-36, -109, -183, -256, -329, -402, -476, -549, },
{ 43, 130, 218, 305, 392, 479, 567, 654,
-43, -130, -218, -305, -392, -479, -567, -654, },
{ 52, 156, 260, 364, 468, 572, 676, 780,
-52, -156, -260, -364, -468, -572, -676, -780, },
{ 62, 186, 310, 434, 558, 682, 806, 930,
-62, -186, -310, -434, -558, -682, -806, -930, },
{ 73, 221, 368, 516, 663, 811, 958, 1106,
-73, -221, -368, -516, -663, -811, -958, -1106, },
{ 87, 263, 439, 615, 790, 966, 1142, 1318,
-87, -263, -439, -615, -790, -966, -1142, -1318, },
{ 104, 314, 523, 733, 942, 1152, 1361, 1571,
-104, -314, -523, -733, -942, -1152, -1361, -1571, },
{ 124, 374, 623, 873, 1122, 1372, 1621, 1871,
-124, -374, -623, -873, -1122, -1372, -1621, -1871, },
{ 148, 445, 743, 1040, 1337, 1634, 1932, 2229,
-148, -445, -743, -1040, -1337, -1634, -1932, -2229, },
{ 177, 531, 885, 1239, 1593, 1947, 2301, 2655,
-177, -531, -885, -1239, -1593, -1947, -2301, -2655, },
{ 210, 632, 1053, 1475, 1896, 2318, 2739, 3161,
-210, -632, -1053, -1475, -1896, -2318, -2739, -3161, },
{ 251, 753, 1255, 1757, 2260, 2762, 3264, 3766,
-251, -753, -1255, -1757, -2260, -2762, -3264, -3766, },
{ 299, 897, 1495, 2093, 2692, 3290, 3888, 4486,
-299, -897, -1495, -2093, -2692, -3290, -3888, -4486, },
{ 356, 1068, 1781, 2493, 3206, 3918, 4631, 5343,
-356, -1068, -1781, -2493, -3206, -3918, -4631, -5343, },
{ 424, 1273, 2121, 2970, 3819, 4668, 5516, 6365,
-424, -1273, -2121, -2970, -3819, -4668, -5516, -6365, },
};
#ifdef MTAF_BLOCK_SUPPORT
/* autodetect and skip "macroblocks" */
static void mtaf_block_update(VGMSTREAMCHANNEL * stream) {
int block_type, block_size, block_empty, block_tracks, repeat = 1;
do {
block_type = read_32bitLE(stream->offset+0x00, stream->streamfile);
block_size = read_32bitLE(stream->offset+0x04, stream->streamfile); /* including this header */
block_empty = read_32bitLE(stream->offset+0x08, stream->streamfile); /* always 0 */
block_tracks = read_32bitLE(stream->offset+0x0c, stream->streamfile); /* total tracks of 0x110 (can be 0)*/
/* 0x110001: music (type 0x11=adpcm), 0xf0: loop control (goes at the end) */
if ((block_type != 0x00110001 && block_type != 0x000000F0) || block_empty != 0)
return; /* not a block */
/* track=001100+01 could be mistaken as block_type, do extra checks */
{
int track = read_8bit(stream->offset+0x10, stream->streamfile);
if (track != 0 && track != 1)
return; /* if this is a block, next header should be from track 0/1 */
if (block_tracks > 0 && (block_size-0x10) != block_tracks*0x110)
return; /* wrong expected size */
}
if (block_size <= 0 || block_tracks < 0) { /* nonsense block (maybe at EOF) */
VGM_LOG("MTAF: bad block @ %08lx\n", stream->offset);
stream->offset += 0x10;
repeat = 0;
}
else if (block_tracks == 0) { /* empty block (common), keep repeating */
stream->offset += block_size;
}
else { /* normal block, position into next track header */
stream->offset += 0x10;
repeat = 0;
}
} while(repeat);
}
#endif
void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int channels) {
int32_t sample_count;
off_t cur_off = stream->offset;
int i;
int c = channel%2; /* global channel to stream channel */
int c = channel%2; /* global channel to track channel */
int32_t hist = stream->adpcm_history1_16;
int32_t step_idx = stream->adpcm_step_index;
uint8_t byte = 0;
#if MTAF_BLOCK_SUPPORT
{
/* "macroblock" support (layout/mtaf_block.c) was removed since the extractor now produces clean files;
* this a hack to skip those blocks, left as a reminder (not well tested) */
int unk, size, empty, frames, repeat = 1;
do {
unk = read_32bitLE(cur_off+0x00, stream->streamfile); /* always BE 0x01001100? */
size = read_32bitLE(cur_off+0x04, stream->streamfile); /* block size */
empty = read_32bitLE(cur_off+0x08, stream->streamfile); /* always 0? */
frames = read_32bitLE(cur_off+0x0c, stream->streamfile); /* total frames of 0x110 */
if (unk == 0x00110001 && empty == 0 && size > 0) {
if (frames == 0) {
stream->offset += size; /* full skip */
} else if ((size-0x10) == frames*0x110) {
stream->offset += 0x10; /* header skip */
repeat = 0;
}
cur_off = stream->offset;
}
else {
repeat = 0;
}
} while(repeat);
}
#endif
#ifdef MTAF_BLOCK_SUPPORT
/* autodetect and skip macroblock header */
mtaf_block_update(stream);
#endif
/* read header when we hit a new track every 0x100 samples */
first_sample = first_sample % 0x100;
/* read header when we hit a new frame every 0x100 samples */
if (first_sample == 0) {
int32_t init_idx, init_hist;
/* 0x10 header: owner stream, frame count, step-L, step-R, hist-L, hist-R */
/* uint32_t stream = read_8bit(cur_off+0+c*2, stream->streamfile); */ /* 0=first */
/* uint24_t frames = (uint24_t)read_16bitLE(cur_off+1, stream->streamfile); */ /* 1=first */
init_idx = read_16bitLE(cur_off+4+c*2, stream->streamfile); /* step-L/R */
init_hist = read_16bitLE(cur_off+4+4+c*4, stream->streamfile); /* hist-L/R: hist 16bit + empty 16bit */
VGM_ASSERT( read_16bitLE(cur_off+4+4+2+c*4, stream->streamfile) != 0,
"init_hist not 16bit at 0x%lx, ch=%d\n", cur_off, c);
VGM_ASSERT( init_idx < 0 || init_idx > 31,
"init_idx out of range at 0x%lx, ch=%d\n", cur_off, c);
VGM_ASSERT( step_idx != init_idx,
"step_idx does not match init_idx at 0x%lx, step=%d, init=%d\n",cur_off,step_idx, init_idx);
/* 0x10 header: track (8b, 0=first), track count (24b, 1=first), step-L, step-R, hist-L, hist-R */
int32_t init_idx = read_16bitLE(stream->offset+4+0+c*2, stream->streamfile); /* step-L/R */
int32_t init_hist = read_16bitLE(stream->offset+4+4+c*4, stream->streamfile); /* hist-L/R: hist 16bit + empty 16bit */
VGM_ASSERT(init_idx < 0 || init_idx > 31, "MTAF: bad header idx @ 0x%lx\n", stream->offset);
/* avoid index out of range in corrupt files */
if (init_idx < 0) {
init_idx = 0;
@ -149,18 +159,12 @@ void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
}
/* skip to nibble */
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
uint8_t nibble;
if (i%2 != 1) { /* low nibble first */
byte = read_8bit(cur_off + 0x10 + 0x80*c + i/2, stream->streamfile);
nibble = byte & 0x0f;
} else { /* high nibble last */
nibble = byte >> 4;
}
uint8_t byte = read_8bit(stream->offset + 0x10 + 0x80*c + i/2, stream->streamfile);
uint8_t nibble = (byte >> (!(i&1)?0:4)) & 0xf; /* lower first */
hist = clamp16(hist+step_size[step_idx][nibble]);
outbuf[sample_count] = hist;
step_idx += index_table[nibble];
@ -169,10 +173,9 @@ void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
} else if (step_idx > 31) {
step_idx = 31;
}
} /* end sample loop */
}
// update state
/* update state */
stream->adpcm_step_index = step_idx;
stream->adpcm_history1_16 = hist;
}

View File

@ -53,6 +53,7 @@ static const char* extension_list[] = {
"bfwav",
"bfwavnsmbu",
"bg00",
"bgm",
"bgw",
"bh2pcm",
"bik",
@ -82,6 +83,7 @@ static const char* extension_list[] = {
"cps",
"cxs",
"dbm",
"dcs",
"ddsp",
"de2",
@ -143,6 +145,7 @@ static const char* extension_list[] = {
"kovs",
"kraw",
"laac", //fake extension, for tri-Ace/FFmpeg
"leg",
"lmp4", //fake extension, for looping
"logg", //fake extension, for looping
@ -156,6 +159,7 @@ static const char* extension_list[] = {
"mca",
"mcg",
"mds",
"mdsp",
"mi4",
"mib",
"mic",
@ -168,6 +172,7 @@ static const char* extension_list[] = {
"msf",
"mss",
"msvp",
"mta2",
"mtaf",
"mus",
"musc",
@ -288,11 +293,9 @@ static const char* extension_list[] = {
"vgs",
"vgv",
"vig",
"vds",
"vdm",
"vms",
"vms",
"voi",
"vpk",
"vs",
@ -446,6 +449,7 @@ static const coding_info coding_info_list[] = {
{coding_SASSC, "Activision / EXAKT SASSC 8-bit DPCM"},
{coding_LSF, "lsf 4-bit ADPCM"},
{coding_MTAF, "Konami MTAF 4-bit ADPCM"},
{coding_MTA2, "Konami MTA2 4-bit ADPCM"},
{coding_MC3, "Paradigm MC3 3-bit ADPCM"},
#ifdef VGM_USE_VORBIS
@ -791,7 +795,7 @@ static const meta_info meta_info_list[] = {
{meta_DSP_CABELAS, "Cabelas games dsp header"},
{meta_PS2_LPCM, "LPCM header"},
{meta_PS2_VMS, "VMS Header"},
{meta_PS2_XAU, "XAU Header"},
{meta_XAU, "XPEC XAU header"},
{meta_GH3_BAR, "Guitar Hero III Mobile .bar"},
{meta_FFW, "Freedom Fighters BGM header"},
{meta_DSP_DSPW, "DSPW dsp header"},
@ -861,6 +865,7 @@ static const meta_info meta_info_list[] = {
{meta_GTD, "GTD/GHS header"},
{meta_TA_AAC_X360, "tri-Ace AAC (X360) header"},
{meta_TA_AAC_PS3, "tri-Ace AAC (PS3) header"},
{meta_PS3_MTA2, "Konami MTA2 header"},
#ifdef VGM_USE_VORBIS
{meta_OGG_VORBIS, "Ogg Vorbis"},

View File

@ -946,10 +946,6 @@
RelativePath=".\meta\ps2_xa30.c"
>
</File>
<File
RelativePath=".\meta\ps2_xau.c"
>
</File>
<File
RelativePath=".\meta\ps3_cps.c"
>
@ -966,6 +962,10 @@
RelativePath=".\meta\ps3_msf.c"
>
</File>
<File
RelativePath=".\meta\ps3_mta2.c"
>
</File>
<File
RelativePath=".\meta\ps3_past.c"
>
@ -1202,6 +1202,10 @@
RelativePath=".\meta\x360_tra.c"
>
</File>
<File
RelativePath=".\meta\xau.c"
>
</File>
<File
RelativePath=".\meta\xbox_hlwav.c"
>
@ -1358,6 +1362,10 @@
RelativePath=".\coding\mtaf_decoder.c"
>
</File>
<File
RelativePath=".\coding\mta2_decoder.c"
>
</File>
<File
RelativePath=".\coding\nds_procyon_decoder.c"
>

View File

@ -129,6 +129,7 @@
<ClCompile Include="coding\lsf_decoder.c" />
<ClCompile Include="coding\mp4_aac_decoder.c" />
<ClCompile Include="coding\mtaf_decoder.c" />
<ClCompile Include="coding\mta2_decoder.c" />
<ClCompile Include="layout\ps2_iab_blocked.c" />
<ClCompile Include="layout\ps2_strlr_blocked.c" />
<ClCompile Include="layout\scd_int_layout.c" />
@ -340,9 +341,9 @@
<ClCompile Include="meta\ps2_wb.c" />
<ClCompile Include="meta\ps2_xa2.c" />
<ClCompile Include="meta\ps2_xa30.c" />
<ClCompile Include="meta\ps2_xau.c" />
<ClCompile Include="meta\ps3_cps.c" />
<ClCompile Include="meta\ps3_msf.c" />
<ClCompile Include="meta\ps3_mta2.c" />
<ClCompile Include="meta\ps3_xvag.c" />
<ClCompile Include="meta\psx_cdxa.c" />
<ClCompile Include="meta\psx_fag.c" />
@ -389,6 +390,7 @@
<ClCompile Include="meta\ws_aud.c" />
<ClCompile Include="meta\wvs.c" />
<ClCompile Include="meta\wwise.c" />
<ClCompile Include="meta\xau.c" />
<ClCompile Include="meta\xbox_hlwav.c" />
<ClCompile Include="meta\xbox_ims.c" />
<ClCompile Include="meta\xbox_stma.c" />

View File

@ -571,15 +571,15 @@
<ClCompile Include="meta\ps2_xa30.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ps2_xau.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ps3_cps.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ps3_msf.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ps3_mta2.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ps3_xvag.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -724,6 +724,9 @@
<ClCompile Include="meta\x360_pasx.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\xau.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\xbox_hlwav.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -1009,6 +1012,9 @@
<ClCompile Include="coding\mtaf_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\mta2_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\tun.c">
<Filter>meta\Source Files</Filter>
</ClCompile>

View File

@ -1,5 +1,5 @@
#include "../vgmstream.h"
#include "meta.h"
#include "../coding/coding.h"
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
/* AKB (AAC only) - found in SQEX iOS games */

View File

@ -1,41 +1,11 @@
#include "../vgmstream.h"
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
#ifdef VGM_USE_FFMPEG
/* internal sizes, can be any value */
#define FFMPEG_DEFAULT_BUFFER_SIZE 2048
#define FFMPEG_DEFAULT_IO_BUFFER_SIZE 128 * 1024
static int init_seek(ffmpeg_codec_data * data);
static volatile int g_ffmpeg_initialized = 0;
/*
* Global FFmpeg init
*/
static void g_init_ffmpeg()
{
if (g_ffmpeg_initialized == 1)
{
while (g_ffmpeg_initialized < 2);
}
else if (g_ffmpeg_initialized == 0)
{
g_ffmpeg_initialized = 1;
av_log_set_flags(AV_LOG_SKIP_REPEATED);
av_log_set_level(AV_LOG_ERROR);
av_register_all();
g_ffmpeg_initialized = 2;
}
}
/**
* Generic init FFmpeg and vgmstream for any file supported by FFmpeg.
* Always called by vgmstream when trying to identify the file type (if the player allows it).
* Called by vgmstream when trying to identify the file type (if the player allows it).
*/
VGMSTREAM * init_vgmstream_ffmpeg(STREAMFILE *streamFile) {
return init_vgmstream_ffmpeg_offset( streamFile, 0, streamFile->get_size(streamFile) );
@ -105,436 +75,4 @@ fail:
return NULL;
}
/**
* AVIO callback: read stream, skipping external headers if needed
*/
static int ffmpeg_read(void *opaque, uint8_t *buf, int buf_size)
{
ffmpeg_codec_data *data = (ffmpeg_codec_data *) opaque;
uint64_t offset = data->offset;
int max_to_copy = 0;
int ret;
if (data->header_insert_block) {
if (offset < data->header_size) {
max_to_copy = (int)(data->header_size - offset);
if (max_to_copy > buf_size) {
max_to_copy = buf_size;
}
memcpy(buf, data->header_insert_block + offset, max_to_copy);
buf += max_to_copy;
buf_size -= max_to_copy;
offset += max_to_copy;
if (!buf_size) {
data->offset = offset;
return max_to_copy;
}
}
offset -= data->header_size;
}
/* when "fake" size is smaller than "real" size we need to make sure bytes_read (ret) is clamped;
* it confuses FFmpeg in rare cases (STREAMFILE may have valid data after size) */
if (offset + buf_size > data->size + data->header_size) {
buf_size = data->size - offset; /* header "read" is manually inserted later */
}
ret = read_streamfile(buf, offset + data->start, buf_size, data->streamfile);
if (ret > 0) {
offset += ret;
if (data->header_insert_block) {
ret += max_to_copy;
}
}
if (data->header_insert_block) {
offset += data->header_size;
}
data->offset = offset;
return ret;
}
/**
* AVIO callback: write stream not needed
*/
static int ffmpeg_write(void *opaque, uint8_t *buf, int buf_size)
{
return -1;
}
/**
* AVIO callback: seek stream, skipping external headers if needed
*/
static int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence)
{
ffmpeg_codec_data *data = (ffmpeg_codec_data *) opaque;
int ret = 0;
if (whence & AVSEEK_SIZE) {
return data->size + data->header_size;
}
whence &= ~(AVSEEK_SIZE | AVSEEK_FORCE);
/* false offsets, on reads data->start will be added */
switch (whence) {
case SEEK_SET:
break;
case SEEK_CUR:
offset += data->offset;
break;
case SEEK_END:
offset += data->size;
if (data->header_insert_block)
offset += data->header_size;
break;
}
/* clamp offset; fseek returns 0 when offset > size, too */
if (offset > data->size + data->header_size) {
offset = data->size + data->header_size;
}
data->offset = offset;
return ret;
}
/**
* Manually init FFmpeg, from an offset.
* Can be used if the stream has an extra header over data recognized by FFmpeg.
*/
ffmpeg_codec_data * init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size) {
return init_ffmpeg_header_offset(streamFile, NULL, 0, start, size);
}
/**
* Manually init FFmpeg, from a fake header / offset.
*
* Can take a fake header, to trick FFmpeg into demuxing/decoding the stream.
* This header will be seamlessly inserted before 'start' offset, and total filesize will be 'header_size' + 'size'.
* The header buffer will be copied and memory-managed internally.
*/
ffmpeg_codec_data * init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size) {
char filename[PATH_LIMIT];
ffmpeg_codec_data * data;
int errcode, i;
int streamIndex, streamCount;
AVStream *stream;
AVCodecParameters *codecPar;
AVRational tb;
/* basic setup */
g_init_ffmpeg();
data = ( ffmpeg_codec_data * ) calloc(1, sizeof(ffmpeg_codec_data));
if (!data) return NULL;
streamFile->get_name( streamFile, filename, sizeof(filename) );
data->streamfile = streamFile->open(streamFile, filename, STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!data->streamfile) goto fail;
data->start = start;
data->size = size;
/* insert fake header to trick FFmpeg into demuxing/decoding the stream */
if (header_size > 0) {
data->header_size = header_size;
data->header_insert_block = av_memdup(header, header_size);
if (!data->header_insert_block) goto fail;
}
/* setup IO, attempt to autodetect format and gather some info */
data->buffer = av_malloc(FFMPEG_DEFAULT_IO_BUFFER_SIZE);
if (!data->buffer) goto fail;
data->ioCtx = avio_alloc_context(data->buffer, FFMPEG_DEFAULT_IO_BUFFER_SIZE, 0, data, ffmpeg_read, ffmpeg_write, ffmpeg_seek);
if (!data->ioCtx) goto fail;
data->formatCtx = avformat_alloc_context();
if (!data->formatCtx) goto fail;
data->formatCtx->pb = data->ioCtx;
if ((errcode = avformat_open_input(&data->formatCtx, "", NULL, NULL)) < 0) goto fail; /* autodetect */
if ((errcode = avformat_find_stream_info(data->formatCtx, NULL)) < 0) goto fail;
/* find valid audio stream inside */
streamIndex = -1;
streamCount = 0; /* audio streams only */
for (i = 0; i < data->formatCtx->nb_streams; ++i) {
stream = data->formatCtx->streams[i];
codecPar = stream->codecpar;
if (streamIndex < 0 && codecPar->codec_type == AVMEDIA_TYPE_AUDIO) {
streamIndex = i; /* select first audio stream found */
} else {
stream->discard = AVDISCARD_ALL; /* disable demuxing unneded streams */
}
if (codecPar->codec_type == AVMEDIA_TYPE_AUDIO)
streamCount++;
}
if (streamIndex < 0) goto fail;
data->streamIndex = streamIndex;
stream = data->formatCtx->streams[streamIndex];
data->streamCount = streamCount;
/* prepare codec and frame/packet buffers */
data->codecCtx = avcodec_alloc_context3(NULL);
if (!data->codecCtx) goto fail;
if ((errcode = avcodec_parameters_to_context(data->codecCtx, codecPar)) < 0) goto fail;
av_codec_set_pkt_timebase(data->codecCtx, stream->time_base);
data->codec = avcodec_find_decoder(data->codecCtx->codec_id);
if (!data->codec) goto fail;
if ((errcode = avcodec_open2(data->codecCtx, data->codec, NULL)) < 0) goto fail;
data->lastDecodedFrame = av_frame_alloc();
if (!data->lastDecodedFrame) goto fail;
av_frame_unref(data->lastDecodedFrame);
data->lastReadPacket = malloc(sizeof(AVPacket));
if (!data->lastReadPacket) goto fail;
av_new_packet(data->lastReadPacket, 0);
data->readNextPacket = 1;
data->bytesConsumedFromDecodedFrame = INT_MAX;
/* other setup */
data->sampleRate = data->codecCtx->sample_rate;
data->channels = data->codecCtx->channels;
data->floatingPoint = 0;
switch (data->codecCtx->sample_fmt) {
case AV_SAMPLE_FMT_U8:
case AV_SAMPLE_FMT_U8P:
data->bitsPerSample = 8;
break;
case AV_SAMPLE_FMT_S16:
case AV_SAMPLE_FMT_S16P:
data->bitsPerSample = 16;
break;
case AV_SAMPLE_FMT_S32:
case AV_SAMPLE_FMT_S32P:
data->bitsPerSample = 32;
break;
case AV_SAMPLE_FMT_FLT:
case AV_SAMPLE_FMT_FLTP:
data->bitsPerSample = 32;
data->floatingPoint = 1;
break;
case AV_SAMPLE_FMT_DBL:
case AV_SAMPLE_FMT_DBLP:
data->bitsPerSample = 64;
data->floatingPoint = 1;
break;
default:
goto fail;
}
data->bitrate = (int)(data->codecCtx->bit_rate);
data->endOfStream = 0;
data->endOfAudio = 0;
/* try to guess frames/samples (duration isn't always set) */
tb.num = 1; tb.den = data->codecCtx->sample_rate;
data->totalSamples = av_rescale_q(stream->duration, stream->time_base, tb);
if (data->totalSamples < 0)
data->totalSamples = 0; /* caller must consider this */
data->blockAlign = data->codecCtx->block_align;
data->frameSize = data->codecCtx->frame_size;
if(data->frameSize == 0) /* some formats don't set frame_size but can get on request, and vice versa */
data->frameSize = av_get_audio_frame_duration(data->codecCtx,0);
/* setup decode buffer */
data->sampleBufferBlock = FFMPEG_DEFAULT_BUFFER_SIZE;
data->sampleBuffer = av_malloc( data->sampleBufferBlock * (data->bitsPerSample / 8) * data->channels );
if (!data->sampleBuffer)
goto fail;
/* setup decent seeking for faulty formats */
errcode = init_seek(data);
if (errcode < 0) goto fail;
/* expose start samples to be skipped (encoder delay, usually added by MDCT-based encoders like AAC/MP3/ATRAC3/XMA/etc)
* get after init_seek because some demuxers like AAC only fill skip_samples for the first packet */
if (stream->start_skip_samples) /* samples to skip in the first packet */
data->skipSamples = stream->start_skip_samples;
else if (stream->skip_samples) /* samples to skip in any packet (first in this case), used sometimes instead (ex. AAC) */
data->skipSamples = stream->skip_samples;
return data;
fail:
free_ffmpeg(data);
return NULL;
}
/**
* Special patching for FFmpeg's buggy seek code.
*
* To seek with avformat_seek_file/av_seek_frame, FFmpeg's demuxers can implement read_seek2 (newest API)
* or read_seek (older API), with various search modes. If none are available it will use seek_frame_generic,
* which manually reads frame by frame until the selected timestamp. However, the prev frame will be consumed
* (so after seeking to 0 next av_read_frame will actually give the second frame and so on).
*
* Fortunately seek_frame_generic can use an index to find the correct position. This function reads the
* first frame/packet and sets up index to timestamp 0. This ensures faulty demuxers will seek to 0 correctly.
* Some formats may not seek to 0 even with this, though.
*/
static int init_seek(ffmpeg_codec_data * data) {
int ret, ts_index, found_first = 0;
int64_t ts = 0;
int64_t pos = 0; /* offset */
int size = 0; /* coded size */
int distance = 0; /* always? */
AVStream * stream;
AVPacket * pkt;
stream = data->formatCtx->streams[data->streamIndex];
pkt = data->lastReadPacket;
/* read_seek shouldn't need this index, but direct access to FFmpeg's internals is no good */
/* if (data->formatCtx->iformat->read_seek || data->formatCtx->iformat->read_seek2)
return 0; */
/* some formats already have a proper index (e.g. M4A) */
ts_index = av_index_search_timestamp(stream, ts, AVSEEK_FLAG_ANY);
if (ts_index>=0)
goto test_seek;
/* find the first + second packets to get pos/size */
while (1) {
av_packet_unref(pkt);
ret = av_read_frame(data->formatCtx, pkt);
if (ret < 0)
break;
if (pkt->stream_index != data->streamIndex)
continue; /* ignore non-selected streams */
if (!found_first) { /* first found */
found_first = 1;
pos = pkt->pos;
ts = pkt->dts;
continue;
} else { /* second found */
size = pkt->pos - pos; /* coded, pkt->size is decoded size */
break;
}
}
if (!found_first)
goto fail;
/* in rare cases there is only one packet */
/* if (size == 0) { size = data_end - pos; } */ /* no easy way to know, ignore (most formats don's need size) */
/* some formats (XMA1) don't seem to have packet.dts, pretend it's 0 */
if (ts == INT64_MIN)
ts = 0;
/* Some streams start with negative DTS (observed in Ogg). For Ogg seeking to negative or 0 doesn't alter the output.
* It does seem seeking before decoding alters a bunch of (inaudible) +-1 lower bytes though. */
VGM_ASSERT(ts != 0, "FFMPEG: negative start_ts (%li)\n", (long)ts);
if (ts != 0)
ts = 0;
/* add index 0 */
ret = av_add_index_entry(stream, pos, ts, size, distance, AVINDEX_KEYFRAME);
if ( ret < 0 )
return ret;
test_seek:
/* seek to 0 test / move back to beginning, since we just consumed packets */
ret = avformat_seek_file(data->formatCtx, data->streamIndex, ts, ts, ts, AVSEEK_FLAG_ANY);
if ( ret < 0 )
return ret; /* we can't even reset_vgmstream the file */
avcodec_flush_buffers(data->codecCtx);
return 0;
fail:
return -1;
}
void free_ffmpeg(ffmpeg_codec_data *data) {
if (data == NULL)
return;
if (data->lastReadPacket) {
av_packet_unref(data->lastReadPacket);
free(data->lastReadPacket);
data->lastReadPacket = NULL;
}
if (data->lastDecodedFrame) {
av_free(data->lastDecodedFrame);
data->lastDecodedFrame = NULL;
}
if (data->codecCtx) {
avcodec_close(data->codecCtx);
avcodec_free_context(&(data->codecCtx));
data->codecCtx = NULL;
}
if (data->formatCtx) {
avformat_close_input(&(data->formatCtx));
data->formatCtx = NULL;
}
if (data->ioCtx) {
// buffer passed in is occasionally freed and replaced.
// the replacement must be freed as well.
data->buffer = data->ioCtx->buffer;
av_free(data->ioCtx);
data->ioCtx = NULL;
}
if (data->buffer) {
av_free(data->buffer);
data->buffer = NULL;
}
if (data->sampleBuffer) {
av_free(data->sampleBuffer);
data->sampleBuffer = NULL;
}
if (data->header_insert_block) {
av_free(data->header_insert_block);
data->header_insert_block = NULL;
}
if (data->streamfile) {
close_streamfile(data->streamfile);
data->streamfile = NULL;
}
free(data);
}
#endif

View File

@ -19,7 +19,7 @@ VGMSTREAM * init_vgmstream_gtd(STREAMFILE *streamFile) {
if (read_32bitBE(0x00,streamFile) != 0x47485320) /* "GHS " */
goto fail;
VGM_LOG("1");
/* header type, not formally specified */
if (read_32bitBE(0x04,streamFile) == 1 && read_16bitBE(0x0C,streamFile) == 0x0166) { /* XMA2 */
/* 0x08(4): seek table size */
@ -55,8 +55,8 @@ VGM_LOG("1");
vgmstream->meta_type = meta_GTD;
switch(codec) {
case XMA2: {
#ifdef VGM_USE_FFMPEG
case XMA2: {
uint8_t buf[0x100];
size_t bytes;

View File

@ -121,21 +121,14 @@ VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_hca(STREAMFILE *streamFile);
#ifdef VGM_USE_FFMPEG
ffmpeg_codec_data * init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size);
ffmpeg_codec_data * init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size);
void free_ffmpeg(ffmpeg_codec_data *data);
VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size);
VGMSTREAM * init_vgmstream_ffmpeg(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size);
VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE * streamFile);
#endif
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
VGMSTREAM * init_vgmstream_mp4_aac(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_mp4_aac_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size);
VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile);
@ -541,7 +534,7 @@ VGMSTREAM * init_vgmstream_dsp_bdsp(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps2_vms(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps2_xau(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_xau(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_gh3_bar(STREAMFILE* streamFile);
@ -677,4 +670,6 @@ VGMSTREAM * init_vgmstream_gtd(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ta_aac_x360(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ta_aac_ps3(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ps3_mta2(STREAMFILE *streamFile);
#endif /*_META_H*/

View File

@ -1,6 +1,5 @@
#include "../vgmstream.h"
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
#ifdef VGM_USE_MP4V2
void* mp4_file_open( const char* name, MP4FileMode mode )

View File

@ -1,91 +1,62 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
/* AST */
/* AST - from Koei and Marvelous games (same internal dev?) */
VGMSTREAM * init_vgmstream_ps2_ast(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag, channel_count, variant_type;
int loop_flag = 0;
int channel_count;
int variant_type;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("ast",filename_extension(filename))) goto fail;
/* check extension */
if (!check_extensions(streamFile,"ast")) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x41535400) /* "AST\0" */
goto fail;
/* determine variant */
if (read_32bitBE(0x10,streamFile) == 0)
{
variant_type = 1;
}
else
{
variant_type = 2;
}
/* determine variant (after 0x10 is garbage/code data in type 1 until 0x800, but consistent in all songs) */
if (read_32bitBE(0x10,streamFile) == 0x00000000 || read_32bitBE(0x10,streamFile) == 0x20002000) {
variant_type = 1; /* Koei: P.T.O. IV (0x00000000), Naval Ops: Warship Gunner (0x20002000) */
channel_count = 2;
}
else {
variant_type = 2; /* Marvelous: Katekyoo Hitman Reborn! Dream Hyper Battle!, Binchou-tan: Shiawasegoyomi */
channel_count = read_32bitLE(0x0C,streamFile);
}
loop_flag = 0;
channel_count = 2;
/* build the VGMSTREAM */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
if (variant_type == 1)
{
start_offset = 0x800;
channel_count = 2;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
vgmstream->num_samples = (read_32bitLE(0x0C,streamFile)-start_offset)*28/16/channel_count;
vgmstream->interleave_block_size = read_32bitLE(0x08,streamFile);
loop_flag = 0;
}
else if (variant_type == 2)
{
start_offset = 0x100;
channel_count = read_32bitLE(0x0C,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
vgmstream->num_samples = (read_32bitLE(0x04,streamFile)-start_offset)*28/16/channel_count;
vgmstream->interleave_block_size = read_32bitLE(0x10,streamFile);
}
else
{
/* fill in the vital statistics */
if (variant_type == 1) {
start_offset = 0x800;
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x0C,streamFile)-start_offset,channel_count);
vgmstream->interleave_block_size = read_32bitLE(0x08,streamFile);
}
else if (variant_type == 2) {
start_offset = 0x100;
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x04,streamFile)-start_offset,channel_count);
vgmstream->interleave_block_size = read_32bitLE(0x10,streamFile);
}
else {
goto fail;
}
vgmstream->layout_type = layout_interleave;
vgmstream->coding_type = coding_PSX;
vgmstream->meta_type = meta_PS2_AST;
vgmstream->coding_type = coding_PSX;
vgmstream->meta_type = meta_PS2_AST;
/* 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;i<channel_count;i++) {
vgmstream->ch[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);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,182 +1,94 @@
//#include <stdlib.h>
#include "meta.h"
#include "../util.h"
/* MTAF (Metal Gear Solid 3: Snake Eater) */
/* MTAF - found in Metal Gear Solid 3: Snake Eater (Subsistence and HD too) */
VGMSTREAM * init_vgmstream_ps2_mtaf(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag, channel_count;
int32_t loop_start, loop_end;
int stream_count;
int loop_flag = 1;
int channel_count;
int32_t loop_start;
int32_t loop_end;
int i;
/* check extension */
if ( !check_extensions(streamFile,"mtaf"))
goto fail;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("mtaf",filename_extension(filename))) goto fail;
/* base header */
if (read_32bitBE(0x00, streamFile) != 0x4d544146) /* "MTAF" */
goto fail;
/* 0x04(4): pseudo file size (close but smaller) */
/* 0x08(4): version? (0), 0x0c(20): null, 0x30(32): some kind of id or config? */
/* check header */
// master MTAF header (mostly useless)
/* HEAD chunk */
if (read_32bitBE(0x40, streamFile) != 0x48454144) /* "HEAD" */
goto fail;
if (read_32bitLE(0x44, streamFile) != 0xB0) /* HEAD size */
goto fail;
if (read_32bitBE(0, streamFile) != 0x4d544146) // "MTAF"
{
//fprintf(stderr, "no MTAF header at 0x%08lx\n", cur_off);
/* 0x48(4): null, 0x4c: usually channel count (sometimes 0x10 with 2ch), 0x50(4): 0x7F (vol?), 0x54(2): 0x40 (pan?) */
channel_count = 2 * read_8bit(0x61, streamFile); /* 0x60(4): full block size (0x110 * channels), but this works */
/* 0x70(4): ? (00/05/07), 0x80 .. 0xf8: null */
loop_start = read_32bitLE(0x58, streamFile);
loop_end = read_32bitLE(0x5c, streamFile);
loop_flag = (loop_start != loop_end);
/* check loop points vs frame counts */
if (loop_start/0x100 != read_32bitLE(0x64, streamFile) ||
loop_end /0x100 != read_32bitLE(0x68, streamFile) ) {
VGM_LOG("MTAF: wrong loop points\n");
goto fail;
}
//const uint32_t pseudo_size = readint32(&mtaf_header_buf[4]);
/* TRKP chunks (x16) */
/* just seem to contain pan/vol stuff (0x7f/0x40), one TRKP with data per channel and the rest fixed values */
// check the rest is clear
for (i = 0x8; i < 0x20; i++)
{
if (read_8bit(i, streamFile) != 0)
{
//fprintf(stderr, "unexpected nonzero in MTAF header at 0x%08lx\n", cur_off+i);
goto fail;
}
}
// ignore the rest for now
// HEAD chunk header
if (read_32bitBE(0x40, streamFile) != 0x48454144) // "HEAD"
{
//fprintf(stderr, "no HEAD chunk at 0x%08lx\n", cur_off);
goto fail;
}
{
uint32_t mtaf_head_chunk_size = read_32bitLE(0x44, streamFile);
if (mtaf_head_chunk_size != 0xB0)
{
//fprintf(stderr, "unexpected size for MTAF header at 0x%08lx\n", cur_off);
goto fail;
}
}
stream_count = read_8bit(0x61, streamFile);
// check some standard stuff
if ( 0 != read_32bitLE(0x48, streamFile) ||
0x7F != read_32bitLE(0x50, streamFile) ||
0x40 != read_32bitLE(0x54, streamFile) ||
0 != read_16bitLE(0x62, streamFile) ||
0 != read_32bitLE(0x6c, streamFile)) // ||
//5 != readint32(&mtaf_header_buf[0x68])) ||
//(dc.streams==3 ? 12:0) != readint32(&mtaf_header_buf[0x7c]))
{
//fprintf(stderr, "unexpected header values at 0x%08lx\n", cur_off);
/* DATA chunk */
if (read_32bitBE(0x7f8, streamFile) != 0x44415441) /* "DATA" */
goto fail;
}
/* 0x7fc: data size (without blocks in case of blocked layout) */
// 0 streams should be impossible
if (stream_count == 0)
{
//fprintf(stderr, "0 streams at 0x%08lx\n", cur_off);
goto fail;
}
/* without blocks it should start with 0x00000100 ("frame 1 from track 0") */
//is_blocked = read_32bitLE(0x800,streamFile) != 0x00000100 && read_32bitLE(0x810,streamFile) == 0x00000100;
// check the other stream count indicator
if (stream_count*0x10 != read_8bit(0x60, streamFile))
{
//fprintf(stderr, "secondary stream count mismatch at 0x%08lx\n", cur_off);
goto fail;
}
#if 0
// maybe this is how to compute channels per stream?
// check total channel count
if (2*stream_count != read_32bitLE(0x4c, streamFile))
{
//fprintf(stderr, "total channel count does not match stream count at 0x%08lx\n", cur_off);
goto fail;
}
#endif
// check loop points as frame counts
if (read_32bitLE(0x64, streamFile) != read_32bitLE(0x58, streamFile)/0x100 ||
read_32bitLE(0x68, streamFile) != read_32bitLE(0x5c, streamFile)/0x100)
{
//fprintf(stderr, "loop frame count mismatch at 0x%lx\n", cur_off);
goto fail;
}
// check that rest is clear
for (i = 0x78; i < 0xf8; i++)
{
if (read_8bit(i, streamFile) != 0)
{
//fprintf(stderr, "unexpected nonzero in HEAD chunk at 0x%lx\n", cur_off+i);
goto fail;
}
}
// check TRKP chunks
for (i = 0; i < 16; i++)
{
if (read_32bitBE(0xf8+0x70*i, streamFile) != 0x54524b50 || // "TRKP"
read_32bitLE(0xf8+0x70*i+4, streamFile) != 0x68)
{
//fprintf(stderr, "missing or unusual TRKP chunk #%d at 0x%lx\n", i, cur_off);
goto fail;
}
}
// check for grand finale, DATA
if (read_32bitBE(0x7f8, streamFile) != 0x44415441) // "DATA"
{
//fprintf(stderr, "missing DATA header at 0x%lx\n", cur_off);
goto fail;
}
start_offset = 0x800;
// seems to always be the case
channel_count = 2 * stream_count;
loop_start = read_32bitLE(0x58, streamFile);
loop_end = read_32bitLE(0x5c, streamFile);
if (loop_start == loop_end) loop_flag = 0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
// a guess
vgmstream->channels = channel_count;
vgmstream->sample_rate = 48000;
vgmstream->coding_type = coding_MTAF;
vgmstream->num_samples = read_32bitLE(0x5c, streamFile);
vgmstream->sample_rate = 48000; /* always */
vgmstream->num_samples = loop_end;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->interleave_block_size = 0x110/2;
vgmstream->coding_type = coding_MTAF;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x110/2; /* kinda hacky for MTAF track layout */
vgmstream->meta_type = meta_PS2_MTAF;
//const uint32_t pseudo_data_size = readint32(&mtaf_header_buf[4]);
// TODO: first block
/* open the file for reading, in a specific way */
{
int i;
char filename[PATH_LIMIT];
/* open the file for reading */
for (i = 0; i < channel_count; i++) {
STREAMFILE * file = streamFile->open(streamFile,filename,vgmstream->interleave_block_size);
if (!file) goto fail;
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset = vgmstream->ch[i].offset = start_offset + vgmstream->interleave_block_size*2*(i/2);
streamFile->get_name(streamFile,filename,sizeof(filename));
for (i = 0; i < channel_count; i++) {
STREAMFILE * file = streamFile->open(streamFile,filename,vgmstream->interleave_block_size);
if (!file) goto fail;
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset = vgmstream->ch[i].offset = start_offset + vgmstream->interleave_block_size*2*(i/2);
}
}
return vgmstream;
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -23,6 +23,10 @@ VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE *streamFile) {
goto fail;
#endif
/* don't hijack Sonic & Sega All Stars Racing X360 (xma) */
if (read_32bitBE(0x00,streamFile) == 0x52494646) /* "RIFF"*/
goto fail;
loop_flag = 0;
channel_count = 2;

View File

@ -1,67 +0,0 @@
#include "meta.h"
#include "../util.h"
/* XAU (Spectral Force Chronicle [SLPM-65967]) */
VGMSTREAM * init_vgmstream_ps2_xau(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("xau",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x58415500)
goto fail;
loop_flag = 0;
channel_count = read_8bit(0x18,streamFile);
/* 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 = read_32bitBE(0x50, streamFile);
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = ((read_32bitBE(0x4C, streamFile) * channel_count)/ 16 / channel_count * 28);
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x8000;
vgmstream->meta_type = meta_PS2_XAU;
/* 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;i<channel_count;i++)
{
vgmstream->ch[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;
}

View File

@ -34,7 +34,7 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
/* byte flags, not in MSFv1 or v2
* 0x01/02/04/08: loop marker 0/1/2/3
* 0x10: "resample" loop option (may be active with no 0x01 flag set)
* 0x10: resample options (force 44/48khz)
* 0x20: VBR MP3
* 0x40: joint stereo MP3 (apparently interleaved stereo for other formats)
* 0x80+: (none/reserved) */
@ -104,17 +104,19 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
case 0x6: { /* ATRAC3 high (132 kbps, frame size 192) */
ffmpeg_codec_data *ffmpeg_data = NULL;
uint8_t buf[100];
int32_t bytes, block_size, encoder_delay, joint_stereo, max_samples;
int32_t bytes, block_size, encoder_delay, joint_stereo;
block_size = (codec_id==4 ? 0x60 : (codec_id==5 ? 0x98 : 0xC0)) * vgmstream->channels;
encoder_delay = 0x0; //todo MSF encoder delay (around 440-450*2)
max_samples = atrac3_bytes_to_samples(data_size, block_size);
joint_stereo = codec_id==4; /* interleaved joint stereo (ch must be even) */
joint_stereo = (codec_id==4); /* interleaved joint stereo (ch must be even) */
/* MSF skip samples: from tests with MSEnc and real files (ex. TTT2 eddy.msf v43, v01 demos) seems like 1162 is consistent.
* Atelier Rorona bt_normal01 needs it to properly skip the beginning garbage but usually doesn't matter.
* (note that encoder may add a fade-in with looping/resampling enabled but should be skipped) */
encoder_delay = 1162;
vgmstream->num_samples = atrac3_bytes_to_samples(data_size, block_size) - encoder_delay;
if (vgmstream->sample_rate==0xFFFFFFFF) /* some MSFv1 (Digi World SP) */
vgmstream->sample_rate = 44100;//voice tracks seems to use 44khz, not sure about other tracks
/* make a fake riff so FFmpeg can parse the ATRAC3 */
bytes = ffmpeg_make_riff_atrac3(buf, 100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, encoder_delay);
if (bytes <= 0) goto fail;
@ -124,10 +126,16 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = max_samples;
/* manually set skip_samples if FFmpeg didn't do it */
if (ffmpeg_data->skipSamples <= 0) {
ffmpeg_set_skip_samples(ffmpeg_data, encoder_delay);
}
/* MSF loop/sample values are offsets so trickier to adjust the skip_samples but this seems correct */
if (loop_flag) {
vgmstream->loop_start_sample = atrac3_bytes_to_samples(loop_start, block_size);
vgmstream->loop_end_sample = atrac3_bytes_to_samples(loop_end, block_size);
vgmstream->loop_start_sample = atrac3_bytes_to_samples(loop_start, block_size) /* - encoder_delay*/;
vgmstream->loop_end_sample = atrac3_bytes_to_samples(loop_end, block_size) - encoder_delay;
}
break;

104
src/meta/ps3_mta2.c Normal file
View File

@ -0,0 +1,104 @@
#include "meta.h"
#include "../util.h"
/* MTA2 - found in Metal Gear Solid 4 */
VGMSTREAM * init_vgmstream_ps3_mta2(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t header_offset, start_offset;
int loop_flag, channel_count, sample_rate; //block_offset;
int32_t loop_start, loop_end;
/* check extension */
/* .mta2: normal file, .bgm: mta2 with block layout, .dbm: iPod metadata + block layout mta2 */
if ( !check_extensions(streamFile,"mta2,bgm,dbm"))
goto fail;
/* base header (everything is very similar to MGS3's MTAF but BE) */
if (read_32bitBE(0x00,streamFile) == 0x4d544132) { /* "MTA2" (.mta) */
//block_offset = 0;
header_offset = 0x00;
} else if (read_32bitBE(0x20,streamFile) == 0x4d544132) { /* "MTA2" @ 0x20 (.bgm) */
//block_offset = 0x10;
header_offset = 0x20;
} else if (read_32bitBE(0x00, streamFile) == 0x444C424D
&& read_32bitBE(0x820,streamFile) == 0x4d544132) { /* "DLBM" + "MTA2" @ 0x820 (.dbm) */
//block_offset = 0x810;
header_offset = 0x820;
} else {
goto fail;
}
/* 0x04(4): file size -4-4 (not including block headers in case of block layout) */
/* 0x08(4): version? (1), 0x0c(52): null */
/* HEAD chunk */
if (read_32bitBE(header_offset+0x40, streamFile) != 0x48454144) /* "HEAD" */
goto fail;
if (read_32bitBE(header_offset+0x44, streamFile) != 0xB0) /* HEAD size */
goto fail;
/* 0x48(4): null, 0x4c: ? (0x10), 0x50(4): 0x7F (vol?), 0x54(2): 0x40 (pan?) */
channel_count = read_16bitBE(header_offset+0x56, streamFile); /* counting all tracks */
/* 0x60(4): full block size (0x110 * channels), indirectly channels_per_track = channels / (block_size / 0x110) */
/* 0x80 .. 0xf8: null */
loop_start = read_32bitBE(header_offset+0x58, streamFile);
loop_end = read_32bitBE(header_offset+0x5c, streamFile);
loop_flag = (loop_start != loop_end); /* also flag possibly @ 0x73 */
#if 0
/* those values look like some kind of loop offsets */
if (loop_start/0x100 != read_32bitBE(header_offset+0x68, streamFile) ||
loop_end /0x100 != read_32bitBE(header_offset+0x6C, streamFile) ) {
VGM_LOG("MTA2: wrong loop points\n");
goto fail;
}
#endif
sample_rate = read_32bitBE(header_offset+0x7c, streamFile);
if (sample_rate) { /* sample rate in 32b float (WHY?) typically 48000.0 */
float sample_float;
memcpy(&sample_float, &sample_rate, 4);
sample_rate = (int)sample_float;
} else { /* default when not specified (most of the time) */
sample_rate = 48000;
}
/* TRKP chunks (x16) */
/* just seem to contain pan/vol stuff (0x7f/0x40), TRKP per track (sometimes +1 main track?) */
/* there is channel layout bitmask @ 0x0f (ex. 1ch = 0x04, 3ch = 0x07, 4ch = 0x33, 6ch = 0x3f), surely:
* FRONT_L = 0x01, FRONT_R = 0x02, FRONT_M = 0x04, BACK_L = 0x08, BACK_R = 0x10, BACK_M = 0x20 */
/* DATA chunk */
if (read_32bitBE(header_offset+0x7f8, streamFile) != 0x44415441) // "DATA"
goto fail;
/* 0x7fc: data size (without blocks in case of blocked layout) */
start_offset = header_offset + 0x800;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = loop_end;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->coding_type = coding_MTA2;
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_PS3_MTA2;
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -174,7 +174,6 @@ int read_fmt(int big_endian,
case 0xFFFE: /* WAVEFORMATEXTENSIBLE / ATRAC3plus */
#endif /* defined */
fmt->coding_type = coding_FFmpeg;
fmt->block_size = 2048;
fmt->interleave = 0;
break;
#endif /* VGM_USE_FFMPEG */
@ -408,10 +407,20 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
if ( !ffmpeg_data ) goto fail;
sample_count = ffmpeg_data->totalSamples; /* fact_sample_count */
/* the encoder introduces some garbage (usually silent) samples to skip before the stream
* loop values include the skip samples but fact_sample_count doesn't; add them back to fix some edge loops */
if (fact_sample_skip > 0)
sample_count += fact_sample_skip;
if (at3) {
/* the encoder introduces some garbage (not always silent) samples to skip before the stream */
/* manually set skip_samples if FFmpeg didn't do it */
if (ffmpeg_data->skipSamples <= 0) {
ffmpeg_set_skip_samples(ffmpeg_data, fact_sample_skip);
}
/* RIFF loop/sample values are absolute (with skip samples), adjust */
if (loop_flag) {
loop_start_offset -= ffmpeg_data->skipSamples;
loop_end_offset -= ffmpeg_data->skipSamples;
}
}
}
break;
#endif

View File

@ -1,49 +1,28 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
/* utils to fix AT3 looping */
typedef struct {
int32_t fact_samples;
int32_t loop_start_sample;
int32_t loop_end_sample;
int32_t skip_samples;
} at3_riff_info;
static int get_at3_riff_info(at3_riff_info* info, STREAMFILE *streamFile, int32_t offset);
/* Sony's SGB+SGH / SGD / SGX (variations of the same format)
* PS3: Genji (SGX only), Folklore, Afrika, Tokyo Jungle
* PSP: Brave Story, Sarugetchu Sarusaru Daisakusen, Kurohyo 1/2
*
* Contains header + chunks, usually:
* WAVE: stream(s) header of ADPCM, AC3, ATRAC3plus, etc
* NAME: stream name(s)
* WSUR, WMRK, BUSS: unknown
* RGND, SEQD: unknown (related to SE)
* Then data, containing the original header if applicable (ex. AT3 RIFF).
* The SGXD header has priority over it (ex. some ATRAC3plus files have 48000 while the data RIFF 44100)
*/
/* SGXD - Sony/SCEI's format (SGB+SGH / SGD / SGX), found in:
* PS3: Genji, Folklore, Afrika (Short VAG), Tokyo Jungle
* PSP: Brave Story, Sarugetchu Sarusaru Daisakusen, Kurohyo 1/2, Pathwork Heroes */
VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * streamHeader = NULL;
off_t start_offset, data_offset, chunk_offset;
size_t data_size;
int is_sgx, is_sgb;
int loop_flag, channels, type;
int sample_rate, num_samples, loop_start_sample, loop_end_sample;
int target_stream = 0, total_streams;
/* check extension, case insensitive */
/* .sgx: header+data (Genji), .sgd: header+data, .sgh/sgd: header/data */
if (!check_extensions(streamFile,"sgx,sgd,sgb"))
goto fail;
is_sgx = check_extensions(streamFile,"sgx");
is_sgb = check_extensions(streamFile,"sgb");
//is_sgd = check_extensions(streamFile,"sgd");
/* SGB+SGH: use SGH as header; otherwise use the current file as header */
if (is_sgb) {
@ -69,14 +48,15 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
}
/* typical chunks: WAVE, NAME (strings), RGND, SEQD (related to SFX), WSUR, WMKR, BUSS */
/* WAVE chunk (size 0x10 + files * 0x38 + optional padding) */
/* 0x04 SGX: unknown; SGD/SGH: chunk length, 0x08 null */
if (is_sgx) { /* position after chunk+size */
if (read_32bitBE(0x10,streamHeader) != 0x57415645) goto fail; /* "WAVE" */
chunk_offset = 0x18;
} else {
if (!find_chunk_le(streamHeader, 0x57415645,0x10,0, &chunk_offset,NULL)) goto fail; /* "WAVE" */
}
/* 0x04 SGX: unknown; SGD/SGH: chunk length, 0x08 null */
/* check multi-streams (usually only SE containers; Puppeteer) */
total_streams = read_32bitLE(chunk_offset+0x04,streamHeader);
@ -107,7 +87,7 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
data_size = read_32bitLE(chunk_offset+0x2c,streamHeader); /* stream size (without padding) / interleave (for type3) */
if (is_sgx) {
stream_offset = 0x0; /* TODO unknown (not seen multi SGX) */
stream_offset = 0x0;
} else{
stream_offset = read_32bitLE(chunk_offset+0x30,streamHeader);
}
@ -128,41 +108,53 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
vgmstream->num_streams = total_streams;
vgmstream->meta_type = meta_SGXD;
/* needs -1 to match RIFF AT3's loop chunk
* (maybe SGXD = "loop before this sample" rather than "loop after this sample" as expected by vgmstream) */
if (vgmstream->loop_end_sample > 0)
vgmstream->loop_end_sample -= 1;
switch (type) {
case 0x03: /* PSX ADPCM */
case 0x03: /* PS-ADPCM */
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
if (is_sgx || is_sgb) {
vgmstream->interleave_block_size = 0x10;
} else { //todo this only seems to happen with SFX
} else { /* this only seems to happen with SFX */
vgmstream->interleave_block_size = data_size;
}
break;
#ifdef VGM_USE_FFMPEG
case 0x04: { /* ATRAC3plus */
at3_riff_info info;
ffmpeg_codec_data *ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, data_size);
case 0x04: { /* ATRAC3plus */
ffmpeg_codec_data *ffmpeg_data;
/* internally has a RIFF header; but the SGXD header / sample rate has priority over it (may not match) */
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, data_size);
if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
/* manually fix looping due to FFmpeg bugs */
if (loop_flag && get_at3_riff_info(&info, streamFile, start_offset)) {
if (vgmstream->num_samples == info.fact_samples) { /* use if looks normal */
/* todo use "skip samples"; for now we just use absolute loop values */
vgmstream->loop_start_sample = info.loop_start_sample;
vgmstream->loop_end_sample = info.loop_end_sample;
vgmstream->num_samples += info.skip_samples; /* to ensure it always reaches loop_end */
/* manually read skip_samples if FFmpeg didn't do it */
if (ffmpeg_data->skipSamples <= 0) {
off_t chunk_offset;
size_t chunk_size, fact_skip_samples = 0;
if (!find_chunk_le(streamFile, 0x66616374,start_offset+0xc,0, &chunk_offset,&chunk_size)) /* find "fact" */
goto fail;
if (chunk_size == 0x8) {
fact_skip_samples = read_32bitLE(chunk_offset+0x4, streamFile);
} else if (chunk_size == 0xc) {
fact_skip_samples = read_32bitLE(chunk_offset+0x8, streamFile);
}
ffmpeg_set_skip_samples(ffmpeg_data, fact_skip_samples);
}
/* SGXD loop/sample values are relative (without skip samples) vs RIFF (with skip samples), no need to adjust */
break;
}
#endif
case 0x05: /* Short VAG ADPCM */
case 0x05: /* Short PS-ADPCM */
vgmstream->coding_type = coding_PSX_cfg;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x4;
@ -170,13 +162,23 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
break;
#ifdef VGM_USE_FFMPEG
case 0x06: { /* AC3 */
ffmpeg_codec_data *ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, data_size);
case 0x06: { /* AC3 */
ffmpeg_codec_data *ffmpeg_data;
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, data_size);
if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
/* manually set skip_samples if FFmpeg didn't do it */
if (ffmpeg_data->skipSamples <= 0) {
/* PS3 AC3 consistently has 256 encoder delay samples, and there are ~1000-2000 samples after num_samples.
* Skipping them marginally improves full loops in some Tokyo Jungle tracks (ex. a_1.sgd). */
ffmpeg_set_skip_samples(ffmpeg_data, 256);
}
/* SGXD loop/sample values are relative (without skip samples), no need to adjust */
break;
}
#endif
@ -197,50 +199,3 @@ fail:
close_vgmstream(vgmstream);
return NULL;
}
/**
* AT3 RIFF headers have a "skip samples at the beginning" value that the decoder should use,
* and absolute loop values. However the SGXD header loop values assume those samples are skipped.
*
* FFmpeg doesn't support/export this, so we have to manually get the absolute values to fix looping.
*/
static int get_at3_riff_info(at3_riff_info* info, STREAMFILE *streamFile, int32_t offset) {
off_t chunk_offset;
size_t chunk_size;
memset(info, 0, sizeof(at3_riff_info));
if (read_32bitBE(offset+0x0,streamFile)!=0x52494646 /* "RIFF" */
&& read_32bitBE(offset+0x8,streamFile)!=0x57415645 ) /* "WAVE" */
goto fail;
/*"smpl"*/
if (!find_chunk_le(streamFile, 0x736D706C,offset+0xc,0, &chunk_offset,&chunk_size)) goto fail;
if (read_32bitLE(chunk_offset+0x1C, streamFile)==0
|| read_32bitLE(chunk_offset+0x24+0x4, streamFile)!=0 )
goto fail;
info->loop_start_sample = read_32bitLE(chunk_offset+0x1C+0x8+0x8, streamFile);
info->loop_end_sample = read_32bitLE(chunk_offset+0x1C+0x8+0xc,streamFile);
/*"fact"*/
if (!find_chunk_le(streamFile, 0x66616374,offset+0xc,0, &chunk_offset,&chunk_size)) goto fail;
if (chunk_size == 0x8) {
info->fact_samples = read_32bitLE(chunk_offset+0x0, streamFile);
info->skip_samples = read_32bitLE(chunk_offset+0x4, streamFile);
} else if (chunk_size == 0xc) {
info->fact_samples = read_32bitLE(chunk_offset+0x0, streamFile);
info->skip_samples = read_32bitLE(chunk_offset+0x8, streamFile);
} else {
goto fail;
}
/* found */
return 1;
fail:
/* not found */
return 0;
}

View File

@ -1,6 +1,5 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util.h"
/* Square-Enix SCD (FF XIII, XIV) */
@ -358,7 +357,6 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
int32_t bytes;
/* post_meta_offset+0x00: fmt0x166 header (BE), post_meta_offset+0x34: seek table */
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,200, post_meta_offset,0x34, stream_size, streamFile, 1);
if (bytes <= 0) goto fail;
@ -378,30 +376,33 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
/* ATRAC3plus */ /* Lord of Arcana (PSP) */
{
ffmpeg_codec_data *ffmpeg_data = NULL;
off_t chunk_offset;
size_t chunk_size, fact_sample_skip = 0;
/* full riff header at start_offset/post_meta_offset (same) */
/* full RIFF header at start_offset/post_meta_offset (same) */
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
if (!ffmpeg_data) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = ffmpeg_data->totalSamples;
vgmstream->num_samples = ffmpeg_data->totalSamples; /* fact samples */
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
/* manually find encoder_delay to adjust samples since it's not properly used by FFmpeg */
if (!find_chunk_le(streamFile, 0x66616374,start_offset+0xc,0, &chunk_offset,&chunk_size)) goto fail; /*"fact"*/
if (chunk_size == 0x8) {
fact_sample_skip = read_32bitLE(chunk_offset+0x4, streamFile);
} else if (chunk_size == 0xc) {
fact_sample_skip = read_32bitLE(chunk_offset+0x8, streamFile);
/* manually read skip_samples if FFmpeg didn't do it */
if (ffmpeg_data->skipSamples <= 0) {
off_t chunk_offset;
size_t chunk_size, fact_skip_samples = 0;
if (!find_chunk_le(streamFile, 0x66616374,start_offset+0xc,0, &chunk_offset,&chunk_size)) /* find "fact" */
goto fail;
if (chunk_size == 0x8) {
fact_skip_samples = read_32bitLE(chunk_offset+0x4, streamFile);
} else if (chunk_size == 0xc) {
fact_skip_samples = read_32bitLE(chunk_offset+0x8, streamFile);
}
ffmpeg_set_skip_samples(ffmpeg_data, fact_skip_samples);
}
vgmstream->num_samples += fact_sample_skip;
vgmstream->loop_start_sample += fact_sample_skip;
vgmstream->loop_end_sample += fact_sample_skip;
/* SCD loop/sample values are relative (without skip samples) vs RIFF (with skip samples), no need to adjust */
}
break;

80
src/meta/xau.c Normal file
View File

@ -0,0 +1,80 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
/* XAU - XPEC Entertainment sound format (Beat Down PS2/Xbox, Spectral Force Chronicle [SLPM-65967]) */
VGMSTREAM * init_vgmstream_xau(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, type, loop_start, loop_end;
/* check extension */
if (!check_extensions(streamFile, "xau"))
goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x58415500) /* "XAU\0" "*/
goto fail;
if (read_32bitLE(0x08,streamFile) != 0x40) /* header start */
goto fail;
/* 0x04: version? (0x100) */
type = read_32bitBE(0x0c, streamFile);
loop_start = read_32bitLE(0x10, streamFile);
loop_end = read_32bitLE(0x14, streamFile);
loop_flag = (loop_end > 0);
channel_count = read_8bit(0x18,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->channels = channel_count;
vgmstream->meta_type = meta_XAU;
/* miniheader over a common header with some tweaks, so we'll simplify parsing */
switch(type) {
case 0x50533200: /* "PS2\0" */
if (read_32bitBE(0x40,streamFile) != 0x56414770) goto fail; /* "VAGp" */
start_offset = 0x800;
vgmstream->sample_rate = read_32bitBE(0x50, streamFile);
vgmstream->num_samples = ps_bytes_to_samples(read_32bitBE(0x4C,streamFile) * channel_count, channel_count);
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x8000;
break;
case 0x58420000: /* "XB\0\0" */
if (read_32bitBE(0x40,streamFile) != 0x52494646) goto fail; /* "RIFF" */
start_offset = 0x70;
vgmstream->sample_rate = read_32bitLE(0x58, streamFile);
vgmstream->num_samples = ms_ima_bytes_to_samples(read_32bitLE(0x6c, streamFile), read_16bitLE(0x60, streamFile), channel_count);
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
/* there is also a "smpl" chunk at the end, same as loop_start/end */
vgmstream->coding_type = coding_XBOX;
vgmstream->layout_type = layout_none;
break;
default:
goto fail;
}
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -11,8 +11,8 @@ VGMSTREAM * init_vgmstream_xma(STREAMFILE *streamFile) {
/* check extension, case insensitive */
/* .xma2: Skullgirls, .nps: Beautiful Katamari (renamed .xma) */
if ( !check_extensions(streamFile, "xma,xma2,nps") )
/* .xma2: Skullgirls, .nps: Beautiful Katamari (renamed .xma), .str: Sonic & Sega All Stars Racing */
if ( !check_extensions(streamFile, "xma,xma2,nps,str") )
goto fail;
{

View File

@ -14,7 +14,8 @@
#define XACT2_1_MAX 38 /* Prey (v38) */ // v39 too?
#define XACT2_2_MAX 41 /* Blue Dragon (v40) */
#define XACT3_0_MAX 46 /* Ninja Blade (t43 v42), Persona 4 Ultimax NESSICA (t45 v43) */
#define XACT_TECHLAND 0x10000 /* Sniper Ghost Warrior, Nail'd (PS3/X360) */
#define XACT_TECHLAND 0x10000 /* Sniper Ghost Warrior, Nail'd (PS3/X360), equivalent to XACT3_0 */
#define XACT_CRACKDOWN 0x87 /* Crackdown 1, equivalent to XACT2_2 */
static const int wma_avg_bps_index[7] = {
12000, 24000, 4000, 6000, 8000, 20000, 2500
@ -92,6 +93,10 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* read main header (WAVEBANKHEADER) */
xwb.version = read_32bit(0x04, streamFile); /* XACT3: 0x04=tool version, 0x08=header version */
/* Crackdown 1 X360, essentially XACT2 but may have split header in some cases */
if (xwb.version == XACT_CRACKDOWN)
xwb.version = XACT2_2_MAX;
/* read segment offsets (SEGIDX) */
if (xwb.version <= XACT1_0_MAX) {
xwb.streams = read_32bit(0x0c, streamFile);
@ -306,7 +311,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
xwb.loop_end_sample = msd.loop_end_sample;
// todo fix properly (XWB loop_start/end seem to count padding samples while XMA1 RIFF doesn't)
//this doesn't seem ok because can fall within 0 to 512 (ie.- first frame)
//this doesn't seem ok because can fall within 0 to 512 (ie.- first frame, 384)
//if (xwb.loop_start_sample) xwb.loop_start_sample -= 512;
//if (xwb.loop_end_sample) xwb.loop_end_sample -= 512;
@ -314,6 +319,11 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
// (in rare cases this causes a glitch in FFmpeg since it has a bug where it's missing some samples)
xwb.num_samples += 64 + 512;
}
else if ((xwb.codec == XMA1 || xwb.codec == XMA2) && xwb.loop_flag) {
/* seems to be needed by some edge cases, ex. Crackdown */
//add padding, see above
xwb.num_samples += 64 + 512;
}
/* build the VGMSTREAM */

View File

@ -292,7 +292,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_ps2_lpcm,
init_vgmstream_dsp_bdsp,
init_vgmstream_ps2_vms,
init_vgmstream_ps2_xau,
init_vgmstream_xau,
init_vgmstream_gh3_bar,
init_vgmstream_ffw,
init_vgmstream_dsp_dspw,
@ -360,6 +360,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_rsd6xma,
init_vgmstream_ta_aac_x360,
init_vgmstream_ta_aac_ps3,
init_vgmstream_ps3_mta2,
#ifdef VGM_USE_FFMPEG
init_vgmstream_mp4_aac_ffmpeg,
@ -868,12 +869,31 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
free(vgmstream);
}
/* calculate samples based on player's config */
int32_t get_vgmstream_play_samples(double looptimes, double fadeseconds, double fadedelayseconds, VGMSTREAM * vgmstream) {
if (vgmstream->loop_flag) {
return vgmstream->loop_start_sample+(vgmstream->loop_end_sample-vgmstream->loop_start_sample)*looptimes+(fadedelayseconds+fadeseconds)*vgmstream->sample_rate;
} else return vgmstream->num_samples;
if (fadeseconds < 0) { /* a bit hack-y to avoid signature change */
/* Continue playing the file normally after looping, instead of fading.
* Most files cut abruply after the loop, but some do have proper endings.
* With looptimes = 1 this option should give the same output vs loop disabled */
int loop_count = (int)looptimes; /* no half loops allowed */
vgmstream->loop_target = loop_count;
return vgmstream->loop_start_sample
+ (vgmstream->loop_end_sample - vgmstream->loop_start_sample) * loop_count
+ (vgmstream->num_samples - vgmstream->loop_end_sample);
}
else {
return vgmstream->loop_start_sample
+ (vgmstream->loop_end_sample - vgmstream->loop_start_sample) * looptimes
+ (fadedelayseconds + fadeseconds) * vgmstream->sample_rate;
}
}
else {
return vgmstream->num_samples;
}
}
/* decode data into sample buffer */
void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
switch (vgmstream->layout_type) {
case layout_interleave:
@ -1065,6 +1085,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
return 54;
case coding_MTAF:
return 0x80*2;
case coding_MTA2:
return 0x80*2;
case coding_MC3:
return 10;
case coding_CRI_HCA:
@ -1191,6 +1213,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
case coding_MSADPCM:
case coding_MTAF:
return vgmstream->interleave_block_size;
case coding_MTA2:
return 0x90;
case coding_MC3:
return 4;
default:
@ -1735,6 +1759,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
chan, vgmstream->channels);
}
break;
case coding_MTA2:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_mta2(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
vgmstream->channels, vgmstream->samples_into_block, samples_to_do,
chan);
}
break;
case coding_MC3:
for (chan=0;chan<vgmstream->channels;chan++) {
decode_mc3(vgmstream, &vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
@ -1776,13 +1807,21 @@ int vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, VGMST
return samples_to_do;
}
/* return 1 if we just looped */
/* loop if end sample is reached, and return 1 if we did loop */
int vgmstream_do_loop(VGMSTREAM * vgmstream) {
/*if (vgmstream->loop_flag) return 0;*/
/*if (!vgmstream->loop_flag) return 0;*/
/* is this the loop end? */
/* is this the loop end? = new loop, continue from loop_start_sample */
if (vgmstream->current_sample==vgmstream->loop_end_sample) {
/* disable looping if target count reached and continue normally
* (only needed with the "play stream end after looping N times" option enabled) */
vgmstream->loop_count++;
if (vgmstream->loop_target && vgmstream->loop_target == vgmstream->loop_count) {
vgmstream->loop_flag = 0; /* could be improved but works ok */
return 0;
}
/* against everything I hold sacred, preserve adpcm
* history through loop for certain types */
if (vgmstream->meta_type == meta_DSP_STD ||

View File

@ -134,6 +134,7 @@ typedef enum {
coding_SASSC, /* Activision EXAKT SASSC DPCM */
coding_LSF, /* lsf ADPCM (Fastlane Street Racing iPhone)*/
coding_MTAF, /* Konami MTAF ADPCM (IMA-derived) */
coding_MTA2, /* Konami MTA2 ADPCM */
coding_MC3, /* Paradigm MC3 3-bit ADPCM */
/* others */
@ -548,7 +549,7 @@ typedef enum {
meta_PS2_LPCM, /* Ah! My Goddess */
meta_DSP_BDSP, /* Ah! My Goddess */
meta_PS2_VMS, /* Autobahn Raser - Police Madness */
meta_PS2_XAU, /* Spectral Force Chronicle */
meta_XAU, /* XPEC Entertainment (Beat Down (PS2 Xbox), Spectral Force Chronicle (PS2)) */
meta_GH3_BAR, /* Guitar Hero III Mobile .bar */
meta_FFW, /* Freedom Fighters [NGC] */
meta_DSP_DSPW, /* Sengoku Basara 3 [WII] */
@ -615,6 +616,7 @@ typedef enum {
meta_GTD, /* Knights Contract (X360/PS3), Valhalla Knights 3 (PSV) */
meta_TA_AAC_X360, /* tri-ace AAC (Star Ocean 4, End of Eternity, Infinite Undiscovery) */
meta_TA_AAC_PS3, /* tri-ace AAC (Star Ocean International, Resonance of Fate) */
meta_PS3_MTA2, /* Metal Gear Solid 4 MTA2 */
#ifdef VGM_USE_VORBIS
meta_OGG_VORBIS, /* Ogg Vorbis */
@ -726,8 +728,6 @@ typedef struct {
off_t next_block_offset; /* offset of header of the next block */
int block_count; /* count of "semi" block in total block */
int hit_loop; /* have we seen the loop yet? */
/* loop layout (saved values) */
int32_t loop_sample; /* saved from current_sample, should be loop_start_sample... */
int32_t loop_samples_into_block;/* saved from samples_into_block */
@ -735,6 +735,12 @@ typedef struct {
size_t loop_block_size; /* saved from current_block_size */
off_t loop_next_block_offset; /* saved from next_block_offset */
/* loop internals */
int hit_loop; /* have we seen the loop yet? */
/* counters for "loop + play end of the stream instead of fading" (not used/needed otherwise) */
int loop_count; /* number of complete loops (1=looped once) */
int loop_target; /* max loops before continuing with the stream end */
/* decoder specific */
int codec_endian; /* little/big endian marker; name is left vague but usually means big endian */

View File

@ -36,7 +36,7 @@ void usage(const char * name) {
"Options:\n"
" -o outfile.wav: name of output .wav file, default is dump.wav\n"
" -l loop count: loop count, default 2.0\n"
" -f fade time: fade time (seconds), default 10.0\n"
" -f fade time: fade time (seconds) after N loops, default 10.0\n"
" -d fade delay: fade delay (seconds, default 0.0\n"
" -i: ignore looping information and play the whole stream once\n"
" -p: output to stdout (for piping into another program)\n"
@ -46,11 +46,12 @@ void usage(const char * name) {
" -x: decode and print adxencd command line to encode as ADX\n"
" -g: decode and print oggenc command line to encode as OGG\n"
" -b: decode and print batch variable commands\n"
" -L: append a smpl chunk and create a looping wav\n"
" -L: append a smpl chunk and create a looping wav\n"
" -e: force end-to-end looping\n"
" -E: force end-to-end looping even if file has real loop points\n"
" -r outfile2.wav: output a second time after resetting\n"
" -2 N: only output the Nth (first is 0) set of stereo channels\n"
" -F: don't fade after N loops and play the rest of the stream\n"
,name);
}
@ -73,15 +74,16 @@ int main(int argc, char ** argv) {
int metaonly = 0;
int adxencd = 0;
int oggenc = 0;
int lwav = 0;
int lwav = 0;
int batchvar = 0;
int only_stereo = -1;
double loop_count = 2.0;
double fade_seconds = 10.0;
double fade_delay_seconds = 0.0;
int32_t bytecount;
int fade_ignore = 0;
int32_t bytecount;
while ((opt = getopt(argc, argv, "o:l:f:d:ipPcmxeLEr:gb2:")) != -1) {
while ((opt = getopt(argc, argv, "o:l:f:d:ipPcmxeLEFr:gb2:")) != -1) {
switch (opt) {
case 'o':
outfilename = optarg;
@ -127,14 +129,17 @@ int main(int argc, char ** argv) {
really_force_loop = 1;
break;
case 'L':
lwav = 1;
break;
lwav = 1;
break;
case 'r':
reset_outfilename = optarg;
break;
case '2':
only_stereo = atoi(optarg);
break;
case 'F':
fade_ignore = 1;
break;
default:
usage(argv[0]);
return 1;
@ -263,6 +268,11 @@ int main(int argc, char ** argv) {
return 1;
}
/* signal ignore fade for get_vgmstream_play_samples */
if (loop_count && fade_ignore) {
fade_seconds = -1.0;
}
len = get_vgmstream_play_samples(loop_count,fade_seconds,fade_delay_seconds,s);
if (!play && !adxencd && !oggenc && !batchvar) printf("samples to play: %d (%.4lf seconds)\n",len,(double)len/s->sample_rate);
fade_samples = fade_seconds * s->sample_rate;
@ -273,10 +283,10 @@ int main(int argc, char ** argv) {
} else {
make_wav_header((uint8_t*)buf, len, s->sample_rate, s->channels);
}
if (lwav && s->loop_flag) { // Adding space for smpl chunk at end
if (lwav && s->loop_flag) { // Adding space for smpl chunk at end
bytecount = get_32bitLE((uint8_t*)buf + 4);
put_32bitLE((uint8_t*)buf + 4, bytecount + 0x44);
}
}
fwrite(buf,1,0x2c,outfile);
/* decode forever */
@ -325,9 +335,9 @@ int main(int argc, char ** argv) {
}
}
if (lwav && s->loop_flag) { // Writing smpl chuck
make_smpl_chunk((uint8_t*)buf, s->loop_start_sample, s->loop_end_sample);
fwrite(buf,1,0x44,outfile);
if (lwav && s->loop_flag) { // Writing smpl chuck
make_smpl_chunk((uint8_t*)buf, s->loop_start_sample, s->loop_end_sample);
fwrite(buf,1,0x44,outfile);
}
fclose(outfile); outfile = NULL;