Updated VGMStream to r1640-85-gfe316bb2
parent
fdae7eec21
commit
cb70b066d7
|
@ -586,6 +586,8 @@
|
||||||
83AFABBC23795202002F3947 /* xssb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AFABB923795201002F3947 /* xssb.c */; };
|
83AFABBC23795202002F3947 /* xssb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AFABB923795201002F3947 /* xssb.c */; };
|
||||||
83AFABBD23795202002F3947 /* ea_eaac_opus_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83AFABBA23795202002F3947 /* ea_eaac_opus_streamfile.h */; };
|
83AFABBD23795202002F3947 /* ea_eaac_opus_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 83AFABBA23795202002F3947 /* ea_eaac_opus_streamfile.h */; };
|
||||||
83AFABBE23795202002F3947 /* isb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AFABBB23795202002F3947 /* isb.c */; };
|
83AFABBE23795202002F3947 /* isb.c in Sources */ = {isa = PBXBuildFile; fileRef = 83AFABBB23795202002F3947 /* isb.c */; };
|
||||||
|
83B46FD12707FB2100847FC9 /* at3plus_decoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B46FCD2707FB2100847FC9 /* at3plus_decoder.h */; };
|
||||||
|
83B46FD52707FB9A00847FC9 /* endianness.h in Headers */ = {isa = PBXBuildFile; fileRef = 83B46FD42707FB9A00847FC9 /* endianness.h */; };
|
||||||
83BAFB6C19F45EB3005DAB60 /* bfstm.c in Sources */ = {isa = PBXBuildFile; fileRef = 83BAFB6B19F45EB3005DAB60 /* bfstm.c */; };
|
83BAFB6C19F45EB3005DAB60 /* bfstm.c in Sources */ = {isa = PBXBuildFile; fileRef = 83BAFB6B19F45EB3005DAB60 /* bfstm.c */; };
|
||||||
83C7280F22BC893D00678B4A /* xwb_xsb.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C727FB22BC893800678B4A /* xwb_xsb.h */; };
|
83C7280F22BC893D00678B4A /* xwb_xsb.h in Headers */ = {isa = PBXBuildFile; fileRef = 83C727FB22BC893800678B4A /* xwb_xsb.h */; };
|
||||||
83C7281022BC893D00678B4A /* nps.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C727FC22BC893900678B4A /* nps.c */; };
|
83C7281022BC893D00678B4A /* nps.c in Sources */ = {isa = PBXBuildFile; fileRef = 83C727FC22BC893900678B4A /* nps.c */; };
|
||||||
|
@ -1394,6 +1396,8 @@
|
||||||
83AFABB923795201002F3947 /* xssb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xssb.c; sourceTree = "<group>"; };
|
83AFABB923795201002F3947 /* xssb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xssb.c; sourceTree = "<group>"; };
|
||||||
83AFABBA23795202002F3947 /* ea_eaac_opus_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ea_eaac_opus_streamfile.h; sourceTree = "<group>"; };
|
83AFABBA23795202002F3947 /* ea_eaac_opus_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ea_eaac_opus_streamfile.h; sourceTree = "<group>"; };
|
||||||
83AFABBB23795202002F3947 /* isb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = isb.c; sourceTree = "<group>"; };
|
83AFABBB23795202002F3947 /* isb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = isb.c; sourceTree = "<group>"; };
|
||||||
|
83B46FCD2707FB2100847FC9 /* at3plus_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = at3plus_decoder.h; sourceTree = "<group>"; };
|
||||||
|
83B46FD42707FB9A00847FC9 /* endianness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = endianness.h; sourceTree = "<group>"; };
|
||||||
83BAFB6B19F45EB3005DAB60 /* bfstm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bfstm.c; sourceTree = "<group>"; };
|
83BAFB6B19F45EB3005DAB60 /* bfstm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bfstm.c; sourceTree = "<group>"; };
|
||||||
83C727FB22BC893800678B4A /* xwb_xsb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xwb_xsb.h; sourceTree = "<group>"; };
|
83C727FB22BC893800678B4A /* xwb_xsb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xwb_xsb.h; sourceTree = "<group>"; };
|
||||||
83C727FC22BC893900678B4A /* nps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nps.c; sourceTree = "<group>"; };
|
83C727FC22BC893900678B4A /* nps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nps.c; sourceTree = "<group>"; };
|
||||||
|
@ -1631,6 +1635,7 @@
|
||||||
836F6DE218BDC2180095E648 /* adx_decoder.c */,
|
836F6DE218BDC2180095E648 /* adx_decoder.c */,
|
||||||
8315958320FEC831007002F0 /* asf_decoder.c */,
|
8315958320FEC831007002F0 /* asf_decoder.c */,
|
||||||
8306B08120984517000302D4 /* at3plus_decoder.c */,
|
8306B08120984517000302D4 /* at3plus_decoder.c */,
|
||||||
|
83B46FCD2707FB2100847FC9 /* at3plus_decoder.h */,
|
||||||
830EBE0F2004655D0023AA10 /* atrac9_decoder.c */,
|
830EBE0F2004655D0023AA10 /* atrac9_decoder.c */,
|
||||||
834FE0B2215C798C000A5D3D /* celt_fsb_decoder.c */,
|
834FE0B2215C798C000A5D3D /* celt_fsb_decoder.c */,
|
||||||
83031EBF243C50A800C3F3E0 /* circus_decoder_lib_data.h */,
|
83031EBF243C50A800C3F3E0 /* circus_decoder_lib_data.h */,
|
||||||
|
@ -2253,6 +2258,7 @@
|
||||||
children = (
|
children = (
|
||||||
83D26A8026E66DC2001A9475 /* chunks.c */,
|
83D26A8026E66DC2001A9475 /* chunks.c */,
|
||||||
83D26A7E26E66DC2001A9475 /* chunks.h */,
|
83D26A7E26E66DC2001A9475 /* chunks.h */,
|
||||||
|
83B46FD42707FB9A00847FC9 /* endianness.h */,
|
||||||
83D26A7D26E66DC2001A9475 /* log.c */,
|
83D26A7D26E66DC2001A9475 /* log.c */,
|
||||||
83D26A7F26E66DC2001A9475 /* log.h */,
|
83D26A7F26E66DC2001A9475 /* log.h */,
|
||||||
8315868826F586F900803A3A /* m2_psb.c */,
|
8315868826F586F900803A3A /* m2_psb.c */,
|
||||||
|
@ -2319,6 +2325,7 @@
|
||||||
83E7FD6225EF2B0C00683FD2 /* tac_decoder_lib_ops.h in Headers */,
|
83E7FD6225EF2B0C00683FD2 /* tac_decoder_lib_ops.h in Headers */,
|
||||||
83AF2CCC26226BA500538240 /* encrypted_bgm_streamfile.h in Headers */,
|
83AF2CCC26226BA500538240 /* encrypted_bgm_streamfile.h in Headers */,
|
||||||
8349A90F1FE6258200E26435 /* aix_streamfile.h in Headers */,
|
8349A90F1FE6258200E26435 /* aix_streamfile.h in Headers */,
|
||||||
|
83B46FD52707FB9A00847FC9 /* endianness.h in Headers */,
|
||||||
836F705718BDC2190095E648 /* util.h in Headers */,
|
836F705718BDC2190095E648 /* util.h in Headers */,
|
||||||
83C7282722BC8C1500678B4A /* plugins.h in Headers */,
|
83C7282722BC8C1500678B4A /* plugins.h in Headers */,
|
||||||
834FE0ED215C79ED000A5D3D /* fsb_interleave_streamfile.h in Headers */,
|
834FE0ED215C79ED000A5D3D /* fsb_interleave_streamfile.h in Headers */,
|
||||||
|
@ -2333,6 +2340,7 @@
|
||||||
8306B0E020984590000302D4 /* ppst_streamfile.h in Headers */,
|
8306B0E020984590000302D4 /* ppst_streamfile.h in Headers */,
|
||||||
83AA7F722519BFEA004C5298 /* vorbis_bitreader.h in Headers */,
|
83AA7F722519BFEA004C5298 /* vorbis_bitreader.h in Headers */,
|
||||||
834FE0BA215C798C000A5D3D /* ea_mt_decoder_utk.h in Headers */,
|
834FE0BA215C798C000A5D3D /* ea_mt_decoder_utk.h in Headers */,
|
||||||
|
83B46FD12707FB2100847FC9 /* at3plus_decoder.h in Headers */,
|
||||||
835C883722CC17BE001B4B3F /* ogg_vorbis_streamfile.h in Headers */,
|
835C883722CC17BE001B4B3F /* ogg_vorbis_streamfile.h in Headers */,
|
||||||
837CEAFE23487F2C00E62A4A /* jstm_streamfile.h in Headers */,
|
837CEAFE23487F2C00E62A4A /* jstm_streamfile.h in Headers */,
|
||||||
832BF82021E0514B006F50F1 /* zsnd_streamfile.h in Headers */,
|
832BF82021E0514B006F50F1 /* zsnd_streamfile.h in Headers */,
|
||||||
|
|
|
@ -3,14 +3,7 @@
|
||||||
|
|
||||||
#ifdef VGM_USE_MAIATRAC3PLUS
|
#ifdef VGM_USE_MAIATRAC3PLUS
|
||||||
#include "maiatrac3plus.h"
|
#include "maiatrac3plus.h"
|
||||||
|
#include "at3plus_decoder.h"
|
||||||
struct maiatrac3plus_codec_data {
|
|
||||||
sample_t* buffer;
|
|
||||||
int channels;
|
|
||||||
int samples_discard;
|
|
||||||
void* handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
maiatrac3plus_codec_data *init_at3plus() {
|
maiatrac3plus_codec_data *init_at3plus() {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef _AT3PLUS_DECODER_H
|
||||||
|
#define _AT3PLUS_DECODER_H
|
||||||
|
|
||||||
|
struct maiatrac3plus_codec_data {
|
||||||
|
sample_t* buffer;
|
||||||
|
int channels;
|
||||||
|
int samples_discard;
|
||||||
|
void* handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -680,7 +680,7 @@ size_t atrac3plus_bytes_to_samples(size_t bytes, int full_block_align);
|
||||||
size_t ac3_bytes_to_samples(size_t bytes, int full_block_align, int channels);
|
size_t ac3_bytes_to_samples(size_t bytes, int full_block_align, int channels);
|
||||||
size_t aac_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes);
|
size_t aac_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes);
|
||||||
size_t mpeg_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes);
|
size_t mpeg_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes);
|
||||||
int32_t mpeg_get_samples_clean(STREAMFILE* sf, off_t start, size_t size, size_t* p_loop_start, size_t* p_loop_end, int is_vbr);
|
int32_t mpeg_get_samples_clean(STREAMFILE* sf, off_t start, size_t size, uint32_t* p_loop_start, uint32_t* p_loop_end, int is_vbr);
|
||||||
int mpc_get_samples(STREAMFILE* sf, off_t offset, int32_t* p_samples, int32_t* p_delay);
|
int mpc_get_samples(STREAMFILE* sf, off_t offset, int32_t* p_samples, int32_t* p_delay);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ struct ffmpeg_codec_data {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define FFMPEG_DEFAULT_IO_BUFFER_SIZE 128 * 1024
|
#define FFMPEG_DEFAULT_IO_BUFFER_SIZE STREAMFILE_DEFAULT_BUFFER_SIZE
|
||||||
|
|
||||||
static volatile int g_ffmpeg_initialized = 0;
|
static volatile int g_ffmpeg_initialized = 0;
|
||||||
|
|
||||||
|
@ -322,7 +322,7 @@ ffmpeg_codec_data* init_ffmpeg_header_offset_subsong(STREAMFILE* sf, uint8_t* he
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (size == 0 || start + size > get_streamfile_size(sf)) {
|
if (size == 0 || start + size > get_streamfile_size(sf)) {
|
||||||
vgm_asserti(size != 0, "FFMPEG: wrong start+size found: %x + %x > %x \n", (uint32_t)start, (uint32_t)size, get_streamfile_size(sf));
|
vgm_asserti(size != 0, "FFMPEG: wrong start+size found: %x + %x > %x \n", (uint32_t)start, (uint32_t)size, (uint32_t)get_streamfile_size(sf));
|
||||||
size = get_streamfile_size(sf) - start;
|
size = get_streamfile_size(sf) - start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -451,7 +451,7 @@ size_t mpeg_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes) {
|
||||||
|
|
||||||
/* variation of the above, for clean streams = no ID3/VBR headers
|
/* variation of the above, for clean streams = no ID3/VBR headers
|
||||||
* (maybe should be fused in a single thing with config, API is kinda messy too) */
|
* (maybe should be fused in a single thing with config, API is kinda messy too) */
|
||||||
int32_t mpeg_get_samples_clean(STREAMFILE *sf, off_t start, size_t size, size_t* p_loop_start, size_t* p_loop_end, int is_vbr) {
|
int32_t mpeg_get_samples_clean(STREAMFILE* sf, off_t start, size_t size, uint32_t* p_loop_start, uint32_t* p_loop_end, int is_vbr) {
|
||||||
mpeg_frame_info info;
|
mpeg_frame_info info;
|
||||||
off_t offset = start;
|
off_t offset = start;
|
||||||
int32_t num_samples = 0, loop_start = 0, loop_end = 0;
|
int32_t num_samples = 0, loop_start = 0, loop_end = 0;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#include "vorbis_custom_decoder.h"
|
#include "vorbis_custom_decoder.h"
|
||||||
|
|
||||||
|
#ifdef VGM_USE_VORBIS
|
||||||
#define BITSTREAM_READ_ONLY /* config */
|
#define BITSTREAM_READ_ONLY /* config */
|
||||||
#include "vorbis_bitreader.h"
|
#include "vorbis_bitreader.h"
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
#include <vorbis/codec.h>
|
#include <vorbis/codec.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "vorbis_custom_decoder.h"
|
#include "vorbis_custom_decoder.h"
|
||||||
#include "vorbis_bitreader.h"
|
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
#ifdef VGM_USE_VORBIS
|
||||||
|
#include "vorbis_bitreader.h"
|
||||||
#include <vorbis/codec.h>
|
#include <vorbis/codec.h>
|
||||||
|
|
||||||
#define WWISE_VORBIS_USE_PRECOMPILED_WVC 1 /* if enabled vgmstream weights ~150kb more but doesn't need external .wvc packets */
|
#define WWISE_VORBIS_USE_PRECOMPILED_WVC 1 /* if enabled vgmstream weights ~150kb more but doesn't need external .wvc packets */
|
||||||
|
|
|
@ -4,6 +4,9 @@
|
||||||
#include "coding/coding.h"
|
#include "coding/coding.h"
|
||||||
#include "mixing.h"
|
#include "mixing.h"
|
||||||
#include "plugins.h"
|
#include "plugins.h"
|
||||||
|
#ifdef VGM_USE_MAIATRAC3PLUS
|
||||||
|
#include "at3plus_decoder.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* custom codec handling, not exactly "decode" stuff but here to simplify adding new codecs */
|
/* custom codec handling, not exactly "decode" stuff but here to simplify adding new codecs */
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,7 +11,7 @@
|
||||||
#define ADX_KEY_MAX_TEST_FRAMES 32768
|
#define ADX_KEY_MAX_TEST_FRAMES 32768
|
||||||
#define ADX_KEY_TEST_BUFFER_SIZE 0x8000
|
#define ADX_KEY_TEST_BUFFER_SIZE 0x8000
|
||||||
|
|
||||||
static int find_adx_key(STREAMFILE *sf, uint8_t type, uint16_t *xor_start, uint16_t *xor_mult, uint16_t *xor_add, uint16_t subkey);
|
static int find_adx_key(STREAMFILE* sf, uint8_t type, uint16_t* xor_start, uint16_t* xor_mult, uint16_t* xor_add, uint16_t subkey);
|
||||||
|
|
||||||
VGMSTREAM* init_vgmstream_adx(STREAMFILE* sf) {
|
VGMSTREAM* init_vgmstream_adx(STREAMFILE* sf) {
|
||||||
return init_vgmstream_adx_subkey(sf, 0);
|
return init_vgmstream_adx_subkey(sf, 0);
|
||||||
|
@ -34,14 +34,14 @@ VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) {
|
||||||
|
|
||||||
|
|
||||||
/* checks*/
|
/* checks*/
|
||||||
|
if (read_u16be(0x00,sf) != 0x8000)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* .adx: standard
|
/* .adx: standard
|
||||||
* .adp: Headhunter (DC) */
|
* .adp: Headhunter (DC) */
|
||||||
if (!check_extensions(sf,"adx,adp"))
|
if (!check_extensions(sf,"adx,adp"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (read_u16be(0x00,sf) != 0x8000)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
start_offset = read_u16be(0x02,sf) + 0x04;
|
start_offset = read_u16be(0x02,sf) + 0x04;
|
||||||
if (read_u16be(start_offset - 0x06,sf) != 0x2863 || /* "(c" */
|
if (read_u16be(start_offset - 0x06,sf) != 0x2863 || /* "(c" */
|
||||||
read_u32be(start_offset - 0x04,sf) != 0x29435249) /* ")CRI" */
|
read_u32be(start_offset - 0x04,sf) != 0x29435249) /* ")CRI" */
|
||||||
|
@ -79,18 +79,19 @@ VGMSTREAM* init_vgmstream_adx_subkey(STREAMFILE* sf, uint16_t subkey) {
|
||||||
|
|
||||||
/* encryption */
|
/* encryption */
|
||||||
if (version == 0x0408) {
|
if (version == 0x0408) {
|
||||||
|
|
||||||
if (find_adx_key(sf, 8, &xor_start, &xor_mult, &xor_add, 0)) {
|
if (find_adx_key(sf, 8, &xor_start, &xor_mult, &xor_add, 0)) {
|
||||||
coding_type = coding_CRI_ADX_enc_8;
|
vgm_logi("ADX: decryption keystring not found\n");
|
||||||
version = 0x0400;
|
|
||||||
}
|
}
|
||||||
vgm_asserti(version != 0x0400, "ADX: decryption keystring not found\n");
|
coding_type = coding_CRI_ADX_enc_8;
|
||||||
|
version = 0x0400;
|
||||||
}
|
}
|
||||||
else if (version == 0x0409) {
|
else if (version == 0x0409) {
|
||||||
if (find_adx_key(sf, 9, &xor_start, &xor_mult, &xor_add, subkey)) {
|
if (find_adx_key(sf, 9, &xor_start, &xor_mult, &xor_add, subkey)) {
|
||||||
coding_type = coding_CRI_ADX_enc_9;
|
vgm_logi("ADX: decryption keycode not found\n");
|
||||||
version = 0x0400;
|
|
||||||
}
|
}
|
||||||
vgm_asserti(version != 0x0400, "ADX: decryption keycode not found\n");
|
coding_type = coding_CRI_ADX_enc_9;
|
||||||
|
version = 0x0400;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* version + extra data */
|
/* version + extra data */
|
||||||
|
|
|
@ -2,18 +2,17 @@
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
/* .AO - from AlphaOgg lib [Cloudphobia (PC), GEO ~The Sword Millennia~ Kasumi no Tani no Kaibutsu (PC)] */
|
/* .AO - from AlphaOgg lib [Cloudphobia (PC), GEO ~The Sword Millennia~ Kasumi no Tani no Kaibutsu (PC)] */
|
||||||
VGMSTREAM* init_vgmstream_ao(STREAMFILE *sf) {
|
VGMSTREAM* init_vgmstream_ao(STREAMFILE* sf) {
|
||||||
VGMSTREAM* vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
if (!check_extensions(sf,"ao"))
|
|
||||||
goto fail;
|
|
||||||
if (!is_id64be(0x00,sf, "ALPHAOGG"))
|
if (!is_id64be(0x00,sf, "ALPHAOGG"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
if (!check_extensions(sf,"ao"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
{
|
{
|
||||||
ogg_vorbis_meta_info_t ovmi = {0};
|
ogg_vorbis_meta_info_t ovmi = {0};
|
||||||
int sample_rate = read_u32le(0xF0, sf); /* Ogg header */
|
int sample_rate = read_u32le(0xF0, sf); /* Ogg header */
|
||||||
|
@ -29,9 +28,6 @@ VGMSTREAM* init_vgmstream_ao(STREAMFILE *sf) {
|
||||||
start_offset = 0xc8;
|
start_offset = 0xc8;
|
||||||
vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
goto fail;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
fail:
|
fail:
|
||||||
|
|
|
@ -10,7 +10,7 @@ VGMSTREAM* init_vgmstream_atsl(STREAMFILE* sf) {
|
||||||
int type, big_endian = 0, entries;
|
int type, big_endian = 0, entries;
|
||||||
uint32_t subfile_offset = 0, subfile_size = 0, header_size, entry_size;
|
uint32_t subfile_offset = 0, subfile_size = 0, header_size, entry_size;
|
||||||
|
|
||||||
VGMSTREAM* (*init_vgmstream)(STREAMFILE* sf) = NULL;
|
init_vgmstream_t init_vgmstream = NULL;
|
||||||
const char* fake_ext;
|
const char* fake_ext;
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,7 +47,6 @@ VGMSTREAM* init_vgmstream_atsl(STREAMFILE* sf) {
|
||||||
|
|
||||||
type = read_u16le(0x0c, sf);
|
type = read_u16le(0x0c, sf);
|
||||||
switch(type) {
|
switch(type) {
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
case 0x0100: /* KOVS */
|
case 0x0100: /* KOVS */
|
||||||
init_vgmstream = init_vgmstream_ogg_vorbis;
|
init_vgmstream = init_vgmstream_ogg_vorbis;
|
||||||
fake_ext = "kvs";
|
fake_ext = "kvs";
|
||||||
|
@ -58,7 +57,6 @@ VGMSTREAM* init_vgmstream_atsl(STREAMFILE* sf) {
|
||||||
fake_ext = "kvs";
|
fake_ext = "kvs";
|
||||||
entry_size = 0x3c;
|
entry_size = 0x3c;
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
case 0x0200: /* ATRAC3 */
|
case 0x0200: /* ATRAC3 */
|
||||||
init_vgmstream = init_vgmstream_riff;
|
init_vgmstream = init_vgmstream_riff;
|
||||||
fake_ext = "at3";
|
fake_ext = "at3";
|
||||||
|
|
|
@ -87,7 +87,7 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
|
||||||
VGMSTREAM* (*init_vgmstream_subkey)(STREAMFILE* sf, uint16_t subkey) = NULL;
|
VGMSTREAM* (*init_vgmstream_subkey)(STREAMFILE* sf, uint16_t subkey) = NULL;
|
||||||
const char* extension = NULL;
|
const char* extension = NULL;
|
||||||
|
|
||||||
if (read_u16be(subfile_offset, sf) == 0x8000) { /* (type 0=ADX) */
|
if (read_u16be(subfile_offset, sf) == 0x8000) { /* (type 0=ADX, also 3?) */
|
||||||
init_vgmstream_subkey = init_vgmstream_adx_subkey; /* Okami HD (PS4) */
|
init_vgmstream_subkey = init_vgmstream_adx_subkey; /* Okami HD (PS4) */
|
||||||
extension = "adx";
|
extension = "adx";
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
|
||||||
init_vgmstream = init_vgmstream_vag; /* Ukiyo no Roushi (Vita) */
|
init_vgmstream = init_vgmstream_vag; /* Ukiyo no Roushi (Vita) */
|
||||||
extension = "vag";
|
extension = "vag";
|
||||||
}
|
}
|
||||||
else if (is_id32be(subfile_offset,sf, "RIFF")) { /* (type 8=ATRAC3, 11=ATRAC9) */
|
else if (is_id32be(subfile_offset,sf, "RIFF")) { /* (type 8=ATRAC3, 11=ATRAC9, also 18=ATRAC9?) */
|
||||||
init_vgmstream = init_vgmstream_riff; /* Ukiyo no Roushi (Vita) */
|
init_vgmstream = init_vgmstream_riff; /* Ukiyo no Roushi (Vita) */
|
||||||
extension = "wav";
|
extension = "wav";
|
||||||
subfile_size = read_u32le(subfile_offset + 0x04,sf) + 0x08; /* padded size, use RIFF's */
|
subfile_size = read_u32le(subfile_offset + 0x04,sf) + 0x08; /* padded size, use RIFF's */
|
||||||
|
@ -111,7 +111,7 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
|
||||||
else if (read_u32be(subfile_offset + 0x08,sf) >= 8000 && read_u32be(subfile_offset + 0x08,sf) <= 48000 &&
|
else if (read_u32be(subfile_offset + 0x08,sf) >= 8000 && read_u32be(subfile_offset + 0x08,sf) <= 48000 &&
|
||||||
read_u16be(subfile_offset + 0x0e,sf) == 0 &&
|
read_u16be(subfile_offset + 0x0e,sf) == 0 &&
|
||||||
read_u32be(subfile_offset + 0x18,sf) == 2 &&
|
read_u32be(subfile_offset + 0x18,sf) == 2 &&
|
||||||
read_u32be(subfile_offset + 0x50,sf) == 0) { /* (type 13=DSP), probably should call some check function */
|
read_u32be(subfile_offset + 0x50,sf) == 0) { /* (type 13=DSP, also 4=Wii?, 5=NDS?), probably should call some check function */
|
||||||
init_vgmstream = init_vgmstream_ngc_dsp_std; /* Sonic: Lost World (WiiU) */
|
init_vgmstream = init_vgmstream_ngc_dsp_std; /* Sonic: Lost World (WiiU) */
|
||||||
extension = "dsp";
|
extension = "dsp";
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
|
||||||
extension = "m4a";
|
extension = "m4a";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else {
|
else { /* 12=XMA? */
|
||||||
vgm_logi("AWB: unknown codec (report)\n");
|
vgm_logi("AWB: unknown codec (report)\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,34 +2,31 @@
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
/* FWAV - Nintendo streams */
|
/* FWAV - Nintendo streams */
|
||||||
VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) {
|
VGMSTREAM* init_vgmstream_bfwav(STREAMFILE* sf) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
off_t info_offset, data_offset;
|
off_t info_offset, data_offset;
|
||||||
int channel_count, loop_flag, codec;
|
int channels, loop_flag, codec, sample_rate;
|
||||||
int big_endian;
|
int big_endian;
|
||||||
size_t interleave = 0;
|
size_t interleave = 0;
|
||||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||||
int nsmbu_flag = 0;
|
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
|
if (!is_id32be(0x00, sf, "FWAV"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* .bfwavnsmbu: fake extension to detect New Super Mario Bros U files with weird sample rate */
|
/* .bfwavnsmbu: fake extension to detect New Super Mario Bros U files with weird sample rate */
|
||||||
if (!check_extensions(streamFile, "bfwav,fwav,bfwavnsmbu"))
|
if (!check_extensions(sf, "bfwav,fwav,bfwavnsmbu"))
|
||||||
goto fail;
|
goto fail;
|
||||||
nsmbu_flag = check_extensions(streamFile, "bfwavnsmbu");
|
|
||||||
|
|
||||||
/* FWAV header */
|
/* BOM check */
|
||||||
if (read_32bitBE(0x00, streamFile) != 0x46574156) /* "FWAV" */
|
if (read_u16be(0x04, sf) == 0xFEFF) {
|
||||||
goto fail;
|
|
||||||
/* 0x06(2): header size (0x40), 0x08: version (0x00010200), 0x0c: file size 0x10(2): sections (2) */
|
|
||||||
|
|
||||||
if ((uint16_t)read_16bitBE(0x04, streamFile) == 0xFEFF) { /* BE BOM check */
|
|
||||||
read_32bit = read_32bitBE;
|
read_32bit = read_32bitBE;
|
||||||
read_16bit = read_16bitBE;
|
read_16bit = read_16bitBE;
|
||||||
big_endian = 1;
|
big_endian = 1;
|
||||||
} else if ((uint16_t)read_16bitBE(0x04, streamFile) == 0xFFFE) { /* LE BOM check */
|
} else if (read_u16be(0x04, sf) == 0xFFFE) {
|
||||||
read_32bit = read_32bitLE;
|
read_32bit = read_32bitLE;
|
||||||
read_16bit = read_16bitLE;
|
read_16bit = read_16bitLE;
|
||||||
big_endian = 0;
|
big_endian = 0;
|
||||||
|
@ -37,60 +34,74 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
info_offset = read_32bit(0x18, streamFile); /* 0x14(2): info mark (0x7000), 0x1c: info size */
|
/* FWAV header */
|
||||||
data_offset = read_32bit(0x24, streamFile); /* 0x20(2): data mark (0x7001), 0x28: data size */
|
/* 0x06(2): header size (0x40) */
|
||||||
|
/* 0x08: version (0x00010200) */
|
||||||
|
/* 0x0c: file size */
|
||||||
|
/* 0x10(2): sections (2) */
|
||||||
|
|
||||||
|
/* 0x14(2): info mark (0x7000) */
|
||||||
|
info_offset = read_32bit(0x18, sf);
|
||||||
|
/* 0x1c: info size */
|
||||||
|
|
||||||
|
/* 0x20(2): data mark (0x7001) */
|
||||||
|
data_offset = read_32bit(0x24, sf);
|
||||||
|
/* 0x28: data size */
|
||||||
|
|
||||||
/* INFO section */
|
/* INFO section */
|
||||||
if (read_32bitBE(info_offset, streamFile) != 0x494E464F) /* "INFO" */
|
if (!is_id32be(info_offset, sf, "INFO"))
|
||||||
goto fail;
|
goto fail;
|
||||||
codec = read_8bit(info_offset + 0x08, streamFile);
|
codec = read_u8(info_offset + 0x08, sf);
|
||||||
loop_flag = read_8bit(info_offset + 0x09, streamFile);
|
loop_flag = read_u8(info_offset + 0x09, sf);
|
||||||
channel_count = read_32bit(info_offset + 0x1C, streamFile);
|
sample_rate = read_32bit(info_offset + 0x0C, sf);
|
||||||
|
channels = read_32bit(info_offset + 0x1C, sf);
|
||||||
|
|
||||||
|
//TODO remove
|
||||||
|
if (check_extensions(sf, "bfwavnsmbu"))
|
||||||
|
sample_rate = 16000;
|
||||||
|
|
||||||
/* parse channel table */
|
/* parse channel table */
|
||||||
{
|
{
|
||||||
off_t channel1_info, data_start;
|
off_t channel1_info, data_start;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
channel1_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*0+0x04, streamFile);
|
channel1_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*0+0x04, sf);
|
||||||
data_start = read_32bit(channel1_info+0x04, streamFile); /* within "DATA" after 0x08 */
|
data_start = read_32bit(channel1_info+0x04, sf); /* within "DATA" after 0x08 */
|
||||||
|
|
||||||
/* channels use absolute offsets but should be ok as interleave */
|
/* channels use absolute offsets but should be ok as interleave */
|
||||||
interleave = 0;
|
interleave = 0;
|
||||||
if (channel_count > 1) {
|
if (channels > 1) {
|
||||||
off_t channel2_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*1+0x04, streamFile);
|
off_t channel2_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*1+0x04, sf);
|
||||||
interleave = read_32bit(channel2_info+0x04, streamFile) - data_start;
|
interleave = read_32bit(channel2_info+0x04, sf) - data_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
start_offset = data_offset + 0x08 + data_start;
|
start_offset = data_offset + 0x08 + data_start;
|
||||||
|
|
||||||
/* validate all channels just in case of multichannel with non-constant interleave */
|
/* validate all channels just in case of multichannel with non-constant interleave */
|
||||||
for (i = 0; i < channel_count; i++) {
|
for (i = 0; i < channels; i++) {
|
||||||
/* channel table, 0x00: flag (0x7100), 0x04: channel info offset */
|
/* channel table, 0x00: flag (0x7100), 0x04: channel info offset */
|
||||||
off_t channel_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*i+0x04, streamFile);
|
off_t channel_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*i+0x04, sf);
|
||||||
/* channel info, 0x00(2): flag (0x1f00), 0x04: offset, 0x08(2): ADPCM flag (0x0300), 0x0c: ADPCM offset */
|
/* channel info, 0x00(2): flag (0x1f00), 0x04: offset, 0x08(2): ADPCM flag (0x0300), 0x0c: ADPCM offset */
|
||||||
if ((uint16_t)read_16bit(channel_info+0x00, streamFile) != 0x1F00)
|
if ((uint16_t)read_16bit(channel_info+0x00, sf) != 0x1F00)
|
||||||
goto fail;
|
goto fail;
|
||||||
if (read_32bit(channel_info+0x04, streamFile) != data_start + interleave*i)
|
if (read_32bit(channel_info+0x04, sf) != data_start + interleave*i)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
vgmstream->sample_rate = read_32bit(info_offset + 0x0C, streamFile);
|
vgmstream->sample_rate = sample_rate;
|
||||||
if (nsmbu_flag)
|
|
||||||
vgmstream->sample_rate = 16000;
|
|
||||||
|
|
||||||
vgmstream->num_samples = read_32bit(info_offset + 0x14, streamFile);
|
vgmstream->num_samples = read_32bit(info_offset + 0x14, sf);
|
||||||
vgmstream->loop_start_sample = read_32bit(info_offset + 0x10, streamFile);
|
vgmstream->loop_start_sample = read_32bit(info_offset + 0x10, sf);
|
||||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||||
|
|
||||||
vgmstream->meta_type = meta_FWAV;
|
vgmstream->meta_type = meta_FWAV;
|
||||||
vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave;
|
vgmstream->layout_type = (channels == 1) ? layout_none : layout_interleave;
|
||||||
vgmstream->interleave_block_size = interleave;
|
vgmstream->interleave_block_size = interleave;
|
||||||
|
|
||||||
switch (codec) {
|
switch (codec) {
|
||||||
|
@ -110,9 +121,9 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
for (i = 0; i < vgmstream->channels; i++) {
|
for (i = 0; i < vgmstream->channels; i++) {
|
||||||
for (c = 0; c < 16; c++) {
|
for (c = 0; c < 16; c++) {
|
||||||
coef_header = info_offset + 0x1C + read_32bit(info_offset + 0x24 + (i*0x08), streamFile);
|
coef_header = info_offset + 0x1C + read_32bit(info_offset + 0x24 + (i*0x08), sf);
|
||||||
coef_offset = read_32bit(coef_header + 0x0c, streamFile) + coef_header;
|
coef_offset = read_32bit(coef_header + 0x0c, sf) + coef_header;
|
||||||
vgmstream->ch[i].adpcm_coef[c] = read_16bit(coef_offset + c*2, streamFile);
|
vgmstream->ch[i].adpcm_coef[c] = read_16bit(coef_offset + c*2, sf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,7 +134,7 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
|
||||||
goto fail;
|
goto fail;
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ VGMSTREAM* init_vgmstream_csb(STREAMFILE* sf) {
|
||||||
utf_context *utf_sdl = NULL;
|
utf_context *utf_sdl = NULL;
|
||||||
int total_subsongs, target_subsong = sf->stream_index;
|
int total_subsongs, target_subsong = sf->stream_index;
|
||||||
uint8_t fmt = 0;
|
uint8_t fmt = 0;
|
||||||
const char* stream_name;
|
const char* stream_name = NULL;
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
|
|
|
@ -38,9 +38,8 @@ VGMSTREAM* init_vgmstream_encrypted(STREAMFILE* sf) {
|
||||||
|
|
||||||
temp_sf = setup_ogg_vorbis_streamfile(sf, cfg);
|
temp_sf = setup_ogg_vorbis_streamfile(sf, cfg);
|
||||||
if (!temp_sf) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
vgmstream = init_vgmstream_ogg_vorbis(temp_sf);
|
vgmstream = init_vgmstream_ogg_vorbis(temp_sf);
|
||||||
#endif
|
|
||||||
close_streamfile(temp_sf);
|
close_streamfile(temp_sf);
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
|
|
||||||
|
|
||||||
/* FFDL - Matrix Software wrapper [Final Fantasy Dimensions (Android/iOS)] */
|
/* FFDL - Matrix Software wrapper [Final Fantasy Dimensions (Android/iOS)] */
|
||||||
VGMSTREAM * init_vgmstream_ffdl(STREAMFILE *sf) {
|
VGMSTREAM* init_vgmstream_ffdl(STREAMFILE* sf) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
STREAMFILE *temp_sf = NULL;
|
STREAMFILE* temp_sf = NULL;
|
||||||
int loop_flag = 0, is_ffdl = 0;
|
int loop_flag = 0, is_ffdl = 0;
|
||||||
int32_t num_samples = 0, loop_start_sample = 0, loop_end_sample = 0;
|
int32_t num_samples = 0, loop_start_sample = 0, loop_end_sample = 0;
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
|
@ -13,6 +13,10 @@ VGMSTREAM * init_vgmstream_ffdl(STREAMFILE *sf) {
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
|
if (!is_id32be(0x00,sf, "FFDL") &&
|
||||||
|
!is_id32be(0x00,sf, "mtxs"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* .ogg/logg: probable extension for Android
|
/* .ogg/logg: probable extension for Android
|
||||||
* .mp4/lmp4: probable extension for iOS
|
* .mp4/lmp4: probable extension for iOS
|
||||||
* .bin: iOS FFDL extension
|
* .bin: iOS FFDL extension
|
||||||
|
@ -24,16 +28,15 @@ VGMSTREAM * init_vgmstream_ffdl(STREAMFILE *sf) {
|
||||||
* Ogg/MP4 or "mtxs" w/ loops + Ogg/MP4, and may concatenate multiple of them
|
* Ogg/MP4 or "mtxs" w/ loops + Ogg/MP4, and may concatenate multiple of them
|
||||||
* (without size in sight), so they should be split externally first. */
|
* (without size in sight), so they should be split externally first. */
|
||||||
|
|
||||||
start_offset = 0x00;
|
|
||||||
|
|
||||||
/* may start with wrapper (not split) */
|
/* may start with wrapper (not split) */
|
||||||
if (read_u32be(0x00,sf) == 0x4646444C) { /* "FFDL" */
|
start_offset = 0x00;
|
||||||
|
if (is_id32be(0x00,sf, "FFDL")) {
|
||||||
is_ffdl = 1;
|
is_ffdl = 1;
|
||||||
start_offset += 0x04;
|
start_offset += 0x04;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* may start with sample info (split) or after "FFDL" */
|
/* may start with sample info (split) or after "FFDL" */
|
||||||
if (read_u32be(start_offset+0x00,sf) == 0x6D747873) { /* "mtxs" */
|
if (is_id32be(start_offset+0x00,sf, "mtxs")) {
|
||||||
is_ffdl = 1;
|
is_ffdl = 1;
|
||||||
|
|
||||||
num_samples = read_s32le(start_offset + 0x04,sf);
|
num_samples = read_s32le(start_offset + 0x04,sf);
|
||||||
|
@ -51,15 +54,11 @@ VGMSTREAM * init_vgmstream_ffdl(STREAMFILE *sf) {
|
||||||
file_size = get_streamfile_size(sf) - start_offset;
|
file_size = get_streamfile_size(sf) - start_offset;
|
||||||
|
|
||||||
if (read_u32be(start_offset + 0x00,sf) == 0x4F676753) { /* "OggS" */
|
if (read_u32be(start_offset + 0x00,sf) == 0x4F676753) { /* "OggS" */
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
temp_sf = setup_subfile_streamfile(sf, start_offset, file_size, "ogg");
|
temp_sf = setup_subfile_streamfile(sf, start_offset, file_size, "ogg");
|
||||||
if (!temp_sf) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
vgmstream = init_vgmstream_ogg_vorbis(temp_sf);
|
vgmstream = init_vgmstream_ogg_vorbis(temp_sf);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
#else
|
|
||||||
goto fail;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else if (read_u32be(start_offset + 0x04,sf) == 0x66747970) { /* "ftyp" after atom size */
|
else if (read_u32be(start_offset + 0x04,sf) == 0x66747970) { /* "ftyp" after atom size */
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
|
|
|
@ -18,10 +18,10 @@ typedef struct {
|
||||||
int32_t loop_end;
|
int32_t loop_end;
|
||||||
int loop_flag;
|
int loop_flag;
|
||||||
|
|
||||||
size_t sample_header_size;
|
uint32_t sample_header_size;
|
||||||
size_t name_table_size;
|
uint32_t name_table_size;
|
||||||
size_t sample_data_size;
|
uint32_t sample_data_size;
|
||||||
size_t base_header_size;
|
uint32_t base_header_size;
|
||||||
|
|
||||||
uint32_t extradata_offset;
|
uint32_t extradata_offset;
|
||||||
uint32_t extradata_size;
|
uint32_t extradata_size;
|
||||||
|
@ -46,15 +46,15 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
|
if (!is_id32be(0x00,sf, "FSB5"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* .fsb: standard
|
/* .fsb: standard
|
||||||
* .snd: Alchemy engine (also Unity) */
|
* .snd: Alchemy engine (also Unity) */
|
||||||
if (!check_extensions(sf,"fsb,snd"))
|
if (!check_extensions(sf,"fsb,snd"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (!is_id32be(0x00,sf, "FSB5"))
|
/* v0 is rare, seen in Tales from Space (Vita) */
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/* v0 is rare (seen in Tales from Space Vita) */
|
|
||||||
fsb5.version = read_u32le(0x04,sf);
|
fsb5.version = read_u32le(0x04,sf);
|
||||||
if (fsb5.version != 0x00 && fsb5.version != 0x01)
|
if (fsb5.version != 0x00 && fsb5.version != 0x01)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -80,7 +80,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((fsb5.sample_header_size + fsb5.name_table_size + fsb5.sample_data_size + fsb5.base_header_size) != get_streamfile_size(sf)) {
|
if ((fsb5.sample_header_size + fsb5.name_table_size + fsb5.sample_data_size + fsb5.base_header_size) != get_streamfile_size(sf)) {
|
||||||
vgm_logi("FSB5: wrong size, expected %x + %x + %x + %x vs %x (re-rip)\n", fsb5.sample_header_size, fsb5.name_table_size, fsb5.sample_data_size, fsb5.base_header_size, get_streamfile_size(sf));
|
vgm_logi("FSB5: wrong size, expected %x + %x + %x + %x vs %x (re-rip)\n", fsb5.sample_header_size, fsb5.name_table_size, fsb5.sample_data_size, fsb5.base_header_size, (uint32_t)get_streamfile_size(sf));
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -191,10 +191,21 @@ done:
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HCA_BRUTEFORCE
|
#ifdef HCA_BRUTEFORCE
|
||||||
|
typedef enum {
|
||||||
|
HBF_TYPE_64LE_1,
|
||||||
|
HBF_TYPE_64BE_1,
|
||||||
|
HBF_TYPE_32LE_1,
|
||||||
|
HBF_TYPE_32BE_1,
|
||||||
|
HBF_TYPE_64LE_4,
|
||||||
|
HBF_TYPE_64BE_4,
|
||||||
|
HBF_TYPE_32LE_4,
|
||||||
|
HBF_TYPE_32BE_4,
|
||||||
|
} HBF_type_t;
|
||||||
|
|
||||||
/* Bruteforce binary keys in executables and similar files, mainly for some mobile games.
|
/* Bruteforce binary keys in executables and similar files, mainly for some mobile games.
|
||||||
* Kinda slow but acceptable for ~20MB exes, not very optimized. Unity usually has keys
|
* Kinda slow but acceptable for ~20MB exes, not very optimized. Unity usually has keys
|
||||||
* in plaintext (inside levelX or other base files) instead though. */
|
* in plaintext (inside levelX or other base files) instead though. */
|
||||||
static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
|
static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey, HBF_type_t type) {
|
||||||
STREAMFILE* sf_keys = NULL;
|
STREAMFILE* sf_keys = NULL;
|
||||||
uint8_t* buf = NULL;
|
uint8_t* buf = NULL;
|
||||||
int best_score = 0xFFFFFF, cur_score;
|
int best_score = 0xFFFFFF, cur_score;
|
||||||
|
@ -203,7 +214,7 @@ static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, uns
|
||||||
uint64_t old_key = 0;
|
uint64_t old_key = 0;
|
||||||
|
|
||||||
|
|
||||||
VGM_LOG("HCA: test keys.bin\n");
|
VGM_LOG("HCA: test keys.bin (type %i)\n", type);
|
||||||
|
|
||||||
*p_keycode = 0;
|
*p_keycode = 0;
|
||||||
|
|
||||||
|
@ -226,17 +237,18 @@ static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, uns
|
||||||
uint64_t key;
|
uint64_t key;
|
||||||
VGM_ASSERT(pos % 0x1000000 == 0, "HCA: pos %x...\n", pos);
|
VGM_ASSERT(pos % 0x1000000 == 0, "HCA: pos %x...\n", pos);
|
||||||
|
|
||||||
/* keys are usually u32le lower, u32le upper (u64le) but other orders may exist */
|
/* keys are usually u64le but other orders may exist */
|
||||||
key = ((uint64_t)get_u32le(buf + pos + 0x00) << 0 ) | ((uint64_t)get_u32le(buf + pos + 0x04) << 32);
|
switch(type) {
|
||||||
//key = ((uint64_t)get_u32le(buf + pos + 0x00) << 32) | ((uint64_t)get_u32le(buf + pos + 0x04) << 0);
|
case HBF_TYPE_64LE_1: key = get_u64le(buf + pos); pos += 0x01; break;
|
||||||
//key = ((uint64_t)get_u32be(buf + pos + 0x00) << 0 ) | ((uint64_t)get_u32be(buf + pos + 0x04) << 32);
|
case HBF_TYPE_64BE_1: key = get_u64be(buf + pos); pos += 0x01; break;
|
||||||
//key = ((uint64_t)get_u32be(buf + pos + 0x00) << 32) | ((uint64_t)get_u32be(buf + pos + 0x04) << 0);
|
case HBF_TYPE_32LE_1: key = get_u32le(buf + pos); pos += 0x01; break;
|
||||||
//key = ((uint64_t)get_u32le(buf + pos + 0x00) << 0 ) | 0; /* upper bytes not set, ex. P5 */
|
case HBF_TYPE_32BE_1: key = get_u32be(buf + pos); pos += 0x01; break;
|
||||||
//key = ((uint64_t)get_u32be(buf + pos + 0x00) << 0 ) | 0; /* upper bytes not set, ex. P5 */
|
case HBF_TYPE_64LE_4: key = get_u64le(buf + pos); pos += 0x04; break;
|
||||||
|
case HBF_TYPE_64BE_4: key = get_u64be(buf + pos); pos += 0x04; break;
|
||||||
/* observed files have aligned keys, change if needed */
|
case HBF_TYPE_32LE_4: key = get_u32le(buf + pos); pos += 0x04; break;
|
||||||
pos += 0x04;
|
case HBF_TYPE_32BE_4: key = get_u32be(buf + pos); pos += 0x04; break;
|
||||||
//pos++;
|
default: key = 0; pos = keys_size; break;
|
||||||
|
}
|
||||||
|
|
||||||
if (key == 0 || key == old_key)
|
if (key == 0 || key == old_key)
|
||||||
continue;
|
continue;
|
||||||
|
@ -266,6 +278,18 @@ done:
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
|
||||||
|
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_4);
|
||||||
|
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_4);
|
||||||
|
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_4);
|
||||||
|
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_4);
|
||||||
|
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_1);
|
||||||
|
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_1);
|
||||||
|
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_1);
|
||||||
|
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
//#include <stdio.h>
|
//#include <stdio.h>
|
||||||
|
|
||||||
|
@ -303,14 +327,13 @@ static void bruteforce_hca_key_txt(STREAMFILE* sf, hca_codec_data* hca_data, uns
|
||||||
uint64_t key = 0;
|
uint64_t key = 0;
|
||||||
|
|
||||||
bytes_read = read_line(line, sizeof(line), pos, sf_keys, &line_ok);
|
bytes_read = read_line(line, sizeof(line), pos, sf_keys, &line_ok);
|
||||||
if (!line_ok) continue; //???
|
|
||||||
|
|
||||||
pos += bytes_read;
|
pos += bytes_read;
|
||||||
|
if (!line_ok) continue; /* line too long */
|
||||||
|
|
||||||
count = sscanf(line, "%" SCNd64, &key);
|
count = sscanf(line, "%" SCNd64, &key);
|
||||||
if (count != 1) continue;
|
if (count != 1) continue;
|
||||||
|
|
||||||
VGM_ASSERT(pos % 100000 == 0, "HCA: count %i...\n", i);
|
VGM_ASSERT(pos % 10000 == 0, "HCA: count %i...\n", i);
|
||||||
|
|
||||||
if (key == 0)
|
if (key == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -435,6 +435,8 @@ static const hcakey_info hcakey_list[] = {
|
||||||
{0x2f778c736a8a4597}, //music_0110015
|
{0x2f778c736a8a4597}, //music_0110015
|
||||||
{0xa90c8ebf8463d05}, //music_0110016
|
{0xa90c8ebf8463d05}, //music_0110016
|
||||||
{0x750beaf22ddc700b}, //music_0110018
|
{0x750beaf22ddc700b}, //music_0110018
|
||||||
|
{0x16ccc93f976a8329}, //music_0110019
|
||||||
|
{0x9f7a0810034669fe}, //music_0110020
|
||||||
{0xfb647d074e53fab6}, //music_0120001
|
{0xfb647d074e53fab6}, //music_0120001
|
||||||
{0xc24049b9f7ed3105}, //music_0120002
|
{0xc24049b9f7ed3105}, //music_0120002
|
||||||
{0xdc128f2fd48bf4b}, //music_0120003
|
{0xdc128f2fd48bf4b}, //music_0120003
|
||||||
|
@ -450,7 +452,9 @@ static const hcakey_info hcakey_list[] = {
|
||||||
{0x6ba36cadf1e045cf}, //music_0120013
|
{0x6ba36cadf1e045cf}, //music_0120013
|
||||||
{0xb96786621e27daf3}, //music_0120014
|
{0xb96786621e27daf3}, //music_0120014
|
||||||
{0xa2c543b227b8e5e2}, //music_0120015
|
{0xa2c543b227b8e5e2}, //music_0120015
|
||||||
|
{0x845437ec4e367a13}, //music_0120016
|
||||||
{0x3674aba8da7bc84b}, //music_0120018
|
{0x3674aba8da7bc84b}, //music_0120018
|
||||||
|
{0xfd61f2c3b89f3888}, //music_0120019
|
||||||
{0x4fffee4065d22bec}, //music_0210001
|
{0x4fffee4065d22bec}, //music_0210001
|
||||||
{0x7678588b0adf59df}, //music_0210002
|
{0x7678588b0adf59df}, //music_0210002
|
||||||
{0xa0316b536c8b7540}, //music_0210003
|
{0xa0316b536c8b7540}, //music_0210003
|
||||||
|
@ -461,6 +465,7 @@ static const hcakey_info hcakey_list[] = {
|
||||||
{0x73621a0d321e60c2}, //music_0210008
|
{0x73621a0d321e60c2}, //music_0210008
|
||||||
{0xff04547fe629c8bf}, //music_0210009
|
{0xff04547fe629c8bf}, //music_0210009
|
||||||
{0x5ef795cdbcdcba91}, //music_0210010
|
{0x5ef795cdbcdcba91}, //music_0210010
|
||||||
|
{0x868acc0102c59a38}, //music_0210011
|
||||||
{0x15bb78c31db0a0b6}, //music_0220001
|
{0x15bb78c31db0a0b6}, //music_0220001
|
||||||
{0x59b1257242c40109}, //music_0220002
|
{0x59b1257242c40109}, //music_0220002
|
||||||
{0xdb402bd08d522f34}, //music_0220003
|
{0xdb402bd08d522f34}, //music_0220003
|
||||||
|
@ -474,6 +479,7 @@ static const hcakey_info hcakey_list[] = {
|
||||||
{0xf0c624dc0385adae}, //music_0220011
|
{0xf0c624dc0385adae}, //music_0220011
|
||||||
{0xce0796d2a956dc5a}, //music_0220012
|
{0xce0796d2a956dc5a}, //music_0220012
|
||||||
{0xf9d6fb07c0b4e967}, //music_0220013
|
{0xf9d6fb07c0b4e967}, //music_0220013
|
||||||
|
{0x4aa31e0c4f787a8}, //music_0220014
|
||||||
{0x94466db0d3c10f4b}, //music_0220015
|
{0x94466db0d3c10f4b}, //music_0220015
|
||||||
{0xe6d1fd6effa46736}, //music_0220017
|
{0xe6d1fd6effa46736}, //music_0220017
|
||||||
{0x6a15a9610d10d210}, //music_0310001
|
{0x6a15a9610d10d210}, //music_0310001
|
||||||
|
@ -502,6 +508,7 @@ static const hcakey_info hcakey_list[] = {
|
||||||
{0x244a92885ab77b7c}, //music_0320012
|
{0x244a92885ab77b7c}, //music_0320012
|
||||||
{0xfc3fa77fc33460d4}, //music_0320013
|
{0xfc3fa77fc33460d4}, //music_0320013
|
||||||
{0x26ee13598091b548}, //music_0320014
|
{0x26ee13598091b548}, //music_0320014
|
||||||
|
{0x2df608ef06aca41c}, //music_0320016
|
||||||
{0x776c4aded0bca5d1}, //music_0410001
|
{0x776c4aded0bca5d1}, //music_0410001
|
||||||
{0xb7bff4fbf66be43f}, //music_0410002
|
{0xb7bff4fbf66be43f}, //music_0410002
|
||||||
{0x904f50c5ce8ec6e4}, //music_0410003
|
{0x904f50c5ce8ec6e4}, //music_0410003
|
||||||
|
@ -527,6 +534,7 @@ static const hcakey_info hcakey_list[] = {
|
||||||
{0x52723f026d5238e8}, //music_0420012
|
{0x52723f026d5238e8}, //music_0420012
|
||||||
{0xd13a315c0005f0}, //music_0420013
|
{0xd13a315c0005f0}, //music_0420013
|
||||||
{0x35f2d3cec84aba1}, //music_0420014
|
{0x35f2d3cec84aba1}, //music_0420014
|
||||||
|
{0xdad11fe0e397ede}, //music_0420015
|
||||||
{0xdf31e26a7b036a2}, //music_0510001
|
{0xdf31e26a7b036a2}, //music_0510001
|
||||||
{0xb2770dced3cfd9a7}, //music_0510002
|
{0xb2770dced3cfd9a7}, //music_0510002
|
||||||
{0x6c6c1fd51e28a1e7}, //music_0510003
|
{0x6c6c1fd51e28a1e7}, //music_0510003
|
||||||
|
@ -540,6 +548,7 @@ static const hcakey_info hcakey_list[] = {
|
||||||
{0xc5c9bf138c9e28ce}, //music_0510011
|
{0xc5c9bf138c9e28ce}, //music_0510011
|
||||||
{0x1980271cfe0da9bd}, //music_0510012
|
{0x1980271cfe0da9bd}, //music_0510012
|
||||||
{0x75c5bd4e3a01a8a4}, //music_0510013
|
{0x75c5bd4e3a01a8a4}, //music_0510013
|
||||||
|
{0xec5f5fbe92bbb771}, //music_0510014
|
||||||
{0x15f82c1617013c36}, //music_0520001
|
{0x15f82c1617013c36}, //music_0520001
|
||||||
{0xc7da8e6f0e2fe399}, //music_0520002
|
{0xc7da8e6f0e2fe399}, //music_0520002
|
||||||
{0xe350bffcdc9cb686}, //music_0520003
|
{0xe350bffcdc9cb686}, //music_0520003
|
||||||
|
@ -552,6 +561,7 @@ static const hcakey_info hcakey_list[] = {
|
||||||
{0xde4959221bc2675}, //music_0520010
|
{0xde4959221bc2675}, //music_0520010
|
||||||
{0xeeaf8d2458ccdb36}, //music_0520011
|
{0xeeaf8d2458ccdb36}, //music_0520011
|
||||||
{0xb140168a47d55b92}, //music_0520012
|
{0xb140168a47d55b92}, //music_0520012
|
||||||
|
{0x1bf43def1e4b103a}, //music_0520014
|
||||||
{0xd2ce91dbfc209b10}, //music_0610001
|
{0xd2ce91dbfc209b10}, //music_0610001
|
||||||
{0xa662be1601e49476}, //music_0610002
|
{0xa662be1601e49476}, //music_0610002
|
||||||
{0xe5e83d31e64273f8}, //music_0610003
|
{0xe5e83d31e64273f8}, //music_0610003
|
||||||
|
@ -576,6 +586,7 @@ static const hcakey_info hcakey_list[] = {
|
||||||
{0x33848be13a2884a3}, //music_0620011
|
{0x33848be13a2884a3}, //music_0620011
|
||||||
{0xfab3596f11cc4d7a}, //music_0620012
|
{0xfab3596f11cc4d7a}, //music_0620012
|
||||||
{0xe35d52b6d2c094fb}, //music_0620013
|
{0xe35d52b6d2c094fb}, //music_0620013
|
||||||
|
{0xcdb9bc2ad7024ca2}, //music_0620014
|
||||||
{0x2a47feac8dc3ca9c}, //music_3010001
|
{0x2a47feac8dc3ca9c}, //music_3010001
|
||||||
{0x9ebbaf63ffe9d9ef}, //music_3010002
|
{0x9ebbaf63ffe9d9ef}, //music_3010002
|
||||||
{0xe553dba6592293d8}, //music_3010003
|
{0xe553dba6592293d8}, //music_3010003
|
||||||
|
@ -586,12 +597,16 @@ static const hcakey_info hcakey_list[] = {
|
||||||
{0x1ab266a4cbb5133a}, //music_3010008
|
{0x1ab266a4cbb5133a}, //music_3010008
|
||||||
{0x7d4719615fbb2f4d}, //music_3010009
|
{0x7d4719615fbb2f4d}, //music_3010009
|
||||||
{0x28aa75a01f26a853}, //music_3010010
|
{0x28aa75a01f26a853}, //music_3010010
|
||||||
|
{0x7555feeaa2a8fac4}, //music_3010011
|
||||||
{0xa42de67a89fb3175}, //music_3010012
|
{0xa42de67a89fb3175}, //music_3010012
|
||||||
|
{0xbdd0c58062c675d4}, //music_3010014
|
||||||
{0xfd3ea450350d666f}, //music_3020001
|
{0xfd3ea450350d666f}, //music_3020001
|
||||||
{0x5e91a3790c32e2b3}, //music_3020002
|
{0x5e91a3790c32e2b3}, //music_3020002
|
||||||
{0x358adfd1bbd3a95e}, //music_3020003
|
{0x358adfd1bbd3a95e}, //music_3020003
|
||||||
{0x1948edf7ff41e79b}, //music_3020004
|
{0x1948edf7ff41e79b}, //music_3020004
|
||||||
{0x100293729f35b4de}, //music_3020005
|
{0x100293729f35b4de}, //music_3020005
|
||||||
|
{0x140ac59d2b870a13}, //music_3020006
|
||||||
|
{0x402b13df5481d4e6}, //music_3020007
|
||||||
{0xdfad847a86a126bb}, //music_5030001
|
{0xdfad847a86a126bb}, //music_5030001
|
||||||
{0x711ef85045b8c26e}, //music_5030002
|
{0x711ef85045b8c26e}, //music_5030002
|
||||||
{0xff7640b46d72b337}, //music_5030003
|
{0xff7640b46d72b337}, //music_5030003
|
||||||
|
@ -623,6 +638,8 @@ static const hcakey_info hcakey_list[] = {
|
||||||
{0x24c0b49097e9ebff}, //music_5030029
|
{0x24c0b49097e9ebff}, //music_5030029
|
||||||
{0x2ecdf66c680f3a45}, //music_5030030
|
{0x2ecdf66c680f3a45}, //music_5030030
|
||||||
{0x54aaada4a1b8deef}, //music_5030031
|
{0x54aaada4a1b8deef}, //music_5030031
|
||||||
|
{0x46bed365593c560c}, //music_5030032
|
||||||
|
{0xa954b315630e3ed0}, //music_5030033
|
||||||
{0x8328668369631cc1}, //music_5030034
|
{0x8328668369631cc1}, //music_5030034
|
||||||
{0xa5c1adeb7919845f}, //music_5030035
|
{0xa5c1adeb7919845f}, //music_5030035
|
||||||
{0x8e35d68632fc0d77}, //music_5030036
|
{0x8e35d68632fc0d77}, //music_5030036
|
||||||
|
@ -631,6 +648,9 @@ static const hcakey_info hcakey_list[] = {
|
||||||
{0x6abcc90be62f2cec}, //music_5030039
|
{0x6abcc90be62f2cec}, //music_5030039
|
||||||
{0x7f617e396e9a1e5c}, //music_5030040
|
{0x7f617e396e9a1e5c}, //music_5030040
|
||||||
{0xd0471c163265ca1b}, //music_5030041
|
{0xd0471c163265ca1b}, //music_5030041
|
||||||
|
{0xd689966609595d7d}, //music_5030042
|
||||||
|
{0x32cb728ddab4d956}, //music_5030050
|
||||||
|
{0x52c5dfb61fe4c87a}, //music_5030054
|
||||||
{0x444dda6d55d76095}, //music_5040001
|
{0x444dda6d55d76095}, //music_5040001
|
||||||
{0xcbf4f1324081e0a6}, //music_5040002
|
{0xcbf4f1324081e0a6}, //music_5040002
|
||||||
{0xf1db3c1d9542063a}, //music_5040003
|
{0xf1db3c1d9542063a}, //music_5040003
|
||||||
|
@ -688,6 +708,10 @@ static const hcakey_info hcakey_list[] = {
|
||||||
{0xfa842bc07360137d}, //music_5050035
|
{0xfa842bc07360137d}, //music_5050035
|
||||||
{0xf8d72c405d3f0456}, //music_5050036
|
{0xf8d72c405d3f0456}, //music_5050036
|
||||||
{0xd4d5fa6c87342e6b}, //music_5050037
|
{0xd4d5fa6c87342e6b}, //music_5050037
|
||||||
|
{0xd8cbc946fa660944}, //music_5050038
|
||||||
|
{0xfac398719cd9e4a}, //music_5050039
|
||||||
|
{0x9c4ba796548a019}, //music_5050040
|
||||||
|
{0x7e7c462ba7d473cf}, //music_5050041
|
||||||
{0xe278eccf08eb2565}, //music_5050044
|
{0xe278eccf08eb2565}, //music_5050044
|
||||||
{0x1cf133b26d8160d1}, //music_5050045
|
{0x1cf133b26d8160d1}, //music_5050045
|
||||||
{0xda08e9d3961c93f2}, //music_5050046
|
{0xda08e9d3961c93f2}, //music_5050046
|
||||||
|
@ -702,6 +726,7 @@ static const hcakey_info hcakey_list[] = {
|
||||||
{0xbce9e85d31089fb2}, //music_5050056
|
{0xbce9e85d31089fb2}, //music_5050056
|
||||||
{0x817b919679c96d7}, //music_5050057
|
{0x817b919679c96d7}, //music_5050057
|
||||||
{0x3e0e51043bd7d5e5}, //music_5050058
|
{0x3e0e51043bd7d5e5}, //music_5050058
|
||||||
|
{0x86d17e28b2f2b91c}, //music_5050059
|
||||||
{0x115f906b6b7fb845}, //music_5050060
|
{0x115f906b6b7fb845}, //music_5050060
|
||||||
{0xa8d5e9b1c6cf1505}, //music_5050061
|
{0xa8d5e9b1c6cf1505}, //music_5050061
|
||||||
{0x69ffd3fefdf7ee71}, //music_5050062
|
{0x69ffd3fefdf7ee71}, //music_5050062
|
||||||
|
@ -710,10 +735,21 @@ static const hcakey_info hcakey_list[] = {
|
||||||
{0x27992dd621b8a07e}, //music_5050065
|
{0x27992dd621b8a07e}, //music_5050065
|
||||||
{0x8e2a8439f5628513}, //music_5050066
|
{0x8e2a8439f5628513}, //music_5050066
|
||||||
{0x8b5be21e70a84eed}, //music_5050067
|
{0x8b5be21e70a84eed}, //music_5050067
|
||||||
|
{0x227297416c6ccc7c}, //music_5050068
|
||||||
{0xb544dc8524419109}, //music_5050069
|
{0xb544dc8524419109}, //music_5050069
|
||||||
{0x6c2d9160672cbf95}, //music_5050070
|
{0x6c2d9160672cbf95}, //music_5050070
|
||||||
{0x7ff6630286d2d93b}, //music_5050071
|
{0x7ff6630286d2d93b}, //music_5050071
|
||||||
|
{0xc6deecd2d1391713}, //music_5050072
|
||||||
{0x78bec41dd27d8788}, //music_5050074
|
{0x78bec41dd27d8788}, //music_5050074
|
||||||
|
{0xf86991a3b9aec2b}, //music_5050075
|
||||||
|
{0x8f750fabaa794130}, //music_5050076
|
||||||
|
{0x3c68e8102dbec720}, //music_5050077
|
||||||
|
{0xf653b47bc8d4d1cd}, //music_5050079
|
||||||
|
{0xb50f482149140fda}, //music_5050080
|
||||||
|
{0xd61cc4e14e7073f4}, //music_5050081
|
||||||
|
{0x85a236b5270bac29}, //music_5050083
|
||||||
|
{0x598e133e0673b1e6}, //music_5050086
|
||||||
|
{0x3f8abfcd47711be2}, //music_5050088
|
||||||
{0x52c250eade92393b}, //music_9010001
|
{0x52c250eade92393b}, //music_9010001
|
||||||
{0xfea0d6adff136868}, //music_9050001
|
{0xfea0d6adff136868}, //music_9050001
|
||||||
|
|
||||||
|
|
|
@ -5,47 +5,50 @@
|
||||||
/* HIS - Her Interactive games [Nancy Drew series (PC)] */
|
/* HIS - Her Interactive games [Nancy Drew series (PC)] */
|
||||||
VGMSTREAM * init_vgmstream_his(STREAMFILE *sf) {
|
VGMSTREAM * init_vgmstream_his(STREAMFILE *sf) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
int channel_count, loop_flag = 0, bps, sample_rate, num_samples, version;
|
int channels, loop_flag = 0, bps, sample_rate, num_samples, version;
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
|
if (!is_id32be(0x00,sf, "Her ") &&
|
||||||
|
!is_id32be(0x00,sf, "HIS\0"))
|
||||||
|
goto fail;
|
||||||
if (!check_extensions(sf, "his"))
|
if (!check_extensions(sf, "his"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (read_32bitBE(0x00,sf) == 0x48657220) { /* "Her Interactive Sound\x1a" */
|
if (is_id32be(0x00,sf, "Her ")) { /* "Her Interactive Sound\x1a" */
|
||||||
/* Nancy Drew: Secrets Can Kill (PC) */
|
/* Nancy Drew: Secrets Can Kill (PC) */
|
||||||
version = 0;
|
version = 0;
|
||||||
channel_count = read_16bitLE(0x16,sf);
|
channels = read_u16le(0x16,sf);
|
||||||
sample_rate = read_32bitLE(0x18,sf);
|
sample_rate = read_u32le(0x18,sf);
|
||||||
/* 0x1c: bitrate */
|
/* 0x1c: bitrate */
|
||||||
/* 0x20: block size */
|
/* 0x20: block size */
|
||||||
bps = read_16bitLE(0x22,sf);
|
bps = read_u16le(0x22,sf);
|
||||||
|
|
||||||
if (read_32bitBE(0x24,sf) != 0x64617461) /* "data" */
|
if (!is_id32be(0x24,sf, "data"))
|
||||||
goto fail;
|
goto fail;
|
||||||
num_samples = pcm_bytes_to_samples(read_32bitLE(0x28,sf), channel_count, bps);
|
num_samples = pcm_bytes_to_samples(read_u32le(0x28,sf), channels, bps);
|
||||||
|
|
||||||
start_offset = 0x2c;
|
start_offset = 0x2c;
|
||||||
}
|
}
|
||||||
else if (read_32bitBE(0x00,sf) == 0x48495300) { /* HIS\0 */
|
else if (is_id32be(0x00,sf, "HIS\0")) {
|
||||||
/* most(?) others */
|
/* most(?) others */
|
||||||
version = read_32bitLE(0x04,sf);
|
version = read_u32le(0x04,sf);
|
||||||
/* 0x08: codec */
|
/* 0x08: codec */
|
||||||
channel_count = read_16bitLE(0x0a,sf);
|
channels = read_u16le(0x0a,sf);
|
||||||
sample_rate = read_32bitLE(0x0c,sf);
|
sample_rate = read_u32le(0x0c,sf);
|
||||||
/* 0x10: bitrate */
|
/* 0x10: bitrate */
|
||||||
/* 0x14: block size */
|
/* 0x14: block size */
|
||||||
bps = read_16bitLE(0x16,sf);
|
bps = read_u16le(0x16,sf);
|
||||||
|
|
||||||
num_samples = pcm_bytes_to_samples(read_32bitLE(0x18,sf), channel_count, bps); /* true even for Ogg */
|
num_samples = pcm_bytes_to_samples(read_u32le(0x18,sf), channels, bps); /* true even for Ogg */
|
||||||
|
|
||||||
/* later games use "OggS" */
|
/* later games use "OggS" */
|
||||||
if (version == 1)
|
if (version == 1)
|
||||||
start_offset = 0x1c; /* Nancy Drew: The Final Scene (PC) */
|
start_offset = 0x1c; /* Nancy Drew: The Final Scene (PC) */
|
||||||
else if (version == 2 && read_32bitBE(0x1e,sf) == 0x4F676753)
|
else if (version == 2 && is_id32be(0x1e,sf, "OggS"))
|
||||||
start_offset = 0x1e; /* Nancy Drew: The Haunted Carousel (PC) */
|
start_offset = 0x1e; /* Nancy Drew: The Haunted Carousel (PC) */
|
||||||
else if (version == 2 && read_32bitBE(0x20,sf) == 0x4F676753)
|
else if (version == 2 && is_id32be(0x20,sf, "OggS"))
|
||||||
start_offset = 0x20; /* Nancy Drew: The Silent Spy (PC) */
|
start_offset = 0x20; /* Nancy Drew: The Silent Spy (PC) */
|
||||||
else
|
else
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -56,18 +59,14 @@ VGMSTREAM * init_vgmstream_his(STREAMFILE *sf) {
|
||||||
|
|
||||||
|
|
||||||
if (version == 2) {
|
if (version == 2) {
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
ogg_vorbis_meta_info_t ovmi = {0};
|
ogg_vorbis_meta_info_t ovmi = {0};
|
||||||
|
|
||||||
ovmi.meta_type = meta_HIS;
|
ovmi.meta_type = meta_HIS;
|
||||||
return init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
return init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||||
#else
|
|
||||||
goto fail;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
vgmstream->meta_type = meta_HIS;
|
vgmstream->meta_type = meta_HIS;
|
||||||
|
@ -89,7 +88,7 @@ VGMSTREAM * init_vgmstream_his(STREAMFILE *sf) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
|
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||||
goto fail;
|
goto fail;
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
|
|
|
@ -10,14 +10,14 @@ VGMSTREAM* init_vgmstream_ikm_ps2(STREAMFILE* sf) {
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
if ( !check_extensions(sf,"ikm") )
|
if (!is_id32be(0x00,sf, "IKM\0"))
|
||||||
goto fail;
|
goto fail;
|
||||||
if (read_u32be(0x00,sf) != 0x494B4D00) /* "IKM\0" */
|
if (!check_extensions(sf,"ikm"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (read_u32be(0x40,sf) != 0x41535400) /* "AST\0" */
|
|
||||||
goto fail;
|
|
||||||
/* 0x20: type 03? */
|
/* 0x20: type 03? */
|
||||||
|
if (!is_id32be(0x40,sf, "AST\0"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
loop_flag = (read_s32le(0x14, sf) > 0);
|
loop_flag = (read_s32le(0x14, sf) > 0);
|
||||||
channel_count = read_s32le(0x50, sf);
|
channel_count = read_s32le(0x50, sf);
|
||||||
|
@ -53,23 +53,24 @@ VGMSTREAM* init_vgmstream_ikm_pc(STREAMFILE* sf) {
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
if ( !check_extensions(sf,"ikm") )
|
if (!is_id32be(0x00,sf, "IKM\0"))
|
||||||
goto fail;
|
goto fail;
|
||||||
if (read_u32be(0x00,sf) != 0x494B4D00) /* "IKM\0" */
|
if (!check_extensions(sf,"ikm"))
|
||||||
goto fail;
|
goto fail;
|
||||||
/* 0x20: type 01? */
|
/* 0x20: type 01? */
|
||||||
|
|
||||||
/* find "OggS" start */
|
/* find "OggS" start */
|
||||||
if (read_u32be(0x30,sf) == 0x4F676753) {
|
if (is_id32be(0x30,sf, "OggS")) {
|
||||||
start_offset = 0x30; /* Chaos Legion (PC) */
|
start_offset = 0x30; /* Chaos Legion (PC) */
|
||||||
} else if (read_u32be(0x800,sf) == 0x4F676753) {
|
}
|
||||||
|
else if (is_id32be(0x800,sf, "OggS")) {
|
||||||
start_offset = 0x800; /* Legend of Galactic Heroes (PC) */
|
start_offset = 0x800; /* Legend of Galactic Heroes (PC) */
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
{
|
{
|
||||||
ogg_vorbis_meta_info_t ovmi = {0};
|
ogg_vorbis_meta_info_t ovmi = {0};
|
||||||
|
|
||||||
|
@ -82,9 +83,6 @@ VGMSTREAM* init_vgmstream_ikm_pc(STREAMFILE* sf) {
|
||||||
|
|
||||||
vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
goto fail;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
|
@ -102,13 +100,14 @@ VGMSTREAM* init_vgmstream_ikm_psp(STREAMFILE* sf) {
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
|
if (!is_id32be(0x00,sf, "IKM\0"))
|
||||||
|
goto fail;
|
||||||
if (!check_extensions(sf,"ikm"))
|
if (!check_extensions(sf,"ikm"))
|
||||||
goto fail;
|
goto fail;
|
||||||
if (read_u32be(0x00,sf) != 0x494B4D00) /* "IKM\0" */
|
|
||||||
goto fail;
|
|
||||||
if (read_u32be(0x800,sf) != 0x52494646) /* "RIFF" */
|
|
||||||
goto fail;
|
|
||||||
/* 0x20: type 00? */
|
/* 0x20: type 00? */
|
||||||
|
if (!is_id32be(0x800,sf, "RIFF"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* loop values (pre-adjusted without encoder delay) at 0x14/18 are found in the RIFF too */
|
/* loop values (pre-adjusted without encoder delay) at 0x14/18 are found in the RIFF too */
|
||||||
data_size = read_s32le(0x24, sf);
|
data_size = read_s32le(0x24, sf);
|
||||||
|
|
|
@ -2,13 +2,6 @@
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
|
|
||||||
static int is_id4(const char* test, off_t offset, STREAMFILE* sf) {
|
|
||||||
uint8_t buf[4];
|
|
||||||
if (read_streamfile(buf, offset, sizeof(buf), sf) != sizeof(buf))
|
|
||||||
return 0;
|
|
||||||
return memcmp(buf, test, sizeof(buf)) == 0; /* memcmp to allow "AB\0\0" */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* LucasArts iMUSE (Interactive Music Streaming Engine) formats */
|
/* LucasArts iMUSE (Interactive Music Streaming Engine) formats */
|
||||||
VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) {
|
VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) {
|
||||||
VGMSTREAM* vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
|
@ -19,19 +12,13 @@ VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) {
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
/* .imx: The Curse of Monkey Island (PC)
|
|
||||||
* .imc: Grim Fandango (multi)
|
|
||||||
* .wav: Grim Fandango (multi) RIFF sfx */
|
|
||||||
if (!check_extensions(sf, "imx,imc,wav,lwav"))
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
|
|
||||||
/* base decoder block table */
|
/* base decoder block table */
|
||||||
if (is_id4("COMP", 0x00, sf)) { /* The Curse of Monkey Island (PC), The Dig (PC) */
|
if (is_id32be(0x00, sf, "COMP")) { /* The Curse of Monkey Island (PC), The Dig (PC) */
|
||||||
int entries = read_u32be(0x04,sf);
|
int entries = read_u32be(0x04,sf);
|
||||||
head_offset = 0x10 + entries * 0x10 + 0x02; /* base header + table + header size */
|
head_offset = 0x10 + entries * 0x10 + 0x02; /* base header + table + header size */
|
||||||
}
|
}
|
||||||
else if (is_id4("MCMP", 0x00, sf)) { /* Grim Fandango (multi), Star Wars: X-Wing Alliance (PC) */
|
else if (is_id32be(0x00, sf, "MCMP")) { /* Grim Fandango (multi), Star Wars: X-Wing Alliance (PC) */
|
||||||
int entries = read_u16be(0x04,sf);
|
int entries = read_u16be(0x04,sf);
|
||||||
head_offset = 0x06 + entries * 0x09; /* base header + table */
|
head_offset = 0x06 + entries * 0x09; /* base header + table */
|
||||||
head_offset += 0x02 + read_u16be(head_offset, sf); /* + mini text header */
|
head_offset += 0x02 + read_u16be(head_offset, sf); /* + mini text header */
|
||||||
|
@ -40,17 +27,23 @@ VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* .imx: The Curse of Monkey Island (PC)
|
||||||
|
* .imc: Grim Fandango (multi)
|
||||||
|
* .wav: Grim Fandango (multi) RIFF sfx */
|
||||||
|
if (!check_extensions(sf, "imx,imc,wav,lwav"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
|
||||||
/* "offsets" below seem to count decoded data. Data is divided into variable-sized blocks that usually
|
/* "offsets" below seem to count decoded data. Data is divided into variable-sized blocks that usually
|
||||||
* return 0x2000 bytes (starting from and including header). File starts with a block table to make
|
* return 0x2000 bytes (starting from and including header). File starts with a block table to make
|
||||||
* this manageable. Most offsets don't seem to match block or data boundaries so not really sure. */
|
* this manageable. Most offsets don't seem to match block or data boundaries so not really sure. */
|
||||||
|
|
||||||
/* main header after table */
|
/* main header after table */
|
||||||
if (is_id4("iMUS", head_offset, sf)) { /* COMP/MCMP */
|
if (is_id32be(head_offset, sf, "iMUS")) { /* COMP/MCMP */
|
||||||
int header_found = 0;
|
int header_found = 0;
|
||||||
|
|
||||||
/* 0x04: decompressed size (header size + pcm bytes) */
|
/* 0x04: decompressed size (header size + pcm bytes) */
|
||||||
if (!is_id4("MAP ", head_offset + 0x08, sf))
|
if (!is_id32be(head_offset + 0x08, sf, "MAP "))
|
||||||
goto fail;
|
goto fail;
|
||||||
map_size = read_u32be(head_offset + 0x0c, sf);
|
map_size = read_u32be(head_offset + 0x0c, sf);
|
||||||
map_offset = head_offset + 0x10;
|
map_offset = head_offset + 0x10;
|
||||||
|
@ -105,12 +98,12 @@ VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) {
|
||||||
if (!header_found)
|
if (!header_found)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (!is_id4("DATA", head_offset + 0x10 + map_size + 0x00, sf))
|
if (!is_id32be(head_offset + 0x10 + map_size + 0x00, sf, "DATA"))
|
||||||
goto fail;
|
goto fail;
|
||||||
data_bytes = read_u32be(head_offset + 0x10 + map_size + 0x04, sf);
|
data_bytes = read_u32be(head_offset + 0x10 + map_size + 0x04, sf);
|
||||||
num_samples = data_bytes / channels / sizeof(int16_t);
|
num_samples = data_bytes / channels / sizeof(int16_t);
|
||||||
}
|
}
|
||||||
else if (is_id4("RIFF", head_offset, sf)) { /* MCMP voices */
|
else if (is_id32be(head_offset, sf, "RIFF")) { /* MCMP voices */
|
||||||
/* standard (LE), with fake codec 1 and sizes also in decoded bytes (see above),
|
/* standard (LE), with fake codec 1 and sizes also in decoded bytes (see above),
|
||||||
* has standard RIFF chunks (may include extra), start offset in MCSC */
|
* has standard RIFF chunks (may include extra), start offset in MCSC */
|
||||||
|
|
||||||
|
@ -124,7 +117,8 @@ VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) {
|
||||||
num_samples = data_bytes / channels / sizeof(int16_t);
|
num_samples = data_bytes / channels / sizeof(int16_t);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
goto fail; /* The Dig (PC) has no header, detect? */
|
vgm_logi("IMUSE: unsupported format\n");
|
||||||
|
goto fail; /* The Dig (PC) has no header, detect? (needs a bunch of sub-codecs) */
|
||||||
}
|
}
|
||||||
|
|
||||||
loop_flag = 0;
|
loop_flag = 0;
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "../vgmstream.h"
|
#include "../vgmstream.h"
|
||||||
|
|
||||||
|
typedef VGMSTREAM* (*init_vgmstream_t)(STREAMFILE* sf);
|
||||||
|
|
||||||
VGMSTREAM* init_vgmstream_silence(int channels, int sample_rate, int32_t num_samples);
|
VGMSTREAM* init_vgmstream_silence(int channels, int sample_rate, int32_t num_samples);
|
||||||
VGMSTREAM* init_vgmstream_silence_container(int total_subsongs);
|
VGMSTREAM* init_vgmstream_silence_container(int total_subsongs);
|
||||||
|
|
||||||
|
@ -116,8 +118,7 @@ VGMSTREAM * init_vgmstream_vpk(STREAMFILE *streamFile);
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile);
|
VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile);
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf);
|
||||||
VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile);
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int loop_flag;
|
int loop_flag;
|
||||||
|
@ -142,16 +143,15 @@ typedef struct {
|
||||||
|
|
||||||
} ogg_vorbis_meta_info_t;
|
} ogg_vorbis_meta_info_t;
|
||||||
|
|
||||||
VGMSTREAM* init_vgmstream_ogg_vorbis_config(STREAMFILE *sf, off_t start, const ogg_vorbis_meta_info_t* ovmi);
|
VGMSTREAM* init_vgmstream_ogg_vorbis_config(STREAMFILE* sf, off_t start, const ogg_vorbis_meta_info_t* ovmi);
|
||||||
#endif
|
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_hca(STREAMFILE *streamFile);
|
VGMSTREAM* init_vgmstream_hca(STREAMFILE* sf);
|
||||||
VGMSTREAM * init_vgmstream_hca_subkey(STREAMFILE *streamFile, uint16_t subkey);
|
VGMSTREAM* init_vgmstream_hca_subkey(STREAMFILE* sf, uint16_t subkey);
|
||||||
|
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
VGMSTREAM * init_vgmstream_ffmpeg(STREAMFILE *streamFile);
|
VGMSTREAM* init_vgmstream_ffmpeg(STREAMFILE* sf);
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE * streamFile);
|
VGMSTREAM* init_vgmstream_mp4_aac_ffmpeg(STREAMFILE* sf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
|
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
|
||||||
|
|
|
@ -1,39 +1,27 @@
|
||||||
/*
|
|
||||||
2017-12-10: Preliminary MOGG Support. As long as the stream is unencrypted, this should be fine.
|
|
||||||
This will also work on unconventional 5 channel Vorbis streams but some sound cards might not like it.
|
|
||||||
TODO (Eventually): Add decryption for encrypted MOGG types (Rock Band, etc.)
|
|
||||||
|
|
||||||
-bxaimc
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
/* MOGG - Harmonix Music Systems (Guitar Hero)[Unencrypted Type] */
|
/* MOGG - Harmonix Music Systems's Ogg (unencrypted type) [Guitar Hero II (X360)] */
|
||||||
VGMSTREAM* init_vgmstream_mogg(STREAMFILE *sf) {
|
VGMSTREAM* init_vgmstream_mogg(STREAMFILE* sf) {
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
|
if (read_u32le(0x00, sf) != 0x0A) /* type? */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
if (!check_extensions(sf, "mogg"))
|
if (!check_extensions(sf, "mogg"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
{
|
{
|
||||||
ogg_vorbis_meta_info_t ovmi = {0};
|
ogg_vorbis_meta_info_t ovmi = {0};
|
||||||
VGMSTREAM * result = NULL;
|
|
||||||
|
|
||||||
ovmi.meta_type = meta_MOGG;
|
ovmi.meta_type = meta_MOGG;
|
||||||
|
|
||||||
start_offset = read_32bitLE(0x04, sf);
|
start_offset = read_u32le(0x04, sf);
|
||||||
result = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
return init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||||
|
|
||||||
if (result != NULL) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
/* clean up anything we may have opened */
|
|
||||||
#endif
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,30 +6,27 @@
|
||||||
/* MUPS - from Watermelon/HUCARD games (same programmer) [Pier Solar and the Great Architects (PC), Ghost Blade HD (PC/Switch)] */
|
/* MUPS - from Watermelon/HUCARD games (same programmer) [Pier Solar and the Great Architects (PC), Ghost Blade HD (PC/Switch)] */
|
||||||
VGMSTREAM* init_vgmstream_mups(STREAMFILE* sf) {
|
VGMSTREAM* init_vgmstream_mups(STREAMFILE* sf) {
|
||||||
VGMSTREAM* vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
STREAMFILE *temp_sf = NULL;
|
STREAMFILE* temp_sf = NULL;
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
|
if (!is_id32be(0x00,sf, "MUPS"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* mups: header id?
|
/* mups: header id?
|
||||||
* (extensionless): default? */
|
* (extensionless): default? */
|
||||||
if (!check_extensions(sf, "mups,"))
|
if (!check_extensions(sf, "mups,"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (read_u32be(0x00,sf) != 0x4D555053) /* "MUPS" */
|
if (!is_id32be(0x08,sf, "PssH"))
|
||||||
goto fail;
|
|
||||||
if (read_u32be(0x08,sf) != 0x50737348) /* "PssH" */
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* just an Ogg with changed OggS/vorbis words (see streamfile) */
|
/* just an Ogg with changed OggS/vorbis words (see streamfile) */
|
||||||
temp_sf = setup_mups_streamfile(sf, 0x08);
|
temp_sf = setup_mups_streamfile(sf, 0x08);
|
||||||
if (!temp_sf) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
vgmstream = init_vgmstream_ogg_vorbis(temp_sf);
|
vgmstream = init_vgmstream_ogg_vorbis(temp_sf);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
#else
|
|
||||||
goto fail;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
close_streamfile(temp_sf);
|
close_streamfile(temp_sf);
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_loop_flag, int *out_loop_start_index, int *out_loop_end_index);
|
static char** parse_mus(STREAMFILE* sf, int *out_file_count, int *out_loop_flag, int *out_loop_start_index, int *out_loop_end_index);
|
||||||
static void clean_mus(char** mus_filenames, int file_count);
|
static void clean_mus(char** mus_filenames, int file_count);
|
||||||
|
|
||||||
/* .MUS - playlist for InterPlay games [Planescape: Torment (PC), Baldur's Gate Enhanced Edition (PC)] */
|
/* .MUS - playlist for InterPlay games [Planescape: Torment (PC), Baldur's Gate Enhanced Edition (PC)] */
|
||||||
VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
|
VGMSTREAM* init_vgmstream_mus_acm(STREAMFILE* sf) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
segmented_layout_data *data = NULL;
|
segmented_layout_data *data = NULL;
|
||||||
|
|
||||||
|
@ -27,11 +27,11 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
if (!check_extensions(streamFile, "mus"))
|
if (!check_extensions(sf, "mus"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* get file paths from the .MUS text file */
|
/* get file paths from the .MUS text file */
|
||||||
mus_filenames = parse_mus(streamFile, &segment_count, &loop_flag, &loop_start_index, &loop_end_index);
|
mus_filenames = parse_mus(sf, &segment_count, &loop_flag, &loop_start_index, &loop_end_index);
|
||||||
if (!mus_filenames) goto fail;
|
if (!mus_filenames) goto fail;
|
||||||
|
|
||||||
/* init layout */
|
/* init layout */
|
||||||
|
@ -40,24 +40,22 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
/* open each segment subfile */
|
/* open each segment subfile */
|
||||||
for (i = 0; i < segment_count; i++) {
|
for (i = 0; i < segment_count; i++) {
|
||||||
STREAMFILE* temp_streamFile = streamFile->open(streamFile, mus_filenames[i], STREAMFILE_DEFAULT_BUFFER_SIZE);
|
STREAMFILE* temp_sf = sf->open(sf, mus_filenames[i], STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||||
if (!temp_streamFile) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
/* find .ACM type */
|
/* find .ACM type */
|
||||||
switch(read_32bitBE(0x00,temp_streamFile)) {
|
switch(read_32bitBE(0x00,temp_sf)) {
|
||||||
case 0x97280301: /* ACM header id [Planescape: Torment (PC)] */
|
case 0x97280301: /* ACM header id [Planescape: Torment (PC)] */
|
||||||
data->segments[i] = init_vgmstream_acm(temp_streamFile);
|
data->segments[i] = init_vgmstream_acm(temp_sf);
|
||||||
break;
|
break;
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
case 0x4F676753: /* "OggS" [Planescape: Torment Enhanced Edition (PC)] */
|
case 0x4F676753: /* "OggS" [Planescape: Torment Enhanced Edition (PC)] */
|
||||||
data->segments[i] = init_vgmstream_ogg_vorbis(temp_streamFile);
|
data->segments[i] = init_vgmstream_ogg_vorbis(temp_sf);
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
data->segments[i] = NULL;
|
data->segments[i] = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
close_streamfile(temp_streamFile);
|
close_streamfile(temp_sf);
|
||||||
|
|
||||||
if (!data->segments[i]) goto fail;
|
if (!data->segments[i]) goto fail;
|
||||||
|
|
||||||
|
@ -184,7 +182,7 @@ fail:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_loop_flag, int *out_loop_start_index, int *out_loop_end_index) {
|
static char** parse_mus(STREAMFILE *sf, int *out_file_count, int *out_loop_flag, int *out_loop_start_index, int *out_loop_end_index) {
|
||||||
char** names = NULL;
|
char** names = NULL;
|
||||||
|
|
||||||
char filename[NAME_LENGTH];
|
char filename[NAME_LENGTH];
|
||||||
|
@ -204,7 +202,7 @@ static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_lo
|
||||||
|
|
||||||
|
|
||||||
/* read file name base */
|
/* read file name base */
|
||||||
bytes_read = read_line(line, sizeof(line), mus_offset, streamFile, &line_ok);
|
bytes_read = read_line(line, sizeof(line), mus_offset, sf, &line_ok);
|
||||||
if (!line_ok) goto fail;
|
if (!line_ok) goto fail;
|
||||||
mus_offset += bytes_read;
|
mus_offset += bytes_read;
|
||||||
memcpy(name_base,line,sizeof(name_base));
|
memcpy(name_base,line,sizeof(name_base));
|
||||||
|
@ -217,7 +215,7 @@ static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_lo
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read track entry count */
|
/* read track entry count */
|
||||||
bytes_read = read_line(line, sizeof(line), mus_offset, streamFile, &line_ok);
|
bytes_read = read_line(line, sizeof(line), mus_offset, sf, &line_ok);
|
||||||
if (!line_ok) goto fail;
|
if (!line_ok) goto fail;
|
||||||
if (line[0] == '\0') goto fail;
|
if (line[0] == '\0') goto fail;
|
||||||
mus_offset += bytes_read;
|
mus_offset += bytes_read;
|
||||||
|
@ -235,7 +233,7 @@ static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_lo
|
||||||
}
|
}
|
||||||
|
|
||||||
dir_name[0]='\0';
|
dir_name[0]='\0';
|
||||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
sf->get_name(sf,filename,sizeof(filename));
|
||||||
concatn(sizeof(dir_name),dir_name,filename);
|
concatn(sizeof(dir_name),dir_name,filename);
|
||||||
|
|
||||||
/* find directory name for the directory contianing the MUS */
|
/* find directory name for the directory contianing the MUS */
|
||||||
|
@ -262,7 +260,7 @@ static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_lo
|
||||||
for (i = 0; i < file_count; i++)
|
for (i = 0; i < file_count; i++)
|
||||||
{
|
{
|
||||||
int fields_matched;
|
int fields_matched;
|
||||||
bytes_read = read_line(line,sizeof(line), mus_offset, streamFile, &line_ok);
|
bytes_read = read_line(line,sizeof(line), mus_offset, sf, &line_ok);
|
||||||
if (!line_ok) goto fail;
|
if (!line_ok) goto fail;
|
||||||
mus_offset += bytes_read;
|
mus_offset += bytes_read;
|
||||||
|
|
||||||
|
@ -308,13 +306,13 @@ static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_lo
|
||||||
concatn(NAME_LENGTH,names[i],name);
|
concatn(NAME_LENGTH,names[i],name);
|
||||||
concatn(NAME_LENGTH,names[i],".ACM");
|
concatn(NAME_LENGTH,names[i],".ACM");
|
||||||
|
|
||||||
if (!exists(names[i],streamFile)) {
|
if (!exists(names[i],sf)) {
|
||||||
|
|
||||||
/* We can't test for the directory until we have a file name
|
/* We can't test for the directory until we have a file name
|
||||||
* to look for, so we do it here with the first file that seems to
|
* to look for, so we do it here with the first file that seems to
|
||||||
* be in a subdirectory */
|
* be in a subdirectory */
|
||||||
if (subdir_name[0]=='\0') {
|
if (subdir_name[0]=='\0') {
|
||||||
if (find_directory_name(name_base, dir_name, sizeof(subdir_name), subdir_name, name, filename, streamFile))
|
if (find_directory_name(name_base, dir_name, sizeof(subdir_name), subdir_name, name, filename, sf))
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +323,7 @@ static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_lo
|
||||||
concatn(NAME_LENGTH,names[i],name);
|
concatn(NAME_LENGTH,names[i],name);
|
||||||
concatn(NAME_LENGTH,names[i],".ACM");
|
concatn(NAME_LENGTH,names[i],".ACM");
|
||||||
|
|
||||||
if (!exists(names[i],streamFile)) goto fail;
|
if (!exists(names[i],sf)) goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,41 +2,43 @@
|
||||||
#include "../util.h"
|
#include "../util.h"
|
||||||
|
|
||||||
/* STRM - common Nintendo NDS streaming format */
|
/* STRM - common Nintendo NDS streaming format */
|
||||||
VGMSTREAM * init_vgmstream_nds_strm(STREAMFILE *streamFile) {
|
VGMSTREAM* init_vgmstream_nds_strm(STREAMFILE* sf) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
int channel_count, loop_flag, codec;
|
int channels, loop_flag, codec, sample_rate;
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
if (!check_extensions(streamFile, "strm"))
|
if (!is_id32be(0x00,sf, "STRM"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (read_32bitBE(0x00,streamFile) != 0x5354524D) /* "STRM" */
|
if (!check_extensions(sf, "strm"))
|
||||||
goto fail;
|
|
||||||
if (read_32bitBE(0x04,streamFile) != 0xFFFE0001 && /* Old Header Check */
|
|
||||||
(read_32bitBE(0x04,streamFile) != 0xFEFF0001)) /* Some newer games have a new flag */
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (read_32bitBE(0x10,streamFile) != 0x48454144 && /* "HEAD" */
|
/* BOM check? */
|
||||||
read_32bitLE(0x14,streamFile) != 0x50) /* 0x50-sized head is all I've seen */
|
if (read_u32be(0x04,sf) != 0xFFFE0001 &&
|
||||||
|
read_u32be(0x04,sf) != 0xFEFF0001) /* newer games? */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
codec = read_8bit(0x18,streamFile);
|
if (!is_id32be(0x10,sf, "HEAD") &&
|
||||||
loop_flag = read_8bit(0x19,streamFile);
|
read_u32le(0x14,sf) != 0x50)
|
||||||
channel_count = read_8bit(0x1a,streamFile);
|
goto fail;
|
||||||
if (channel_count > 2) goto fail;
|
|
||||||
|
|
||||||
start_offset = read_32bitLE(0x28,streamFile);
|
codec = read_u8(0x18,sf);
|
||||||
|
loop_flag = read_u8(0x19,sf);
|
||||||
|
sample_rate = read_u16le(0x1c,sf);
|
||||||
|
channels = read_u8(0x1a,sf);
|
||||||
|
if (channels > 2) goto fail;
|
||||||
|
|
||||||
|
start_offset = read_u32le(0x28,sf);
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
vgmstream->sample_rate = (uint16_t)read_16bitLE(0x1c,streamFile);
|
vgmstream->sample_rate = sample_rate;
|
||||||
vgmstream->num_samples = read_32bitLE(0x24,streamFile);
|
vgmstream->num_samples = read_32bitLE(0x24,sf);
|
||||||
vgmstream->loop_start_sample = read_32bitLE(0x20,streamFile);
|
vgmstream->loop_start_sample = read_32bitLE(0x20,sf);
|
||||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||||
|
|
||||||
vgmstream->meta_type = meta_STRM;
|
vgmstream->meta_type = meta_STRM;
|
||||||
|
@ -55,11 +57,11 @@ VGMSTREAM * init_vgmstream_nds_strm(STREAMFILE *streamFile) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->interleave_block_size = read_32bitLE(0x30,streamFile);
|
vgmstream->interleave_block_size = read_32bitLE(0x30,sf);
|
||||||
vgmstream->interleave_last_block_size = read_32bitLE(0x38,streamFile);
|
vgmstream->interleave_last_block_size = read_32bitLE(0x38,sf);
|
||||||
|
|
||||||
|
|
||||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||||
goto fail;
|
goto fail;
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
|
|
|
@ -2,37 +2,35 @@
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
/* NWAV - from Chunsoft games [Fuurai no Shiren Gaiden: Onnakenshi Asuka Kenzan! (PC)] */
|
/* NWAV - from Chunsoft games [Fuurai no Shiren Gaiden: Onnakenshi Asuka Kenzan! (PC)] */
|
||||||
VGMSTREAM * init_vgmstream_nwav(STREAMFILE *sf) {
|
VGMSTREAM* init_vgmstream_nwav(STREAMFILE* sf) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
|
if (!is_id32be(0x00,sf, "NWAV"))
|
||||||
|
goto fail;
|
||||||
/* .nwav: header id (no filenames in bigfiles) */
|
/* .nwav: header id (no filenames in bigfiles) */
|
||||||
if ( !check_extensions(sf,"nwav") )
|
if (!check_extensions(sf,"nwav,") )
|
||||||
goto fail;
|
|
||||||
if (read_32bitBE(0x00,sf) != 0x4E574156) /* "NWAV" */
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
{
|
{
|
||||||
ogg_vorbis_meta_info_t ovmi = {0};
|
ogg_vorbis_meta_info_t ovmi = {0};
|
||||||
int channels;
|
int channels;
|
||||||
|
|
||||||
/* 0x04: version? */
|
/* 0x04: version? */
|
||||||
/* 0x08: crc? */
|
/* 0x08: crc? */
|
||||||
ovmi.stream_size = read_32bitLE(0x0c, sf);
|
ovmi.stream_size = read_u32le(0x0c, sf);
|
||||||
ovmi.loop_end = read_32bitLE(0x10, sf); /* num_samples, actually */
|
ovmi.loop_end = read_u32le(0x10, sf); /* num_samples, actually */
|
||||||
/* 0x14: sample rate */
|
/* 0x14: sample rate */
|
||||||
/* 0x18: bps? (16) */
|
/* 0x18: bps? (16) */
|
||||||
channels = read_8bit(0x19, sf);
|
channels = read_u8(0x19, sf);
|
||||||
start_offset = read_16bitLE(0x1a, sf);
|
start_offset = read_u16le(0x1a, sf);
|
||||||
|
|
||||||
ovmi.loop_flag = read_16bitLE(0x1c, sf) != 0; /* loop count? -1 = loops */
|
ovmi.loop_flag = read_u16le(0x1c, sf) != 0; /* loop count? -1 = loops */
|
||||||
/* 0x1e: always 2? */
|
/* 0x1e: always 2? */
|
||||||
/* 0x20: always 1? */
|
/* 0x20: always 1? */
|
||||||
ovmi.loop_start = read_32bitLE(0x24, sf);
|
ovmi.loop_start = read_u32le(0x24, sf);
|
||||||
/* 0x28: always 1? */
|
/* 0x28: always 1? */
|
||||||
/* 0x2a: always 1? */
|
/* 0x2a: always 1? */
|
||||||
/* 0x2c: always null? */
|
/* 0x2c: always null? */
|
||||||
|
@ -43,15 +41,9 @@ VGMSTREAM * init_vgmstream_nwav(STREAMFILE *sf) {
|
||||||
ovmi.loop_start = ovmi.loop_start / sizeof(int16_t) / channels;
|
ovmi.loop_start = ovmi.loop_start / sizeof(int16_t) / channels;
|
||||||
ovmi.loop_end = ovmi.loop_end / sizeof(int16_t) / channels;
|
ovmi.loop_end = ovmi.loop_end / sizeof(int16_t) / channels;
|
||||||
|
|
||||||
vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
return init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
goto fail;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return vgmstream;
|
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
close_vgmstream(vgmstream);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
|
@ -6,6 +5,28 @@
|
||||||
#include "ogg_vorbis_streamfile.h"
|
#include "ogg_vorbis_streamfile.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef VGM_USE_VORBIS
|
||||||
|
static VGMSTREAM* _init_vgmstream_ogg_vorbis(STREAMFILE* sf);
|
||||||
|
static VGMSTREAM* _init_vgmstream_ogg_vorbis_config(STREAMFILE* sf, off_t start, const ogg_vorbis_meta_info_t* ovmi);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
||||||
|
#ifdef VGM_USE_VORBIS
|
||||||
|
return _init_vgmstream_ogg_vorbis(sf);
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
VGMSTREAM* init_vgmstream_ogg_vorbis_config(STREAMFILE* sf, off_t start, const ogg_vorbis_meta_info_t* ovmi) {
|
||||||
|
#ifdef VGM_USE_VORBIS
|
||||||
|
return _init_vgmstream_ogg_vorbis_config(sf, start, ovmi);
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef VGM_USE_VORBIS
|
||||||
static void um3_ogg_decryption_callback(void* ptr, size_t size, size_t nmemb, void* datasource) {
|
static void um3_ogg_decryption_callback(void* ptr, size_t size, size_t nmemb, void* datasource) {
|
||||||
uint8_t *ptr8 = ptr;
|
uint8_t *ptr8 = ptr;
|
||||||
size_t bytes_read = size * nmemb;
|
size_t bytes_read = size * nmemb;
|
||||||
|
@ -110,8 +131,8 @@ static const uint32_t xiph_mappings[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Ogg Vorbis, may contain loop comments */
|
/* Ogg Vorbis - standard .ogg with (possibly) loop comments/metadata */
|
||||||
VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
static VGMSTREAM* _init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
||||||
VGMSTREAM* vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
STREAMFILE* temp_sf = NULL;
|
STREAMFILE* temp_sf = NULL;
|
||||||
ogg_vorbis_io_config_data cfg = {0};
|
ogg_vorbis_io_config_data cfg = {0};
|
||||||
|
@ -416,7 +437,7 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
||||||
ovmi.meta_type = meta_OGG_VORBIS;
|
ovmi.meta_type = meta_OGG_VORBIS;
|
||||||
}
|
}
|
||||||
|
|
||||||
vgmstream = init_vgmstream_ogg_vorbis_config(temp_sf != NULL ? temp_sf : sf, start_offset, &ovmi);
|
vgmstream = _init_vgmstream_ogg_vorbis_config(temp_sf != NULL ? temp_sf : sf, start_offset, &ovmi);
|
||||||
|
|
||||||
close_streamfile(temp_sf);
|
close_streamfile(temp_sf);
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
@ -426,7 +447,7 @@ fail:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
VGMSTREAM* init_vgmstream_ogg_vorbis_config(STREAMFILE* sf, off_t start, const ogg_vorbis_meta_info_t* ovmi) {
|
static VGMSTREAM* _init_vgmstream_ogg_vorbis_config(STREAMFILE* sf, off_t start, const ogg_vorbis_meta_info_t* ovmi) {
|
||||||
VGMSTREAM* vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
ogg_vorbis_codec_data* data = NULL;
|
ogg_vorbis_codec_data* data = NULL;
|
||||||
ogg_vorbis_io io = {0};
|
ogg_vorbis_io io = {0};
|
||||||
|
|
|
@ -3,15 +3,14 @@
|
||||||
|
|
||||||
/* OGV - .ogg container (not related to ogv video) [Bloody Rondo (PC)] */
|
/* OGV - .ogg container (not related to ogv video) [Bloody Rondo (PC)] */
|
||||||
VGMSTREAM* init_vgmstream_ogv_3rdeye(STREAMFILE* sf) {
|
VGMSTREAM* init_vgmstream_ogv_3rdeye(STREAMFILE* sf) {
|
||||||
VGMSTREAM* vgmstream = NULL;
|
uint32_t subfile_offset, subfile_size;
|
||||||
off_t subfile_offset, subfile_size;
|
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
if (!check_extensions(sf,"ogv"))
|
|
||||||
goto fail;
|
|
||||||
if (!is_id32be(0x00,sf, "OGV\0"))
|
if (!is_id32be(0x00,sf, "OGV\0"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
if (!check_extensions(sf,"ogv"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* 0x04: PCM size */
|
/* 0x04: PCM size */
|
||||||
subfile_size = read_u32le(0x08, sf);
|
subfile_size = read_u32le(0x08, sf);
|
||||||
|
@ -20,21 +19,15 @@ VGMSTREAM* init_vgmstream_ogv_3rdeye(STREAMFILE* sf) {
|
||||||
|
|
||||||
/* no loops (files bgm does full loops but sfx doesn't) */
|
/* no loops (files bgm does full loops but sfx doesn't) */
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
{
|
{
|
||||||
ogg_vorbis_meta_info_t ovmi = {0};
|
ogg_vorbis_meta_info_t ovmi = {0};
|
||||||
|
|
||||||
ovmi.meta_type = meta_OGV_3RDEYE;
|
ovmi.meta_type = meta_OGV_3RDEYE;
|
||||||
ovmi.stream_size = subfile_size;
|
ovmi.stream_size = subfile_size;
|
||||||
|
|
||||||
vgmstream = init_vgmstream_ogg_vorbis_config(sf, subfile_offset, &ovmi);
|
return init_vgmstream_ogg_vorbis_config(sf, subfile_offset, &ovmi);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
goto fail;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return vgmstream;
|
|
||||||
fail:
|
fail:
|
||||||
close_vgmstream(vgmstream);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,15 +132,27 @@ VGMSTREAM* init_vgmstream_psb(STREAMFILE* sf) {
|
||||||
|
|
||||||
switch(psb.codec) {
|
switch(psb.codec) {
|
||||||
case PCM:
|
case PCM:
|
||||||
|
if (psb.layers > 1) {
|
||||||
|
/* somehow R offset can go before L, use layered */
|
||||||
|
vgmstream->layout_data = build_layered_psb(sf, &psb);
|
||||||
|
if (!vgmstream->layout_data) goto fail;
|
||||||
|
vgmstream->layout_type = layout_layered;
|
||||||
|
|
||||||
|
if (!vgmstream->num_samples)
|
||||||
|
vgmstream->num_samples = pcm_bytes_to_samples(psb.stream_size[0], 1, psb.bps);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vgmstream->layout_type = layout_interleave;
|
||||||
|
vgmstream->interleave_block_size = psb.block_size / psb.channels;
|
||||||
|
if (!vgmstream->num_samples)
|
||||||
|
vgmstream->num_samples = pcm_bytes_to_samples(psb.stream_size[0], psb.channels, psb.bps);
|
||||||
|
}
|
||||||
|
|
||||||
switch(psb.bps) {
|
switch(psb.bps) {
|
||||||
case 16: vgmstream->coding_type = coding_PCM16LE; break; /* Legend of Mana (PC), Namco Museum Archives Vol.1 (PC) */
|
case 16: vgmstream->coding_type = coding_PCM16LE; break; /* Legend of Mana (PC), Namco Museum Archives Vol.1 (PC) */
|
||||||
case 24: vgmstream->coding_type = coding_PCM24LE; break; /* Legend of Mana (PC) */
|
case 24: vgmstream->coding_type = coding_PCM24LE; break; /* Legend of Mana (PC) */
|
||||||
default: goto fail;
|
default: goto fail;
|
||||||
}
|
}
|
||||||
vgmstream->layout_type = layout_interleave;
|
|
||||||
vgmstream->interleave_block_size = psb.block_size / psb.channels;
|
|
||||||
if (!vgmstream->num_samples)
|
|
||||||
vgmstream->num_samples = pcm_bytes_to_samples(psb.stream_size[0], psb.channels, psb.bps);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSADPCM: /* [Senxin Aleste (AC)] */
|
case MSADPCM: /* [Senxin Aleste (AC)] */
|
||||||
|
@ -279,6 +291,21 @@ fail:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static VGMSTREAM* try_init_vgmstream(STREAMFILE* sf, init_vgmstream_t init_vgmstream, const char* extension, uint32_t offset, uint32_t size) {
|
||||||
|
STREAMFILE* temp_sf = NULL;
|
||||||
|
VGMSTREAM* v = NULL;
|
||||||
|
|
||||||
|
temp_sf = setup_subfile_streamfile(sf, offset, size, extension);
|
||||||
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
|
v = init_vgmstream(temp_sf);
|
||||||
|
close_streamfile(temp_sf);
|
||||||
|
return v;
|
||||||
|
fail:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static layered_layout_data* build_layered_psb(STREAMFILE* sf, psb_header_t* psb) {
|
static layered_layout_data* build_layered_psb(STREAMFILE* sf, psb_header_t* psb) {
|
||||||
layered_layout_data* data = NULL;
|
layered_layout_data* data = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
@ -289,25 +316,39 @@ static layered_layout_data* build_layered_psb(STREAMFILE* sf, psb_header_t* psb)
|
||||||
if (!data) goto fail;
|
if (!data) goto fail;
|
||||||
|
|
||||||
for (i = 0; i < psb->layers; i++) {
|
for (i = 0; i < psb->layers; i++) {
|
||||||
STREAMFILE* temp_sf = NULL;
|
|
||||||
VGMSTREAM* (*init_vgmstream)(STREAMFILE* sf) = NULL;
|
|
||||||
const char* extension = NULL;
|
|
||||||
|
|
||||||
switch (psb->codec) {
|
switch (psb->codec) {
|
||||||
case DSP:
|
case PCM: {
|
||||||
extension = "adpcm";
|
VGMSTREAM* v = allocate_vgmstream(1, 0);
|
||||||
init_vgmstream = init_vgmstream_ngc_dsp_std_le;
|
if (!v) goto fail;
|
||||||
|
|
||||||
|
data->layers[i] = v;
|
||||||
|
|
||||||
|
v->sample_rate = psb->sample_rate;
|
||||||
|
v->num_samples = psb->num_samples;
|
||||||
|
|
||||||
|
switch(psb->bps) {
|
||||||
|
case 16: v->coding_type = coding_PCM16LE; break;
|
||||||
|
case 24: v->coding_type = coding_PCM24LE; break;
|
||||||
|
default: goto fail;
|
||||||
|
}
|
||||||
|
v->layout_type = layout_none;
|
||||||
|
if (!v->num_samples)
|
||||||
|
v->num_samples = pcm_bytes_to_samples(psb->stream_size[i], 1, psb->bps);
|
||||||
|
|
||||||
|
if (!vgmstream_open_stream(v, sf, psb->stream_offset[i]))
|
||||||
|
goto fail;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DSP:
|
||||||
|
data->layers[i] = try_init_vgmstream(sf, init_vgmstream_ngc_dsp_std_le, "adpcm", psb->stream_offset[i], psb->stream_size[i]);
|
||||||
|
if (!data->layers[i]) goto fail;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
VGM_LOG("psb: layer not implemented\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
temp_sf = setup_subfile_streamfile(sf, psb->stream_offset[i], psb->stream_size[i], extension);
|
|
||||||
if (!temp_sf) goto fail;
|
|
||||||
|
|
||||||
data->layers[i] = init_vgmstream(temp_sf);
|
|
||||||
close_streamfile(temp_sf);
|
|
||||||
if (!data->layers[i]) goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setup layered VGMSTREAMs */
|
/* setup layered VGMSTREAMs */
|
||||||
|
@ -397,6 +438,7 @@ static int prepare_codec(STREAMFILE* sf, psb_header_t* psb) {
|
||||||
if (!ext)
|
if (!ext)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
/* common, multichannel */
|
||||||
if (strcmp(ext, ".opus") == 0) {
|
if (strcmp(ext, ".opus") == 0) {
|
||||||
psb->codec = OPUSNX;
|
psb->codec = OPUSNX;
|
||||||
|
|
||||||
|
@ -409,12 +451,22 @@ static int prepare_codec(STREAMFILE* sf, psb_header_t* psb) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Legend of Mana (Switch), layered */
|
||||||
if (strcmp(ext, ".adpcm") == 0) {
|
if (strcmp(ext, ".adpcm") == 0) {
|
||||||
psb->codec = DSP;
|
psb->codec = DSP;
|
||||||
|
|
||||||
psb->channels = psb->layers;
|
psb->channels = psb->layers;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Castlevania Advance Collection (Switch), layered */
|
||||||
|
if (strcmp(ext, ".p16") == 0) {
|
||||||
|
psb->codec = PCM;
|
||||||
|
psb->bps = 16;
|
||||||
|
|
||||||
|
psb->channels = psb->layers;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(spec, "ps3") == 0) {
|
if (strcmp(spec, "ps3") == 0) {
|
||||||
|
|
|
@ -215,7 +215,13 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
#ifdef VGM_USE_VORBIS
|
||||||
case 0x6771: /* Ogg Vorbis (mode 3+) */
|
//case 0x674f: /* Ogg Vorbis (mode 1) */
|
||||||
|
//case 0x6750: /* Ogg Vorbis (mode 2) */
|
||||||
|
//case 0x6751: /* Ogg Vorbis (mode 3) */
|
||||||
|
case 0x676f: /* Ogg Vorbis (mode 1+) [Only One 2 (PC)] */
|
||||||
|
//case 0x6770: /* Ogg Vorbis (mode 2+) */
|
||||||
|
case 0x6771: /* Ogg Vorbis (mode 3+) [Liar-soft games] */
|
||||||
|
/* vorbis.acm codecs (official-ish, "+" = CBR-style modes?) */
|
||||||
fmt->coding_type = coding_OGG_VORBIS;
|
fmt->coding_type = coding_OGG_VORBIS;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
@ -233,7 +239,7 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk
|
||||||
(read_u16 (offset+0x26,sf));
|
(read_u16 (offset+0x26,sf));
|
||||||
uint32_t guid3 = read_u32be(offset+0x28,sf);
|
uint32_t guid3 = read_u32be(offset+0x28,sf);
|
||||||
uint32_t guid4 = read_u32be(offset+0x2c,sf);
|
uint32_t guid4 = read_u32be(offset+0x2c,sf);
|
||||||
//;VGM_LOG("RIFF: guid %08x %08x %08x %08x\n", guid1, guid2, guid3, guid4);
|
//;VGM_LOG("riff: guid %08x %08x %08x %08x\n", guid1, guid2, guid3, guid4);
|
||||||
|
|
||||||
/* PCM GUID (0x00000001,0000,0010,80,00,00,AA,00,38,9B,71) */
|
/* PCM GUID (0x00000001,0000,0010,80,00,00,AA,00,38,9B,71) */
|
||||||
if (guid1 == 0x00000001 && guid2 == 0x00000010 && guid3 == 0x800000AA && guid4 == 0x00389B71) {
|
if (guid1 == 0x00000001 && guid2 == 0x00000010 && guid3 == 0x800000AA && guid4 == 0x00389B71) {
|
||||||
|
@ -280,7 +286,7 @@ static int read_fmt(int big_endian, STREAMFILE* sf, off_t offset, riff_fmt_chunk
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* FFmpeg may play it */
|
/* FFmpeg may play it */
|
||||||
//vgm_logi("WWISE: unknown codec 0x%04x (report)\n", fmt->format);
|
//vgm_logi("RIFF: unknown codec 0x%04x (report)\n", fmt->format);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,7 +324,10 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||||
off_t mwv_ctrl_offset = -1;
|
off_t mwv_ctrl_offset = -1;
|
||||||
|
|
||||||
|
|
||||||
/* check extension */
|
/* checks*/
|
||||||
|
if (!is_id32be(0x00,sf,"RIFF"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* .lwav: to avoid hijacking .wav
|
/* .lwav: to avoid hijacking .wav
|
||||||
* .xwav: fake for Xbox games (not needed anymore)
|
* .xwav: fake for Xbox games (not needed anymore)
|
||||||
* .da: The Great Battle VI (PS1)
|
* .da: The Great Battle VI (PS1)
|
||||||
|
@ -355,21 +364,19 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check header */
|
riff_size = read_u32le(0x04,sf);
|
||||||
if (!is_id32be(0x00,sf,"RIFF"))
|
|
||||||
goto fail;
|
|
||||||
if (!is_id32be(0x08,sf, "WAVE"))
|
if (!is_id32be(0x08,sf, "WAVE"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
riff_size = read_u32le(0x04,sf);
|
|
||||||
file_size = get_streamfile_size(sf);
|
file_size = get_streamfile_size(sf);
|
||||||
|
|
||||||
/* some games have wonky sizes, selectively fix to catch bad rips and new mutations */
|
/* some games have wonky sizes, selectively fix to catch bad rips and new mutations */
|
||||||
if (file_size != riff_size + 0x08) {
|
if (file_size != riff_size + 0x08) {
|
||||||
uint16_t codec = read_u16le(0x14,sf);
|
uint16_t codec = read_u16le(0x14,sf);
|
||||||
|
|
||||||
if (codec == 0x6771 && riff_size + 0x08 + 0x01 == file_size)
|
if ((codec & 0xFF00) == 0x6700 && riff_size + 0x08 + 0x01 == file_size)
|
||||||
riff_size += 0x01; /* [Shikkoku no Sharnoth (PC)] (Sony Sound Forge?) */
|
riff_size += 0x01; /* [Shikkoku no Sharnoth (PC), Only One 2 (PC)] (Sony Sound Forge?) */
|
||||||
|
|
||||||
else if (codec == 0x0069 && riff_size == file_size)
|
else if (codec == 0x0069 && riff_size == file_size)
|
||||||
riff_size -= 0x08; /* [Dynasty Warriors 3 (Xbox), BloodRayne (Xbox)] */
|
riff_size -= 0x08; /* [Dynasty Warriors 3 (Xbox), BloodRayne (Xbox)] */
|
||||||
|
@ -422,6 +429,7 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||||
/* check for truncated RIFF */
|
/* check for truncated RIFF */
|
||||||
if (file_size != riff_size + 0x08) {
|
if (file_size != riff_size + 0x08) {
|
||||||
vgm_logi("RIFF: wrong expected size (report/re-rip?)\n");
|
vgm_logi("RIFF: wrong expected size (report/re-rip?)\n");
|
||||||
|
VGM_LOG("riff: file_size = %x, riff_size+8 = %x\n", file_size, riff_size + 0x08); /* don't log to user */
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -774,8 +782,9 @@ VGMSTREAM* init_vgmstream_riff(STREAMFILE* sf) {
|
||||||
#endif
|
#endif
|
||||||
#ifdef VGM_USE_VORBIS
|
#ifdef VGM_USE_VORBIS
|
||||||
case coding_OGG_VORBIS: {
|
case coding_OGG_VORBIS: {
|
||||||
/* special handling of Liar-soft's buggy RIFF+Ogg made with Soundforge [Shikkoku no Sharnoth (PC)] */
|
/* special handling of Liar-soft's buggy RIFF+Ogg made with Soundforge/vorbis.acm [Shikkoku no Sharnoth (PC)],
|
||||||
STREAMFILE *temp_sf = setup_riff_ogg_streamfile(sf, start_offset, data_size);
|
* and rarely other devs, not always buggy [Kirara Kirara NTR (PC), No One 2 (PC)] */
|
||||||
|
STREAMFILE* temp_sf = setup_riff_ogg_streamfile(sf, start_offset, data_size);
|
||||||
if (!temp_sf) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
vgmstream->codec_data = init_ogg_vorbis(temp_sf, 0x00, get_streamfile_size(temp_sf), NULL);
|
vgmstream->codec_data = init_ogg_vorbis(temp_sf, 0x00, get_streamfile_size(temp_sf), NULL);
|
||||||
|
@ -983,13 +992,13 @@ VGMSTREAM* init_vgmstream_rifx(STREAMFILE* sf) {
|
||||||
int FormatChunkFound = 0, DataChunkFound = 0;
|
int FormatChunkFound = 0, DataChunkFound = 0;
|
||||||
|
|
||||||
|
|
||||||
/* check extension, case insensitive */
|
/* checks */
|
||||||
|
if (!is_id32be(0x00,sf, "RIFX"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
if (!check_extensions(sf, "wav,lwav"))
|
if (!check_extensions(sf, "wav,lwav"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* check header */
|
|
||||||
if (!is_id32be(0x00,sf, "RIFX"))
|
|
||||||
goto fail;
|
|
||||||
if (!is_id32be(0x08,sf, "WAVE"))
|
if (!is_id32be(0x08,sf, "WAVE"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
|
|
@ -3,22 +3,22 @@
|
||||||
#include "deblock_streamfile.h"
|
#include "deblock_streamfile.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
off_t patch_offset;
|
uint32_t patch_offset;
|
||||||
} riff_ogg_io_data;
|
} riff_ogg_io_data;
|
||||||
|
|
||||||
static size_t riff_ogg_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_t length, riff_ogg_io_data* data) {
|
static size_t riff_ogg_io_read(STREAMFILE* sf, uint8_t* dst, uint32_t offset, size_t length, riff_ogg_io_data* data) {
|
||||||
size_t bytes = read_streamfile(dest, offset, length, sf);
|
size_t bytes = read_streamfile(dst, offset, length, sf);
|
||||||
|
|
||||||
/* has garbage init Oggs pages, patch bad flag */
|
/* has garbage init Oggs pages, patch bad flag */
|
||||||
if (data->patch_offset && data->patch_offset >= offset && data->patch_offset < offset + bytes) {
|
if (data->patch_offset && data->patch_offset >= offset && data->patch_offset < offset + bytes) {
|
||||||
VGM_ASSERT(dest[data->patch_offset - offset] != 0x02, "RIFF Ogg: bad patch offset at %lx\n", data->patch_offset);
|
VGM_ASSERT(dst[data->patch_offset - offset] != 0x02, "RIFF Ogg: bad patch offset at %x\n", data->patch_offset);
|
||||||
dest[data->patch_offset - offset] = 0x00;
|
dst[data->patch_offset - offset] = 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t ogg_get_page(uint8_t *buf, size_t bufsize, off_t offset, STREAMFILE *sf) {
|
static size_t ogg_get_page(uint8_t* buf, size_t bufsize, uint32_t offset, STREAMFILE* sf) {
|
||||||
size_t segments, bytes, page_size;
|
size_t segments, bytes, page_size;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -43,8 +43,8 @@ fail:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* patches Ogg with weirdness */
|
/* patches Ogg with weirdness */
|
||||||
static STREAMFILE* setup_riff_ogg_streamfile(STREAMFILE *sf, off_t start, size_t size) {
|
static STREAMFILE* setup_riff_ogg_streamfile(STREAMFILE* sf, uint32_t start, size_t size) {
|
||||||
off_t patch_offset = 0;
|
uint32_t patch_offset = 0;
|
||||||
size_t real_size = size;
|
size_t real_size = size;
|
||||||
uint8_t buf[0x1000];
|
uint8_t buf[0x1000];
|
||||||
|
|
||||||
|
@ -52,11 +52,11 @@ static STREAMFILE* setup_riff_ogg_streamfile(STREAMFILE *sf, off_t start, size_t
|
||||||
/* initial page flag is repeated and causes glitches in decoders, find bad offset */
|
/* initial page flag is repeated and causes glitches in decoders, find bad offset */
|
||||||
//todo callback could patch on-the-fly by analyzing all "OggS", but is problematic due to arbitrary offsets
|
//todo callback could patch on-the-fly by analyzing all "OggS", but is problematic due to arbitrary offsets
|
||||||
{
|
{
|
||||||
off_t offset = start;
|
uint32_t offset = start;
|
||||||
size_t page_size;
|
size_t page_size;
|
||||||
off_t offset_limit = start + size; /* usually in the first 0x3000 but can be +0x100000 */
|
uint32_t offset_limit = start + size; /* usually in the first 0x3000 but can be +0x100000 */
|
||||||
//todo this doesn't seem to help much
|
//todo this doesn't seem to help much
|
||||||
STREAMFILE *temp_sf = reopen_streamfile(sf, 0x100); /* use small-ish sf to avoid reading the whole thing */
|
STREAMFILE* temp_sf = reopen_streamfile(sf, 0x100); /* use small-ish sf to avoid reading the whole thing */
|
||||||
|
|
||||||
/* first page is ok */
|
/* first page is ok */
|
||||||
page_size = ogg_get_page(buf, sizeof(buf), offset, temp_sf);
|
page_size = ogg_get_page(buf, sizeof(buf), offset, temp_sf);
|
||||||
|
@ -66,7 +66,7 @@ static STREAMFILE* setup_riff_ogg_streamfile(STREAMFILE *sf, off_t start, size_t
|
||||||
page_size = ogg_get_page(buf, sizeof(buf), offset, temp_sf);
|
page_size = ogg_get_page(buf, sizeof(buf), offset, temp_sf);
|
||||||
if (page_size == 0) break;
|
if (page_size == 0) break;
|
||||||
|
|
||||||
if (get_u32be(buf + 0x00) != 0x4f676753) /* "OggS" */
|
if (get_u32be(buf + 0x00) != get_id32be("OggS"))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (get_u16be(buf + 0x04) == 0x0002) { /* start page flag */
|
if (get_u16be(buf + 0x04) == 0x0002) { /* start page flag */
|
||||||
|
@ -80,8 +80,9 @@ static STREAMFILE* setup_riff_ogg_streamfile(STREAMFILE *sf, off_t start, size_t
|
||||||
|
|
||||||
close_streamfile(temp_sf);
|
close_streamfile(temp_sf);
|
||||||
|
|
||||||
if (patch_offset == 0)
|
/* no need to patch initial flag */
|
||||||
return NULL;
|
//if (patch_offset == 0)
|
||||||
|
// return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* has a bunch of padding(?) pages at the end with no data nor flag that confuse decoders, find actual end */
|
/* has a bunch of padding(?) pages at the end with no data nor flag that confuse decoders, find actual end */
|
||||||
|
@ -89,14 +90,14 @@ static STREAMFILE* setup_riff_ogg_streamfile(STREAMFILE *sf, off_t start, size_t
|
||||||
size_t chunk_size = sizeof(buf); /* not worth testing more */
|
size_t chunk_size = sizeof(buf); /* not worth testing more */
|
||||||
size_t max_size = size;
|
size_t max_size = size;
|
||||||
size_t pos;
|
size_t pos;
|
||||||
off_t read_offset = start + size - chunk_size;
|
uint32_t read_offset = start + size - chunk_size;
|
||||||
|
|
||||||
pos = read_streamfile(buf, read_offset, chunk_size, sf);
|
pos = read_streamfile(buf, read_offset, chunk_size, sf);
|
||||||
if (read_offset < 0 || pos <= 0x1a) return NULL;
|
if (read_offset < 0 || pos <= 0x1a) return NULL;
|
||||||
|
|
||||||
pos -= 0x1a; /* at least one OggS page */
|
pos -= 0x1a; /* at least one OggS page */
|
||||||
while (pos > 0) {
|
while (pos > 0) {
|
||||||
if (get_u32be(buf + pos + 0x00) == 0x4f676753) { /* "OggS" */
|
if (get_u32be(buf + pos + 0x00) == get_id32be("OggS")) {
|
||||||
|
|
||||||
if (get_u16be(buf + pos + 0x04) == 0x0004) { /* last page flag is ok */
|
if (get_u16be(buf + pos + 0x04) == 0x0004) { /* last page flag is ok */
|
||||||
real_size = max_size;
|
real_size = max_size;
|
||||||
|
@ -112,7 +113,7 @@ static STREAMFILE* setup_riff_ogg_streamfile(STREAMFILE *sf, off_t start, size_t
|
||||||
|
|
||||||
/* actual custom streamfile init */
|
/* actual custom streamfile init */
|
||||||
{
|
{
|
||||||
STREAMFILE *new_sf = NULL;
|
STREAMFILE* new_sf = NULL;
|
||||||
riff_ogg_io_data io_data = {0};
|
riff_ogg_io_data io_data = {0};
|
||||||
|
|
||||||
io_data.patch_offset = patch_offset;
|
io_data.patch_offset = patch_offset;
|
||||||
|
|
|
@ -12,8 +12,8 @@ VGMSTREAM* init_vgmstream_sps_n1(STREAMFILE* sf) {
|
||||||
off_t subfile_offset;
|
off_t subfile_offset;
|
||||||
size_t subfile_size;
|
size_t subfile_size;
|
||||||
|
|
||||||
VGMSTREAM* (*init_vgmstream_subfile)(STREAMFILE*) = NULL;
|
init_vgmstream_t init_vgmstream = NULL;
|
||||||
const char* extension;
|
const char* extension = NULL;
|
||||||
uint32_t (*read_u32)(off_t,STREAMFILE*);
|
uint32_t (*read_u32)(off_t,STREAMFILE*);
|
||||||
uint16_t (*read_u16)(off_t,STREAMFILE*);
|
uint16_t (*read_u16)(off_t,STREAMFILE*);
|
||||||
|
|
||||||
|
@ -38,12 +38,12 @@ VGMSTREAM* init_vgmstream_sps_n1(STREAMFILE* sf) {
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case 1:
|
case 1:
|
||||||
init_vgmstream_subfile = init_vgmstream_vag;
|
init_vgmstream = init_vgmstream_vag;
|
||||||
extension = "vag";
|
extension = "vag";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
init_vgmstream_subfile = init_vgmstream_riff;
|
init_vgmstream = init_vgmstream_riff;
|
||||||
extension = "at3";
|
extension = "at3";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ VGMSTREAM* init_vgmstream_sps_n1(STREAMFILE* sf) {
|
||||||
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, extension);
|
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, extension);
|
||||||
if (!temp_sf) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
vgmstream = init_vgmstream_subfile(temp_sf);
|
vgmstream = init_vgmstream(temp_sf);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
vgmstream->sample_rate = sample_rate; /* .vag header doesn't match */
|
vgmstream->sample_rate = sample_rate; /* .vag header doesn't match */
|
||||||
|
@ -81,7 +81,7 @@ VGMSTREAM* init_vgmstream_sps_n1_segmented(STREAMFILE* sf) {
|
||||||
int loop_flag, type, sample_rate;
|
int loop_flag, type, sample_rate;
|
||||||
int i, segment;
|
int i, segment;
|
||||||
|
|
||||||
VGMSTREAM* (*init_vgmstream_subfile)(STREAMFILE*) = NULL;
|
init_vgmstream_t init_vgmstream = NULL;
|
||||||
const char* extension;
|
const char* extension;
|
||||||
segmented_layout_data* data = NULL;
|
segmented_layout_data* data = NULL;
|
||||||
int segment_count, loop_start_segment, loop_end_segment;
|
int segment_count, loop_start_segment, loop_end_segment;
|
||||||
|
@ -101,15 +101,13 @@ VGMSTREAM* init_vgmstream_sps_n1_segmented(STREAMFILE* sf) {
|
||||||
/* 0x0c: num_samples (slightly smaller than added samples?) */
|
/* 0x0c: num_samples (slightly smaller than added samples?) */
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
case 7:
|
case 7:
|
||||||
init_vgmstream_subfile = init_vgmstream_ogg_vorbis;
|
init_vgmstream = init_vgmstream_ogg_vorbis;
|
||||||
extension = "ogg";
|
extension = "ogg";
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
|
|
||||||
case 9:
|
case 9:
|
||||||
init_vgmstream_subfile = init_vgmstream_opus_std;
|
init_vgmstream = init_vgmstream_opus_std;
|
||||||
extension = "opus";
|
extension = "opus";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -155,7 +153,7 @@ VGMSTREAM* init_vgmstream_sps_n1_segmented(STREAMFILE* sf) {
|
||||||
temp_sf = setup_subfile_streamfile(sf, segment_offset,segment_size, extension);
|
temp_sf = setup_subfile_streamfile(sf, segment_offset,segment_size, extension);
|
||||||
if (!temp_sf) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
data->segments[segment] = init_vgmstream_subfile(temp_sf);
|
data->segments[segment] = init_vgmstream(temp_sf);
|
||||||
close_streamfile(temp_sf);
|
close_streamfile(temp_sf);
|
||||||
if (!data->segments[segment]) goto fail;
|
if (!data->segments[segment]) goto fail;
|
||||||
|
|
||||||
|
|
|
@ -213,11 +213,6 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa
|
||||||
* table entries don't need to match (table2 may be slightly bigger)
|
* table entries don't need to match (table2 may be slightly bigger)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//breaking ta rules full test again, fuse with Pac-Man World 3
|
|
||||||
//same on xbox and pc
|
|
||||||
//same with zapper + pw3 gc
|
|
||||||
|
|
||||||
|
|
||||||
//todo loop start/end values may be off for some headers
|
//todo loop start/end values may be off for some headers
|
||||||
|
|
||||||
/* Fuzion Frenzy (Xbox)[2001] wma */
|
/* Fuzion Frenzy (Xbox)[2001] wma */
|
||||||
|
@ -251,7 +246,7 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa
|
||||||
/* Cubix Robots for Everyone: Showdown (GC)[2003] */
|
/* Cubix Robots for Everyone: Showdown (GC)[2003] */
|
||||||
if ( read_u32be(0x04,sf_h) == 0x00000900 &&
|
if ( read_u32be(0x04,sf_h) == 0x00000900 &&
|
||||||
read_u32be(0x0c,sf_h) != header_size &&
|
read_u32be(0x0c,sf_h) != header_size &&
|
||||||
read_u32le(0x24,sf_h) != 0 &&
|
read_u32be(0x24,sf_h) != 0 &&
|
||||||
read_u32be(0x24,sf_h) == read_u32be(0x90,sf_h) && /* sample rate repeat */
|
read_u32be(0x24,sf_h) == read_u32be(0x90,sf_h) && /* sample rate repeat */
|
||||||
read_u32be(0xa0,sf_h) == header_size /* ~0x3C0 */
|
read_u32be(0xa0,sf_h) == header_size /* ~0x3C0 */
|
||||||
) {
|
) {
|
||||||
|
@ -367,9 +362,11 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Zapper: One Wicked Cricket! (GC)[2005] */
|
/* Zapper: One Wicked Cricket! Beta (GC)[2002] */
|
||||||
|
/* Zapper: One Wicked Cricket! (GC)[2002] */
|
||||||
if ( read_u32be(0x04,sf_h) == 0x00000900 &&
|
if ( read_u32be(0x04,sf_h) == 0x00000900 &&
|
||||||
read_u32be(0x24,sf_h) == read_u32be(0xB0,sf_h) && /* sample rate repeat */
|
read_u32be(0x24,sf_h) == read_u32be(0xB0,sf_h) && /* sample rate repeat */
|
||||||
|
read_u32be(0x88,sf_h) != 0 &&
|
||||||
read_u32le(0xc0,sf_h) == header_size /* LE! */
|
read_u32le(0xc0,sf_h) == header_size /* LE! */
|
||||||
) {
|
) {
|
||||||
/* 0x08: null */
|
/* 0x08: null */
|
||||||
|
@ -399,10 +396,36 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Zapper: One Wicked Cricket! Beta (PS2)[2002] */
|
||||||
|
if ( read_u32be(0x04,sf_h) == 0x00000900 &&
|
||||||
|
read_u32le(0x2c,sf_h) == 44100 && /* sample rate */
|
||||||
|
read_u32le(0x70,sf_h) == 0 && /* sample rate repeat? */
|
||||||
|
header_size == 0x78
|
||||||
|
) {
|
||||||
|
/* 0x08: null */
|
||||||
|
/* 0x0c: hashname */
|
||||||
|
/* 0x28: loop start? */
|
||||||
|
strwav->sample_rate = read_s32le(0x2c,sf_h);
|
||||||
|
/* 0x30: number of 0x800 sectors */
|
||||||
|
strwav->flags = read_u32le(0x34,sf_h);
|
||||||
|
strwav->num_samples = read_s32le(0x5c,sf_h);
|
||||||
|
strwav->tracks = read_s32le(0x60,sf_h);
|
||||||
|
|
||||||
|
strwav->loop_start = 0;
|
||||||
|
strwav->loop_end = 0;
|
||||||
|
|
||||||
|
strwav->codec = PSX;
|
||||||
|
strwav->interleave = strwav->tracks > 1 ? 0x8000 : 0x8000;
|
||||||
|
//todo: tracks are stereo blocks of size 0x20000*tracks, containing 4 interleaves of 0x8000:
|
||||||
|
// | 1 2 1 2 | 3 4 3 4 | 5 6 5 6 | 1 2 1 2 | 3 4 3 4 | 5 6 5 6 | ...
|
||||||
|
;VGM_LOG("STR+WAV: header ZPb (PS2)\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zapper: One Wicked Cricket! (PS2)[2002] */
|
||||||
/* The Fairly OddParents - Breakin' da Rules (PS2)[2003] */
|
/* The Fairly OddParents - Breakin' da Rules (PS2)[2003] */
|
||||||
/* The Fairly OddParents! - Shadow Showdown (PS2)[2004] */
|
/* The Fairly OddParents! - Shadow Showdown (PS2)[2004] */
|
||||||
/* Bad Boys II (PS2)[2004] */
|
/* Bad Boys II (PS2)[2004] */
|
||||||
/* Zapper: One Wicked Cricket! (PS2)[2005] */
|
|
||||||
if ((read_u32be(0x04,sf_h) == 0x00000800 || /* BB2 */
|
if ((read_u32be(0x04,sf_h) == 0x00000800 || /* BB2 */
|
||||||
read_u32be(0x04,sf_h) == 0x00000900) && /* FOP, ZP */
|
read_u32be(0x04,sf_h) == 0x00000900) && /* FOP, ZP */
|
||||||
read_u32le(0x24,sf_h) == read_u32le(0x70,sf_h) && /* sample rate repeat */
|
read_u32le(0x24,sf_h) == read_u32le(0x70,sf_h) && /* sample rate repeat */
|
||||||
|
@ -456,7 +479,62 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Zapper: One Wicked Cricket! (PC)[2005] */
|
/* Zapper: One Wicked Cricket! Beta (Xbox)[2002] */
|
||||||
|
if ( read_u32be(0x04,sf_h) == 0x00000900 &&
|
||||||
|
read_u32le(0x0c,sf_h) != header_size &&
|
||||||
|
read_u32le(0x24,sf_h) != 0 &&
|
||||||
|
read_u32le(0x24,sf_h) == read_u32le(0x90,sf_h) && /* sample rate repeat */
|
||||||
|
read_u32le(0xa0,sf_h) == header_size /* ~0xC0 */
|
||||||
|
) {
|
||||||
|
/* 0x08: null */
|
||||||
|
/* 0x0c: hashname */
|
||||||
|
strwav->num_samples = read_s32le(0x20,sf_h);
|
||||||
|
strwav->sample_rate = read_s32le(0x24,sf_h);
|
||||||
|
/* 0x28: 16 bps */
|
||||||
|
strwav->flags = read_u32le(0x2c,sf_h);
|
||||||
|
strwav->loop_start = read_s32le(0x38,sf_h);
|
||||||
|
strwav->tracks = read_s32le(0x50,sf_h);
|
||||||
|
/* 0x58: number of chunks? */
|
||||||
|
/* 0x90: sample rate 2 */
|
||||||
|
/* 0xb8: total frames? */
|
||||||
|
|
||||||
|
strwav->loop_end = strwav->num_samples;
|
||||||
|
|
||||||
|
strwav->codec = XBOX;
|
||||||
|
strwav->interleave = strwav->tracks > 1 ? 0xD800/2 : 0xD800;
|
||||||
|
;VGM_LOG("STR+WAV: header ZPb (Xbox)\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zapper: One Wicked Cricket! (Xbox)[2002] */
|
||||||
|
if ( read_u32be(0x04,sf_h) == 0x00000900 &&
|
||||||
|
read_u32le(0x0c,sf_h) != header_size &&
|
||||||
|
read_u32le(0x24,sf_h) != 0 &&
|
||||||
|
read_u32le(0x24,sf_h) == read_u32le(0xb0,sf_h) && /* sample rate repeat */
|
||||||
|
read_u32le(0xc0,sf_h) == header_size
|
||||||
|
) {
|
||||||
|
/* 0x08: null */
|
||||||
|
/* 0x0c: hashname */
|
||||||
|
strwav->num_samples = read_s32le(0x20,sf_h);
|
||||||
|
strwav->sample_rate = read_s32le(0x24,sf_h);
|
||||||
|
/* 0x28: 16 bps */
|
||||||
|
strwav->flags = read_u32le(0x2c,sf_h);
|
||||||
|
strwav->loop_start = read_s32le(0x38,sf_h);
|
||||||
|
strwav->tracks = read_s32le(0x70,sf_h);
|
||||||
|
/* 0x78: number of chunks? */
|
||||||
|
/* 0xb0: sample rate 2 */
|
||||||
|
/* 0xc0: header size*/
|
||||||
|
/* 0xd8: total frames? */
|
||||||
|
|
||||||
|
strwav->loop_end = strwav->num_samples;
|
||||||
|
|
||||||
|
strwav->codec = XBOX;
|
||||||
|
strwav->interleave = strwav->tracks > 1 ? 0xD800/2 : 0xD800;
|
||||||
|
;VGM_LOG("STR+WAV: header ZP (Xbox)\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zapper: One Wicked Cricket! (PC)[2002] */
|
||||||
if ( read_u32be(0x04,sf_h) == 0x00000900 &&
|
if ( read_u32be(0x04,sf_h) == 0x00000900 &&
|
||||||
read_u32le(0x24,sf_h) == read_u32le(0x114,sf_h) && /* sample rate repeat */
|
read_u32le(0x24,sf_h) == read_u32le(0x114,sf_h) && /* sample rate repeat */
|
||||||
read_u32le(0x12c,sf_h) == header_size /* ~0x130 */
|
read_u32le(0x12c,sf_h) == header_size /* ~0x130 */
|
||||||
|
@ -514,32 +592,6 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Zapper: One Wicked Cricket! Beta (PS2)[2005] */
|
|
||||||
if ( read_u32be(0x04,sf_h) == 0x00000900 &&
|
|
||||||
read_u32le(0x2c,sf_h) == 44100 && /* sample rate */
|
|
||||||
read_u32le(0x70,sf_h) == 0 && /* sample rate repeat? */
|
|
||||||
header_size == 0x78
|
|
||||||
) {
|
|
||||||
/* 0x08: null */
|
|
||||||
/* 0x0c: hashname */
|
|
||||||
/* 0x28: loop start? */
|
|
||||||
strwav->sample_rate = read_s32le(0x2c,sf_h);
|
|
||||||
/* 0x30: number of 0x800 sectors */
|
|
||||||
strwav->flags = read_u32le(0x34,sf_h);
|
|
||||||
strwav->num_samples = read_s32le(0x5c,sf_h);
|
|
||||||
strwav->tracks = read_s32le(0x60,sf_h);
|
|
||||||
|
|
||||||
strwav->loop_start = 0;
|
|
||||||
strwav->loop_end = 0;
|
|
||||||
|
|
||||||
strwav->codec = PSX;
|
|
||||||
strwav->interleave = strwav->tracks > 1 ? 0x8000 : 0x8000;
|
|
||||||
//todo: tracks are stereo blocks of size 0x20000*tracks, containing 4 interleaves of 0x8000:
|
|
||||||
// | 1 2 1 2 | 3 4 3 4 | 5 6 5 6 | 1 2 1 2 | 3 4 3 4 | 5 6 5 6 | ...
|
|
||||||
;VGM_LOG("STR+WAV: header ZPb (PS2)\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Pac-Man World 3 (GC)[2005] */
|
/* Pac-Man World 3 (GC)[2005] */
|
||||||
/* SpongeBob SquarePants: Creature from the Krusty Krab (GC)[2006] */
|
/* SpongeBob SquarePants: Creature from the Krusty Krab (GC)[2006] */
|
||||||
/* SpongeBob SquarePants: Creature from the Krusty Krab (Wii)[2006] */
|
/* SpongeBob SquarePants: Creature from the Krusty Krab (Wii)[2006] */
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../layout/layout.h"
|
#include "../layout/layout.h"
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
|
#include "../util/endianness.h"
|
||||||
|
|
||||||
|
|
||||||
typedef enum { PCM, UBI, PSX, DSP, XIMA, ATRAC3, XMA2, MP3 } ubi_hx_codec;
|
typedef enum { PCM, UBI, PSX, DSP, XIMA, ATRAC3, XMA2, MP3 } ubi_hx_codec;
|
||||||
|
@ -12,14 +13,14 @@ typedef struct {
|
||||||
int codec_id;
|
int codec_id;
|
||||||
ubi_hx_codec codec; /* unified codec */
|
ubi_hx_codec codec; /* unified codec */
|
||||||
int header_index; /* entry number within section2 */
|
int header_index; /* entry number within section2 */
|
||||||
off_t header_offset; /* entry offset within internal .HXx */
|
uint32_t header_offset; /* entry offset within internal .HXx */
|
||||||
size_t header_size; /* entry offset within internal .HXx */
|
uint32_t header_size; /* entry offset within internal .HXx */
|
||||||
char class_name[255];
|
char class_name[255];
|
||||||
size_t class_size;
|
size_t class_size;
|
||||||
size_t stream_mode;
|
size_t stream_mode;
|
||||||
|
|
||||||
off_t stream_offset; /* data offset within external stream */
|
uint32_t stream_offset; /* data offset within external stream */
|
||||||
size_t stream_size; /* data size within external stream */
|
uint32_t stream_size; /* data size within external stream */
|
||||||
uint32_t cuuid1; /* usually "Res" id1: class (1=Event, 3=Wave), id2: group id+sound id, */
|
uint32_t cuuid1; /* usually "Res" id1: class (1=Event, 3=Wave), id2: group id+sound id, */
|
||||||
uint32_t cuuid2; /* others have some complex id (not hash), id1: parent id?, id2: file id? */
|
uint32_t cuuid2; /* others have some complex id (not hash), id1: parent id?, id2: file id? */
|
||||||
|
|
||||||
|
@ -47,6 +48,12 @@ VGMSTREAM* init_vgmstream_ubi_hx(STREAMFILE* sf) {
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
|
{
|
||||||
|
uint32_t name_size = read_u32be(0x04, sf); /* BE/LE, should always be < 0xFF */
|
||||||
|
if (name_size == 0 || (name_size & 0x00FFFF00) != 0)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
/* .hxd: Rayman M/Arena (all), PK: Out of Shadows (all)
|
/* .hxd: Rayman M/Arena (all), PK: Out of Shadows (all)
|
||||||
* .hxc: Rayman 3 (PC), XIII (PC)
|
* .hxc: Rayman 3 (PC), XIII (PC)
|
||||||
* .hx2: Rayman 3 (PS2), XIII (PS2)
|
* .hx2: Rayman 3 (PS2), XIII (PS2)
|
||||||
|
@ -60,10 +67,8 @@ VGMSTREAM* init_vgmstream_ubi_hx(STREAMFILE* sf) {
|
||||||
* then an index to those types. Some games leave a companion .bnh with text info, probably leftover from their tools.
|
* then an index to those types. Some games leave a companion .bnh with text info, probably leftover from their tools.
|
||||||
* Game seems to play files by calling linked ids: EventResData (play/stop/etc) > Random/Program/Wav ResData (1..N refs) > FileIdObj */
|
* Game seems to play files by calling linked ids: EventResData (play/stop/etc) > Random/Program/Wav ResData (1..N refs) > FileIdObj */
|
||||||
|
|
||||||
/* HX CONFIG */
|
|
||||||
hx.big_endian = guess_endianness32bit(0x00, sf);
|
|
||||||
|
|
||||||
/* HX HEADER */
|
/* HX HEADER */
|
||||||
|
hx.big_endian = guess_endianness32bit(0x00, sf);
|
||||||
if (!parse_hx(&hx, sf, target_subsong))
|
if (!parse_hx(&hx, sf, target_subsong))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
@ -133,8 +138,8 @@ fail:
|
||||||
|
|
||||||
/* get referenced name from WavRes, using the index again (abridged) */
|
/* get referenced name from WavRes, using the index again (abridged) */
|
||||||
static int parse_name(ubi_hx_header* hx, STREAMFILE* sf) {
|
static int parse_name(ubi_hx_header* hx, STREAMFILE* sf) {
|
||||||
uint32_t (*read_u32)(off_t,STREAMFILE*) = hx->big_endian ? read_u32be : read_u32le;
|
read_u32_t read_u32 = hx->big_endian ? read_u32be : read_u32le;
|
||||||
int32_t (*read_s32)(off_t,STREAMFILE*) = hx->big_endian ? read_s32be : read_s32le;
|
read_s32_t read_s32 = hx->big_endian ? read_s32be : read_s32le;
|
||||||
off_t index_offset, offset;
|
off_t index_offset, offset;
|
||||||
int i, index_entries;
|
int i, index_entries;
|
||||||
char class_name[255];
|
char class_name[255];
|
||||||
|
@ -228,17 +233,17 @@ fail:
|
||||||
|
|
||||||
|
|
||||||
/* parse a single known header resource at offset */
|
/* parse a single known header resource at offset */
|
||||||
static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, off_t offset, size_t size, int index) {
|
static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, uint32_t offset, uint32_t size, int index) {
|
||||||
uint32_t (*read_u32)(off_t,STREAMFILE*) = hx->big_endian ? read_u32be : read_u32le;
|
read_u32_t read_u32 = hx->big_endian ? read_u32be : read_u32le;
|
||||||
int32_t (*read_s32)(off_t,STREAMFILE*) = hx->big_endian ? read_s32be : read_s32le;
|
read_s32_t read_s32 = hx->big_endian ? read_s32be : read_s32le;
|
||||||
uint16_t (*read_u16)(off_t,STREAMFILE*) = hx->big_endian ? read_u16be : read_u16le;
|
read_u16_t read_u16 = hx->big_endian ? read_u16be : read_u16le;
|
||||||
off_t riff_offset, riff_size, chunk_offset, stream_adjust = 0, resource_size;
|
off_t riff_offset, riff_size, chunk_offset, stream_adjust = 0, resource_size;
|
||||||
size_t chunk_size;
|
size_t chunk_size;
|
||||||
int cue_flag = 0;
|
int cue_flag = 0;
|
||||||
|
|
||||||
//todo cleanup/unify common readings
|
//todo cleanup/unify common readings
|
||||||
|
|
||||||
//;VGM_LOG("UBI HX: header o=%lx, s=%x\n\n", offset, size);
|
//;VGM_LOG("ubi hx: header o=%x, s=%x\n\n", offset, size);
|
||||||
|
|
||||||
hx->header_index = index;
|
hx->header_index = index;
|
||||||
hx->header_offset = offset;
|
hx->header_offset = offset;
|
||||||
|
@ -284,7 +289,7 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, off_t offset, size_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
VGM_LOG("UBI HX: unknown flag-type\n");
|
VGM_LOG("ubi hx: unknown flag-type\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,7 +321,7 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, off_t offset, size_t
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
VGM_LOG("UBI HX: %x\n", hx->stream_mode);
|
VGM_LOG("ubi hx: %x\n", hx->stream_mode);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,7 +338,7 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, off_t offset, size_t
|
||||||
case 0x05: hx->codec = XIMA; break;
|
case 0x05: hx->codec = XIMA; break;
|
||||||
case 0x55: hx->codec = MP3; break; /* Largo Winch: Empire Under Threat (PC) */
|
case 0x55: hx->codec = MP3; break; /* Largo Winch: Empire Under Threat (PC) */
|
||||||
default:
|
default:
|
||||||
VGM_LOG("UBI HX: unknown codec %x\n", hx->codec_id);
|
VGM_LOG("ubi hx: unknown codec %x\n", hx->codec_id);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
hx->channels = read_u16(riff_offset + 0x16, sf);
|
hx->channels = read_u16(riff_offset + 0x16, sf);
|
||||||
|
@ -383,21 +388,22 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, off_t offset, size_t
|
||||||
/* 0x04: some kind of parent id shared by multiple Waves, or 0 */
|
/* 0x04: some kind of parent id shared by multiple Waves, or 0 */
|
||||||
offset += 0x08;
|
offset += 0x08;
|
||||||
|
|
||||||
hx->stream_mode = read_8bit(offset, sf);
|
hx->stream_mode = read_u8(offset, sf);
|
||||||
offset += 0x01;
|
offset += 0x01;
|
||||||
|
|
||||||
if ((strcmp(hx->class_name, "CXBoxStaticHWWaveFileIdObj") == 0 ||
|
if ((strcmp(hx->class_name, "CXBoxStaticHWWaveFileIdObj") == 0 ||
|
||||||
strcmp(hx->class_name, "CXBoxStreamHWWaveFileIdObj") == 0) && !hx->big_endian) {
|
strcmp(hx->class_name, "CXBoxStreamHWWaveFileIdObj") == 0) && !hx->big_endian) {
|
||||||
/* micro header: some mix of channels + block size + sample rate + flags, unsure of which bits */
|
/* micro header: some mix of channels + block size + sample rate + flags, unsure of which bits */
|
||||||
hx->codec = XIMA;
|
hx->codec = XIMA;
|
||||||
hx->channels = (uint8_t)read_8bit(offset + 0x01, sf);
|
/* 0x00: ? */
|
||||||
switch(hx->channels) { /* upper 2 bits? */
|
hx->channels = read_u8(offset + 0x01, sf); /* upper 2 bits? */
|
||||||
|
switch(hx->channels) {
|
||||||
case 0x48: hx->channels = 1; break;
|
case 0x48: hx->channels = 1; break;
|
||||||
case 0x90: hx->channels = 2; break;
|
case 0x90: hx->channels = 2; break;
|
||||||
default: goto fail;
|
default: goto fail;
|
||||||
}
|
}
|
||||||
hx->sample_rate = (read_u16(offset + 0x02, sf) & 0x7FFFu) << 1u; /* ??? */
|
hx->sample_rate = (read_u16(offset + 0x02, sf) & 0x7FFFu) << 1u; /* ??? */
|
||||||
cue_flag = read_u8(offset + 0x03, sf) & (1<<7);
|
cue_flag = read_u8(offset + 0x03, sf) & (1 << 7);
|
||||||
offset += 0x04;
|
offset += 0x04;
|
||||||
}
|
}
|
||||||
else if ((strcmp(hx->class_name, "CXBoxStaticHWWaveFileIdObj") == 0 ||
|
else if ((strcmp(hx->class_name, "CXBoxStaticHWWaveFileIdObj") == 0 ||
|
||||||
|
@ -435,6 +441,10 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, off_t offset, size_t
|
||||||
|
|
||||||
|
|
||||||
switch(hx->stream_mode) {
|
switch(hx->stream_mode) {
|
||||||
|
case 0x00: /* static (smaller internal file) [XIII (Xbox)] */
|
||||||
|
hx->stream_offset += offset;
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x01: /* static (smaller external file) */
|
case 0x01: /* static (smaller external file) */
|
||||||
case 0x03: /* stream (bigger external file) */
|
case 0x03: /* stream (bigger external file) */
|
||||||
case 0x07: /* stream? */
|
case 0x07: /* stream? */
|
||||||
|
@ -446,6 +456,7 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, off_t offset, size_t
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
VGM_LOG("ubi hx: unknown stream mode %x\n", hx->stream_mode);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -455,22 +466,22 @@ static int parse_header(ubi_hx_header* hx, STREAMFILE* sf, off_t offset, size_t
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
fail:
|
fail:
|
||||||
VGM_LOG("UBI HX: error parsing header at %lx\n", hx->header_offset);
|
vgm_logi("UBI HX: error parsing header at %x (report)\n", hx->header_offset);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* parse a bank index and its possible audio headers (some info from Droolie's .bms) */
|
/* parse a bank index and its possible audio headers (some info from Droolie's .bms) */
|
||||||
static int parse_hx(ubi_hx_header* hx, STREAMFILE* sf, int target_subsong) {
|
static int parse_hx(ubi_hx_header* hx, STREAMFILE* sf, int target_subsong) {
|
||||||
uint32_t (*read_u32)(off_t,STREAMFILE*) = hx->big_endian ? read_u32be : read_u32le;
|
read_u32_t read_u32 = hx->big_endian ? read_u32be : read_u32le;
|
||||||
int32_t (*read_s32)(off_t,STREAMFILE*) = hx->big_endian ? read_s32be : read_s32le;
|
read_s32_t read_s32 = hx->big_endian ? read_s32be : read_s32le;
|
||||||
off_t index_offset, offset;
|
uint32_t index_offset, offset;
|
||||||
int i, index_entries;
|
int i, index_entries;
|
||||||
char class_name[255];
|
char class_name[255];
|
||||||
|
|
||||||
|
|
||||||
index_offset = read_u32(0x00, sf);
|
index_offset = read_u32(0x00, sf);
|
||||||
if (read_u32(index_offset + 0x00, sf) != 0x58444E49) /* "XDNI" (INDX in given endianness) */
|
if (read_u32(index_offset + 0x00, sf) != get_id32be("XDNI")) /* (INDX in given endianness) */
|
||||||
goto fail;
|
goto fail;
|
||||||
if (read_u32(index_offset + 0x04, sf) != 0x02) /* type? */
|
if (read_u32(index_offset + 0x04, sf) != 0x02) /* type? */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -480,11 +491,10 @@ static int parse_hx(ubi_hx_header* hx, STREAMFILE* sf, int target_subsong) {
|
||||||
index_entries = read_s32(index_offset + 0x08, sf);
|
index_entries = read_s32(index_offset + 0x08, sf);
|
||||||
offset = index_offset + 0x0c;
|
offset = index_offset + 0x0c;
|
||||||
for (i = 0; i < index_entries; i++) {
|
for (i = 0; i < index_entries; i++) {
|
||||||
off_t header_offset;
|
uint32_t header_offset, class_size, header_size;
|
||||||
size_t class_size, header_size;
|
|
||||||
int j, unknown_count, link_count, language_count;
|
int j, unknown_count, link_count, language_count;
|
||||||
|
|
||||||
//;VGM_LOG("UBI HX: index %i at %lx\n", i, offset);
|
//;VGM_LOG("ubi hx: index %i at %x\n", i, offset);
|
||||||
|
|
||||||
/* parse index entries: offset to actual header plus some extra info also in the header */
|
/* parse index entries: offset to actual header plus some extra info also in the header */
|
||||||
|
|
||||||
|
@ -502,7 +512,7 @@ static int parse_hx(ubi_hx_header* hx, STREAMFILE* sf, int target_subsong) {
|
||||||
/* not seen */
|
/* not seen */
|
||||||
unknown_count = read_s32(offset + 0x00, sf);
|
unknown_count = read_s32(offset + 0x00, sf);
|
||||||
if (unknown_count != 0) {
|
if (unknown_count != 0) {
|
||||||
VGM_LOG("UBI HX: found unknown near %lx\n", offset);
|
VGM_LOG("ubi hx: found unknown near %x\n", offset);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
offset += 0x04;
|
offset += 0x04;
|
||||||
|
@ -520,7 +530,7 @@ static int parse_hx(ubi_hx_header* hx, STREAMFILE* sf, int target_subsong) {
|
||||||
/* 0x08: id1+2 */
|
/* 0x08: id1+2 */
|
||||||
|
|
||||||
if (read_u32(offset + 0x04, sf) != 1) {
|
if (read_u32(offset + 0x04, sf) != 1) {
|
||||||
VGM_LOG("UBI HX: wrong lang count near %lx\n", offset);
|
VGM_LOG("ubi hx: wrong lang count near %x\n", offset);
|
||||||
goto fail; /* WavRes doesn't have this field */
|
goto fail; /* WavRes doesn't have this field */
|
||||||
}
|
}
|
||||||
offset += 0x10;
|
offset += 0x10;
|
||||||
|
@ -557,12 +567,12 @@ static int parse_hx(ubi_hx_header* hx, STREAMFILE* sf, int target_subsong) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
VGM_LOG("UBI HX: unknown type: %s\n", class_name);
|
vgm_logi("UBI HX: unknown type: %s (report)\n", class_name);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link_count != 0) {
|
if (link_count != 0) {
|
||||||
VGM_LOG("UBI HX: found links in wav object\n");
|
vgm_logi("UBI HX: found links in wav object (report)\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -596,7 +606,7 @@ static STREAMFILE* open_hx_streamfile(ubi_hx_header* hx, STREAMFILE* sf) {
|
||||||
|
|
||||||
sb = open_streamfile_by_filename(sf, hx->resource_name);
|
sb = open_streamfile_by_filename(sf, hx->resource_name);
|
||||||
if (sb == NULL) {
|
if (sb == NULL) {
|
||||||
VGM_LOG("UBI HX: external stream '%s' not found\n", hx->resource_name);
|
vgm_logi("UBI HX: external file '%s' not found (put together)\n", hx->resource_name);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../util.h"
|
#include "../util.h"
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
|
#include "../util/chunks.h"
|
||||||
|
#include "../util/endianness.h"
|
||||||
|
|
||||||
|
|
||||||
/* Wwise uses a custom RIFF/RIFX header, non-standard enough that it's parsed it here.
|
/* Wwise uses a custom RIFF/RIFX header, non-standard enough that it's parsed it here.
|
||||||
|
@ -14,6 +16,7 @@ typedef struct {
|
||||||
int big_endian;
|
int big_endian;
|
||||||
size_t file_size;
|
size_t file_size;
|
||||||
int truncated;
|
int truncated;
|
||||||
|
int is_wem;
|
||||||
|
|
||||||
/* chunks references */
|
/* chunks references */
|
||||||
off_t fmt_offset;
|
off_t fmt_offset;
|
||||||
|
@ -55,22 +58,28 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww);
|
||||||
static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_offset);
|
static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_offset);
|
||||||
|
|
||||||
|
|
||||||
/* Wwise - Audiokinetic Wwise (Wave Works Interactive Sound Engine) middleware */
|
|
||||||
|
/* Wwise - Audiokinetic Wwise (WaveWorks Interactive Sound Engine) middleware */
|
||||||
VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
||||||
VGMSTREAM* vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
wwise_header ww = {0};
|
wwise_header ww = {0};
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL;
|
read_u32_t read_u32 = NULL;
|
||||||
int32_t (*read_s32)(off_t,STREAMFILE*) = NULL;
|
read_s32_t read_s32 = NULL;
|
||||||
uint16_t (*read_u16)(off_t,STREAMFILE*) = NULL;
|
read_u16_t read_u16 = NULL;
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
/* .wem: newer "Wwise Encoded Media" used after the 2011.2 SDK (~july 2011)
|
if (!is_id32be(0x00,sf, "RIFF") && /* LE */
|
||||||
|
!is_id32be(0x00,sf, "RIFX")) /* BE */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* note that Wwise allows those extensions only, so custom engine exts shouldn't be added
|
||||||
|
* .wem: newer "Wwise Encoded Media" used after the 2011.2 SDK (~july 2011)
|
||||||
* .wav: older PCM/ADPCM files [Spider-Man: Web of Shadows (PC), Punch Out!! (Wii)]
|
* .wav: older PCM/ADPCM files [Spider-Man: Web of Shadows (PC), Punch Out!! (Wii)]
|
||||||
* .xma: older XMA files [Too Human (X360), Tron Evolution (X360)]
|
* .xma: older XMA files [Too Human (X360), Tron Evolution (X360)]
|
||||||
* .ogg: older Vorbis files [The King of Fighters XII (X360)]
|
* .ogg: older Vorbis files [The King of Fighters XII (X360)]
|
||||||
* .bnk: Wwise banks for memory .wem detection */
|
* .bnk: Wwise banks for memory .wem detection (hack) */
|
||||||
if (!check_extensions(sf,"wem,wav,lwav,ogg,logg,xma,bnk"))
|
if (!check_extensions(sf,"wem,wav,lwav,ogg,logg,xma,bnk"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
@ -92,6 +101,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
||||||
vgmstream->loop_start_sample = ww.loop_start_sample;
|
vgmstream->loop_start_sample = ww.loop_start_sample;
|
||||||
vgmstream->loop_end_sample = ww.loop_end_sample;
|
vgmstream->loop_end_sample = ww.loop_end_sample;
|
||||||
vgmstream->channel_layout = ww.channel_layout;
|
vgmstream->channel_layout = ww.channel_layout;
|
||||||
|
vgmstream->stream_size = ww.data_size;
|
||||||
|
|
||||||
switch(ww.codec) {
|
switch(ww.codec) {
|
||||||
case PCM: /* common */
|
case PCM: /* common */
|
||||||
|
@ -234,7 +244,6 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
||||||
else {
|
else {
|
||||||
/* newer Wwise (>2012) */
|
/* newer Wwise (>2012) */
|
||||||
off_t extra_offset = ww.fmt_offset + 0x18; /* after flag + channels */
|
off_t extra_offset = ww.fmt_offset + 0x18; /* after flag + channels */
|
||||||
int is_wem = check_extensions(sf,"wem,bnk"); /* use extension as a guide for faster vorbis inits */
|
|
||||||
|
|
||||||
switch(ww.extra_size) {
|
switch(ww.extra_size) {
|
||||||
case 0x30:
|
case 0x30:
|
||||||
|
@ -246,7 +255,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
||||||
/* setup not detectable by header, so we'll try both; libvorbis should reject wrong codebooks
|
/* setup not detectable by header, so we'll try both; libvorbis should reject wrong codebooks
|
||||||
* - standard: early (<2012), ex. The King of Fighters XIII (X360)-2011/11, .ogg (cbs are from aoTuV, too)
|
* - standard: early (<2012), ex. The King of Fighters XIII (X360)-2011/11, .ogg (cbs are from aoTuV, too)
|
||||||
* - aoTuV603: later (>2012), ex. Sonic & All-Stars Racing Transformed (PC)-2012/11, .wem */
|
* - aoTuV603: later (>2012), ex. Sonic & All-Stars Racing Transformed (PC)-2012/11, .wem */
|
||||||
cfg.setup_type = is_wem ? WWV_AOTUV603_CODEBOOKS : WWV_EXTERNAL_CODEBOOKS; /* aoTuV came along .wem */
|
cfg.setup_type = ww.is_wem ? WWV_AOTUV603_CODEBOOKS : WWV_EXTERNAL_CODEBOOKS; /* aoTuV came along .wem */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -278,7 +287,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
|
||||||
vgmstream->codec_data = init_vorbis_custom(sf, start_offset + setup_offset, VORBIS_WWISE, &cfg);
|
vgmstream->codec_data = init_vorbis_custom(sf, start_offset + setup_offset, VORBIS_WWISE, &cfg);
|
||||||
if (!vgmstream->codec_data) {
|
if (!vgmstream->codec_data) {
|
||||||
/* codebooks failed: try again with the other type */
|
/* codebooks failed: try again with the other type */
|
||||||
cfg.setup_type = is_wem ? WWV_EXTERNAL_CODEBOOKS : WWV_AOTUV603_CODEBOOKS;
|
cfg.setup_type = ww.is_wem ? WWV_EXTERNAL_CODEBOOKS : WWV_AOTUV603_CODEBOOKS;
|
||||||
vgmstream->codec_data = init_vorbis_custom(sf, start_offset + setup_offset, VORBIS_WWISE, &cfg);
|
vgmstream->codec_data = init_vorbis_custom(sf, start_offset + setup_offset, VORBIS_WWISE, &cfg);
|
||||||
if (!vgmstream->codec_data) goto fail;
|
if (!vgmstream->codec_data) goto fail;
|
||||||
}
|
}
|
||||||
|
@ -690,18 +699,12 @@ static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_o
|
||||||
|
|
||||||
|
|
||||||
static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
|
static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
|
||||||
uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL;
|
read_u32_t read_u32;
|
||||||
uint16_t (*read_u16)(off_t,STREAMFILE*) = NULL;
|
read_u16_t read_u16;
|
||||||
|
|
||||||
if (read_u32be(0x00,sf) != 0x52494646 && /* "RIFF" (LE) */
|
/* Wwise honors machine's endianness (PC=RIFF, X360=RIFX --unlike XMA) */
|
||||||
read_u32be(0x00,sf) != 0x52494658) /* "RIFX" (BE) */
|
ww->big_endian = is_id32be(0x00,sf, "RIFX"); /* RIFF size not useful to detect, see below */
|
||||||
goto fail;
|
if (ww->big_endian) {
|
||||||
if (read_u32be(0x08,sf) != 0x57415645 && /* "WAVE" */
|
|
||||||
read_u32be(0x08,sf) != 0x58574D41) /* "XWMA" */
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
ww->big_endian = read_u32be(0x00,sf) == 0x52494658; /* RIFX */
|
|
||||||
if (ww->big_endian) { /* Wwise honors machine's endianness (PC=RIFF, X360=RIFX --unlike XMA) */
|
|
||||||
read_u32 = read_u32be;
|
read_u32 = read_u32be;
|
||||||
read_u16 = read_u16be;
|
read_u16 = read_u16be;
|
||||||
} else {
|
} else {
|
||||||
|
@ -727,50 +730,56 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (!is_id32be(0x08,sf, "WAVE") &&
|
||||||
|
!is_id32be(0x08,sf, "XWMA"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
|
||||||
/* parse chunks (reads once linearly) */
|
/* parse chunks (reads once linearly) */
|
||||||
{
|
{
|
||||||
off_t offset = 0x0c;
|
chunk_t rc = {0};
|
||||||
while (offset < ww->file_size) {
|
|
||||||
uint32_t type = read_u32be(offset + 0x00,sf);
|
|
||||||
uint32_t size = read_u32 (offset + 0x04,sf);
|
|
||||||
offset += 0x08;
|
|
||||||
|
|
||||||
switch(type) {
|
/* chunks are even-aligned and don't need to add padding byte, unlike real RIFFs */
|
||||||
|
rc.be_size = ww->big_endian;
|
||||||
|
rc.current = 0x0c;
|
||||||
|
while (next_chunk(&rc, sf)) {
|
||||||
|
|
||||||
|
switch(rc.type) {
|
||||||
case 0x666d7420: /* "fmt " */
|
case 0x666d7420: /* "fmt " */
|
||||||
ww->fmt_offset = offset;
|
ww->fmt_offset = rc.offset;
|
||||||
ww->fmt_size = size;
|
ww->fmt_size = rc.size;
|
||||||
break;
|
break;
|
||||||
case 0x584D4132: /* "XMA2" */
|
case 0x584D4132: /* "XMA2" */
|
||||||
ww->xma2_offset = offset;
|
ww->xma2_offset = rc.offset;
|
||||||
ww->xma2_size = size;
|
ww->xma2_size = rc.size;
|
||||||
break;
|
break;
|
||||||
case 0x64617461: /* "data" */
|
case 0x64617461: /* "data" */
|
||||||
ww->data_offset = offset;
|
ww->data_offset = rc.offset;
|
||||||
ww->data_size = size;
|
ww->data_size = rc.size;
|
||||||
break;
|
break;
|
||||||
case 0x766F7262: /* "vorb" */
|
case 0x766F7262: /* "vorb" */
|
||||||
ww->vorb_offset = offset;
|
ww->vorb_offset = rc.offset;
|
||||||
ww->vorb_size = size;
|
ww->vorb_size = rc.size;
|
||||||
break;
|
break;
|
||||||
case 0x57696948: /* "WiiH" */
|
case 0x57696948: /* "WiiH" */
|
||||||
ww->wiih_offset = offset;
|
ww->wiih_offset = rc.offset;
|
||||||
ww->wiih_size = size;
|
ww->wiih_size = rc.size;
|
||||||
break;
|
break;
|
||||||
case 0x7365656B: /* "seek" */
|
case 0x7365656B: /* "seek" */
|
||||||
ww->seek_offset = offset;
|
ww->seek_offset = rc.offset;
|
||||||
ww->seek_size = size;
|
ww->seek_size = rc.size;
|
||||||
break;
|
break;
|
||||||
case 0x736D706C: /* "smpl" */
|
case 0x736D706C: /* "smpl" */
|
||||||
ww->smpl_offset = offset;
|
ww->smpl_offset = rc.offset;
|
||||||
ww->smpl_size = size;
|
ww->smpl_size = rc.size;
|
||||||
break;
|
break;
|
||||||
case 0x6D657461: /* "meta" */
|
case 0x6D657461: /* "meta" */
|
||||||
ww->meta_offset = offset;
|
ww->meta_offset = rc.offset;
|
||||||
ww->meta_size = size;
|
ww->meta_size = rc.size;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x66616374: /* "fact" */
|
case 0x66616374: /* "fact" */
|
||||||
/* Wwise shouldn't use fact, but if somehow some file does uncomment the following: */
|
/* Wwise never uses fact, but if somehow some file does uncomment the following: */
|
||||||
//if (size == 0x10 && read_u32be(offset + 0x04, sf) == 0x4C794E20) /* "LyN " */
|
//if (size == 0x10 && read_u32be(offset + 0x04, sf) == 0x4C794E20) /* "LyN " */
|
||||||
// goto fail; /* ignore LyN RIFF */
|
// goto fail; /* ignore LyN RIFF */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -783,12 +792,11 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* chunks are even-aligned and don't need to add padding byte, unlike real RIFFs */
|
|
||||||
offset += size;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* use extension as a guide for certain cases */
|
||||||
|
ww->is_wem = check_extensions(sf,"wem,bnk");
|
||||||
|
|
||||||
/* parse format (roughly spec-compliant but some massaging is needed) */
|
/* parse format (roughly spec-compliant but some massaging is needed) */
|
||||||
if (ww->xma2_offset) {
|
if (ww->xma2_offset) {
|
||||||
|
@ -806,7 +814,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
|
||||||
ww->channels = read_u16(ww->fmt_offset + 0x02,sf);
|
ww->channels = read_u16(ww->fmt_offset + 0x02,sf);
|
||||||
ww->sample_rate = read_u32(ww->fmt_offset + 0x04,sf);
|
ww->sample_rate = read_u32(ww->fmt_offset + 0x04,sf);
|
||||||
ww->avg_bitrate = read_u32(ww->fmt_offset + 0x08,sf);
|
ww->avg_bitrate = read_u32(ww->fmt_offset + 0x08,sf);
|
||||||
ww->block_size = read_u16(ww->fmt_offset + 0x0c,sf);
|
ww->block_size = read_u16(ww->fmt_offset + 0x0c,sf);
|
||||||
ww->bits_per_sample = read_u16(ww->fmt_offset + 0x0e,sf);
|
ww->bits_per_sample = read_u16(ww->fmt_offset + 0x0e,sf);
|
||||||
if (ww->fmt_size > 0x10 && ww->format != 0x0165 && ww->format != 0x0166) /* ignore XMAWAVEFORMAT */
|
if (ww->fmt_size > 0x10 && ww->format != 0x0165 && ww->format != 0x0166) /* ignore XMAWAVEFORMAT */
|
||||||
ww->extra_size = read_u16(ww->fmt_offset + 0x10,sf);
|
ww->extra_size = read_u16(ww->fmt_offset + 0x10,sf);
|
||||||
|
@ -864,7 +872,9 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
|
||||||
case 0x3041: ww->codec = OPUSWW; break; /* "OPUS_WEM", added on Wwise 2019.2.3, replaces OPUS */
|
case 0x3041: ww->codec = OPUSWW; break; /* "OPUS_WEM", added on Wwise 2019.2.3, replaces OPUS */
|
||||||
case 0x8311: ww->codec = PTADPCM; break; /* added on Wwise 2019.1, replaces IMA */
|
case 0x8311: ww->codec = PTADPCM; break; /* added on Wwise 2019.1, replaces IMA */
|
||||||
default:
|
default:
|
||||||
vgm_logi("WWISE: unknown codec 0x%04x (report)\n", ww->format);
|
/* some .wav may end up here, only report in .wem cases (newer codecs) */
|
||||||
|
if (ww->is_wem)
|
||||||
|
vgm_logi("WWISE: unknown codec 0x%04x (report)\n", ww->format);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,10 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) {
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
if (!check_extensions(sf,"xnb"))
|
|
||||||
goto fail;
|
|
||||||
if ((read_u32be(0x00, sf) & 0xFFFFFF00) != get_id32be("XNB\0"))
|
if ((read_u32be(0x00, sf) & 0xFFFFFF00) != get_id32be("XNB\0"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
if (!check_extensions(sf,"xnb"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* XNA Studio platforms: 'w' = Windows, 'm' = Windows Phone 7, 'x' = X360
|
/* XNA Studio platforms: 'w' = Windows, 'm' = Windows Phone 7, 'x' = X360
|
||||||
* MonoGame extensions: 'i' = iOS, 'a' = Android, 'X' = MacOSX, 'P' = PS4, 'S' = Switch, etc */
|
* MonoGame extensions: 'i' = iOS, 'a' = Android, 'X' = MacOSX, 'P' = PS4, 'S' = Switch, etc */
|
||||||
|
@ -184,10 +184,9 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) {
|
||||||
if (!temp_sf) goto fail;
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
if (is_ogg) {
|
if (is_ogg) {
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
vgmstream = init_vgmstream_ogg_vorbis(temp_sf);
|
vgmstream = init_vgmstream_ogg_vorbis(temp_sf);
|
||||||
#endif
|
}
|
||||||
} else {
|
else {
|
||||||
vgmstream = init_vgmstream_riff(temp_sf);
|
vgmstream = init_vgmstream_riff(temp_sf);
|
||||||
}
|
}
|
||||||
close_streamfile(temp_sf);
|
close_streamfile(temp_sf);
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
* - Clang: seems only defined on Linux/GNU environments, somehow emscripten is out
|
* - Clang: seems only defined on Linux/GNU environments, somehow emscripten is out
|
||||||
* (unsure about Clang Win since apparently they define _MSC_VER)
|
* (unsure about Clang Win since apparently they define _MSC_VER)
|
||||||
* - Android: API +24 if not using __USE_FILE_OFFSET64
|
* - Android: API +24 if not using __USE_FILE_OFFSET64
|
||||||
* Not sure if fopen64 is needed in some cases. May be worth adding some compiler flag to enable 64 versions manually.
|
* Not sure if fopen64 is needed in some cases.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* MSVC fixes (though mingw uses MSVCRT but not MSC_VER, maybe use AND?) */
|
#if defined(_MSC_VER) //&& defined(__MSVCRT__)
|
||||||
#if defined(__MSVCRT__) || defined(_MSC_VER)
|
/* MSVC fixes (MinG64 seems to set MSVCRT too, but we want it below) */
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
|
|
||||||
#define fopen_v fopen
|
#define fopen_v fopen
|
||||||
|
@ -43,14 +43,22 @@
|
||||||
// #define off_t/off64_t __int64
|
// #define off_t/off64_t __int64
|
||||||
//#endif
|
//#endif
|
||||||
|
|
||||||
|
#elif defined(VGMSTREAM_USE_IO64) || defined(__MINGW32__) || defined(__MINGW64__)
|
||||||
|
/* force, or known to work */
|
||||||
|
#define fopen_v fopen
|
||||||
|
#define fseek_v fseeko64 //fseeko
|
||||||
|
#define ftell_v ftello64 //ftello
|
||||||
|
|
||||||
#elif defined(XBMC) || defined(__EMSCRIPTEN__) || defined (__ANDROID__) || defined(__APPLE__)
|
#elif defined(XBMC) || defined(__EMSCRIPTEN__) || defined (__ANDROID__) || defined(__APPLE__)
|
||||||
|
/* may depend on version */
|
||||||
#define fopen_v fopen
|
#define fopen_v fopen
|
||||||
#define fseek_v fseek
|
#define fseek_v fseek
|
||||||
#define ftell_v ftell
|
#define ftell_v ftell
|
||||||
#else
|
#else
|
||||||
|
/* other Linux systems may already use off64_t in fseeko/ftello? */
|
||||||
#define fopen_v fopen
|
#define fopen_v fopen
|
||||||
#define fseek_v fseeko64 //fseeko
|
#define fseek_v fseeko
|
||||||
#define ftell_v ftello64 //ftello
|
#define ftell_v ftello
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -952,22 +960,12 @@ STREAMFILE* open_streamfile(STREAMFILE* sf, const char* pathname) {
|
||||||
|
|
||||||
STREAMFILE* open_streamfile_by_ext(STREAMFILE* sf, const char* ext) {
|
STREAMFILE* open_streamfile_by_ext(STREAMFILE* sf, const char* ext) {
|
||||||
char filename[PATH_LIMIT];
|
char filename[PATH_LIMIT];
|
||||||
int filename_len, fileext_len;
|
|
||||||
|
|
||||||
sf->get_name(sf, filename, sizeof(filename));
|
get_streamfile_name(sf, filename, sizeof(filename));
|
||||||
|
|
||||||
filename_len = strlen(filename);
|
swap_extension(filename, sizeof(filename), ext);
|
||||||
fileext_len = strlen(filename_extension(filename));
|
|
||||||
|
|
||||||
if (fileext_len == 0) {/* extensionless */
|
return open_streamfile(sf, filename);
|
||||||
strcat(filename,".");
|
|
||||||
strcat(filename,ext);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
strcpy(filename + filename_len - fileext_len, ext);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sf->open(sf, filename, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
STREAMFILE* open_streamfile_by_filename(STREAMFILE* sf, const char* filename) {
|
STREAMFILE* open_streamfile_by_filename(STREAMFILE* sf, const char* filename) {
|
||||||
|
@ -977,7 +975,7 @@ STREAMFILE* open_streamfile_by_filename(STREAMFILE* sf, const char* filename) {
|
||||||
|
|
||||||
if (!sf || !filename || !filename[0]) return NULL;
|
if (!sf || !filename || !filename[0]) return NULL;
|
||||||
|
|
||||||
sf->get_name(sf, fullname, sizeof(fullname));
|
get_streamfile_name(sf, fullname, sizeof(fullname));
|
||||||
|
|
||||||
//todo normalize separators in a better way, safeops, improve copying
|
//todo normalize separators in a better way, safeops, improve copying
|
||||||
|
|
||||||
|
@ -1026,7 +1024,7 @@ STREAMFILE* open_streamfile_by_filename(STREAMFILE* sf, const char* filename) {
|
||||||
strcpy(fullname, filename);
|
strcpy(fullname, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
return sf->open(sf, fullname, STREAMFILE_DEFAULT_BUFFER_SIZE);
|
return open_streamfile(sf, fullname);
|
||||||
}
|
}
|
||||||
|
|
||||||
STREAMFILE* reopen_streamfile(STREAMFILE* sf, size_t buffer_size) {
|
STREAMFILE* reopen_streamfile(STREAMFILE* sf, size_t buffer_size) {
|
||||||
|
@ -1036,7 +1034,7 @@ STREAMFILE* reopen_streamfile(STREAMFILE* sf, size_t buffer_size) {
|
||||||
|
|
||||||
if (buffer_size == 0)
|
if (buffer_size == 0)
|
||||||
buffer_size = STREAMFILE_DEFAULT_BUFFER_SIZE;
|
buffer_size = STREAMFILE_DEFAULT_BUFFER_SIZE;
|
||||||
sf->get_name(sf, pathname,sizeof(pathname));
|
get_streamfile_name(sf, pathname, sizeof(pathname));
|
||||||
return sf->open(sf, pathname, buffer_size);
|
return sf->open(sf, pathname, buffer_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1262,6 +1260,11 @@ STREAMFILE* read_filemap_file_pos(STREAMFILE* sf, int file_num, int* p_pos) {
|
||||||
/* get key/val (ignores lead/trailing spaces, stops at comment/separator) */
|
/* get key/val (ignores lead/trailing spaces, stops at comment/separator) */
|
||||||
ok = sscanf(line, " %[^\t#:] : %[^\t#\r\n] ", key, val);
|
ok = sscanf(line, " %[^\t#:] : %[^\t#\r\n] ", key, val);
|
||||||
if (ok != 2) { /* ignore line if no key=val (comment or garbage) */
|
if (ok != 2) { /* ignore line if no key=val (comment or garbage) */
|
||||||
|
/* better way? */
|
||||||
|
if (strcmp(line, "#@reset-pos") == 0) {
|
||||||
|
file_pos = 0;
|
||||||
|
VGM_LOG("pos =%i\n", file_pos);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,34 +2,40 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "streamtypes.h"
|
#include "streamtypes.h"
|
||||||
|
|
||||||
const char * filename_extension(const char * pathname) {
|
const char* filename_extension(const char* pathname) {
|
||||||
const char * filename;
|
const char* extension;
|
||||||
const char * extension;
|
|
||||||
|
|
||||||
/* favor strrchr (optimized/aligned) rather than homemade loops */
|
/* favor strrchr (optimized/aligned) rather than homemade loops */
|
||||||
|
extension = strrchr(pathname,'.');
|
||||||
|
|
||||||
/* find possible separator first to avoid misdetecting folders with dots + extensionless files
|
if (extension != NULL) {
|
||||||
* (allow both slashes as plugin could pass normalized '/') */
|
/* probably has extension */
|
||||||
filename = strrchr(pathname, '/');
|
extension++; /* skip dot */
|
||||||
if (filename != NULL)
|
|
||||||
filename++; /* skip separator */
|
/* find possible separators to avoid misdetecting folders with dots + extensionless files
|
||||||
else {
|
* (after the above to reduce search space, allows both slashes in case of non-normalized names) */
|
||||||
filename = strrchr(pathname, '\\');
|
if (strchr(extension, '/') == NULL && strchr(extension, '\\') == NULL)
|
||||||
if (filename != NULL)
|
return extension; /* no slashes = really has extension */
|
||||||
filename++; /* skip separator */
|
|
||||||
else
|
|
||||||
filename = pathname; /* pathname has no separators (single filename) */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension = strrchr(filename,'.');
|
/* extensionless: point to null after current name
|
||||||
if (extension != NULL)
|
* (could return NULL but prev code expects with to return an actual c-string) */
|
||||||
extension++; /* skip dot */
|
return pathname + strlen(pathname);
|
||||||
else
|
|
||||||
extension = filename + strlen(filename); /* point to null (empty "" string for extensionless files) */
|
|
||||||
|
|
||||||
return extension;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void swap_extension(char* pathname, int pathname_len, const char* swap) {
|
||||||
|
char* extension = (char*)filename_extension(pathname);
|
||||||
|
//todo safeops
|
||||||
|
if (extension[0] == '\0') {
|
||||||
|
strcat(pathname, ".");
|
||||||
|
strcat(pathname, swap);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strcpy(extension, swap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* unused */
|
/* unused */
|
||||||
/*
|
/*
|
||||||
void interleave_channel(sample_t * outbuffer, sample_t * inbuffer, int32_t sample_count, int channel_count, int channel_number) {
|
void interleave_channel(sample_t * outbuffer, sample_t * inbuffer, int32_t sample_count, int channel_count, int channel_number) {
|
||||||
|
|
|
@ -175,7 +175,10 @@ int round10(int val);
|
||||||
|
|
||||||
/* return a file's extension (a pointer to the first character of the
|
/* return a file's extension (a pointer to the first character of the
|
||||||
* extension in the original filename or the ending null byte if no extension */
|
* extension in the original filename or the ending null byte if no extension */
|
||||||
const char * filename_extension(const char * filename);
|
const char* filename_extension(const char* pathname);
|
||||||
|
|
||||||
|
/* change pathname's extension to another (or add it if extensionless) */
|
||||||
|
void swap_extension(char* pathname, /*size_t*/ int pathname_len, const char* swap);
|
||||||
|
|
||||||
/* swap samples in machine endianness to little endian (useful to write .wav) */
|
/* swap samples in machine endianness to little endian (useful to write .wav) */
|
||||||
void swap_samples_le(sample_t *buf, int count);
|
void swap_samples_le(sample_t *buf, int count);
|
||||||
|
|
|
@ -26,8 +26,8 @@ int next_chunk(chunk_t* chunk, STREAMFILE* sf) {
|
||||||
if (chunk->type == 0xFFFFFFFF || chunk->size == 0xFFFFFFFF)
|
if (chunk->type == 0xFFFFFFFF || chunk->size == 0xFFFFFFFF)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* empty chunk with 0 size, seen in some formats (XVAG uses it as end marker, Wwise doesn't) */
|
/* empty chunk with 0 size is ok, seen in some formats (XVAG uses it as end marker, Wwise in JUNK) */
|
||||||
if (chunk->type == 0 || chunk->size == 0)
|
if (chunk->type == 0 /*|| chunk->size == 0*/)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* more chunks remain */
|
/* more chunks remain */
|
||||||
|
|
|
@ -13,6 +13,7 @@ typedef struct {
|
||||||
int le_type; /* read type as LE instead of more common BE */
|
int le_type; /* read type as LE instead of more common BE */
|
||||||
int be_size; /* read type as BE instead of more common LE */
|
int be_size; /* read type as BE instead of more common LE */
|
||||||
int full_size; /* chunk size includes type+size */
|
int full_size; /* chunk size includes type+size */
|
||||||
|
int alignment; /* chunks with odd size need to be aligned to even, per RIFF spec */
|
||||||
} chunk_t;
|
} chunk_t;
|
||||||
|
|
||||||
int next_chunk(chunk_t* chunk, STREAMFILE* sf);
|
int next_chunk(chunk_t* chunk, STREAMFILE* sf);
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef _UTIL_ENDIAN_H
|
||||||
|
#define _UTIL_ENDIAN_H
|
||||||
|
|
||||||
|
#include "../streamfile.h"
|
||||||
|
|
||||||
|
typedef uint32_t (*read_u32_t)(off_t, STREAMFILE*);
|
||||||
|
typedef int32_t (*read_s32_t)(off_t, STREAMFILE*);
|
||||||
|
typedef uint16_t (*read_u16_t)(off_t, STREAMFILE*);
|
||||||
|
|
||||||
|
#endif
|
|
@ -22,8 +22,6 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
||||||
init_vgmstream_adx,
|
init_vgmstream_adx,
|
||||||
init_vgmstream_brstm,
|
init_vgmstream_brstm,
|
||||||
init_vgmstream_bfwav,
|
init_vgmstream_bfwav,
|
||||||
init_vgmstream_bfstm,
|
|
||||||
init_vgmstream_mca,
|
|
||||||
init_vgmstream_nds_strm,
|
init_vgmstream_nds_strm,
|
||||||
init_vgmstream_agsc,
|
init_vgmstream_agsc,
|
||||||
init_vgmstream_ngc_adpdtk,
|
init_vgmstream_ngc_adpdtk,
|
||||||
|
@ -61,17 +59,9 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
||||||
init_vgmstream_caf,
|
init_vgmstream_caf,
|
||||||
init_vgmstream_vpk,
|
init_vgmstream_vpk,
|
||||||
init_vgmstream_genh,
|
init_vgmstream_genh,
|
||||||
#ifdef VGM_USE_VORBIS
|
|
||||||
init_vgmstream_ogg_vorbis,
|
init_vgmstream_ogg_vorbis,
|
||||||
#endif
|
|
||||||
init_vgmstream_sli_ogg,
|
init_vgmstream_sli_ogg,
|
||||||
init_vgmstream_sfl_ogg,
|
init_vgmstream_sfl_ogg,
|
||||||
#if 0
|
|
||||||
init_vgmstream_mp4_aac,
|
|
||||||
#endif
|
|
||||||
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
|
|
||||||
init_vgmstream_akb_mp4,
|
|
||||||
#endif
|
|
||||||
init_vgmstream_sadb,
|
init_vgmstream_sadb,
|
||||||
init_vgmstream_ps2_bmdx,
|
init_vgmstream_ps2_bmdx,
|
||||||
init_vgmstream_wsi,
|
init_vgmstream_wsi,
|
||||||
|
@ -294,6 +284,14 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
||||||
init_vgmstream_idsp_namco,
|
init_vgmstream_idsp_namco,
|
||||||
init_vgmstream_kt_g1l,
|
init_vgmstream_kt_g1l,
|
||||||
init_vgmstream_kt_wiibgm,
|
init_vgmstream_kt_wiibgm,
|
||||||
|
init_vgmstream_bfstm,
|
||||||
|
init_vgmstream_mca,
|
||||||
|
#if 0
|
||||||
|
init_vgmstream_mp4_aac,
|
||||||
|
#endif
|
||||||
|
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
|
||||||
|
init_vgmstream_akb_mp4,
|
||||||
|
#endif
|
||||||
init_vgmstream_ktss,
|
init_vgmstream_ktss,
|
||||||
init_vgmstream_hca,
|
init_vgmstream_hca,
|
||||||
init_vgmstream_svag_snk,
|
init_vgmstream_svag_snk,
|
||||||
|
|
|
@ -11,17 +11,21 @@
|
||||||
|
|
||||||
#import "PlaylistController.h"
|
#import "PlaylistController.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
static NSString* get_description_tag(const char* description, const char *tag, char delimiter) {
|
static NSString* get_description_tag(const char* description, const char *tag, char delimiter) {
|
||||||
// extract a "tag" from the description string
|
// extract a "tag" from the description string
|
||||||
|
if (!delimiter) delimiter = '\n';
|
||||||
const char* pos = strstr(description, tag);
|
const char* pos = strstr(description, tag);
|
||||||
const char* eos = NULL;
|
const char* eos = NULL;
|
||||||
if (pos != NULL) {
|
if (pos != NULL) {
|
||||||
pos += strlen(tag);
|
pos += strlen(tag);
|
||||||
eos = strchr(pos, delimiter);
|
eos = strchr(pos, delimiter);
|
||||||
if (eos == NULL) eos = pos + strlen(pos);
|
if (eos == NULL) eos = pos + strlen(pos);
|
||||||
NSMutableData* data = [NSData dataWithBytes:pos length:(eos - pos + 1)];
|
char temp[eos - pos + 1];
|
||||||
((char *)[data mutableBytes])[eos - pos] = '\0';
|
memcpy(temp, pos, eos - pos);
|
||||||
return [NSString stringWithUTF8String:[data bytes]];
|
temp[eos - pos] = '\0';
|
||||||
|
return [NSString stringWithUTF8String:temp];
|
||||||
}
|
}
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue