Merge pull request #1559 from bnnm/api-misc2

- Fix some Ongakukan .adp + cleanup
- cleanup
This commit is contained in:
bnnm 2024-07-19 00:05:49 +02:00 committed by GitHub
commit 644da84023
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
35 changed files with 1184 additions and 1220 deletions

View File

@ -21,7 +21,7 @@ The main development repository: https://github.com/vgmstream/vgmstream/
Automated builds with the latest changes: https://vgmstream.org Automated builds with the latest changes: https://vgmstream.org
(https://github.com/vgmstream/vgmstream-releases/releases/tag/nightly) (https://github.com/vgmstream/vgmstream-releases/releases/tag/nightly)
Common releases: https://github.com/vgmstream/vgmstream/releases Numbered releases: https://github.com/vgmstream/vgmstream/releases
Help can be found here: https://www.hcs64.com/ Help can be found here: https://www.hcs64.com/
@ -39,56 +39,54 @@ There are multiple end-user components:
The main library (plain *vgmstream*) is the code that handles the internal conversion, while the The main library (plain *vgmstream*) is the code that handles the internal conversion, while the
above components are what you use to get sound. above components are what you use to get sound.
If you want to convert game audio to `.wav`, try getting *vgmstream-cli* (see below) then ### Usage
drag-and-drop one or more files to the executable (support may vary per O.S. or distro). If you want to convert game audio to `.wav`, get *vgmstream-cli* then drag-and-drop one
This should create `(file.extension).wav`, if the format is supported. More user-friendly or more files to the executable (support may vary per O.S. or distro). This should create
would be installing a player like *foobar2000* (for Windows) or *Audacious* (for Linux) `(file.extension).wav`, if the format is supported. You can also try the online web player
and the vgmstream plugin. Then you can directly listen your files and set options like infinite instead. See: https://vgmstream.org
looping, or convert to `.wav` with the player's options (also easier if your file has multiple
"subsongs"). More user-friendly would be installing a player like *foobar2000* (on Windows) or *Audacious*
(on Linux) and the vgmstream plugin. Then you can directly listen your files and set options like
infinite looping, or convert to `.wav` with the player's options (also easier to use if your file
has multiple "subsongs").
See [components](doc/USAGE.md#components) in the *usage guide* for full install instructions and See [components](doc/USAGE.md#components) in the *usage guide* for full install instructions and
explanations. The aim is feature parity, but there are a few differences between them due to explanations. The aim is feature parity, but there are a few differences between them due to
missing parts on vgmstream's side or lack of support in the player. missing parts on vgmstream's side or lack of support in the player.
Note that vgmstream cannot *encode* (convert from `.wav` to a video game format), it only *decodes* Note that vgmstream cannot *encode* (convert from `.wav` to a game format), it only *decodes*
(plays game audio). (plays game audio).
### Windows binaries
### Windows Prebuilt binaries:
Get the latest prebuilt binaries (CLI/plugins/etc) on our website: - https://vgmstream.org (latest)
- https://vgmstream.org - https://github.com/vgmstream/vgmstream/releases (infrequent numbered releases)
Or the less frequent "official" releases on GitHub:
- https://github.com/vgmstream/vgmstream/releases
The foobar2000 component is also available on https://www.foobar2000.org based on current The foobar2000 component is also available on https://www.foobar2000.org based on current
release. release.
If the above links fail, you may also try the alternative versions built by You may also try the alternative versions (irregularly) built by [bnnm](https://github.com/bnnm):
[bnnm](https://github.com/bnnm):
- https://github.com/bnnm/vgmstream-builds/raw/master/bin/vgmstream-latest-test-u.zip - https://github.com/bnnm/vgmstream-builds/raw/master/bin/vgmstream-latest-test-u.zip
You may compile from source as well, see the [build guide](doc/BUILD.md). Or compile from source, see the [build guide](doc/BUILD.md).
### Linux ### Linux binaries
A prebuilt CLI binary is available. It's statically linked and should work on systems running A prebuilt CLI binary is available. It's statically linked and should work on systems running
Linux kernel v3.2 and above: Linux kernel v3.2 and above:
- https://vgmstream.org - https://vgmstream.org (latest)
- https://github.com/vgmstream/vgmstream/releases - https://github.com/vgmstream/vgmstream/releases (infrequent numbered releases)
Building from source will also give you *vgmstream.so* (Audacious plugin), and *vgmstream123* Building from source will also give you *vgmstream.so* (Audacious plugin), and *vgmstream123*
(command-line player). (command-line player), which can't be statically linked.
When building, many extra components have to be installed or compiled separately, which the When building it needs several external libraries. For a quick script for Debian and Ubuntu-style
[build guide](doc/BUILD.md) describes in detail. For a quick build on Debian and Ubuntu-style distros run `./make-build-cmake.sh`. The script will need to install dependencies first, so you
distributions run `./make-build-cmake.sh`. The script will need to install various dependencies, may prefer to run steps manually, which the [build guide](doc/BUILD.md) describes in detail.
so you may prefer to copy commands and run them manually.
### macOS ### macOS binaries
A prebuilt CLI binary is available as well: A prebuilt CLI binary is available:
- https://vgmstream.org - https://vgmstream.org (latest)
- https://github.com/vgmstream/vgmstream/releases - https://github.com/vgmstream/vgmstream/releases (infrequent numbered releases)
Otherwise follow the [build guide](doc/BUILD.md). Otherwise follow the [build guide](doc/BUILD.md).

View File

@ -268,8 +268,7 @@ static void test_libsf_size(libvgmstream_streamfile_t* libsf) {
static void test_libsf_name(libvgmstream_streamfile_t* libsf) { static void test_libsf_name(libvgmstream_streamfile_t* libsf) {
VGM_STEP(); VGM_STEP();
char name[128]; const char* name = libsf->get_name(libsf->user_data);
libsf->get_name(libsf->user_data, name, sizeof(name));
assert(strcmp(name, "api.bin") == 0); assert(strcmp(name, "api.bin") == 0);
} }

View File

@ -103,7 +103,7 @@ different internally (encrypted, different versions, etc) and not always can be
- Kuju London .KWA header [*DSP_KWA*] - Kuju London .KWA header [*DSP_KWA*]
- Koei Tecmo APEX header [*DSP_APEX*] - Koei Tecmo APEX header [*DSP_APEX*]
- Rebellion DSP header [*DSP_ASURA*] - Rebellion DSP header [*DSP_ASURA*]
- *ngc_dsp_std*: `.dsp .adp .(extensionless) .wav .lwav .dat .ldat` - *ngc_dsp_std*: `.dsp .adp .(extensionless) .wav .lwav .dat .ldat .rsm`
- *ngc_dsp_std_le*: `.adpcm` - *ngc_dsp_std_le*: `.adpcm`
- *ngc_mdsp_std*: `.dsp .mdsp` - *ngc_mdsp_std*: `.dsp .mdsp`
- *ngc_dsp_stm*: `.stm .lstm .dsp` - *ngc_dsp_stm*: `.stm .lstm .dsp`
@ -193,6 +193,7 @@ different internally (encrypted, different versions, etc) and not always can be
- *vag*: `.vag .swag .str .vig .l .r .vas .xa2 .snd .svg .(extensionless) .wav .lwav` - *vag*: `.vag .swag .str .vig .l .r .vas .xa2 .snd .svg .(extensionless) .wav .lwav`
- *vag_aaap*: `.vag` - *vag_aaap*: `.vag`
- *vag_footer*: `.(extensionless) .vag` - *vag_footer*: `.(extensionless) .vag`
- *vag_evolution_games*: `.vag`
- Codecs: PSX HEVAG - Codecs: PSX HEVAG
- **ild.c** - **ild.c**
- Tose ILD header [*ILD*] - Tose ILD header [*ILD*]
@ -202,27 +203,17 @@ different internally (encrypted, different versions, etc) and not always can be
- Cauldron .STR header [*DSP_STR*] - Cauldron .STR header [*DSP_STR*]
- *ngc_str*: `.str` - *ngc_str*: `.str`
- Codecs: NGC_DSP - Codecs: NGC_DSP
- **ea_schl.c** - **ea_schl_standard.c**
- Electronic Arts BNK header [*EA_BNK*] - (container)
- Electronic Arts SCHl header [*EA_SCHL*]
- *ea_schl*: `.asf .lasf .str .chk .eam .exa .sng .aud .sx .xa .strm .stm .hab .xsf .gsf .(extensionless) .r` - *ea_schl*: `.asf .lasf .str .chk .eam .exa .sng .aud .sx .xa .strm .stm .hab .xsf .gsf .(extensionless) .r`
- *ea_schl_video*: `.uv .dct .mad .wve .vp6 .mpc .lmpc`
- *ea_bnk*: `.bnk .sdt .hdt .ldt .abk .ast .cat .(extensionless)` - *ea_bnk*: `.bnk .sdt .hdt .ldt .abk .ast .cat .(extensionless)`
- *ea_abk*: `.abk + .ast` - *ea_schl_video*: `.uv .dct .mpc .lmpc .vp6 .mad .wve`
- *ea_hdr_dat*: `.hdr + .dat`
- Subfiles: *vag*
- *ea_hdr_dat_v2*: `.hdr + .dat .mus .(external)`
- *ea_map_mus*: `.map .lin .mpf`
- *ea_mpf_mus*: `.mpf`
- *ea_msb_mus*: `.msb .msx`
- *ea_mpf_mus_main*: `(base) + .(external)`
- Codecs: EA_XA EA_XA_int EA_XA_V2 PCM8_int PCM16_int PCM8 PCM16LE PCM16BE PSX XBOX_IMA_int NGC_DSP VADPCM MPEG EA_MT ATRAC3
- **caf.c** - **caf.c**
- tri-Crescendo CAF Header [*CAF*] - tri-Crescendo CAF header [*CAF*]
- *caf*: `.caf .cfn .(extensionless)` - *caf*: `.caf .cfn .(extensionless)`
- Codecs: NGC_DSP - Codecs: NGC_DSP
- **vpk.c** - **vpk.c**
- SCE America VPK Header [*VPK*] - SCE America VPK header [*VPK*]
- *vpk*: `.vpk` - *vpk*: `.vpk`
- Codecs: PSX - Codecs: PSX
- **ogg_vorbis.c** - **ogg_vorbis.c**
@ -249,7 +240,7 @@ different internally (encrypted, different versions, etc) and not always can be
- **aifc.c** - **aifc.c**
- Apple AIFF-C header [*AIFC*] - Apple AIFF-C header [*AIFC*]
- Apple AIFF header [*AIFF*] - Apple AIFF header [*AIFF*]
- *aifc*: `.aif .laif .wav .lwav .aiff .laiff .(extensionless) .aifc .laifc .afc .cbd2 .bgm .fda .n64 .xa .caf .acm .adp .ai .pcm` - *aifc*: `.aif .laif .wav .lwav .aiff .laiff .(extensionless) .aifc .laifc .afc .cbd2 .bgm .fda .n64 .xa .caf .acm .adp .ai .pcm .vp6 .mpc .lmpc`
- Codecs: SDX2 CBD2 DVI_IMA_int APPLE_IMA4 RELIC VADPCM PCM8 PCM16BE XA - Codecs: SDX2 CBD2 DVI_IMA_int APPLE_IMA4 RELIC VADPCM PCM8 PCM16BE XA
- **str_snds.c** - **str_snds.c**
- 3DO SNDS header [*STR_SNDS*] - 3DO SNDS header [*STR_SNDS*]
@ -263,9 +254,9 @@ different internally (encrypted, different versions, etc) and not always can be
- CRI AHX header [*AHX*] - CRI AHX header [*AHX*]
- *ahx*: `.ahx` - *ahx*: `.ahx`
- Codecs: MPEG - Codecs: MPEG
- **ivb.c** - **iivb.c**
- IVB/BVII header [*PS2_IVB*] - Vingt-et-un IIVB header [*IIVB*]
- *ivb*: `.ivb` - *iivb*: `.ivb`
- Codecs: PSX - Codecs: PSX
- **svs.c** - **svs.c**
- Square SVS header [*SVS*] - Square SVS header [*SVS*]
@ -281,7 +272,7 @@ different internally (encrypted, different versions, etc) and not always can be
- RIFX WAVE header (smpl looping) [*RIFX_WAVE_smpl*] - RIFX WAVE header (smpl looping) [*RIFX_WAVE_smpl*]
- *riff*: `.wav .lwav .xwav .mwv .da .dax .cd .med .snd .adx .adp .xss .xsew .adpcm .adw .wd .(extensionless) .sbv .wvx .str .at3 .rws .aud .at9 .ckd .saf .ima .nsa .pcm .xvag .ogg .logg .p1d .xms .mus .dat .ldat .wma .lwma .caf .wax .voi .se` - *riff*: `.wav .lwav .xwav .mwv .da .dax .cd .med .snd .adx .adp .xss .xsew .adpcm .adw .wd .(extensionless) .sbv .wvx .str .at3 .rws .aud .at9 .ckd .saf .ima .nsa .pcm .xvag .ogg .logg .p1d .xms .mus .dat .ldat .wma .lwma .caf .wax .voi .se`
- *rifx*: `.wav .lwav` - *rifx*: `.wav .lwav`
- Codecs: AICA_int PCM32LE PCM24LE PCM16BE PCM16LE PCM8_U MSADPCM IMA PCMFLOAT MS_IMA AICA MPEG_custom XBOX_IMA MS_IMA_3BIT DVI_IMA L5_555 OGG_VORBIS ATRAC9 ATRAC3 MPEG MSADPCM_int - Codecs: AICA_int PCM32LE PCM24LE PCM16BE PCM16LE PCM8_U MSADPCM IMA PCMFLOAT MS_IMA AICA MPEG_custom XBOX_IMA MS_IMA_3BIT DVI_IMA L5_555 OGG_VORBIS ATRAC9 ATRAC3 MPEG MSADPCM_mono
- **nwa.c** - **nwa.c**
- VisualArt's NWA header (NWAINFO.INI looping) [*NWA_NWAINFOINI*] - VisualArt's NWA header (NWAINFO.INI looping) [*NWA_NWAINFOINI*]
- VisualArt's NWA header (Gameexe.ini looping) [*NWA_GAMEEXEINI*] - VisualArt's NWA header (Gameexe.ini looping) [*NWA_GAMEEXEINI*]
@ -307,7 +298,7 @@ different internally (encrypted, different versions, etc) and not always can be
- *hgc1*: `.str` - *hgc1*: `.str`
- Codecs: PSX - Codecs: PSX
- **aus.c** - **aus.c**
- Capcom AUS Header [*AUS*] - Atomic Planet AUS header [*AUS*]
- *aus*: `.aus` - *aus*: `.aus`
- Codecs: XBOX_IMA PSX - Codecs: XBOX_IMA PSX
- **rws_80d.c** - **rws_80d.c**
@ -320,9 +311,7 @@ different internally (encrypted, different versions, etc) and not always can be
- FMOD FSB3 header [*FSB3*] - FMOD FSB3 header [*FSB3*]
- FMOD FSB4 header [*FSB4*] - FMOD FSB4 header [*FSB4*]
- *fsb*: `.fsb .bnk .sfx .ps3 .xen` - *fsb*: `.fsb .bnk .sfx .ps3 .xen`
- *fsb4_wav*: `.fsb .wii` - Codecs: MPEG FSB_IMA XBOX_IMA PSX XMA1 XMA2 NGC_DSP NGC_DSP_subint CELT_FSB PCM8_U PCM8 PCM16BE PCM16LE
- Subfiles: *fsb*
- Codecs: MPEG XBOX_IMA FSB_IMA PSX XMA1 XMA2 NGC_DSP NGC_DSP_subint CELT_FSB PCM8_U PCM8 PCM16BE PCM16LE
- **fsb5.c** - **fsb5.c**
- FMOD FSB5 header [*FSB5*] - FMOD FSB5 header [*FSB5*]
- *fsb5*: `.fsb .snd` - *fsb5*: `.fsb .snd`
@ -349,7 +338,7 @@ different internally (encrypted, different versions, etc) and not always can be
- *musx*: `.sfx .musx` - *musx*: `.sfx .musx`
- Codecs: PSX DAT4_IMA DVI_IMA_int XBOX_IMA NGC_DSP PCM16BE PCM16LE - Codecs: PSX DAT4_IMA DVI_IMA_int XBOX_IMA NGC_DSP PCM16BE PCM16LE
- **filp.c** - **filp.c**
- cavia FILp Header [*FILP*] - cavia FILp header [*FILP*]
- *filp*: `.fil` - *filp*: `.fil`
- Codecs: PSX - Codecs: PSX
- **ikm.c** - **ikm.c**
@ -377,11 +366,11 @@ different internally (encrypted, different versions, etc) and not always can be
- *dc_kcey*: `.pcm .kcey` - *dc_kcey*: `.pcm .kcey`
- Codecs: DVI_IMA - Codecs: DVI_IMA
- **rstm_rockstar.c** - **rstm_rockstar.c**
- Rockstar Games RSTM Header [*RSTM_ROCKSTAR*] - Rockstar Games RSTM header [*RSTM_ROCKSTAR*]
- *rstm_rockstar*: `.rsm .rstm` - *rstm_rockstar*: `.rsm .rstm`
- Codecs: PSX - Codecs: PSX
- **acm.c** - **acm.c**
- InterPlay ACM Header [*ACM*] - InterPlay ACM header [*ACM*]
- *acm*: `.acm .tun .wavc` - *acm*: `.acm .tun .wavc`
- Codecs: ACM - Codecs: ACM
- **mus_acm.c** - **mus_acm.c**
@ -389,11 +378,11 @@ different internally (encrypted, different versions, etc) and not always can be
- *mus_acm*: `.mus` - *mus_acm*: `.mus`
- Subfiles: *acm ogg_vorbis* - Subfiles: *acm ogg_vorbis*
- **vig_kces.c** - **vig_kces.c**
- Konami .VIG Header [*VIG_KCES*] - Konami .VIG header [*VIG_KCES*]
- *vig_kces*: `.vig` - *vig_kces*: `.vig`
- Codecs: PSX - Codecs: PSX
- **hxd.c** - **hxd.c**
- Tecmo HXD Header [*HXD*] - Tecmo HXD header [*HXD*]
- *hxd*: `.hxd + .bd .str .at3` - *hxd*: `.hxd + .bd .str .at3`
- Codecs: PSX - Codecs: PSX
- **vsv.c** - **vsv.c**
@ -466,11 +455,11 @@ different internally (encrypted, different versions, etc) and not always can be
- *kraw*: `.kraw` - *kraw*: `.kraw`
- Codecs: PCM16BE - Codecs: PCM16BE
- **omu.c** - **omu.c**
- Outrage OMU Header [*OMU*] - Outrage OMU header [*OMU*]
- *omu*: `.omu` - *omu*: `.omu`
- Codecs: PCM16LE - Codecs: PCM16LE
- **xa2_acclaim.c** - **xa2_acclaim.c**
- Acclaim .XA2 Header [*XA2_ACCLAIM*] - Acclaim .XA2 header [*XA2_ACCLAIM*]
- *xa2_acclaim*: `.xa2` - *xa2_acclaim*: `.xa2`
- Codecs: PSX - Codecs: PSX
- **idsp_ie.c** - **idsp_ie.c**
@ -642,7 +631,7 @@ different internally (encrypted, different versions, etc) and not always can be
- **ads_midway.c** - **ads_midway.c**
- Midway ADS header [*ADS_MIDWAY*] - Midway ADS header [*ADS_MIDWAY*]
- *ads_midway*: `.ads` - *ads_midway*: `.ads`
- Codecs: NGC_DSP XBOX_IMA_int - Codecs: NGC_DSP XBOX_IMA_mono
- **ps2_mcg.c** - **ps2_mcg.c**
- Gunvari MCG Header [*PS2_MCG*] - Gunvari MCG Header [*PS2_MCG*]
- *ps2_mcg*: `.mcg` - *ps2_mcg*: `.mcg`
@ -1075,6 +1064,22 @@ different internally (encrypted, different versions, etc) and not always can be
- Reflections 04SW header [*XA_04SW*] - Reflections 04SW header [*XA_04SW*]
- *xa_04sw*: `.xa` - *xa_04sw*: `.xa`
- Codecs: NGC_DSP - Codecs: NGC_DSP
- **ea_schl_abk.c**
- (container)
- *ea_abk_schl*: `.abk`
- *ea_amb_schl*: `.amb .amx`
- *ea_abk_schl_main*: `(base) + .ast`
- **ea_schl_hdr_dat.c**
- (container)
- *ea_hdr_dat*: `.hdr + .dat`
- Subfiles: *vag*
- *ea_hdr_dat_v2*: `.hdr + .dat`
- **ea_schl_map_mpf_mus.c**
- (container)
- *ea_map_mus*: `.map .lin .mpf`
- *ea_mpf_mus_schl*: `.mpf`
- *ea_msb_mus_schl*: `.msb .msx`
- *ea_mpf_mus_schl_main*: `(base) + .(external) .mus`
- **ea_schl_fixed.c** - **ea_schl_fixed.c**
- Electronic Arts SCHl header (fixed) [*EA_SCHL_fixed*] - Electronic Arts SCHl header (fixed) [*EA_SCHL_fixed*]
- *ea_schl_fixed*: `.asf .lasf .cnk` - *ea_schl_fixed*: `.asf .lasf .cnk`
@ -1148,7 +1153,9 @@ different internally (encrypted, different versions, etc) and not always can be
- Codecs: PCM16LE MSADPCM MS_IMA FFmpeg(various) - Codecs: PCM16LE MSADPCM MS_IMA FFmpeg(various)
- **ea_eaac_abk.c** - **ea_eaac_abk.c**
- Electronic Arts SNR+SNS header [*EA_SNR_SNS*] - Electronic Arts SNR+SNS header [*EA_SNR_SNS*]
- *ea_abk_eaac*: `.abk + .ast` - *ea_abk_eaac*: `.abk`
- *ea_amb_eaac*: `.amb .amx`
- *ea_abk_eaac_main*: `(base) + .ast`
- **ea_eaac_hdr_sth_dat.c** - **ea_eaac_hdr_sth_dat.c**
- Electronic Arts SNR+SNS header [*EA_SNR_SNS*] - Electronic Arts SNR+SNS header [*EA_SNR_SNS*]
- *ea_hdr_sth_dat*: `.hdr + .sth .dat` - *ea_hdr_sth_dat*: `.hdr + .sth .dat`
@ -1242,7 +1249,7 @@ different internally (encrypted, different versions, etc) and not always can be
- **sthd.c** - **sthd.c**
- Dream Factory STHD header [*STHD*] - Dream Factory STHD header [*STHD*]
- *sthd*: `.stx` - *sthd*: `.stx`
- Codecs: PCM16LE XBOX_IMA_int - Codecs: PCM16LE XBOX_IMA_mono
- **pcm_sre.c** - **pcm_sre.c**
- Capcom .PCM+SRE header [*PCM_SRE*] - Capcom .PCM+SRE header [*PCM_SRE*]
- *pcm_sre*: `.pcm + .sre` - *pcm_sre*: `.pcm + .sre`
@ -1621,7 +1628,7 @@ different internally (encrypted, different versions, etc) and not always can be
- *asrs*: `.srsa` - *asrs*: `.srsa`
- *ktsr_internal* - *ktsr_internal*
- Subfiles: *riff ogg_vorbis ktss ktac* - Subfiles: *riff ogg_vorbis ktss ktac*
- Codecs: MSADPCM_int NGC_DSP ATRAC9 - Codecs: MSADPCM_mono NGC_DSP ATRAC9
- **mups.c** - **mups.c**
- (container) - (container)
- *mups*: `.mups .(extensionless)` - *mups*: `.mups .(extensionless)`
@ -1833,6 +1840,10 @@ different internally (encrypted, different versions, etc) and not always can be
- Rebellion DSP header [*DSP_ASURA*] - Rebellion DSP header [*DSP_ASURA*]
- *dsp_asura_sfx*: `.sfx` - *dsp_asura_sfx*: `.sfx`
- Codecs: NGC_DSP - Codecs: NGC_DSP
- **adp_ongakukan.c**
- Ongakukan RIFF WAVE header [*ONGAKUKAN_RIFF_ADP*]
- *adp_ongakukan*: `.adp`
- Codecs: ONGAKUKAN_ADPCM
- **agsc.c** - **agsc.c**
- Retro Studios AGSC header [*AGSC*] - Retro Studios AGSC header [*AGSC*]
- *agsc*: `.agsc` - *agsc*: `.agsc`
@ -1957,6 +1968,10 @@ different internally (encrypted, different versions, etc) and not always can be
- Electronic Arts SPS header [*EA_SPS*] - Electronic Arts SPS header [*EA_SPS*]
- *eaaudiocore_main*: `(base) + .sns` - *eaaudiocore_main*: `(base) + .sns`
- Codecs: PCM16_int EA_XAS_V1 MPEG NGC_DSP SPEEX ATRAC9 Opus XMA1 XMA2 - Codecs: PCM16_int EA_XAS_V1 MPEG NGC_DSP SPEEX ATRAC9 Opus XMA1 XMA2
- **ea_schl.c**
- Electronic Arts BNK header [*EA_BNK*]
- Electronic Arts SCHl header [*EA_SCHL*]
- Codecs: EA_XA EA_XA_int EA_XA_V2 PCM8_int PCM16_int PCM8 PCM16LE PCM16BE PSX XBOX_IMA_mono NGC_DSP VADPCM MPEG EA_MT ATRAC3
## Supported extras ## Supported extras
Reminder of some extra formats and helper files vgmstream supports. They are described Reminder of some extra formats and helper files vgmstream supports. They are described

View File

@ -2,13 +2,15 @@
# main vgmstream code # main vgmstream code
# #
# automatically get all possible .o by finding all .c
OBJECTS =
#SRCS = $(wildcard **/*.c) #GNUMake 3.81? #SRCS = $(wildcard **/*.c) #GNUMake 3.81?
SRCS = $(wildcard *.c) $(wildcard */*.c) $(wildcard */*/*.c) SRCS = $(wildcard *.c) $(wildcard */*.c) $(wildcard */*/*.c)
# get all possible .o by finding all .c
OBJECTS = $(patsubst %.c,%.o,$(SRCS)) OBJECTS = $(patsubst %.c,%.o,$(SRCS))
# in case of renamed files
OBJECTS_CLEAN = $(wildcard *.o) $(wildcard */*.o) $(wildcard */*/*.o)
libvgmstream.a: $(OBJECTS) libvgmstream.a: $(OBJECTS)
$(AR) crs libvgmstream.a $(OBJECTS) $(AR) crs libvgmstream.a $(OBJECTS)
@ -20,6 +22,6 @@ libvgmstream.so: $(OBJECTS)
# $(CC) $(CFLAGS) -M -o vgmstream-deps # $(CC) $(CFLAGS) -M -o vgmstream-deps
clean: clean:
$(RMF) $(OBJECTS) libvgmstream.a $(RMF) $(OBJECTS_CLEAN) libvgmstream.a
.PHONY: clean .PHONY: clean

View File

@ -42,9 +42,9 @@ typedef struct libvgmstream_streamfile_t {
*/ */
int64_t (*get_size)(void* user_data); int64_t (*get_size)(void* user_data);
/* copy current filename to name buf /* get current filename
*/ */
void (*get_name)(void* user_data, char* name, int name_size); //TODO return char*? const char* (*get_name)(void* user_data);
/* open another streamfile from filename (may be some path/protocol, or same as current get_name = reopen) /* open another streamfile from filename (may be some path/protocol, or same as current get_name = reopen)
* - vgmstream mainly opens stuff based on current get_name (relative), so there shouldn't be need to transform this path * - vgmstream mainly opens stuff based on current get_name (relative), so there shouldn't be need to transform this path

View File

@ -9,6 +9,7 @@ typedef struct {
int64_t offset; int64_t offset;
int64_t size; int64_t size;
STREAMFILE* inner_sf; STREAMFILE* inner_sf;
char name[PATH_LIMIT];
} libsf_data_t; } libsf_data_t;
static int libsf_read(void* user_data, uint8_t* dst, int dst_size) { static int libsf_read(void* user_data, uint8_t* dst, int dst_size) {
@ -58,16 +59,16 @@ static int64_t libsf_get_size(void* user_data) {
return data->size; return data->size;
} }
static void libsf_get_name(void* user_data, char* name, int name_size) { static const char* libsf_get_name(void* user_data) {
if (!name || !name_size)
return;
name[0] = '\0';
libsf_data_t* data = user_data; libsf_data_t* data = user_data;
if (!data) if (!data)
return; return NULL;
data->inner_sf->get_name(data->inner_sf, name, name_size); /* default */ if (data->name[0] == '\0') {
data->inner_sf->get_name(data->inner_sf, data->name, sizeof(data->name));
}
return data->name;
} }
struct libvgmstream_streamfile_t* libsf_open(void* user_data, const char* filename) { struct libvgmstream_streamfile_t* libsf_open(void* user_data, const char* filename) {

View File

@ -33,7 +33,16 @@ static offv_t api_get_offset(API_STREAMFILE* sf) {
static void api_get_name(API_STREAMFILE* sf, char* name, size_t name_size) { static void api_get_name(API_STREAMFILE* sf, char* name, size_t name_size) {
void* user_data = sf->libsf->user_data; void* user_data = sf->libsf->user_data;
sf->libsf->get_name(user_data, name, name_size); if (!name || !name_size)
return;
name[0] = '\0';
const char* external_name = sf->libsf->get_name(user_data);
if (!external_name)
return;
snprintf(name, name_size, "%s", external_name);
name[name_size - 1] = '\0';
} }
static STREAMFILE* api_open(API_STREAMFILE* sf, const char* filename, size_t buf_size) { static STREAMFILE* api_open(API_STREAMFILE* sf, const char* filename, size_t buf_size) {

View File

@ -49,7 +49,7 @@ struct ongakukan_adp_t
/* filter table consisting of 16 numbers each. */ /* filter table consisting of 16 numbers each. */
const short int ongakukan_adpcm_filter[16] = { 233, 549, 453, 375, 310, 233, 233, 233, 233, 233, 233, 233, 310, 375, 453, 549 }; static const short int ongakukan_adpcm_filter[16] = { 233, 549, 453, 375, 310, 233, 233, 233, 233, 233, 233, 233, 310, 375, 453, 549 };
/* streamfile read function declararion, more may be added in the future. */ /* streamfile read function declararion, more may be added in the future. */
@ -63,13 +63,15 @@ static void decode_ongakukan_adpcm_samples(ongakukan_adp_t* handle);
/* codec management functions, meant to oversee and supervise ADP data from the top-down. /* codec management functions, meant to oversee and supervise ADP data from the top-down.
* in layman terms, they control how ADP data should be handled and when. */ * in layman terms, they control how ADP data should be handled and when. */
ongakukan_adp_t* init_ongakukan_adpcm(STREAMFILE* sf, long int data_offset, long int data_size, ongakukan_adp_t* ongakukan_adpcm_init(STREAMFILE* sf, long int data_offset, long int data_size, bool sound_is_adpcm)
bool sound_is_adpcm)
{ {
ongakukan_adp_t* handle = NULL; ongakukan_adp_t* handle = NULL;
/* allocate handle using malloc. */ if (!sound_is_adpcm)
handle = malloc(sizeof(ongakukan_adp_t)); return NULL;
/* allocate handle. */
handle = calloc(1, sizeof(ongakukan_adp_t));
if (!handle) goto fail; if (!handle) goto fail;
/* now, to set up the rest of the handle with the data we have... */ /* now, to set up the rest of the handle with the data we have... */
@ -134,16 +136,16 @@ void ongakukan_adpcm_seek(ongakukan_adp_t* handle, long int target_sample)
* seek_ongakukan_adpcm_pos in its current state is a bit more involved than the above, but works. */ * seek_ongakukan_adpcm_pos in its current state is a bit more involved than the above, but works. */
} }
long int get_num_samples_from_ongakukan_adpcm(ongakukan_adp_t* handle) long int ongakukan_adpcm_get_num_samples(ongakukan_adp_t* handle)
{ {
if (!handle) return 0; if (!handle) return 0;
return handle->sample_work; return handle->sample_work;
} }
void* get_sample_hist_from_ongakukan_adpcm(ongakukan_adp_t* handle) short* ongakukan_adpcm_get_sample_hist(ongakukan_adp_t* handle)
{ {
if (!handle) return 0; if (!handle) return 0;
return &handle->sample_hist; return handle->sample_hist;
} }
/* function definitions for the inner workings of codec data. */ /* function definitions for the inner workings of codec data. */
@ -163,7 +165,7 @@ static bool set_up_sample_startpoint(ongakukan_adp_t* handle)
return true; return true;
} }
void decode_ongakukan_adpcm_data(ongakukan_adp_t* handle) void ongakukan_adpcm_decode_data(ongakukan_adp_t* handle)
{ {
/* set samples_filled to 0 and have our decoder go through every sample that exists in the sound data.*/ /* set samples_filled to 0 and have our decoder go through every sample that exists in the sound data.*/
decode_ongakukan_adpcm_samples(handle); decode_ongakukan_adpcm_samples(handle);

View File

@ -9,7 +9,7 @@
typedef struct ongakukan_adp_t ongakukan_adp_t; typedef struct ongakukan_adp_t ongakukan_adp_t;
/* function declaration for we need to set up the codec data. */ /* function declaration for we need to set up the codec data. */
ongakukan_adp_t* init_ongakukan_adpcm(STREAMFILE* sf, long int data_offset, long int data_size, ongakukan_adp_t* ongakukan_adpcm_init(STREAMFILE* sf, long int data_offset, long int data_size,
bool sound_is_adpcm); bool sound_is_adpcm);
/* function declaration for freeing all memory related to ongakukan_adp_t struct var. */ /* function declaration for freeing all memory related to ongakukan_adp_t struct var. */
@ -18,10 +18,10 @@ void ongakukan_adpcm_reset(ongakukan_adp_t* handle);
void ongakukan_adpcm_seek(ongakukan_adp_t* handle, long int target_sample); void ongakukan_adpcm_seek(ongakukan_adp_t* handle, long int target_sample);
/* function declaration for when we need to get (and send) certain values from ongakukan_adp_t handle */ /* function declaration for when we need to get (and send) certain values from ongakukan_adp_t handle */
long int get_num_samples_from_ongakukan_adpcm(ongakukan_adp_t* handle); long int ongakukan_adpcm_get_num_samples(ongakukan_adp_t* handle);
void* get_sample_hist_from_ongakukan_adpcm(ongakukan_adp_t* handle); short* ongakukan_adpcm_get_sample_hist(ongakukan_adp_t* handle);
/* function declaration for actually decoding samples, can't be that hard, right? */ /* function declaration for actually decoding samples, can't be that hard, right? */
void decode_ongakukan_adpcm_data(ongakukan_adp_t* handle); void ongakukan_adpcm_decode_data(ongakukan_adp_t* handle);
#endif // _ONGAKUKAN_ADP_LIB_H_ #endif

View File

@ -2,8 +2,7 @@
#include "coding.h" #include "coding.h"
#include "libs/ongakukan_adp_lib.h" #include "libs/ongakukan_adp_lib.h"
struct ongakukan_adp_data struct ongakukan_adp_data {
{
void* handle; void* handle;
int16_t* samples; int16_t* samples;
int32_t samples_done; int32_t samples_done;
@ -12,9 +11,7 @@ struct ongakukan_adp_data
STREAMFILE* sf; STREAMFILE* sf;
}; };
ongakukan_adp_data* init_ongakukan_adp(STREAMFILE* sf, int32_t data_offset, int32_t data_size, ongakukan_adp_data* init_ongakukan_adp(STREAMFILE* sf, int32_t data_offset, int32_t data_size, bool sound_is_adpcm) {
bool sound_is_adpcm)
{
ongakukan_adp_data* data = NULL; ongakukan_adp_data* data = NULL;
data = calloc(1, sizeof(ongakukan_adp_data)); data = calloc(1, sizeof(ongakukan_adp_data));
@ -23,8 +20,8 @@ ongakukan_adp_data* init_ongakukan_adp(STREAMFILE* sf, int32_t data_offset, int3
/* reopen STREAMFILE from here, then pass it as an argument for our init function. */ /* reopen STREAMFILE from here, then pass it as an argument for our init function. */
data->sf = reopen_streamfile(sf, 0); data->sf = reopen_streamfile(sf, 0);
if (!data->sf) goto fail; if (!data->sf) goto fail;
data->handle = init_ongakukan_adpcm(data->sf, (long int)(data_offset), (long int)(data_size),
sound_is_adpcm); data->handle = ongakukan_adpcm_init(data->sf, (long int)(data_offset), (long int)(data_size), sound_is_adpcm);
if (!data->handle) goto fail; if (!data->handle) goto fail;
return data; return data;
@ -33,57 +30,47 @@ fail:
return NULL; return NULL;
} }
void decode_ongakukan_adp(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do) void decode_ongakukan_adp(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do) {
{
ongakukan_adp_data* data = vgmstream->codec_data; ongakukan_adp_data* data = vgmstream->codec_data;
data->getting_samples = 2; data->getting_samples = 2;
data->samples_done = 0; data->samples_done = 0;
data->samples_filled = false; data->samples_filled = false;
/* ^ samples_filled is boolean here because we need to simplify how decoding will work here.
* so, rather than making samples_filled into a long int counter,
* we make it into a boolean flag instead so as to let data->samples_done shine as a counter
* and the decoder to do its job without worry. */
while (data->samples_done < samples_to_do) while (data->samples_done < samples_to_do) {
{ if (data->samples_filled) {
if (data->samples_filled) memcpy(outbuf + data->samples_done, data->samples, data->getting_samples * sizeof(int16_t));
{
memcpy(outbuf + data->samples_done,
data->samples,
data->getting_samples * sizeof(int16_t));
data->samples_done += data->getting_samples; data->samples_done += data->getting_samples;
data->samples_filled = false; data->samples_filled = false;
} }
else { decode_ongakukan_adpcm_data(data->handle); else {
data->samples_filled = true; ongakukan_adpcm_decode_data(data->handle);
data->samples = (int16_t*)get_sample_hist_from_ongakukan_adpcm(data->handle); }
data->samples_filled = true;
data->samples = ongakukan_adpcm_get_sample_hist(data->handle);
}
} }
} }
void reset_ongakukan_adp(ongakukan_adp_data* data) void reset_ongakukan_adp(ongakukan_adp_data* data) {
{
if (!data) return; if (!data) return;
ongakukan_adpcm_reset(data->handle); ongakukan_adpcm_reset(data->handle);
} }
void seek_ongakukan_adp(ongakukan_adp_data* data, int32_t current_sample) void seek_ongakukan_adp(ongakukan_adp_data* data, int32_t current_sample) {
{
if (!data) return; if (!data) return;
ongakukan_adpcm_seek(data->handle, current_sample); ongakukan_adpcm_seek(data->handle, current_sample);
} }
void free_ongakukan_adp(ongakukan_adp_data* data) void free_ongakukan_adp(ongakukan_adp_data* data) {
{
if (!data) return; if (!data) return;
close_streamfile(data->sf); close_streamfile(data->sf);
ongakukan_adpcm_free(data->handle); ongakukan_adpcm_free(data->handle);
free(data); free(data);
} }
int32_t ongakukan_adp_get_samples(ongakukan_adp_data* data) int32_t ongakukan_adp_get_samples(ongakukan_adp_data* data) {
{
if (!data) return 0; if (!data) return 0;
return (int32_t)get_num_samples_from_ongakukan_adpcm(data->handle); return (int32_t)ongakukan_adpcm_get_num_samples(data->handle);
} }

View File

@ -1053,7 +1053,7 @@ static const meta_info meta_info_list[] = {
{meta_AIFF, "Apple AIFF header"}, {meta_AIFF, "Apple AIFF header"},
{meta_STR_SNDS, "3DO SNDS header"}, {meta_STR_SNDS, "3DO SNDS header"},
{meta_WS_AUD, "Westwood Studios .AUD header"}, {meta_WS_AUD, "Westwood Studios .AUD header"},
{meta_PS2_IVB, "IVB/BVII header"}, {meta_IIVB, "Vingt-et-un IIVB header"},
{meta_SVS, "Square SVS header"}, {meta_SVS, "Square SVS header"},
{meta_RIFF_WAVE, "RIFF WAVE header"}, {meta_RIFF_WAVE, "RIFF WAVE header"},
{meta_RIFF_WAVE_POS, "RIFF WAVE header (.pos looping)"}, {meta_RIFF_WAVE_POS, "RIFF WAVE header (.pos looping)"},

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations"> <ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32"> <ProjectConfiguration Include="Debug|Win32">
@ -85,7 +85,6 @@
<ClInclude Include="api_helpers.h" /> <ClInclude Include="api_helpers.h" />
<ClInclude Include="api_streamfile.h" /> <ClInclude Include="api_streamfile.h" />
<ClInclude Include="api_tags.h" /> <ClInclude Include="api_tags.h" />
<ClInclude Include="coding\libs\ongakukan_adp_lib.h" />
<ClInclude Include="streamfile.h" /> <ClInclude Include="streamfile.h" />
<ClInclude Include="streamtypes.h" /> <ClInclude Include="streamtypes.h" />
<ClInclude Include="util.h" /> <ClInclude Include="util.h" />
@ -116,6 +115,7 @@
<ClInclude Include="coding\libs\icelib.h" /> <ClInclude Include="coding\libs\icelib.h" />
<ClInclude Include="coding\libs\libacm.h" /> <ClInclude Include="coding\libs\libacm.h" />
<ClInclude Include="coding\libs\nwa_lib.h" /> <ClInclude Include="coding\libs\nwa_lib.h" />
<ClInclude Include="coding\libs\ongakukan_adp_lib.h" />
<ClInclude Include="coding\libs\relic_lib.h" /> <ClInclude Include="coding\libs\relic_lib.h" />
<ClInclude Include="coding\libs\tac_data.h" /> <ClInclude Include="coding\libs\tac_data.h" />
<ClInclude Include="coding\libs\tac_lib.h" /> <ClInclude Include="coding\libs\tac_lib.h" />
@ -207,10 +207,7 @@
<ClInclude Include="util\zlib_vgmstream.h" /> <ClInclude Include="util\zlib_vgmstream.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="coding\libs\ongakukan_adp_lib.c" />
<ClCompile Include="coding\ongakukan_adp_decoder.c" />
<ClCompile Include="formats.c" /> <ClCompile Include="formats.c" />
<ClCompile Include="meta\adp_ongakukan.c" />
<ClCompile Include="streamfile.c" /> <ClCompile Include="streamfile.c" />
<ClCompile Include="util.c" /> <ClCompile Include="util.c" />
<ClCompile Include="vgmstream.c" /> <ClCompile Include="vgmstream.c" />
@ -283,6 +280,7 @@
<ClCompile Include="coding\nwa_decoder.c" /> <ClCompile Include="coding\nwa_decoder.c" />
<ClCompile Include="coding\ogg_vorbis_decoder.c" /> <ClCompile Include="coding\ogg_vorbis_decoder.c" />
<ClCompile Include="coding\oki_decoder.c" /> <ClCompile Include="coding\oki_decoder.c" />
<ClCompile Include="coding\ongakukan_adp_decoder.c" />
<ClCompile Include="coding\pcm_decoder.c" /> <ClCompile Include="coding\pcm_decoder.c" />
<ClCompile Include="coding\psv_decoder.c" /> <ClCompile Include="coding\psv_decoder.c" />
<ClCompile Include="coding\psx_decoder.c" /> <ClCompile Include="coding\psx_decoder.c" />
@ -318,6 +316,7 @@
<ClCompile Include="coding\libs\libacm_decode.c" /> <ClCompile Include="coding\libs\libacm_decode.c" />
<ClCompile Include="coding\libs\libacm_util.c" /> <ClCompile Include="coding\libs\libacm_util.c" />
<ClCompile Include="coding\libs\nwa_lib.c" /> <ClCompile Include="coding\libs\nwa_lib.c" />
<ClCompile Include="coding\libs\ongakukan_adp_lib.c" />
<ClCompile Include="coding\libs\relic_lib.c" /> <ClCompile Include="coding\libs\relic_lib.c" />
<ClCompile Include="coding\libs\relic_mixfft.c" /> <ClCompile Include="coding\libs\relic_mixfft.c" />
<ClCompile Include="coding\libs\tac_lib.c" /> <ClCompile Include="coding\libs\tac_lib.c" />
@ -379,6 +378,7 @@
<ClCompile Include="meta\adm.c" /> <ClCompile Include="meta\adm.c" />
<ClCompile Include="meta\adpcm_capcom.c" /> <ClCompile Include="meta\adpcm_capcom.c" />
<ClCompile Include="meta\adp_konami.c" /> <ClCompile Include="meta\adp_konami.c" />
<ClCompile Include="meta\adp_ongakukan.c" />
<ClCompile Include="meta\adp_qd.c" /> <ClCompile Include="meta\adp_qd.c" />
<ClCompile Include="meta\adp_wildfire.c" /> <ClCompile Include="meta\adp_wildfire.c" />
<ClCompile Include="meta\ads.c" /> <ClCompile Include="meta\ads.c" />
@ -507,6 +507,7 @@
<ClCompile Include="meta\idsp_ie.c" /> <ClCompile Include="meta\idsp_ie.c" />
<ClCompile Include="meta\idtech.c" /> <ClCompile Include="meta\idtech.c" />
<ClCompile Include="meta\ifs.c" /> <ClCompile Include="meta\ifs.c" />
<ClCompile Include="meta\iivb.c" />
<ClCompile Include="meta\ikm.c" /> <ClCompile Include="meta\ikm.c" />
<ClCompile Include="meta\ild.c" /> <ClCompile Include="meta\ild.c" />
<ClCompile Include="meta\ima.c" /> <ClCompile Include="meta\ima.c" />
@ -515,7 +516,6 @@
<ClCompile Include="meta\isb.c" /> <ClCompile Include="meta\isb.c" />
<ClCompile Include="meta\ish_isd.c" /> <ClCompile Include="meta\ish_isd.c" />
<ClCompile Include="meta\ivag.c" /> <ClCompile Include="meta\ivag.c" />
<ClCompile Include="meta\ivb.c" />
<ClCompile Include="meta\jstm.c" /> <ClCompile Include="meta\jstm.c" />
<ClCompile Include="meta\kat.c" /> <ClCompile Include="meta\kat.c" />
<ClCompile Include="meta\kma9.c" /> <ClCompile Include="meta\kma9.c" />

View File

@ -179,6 +179,9 @@
<ClInclude Include="coding\libs\nwa_lib.h"> <ClInclude Include="coding\libs\nwa_lib.h">
<Filter>coding\libs\Header Files</Filter> <Filter>coding\libs\Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="coding\libs\ongakukan_adp_lib.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\libs\relic_lib.h"> <ClInclude Include="coding\libs\relic_lib.h">
<Filter>coding\libs\Header Files</Filter> <Filter>coding\libs\Header Files</Filter>
</ClInclude> </ClInclude>
@ -446,57 +449,6 @@
<ClInclude Include="util\zlib_vgmstream.h"> <ClInclude Include="util\zlib_vgmstream.h">
<Filter>util\Header Files</Filter> <Filter>util\Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="coding\libs\circus_vq_data.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\libs\circus_vq_lib.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\libs\circus_vq_lzxpcm.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\libs\clhca.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\libs\compresswave_lib.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\libs\g7221_aes.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\libs\g7221_data.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\libs\g7221_lib.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\libs\icelib.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\libs\libacm.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\libs\nwa_lib.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\libs\ongakukan_adp_lib.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\libs\relic_lib.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\libs\tac_data.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\libs\tac_lib.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\libs\tac_ops.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\libs\utkdec.h">
<Filter>coding\libs\Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="formats.c"> <ClCompile Include="formats.c">
@ -718,6 +670,9 @@
<ClCompile Include="coding\oki_decoder.c"> <ClCompile Include="coding\oki_decoder.c">
<Filter>coding\Source Files</Filter> <Filter>coding\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="coding\ongakukan_adp_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\pcm_decoder.c"> <ClCompile Include="coding\pcm_decoder.c">
<Filter>coding\Source Files</Filter> <Filter>coding\Source Files</Filter>
</ClCompile> </ClCompile>
@ -823,6 +778,9 @@
<ClCompile Include="coding\libs\nwa_lib.c"> <ClCompile Include="coding\libs\nwa_lib.c">
<Filter>coding\libs\Source Files</Filter> <Filter>coding\libs\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="coding\libs\ongakukan_adp_lib.c">
<Filter>coding\libs\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\libs\relic_lib.c"> <ClCompile Include="coding\libs\relic_lib.c">
<Filter>coding\libs\Source Files</Filter> <Filter>coding\libs\Source Files</Filter>
</ClCompile> </ClCompile>
@ -1006,6 +964,9 @@
<ClCompile Include="meta\adp_konami.c"> <ClCompile Include="meta\adp_konami.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\adp_ongakukan.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\adp_qd.c"> <ClCompile Include="meta\adp_qd.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
@ -1390,6 +1351,9 @@
<ClCompile Include="meta\ifs.c"> <ClCompile Include="meta\ifs.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\iivb.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ikm.c"> <ClCompile Include="meta\ikm.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
@ -1414,9 +1378,6 @@
<ClCompile Include="meta\ivag.c"> <ClCompile Include="meta\ivag.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\ivb.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\jstm.c"> <ClCompile Include="meta\jstm.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
@ -2290,53 +2251,5 @@
<ClCompile Include="util\text_reader.c"> <ClCompile Include="util\text_reader.c">
<Filter>util\Source Files</Filter> <Filter>util\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\adp_ongakukan.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\ongakukan_adp_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\libs\circus_vq_lib.c">
<Filter>coding\libs\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\libs\clhca.c">
<Filter>coding\libs\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\libs\compresswave_lib.c">
<Filter>coding\libs\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\libs\g7221_aes.c">
<Filter>coding\libs\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\libs\g7221_lib.c">
<Filter>coding\libs\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\libs\icelib.c">
<Filter>coding\libs\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\libs\libacm_decode.c">
<Filter>coding\libs\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\libs\libacm_util.c">
<Filter>coding\libs\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\libs\nwa_lib.c">
<Filter>coding\libs\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\libs\ongakukan_adp_lib.c">
<Filter>coding\libs\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\libs\relic_lib.c">
<Filter>coding\libs\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\libs\relic_mixfft.c">
<Filter>coding\libs\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\libs\tac_lib.c">
<Filter>coding\libs\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\libs\utkdec.c">
<Filter>coding\libs\Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,89 +1,70 @@
#include "meta.h" #include "meta.h"
#include "../coding/coding.h" #include "../coding/coding.h"
/* Ongakukan RIFF with "ADP" extension [Train Simulator - Midousuji-sen (PS2)] */ /* Ongakukan RIFF with "ADP" extension [Train Simulator: Midousuji-sen (PS2), Mobile Train Simulator (PSP)] */
VGMSTREAM* init_vgmstream_ongakukan_adp(STREAMFILE* sf) VGMSTREAM* init_vgmstream_adp_ongakukan(STREAMFILE* sf) {
{
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
off_t start_offset; off_t start_offset;
size_t file_size;
bool has_data_chunk = false, has_fact_chunk = false;
int loop_flag = 0; int loop_flag = 0;
int riff_wave_header_size = 0x2c;
/* ^ where sound data begins, as a consequence their tools couldn't even write full RIFF WAVE header to file beyond that point.. */
bool sound_is_adpcm = false; bool sound_is_adpcm = false;
int32_t supposed_size, fmt_size, fmt_offset, offset_of_supposed_last_chunk; int32_t fmt_size, fmt_offset;
int32_t sample_rate, data_size; int32_t sample_rate, data_size;
int16_t num_channels, block_size; int16_t channels;
/* RIFF+WAVE checks */
if (!is_id32be(0x00, sf, "RIFF")) goto fail;
if (!is_id32be(0x08, sf, "WAVE")) goto fail;
/* WAVE "fmt " check */
if (!is_id32be(0x0c, sf, "fmt ")) goto fail;
/* "adp" extension check (literally only one) */
if (!check_extensions(sf, "adp")) goto fail;
/* catch adp file size from here and use it whenever needed. */ /* checks */
file_size = get_streamfile_size(sf); if (!is_id32be(0x00, sf, "RIFF"))
return NULL;
if (!check_extensions(sf, "adp"))
return NULL;
/* RIFF size from adp file can go beyond actual size (e.g: reported 10MB vs 2MB). do quick calcs around this. */ /* Format starts like RIFF but doesn't have valid chunks beyond fmt (ADPCM data overwrites anything after 0x2c). */
supposed_size = ((read_s32le(0x04, sf) - 0x24) >> 2) + 0x2c;
if (file_size != supposed_size) goto fail; start_offset = 0x2c; /* fixed values, basically how Ongakukan does it */
data_size = get_streamfile_size(sf) - start_offset;
/* RIFF size seem to match original PCM .wav, while encoded .adp data equals or is slightly smaller that that */
uint32_t expected_size = (read_u32le(0x04, sf) - 0x24);
uint32_t pcm_size = data_size * 2 * sizeof(short); // * channels
if (pcm_size > expected_size)
return NULL;
if (!is_id32be(0x08, sf, "WAVE"))
return NULL;
if (!is_id32be(0x0c, sf, "fmt "))
return NULL;
/* read entire WAVE "fmt " chunk. we start by reading fmt_size from yours truly and setting fmt_offset. */
fmt_size = read_s32le(0x10, sf); fmt_size = read_s32le(0x10, sf);
fmt_offset = 0x14; /* depending on the adp, fmt_size alternates between 0x10 and 0x12 */
if ((fmt_size >= 0x10) && (fmt_size <= 0x12)) /* depending on the adp, fmt_size alternates between 0x10 and 0x12 */ if (fmt_size < 0x10 || fmt_size > 0x12)
{
if (read_s16le(fmt_offset + 0, sf) != 1) goto fail; /* chunk reports codec number as signed little-endian PCM, couldn't be more wrong. */
num_channels = read_s16le(fmt_offset + 2, sf);
sample_rate = read_s32le(fmt_offset + 4, sf);
if (read_s16le(fmt_offset + 14, sf) != 0x10) goto fail; /* bit depth as chunk reports it. */
/* rest of fmt header is the usual header for 16-bit PCM wav files: bitrate, block size, and the like (see riff.c) */
/* if fmt_size == 0x12 there is an additional s16 field that's always zero. */
}
else {
goto fail; goto fail;
} fmt_offset = 0x14;
/* now calc the var so we can read either "data" or "fact" chunk; */ if (read_s16le(fmt_offset + 0x00, sf) != 0x0001) /* PCM format */
offset_of_supposed_last_chunk = fmt_offset + fmt_size; goto fail;
channels = read_s16le(fmt_offset + 0x02, sf);
if (channels != 1) /* not seen (decoder can't handle it) */
goto fail;
sample_rate = read_s32le(fmt_offset + 0x04, sf);
if (read_s16le(fmt_offset + 0x0e, sf) != 16) /* PCM bit depth */
goto fail;
/* rest of fmt header is the usual header for 16-bit PCM wav files: bitrate, block size, and the like (see riff.c) */
/* if fmt_size == 0x12 there may be is an additional s16 field that's always zero, but not always. */
/* we need to get to the last WAVE chunk manually, and that means the calc below. */ /* next chunk is at fixed offset, regardless of fmt_size (fmt_size 0x12 with "data" at 0x24 is possible).
offset_of_supposed_last_chunk = fmt_offset + fmt_size; * "data" has chunk size (does not match ADP size but original WAV) and "fact" chunk size 0x04 cut off) */
if (is_id32be(offset_of_supposed_last_chunk + 0, sf, "data")) has_data_chunk = true; if (!is_id32be(0x24, sf, "data") && !is_id32be(0x26, sf, "fact"))
if (is_id32be(offset_of_supposed_last_chunk + 0, sf, "fact")) has_fact_chunk = true; goto fail;
/* and because sound data *must* start at 0x2c, they have to bork both chunks too, so they're now essentially useless. /* Ongagukan games using this format just read it by checking "ADP" extension in a provided file name,
* they're basically leftovers from original (lossless) WAV files at this point. */
if (has_data_chunk)
{
/* RIFF adp files have leftover "data" chunk size... that does NOT match the ADP file size at hand. */
supposed_size = (read_s32le(offset_of_supposed_last_chunk + 4, sf) >> 2) + 0x2c;
if (file_size != supposed_size) goto fail;
}
if (has_fact_chunk)
{
/* RIFF adp files have also cut off "fact" chunk so we're just left with a useless number now. */
if (read_s16le(offset_of_supposed_last_chunk + 4, sf) != 4) goto fail;
}
/* set start_offset value to riff_wave_header_size and calculate data_size by ourselves, basically how Ongakukan does it also. */
start_offset = riff_wave_header_size;
data_size = (int32_t)(file_size) - riff_wave_header_size;
/* Ongagukan games using this format just read it by checking "ADP" extension in an provided file name of a programmer's own choosing,
* and if extension is there they just read the reported "number of samples" and "sample_rate" vars * and if extension is there they just read the reported "number of samples" and "sample_rate" vars
* from RIFF WAVE "fmt " chunk based on an already-opened file with that same name. * from RIFF WAVE "fmt " chunk based on an already-opened file with that same name.
* and they don't even read RIFF chunks, they just pick these two vars and that's basically it. */ * and they don't even read RIFF chunks, they just pick these two vars and that's basically it. */
/* our custom decoder needs at least one flag set. */
sound_is_adpcm = true; sound_is_adpcm = true;
/* build the VGMSTREAM */ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(num_channels, loop_flag); vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->meta_type = meta_ONGAKUKAN_RIFF_ADP; vgmstream->meta_type = meta_ONGAKUKAN_RIFF_ADP;

35
src/meta/iivb.c Normal file
View File

@ -0,0 +1,35 @@
#include "meta.h"
#include "../util.h"
#include "../util/meta_utils.h"
/* IIVB - from Vingt-et-un Systems games [Langrisser III (PS2), Ururun Quest: Koiyuuki (PS2)] */
VGMSTREAM* init_vgmstream_iivb(STREAMFILE* sf) {
/* checks */
if (!is_id32be(0x00, sf, "BVII")) /* IIVB LE, given extension */
return NULL;
if (!check_extensions(sf,"ivb"))
return NULL;
meta_header_t h = {
.meta = meta_IIVB,
};
h.chan_size = read_u32le(0x04,sf);
h.sample_rate = read_s32be(0x08,sf); /* big endian? */
// 0c: empty
h.channels = 2;
h.stream_offset = 0x10;
h.num_samples = ps_bytes_to_samples(h.chan_size, 1);
h.coding = coding_PSX;
h.layout = layout_interleave;
h.interleave = h.chan_size;
h.sf = sf;
h.open_stream = true;
return alloc_metastream(&h);
}

View File

@ -1,60 +0,0 @@
#include "meta.h"
#include "../util.h"
/* a simple PS2 ADPCM format seen in Langrisser 3 */
VGMSTREAM * init_vgmstream_ivb(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
off_t stream_length;
int loop_flag = 0;
int channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("ivb",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x42564949) /* "BVII", probably */
goto fail; /* supposed to be "IIVB"*/
loop_flag = 0;
channel_count = 2;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x8,streamFile); /* big endian? */
vgmstream->coding_type = coding_PSX;
stream_length = read_32bitLE(0x04,streamFile);
start_offset = 0x10;
vgmstream->num_samples = stream_length*28/16;
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_PS2_IVB;
/* open the file for reading */
{
int i;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!vgmstream->ch[i].streamfile) goto fail;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+stream_length*i;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -182,7 +182,7 @@ VGMSTREAM * init_vgmstream_ws_aud(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ahx(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_ahx(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ivb(STREAMFILE * streamFile); VGMSTREAM* init_vgmstream_iivb(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_svs(STREAMFILE * streamFile); VGMSTREAM * init_vgmstream_svs(STREAMFILE * streamFile);
@ -1018,6 +1018,6 @@ VGMSTREAM* init_vgmstream_ea_sbk(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_dsp_asura_sfx(STREAMFILE* sf); VGMSTREAM* init_vgmstream_dsp_asura_sfx(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_ongakukan_adp(STREAMFILE* sf); VGMSTREAM* init_vgmstream_adp_ongakukan(STREAMFILE* sf);
#endif /*_META_H*/ #endif /*_META_H*/

View File

@ -5,10 +5,14 @@
/* Allocate memory and setup a VGMSTREAM */ /* Allocate memory and setup a VGMSTREAM */
VGMSTREAM* alloc_metastream(meta_header_t* h) { VGMSTREAM* alloc_metastream(meta_header_t* h) {
if (h->sample_rate <= 0 || h->sample_rate > VGMSTREAM_MAX_SAMPLE_RATE) if (h->sample_rate <= 0 || h->sample_rate > VGMSTREAM_MAX_SAMPLE_RATE) {
VGM_LOG("meta: wrong sample rate %i\n", h->sample_rate);
return NULL; return NULL;
if (h->num_samples <= 0 || h->num_samples > VGMSTREAM_MAX_NUM_SAMPLES) }
if (h->num_samples <= 0 || h->num_samples > VGMSTREAM_MAX_NUM_SAMPLES) {
VGM_LOG("meta: wrong samples %i\n", h->sample_rate);
return NULL; return NULL;
}
VGMSTREAM* vgmstream = allocate_vgmstream(h->channels, h->loop_flag); VGMSTREAM* vgmstream = allocate_vgmstream(h->channels, h->loop_flag);
if (!vgmstream) return NULL; if (!vgmstream) return NULL;

View File

@ -66,7 +66,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_str_snds, init_vgmstream_str_snds,
init_vgmstream_ws_aud, init_vgmstream_ws_aud,
init_vgmstream_ahx, init_vgmstream_ahx,
init_vgmstream_ivb, init_vgmstream_iivb,
init_vgmstream_svs, init_vgmstream_svs,
init_vgmstream_riff, init_vgmstream_riff,
init_vgmstream_rifx, init_vgmstream_rifx,
@ -533,7 +533,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
init_vgmstream_dsp_asura_ds2, init_vgmstream_dsp_asura_ds2,
init_vgmstream_dsp_asura_ttss, init_vgmstream_dsp_asura_ttss,
init_vgmstream_dsp_asura_sfx, init_vgmstream_dsp_asura_sfx,
init_vgmstream_ongakukan_adp, init_vgmstream_adp_ongakukan,
/* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */ /* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */
init_vgmstream_agsc, init_vgmstream_agsc,

View File

@ -318,7 +318,7 @@ typedef enum {
meta_PWB, meta_PWB,
meta_VPK, /* VPK Audio File */ meta_VPK, /* VPK Audio File */
meta_PS2_BMDX, /* Beatmania thing */ meta_PS2_BMDX, /* Beatmania thing */
meta_PS2_IVB, /* Langrisser 3 IVB */ meta_IIVB,
meta_PS2_SND, /* some Might & Magics SSND header */ meta_PS2_SND, /* some Might & Magics SSND header */
meta_SVS, /* Square SVS */ meta_SVS, /* Square SVS */
meta_XSS, /* Dino Crisis 3 */ meta_XSS, /* Dino Crisis 3 */

View File

@ -150,7 +150,13 @@ class ProjectFixer:
def main(): def main():
types = [ types = [
'./src/*.vcxproj', './src/*.vcxproj',
'./src/*.vcxproj.filters' './src/*.vcxproj.filters',
#'./cli/*.vcxproj',
#'./cli/*.vcxproj.filters',
'./winamp/*.vcxproj',
'./winamp/*.vcxproj.filters',
'./xmplay/*.vcxproj',
'./xmplay/*.vcxproj.filters',
] ]
for type in types: for type in types:

View File

@ -33,14 +33,14 @@ TARGET_EXT_LIBS += $(LIBS_TARGET_EXT_LIBS)
export CFLAGS LDFLAGS export CFLAGS LDFLAGS
#SRC_SRCS = $(wildcard *.c) SRCS = $(wildcard *.c)
SRC_SRCS = in_vgmstream.c in_streamfile.c in_config.c OBJECTS = $(wildcard *.o)
############################################################################### ###############################################################################
### targets ### targets
in_vgmstream: libvgmstream.a $(TARGET_EXT_LIBS) resource.o in_vgmstream: libvgmstream.a $(TARGET_EXT_LIBS) resource.o
$(CC) -shared -static-libgcc $(CFLAGS) $(SRC_SRCS) resource.o $(LDFLAGS) -o $(OUTPUT_WINAMP) $(CC) -shared -static-libgcc $(CFLAGS) $(SRCS) resource.o $(LDFLAGS) -o $(OUTPUT_WINAMP)
$(STRIP) $(OUTPUT_WINAMP) $(STRIP) $(OUTPUT_WINAMP)
resource.o: resource.rc resource.h resource.o: resource.rc resource.h
@ -53,6 +53,6 @@ $(TARGET_EXT_LIBS):
$(MAKE) -C ../ext_libs $@ $(MAKE) -C ../ext_libs $@
clean: clean:
$(RMF) $(OUTPUT_WINAMP) resource.o $(RMF) $(OUTPUT_WINAMP) $(OBJECTS) resource.o
.PHONY: clean in_vgmstream libvgmstream.a $(TARGET_EXT_LIBS) .PHONY: clean in_vgmstream libvgmstream.a $(TARGET_EXT_LIBS)

View File

@ -9,8 +9,8 @@
/* ************************************* */ /* ************************************* */
/* config */ /* config */
#define CONFIG_APP_NAME TEXT("vgmstream plugin") #define CONFIG_APP_NAME TEXT("vgmstream plugin")
#define CONFIG_INI_NAME TEXT("plugin.ini") #define CONFIG_INI_NAME TEXT("plugin.ini")
#define INI_FADE_TIME TEXT("fade_seconds") #define INI_FADE_TIME TEXT("fade_seconds")
#define INI_FADE_DELAY TEXT("fade_delay") #define INI_FADE_DELAY TEXT("fade_delay")
@ -28,28 +28,28 @@
#define INI_CLIP_TYPE TEXT("clip_type") #define INI_CLIP_TYPE TEXT("clip_type")
TCHAR *dlg_priority_strings[7] = { TCHAR *dlg_priority_strings[7] = {
TEXT("Idle"), TEXT("Idle"),
TEXT("Lowest"), TEXT("Lowest"),
TEXT("Below Normal"), TEXT("Below Normal"),
TEXT("Normal"), TEXT("Normal"),
TEXT("Above Normal"), TEXT("Above Normal"),
TEXT("Highest (not recommended)"), TEXT("Highest (not recommended)"),
TEXT("Time Critical (not recommended)") TEXT("Time Critical (not recommended)")
}; };
TCHAR *dlg_replaygain_strings[] = { TCHAR *dlg_replaygain_strings[] = {
TEXT("None"), TEXT("None"),
TEXT("Album"), TEXT("Album"),
TEXT("Peak") TEXT("Peak")
}; };
int priority_values[7] = { const int priority_values[7] = {
THREAD_PRIORITY_IDLE, THREAD_PRIORITY_IDLE,
THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_LOWEST,
THREAD_PRIORITY_BELOW_NORMAL, THREAD_PRIORITY_BELOW_NORMAL,
THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_NORMAL,
THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL,
THREAD_PRIORITY_HIGHEST, THREAD_PRIORITY_HIGHEST,
THREAD_PRIORITY_TIME_CRITICAL THREAD_PRIORITY_TIME_CRITICAL
}; };

120
winamp/in_utils.c Normal file
View File

@ -0,0 +1,120 @@
#include "in_vgmstream.h"
/* Adds ext to Winamp's extension list */
static int add_extension(char* dst, int dst_len, const char* ext) {
int ext_len;
ext_len = strlen(ext);
if (dst_len <= ext_len + 1)
return 0;
strcpy(dst, ext); /* seems winamp uppercases this if needed */
dst[ext_len] = ';';
return ext_len + 1;
}
/* Creates Winamp's extension list, a single string that ends with \0\0.
* Each extension must be in this format: "extensions\0Description\0"
*
* The list is used to accept extensions by default when IsOurFile returns 0, to register file
* types, and in the open dialog's type combo. Format actually can be:
* - "ext1;ext2;...\0EXTS Audio Files (*.ext1; *.ext2; *...\0", //single line with all
* - "ext1\0EXT1 Audio File (*.ext1)\0ext2\0EXT2 Audio File (*.ext2)\0...", //multiple lines
* Open dialog's text (including all plugin's "Description") seems limited to old MAX_PATH 260
* (max size for "extensions" checks seems ~0x40000 though). Given vgmstream's huge number
* of exts, use single line to (probably) work properly with dialogs (used to be multi line).
*/
void build_extension_list(char* winamp_list, int winamp_list_size) {
const char** ext_list;
size_t ext_list_len;
int i, written;
int description_size = 0x100; /* reserved max at the end */
winamp_list[0] = '\0';
winamp_list[1] = '\0';
ext_list = vgmstream_get_formats(&ext_list_len);
for (i = 0; i < ext_list_len; i++) {
int used = add_extension(winamp_list, winamp_list_size - description_size, ext_list[i]);
if (used <= 0) {
vgm_logi("build_extension_list: not enough buf for all exts\n");
break;
}
winamp_list += used;
winamp_list_size -= used;
}
if (i > 0) {
winamp_list[-1] = '\0'; /* last "ext;" to "ext\0" */
}
/* generic description for the info dialog since we can't really show everything */
written = snprintf(winamp_list, winamp_list_size - 2, "vgmstream Audio Files%c", '\0');
/* should end with double \0 */
if (written < 0) {
winamp_list[0] = '\0';
winamp_list[1] = '\0';
}
else {
winamp_list[written + 0] = '\0';
winamp_list[written + 1] = '\0';
}
}
/* makes a modified filename, suitable to pass parameters around */
static void make_fn_subsong(in_char* dst, int dst_size, const in_char* filename, int subsong_index) {
/* Follows "(file)(config)(ext)". Winamp needs to "see" (ext) to validate, and file goes first so relative
* files work in M3Us (path is added). Protocols a la "vgmstream://(config)(file)" work but don't get full paths. */
wa_snprintf(dst,dst_size, wa_L("%s|$s=%i|.vgmstream"), filename, subsong_index);
}
/* unpacks the subsongs by adding entries to the playlist */
bool split_subsongs(const in_char* filename, int subsong_index, VGMSTREAM* vgmstream) {
int i, playlist_index;
HWND hPlaylistWindow;
if (settings.disable_subsongs || vgmstream->num_streams <= 1)
return 0; /* don't split if no subsongs */
if (subsong_index > 0 || vgmstream->stream_index > 0)
return 0; /* no split if already playing subsong */
hPlaylistWindow = (HWND)SendMessage(input_module.hMainWindow, WM_WA_IPC, IPC_GETWND_PE, IPC_GETWND);
playlist_index = SendMessage(input_module.hMainWindow,WM_WA_IPC,0,IPC_GETLISTPOS);
/* The only way to pass info around in Winamp is encoding it into the filename, so a fake name
* is created with the index. Then, winamp_Play (and related) intercepts and reads the index. */
for (i = 0; i < vgmstream->num_streams; i++) {
in_char stream_fn[PATH_LIMIT];
make_fn_subsong(stream_fn,PATH_LIMIT, filename, (i+1)); /* encode index in filename */
/* insert at index */
{
COPYDATASTRUCT cds = {0};
wa_fileinfo f;
wa_strncpy(f.file, stream_fn,MAX_PATH-1);
f.file[MAX_PATH-1] = '\0';
f.index = playlist_index + (i+1);
cds.dwData = wa_IPC_PE_INSERTFILENAME;
cds.lpData = (void*)&f;
cds.cbData = sizeof(wa_fileinfo);
SendMessage(hPlaylistWindow,WM_COPYDATA,0,(LPARAM)&cds);
}
/* IPC_ENQUEUEFILE can pre-set the title without needing the Playlist handle, but can't insert at index */
}
/* remove current file from the playlist */
SendMessage(hPlaylistWindow, WM_WA_IPC, IPC_PE_DELETEINDEX, playlist_index);
/* autoplay doesn't always advance to the first unpacked track, but manually fails somehow */
//SendMessage(input_module.hMainWindow,WM_WA_IPC,playlist_index,IPC_SETPLAYLISTPOS);
//SendMessage(input_module.hMainWindow,WM_WA_IPC,0,IPC_STARTPLAY);
return 1;
}

View File

@ -27,7 +27,7 @@ DWORD WINAPI __stdcall decode(void *arg);
* (older versions of XMPlay also will crash with so many exts but can't autodetect version here) */ * (older versions of XMPlay also will crash with so many exts but can't autodetect version here) */
#define EXTENSION_LIST_SIZE (0x2000 * 6) #define EXTENSION_LIST_SIZE (0x2000 * 6)
/* fixed list to simplify but could also malloc/free on init/close */ /* fixed list to simplify but could also malloc/free on init/close */
char working_extension_list[EXTENSION_LIST_SIZE] = {0}; char extension_list[EXTENSION_LIST_SIZE] = {0};
/* current play state */ /* current play state */
@ -127,61 +127,6 @@ static VGMSTREAM* init_vgmstream_winamp_fileinfo(const in_char* fn) {
} }
/* makes a modified filename, suitable to pass parameters around */
static void make_fn_subsong(in_char* dst, int dst_size, const in_char* filename, int stream_index) {
/* Follows "(file)(config)(ext)". Winamp needs to "see" (ext) to validate, and file goes first so relative
* files work in M3Us (path is added). Protocols a la "vgmstream://(config)(file)" work but don't get full paths. */
wa_snprintf(dst,dst_size, wa_L("%s|$s=%i|.vgmstream"), filename, stream_index);
}
/* unpacks the subsongs by adding entries to the playlist */
static int split_subsongs(const in_char* filename, int stream_index, VGMSTREAM *vgmstream) {
int i, playlist_index;
HWND hPlaylistWindow;
if (settings.disable_subsongs || vgmstream->num_streams <= 1)
return 0; /* don't split if no subsongs */
if (stream_index > 0 || vgmstream->stream_index > 0)
return 0; /* no split if already playing subsong */
hPlaylistWindow = (HWND)SendMessage(input_module.hMainWindow, WM_WA_IPC, IPC_GETWND_PE, IPC_GETWND);
playlist_index = SendMessage(input_module.hMainWindow,WM_WA_IPC,0,IPC_GETLISTPOS);
/* The only way to pass info around in Winamp is encoding it into the filename, so a fake name
* is created with the index. Then, winamp_Play (and related) intercepts and reads the index. */
for (i = 0; i < vgmstream->num_streams; i++) {
in_char stream_fn[PATH_LIMIT];
make_fn_subsong(stream_fn,PATH_LIMIT, filename, (i+1)); /* encode index in filename */
/* insert at index */
{
COPYDATASTRUCT cds = {0};
wa_fileinfo f;
wa_strncpy(f.file, stream_fn,MAX_PATH-1);
f.file[MAX_PATH-1] = '\0';
f.index = playlist_index + (i+1);
cds.dwData = wa_IPC_PE_INSERTFILENAME;
cds.lpData = (void*)&f;
cds.cbData = sizeof(wa_fileinfo);
SendMessage(hPlaylistWindow,WM_COPYDATA,0,(LPARAM)&cds);
}
/* IPC_ENQUEUEFILE can pre-set the title without needing the Playlist handle, but can't insert at index */
}
/* remove current file from the playlist */
SendMessage(hPlaylistWindow, WM_WA_IPC, IPC_PE_DELETEINDEX, playlist_index);
/* autoplay doesn't always advance to the first unpacked track, but manually fails somehow */
//SendMessage(input_module.hMainWindow,WM_WA_IPC,playlist_index,IPC_SETPLAYLISTPOS);
//SendMessage(input_module.hMainWindow,WM_WA_IPC,0,IPC_STARTPLAY);
return 1;
}
/* try to detect XMPlay, which can't interact with the playlist = no splitting */ /* try to detect XMPlay, which can't interact with the playlist = no splitting */
static int is_xmplay() { static int is_xmplay() {
if (GetModuleHandle( TEXT("xmplay.exe") )) if (GetModuleHandle( TEXT("xmplay.exe") ))
@ -194,70 +139,6 @@ static int is_xmplay() {
return 0; return 0;
} }
/* Adds ext to Winamp's extension list */
static int add_extension(char* dst, int dst_len, const char* ext) {
int ext_len;
ext_len = strlen(ext);
if (dst_len <= ext_len + 1)
return 0;
strcpy(dst, ext); /* seems winamp uppercases this if needed */
dst[ext_len] = ';';
return ext_len + 1;
}
/* Creates Winamp's extension list, a single string that ends with \0\0.
* Each extension must be in this format: "extensions\0Description\0"
*
* The list is used to accept extensions by default when IsOurFile returns 0, to register file
* types, and in the open dialog's type combo. Format actually can be:
* - "ext1;ext2;...\0EXTS Audio Files (*.ext1; *.ext2; *...\0", //single line with all
* - "ext1\0EXT1 Audio File (*.ext1)\0ext2\0EXT2 Audio File (*.ext2)\0...", //multiple lines
* Open dialog's text (including all plugin's "Description") seems limited to old MAX_PATH 260
* (max size for "extensions" checks seems ~0x40000 though). Given vgmstream's huge number
* of exts, use single line to (probably) work properly with dialogs (used to be multi line).
*/
static void build_extension_list(char* winamp_list, int winamp_list_size) {
const char** ext_list;
size_t ext_list_len;
int i, written;
int description_size = 0x100; /* reserved max at the end */
winamp_list[0] = '\0';
winamp_list[1] = '\0';
ext_list = vgmstream_get_formats(&ext_list_len);
for (i = 0; i < ext_list_len; i++) {
int used = add_extension(winamp_list, winamp_list_size - description_size, ext_list[i]);
if (used <= 0) {
vgm_logi("build_extension_list: not enough buf for all exts\n");
break;
}
winamp_list += used;
winamp_list_size -= used;
}
if (i > 0) {
winamp_list[-1] = '\0'; /* last "ext;" to "ext\0" */
}
/* generic description for the info dialog since we can't really show everything */
written = snprintf(winamp_list, winamp_list_size - 2, "vgmstream Audio Files%c", '\0');
/* should end with double \0 */
if (written < 0) {
winamp_list[0] = '\0';
winamp_list[1] = '\0';
}
else {
winamp_list[written + 0] = '\0';
winamp_list[written + 1] = '\0';
}
}
/* unicode utils */ /* unicode utils */
static void get_title(in_char* dst, int dst_size, const in_char* fn, VGMSTREAM* infostream) { static void get_title(in_char* dst, int dst_size, const in_char* fn, VGMSTREAM* infostream) {
in_char filename[PATH_LIMIT]; in_char filename[PATH_LIMIT];
@ -388,7 +269,7 @@ void winamp_Init() {
} }
/* dynamically make a list of supported extensions */ /* dynamically make a list of supported extensions */
build_extension_list(working_extension_list, sizeof(working_extension_list)); build_extension_list(extension_list, sizeof(extension_list));
} }
/* called at program quit */ /* called at program quit */
@ -872,7 +753,7 @@ In_Module input_module = {
PLUGIN_NAME, PLUGIN_NAME,
0, /* hMainWindow (filled in by Winamp) */ 0, /* hMainWindow (filled in by Winamp) */
0, /* hDllInstance (filled in by Winamp) */ 0, /* hDllInstance (filled in by Winamp) */
working_extension_list, extension_list,
1, /* is_seekable flag */ 1, /* is_seekable flag */
9, /* UsesOutputPlug flag */ 9, /* UsesOutputPlug flag */
winamp_Config, winamp_Config,

View File

@ -34,7 +34,7 @@
/* ************************************* */ /* ************************************* */
extern In_Module input_module; extern In_Module input_module;
extern int priority_values[7]; extern const int priority_values[7];
typedef enum { typedef enum {
REPLAYGAIN_NONE, REPLAYGAIN_NONE,
@ -87,8 +87,8 @@ extern winamp_log_t* walog;
/* ************************************* */ /* ************************************* */
/* IN_UNICODE */ /* IN_UNICODE */
/* ************************************* */ /* ************************************* */
//todo safe ops //TODO safe ops
//todo there must be a better way to handle unicode... //TODO there must be a better way to handle unicode...
#ifdef UNICODE_INPUT_PLUGIN #ifdef UNICODE_INPUT_PLUGIN
#define wa_strcmp wcscmp #define wa_strcmp wcscmp
#define wa_strncmp wcsncmp #define wa_strncmp wcsncmp
@ -190,11 +190,11 @@ static inline void cfg_char_to_wchar(TCHAR *wdst, size_t wdstsize, const char *s
} }
/* ************************************* */
/* IN_STREAMFILE */
/* ************************************* */
/* in_streamfile.c */ /* in_streamfile.c */
STREAMFILE* open_winamp_streamfile_by_ipath(const in_char* wpath); STREAMFILE* open_winamp_streamfile_by_ipath(const in_char* wpath);
#endif /*_IN_VGMSTREAM_*/ void build_extension_list(char* extension_list, int list_size);
bool split_subsongs(const in_char* filename, int subsong_index, VGMSTREAM* vgmstream);
#endif

View File

@ -67,10 +67,15 @@
<ItemGroup> <ItemGroup>
<ClInclude Include="in_vgmstream.h" /> <ClInclude Include="in_vgmstream.h" />
<ClInclude Include="resource.h" /> <ClInclude Include="resource.h" />
<ClInclude Include="sdk\in2.h" />
<ClInclude Include="sdk\ipc_pe.h" />
<ClInclude Include="sdk\out.h" />
<ClInclude Include="sdk\wa_ipc.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="in_config.c" /> <ClCompile Include="in_config.c" />
<ClCompile Include="in_streamfile.c" /> <ClCompile Include="in_streamfile.c" />
<ClCompile Include="in_utils.c" />
<ClCompile Include="in_vgmstream.c" /> <ClCompile Include="in_vgmstream.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -21,6 +21,18 @@
<ClInclude Include="resource.h"> <ClInclude Include="resource.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="sdk\in2.h">
<Filter>sdk\Header Files</Filter>
</ClInclude>
<ClInclude Include="sdk\ipc_pe.h">
<Filter>sdk\Header Files</Filter>
</ClInclude>
<ClInclude Include="sdk\out.h">
<Filter>sdk\Header Files</Filter>
</ClInclude>
<ClInclude Include="sdk\wa_ipc.h">
<Filter>sdk\Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="resource.rc"> <ResourceCompile Include="resource.rc">
@ -34,6 +46,9 @@
<ClCompile Include="in_streamfile.c"> <ClCompile Include="in_streamfile.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="in_utils.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="in_vgmstream.c"> <ClCompile Include="in_vgmstream.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>

View File

@ -31,12 +31,14 @@ TARGET_EXT_LIBS += $(LIBS_TARGET_EXT_LIBS)
export CFLAGS LDFLAGS export CFLAGS LDFLAGS
SRCS = $(wildcard *.c)
OBJECTS = $(wildcard *.o)
############################################################################### ###############################################################################
### targets ### targets
xmp_vgmstream: libvgmstream.a $(TARGET_EXT_LIBS) xmp_vgmstream: libvgmstream.a $(TARGET_EXT_LIBS)
$(CC) -shared -static-libgcc $(CFLAGS) xmp_vgmstream.c $(LDFLAGS) -o $(OUTPUT_XMPLAY) xmpin.def $(CC) -shared -static-libgcc $(CFLAGS) $(SRCS) $(LDFLAGS) -o $(OUTPUT_XMPLAY) xmpin.def
$(STRIP) $(OUTPUT_XMPLAY) $(STRIP) $(OUTPUT_XMPLAY)
libvgmstream.a: libvgmstream.a:
@ -46,6 +48,6 @@ $(TARGET_EXT_LIBS):
$(MAKE) -C ../ext_libs $@ $(MAKE) -C ../ext_libs $@
clean: clean:
$(RMF) $(OUTPUT_XMPLAY) $(RMF) $(OBJECTS) $(OUTPUT_XMPLAY)
.PHONY: clean xmp_vgmstream libvgmstream.a $(TARGET_EXT_LIBS) .PHONY: clean xmp_vgmstream libvgmstream.a $(TARGET_EXT_LIBS)

View File

@ -69,8 +69,11 @@
<ItemGroup> <ItemGroup>
<ClInclude Include="xmpfunc.h" /> <ClInclude Include="xmpfunc.h" />
<ClInclude Include="xmpin.h" /> <ClInclude Include="xmpin.h" />
<ClInclude Include="xmp_vgmstream.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="xmp_streamfile.c" />
<ClCompile Include="xmp_utils.c" />
<ClCompile Include="xmp_vgmstream.c" /> <ClCompile Include="xmp_vgmstream.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,11 +1,26 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup> <ItemGroup>
<ClCompile Include="xmp_vgmstream.c" /> <ClCompile Include="xmp_streamfile.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="xmp_utils.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="xmp_vgmstream.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="xmpfunc.h" /> <ClInclude Include="xmpfunc.h">
<ClInclude Include="xmpin.h" /> <Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="xmpin.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="xmp_vgmstream.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="xmpin.def" /> <None Include="xmpin.def" />

86
xmplay/xmp_streamfile.c Normal file
View File

@ -0,0 +1,86 @@
#include "xmp_vgmstream.h"
/* a STREAMFILE that operates via XMPlay's XMPFUNC_FILE+XMPFILE */
typedef struct _XMPLAY_STREAMFILE {
STREAMFILE sf; /* callbacks */
XMPFILE infile; /* actual FILE */
XMPFUNC_FILE* xmpf_file; /* helper */
char name[0x8000]; /* path limit */
off_t offset; /* current offset */
int internal_xmpfile; /* infile was not supplied externally and can be closed */
} XMPLAY_STREAMFILE;
static size_t xmpsf_read(XMPLAY_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) {
size_t read;
if (sf->offset != offset) {
if (sf->xmpf_file->Seek(sf->infile, offset))
sf->offset = offset;
else
sf->offset = sf->xmpf_file->Tell(sf->infile);
}
read = sf->xmpf_file->Read(sf->infile, dst, length);
if (read > 0)
sf->offset += read;
return read;
}
static off_t xmpsf_get_size(XMPLAY_STREAMFILE* sf) {
return sf->xmpf_file->GetSize(sf->infile);
}
static off_t xmpsf_get_offset(XMPLAY_STREAMFILE* sf) {
return sf->xmpf_file->Tell(sf->infile);
}
static void xmpsf_get_name(XMPLAY_STREAMFILE* sf, char* buffer, size_t length) {
snprintf(buffer, length, "%s", sf->name);
buffer[length - 1] = '\0';
}
static STREAMFILE* xmpsf_open(XMPLAY_STREAMFILE* sf, const char* const filename, size_t buffersize) {
XMPFILE newfile;
if (!filename)
return NULL;
newfile = sf->xmpf_file->Open(filename);
if (!newfile) return NULL;
return open_xmplay_streamfile_by_xmpfile(newfile, sf->xmpf_file, filename, true); /* internal XMPFILE */
}
static void xmpsf_close(XMPLAY_STREAMFILE* sf) {
/* Close XMPFILE, but only if we opened it (ex. for subfiles inside metas).
* Otherwise must be left open as other parts of XMPlay need it and would crash. */
if (sf->internal_xmpfile) {
sf->xmpf_file->Close(sf->infile);
}
free(sf);
}
STREAMFILE* open_xmplay_streamfile_by_xmpfile(XMPFILE infile, XMPFUNC_FILE* xmpf_file, const char* path, bool internal) {
XMPLAY_STREAMFILE* this_sf = calloc(1, sizeof(XMPLAY_STREAMFILE));
if (!this_sf) return NULL;
this_sf->sf.read = (void*)xmpsf_read;
this_sf->sf.get_size = (void*)xmpsf_get_size;
this_sf->sf.get_offset = (void*)xmpsf_get_offset;
this_sf->sf.get_name = (void*)xmpsf_get_name;
this_sf->sf.open = (void*)xmpsf_open;
this_sf->sf.close = (void*)xmpsf_close;
this_sf->infile = infile;
this_sf->offset = 0;
snprintf(this_sf->name, sizeof(this_sf->name), "%s", path);
this_sf->name[sizeof(this_sf->name) - 1] = '\0';
this_sf->internal_xmpfile = internal;
this_sf->xmpf_file = xmpf_file;
return &this_sf->sf; /* pointer to STREAMFILE start = rest of the custom data follows */
}

262
xmplay/xmp_utils.c Normal file
View File

@ -0,0 +1,262 @@
#include "xmp_vgmstream.h"
/* with <v3.8.5.62, any more than ~1000 will crash XMplay's file list screen. */
#define EXTENSION_LIST_SIZE_OLD 1000
#define EXTENSION_LIST_SIZE_OLD_VERSION 0x0308053d /* less than v3.8.5.62 */
/* Adds ext to XMPlay's extension list. */
static int add_extension(int length, char * dst, const char * ext) {
int ext_len;
int i;
if (length <= 1)
return 0;
ext_len = strlen(ext);
/* check if end reached or not enough room to add */
if (ext_len+2 > length-2) {
dst[0]='\0';
return 0;
}
/* copy new extension + null terminate */
for (i=0; i < ext_len; i++)
dst[i] = ext[i];
dst[i]='/';
dst[i+1]='\0';
return i+1;
}
/* Creates XMPlay's extension list, a single string with 2 nulls.
* Extensions must be in this format: "Description\0extension1/.../extensionN" */
void build_extension_list(char* extension_list, int list_size, DWORD version) {
const char ** ext_list;
size_t ext_list_len;
int i, written;
int limit_old = EXTENSION_LIST_SIZE_OLD;
int limit = list_size;
if (limit > limit_old && version <= EXTENSION_LIST_SIZE_OLD_VERSION)
limit = limit_old;
written = sprintf(extension_list, "%s%c", "vgmstream files",'\0');
ext_list = vgmstream_get_formats(&ext_list_len);
for (i=0; i < ext_list_len; i++) {
written += add_extension(limit-written, extension_list + written, ext_list[i]);
}
extension_list[written-1] = '\0'; /* remove last "/" */
}
/* Get tags as an array of "key\0value\0", NULL-terminated.
* Processes tags from the path alone (expects folders to be named in a particular way),
* so of limited usefulness. */
char* get_tags_from_filepath_info(VGMSTREAM* infostream, XMPFUNC_MISC* xmpf_misc, const char* filepath) {
char* tags;
int pos = 0;
tags = xmpf_misc->Alloc(1024);
memset(tags, 0x00, 1024);
if (strlen(infostream->stream_name) > 0) {
memcpy(tags + pos, "title", 5);
pos += 6;
memcpy(tags + pos, infostream->stream_name, strlen(infostream->stream_name));
pos += strlen(infostream->stream_name) + 1;
}
const char* end;
const char* start = NULL;
int j = 2;
for (const char* i = filepath + strlen(filepath); i > filepath; i--)
{
if ((*i == '\\') && (j == 1))
{
start = i + 1;
j--;
break;
}
if ((*i == '\\') && (j == 2))
{
end = i;
j--;
}
}
//run some sanity checks
int brace_curly = 0, brace_square = 0;
char check_ok = 0;
for (const char* i = filepath; *i != 0; i++)
{
if (*i == '(')
brace_curly++;
if (*i == ')')
brace_curly--;
if (*i == '[')
brace_square++;
if (*i == ']')
brace_square--;
if (brace_curly > 1 || brace_curly < -1 || brace_square > 1 || brace_square < -1)
break;
}
if (brace_square == 0 && brace_curly == 0)
check_ok = 1;
if (start != NULL && strstr(filepath, "\\VGMPP\\") != NULL && check_ok == 1 && strchr(start, '(') != NULL)
{
char tagline[1024];
memset(tagline, 0x00, sizeof(tagline));
strncpy(tagline, start, end - start);
char* alttitle_st;
char* alttitle_ed;
char* album_st;
char* album_ed;
char* company_st;
char* company_ed;
char* company2_st;
char* company2_ed;
char* date_st;
char* date_ed;
char* platform_st;
char* platform_ed;
if (strchr(tagline, '[') != NULL) //either alternative title or platform usually
{
alttitle_st = strchr(tagline, '[') + 1;
alttitle_ed = strchr(alttitle_st, ']');
if (strchr(alttitle_st, '[') != NULL && strchr(alttitle_st, '[') > strchr(alttitle_st, '(')) //both might be present actually
{
platform_st = strchr(alttitle_st, '[') + 1;
platform_ed = strchr(alttitle_ed + 1, ']');
}
else
{
platform_st = NULL;
platform_ed = NULL;
}
}
else
{
platform_st = NULL;
platform_ed = NULL;
alttitle_st = NULL;
alttitle_ed = NULL;
}
album_st = tagline;
if (strchr(tagline, '(') < alttitle_st && alttitle_st != NULL) //square braces after curly braces -- platform
{
platform_st = alttitle_st;
platform_ed = alttitle_ed;
alttitle_st = NULL;
alttitle_ed = NULL;
album_ed = strchr(tagline, '('); //get normal title for now
}
else if (alttitle_st != NULL)
album_ed = strchr(tagline, '[');
else
album_ed = strchr(tagline, '(');
date_st = strchr(album_ed, '(') + 1; //first string in curly braces is usualy release date, I have one package with platform name there
if (date_st == NULL)
date_ed = NULL;
if (date_st[0] >= 0x30 && date_st[0] <= 0x39 && date_st[1] >= 0x30 && date_st[1] <= 0x39) //check if it contains 2 digits
{
date_ed = strchr(date_st, ')');
}
else //platform?
{
platform_st = date_st;
platform_ed = strchr(date_st, ')');
date_st = strchr(platform_ed, '(') + 1;
date_ed = strchr(date_st, ')');
}
company_st = strchr(date_ed, '(') + 1; //company name follows date
if (company_st != NULL)
{
company_ed = strchr(company_st, ')');
if (strchr(company_ed, '(') != NULL)
{
company2_st = strchr(company_ed, '(') + 1;
company2_ed = strchr(company2_st, ')');
}
else
{
company2_st = NULL;
company2_ed = NULL;
}
}
else
{
company_st = NULL;
company_ed = NULL;
company2_st = NULL;
company2_ed = NULL;
}
if (alttitle_st != NULL) //prefer alternative title, which is usually japanese
{
memcpy(tags + pos, "album", 5);
pos += 6;
memcpy(tags + pos, alttitle_st, alttitle_ed - alttitle_st);
pos += alttitle_ed - alttitle_st + 1;
}
else
{
memcpy(tags + pos, "album", 5);
pos += 6;
memcpy(tags + pos, album_st, album_ed - album_st);
pos += album_ed - album_st + 1;
}
if (date_st != NULL)
{
memcpy(tags + pos, "date", 4);
pos += 5;
memcpy(tags + pos, date_st, date_ed - date_st);
pos += date_ed - date_st + 1;
}
if (date_st != NULL)
{
memcpy(tags + pos, "genre", 5);
pos += 6;
memcpy(tags + pos, platform_st, platform_ed - platform_st);
pos += platform_ed - platform_st + 1;
}
if (company_st != NULL)
{
char combuf[256];
memset(combuf, 0x00, sizeof(combuf));
char tmp[128];
memset(tmp, 0x00, sizeof(tmp));
memcpy(tmp, company_st, company_ed - company_st);
if (company2_st != NULL)
{
char tmp2[128];
memset(tmp2, 0x00, sizeof(tmp2));
memcpy(tmp2, company2_st, company2_ed - company2_st);
sprintf(combuf, "\r\n\r\nDeveloper\t%s\r\nPublisher\t%s", tmp, tmp2);
}
else
sprintf(combuf, "\r\n\r\nDeveloper\t%s", tmp);
memcpy(tags + pos, "comment", 7);
pos += 8;
memcpy(tags + pos, combuf, strlen(combuf));
pos += strlen(combuf) + 1;
}
}
return tags; /* assuming XMPlay free()s this, since it Alloc()s it */
}

View File

@ -11,10 +11,7 @@
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include "xmpin.h" #include "xmp_vgmstream.h"
#include "../src/vgmstream.h"
#include "../src/api.h"
#include "../version.h" #include "../version.h"
#ifndef VGMSTREAM_VERSION #ifndef VGMSTREAM_VERSION
@ -28,20 +25,19 @@
#define SAMPLE_BUFFER_SIZE 1024 #define SAMPLE_BUFFER_SIZE 1024
/* XMPlay extension list, only needed to associate extensions in Windows */
/* with <v3.8.5.62, any more than ~1000 will crash XMplay's file list screen. */
#define EXTENSION_LIST_SIZE (0x2000 * 6)
#define EXTENSION_LIST_SIZE_OLD 1000
#define EXTENSION_LIST_SIZE_OLD_VERSION 0x0308053d /* less than v3.8.5.62 */
#define XMPLAY_MAX_PATH 32768 #define XMPLAY_MAX_PATH 32768
/* XMPlay function library */ /* XMPlay function library */
static XMPFUNC_IN *xmpfin; static XMPFUNC_IN* xmpf_in;
static XMPFUNC_MISC *xmpfmisc; static XMPFUNC_MISC* xmpf_misc;
static XMPFUNC_FILE *xmpffile; static XMPFUNC_FILE* xmpf_file;
/* XMPlay extension list, only needed to associate extensions in Windows */
#define EXTENSION_LIST_SIZE (0x2000 * 6)
char working_extension_list[EXTENSION_LIST_SIZE] = {0}; char working_extension_list[EXTENSION_LIST_SIZE] = {0};
char filepath[MAX_PATH];
char last_filepath[MAX_PATH] = {0};
/* plugin config */ /* plugin config */
double fade_seconds = 10.0; double fade_seconds = 10.0;
@ -66,96 +62,11 @@ static int shownerror = 0; /* init error */
/* ************************************* */ /* ************************************* */
/* a STREAMFILE that operates via XMPlay's XMPFUNC_FILE+XMPFILE */
typedef struct _XMPLAY_STREAMFILE {
STREAMFILE sf; /* callbacks */
XMPFILE infile; /* actual FILE */
char name[PATH_LIMIT];
off_t offset; /* current offset */
int internal_xmpfile; /* infile was not supplied externally and can be closed */
} XMPLAY_STREAMFILE;
static STREAMFILE* open_xmplay_streamfile_by_xmpfile(XMPFILE file, const char* path, int internal);
static size_t xmpsf_read(XMPLAY_STREAMFILE* sf, uint8_t* dst, offv_t offset, size_t length) {
size_t read;
if (sf->offset != offset) {
if (xmpffile->Seek(sf->infile, offset))
sf->offset = offset;
else
sf->offset = xmpffile->Tell(sf->infile);
}
read = xmpffile->Read(sf->infile, dst, length);
if (read > 0)
sf->offset += read;
return read;
}
static off_t xmpsf_get_size(XMPLAY_STREAMFILE* sf) {
return xmpffile->GetSize(sf->infile);
}
static off_t xmpsf_get_offset(XMPLAY_STREAMFILE* sf) {
return xmpffile->Tell(sf->infile);
}
static void xmpsf_get_name(XMPLAY_STREAMFILE* sf, char* buffer, size_t length) {
strncpy(buffer, sf->name, length);
buffer[length-1] = '\0';
}
static STREAMFILE* xmpsf_open(XMPLAY_STREAMFILE* sf, const char* const filename, size_t buffersize) {
XMPFILE newfile;
if (!filename)
return NULL;
newfile = xmpffile->Open(filename);
if (!newfile) return NULL;
strncpy(filepath, filename, MAX_PATH);
filepath[MAX_PATH - 1] = 0x00;
return open_xmplay_streamfile_by_xmpfile(newfile, filename, 1); /* internal XMPFILE */
}
static void xmpsf_close(XMPLAY_STREAMFILE* sf) {
/* Close XMPFILE, but only if we opened it (ex. for subfiles inside metas).
* Otherwise must be left open as other parts of XMPlay need it and would crash. */
if (sf->internal_xmpfile) {
xmpffile->Close(sf->infile);
}
free(sf);
}
static STREAMFILE* open_xmplay_streamfile_by_xmpfile(XMPFILE infile, const char* path, int internal) {
XMPLAY_STREAMFILE* this_sf = calloc(1, sizeof(XMPLAY_STREAMFILE));
if (!this_sf) return NULL;
this_sf->sf.read = (void*)xmpsf_read;
this_sf->sf.get_size = (void*)xmpsf_get_size;
this_sf->sf.get_offset = (void*)xmpsf_get_offset;
this_sf->sf.get_name = (void*)xmpsf_get_name;
this_sf->sf.open = (void*)xmpsf_open;
this_sf->sf.close = (void*)xmpsf_close;
this_sf->infile = infile;
this_sf->offset = 0;
strncpy(this_sf->name, path, sizeof(this_sf->name));
this_sf->internal_xmpfile = internal;
return &this_sf->sf; /* pointer to STREAMFILE start = rest of the custom data follows */
}
VGMSTREAM* init_vgmstream_xmplay(XMPFILE infile, const char* path, int subsong) { VGMSTREAM* init_vgmstream_xmplay(XMPFILE infile, const char* path, int subsong) {
STREAMFILE* sf = NULL; STREAMFILE* sf = NULL;
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
sf = open_xmplay_streamfile_by_xmpfile(infile, path, 0); /* external XMPFILE */ sf = open_xmplay_streamfile_by_xmpfile(infile, xmpf_file, path, false); /* external XMPFILE */
if (!sf) return NULL; if (!sf) return NULL;
sf->stream_index = subsong; sf->stream_index = subsong;
@ -184,259 +95,6 @@ static void apply_config(VGMSTREAM* vgmstream) {
vgmstream_apply_config(vgmstream, &vcfg); vgmstream_apply_config(vgmstream, &vcfg);
} }
/* get the tags as an array of "key\0value\0", NULL-terminated */
static char *get_tags(VGMSTREAM * infostream) {
char* tags;
int pos = 0;
tags = xmpfmisc->Alloc(1024);
memset(tags, 0x00, 1024);
if (infostream->stream_name != NULL && strlen(infostream->stream_name) > 0)
{
memcpy(tags + pos, "title", 5);
pos += 6;
memcpy(tags + pos, infostream->stream_name, strlen(infostream->stream_name));
pos += strlen(infostream->stream_name) + 1;
}
char* end;
char* start = NULL;
int j = 2;
for (char* i = filepath+strlen(filepath); i > filepath; i--)
{
if ((*i == '\\') && (j == 1))
{
start = i + 1;
j--;
break;
}
if ((*i == '\\') && (j == 2))
{
end = i;
j--;
}
}
//run some sanity checks
int brace_curly = 0, brace_square = 0;
char check_ok = 0;
for (char* i = filepath; *i != 0; i++)
{
if (*i == '(')
brace_curly++;
if (*i == ')')
brace_curly--;
if (*i == '[')
brace_square++;
if (*i == ']')
brace_square--;
if (brace_curly > 1 || brace_curly < -1 || brace_square > 1 || brace_square < -1)
break;
}
if (brace_square == 0 && brace_curly == 0)
check_ok = 1;
if (start != NULL && strstr(filepath, "\\VGMPP\\") != NULL && check_ok == 1 && strchr(start, '(') != NULL)
{
char tagline[1024];
memset(tagline, 0x00, sizeof(tagline));
strncpy(tagline, start, end - start);
char* alttitle_st;
char* alttitle_ed;
char* album_st;
char* album_ed;
char* company_st;
char* company_ed;
char* company2_st;
char* company2_ed;
char* date_st;
char* date_ed;
char* platform_st;
char* platform_ed;
if (strchr(tagline, '[') != NULL) //either alternative title or platform usually
{
alttitle_st = strchr(tagline, '[') + 1;
alttitle_ed = strchr(alttitle_st, ']');
if (strchr(alttitle_st, '[') != NULL && strchr(alttitle_st, '[') > strchr(alttitle_st, '(')) //both might be present actually
{
platform_st = strchr(alttitle_st, '[') + 1;
platform_ed = strchr(alttitle_ed + 1, ']');
}
else
{
platform_st = NULL;
platform_ed = NULL;
}
}
else
{
platform_st = NULL;
platform_ed = NULL;
alttitle_st = NULL;
alttitle_ed = NULL;
}
album_st = tagline;
if (strchr(tagline, '(') < alttitle_st && alttitle_st != NULL) //square braces after curly braces -- platform
{
platform_st = alttitle_st;
platform_ed = alttitle_ed;
alttitle_st = NULL;
alttitle_ed = NULL;
album_ed = strchr(tagline, '('); //get normal title for now
}
else if (alttitle_st != NULL)
album_ed = strchr(tagline, '[');
else
album_ed = strchr(tagline, '(');
date_st = strchr(album_ed, '(') + 1; //first string in curly braces is usualy release date, I have one package with platform name there
if (date_st == NULL)
date_ed = NULL;
if (date_st[0] >= 0x30 && date_st[0] <= 0x39 && date_st[1] >= 0x30 && date_st[1] <= 0x39) //check if it contains 2 digits
{
date_ed = strchr(date_st, ')');
}
else //platform?
{
platform_st = date_st;
platform_ed = strchr(date_st, ')');
date_st = strchr(platform_ed, '(') + 1;
date_ed = strchr(date_st, ')');
}
company_st = strchr(date_ed, '(') + 1; //company name follows date
if (company_st != NULL)
{
company_ed = strchr(company_st, ')');
if (strchr(company_ed, '(') != NULL)
{
company2_st = strchr(company_ed, '(') + 1;
company2_ed = strchr(company2_st, ')');
}
else
{
company2_st = NULL;
company2_ed = NULL;
}
}
else
{
company_st = NULL;
company_ed = NULL;
company2_st = NULL;
company2_ed = NULL;
}
if (alttitle_st != NULL) //prefer alternative title, which is usually japanese
{
memcpy(tags + pos, "album", 5);
pos += 6;
memcpy(tags + pos, alttitle_st, alttitle_ed - alttitle_st);
pos += alttitle_ed - alttitle_st + 1;
}
else
{
memcpy(tags + pos, "album", 5);
pos += 6;
memcpy(tags + pos, album_st, album_ed - album_st);
pos += album_ed - album_st + 1;
}
if (date_st != NULL)
{
memcpy(tags + pos, "date", 4);
pos += 5;
memcpy(tags + pos, date_st, date_ed - date_st);
pos += date_ed - date_st + 1;
}
if (date_st != NULL)
{
memcpy(tags + pos, "genre", 5);
pos += 6;
memcpy(tags + pos, platform_st, platform_ed - platform_st);
pos += platform_ed - platform_st + 1;
}
if (company_st != NULL)
{
char combuf[256];
memset(combuf, 0x00, sizeof(combuf));
char tmp[128];
memset(tmp, 0x00, sizeof(tmp));
memcpy(tmp, company_st, company_ed - company_st);
if (company2_st != NULL)
{
char tmp2[128];
memset(tmp2, 0x00, sizeof(tmp2));
memcpy(tmp2, company2_st, company2_ed - company2_st);
sprintf(combuf, "\r\n\r\nDeveloper\t%s\r\nPublisher\t%s", tmp, tmp2);
}
else
sprintf(combuf, "\r\n\r\nDeveloper\t%s", tmp);
memcpy(tags + pos, "comment", 7);
pos += 8;
memcpy(tags + pos, combuf, strlen(combuf));
pos += strlen(combuf) + 1;
}
}
return tags; /* assuming XMPlay free()s this, since it Alloc()s it */
}
/* Adds ext to XMPlay's extension list. */
static int add_extension(int length, char * dst, const char * ext) {
int ext_len;
int i;
if (length <= 1)
return 0;
ext_len = strlen(ext);
/* check if end reached or not enough room to add */
if (ext_len+2 > length-2) {
dst[0]='\0';
return 0;
}
/* copy new extension + null terminate */
for (i=0; i < ext_len; i++)
dst[i] = ext[i];
dst[i]='/';
dst[i+1]='\0';
return i+1;
}
/* Creates XMPlay's extension list, a single string with 2 nulls.
* Extensions must be in this format: "Description\0extension1/.../extensionN" */
static void build_extension_list() {
const char ** ext_list;
size_t ext_list_len;
int i, written;
int limit = EXTENSION_LIST_SIZE;
if (xmpfmisc->GetVersion() <= EXTENSION_LIST_SIZE_OLD_VERSION)
limit = EXTENSION_LIST_SIZE_OLD;
written = sprintf(working_extension_list, "%s%c", "vgmstream files",'\0');
ext_list = vgmstream_get_formats(&ext_list_len);
for (i=0; i < ext_list_len; i++) {
written += add_extension(limit-written, working_extension_list + written, ext_list[i]);
}
working_extension_list[written-1] = '\0'; /* remove last "/" */
}
/* ************************************* */ /* ************************************* */
/* info for the "about" button in plugin options */ /* info for the "about" button in plugin options */
@ -487,6 +145,11 @@ DWORD WINAPI xmplay_GetFileInfo(const char *filename, XMPFILE file, float **leng
if (!infostream) if (!infostream)
return 0; return 0;
char temp_filepath[MAX_PATH];
snprintf(temp_filepath, sizeof(temp_filepath), "%s", filename);
temp_filepath[sizeof(temp_filepath) - 1] = '\0';
apply_config(infostream); apply_config(infostream);
//vgmstream_mixing_autodownmix(infostream, downmix_channels); //vgmstream_mixing_autodownmix(infostream, downmix_channels);
@ -494,7 +157,7 @@ DWORD WINAPI xmplay_GetFileInfo(const char *filename, XMPFILE file, float **leng
if (length && infostream->sample_rate) { if (length && infostream->sample_rate) {
int length_samples = vgmstream_get_samples(infostream); int length_samples = vgmstream_get_samples(infostream);
float *lens = (float*)xmpfmisc->Alloc(sizeof(float)); float *lens = (float*)xmpf_misc->Alloc(sizeof(float));
lens[0] = (float)length_samples / (float)infostream->sample_rate; lens[0] = (float)length_samples / (float)infostream->sample_rate;
*length = lens; *length = lens;
} }
@ -503,7 +166,7 @@ DWORD WINAPI xmplay_GetFileInfo(const char *filename, XMPFILE file, float **leng
if (disable_subsongs || subsong_count == 0) if (disable_subsongs || subsong_count == 0)
subsong_count = 1; subsong_count = 1;
*tags = get_tags(infostream); *tags = get_tags_from_filepath_info(infostream, xmpf_misc, temp_filepath);
close_vgmstream(infostream); close_vgmstream(infostream);
return subsong_count; return subsong_count;
@ -518,6 +181,9 @@ DWORD WINAPI xmplay_Open(const char *filename, XMPFILE file) {
if (!vgmstream) if (!vgmstream)
return 0; return 0;
snprintf(last_filepath, sizeof(last_filepath), "%s", filename);
last_filepath[sizeof(last_filepath) - 1] = '\0';
apply_config(vgmstream); apply_config(vgmstream);
//vgmstream_mixing_autodownmix(vgmstream, downmix_channels); //vgmstream_mixing_autodownmix(vgmstream, downmix_channels);
@ -533,7 +199,7 @@ DWORD WINAPI xmplay_Open(const char *filename, XMPFILE file) {
if (length_samples) { if (length_samples) {
float length = (float)length_samples / (float)vgmstream->sample_rate; float length = (float)length_samples / (float)vgmstream->sample_rate;
xmpfin->SetLength(length, TRUE); xmpf_in->SetLength(length, TRUE);
} }
return 1; return 1;
@ -553,8 +219,8 @@ void WINAPI xmplay_SetFormat(XMPFORMAT *form) {
} }
/* get tags, return NULL to delay title update (OPTIONAL) */ /* get tags, return NULL to delay title update (OPTIONAL) */
char * WINAPI xmplay_GetTags() { char* WINAPI xmplay_GetTags() {
return get_tags(vgmstream); return get_tags_from_filepath_info(vgmstream, xmpf_misc, last_filepath);
} }
/* main panel info text (short file info) */ /* main panel info text (short file info) */
@ -677,7 +343,7 @@ double WINAPI xmplay_SetPosition(DWORD pos) {
/* decode some sample data */ /* decode some sample data */
DWORD WINAPI xmplay_Process(float* buf, DWORD bufsize) { DWORD WINAPI xmplay_Process(float* buf, DWORD bufsize) {
int32_t i, done, samples_to_do; int32_t i, done, samples_to_do;
BOOL do_loop = xmpfin->GetLooping(); BOOL do_loop = xmpf_in->GetLooping();
float *sbuf = buf; float *sbuf = buf;
@ -794,11 +460,12 @@ __declspec(dllexport) XMPIN* WINAPI XMPIN_GetInterface(UINT32 face, InterfacePr
return NULL; return NULL;
} }
xmpfin = (XMPFUNC_IN*)faceproc(XMPFUNC_IN_FACE); /* retrieval of xmp helpers */
xmpfmisc = (XMPFUNC_MISC*)faceproc(XMPFUNC_MISC_FACE); xmpf_in = (XMPFUNC_IN*)faceproc(XMPFUNC_IN_FACE);
xmpffile = (XMPFUNC_FILE*)faceproc(XMPFUNC_FILE_FACE); xmpf_misc = (XMPFUNC_MISC*)faceproc(XMPFUNC_MISC_FACE);
xmpf_file = (XMPFUNC_FILE*)faceproc(XMPFUNC_FILE_FACE);
build_extension_list(); build_extension_list(working_extension_list, sizeof(working_extension_list), xmpf_misc->GetVersion());
return &vgmstream_xmpin; return &vgmstream_xmpin;
} }

16
xmplay/xmp_vgmstream.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef _XMP_VGMSTREAM_
#define _XMP_VGMSTREAM_
#include "xmpin.h"
#include "xmpfunc.h"
#include "../src/vgmstream.h"
#include "../src/api.h"
STREAMFILE* open_xmplay_streamfile_by_xmpfile(XMPFILE infile, XMPFUNC_FILE* xmpf_file, const char* path, bool internal);
char* get_tags_from_filepath_info(VGMSTREAM* infostream, XMPFUNC_MISC* xmpf_misc, const char* filepath);
void build_extension_list(char* extension_list, int list_size, DWORD version);
#endif