VGMStream: Updated libvgmstream code base
Updated VGMStream to r1980-277-g72cb4b89 Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
parent
dd69345f54
commit
1eddc831f3
11 changed files with 862 additions and 42 deletions
|
@ -673,6 +673,8 @@
|
|||
83852B0B2680247900378854 /* rxws.c in Sources */ = {isa = PBXBuildFile; fileRef = 83852B092680247900378854 /* rxws.c */; };
|
||||
83852B0C2680247900378854 /* ads_midway.c in Sources */ = {isa = PBXBuildFile; fileRef = 83852B0A2680247900378854 /* ads_midway.c */; };
|
||||
8385D4E6245174C700FF8E67 /* diva.c in Sources */ = {isa = PBXBuildFile; fileRef = 8385D4E2245174C600FF8E67 /* diva.c */; };
|
||||
838A6FF12DCF0850009CBEE7 /* audiopkg_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 838A6FF02DCF0850009CBEE7 /* audiopkg_streamfile.h */; };
|
||||
838A6FF22DCF0850009CBEE7 /* audiopkg.c in Sources */ = {isa = PBXBuildFile; fileRef = 838A6FEF2DCF0850009CBEE7 /* audiopkg.c */; };
|
||||
838BDB681D3AF70D0022CA6F /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 838BDB671D3AF70D0022CA6F /* libz.tbd */; };
|
||||
838BDB6A1D3AF7140022CA6F /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 838BDB691D3AF7140022CA6F /* libiconv.tbd */; };
|
||||
838BDB6E1D3B043C0022CA6F /* ffmpeg.c in Sources */ = {isa = PBXBuildFile; fileRef = 838BDB6D1D3B043C0022CA6F /* ffmpeg.c */; };
|
||||
|
@ -1629,6 +1631,8 @@
|
|||
83852B092680247900378854 /* rxws.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rxws.c; sourceTree = "<group>"; };
|
||||
83852B0A2680247900378854 /* ads_midway.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ads_midway.c; sourceTree = "<group>"; };
|
||||
8385D4E2245174C600FF8E67 /* diva.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = diva.c; sourceTree = "<group>"; };
|
||||
838A6FEF2DCF0850009CBEE7 /* audiopkg.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = audiopkg.c; sourceTree = "<group>"; };
|
||||
838A6FF02DCF0850009CBEE7 /* audiopkg_streamfile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = audiopkg_streamfile.h; sourceTree = "<group>"; };
|
||||
838BDB671D3AF70D0022CA6F /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||
838BDB691D3AF7140022CA6F /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; };
|
||||
838BDB6D1D3B043C0022CA6F /* ffmpeg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffmpeg.c; sourceTree = "<group>"; };
|
||||
|
@ -2340,6 +2344,8 @@
|
|||
83AB8C741E8072A100086084 /* astb.c */,
|
||||
8349A8F01FE6257C00E26435 /* astl.c */,
|
||||
8306B0D520984590000302D4 /* atsl.c */,
|
||||
838A6FEF2DCF0850009CBEE7 /* audiopkg.c */,
|
||||
838A6FF02DCF0850009CBEE7 /* audiopkg_streamfile.h */,
|
||||
83EED5D2203A8BC7008BEB45 /* aus.c */,
|
||||
83A16D2722D2ADE700B90C4C /* awb.c */,
|
||||
83AA5D201F6E2F9B0020821C /* awc.c */,
|
||||
|
@ -3069,6 +3075,7 @@
|
|||
836F6F4D18BDC2190095E648 /* layout.h in Headers */,
|
||||
83269DD22399F5DE00F49FE3 /* nus3bank_streamfile.h in Headers */,
|
||||
83AA5D251F6E2F9C0020821C /* hca_keys.h in Headers */,
|
||||
838A6FF12DCF0850009CBEE7 /* audiopkg_streamfile.h in Headers */,
|
||||
834F7E832C709F5B003AC386 /* apa3_streamfile.h in Headers */,
|
||||
83256CDA28666C620036D9C0 /* l2tables.h in Headers */,
|
||||
83256CC828666C620036D9C0 /* getbits.h in Headers */,
|
||||
|
@ -3608,6 +3615,7 @@
|
|||
834F7DDD2C7093EA003AC386 /* mpeg_decoder.c in Sources */,
|
||||
83A21F8B201D8982000F04B9 /* sps_n1.c in Sources */,
|
||||
836F6F9E18BDC2190095E648 /* mus_acm.c in Sources */,
|
||||
838A6FF22DCF0850009CBEE7 /* audiopkg.c in Sources */,
|
||||
83A16D2B22D2ADE800B90C4C /* awb.c in Sources */,
|
||||
834F7EC72C70A786003AC386 /* api_tags.c in Sources */,
|
||||
831BA6191EAC61A500CF89B0 /* ogl.c in Sources */,
|
||||
|
|
|
@ -137,6 +137,11 @@ LIBVGMSTREAM_API int libvgmstream_fill(libvgmstream_t* lib, void* buf, int buf_s
|
|||
buf_copied += copy_samples;
|
||||
}
|
||||
|
||||
// detect EOF, to avoid another call to _fill that returns with 0 samples
|
||||
if (!done && priv->decode_done && priv->buf.consumed >= priv->buf.samples) {
|
||||
done = true;
|
||||
}
|
||||
|
||||
// TODO improve
|
||||
priv->dec.buf = buf;
|
||||
priv->dec.buf_samples = buf_copied;
|
||||
|
|
|
@ -89,6 +89,7 @@ static const char* extension_list[] = {
|
|||
"aud",
|
||||
"audio", //txth/reserved [Grimm Echoes (Android)]
|
||||
"audio_data",
|
||||
"audiopkg",
|
||||
"aus",
|
||||
"awa", //txth/reserved [Missing Parts Side A (PS2)]
|
||||
"awb",
|
||||
|
@ -1479,6 +1480,7 @@ static const meta_info meta_info_list[] = {
|
|||
{meta_SHAA, "Nintendo SHAA header"},
|
||||
{meta_OOR, "age .OOR header"},
|
||||
{meta_MIO, "Entis .MIO header"},
|
||||
{meta_AUDIOPKG, "Inevitable .AUDIOPKG header"},
|
||||
};
|
||||
|
||||
void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) {
|
||||
|
|
743
Frameworks/vgmstream/vgmstream/src/meta/audiopkg.c
Normal file
743
Frameworks/vgmstream/vgmstream/src/meta/audiopkg.c
Normal file
|
@ -0,0 +1,743 @@
|
|||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util/endianness.h"
|
||||
#include "../util/layout_utils.h"
|
||||
#include "audiopkg_streamfile.h"
|
||||
|
||||
// streams are defined as "hot" (memory) + "warm" (memory + stream?) + "cold" (stream) sample 'temperatures'.
|
||||
// BGM is typically set to either while SFX banks may include hot+cold types.
|
||||
#define MAX_TEMPERATURES 3
|
||||
|
||||
#define MAX_CHANNELS 2
|
||||
#define MAX_NAME 256
|
||||
|
||||
typedef enum { CODEC_NONE, CODEC_PSX, CODEC_XBOX, CODEC_XBOX_PC, CODEC_DSP, CODEC_PCM, CODEC_MP3 } audiopkg_codec_t;
|
||||
typedef enum { PT_NONE, PT_PS2, PT_XBOX, PT_GC, PT_PC } audiopkg_platform_t;
|
||||
|
||||
typedef struct {
|
||||
audiopkg_platform_t platform;
|
||||
int version;
|
||||
bool big_endian;
|
||||
|
||||
int total_subsongs;
|
||||
int target_subsong;
|
||||
|
||||
char name[MAX_NAME];
|
||||
int name_count;
|
||||
|
||||
// package info
|
||||
int descriptors; // total cues
|
||||
int identifiers; // total strings
|
||||
uint32_t descriptors_size;
|
||||
uint32_t strings_size;
|
||||
uint32_t lipsyncs_size;
|
||||
uint32_t musicdata_size;
|
||||
uint32_t breakpoints_size;
|
||||
int sample_headers[MAX_TEMPERATURES]; // actual stream headers
|
||||
int sample_indices[MAX_TEMPERATURES]; // pointers to stream headers
|
||||
int sample_sizes[MAX_TEMPERATURES]; // size per headers (in practice 0x28 or 0x56 for DSP)
|
||||
|
||||
// derived package info
|
||||
uint32_t strings_offset; // c-strings, referenced by identifiers
|
||||
uint32_t lipsyncs_offset; // big table
|
||||
uint32_t breakpoints_offset; // strings + data, probably identifiers to be triggered; some strings start with an u8 ID
|
||||
uint32_t musicdata_offset; // seeks? has N mini tables of count + N time position(?) floats
|
||||
uint32_t identifiers_index_offset; // identifier N to descriptor index
|
||||
uint32_t descriptors_index_offset; // points to descriptor (cue)
|
||||
uint32_t descriptors_offset; // variable-sized cues
|
||||
|
||||
uint32_t sample_indices_offset; // index to header
|
||||
uint32_t sample_headers_offset; // stream info
|
||||
int sample_indices_count; // total indices
|
||||
int sample_indices_extras; // extra indices for stereo handling
|
||||
int sample_headers_count; // total headers
|
||||
|
||||
// calculated current stream info
|
||||
int target_index;
|
||||
int target_temperature;
|
||||
uint32_t head_offset;
|
||||
uint32_t head_size;
|
||||
|
||||
// current stream header
|
||||
audiopkg_codec_t codec;
|
||||
int type;
|
||||
int channels;
|
||||
int sample_rate;
|
||||
int32_t num_samples;
|
||||
int32_t loop_start;
|
||||
int32_t loop_end;
|
||||
uint32_t stream_offset;
|
||||
uint32_t stream_size;
|
||||
uint32_t coefs_offset;
|
||||
uint32_t coefs_spacing;
|
||||
uint32_t stream_offset2;
|
||||
uint32_t stream_size2;
|
||||
|
||||
bool is_interleaved;
|
||||
bool loop_flag;
|
||||
} audiopkg_header_t;
|
||||
|
||||
static bool parse_header(audiopkg_header_t* h, STREAMFILE* sf);
|
||||
static VGMSTREAM* init_vgmstream_audiopkg_main(STREAMFILE* sf, audiopkg_header_t* h);
|
||||
|
||||
|
||||
/* .AUDIOPKG - from Inevitable / Midway Austin games [Area 51 (multi), The Hobbit (multi)] */
|
||||
VGMSTREAM* init_vgmstream_audiopkg(STREAMFILE* sf) {
|
||||
|
||||
/* checks */
|
||||
if (!(is_id32be(0x00,sf, "v1.5") || is_id32be(0x00,sf, "v1.6") || is_id32be(0x00,sf, "v1.7") || is_id32be(0x00,sf, "v1.8")))
|
||||
return NULL;
|
||||
|
||||
if (!check_extensions(sf,"audiopkg"))
|
||||
return NULL;
|
||||
|
||||
audiopkg_header_t h = {0};
|
||||
if (!parse_header(&h, sf))
|
||||
return NULL;
|
||||
|
||||
return init_vgmstream_audiopkg_main(sf, &h);
|
||||
}
|
||||
|
||||
static VGMSTREAM* init_vgmstream_audiopkg_main(STREAMFILE* sf, audiopkg_header_t* h) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(h->channels, h->loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_AUDIOPKG;
|
||||
vgmstream->sample_rate = h->sample_rate;
|
||||
vgmstream->num_samples = h->num_samples;
|
||||
vgmstream->loop_start_sample = h->loop_start;
|
||||
vgmstream->loop_end_sample = h->loop_end;
|
||||
vgmstream->stream_size = h->stream_size;
|
||||
vgmstream->num_streams = h->total_subsongs;
|
||||
|
||||
if (h->name[0] != '\0') {
|
||||
snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%s", h->name);
|
||||
vgmstream->stream_name[STREAM_NAME_SIZE-1] = '\0';
|
||||
}
|
||||
|
||||
switch(h->codec) {
|
||||
case CODEC_PCM: // Area 51 (PC)-sfx
|
||||
if (h->big_endian){
|
||||
VGM_LOG("AUDIOPKG: unsupported big endian found\n");
|
||||
goto fail;
|
||||
}
|
||||
vgmstream->coding_type = h->big_endian ? coding_PCM16BE : coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
break;
|
||||
|
||||
case CODEC_PSX: // The Hobbit (PS2), Area 51 (PS2)
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x8000;
|
||||
break;
|
||||
|
||||
case CODEC_XBOX_PC: // The Hobbit (PC)
|
||||
vgmstream->coding_type = coding_XBOX_IMA_mono;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x9000;
|
||||
break;
|
||||
|
||||
case CODEC_XBOX: // Area 51 (Xbox), The Hobbit (Xbox)
|
||||
vgmstream->coding_type = coding_XBOX_IMA_mono;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x8000;
|
||||
break;
|
||||
|
||||
case CODEC_DSP: // The Hobbit (GC)-sfx
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x8000;
|
||||
|
||||
dsp_read_coefs(vgmstream, sf, h->coefs_offset + 0x00, h->coefs_spacing, h->big_endian);
|
||||
dsp_read_hist (vgmstream, sf, h->coefs_offset + 0x24, h->coefs_spacing, h->big_endian);
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
case CODEC_MP3: { // Area 51 (PC)-music, The Hobbit (GC)-music/voices
|
||||
// not seen, interleaved uses regular stereo MP3
|
||||
if (!h->is_interleaved && h->channels > 1) {
|
||||
VGM_LOG("AUDIOPKG: found non-interleaved MPEG stereo\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// some The Hobbit (GC) file have issues, probably skipped/synced
|
||||
// (engine seems to use Miles Sound System for MPEG)
|
||||
|
||||
// garbage at frame start, seems consistent
|
||||
if ((read_u16be(h->stream_offset, sf) & 0xFFFE0) != 0xFFE0
|
||||
&& (read_u16be(h->stream_offset + 0x61, sf) & 0xFFE0) == 0xFFE0) {
|
||||
h->stream_offset += 0x61;
|
||||
h->stream_size -= 0x61;
|
||||
}
|
||||
|
||||
// single a blank frame
|
||||
if (read_u32be(h->stream_offset, sf) == 0) {
|
||||
h->stream_offset += 0x1B0;
|
||||
h->stream_size -= 0x1B0;
|
||||
}
|
||||
|
||||
mpeg_custom_config cfg = {0};
|
||||
cfg.skip_samples = 0; //?
|
||||
cfg.data_size = h->stream_size;
|
||||
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->codec_data = init_mpeg_custom(sf, h->stream_offset, &vgmstream->coding_type, h->channels, MPEG_STANDARD, &cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
|
||||
vgmstream->num_samples = h->num_samples;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, h->stream_offset))
|
||||
goto fail;
|
||||
|
||||
|
||||
// needed for memory 1ch XBOX_mono
|
||||
if (!h->is_interleaved) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = 0x00;
|
||||
}
|
||||
|
||||
if (!h->is_interleaved && h->channels > 1) {
|
||||
vgmstream->ch[0].channel_start_offset = h->stream_offset;
|
||||
vgmstream->ch[1].channel_start_offset = h->stream_offset2;
|
||||
vgmstream->ch[0].offset = h->stream_offset;
|
||||
vgmstream->ch[1].offset = h->stream_offset2;
|
||||
}
|
||||
|
||||
// TODO: handle streamfiles in a cleaner way
|
||||
// streamed XBOX_mono 0x24 frames can't fit exactly into 0x8000 interleave, and (instead of using 0x9000 like PC) blocks
|
||||
// work like this: [B1-0x8000-ch1][B1-0x8000-ch2][B2-0x7FF0-ch1 + 0x10 padding][B2-0x7FF0-ch2 + 0x10 padding] xN
|
||||
// Last frame in B1 is partially cut (since it doesn't fix that block), meaning we need a custom streamfile to read.
|
||||
if (h->codec == CODEC_XBOX && h->target_temperature == 2) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = 0x00;
|
||||
|
||||
for (int ch = 0; ch < h->channels; ch++) {
|
||||
vgmstream->ch[ch].offset = vgmstream->ch[ch].channel_start_offset = 0;
|
||||
close_streamfile(vgmstream->ch[ch].streamfile);
|
||||
|
||||
vgmstream->ch[ch].streamfile = setup_audiopkg_streamfile(sf, h->stream_offset, h->stream_size, ch, h->channels);
|
||||
if (!vgmstream->ch[ch].streamfile) goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// read base header
|
||||
static bool parse_package_identifier(audiopkg_header_t* h, STREAMFILE* sf) {
|
||||
uint32_t offset = 0x00;
|
||||
|
||||
// 00 version string
|
||||
// 10 platform string
|
||||
// 20 build user string
|
||||
// 30 build date string
|
||||
|
||||
// The Hobbit: v1.5 PS2/Xbox/GC, v1.6* PC (actually 1.5)
|
||||
// Area 51 (beta): v1.6 Xbox, v1.7 PS2
|
||||
// Area 51 (final): v1.7 PS2/Xbox/GC, v1.8* PC (actually 1.7)
|
||||
h->version = read_u8(offset + 0x03, sf) - 0x30;
|
||||
if (h->version < 5 || h->version > 8)
|
||||
return false;
|
||||
|
||||
uint32_t platform = read_u32be(offset + 0x10, sf);
|
||||
if (platform == get_id32be("Wind")) { // Windows
|
||||
h->platform = PT_PC;
|
||||
}
|
||||
else if (platform == get_id32be("Xbox")) {
|
||||
h->platform = PT_XBOX;
|
||||
}
|
||||
else if (platform == get_id32be("Play")) { // PlayStation II
|
||||
h->platform = PT_PS2;
|
||||
}
|
||||
else if (platform == get_id32be("Game")) { // Gamecube
|
||||
h->platform = PT_GC;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// simplify
|
||||
if (h->platform == PT_PC && h->version == 6) {
|
||||
h->version = 5;
|
||||
}
|
||||
|
||||
h->big_endian = (h->platform == PT_GC);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// read main header
|
||||
static bool parse_package_header(audiopkg_header_t* h, STREAMFILE* sf) {
|
||||
read_s32_t read_s32 = h->big_endian ? read_s32be : read_s32le;
|
||||
read_u32_t read_u32 = h->big_endian ? read_u32be : read_u32le;
|
||||
|
||||
uint32_t offset = 0x40;
|
||||
|
||||
/* global bank config (volumes, pan, pitch, etc), changes a bit between versions */
|
||||
if (h->version == 5)
|
||||
offset += 0x60;
|
||||
else if (h->version == 6)
|
||||
offset += 0x70;
|
||||
else if (h->version == 7 || h->version == 8)
|
||||
offset += 0x80;
|
||||
else
|
||||
return false;
|
||||
|
||||
//;VGM_LOG("AUDIOPKG: table at %x\n", offset);
|
||||
|
||||
/* table values */
|
||||
h->descriptors = read_s32(offset + 0x00, sf);
|
||||
h->identifiers = read_s32(offset + 0x04, sf);
|
||||
h->descriptors_size = read_u32(offset + 0x08, sf);
|
||||
h->strings_size = read_u32(offset + 0x0c, sf);
|
||||
h->lipsyncs_size = read_u32(offset + 0x10, sf);
|
||||
h->musicdata_size = read_u32(offset + 0x14, sf);
|
||||
h->breakpoints_size = read_u32(offset + 0x18, sf);
|
||||
h->sample_headers[0] = read_s32(offset + 0x1c, sf);
|
||||
h->sample_headers[1] = read_s32(offset + 0x20, sf);
|
||||
h->sample_headers[2] = read_s32(offset + 0x24, sf);
|
||||
h->sample_indices[0] = read_s32(offset + 0x28, sf);
|
||||
h->sample_indices[1] = read_s32(offset + 0x2c, sf);
|
||||
h->sample_indices[2] = read_s32(offset + 0x30, sf);
|
||||
// 34: compression types x3, useless since it's also defined per stream
|
||||
h->sample_sizes[0] = read_s32(offset + 0x40, sf);
|
||||
h->sample_sizes[1] = read_s32(offset + 0x44, sf);
|
||||
h->sample_sizes[2] = read_s32(offset + 0x48, sf);
|
||||
|
||||
offset += 0x4c;
|
||||
if (h->version >= 6) {
|
||||
// 4c: V1.6: size? v1.7: always 1?, v1.8: always 0?
|
||||
offset += 0x04;
|
||||
}
|
||||
|
||||
if (h->sample_indices[1] != 0 || h->sample_headers[1] != 0) {
|
||||
vgm_logi("AUDIOPKG: 'warm' samples found\n");
|
||||
return false; //not seen (not implemented?)
|
||||
}
|
||||
|
||||
if ((h->lipsyncs_size && h->musicdata_size) || (h->lipsyncs_size && h->breakpoints_size)) {
|
||||
vgm_logi("AUDIOPKG: lipsyncs and musicdata/breakpoints found\n");
|
||||
return false; //unknown order
|
||||
}
|
||||
|
||||
|
||||
/* tables */
|
||||
h->strings_offset = offset;
|
||||
offset += h->strings_size;
|
||||
|
||||
h->lipsyncs_offset = offset;
|
||||
offset += h->lipsyncs_size;
|
||||
|
||||
h->breakpoints_offset = offset;
|
||||
offset += h->breakpoints_size;
|
||||
|
||||
h->musicdata_offset = offset;
|
||||
offset += h->musicdata_size;
|
||||
|
||||
h->identifiers_index_offset = offset;
|
||||
offset += (h->identifiers * 0x08);
|
||||
|
||||
h->descriptors_index_offset = offset;
|
||||
offset += (h->descriptors * 0x04);
|
||||
|
||||
h->descriptors_offset = offset;
|
||||
offset += h->descriptors_size;
|
||||
|
||||
// u16 index N in sample-header table, N per hot + warm + cold,
|
||||
// plus 1 index pointing to end for each defined (for stereo handling)
|
||||
h->sample_indices_count = h->sample_indices[0] + h->sample_indices[1] + h->sample_indices[2];
|
||||
h->sample_indices_extras = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (!h->sample_indices[i])
|
||||
continue;
|
||||
h->sample_indices_extras++;
|
||||
}
|
||||
h->sample_indices_offset = offset;
|
||||
uint32_t sample_indices_size = (h->sample_indices_count + h->sample_indices_extras) * 0x02;
|
||||
offset += sample_indices_size;
|
||||
|
||||
h->sample_headers_count = h->sample_headers[0] + h->sample_headers[1] + h->sample_headers[2];
|
||||
h->sample_headers_offset = offset;
|
||||
uint32_t sample_headers_size = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
sample_headers_size += h->sample_headers[i] * h->sample_sizes[i];
|
||||
}
|
||||
offset += sample_headers_size;
|
||||
|
||||
// after xN sample headers is variable padding then data start
|
||||
|
||||
#if 0
|
||||
VGM_LOG("AUDIOPKG: data:\n");
|
||||
VGM_LOG(" descriptors=%i\n", h->descriptors);
|
||||
VGM_LOG(" identifiers=%i\n", h->identifiers);
|
||||
VGM_LOG(" strings_offset=%x\n", h->strings_offset);
|
||||
VGM_LOG(" lipsyncs_offset=%x\n", h->lipsyncs_offset);
|
||||
VGM_LOG(" breakpoints_offset=%x\n", h->breakpoints_offset);
|
||||
VGM_LOG(" musicdata_offset=%x\n", h->musicdata_offset);
|
||||
VGM_LOG(" identifiers_index_offset=%x\n", h->identifiers_index_offset);
|
||||
VGM_LOG(" descriptors_index_offset=%x\n", h->descriptors_index_offset);
|
||||
VGM_LOG(" descriptors_offset=%x + %x\n", h->descriptors_offset, h->descriptors_size);
|
||||
VGM_LOG(" sample_indices_offset=%x + %x (%i + %i + %i)\n", h->sample_indices_offset, sample_indices_size, h->sample_indices[0], h->sample_indices[1], h->sample_indices[2]);
|
||||
VGM_LOG(" sample_headers_offset=%x + %x (%i + %i + %i)\n", h->sample_headers_offset, sample_headers_size, h->sample_headers[0], h->sample_headers[1], h->sample_headers[2]);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
// calculate subsong info
|
||||
static bool parse_sample_indices(audiopkg_header_t* h, STREAMFILE* sf) {
|
||||
read_u16_t read_u16 = h->big_endian ? read_u16be : read_u16le;
|
||||
|
||||
if (h->sample_indices_count > h->sample_headers_count) {
|
||||
vgm_logi("AUDIOPKG: unexpected count\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// indices point to headers, but for stereo files there is 1 index but 2 headers,
|
||||
// so sample_indices_counts are total subsongs rather than sample_headers_count.
|
||||
h->total_subsongs = h->sample_indices_count;
|
||||
|
||||
if (h->total_subsongs <= 0) {
|
||||
vgm_logi("AUDIOPKG: bank has no subsongs (ignore)\n");
|
||||
return false;
|
||||
}
|
||||
if (h->target_subsong < 1 || h->target_subsong > h->total_subsongs)
|
||||
return false;
|
||||
|
||||
// map target subsong to hot/warm/cold index + offsets
|
||||
int entries_left = h->target_subsong - 1;
|
||||
uint32_t target_offset = h->sample_indices_offset;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (!h->sample_indices[i])
|
||||
continue;
|
||||
|
||||
if (entries_left >= h->sample_indices[i]) {
|
||||
// not in this section
|
||||
target_offset += (h->sample_indices[i] + 1) * 0x02;
|
||||
entries_left -= h->sample_indices[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
target_offset += entries_left * 0x02;
|
||||
|
||||
h->target_temperature = i;
|
||||
h->target_index = entries_left;
|
||||
break;
|
||||
}
|
||||
|
||||
// Stereo songs are detected by checking current index vs next index (really).
|
||||
// There is always +1 extra index to account for this calculation.
|
||||
int header_index0 = read_u16(target_offset + 0x00, sf);
|
||||
int header_index1 = read_u16(target_offset + 0x02, sf);
|
||||
|
||||
h->channels = (header_index1 - header_index0);
|
||||
if (h->channels < 1 || h->channels > MAX_CHANNELS) {
|
||||
VGM_LOG("AUDIOPKG: wrong channels %i (target %x, temp=%i, index=%i)\n", h->channels, target_offset, h->target_temperature, h->target_index);
|
||||
return false;
|
||||
}
|
||||
|
||||
h->head_size = h->sample_sizes[h->target_temperature];
|
||||
|
||||
h->head_offset = h->sample_headers_offset;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (!h->sample_headers[i])
|
||||
continue;
|
||||
|
||||
if (i < h->target_temperature) {
|
||||
// not in this section
|
||||
h->head_offset += h->sample_headers[i] * h->sample_sizes[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
h->head_offset += header_index0 * h->sample_sizes[i];
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
VGM_LOG("AUDIOPKG: subsong:\n");
|
||||
VGM_LOG(" subsongs=%i / %i\n", h->target_subsong, h->total_subsongs);
|
||||
VGM_LOG(" target offset=%x\n", target_offset);
|
||||
VGM_LOG(" header offset=%x + %x\n", h->head_offset, h->head_size);
|
||||
VGM_LOG(" channels=%i\n", h->channels);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// read subsong header
|
||||
static bool parse_sample_header(audiopkg_header_t* h, STREAMFILE* sf) {
|
||||
read_s32_t read_s32 = h->big_endian ? read_s32be : read_s32le;
|
||||
read_u32_t read_u32 = h->big_endian ? read_u32be : read_u32le;
|
||||
|
||||
h->type = -1;
|
||||
|
||||
uint32_t offset = h->head_offset;
|
||||
// 00: memory offset? (null)
|
||||
h->stream_offset = read_u32(offset + 0x04, sf); // absolute
|
||||
h->stream_size = read_u32(offset + 0x08, sf);
|
||||
// 0c: lipsync offset? (-1 if not set)
|
||||
// 10: breakpoint offset (-1 if not set)
|
||||
h->type = read_s32(offset + 0x14, sf);
|
||||
h->num_samples = read_s32(offset + 0x18, sf);
|
||||
h->sample_rate = read_s32(offset + 0x1c, sf);
|
||||
h->loop_start = read_s32(offset + 0x20, sf);
|
||||
h->loop_end = read_s32(offset + 0x24, sf);
|
||||
h->coefs_offset = offset + 0x28; // DSP only
|
||||
h->coefs_spacing = h->head_size;
|
||||
|
||||
h->loop_flag = (h->loop_end > 0);
|
||||
|
||||
// map codec
|
||||
switch(h->type) {
|
||||
case 0x00:
|
||||
if (h->platform == PT_PS2) {
|
||||
h->codec = CODEC_PSX;
|
||||
}
|
||||
if (h->platform == PT_GC) {
|
||||
h->codec = CODEC_DSP;
|
||||
}
|
||||
if (h->platform == PT_XBOX) {
|
||||
h->codec = CODEC_XBOX;
|
||||
}
|
||||
if (h->platform == PT_PC) {
|
||||
h->codec = CODEC_XBOX_PC;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
h->codec = CODEC_PCM;
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
h->codec = CODEC_MP3;
|
||||
break;
|
||||
|
||||
default:
|
||||
VGM_LOG("AUDIOPKG: unknown codec\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// stereo files have 2 sample headers; if both point to the same stream it's interleaved, otherwise dual mono
|
||||
if (h->channels == 2) {
|
||||
offset += h->head_size;
|
||||
h->stream_offset2 = read_u32(offset + 0x04, sf);
|
||||
h->stream_size2 = read_u32(offset + 0x08, sf);
|
||||
|
||||
h->is_interleaved = h->stream_offset == h->stream_offset2;
|
||||
}
|
||||
|
||||
#if 0
|
||||
VGM_LOG("AUDIOPKG: header %x\n", h->head_offset);
|
||||
VGM_LOG(" stream=%x / %x\n", h->stream_offset, h->stream_size);
|
||||
VGM_LOG(" stream2=%x / %x\n", h->stream_offset2, h->stream_size2);
|
||||
VGM_LOG(" srate=%i\n", h->sample_rate);
|
||||
VGM_LOG(" samples=%i\n", h->num_samples);
|
||||
VGM_LOG(" type=%i / interleaved=%i\n", h->type, h->is_interleaved);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// descriptor have a TLV-like header + flags, then optional size, then payload depending on type
|
||||
// which is usually simple list pointing to sample indices
|
||||
static bool parse_names_descriptor(audiopkg_header_t* h, STREAMFILE* sf, uint32_t offset, int depth) {
|
||||
read_u16_t read_u16 = h->big_endian ? read_u16be : read_u16le;
|
||||
read_u32_t read_u32 = h->big_endian ? read_u32be : read_u32le;
|
||||
|
||||
if (depth > 1) {
|
||||
VGM_LOG("AUDIOPKG: recursion found\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t descriptor_header = read_u16(offset, sf);
|
||||
// 02: flags (volume, pan, etc)
|
||||
|
||||
uint16_t descriptor_type = (descriptor_header >> 14) & 0x03;
|
||||
uint16_t descriptor_params = (descriptor_header >> 13) & 0x01;
|
||||
//uint16_t descriptor_value = (descriptor_header >> 0) & 0x1FFF; //always 0?
|
||||
//VGM_LOG("AUDIOPKG: descriptor: type=%x, param=%x, value=%x at %x\n", descriptor_type, descriptor_params, descriptor_value, offset);
|
||||
|
||||
offset += 0x04;
|
||||
if (descriptor_params) {
|
||||
uint16_t params_size = read_u16(offset, sf);
|
||||
offset += params_size;
|
||||
}
|
||||
|
||||
int items = 0;
|
||||
switch(descriptor_type) {
|
||||
case 0x00: // simple cue
|
||||
items = 1;
|
||||
break;
|
||||
|
||||
case 0x01: // complex cue
|
||||
items = read_u16(offset + 0x00, sf);
|
||||
offset += 0x02;
|
||||
break;
|
||||
|
||||
case 0x02: // random list
|
||||
items = read_u16(offset + 0x00, sf);
|
||||
offset += 0x02;
|
||||
offset += 0x08; // up to 64 bits to make a random list
|
||||
break;
|
||||
|
||||
case 0x03: // weighted list
|
||||
items = read_u16(offset + 0x00, sf);
|
||||
offset += 0x02;
|
||||
offset += 0x02 * items; // weights
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
//;VGM_LOG("AUDIOPKG: parse %i items at %x (type=%i)\n", items, offset, descriptor_type);
|
||||
|
||||
// parse index list
|
||||
for (int i = 0; i < items; i++) {
|
||||
if (descriptor_type == 0x01) {
|
||||
offset += 0x02; //time?
|
||||
}
|
||||
uint16_t index_header = read_u16(offset, sf);
|
||||
// 02: flags? (unused?)
|
||||
|
||||
uint16_t index_type = (index_header >> 14) & 0x03;
|
||||
uint16_t index_params = (index_header >> 13) & 0x01;
|
||||
uint16_t index_value = (index_header >> 0) & 0x1FFF;
|
||||
//;VGM_LOG("AUDIOPKG: index: type=%x, param=%x, value=%x at %x\n", index_type, index_params, index_value, offset);
|
||||
|
||||
// index points to another descriptor
|
||||
if (index_type == 0x03) {
|
||||
uint32_t descriptor_index_offset = h->descriptors_index_offset + 0x04 * index_value;
|
||||
uint32_t descriptor_offset = read_u32(descriptor_index_offset, sf);
|
||||
descriptor_offset += h->descriptors_offset;
|
||||
|
||||
return parse_names_descriptor(h, sf, descriptor_offset, depth + 1);
|
||||
}
|
||||
|
||||
// index points to sample (0=hot, 1=warm, 2=cold)
|
||||
int index_temperature = index_type;
|
||||
if (index_temperature == h->target_temperature && index_value == h->target_index) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// skip to next index
|
||||
offset += 0x04;
|
||||
if (index_params) { // not seen but happens in theory
|
||||
uint16_t params_size = read_u16(offset + 0x00, sf);
|
||||
offset += params_size;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//todo safeops, avoid recalc lens
|
||||
static void v_strcat(char* dst, int dst_max, const char* src) {
|
||||
int dst_len = strlen(dst);
|
||||
int src_len = strlen(dst);
|
||||
if (dst_len + src_len > dst_max - 1)
|
||||
return;
|
||||
strcat(dst, src);
|
||||
}
|
||||
#if 0
|
||||
static void v_strcpy(char* dst, int dst_max, const char* src) {
|
||||
int src_len = strlen(dst);
|
||||
if (src_len > dst_max - 1)
|
||||
return;
|
||||
strcpy(dst, src);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Assign names based on identifiers pointing to our stream.
|
||||
// In rare cases some streams don't have assigned names, probably an user mistake or just unused
|
||||
// (ex. The Hobbit's SFX_GUI.AUDIOPKG: LOCKTIMER_TICK + LOCKTIMER_TOCK both point to #20, but the latter should be #21)
|
||||
static bool parse_names(audiopkg_header_t* h, STREAMFILE* sf) {
|
||||
read_u16_t read_u16 = h->big_endian ? read_u16be : read_u16le;
|
||||
read_u32_t read_u32 = h->big_endian ? read_u32be : read_u32le;
|
||||
|
||||
uint32_t offset = h->identifiers_index_offset;
|
||||
char identifier[0x100];
|
||||
|
||||
for (int i = 0; i < h->identifiers; i++) {
|
||||
// identifier index table
|
||||
uint16_t string_offset = read_u16(offset + 0x00, sf) + h->strings_offset;
|
||||
uint16_t descriptor_index = read_u16(offset + 0x02, sf);
|
||||
// 04: reserved (set to some value after load)
|
||||
|
||||
// descriptor index table
|
||||
uint32_t descriptor_index_offset = h->descriptors_index_offset + 0x04 * descriptor_index;
|
||||
uint32_t descriptor_offset = read_u32(descriptor_index_offset, sf);
|
||||
|
||||
uint16_t index_type = descriptor_offset >> 16; //unsure
|
||||
descriptor_offset += h->descriptors_offset;
|
||||
|
||||
if (index_type != 0) {
|
||||
VGM_LOG("AUDIOPKG: bad index=%i in descriptor %i\n", index_type, descriptor_index);
|
||||
return false;
|
||||
}
|
||||
|
||||
//read_string(identifier, sizeof(identifier), string_offset, sf);
|
||||
//;VGM_LOG("AUDIOPKG: name=%s > %i\n", identifier, descriptor_index);
|
||||
|
||||
bool string_used = parse_names_descriptor(h, sf, descriptor_offset, 0);
|
||||
if (string_used) {
|
||||
if (h->name_count)
|
||||
v_strcat(h->name, sizeof(h->name), "; ");
|
||||
|
||||
read_string(identifier, sizeof(identifier), string_offset, sf);
|
||||
v_strcat(h->name, sizeof(h->name), identifier);
|
||||
h->name_count++;
|
||||
}
|
||||
|
||||
offset += 0x08;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// AUDIOPKG info:
|
||||
// - defines a basic "package identifier" and "package header" with common parameters + tables
|
||||
// - tables define N "identifiers" (cue names)
|
||||
// - identifiers point to 1 "descriptor" (cue)
|
||||
// - each descriptor points to N "sample indices"
|
||||
// - each sample index points to 1 or 2 "sample headers"
|
||||
// - sample headers have actual stream info
|
||||
// To play anything devs would call some identifier by name, event style.
|
||||
// Streams are divided into memory ("hot sample") and stream ("cold sample") data, but both work the same.
|
||||
static bool parse_header(audiopkg_header_t* h, STREAMFILE* sf) {
|
||||
h->target_subsong = sf->stream_index;
|
||||
if (h->target_subsong == 0)
|
||||
h->target_subsong = 1;
|
||||
|
||||
if (!parse_package_identifier(h, sf))
|
||||
return false;
|
||||
if (!parse_package_header(h, sf))
|
||||
return false;
|
||||
if (!parse_sample_indices(h, sf))
|
||||
return false;
|
||||
if (!parse_sample_header(h, sf))
|
||||
return false;
|
||||
if (!parse_names(h, sf))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef _LRMD_STREAMFILE_H_
|
||||
#define _LRMD_STREAMFILE_H_
|
||||
#include "deblock_streamfile.h"
|
||||
|
||||
static void block_callback(STREAMFILE* sf, deblock_io_data* data) {
|
||||
data->block_size = 0x10000;
|
||||
data->data_size = data->block_size - 0x10;
|
||||
}
|
||||
|
||||
/* Deinterleaves .AUDIOPKG Xbox streams */
|
||||
static STREAMFILE* setup_audiopkg_streamfile(STREAMFILE* sf, uint32_t stream_offset, uint32_t stream_size, int stream_number, int stream_count) {
|
||||
STREAMFILE* new_sf = NULL;
|
||||
|
||||
// blocks: [B1-0x8000-ch1][B1-0x8000-ch2][B2-0x7FF0-ch1 + 0x10 padding][B2-0x7FF0-ch2 + 0x10 padding] xN
|
||||
// For now add a deblock of L/R blocks, then another to remove padding.
|
||||
// Probably should mix into a single deblocker but can't think of anything decent at the moment.
|
||||
|
||||
deblock_config_t cfg1 = {0};
|
||||
cfg1.stream_start = stream_offset;
|
||||
cfg1.stream_size = stream_size;
|
||||
cfg1.step_start = stream_number;
|
||||
cfg1.step_count = stream_count;
|
||||
cfg1.chunk_size = 0x8000;
|
||||
|
||||
deblock_config_t cfg2 = {0};
|
||||
cfg2.block_callback = block_callback;
|
||||
|
||||
//TODO: this SF is handled a bit differently than usual, improve
|
||||
new_sf = reopen_streamfile(sf, 0); //open_wrap_streamfile(sf);
|
||||
new_sf = open_io_deblock_streamfile_f(new_sf, &cfg1);
|
||||
new_sf = open_io_deblock_streamfile_f(new_sf, &cfg2);
|
||||
return new_sf;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -772,6 +772,7 @@ static const hcakey_info hcakey_list[] = {
|
|||
{0x353e9b0a47ed61bc}, // music_0940001
|
||||
{0x1b06e24d34d67ac8}, // music_1010001
|
||||
{0xab02c0d6f229df05}, // music_1010002
|
||||
{0x56a96f773f447a7e}, // music_1010003
|
||||
{0x2a47feac8dc3ca9c}, // music_3010001
|
||||
{0x9ebbaf63ffe9d9ef}, // music_3010002
|
||||
{0xe553dba6592293d8}, // music_3010003
|
||||
|
@ -1272,12 +1273,20 @@ static const hcakey_info hcakey_list[] = {
|
|||
{0x34c0f6db642145a0}, // music_5050307
|
||||
{0xb7ecea9165c448da}, // music_5050308
|
||||
{0xa5e9bd945c5caf2c}, // music_5050309
|
||||
{0x8f88e97a742ec2b6}, // music_5050310
|
||||
{0xdafc7d4d918a6282}, // music_5050311
|
||||
{0x9260652a706b3616}, // music_5050312
|
||||
{0x91ff4aedae9ce2c3}, // music_5050313
|
||||
{0xeaaa417505d65dd1}, // music_5050322
|
||||
{0x591899d025c3beb7}, // music_5050323
|
||||
{0xa57678c62ef99124}, // music_5050324
|
||||
{0x925f360a8ccb4c32}, // music_5050325
|
||||
{0x2a9281f77161e068}, // music_5050326
|
||||
{0x3a00b50e407febcb}, // music_5050327
|
||||
{0x83c86bfce70eebaa}, // music_5050328
|
||||
{0x250a01be07e87ea4}, // music_5050329
|
||||
{0x664c54cd6651be76}, // music_5050330
|
||||
{0x1b51c4bfabf7a714}, // music_5050331
|
||||
{0x52c250eade92393b}, // music_9010001
|
||||
{0xf66e6bb5b0599b07}, // music_9010002
|
||||
{0x8582b5a60dbbf948}, // music_9010003
|
||||
|
|
|
@ -1035,4 +1035,6 @@ VGMSTREAM* init_vgmstream_2dx(STREAMFILE* sf);
|
|||
|
||||
VGMSTREAM* init_vgmstream_ssp(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM* init_vgmstream_audiopkg(STREAMFILE* sf);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "../util/text_reader.h"
|
||||
#include "../util/endianness.h"
|
||||
#include "../util/paths.h"
|
||||
#include "../util/companion_files.h"
|
||||
|
||||
#define TXT_LINE_MAX 2048 /* probably ~1000 would be ok */
|
||||
#define TXT_LINE_KEY_MAX 128
|
||||
|
@ -1424,7 +1425,7 @@ static int parse_keyval(STREAMFILE* sf_, txth_header* txth, const char* key, cha
|
|||
}
|
||||
|
||||
/* HEADER/BODY CONFIG */
|
||||
else if (is_string(key,"header_file")) {
|
||||
else if (is_string(key,"header_file") || is_string(key,"head_file")) {
|
||||
|
||||
/* first remove old head if needed */
|
||||
if (txth->sf_head_opened) {
|
||||
|
@ -1447,12 +1448,17 @@ static int parse_keyval(STREAMFILE* sf_, txth_header* txth, const char* key, cha
|
|||
else if (val[0]=='*' && val[1]=='.') { /* basename + extension */
|
||||
txth->sf_head = open_streamfile_by_ext(txth->sf, (val+2));
|
||||
if (!txth->sf_head) goto fail;
|
||||
txth->sf_head_opened = 1;
|
||||
txth->sf_head_opened = true;
|
||||
}
|
||||
else if (is_string(val,".txtm")) {
|
||||
txth->sf_head = read_filemap_file(txth->sf, 0);
|
||||
if (!txth->sf_head) goto fail;
|
||||
txth->sf_head_opened = true;
|
||||
}
|
||||
else { /* open file */
|
||||
txth->sf_head = open_path_streamfile(txth->sf, val);
|
||||
if (!txth->sf_head) goto fail;
|
||||
txth->sf_head_opened = 1;
|
||||
txth->sf_head_opened = true;
|
||||
}
|
||||
}
|
||||
else if (is_string(key,"body_file")) {
|
||||
|
@ -1478,12 +1484,17 @@ static int parse_keyval(STREAMFILE* sf_, txth_header* txth, const char* key, cha
|
|||
else if (val[0]=='*' && val[1]=='.') { /* basename + extension */
|
||||
txth->sf_body = open_streamfile_by_ext(txth->sf, (val+2));
|
||||
if (!txth->sf_body) goto fail;
|
||||
txth->sf_body_opened = 1;
|
||||
txth->sf_body_opened = true;
|
||||
}
|
||||
else if (is_string(val,".txtm")) {
|
||||
txth->sf_body = read_filemap_file(txth->sf, 0);
|
||||
if (!txth->sf_body) goto fail;
|
||||
txth->sf_body_opened = true;
|
||||
}
|
||||
else { /* open file */
|
||||
txth->sf_body = open_path_streamfile(txth->sf, val);
|
||||
if (!txth->sf_body) goto fail;
|
||||
txth->sf_body_opened = 1;
|
||||
txth->sf_body_opened = true;
|
||||
}
|
||||
|
||||
/* use body as header when opening a .txth directly to simplify things */
|
||||
|
|
|
@ -511,6 +511,7 @@ init_vgmstream_t init_vgmstream_functions[] = {
|
|||
init_vgmstream_undefind,
|
||||
init_vgmstream_oor,
|
||||
init_vgmstream_mio,
|
||||
init_vgmstream_audiopkg,
|
||||
|
||||
/* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */
|
||||
init_vgmstream_agsc,
|
||||
|
|
|
@ -721,6 +721,7 @@ typedef enum {
|
|||
meta_SHAA,
|
||||
meta_OOR,
|
||||
meta_MIO,
|
||||
meta_AUDIOPKG,
|
||||
} meta_t;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -413,6 +413,7 @@
|
|||
<string>aud</string>
|
||||
<string>audio</string>
|
||||
<string>audio_data</string>
|
||||
<string>audiopkg</string>
|
||||
<string>aus</string>
|
||||
<string>awa</string>
|
||||
<string>awb</string>
|
||||
|
@ -719,6 +720,7 @@
|
|||
<string>omu</string>
|
||||
<string>oor</string>
|
||||
<string>opu</string>
|
||||
<string>opusnx</string>
|
||||
<string>opusx</string>
|
||||
<string>oto</string>
|
||||
<string>ovb</string>
|
||||
|
@ -754,7 +756,6 @@
|
|||
<string>rda</string>
|
||||
<string>res</string>
|
||||
<string>rkv</string>
|
||||
<string>rnd</string>
|
||||
<string>rof</string>
|
||||
<string>rpgmvo</string>
|
||||
<string>rrds</string>
|
||||
|
@ -833,6 +834,7 @@
|
|||
<string>smk</string>
|
||||
<string>smp</string>
|
||||
<string>smv</string>
|
||||
<string>sn0</string>
|
||||
<string>snb</string>
|
||||
<string>snd</string>
|
||||
<string>snds</string>
|
||||
|
@ -852,6 +854,7 @@
|
|||
<string>srsa</string>
|
||||
<string>ss2</string>
|
||||
<string>ssd</string>
|
||||
<string>ssf</string>
|
||||
<string>ssm</string>
|
||||
<string>sspr</string>
|
||||
<string>ssp</string>
|
||||
|
@ -906,7 +909,6 @@
|
|||
<string>vai</string>
|
||||
<string>vam</string>
|
||||
<string>vas</string>
|
||||
<string>vawx</string>
|
||||
<string>vb</string>
|
||||
<string>vbk</string>
|
||||
<string>vbx</string>
|
||||
|
@ -989,6 +991,7 @@
|
|||
<string>xnb</string>
|
||||
<string>xsh</string>
|
||||
<string>xsf</string>
|
||||
<string>xst</string>
|
||||
<string>xse</string>
|
||||
<string>xsew</string>
|
||||
<string>xss</string>
|
||||
|
@ -1398,6 +1401,41 @@
|
|||
<key>LSTypeIsPackage</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>psf</string>
|
||||
<string>minipsf</string>
|
||||
<string>psf2</string>
|
||||
<string>minipsf2</string>
|
||||
<string>ssf</string>
|
||||
<string>minissf</string>
|
||||
<string>dsf</string>
|
||||
<string>minidsf</string>
|
||||
<string>qsf</string>
|
||||
<string>miniqsf</string>
|
||||
<string>gsf</string>
|
||||
<string>minigsf</string>
|
||||
<string>ncsf</string>
|
||||
<string>minincsf</string>
|
||||
<string>2sf</string>
|
||||
<string>mini2sf</string>
|
||||
<string>usf</string>
|
||||
<string>miniusf</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>vg.icns</string>
|
||||
<key>CFBundleTypeIconSystemGenerated</key>
|
||||
<integer>1</integer>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>PSF Format Files</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Default</string>
|
||||
<key>LSTypeIsPackage</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
|
@ -1497,41 +1535,6 @@
|
|||
<key>LSTypeIsPackage</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>psf</string>
|
||||
<string>minipsf</string>
|
||||
<string>psf2</string>
|
||||
<string>minipsf2</string>
|
||||
<string>ssf</string>
|
||||
<string>minissf</string>
|
||||
<string>dsf</string>
|
||||
<string>minidsf</string>
|
||||
<string>qsf</string>
|
||||
<string>miniqsf</string>
|
||||
<string>gsf</string>
|
||||
<string>minigsf</string>
|
||||
<string>ncsf</string>
|
||||
<string>minincsf</string>
|
||||
<string>2sf</string>
|
||||
<string>mini2sf</string>
|
||||
<string>usf</string>
|
||||
<string>miniusf</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>vg.icns</string>
|
||||
<key>CFBundleTypeIconSystemGenerated</key>
|
||||
<integer>1</integer>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>PSF Format Files</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Default</string>
|
||||
<key>LSTypeIsPackage</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
|
|
Loading…
Reference in a new issue