Merge pull request #1231 from bnnm/bigrp-misc

- Fix some .ccc
- Show multiple cue names in SQEX .sab
- Reduce internal path limit for more common cases
- Add .bigrp [Blaster Master Zero 2 (SW), Gunvolt 3 (SW)]
This commit is contained in:
bnnm 2022-09-24 00:15:30 +02:00 committed by GitHub
commit 24f5ee6500
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 2005 additions and 158 deletions

View File

@ -315,6 +315,7 @@ are used in few games.
- Xiph CELT (FSB) - Xiph CELT (FSB)
- Musepack - Musepack
- FLAC - FLAC
- Inti Creates' Range / DCT codecs
- Others - Others
Sometimes standard codecs come in non-standard layouts that aren't normally Sometimes standard codecs come in non-standard layouts that aren't normally

View File

@ -630,6 +630,25 @@ If your main motivation for extracting is to rename or have loose files, remembe
you can simply use TXTP to point to a subsong, and name that `.txtp` whatever you you can simply use TXTP to point to a subsong, and name that `.txtp` whatever you
want, without having to touch original data or needing custom extractors. want, without having to touch original data or needing custom extractors.
### Cue formats
Some formats that vgmstream supports (SQEX's .sab, CRI's .acb+awb, Wwise's .bnk+wem,
Microsoft's .xss+.xwb....) are "cue" formats. The way these work is (more or less),
they have a bunch of named audio "cues"/"events" in a section of the file, that are
called to play one or multiple audio "waves"/"materials" in another section.
Rather than handling cues, vgmstream shows and plays waves, then assigns cue names
that point to the wave if possible, since vgmstream mainly deals with streamed/wave
audio and simulating cues is out of scope. Figuring out a whole cue format can be a
*huge* time investment, so handling waves only is often enough.
Cues can be *very* complex, like N cues pointing to 1 wave with varying pitch, or
1 cue playing one random wave out of 3. Sometimes not all waves are referenced by
cues, or cues do undesirable effects that make only playing waves a good compromise.
Simulating cues is better handled with external tools that allow more flexibility
(for example, this project simulates Wwise's extremely complex cues/events by creating
.TXTP telling vgmstream which config and waves to play, and one can filter desired
cues/TXTP: https://github.com/bnnm/wwiser).
## Logged errors and unplayable supported files ## Logged errors and unplayable supported files
Some formats should normally play, but somehow don't. In those cases plugins Some formats should normally play, but somehow don't. In those cases plugins
can print vgmstream's error info to console (for example, `.fsb` with an unknown can print vgmstream's error info to console (for example, `.fsb` with an unknown

View File

@ -353,6 +353,16 @@ void seek_tac(tac_codec_data* data, int32_t num_sample);
void free_tac(tac_codec_data* data); void free_tac(tac_codec_data* data);
/* ice_decoder */
typedef struct ice_codec_data ice_codec_data;
ice_codec_data* init_ice(STREAMFILE* sf, int subsong);
void decode_ice(ice_codec_data* data, sample_t* outbuf, int32_t samples_to_do);
void reset_ice(ice_codec_data* data);
void seek_ice(ice_codec_data* data, int32_t num_sample);
void free_ice(ice_codec_data* data);
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
/* ogg_vorbis_decoder */ /* ogg_vorbis_decoder */
typedef struct ogg_vorbis_codec_data ogg_vorbis_codec_data; typedef struct ogg_vorbis_codec_data ogg_vorbis_codec_data;

138
src/coding/ice_decoder.c Normal file
View File

@ -0,0 +1,138 @@
#include "coding.h"
#include "ice_decoder_icelib.h"
typedef struct {
STREAMFILE* sf;
int offset;
} icelib_io_t;
struct ice_codec_data {
STREAMFILE* sf;
int channels;
icesnd_handle_t* ctx;
icelib_io_t io;
};
static void icelib_set_callbacks(icesnd_callback_t* cb, STREAMFILE* sf, icelib_io_t* io);
ice_codec_data* init_ice(STREAMFILE* sf, int subsong) {
ice_codec_data* data = NULL;
data = calloc(1, sizeof(ice_codec_data));
if (!data) goto fail;
data->sf = reopen_streamfile(sf, 0);
if (!data->sf) goto fail;
{
icesnd_callback_t cb = {0};
icesnd_info_t info = {0};
int err;
icelib_set_callbacks(&cb, data->sf, &data->io);
data->ctx = icesnd_init(subsong, &cb);
if (!data->ctx) goto fail;
err = icesnd_info(data->ctx, &info);
if (err < ICESND_RESULT_OK) goto fail;
data->channels = info.channels;
}
return data;
fail:
free_ice(data);
return NULL;
}
void decode_ice(ice_codec_data* data, sample_t* outbuf, int32_t samples_to_do) {
int channels = data->channels;
while (samples_to_do > 0) {
int done = icesnd_decode(data->ctx, outbuf, samples_to_do);
if (done <= 0) goto decode_fail;
outbuf += done * channels;
samples_to_do -= done;
}
return;
decode_fail:
VGM_LOG("ICE: decode error\n");
memset(outbuf, 0, samples_to_do * channels * sizeof(sample_t));
}
void reset_ice(ice_codec_data* data) {
if (!data) return;
icesnd_reset(data->ctx, 0);
}
void seek_ice(ice_codec_data* data, int32_t num_sample) {
if (!data) return;
//todo discard (this should only be called when looping)
icesnd_reset(data->ctx, 1);
}
void free_ice(ice_codec_data* data) {
if (!data) return;
close_streamfile(data->sf);
icesnd_free(data->ctx);
free(data);
}
/* ************************* */
static int icelib_read(void* dst, int size, int n, void* arg) {
icelib_io_t* io = arg;
int bytes_read, items_read;
bytes_read = read_streamfile(dst, io->offset, size * n, io->sf);
items_read = bytes_read / size;
io->offset += bytes_read;
return items_read;
}
static int icelib_seek(void* arg, int offset, int whence) {
icelib_io_t* io = arg;
int base_offset, new_offset;
switch (whence) {
case ICESND_SEEK_SET:
base_offset = 0;
break;
case ICESND_SEEK_CUR:
base_offset = io->offset;
break;
case ICESND_SEEK_END:
base_offset = get_streamfile_size(io->sf);
break;
default:
return -1;
break;
}
new_offset = base_offset + offset;
if (new_offset < 0 /*|| new_offset > get_streamfile_size(config->sf)*/) {
return -1; /* unseekable */
}
else {
io->offset = new_offset;
return 0;
}
}
static void icelib_set_callbacks(icesnd_callback_t* cb, STREAMFILE* sf, icelib_io_t* io) {
io->offset = 0;
io->sf = sf;
cb->arg = io;
cb->read = icelib_read;
cb->seek = icelib_seek;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,67 @@
#ifndef _ICELIB_H_
#define _ICELIB_H_
#include <stdint.h>
/* Decodes Inti Creates's "ICE" engine BIGRP sounds. */
#define ICESND_CODEC_RANGE 0x00
#define ICESND_CODEC_DATA 0x01
#define ICESND_CODEC_MIDI 0x02
#define ICESND_CODEC_DCT 0x03
#define ICESND_RESULT_OK 0
#define ICESND_ERROR_HEADER -1
#define ICESND_ERROR_SETUP -2
#define ICESND_ERROR_DECODE -3
typedef struct icesnd_handle_t icesnd_handle_t;
#define ICESND_SEEK_SET 0
#define ICESND_SEEK_CUR 1
#define ICESND_SEEK_END 2
typedef struct {
/* whole file in memory (for testing) */
const uint8_t* filebuf;
int filebuf_size;
/* custom IO */
void* arg;
int (*read)(void* dst, int size, int n, void* arg);
int (*seek)(void* arg, int offset, int whence);
} icesnd_callback_t;
/* Inits ICE lib with config.
* Original code expects all data in memory, but this allows setting read callbacks
* (making it feed-style was a bit complex due to how data is laid out) */
icesnd_handle_t* icesnd_init(int target_subsong, icesnd_callback_t* cb);
void icesnd_free(icesnd_handle_t* handle);
/* resets the decoder. If loop_starts and file loops and
* (format is not seekable but separated into intro+body blocks) */
void icesnd_reset(icesnd_handle_t* handle, int loop_start);
/* Decodes up to samples for N channels into sbuf (interleaved). Returns samples done,
* 0 if not possible (non-looped files past end) or negative on error.
* May return less than wanted samples on block boundaries.
*
* It's designed to decode an arbitrary number of samples, as data isn't divided into frames (original
* player does sample_rate/60.0 at a time). Codec 0 is aligned to 100 samples and codec 3 to 16 though. */
int icesnd_decode(icesnd_handle_t* handle, int16_t* sbuf, int max_samples);
typedef struct {
int total_subsongs;
int codec;
int sample_rate;
int channels;
int loop_start;
int num_samples;
int loop_flag;
} icesnd_info_t;
/* loads info */
int icesnd_info(icesnd_handle_t* handle, icesnd_info_t* info);
#endif

View File

@ -17,8 +17,9 @@ static int build_header_identification(uint8_t* buf, size_t bufsize, int channel
static int build_header_comment(uint8_t* buf, size_t bufsize); static int build_header_comment(uint8_t* buf, size_t bufsize);
static int build_header_setup(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf); static int build_header_setup(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf);
static int load_fvs_file_single(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf); #if !(FSB_VORBIS_USE_PRECOMPILED_FVS)
static int load_fvs_file_multi(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf); static int load_fvs_file(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf);
#endif
static int load_fvs_array(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf); static int load_fvs_array(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf);
@ -58,7 +59,7 @@ int vorbis_custom_parse_packet_fsb(VGMSTREAMCHANNEL* stream, vorbis_custom_codec
size_t bytes; size_t bytes;
/* get next packet size from the FSB 16b header (doesn't count this 16b) */ /* get next packet size from the FSB 16b header (doesn't count this 16b) */
data->op.bytes = (uint16_t)read_16bitLE(stream->offset, stream->streamfile); data->op.bytes = read_u16le(stream->offset, stream->streamfile);
stream->offset += 2; stream->offset += 2;
if (data->op.bytes == 0 || data->op.bytes == 0xFFFF || data->op.bytes > data->buffer_size) goto fail; /* EOF or end padding */ if (data->op.bytes == 0 || data->op.bytes == 0xFFFF || data->op.bytes > data->buffer_size) goto fail; /* EOF or end padding */
@ -108,16 +109,16 @@ static int build_header_identification(uint8_t* buf, size_t bufsize, int channel
} }
blocksizes = (exp_blocksize_0 << 4) | (exp_blocksize_1); blocksizes = (exp_blocksize_0 << 4) | (exp_blocksize_1);
put_8bit (buf+0x00, 0x01); /* packet_type (id) */ put_u8 (buf+0x00, 0x01); /* packet_type (id) */
memcpy (buf+0x01, "vorbis", 6); /* id */ memcpy (buf+0x01, "vorbis", 6); /* id */
put_32bitLE(buf+0x07, 0x00); /* vorbis_version (fixed) */ put_u32le(buf+0x07, 0x00); /* vorbis_version (fixed) */
put_8bit (buf+0x0b, channels); /* audio_channels */ put_u8 (buf+0x0b, channels); /* audio_channels */
put_32bitLE(buf+0x0c, sample_rate); /* audio_sample_rate */ put_s32le(buf+0x0c, sample_rate); /* audio_sample_rate */
put_32bitLE(buf+0x10, 0x00); /* bitrate_maximum (optional hint) */ put_u32le(buf+0x10, 0x00); /* bitrate_maximum (optional hint) */
put_32bitLE(buf+0x14, 0x00); /* bitrate_nominal (optional hint) */ put_u32le(buf+0x14, 0x00); /* bitrate_nominal (optional hint) */
put_32bitLE(buf+0x18, 0x00); /* bitrate_minimum (optional hint) */ put_u32le(buf+0x18, 0x00); /* bitrate_minimum (optional hint) */
put_8bit (buf+0x1c, blocksizes); /* blocksize_0 + blocksize_1 nibbles */ put_u8 (buf+0x1c, blocksizes); /* blocksize_0 + blocksize_1 nibbles */
put_8bit (buf+0x1d, 0x01); /* framing_flag (fixed) */ put_u8 (buf+0x1d, 0x01); /* framing_flag (fixed) */
return bytes; return bytes;
} }
@ -127,12 +128,12 @@ static int build_header_comment(uint8_t* buf, size_t bufsize) {
if (bytes > bufsize) return 0; if (bytes > bufsize) return 0;
put_8bit (buf+0x00, 0x03); /* packet_type (comments) */ put_u8 (buf+0x00, 0x03); /* packet_type (comments) */
memcpy (buf+0x01, "vorbis", 6); /* id */ memcpy (buf+0x01, "vorbis", 6); /* id */
put_32bitLE(buf+0x07, 0x09); /* vendor_length */ put_u32le(buf+0x07, 0x09); /* vendor_length */
memcpy (buf+0x0b, "vgmstream", 9); /* vendor_string */ memcpy (buf+0x0b, "vgmstream", 9); /* vendor_string */
put_32bitLE(buf+0x14, 0x00); /* user_comment_list_length */ put_u32le(buf+0x14, 0x00); /* user_comment_list_length */
put_8bit (buf+0x18, 0x01); /* framing_flag (fixed) */ put_u8 (buf+0x18, 0x01); /* framing_flag (fixed) */
return bytes; return bytes;
} }
@ -145,49 +146,20 @@ static int build_header_setup(uint8_t* buf, size_t bufsize, uint32_t setup_id, S
if (bytes) if (bytes)
return bytes; return bytes;
#if !(FSB_VORBIS_USE_PRECOMPILED_FVS)
/* try to load from external files */ /* try to load from external files */
bytes = load_fvs_file_single(buf, bufsize, setup_id, sf); bytes = load_fvs_file(buf, bufsize, setup_id, sf);
if (bytes)
return bytes;
bytes = load_fvs_file_multi(buf, bufsize, setup_id, sf);
if (bytes) if (bytes)
return bytes; return bytes;
#endif
/* not found */ /* not found */
VGM_LOG("FSB Vorbis: setup_id %08x not found\n", setup_id); VGM_LOG("FSB Vorbis: setup_id %08x not found\n", setup_id);
return 0; return 0;
} }
static int load_fvs_file_single(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) { #if !(FSB_VORBIS_USE_PRECOMPILED_FVS)
STREAMFILE* sf_setup = NULL; static int load_fvs_file(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) {
/* get from artificial external file (used if compiled without codebooks) */
{
char setupname[0x20];
snprintf(setupname, sizeof(setupname), ".fvs_%08x", setup_id);
sf_setup = open_streamfile_by_filename(sf, setupname);
}
/* get codebook and copy to buffer */
if (sf_setup) {
size_t bytes = sf_setup->get_size(sf_setup);
if (bytes > bufsize) goto fail;
if (read_streamfile(buf, 0, bytes, sf_setup) != bytes)
goto fail;
close_streamfile(sf_setup);
return bytes;
}
fail:
close_streamfile(sf_setup);
return 0;
}
static int load_fvs_file_multi(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) {
STREAMFILE* sf_setup = NULL; STREAMFILE* sf_setup = NULL;
/* from to get from artificial external file (used if compiled without codebooks) */ /* from to get from artificial external file (used if compiled without codebooks) */
@ -230,6 +202,7 @@ fail:
if (sf_setup) sf_setup->close(sf_setup); if (sf_setup) sf_setup->close(sf_setup);
return 0; return 0;
} }
#endif
static int load_fvs_array(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) { static int load_fvs_array(uint8_t* buf, size_t bufsize, uint32_t setup_id, STREAMFILE* sf) {
#if FSB_VORBIS_USE_PRECOMPILED_FVS #if FSB_VORBIS_USE_PRECOMPILED_FVS

View File

@ -34,7 +34,9 @@ static int ww2ogg_generate_vorbis_packet(bitstream_t* ow, bitstream_t* iw, wpack
static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis_custom_codec_data* data, size_t packet_size, STREAMFILE* sf); static int ww2ogg_generate_vorbis_setup(bitstream_t* ow, bitstream_t* iw, vorbis_custom_codec_data* data, size_t packet_size, STREAMFILE* sf);
static int load_wvc(uint8_t* ibuf, size_t ibufsize, uint32_t codebook_id, wwise_setup_t setup_type, STREAMFILE* sf); static int load_wvc(uint8_t* ibuf, size_t ibufsize, uint32_t codebook_id, wwise_setup_t setup_type, STREAMFILE* sf);
#if !(WWISE_VORBIS_USE_PRECOMPILED_WVC)
static int load_wvc_file(uint8_t* buf, size_t bufsize, uint32_t codebook_id, STREAMFILE* sf); static int load_wvc_file(uint8_t* buf, size_t bufsize, uint32_t codebook_id, STREAMFILE* sf);
#endif
static int load_wvc_array(uint8_t* buf, size_t bufsize, uint32_t codebook_id, wwise_setup_t setup_type); static int load_wvc_array(uint8_t* buf, size_t bufsize, uint32_t codebook_id, wwise_setup_t setup_type);
@ -1133,16 +1135,19 @@ static int load_wvc(uint8_t* ibuf, size_t ibufsize, uint32_t codebook_id, wwise_
if (bytes) if (bytes)
return bytes; return bytes;
#if !(WWISE_VORBIS_USE_PRECOMPILED_WVC)
/* try to load from external file (ignoring type, just use file if found) */ /* try to load from external file (ignoring type, just use file if found) */
bytes = load_wvc_file(ibuf, ibufsize, codebook_id, sf); bytes = load_wvc_file(ibuf, ibufsize, codebook_id, sf);
if (bytes) if (bytes)
return bytes; return bytes;
#endif
/* not found */ /* not found */
VGM_LOG("Wwise Vorbis: codebook_id %04x not found\n", codebook_id); VGM_LOG("Wwise Vorbis: codebook_id %04x not found\n", codebook_id);
return 0; return 0;
} }
#if !(WWISE_VORBIS_USE_PRECOMPILED_WVC)
static int load_wvc_file(uint8_t* buf, size_t bufsize, uint32_t codebook_id, STREAMFILE* sf) { static int load_wvc_file(uint8_t* buf, size_t bufsize, uint32_t codebook_id, STREAMFILE* sf) {
STREAMFILE* sf_setup = NULL; STREAMFILE* sf_setup = NULL;
size_t wvc_size = 0; size_t wvc_size = 0;
@ -1185,6 +1190,7 @@ fail:
close_streamfile(sf_setup); close_streamfile(sf_setup);
return 0; return 0;
} }
#endif
static int load_wvc_array(uint8_t* buf, size_t bufsize, uint32_t codebook_id, wwise_setup_t setup_type) { static int load_wvc_array(uint8_t* buf, size_t bufsize, uint32_t codebook_id, wwise_setup_t setup_type) {
#if WWISE_VORBIS_USE_PRECOMPILED_WVC #if WWISE_VORBIS_USE_PRECOMPILED_WVC
@ -1217,7 +1223,7 @@ static int load_wvc_array(uint8_t* buf, size_t bufsize, uint32_t codebook_id, ww
} }
} }
// this can be used if the lists contained a 1:1 dump of the codebook files // this can be used with 1:1 dump of the codebook file
#if 0 #if 0
if (wvc == NULL) goto fail; if (wvc == NULL) goto fail;
/* find codebook and copy to buffer */ /* find codebook and copy to buffer */

View File

@ -39,6 +39,11 @@ void free_codec(VGMSTREAM* vgmstream) {
free_tac(vgmstream->codec_data); free_tac(vgmstream->codec_data);
} }
if (vgmstream->coding_type == coding_ICE_RANGE ||
vgmstream->coding_type == coding_ICE_DCT) {
free_ice(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_UBI_ADPCM) { if (vgmstream->coding_type == coding_UBI_ADPCM) {
free_ubi_adpcm(vgmstream->codec_data); free_ubi_adpcm(vgmstream->codec_data);
} }
@ -140,6 +145,11 @@ void seek_codec(VGMSTREAM* vgmstream) {
seek_tac(vgmstream->codec_data, vgmstream->loop_current_sample); seek_tac(vgmstream->codec_data, vgmstream->loop_current_sample);
} }
if (vgmstream->coding_type == coding_ICE_RANGE ||
vgmstream->coding_type == coding_ICE_DCT) {
seek_ice(vgmstream->codec_data, vgmstream->loop_current_sample);
}
if (vgmstream->coding_type == coding_UBI_ADPCM) { if (vgmstream->coding_type == coding_UBI_ADPCM) {
seek_ubi_adpcm(vgmstream->codec_data, vgmstream->loop_current_sample); seek_ubi_adpcm(vgmstream->codec_data, vgmstream->loop_current_sample);
} }
@ -246,6 +256,11 @@ void reset_codec(VGMSTREAM* vgmstream) {
reset_tac(vgmstream->codec_data); reset_tac(vgmstream->codec_data);
} }
if (vgmstream->coding_type == coding_ICE_RANGE ||
vgmstream->coding_type == coding_ICE_DCT) {
reset_ice(vgmstream->codec_data);
}
if (vgmstream->coding_type == coding_UBI_ADPCM) { if (vgmstream->coding_type == coding_UBI_ADPCM) {
reset_ubi_adpcm(vgmstream->codec_data); reset_ubi_adpcm(vgmstream->codec_data);
} }
@ -535,6 +550,9 @@ int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream) {
return 0; /* 1024 - delay/padding (which can be bigger than 1024) */ return 0; /* 1024 - delay/padding (which can be bigger than 1024) */
case coding_TAC: case coding_TAC:
return 0; /* 1024 - delay/padding */ return 0; /* 1024 - delay/padding */
case coding_ICE_RANGE:
case coding_ICE_DCT:
return 0; /* ~100 (range), ~16 (DCT) */
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
case coding_MP4_AAC: case coding_MP4_AAC:
return ((mp4_aac_codec_data*)vgmstream->codec_data)->samples_per_frame; return ((mp4_aac_codec_data*)vgmstream->codec_data)->samples_per_frame;
@ -1075,6 +1093,10 @@ void decode_vgmstream(VGMSTREAM* vgmstream, int samples_written, int samples_to_
case coding_TAC: case coding_TAC:
decode_tac(vgmstream, buffer, samples_to_do); decode_tac(vgmstream, buffer, samples_to_do);
break; break;
case coding_ICE_RANGE:
case coding_ICE_DCT:
decode_ice(vgmstream->codec_data, buffer, samples_to_do);
break;
#ifdef VGM_USE_FFMPEG #ifdef VGM_USE_FFMPEG
case coding_FFmpeg: case coding_FFmpeg:
decode_ffmpeg(vgmstream, buffer, samples_to_do, vgmstream->channels); decode_ffmpeg(vgmstream, buffer, samples_to_do, vgmstream->channels);

View File

@ -105,6 +105,7 @@ static const char* extension_list[] = {
"bgm", "bgm",
"bgw", "bgw",
"bh2pcm", "bh2pcm",
"bigrp",
"bik", "bik",
"bika", //fake extension for .bik (to be removed) "bika", //fake extension for .bik (to be removed)
"bik2", "bik2",
@ -130,7 +131,7 @@ static const char* extension_list[] = {
"caf", "caf",
"cbd2", "cbd2",
"ccc", "ccc", //fake extension (to be removed)
"cd", "cd",
"cfn", //fake extension for CAF (renamed, to be removed?) "cfn", //fake extension for CAF (renamed, to be removed?)
"chd", //txth/reserved [Donkey Konga (GC), Star Fox Assault (GC)] "chd", //txth/reserved [Donkey Konga (GC), Star Fox Assault (GC)]
@ -861,6 +862,8 @@ static const coding_info coding_info_list[] = {
{coding_RELIC, "Relic Codec"}, {coding_RELIC, "Relic Codec"},
{coding_CRI_HCA, "CRI HCA"}, {coding_CRI_HCA, "CRI HCA"},
{coding_TAC, "tri-Ace Codec"}, {coding_TAC, "tri-Ace Codec"},
{coding_ICE_RANGE, "Inti Creates Range Codec"},
{coding_ICE_DCT, "Inti Creates DCT Codec"},
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
{coding_OGG_VORBIS, "Ogg Vorbis"}, {coding_OGG_VORBIS, "Ogg Vorbis"},
@ -1415,6 +1418,7 @@ static const meta_info meta_info_list[] = {
{meta_TT_AD, "Traveller's Tales AUDIO_DATA header"}, {meta_TT_AD, "Traveller's Tales AUDIO_DATA header"},
{meta_SNDZ, "Sony SNDZ header"}, {meta_SNDZ, "Sony SNDZ header"},
{meta_VAB, "Sony VAB header"}, {meta_VAB, "Sony VAB header"},
{meta_BIGRP, "Inti Creates .BIGRP header"},
}; };
void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) { void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) {

View File

@ -83,6 +83,7 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="coding\hca_decoder_clhca.h" /> <ClInclude Include="coding\hca_decoder_clhca.h" />
<ClInclude Include="coding\ice_decoder_icelib.h" />
<ClInclude Include="coding\mpeg_bitreader.h" /> <ClInclude Include="coding\mpeg_bitreader.h" />
<ClInclude Include="coding\mpeg_decoder.h" /> <ClInclude Include="coding\mpeg_decoder.h" />
<ClInclude Include="coding\vorbis_bitreader.h" /> <ClInclude Include="coding\vorbis_bitreader.h" />
@ -328,6 +329,7 @@
<ClCompile Include="meta\baf.c" /> <ClCompile Include="meta\baf.c" />
<ClCompile Include="meta\bgw.c" /> <ClCompile Include="meta\bgw.c" />
<ClCompile Include="meta\bik.c" /> <ClCompile Include="meta\bik.c" />
<ClCompile Include="meta\bigrp.c" />
<ClCompile Include="meta\bkhd.c" /> <ClCompile Include="meta\bkhd.c" />
<ClCompile Include="meta\bmp_konami.c" /> <ClCompile Include="meta\bmp_konami.c" />
<ClCompile Include="meta\bnk_relic.c" /> <ClCompile Include="meta\bnk_relic.c" />
@ -643,6 +645,8 @@
<ClCompile Include="coding\g7221_decoder_lib.c" /> <ClCompile Include="coding\g7221_decoder_lib.c" />
<ClCompile Include="coding\hca_decoder.c" /> <ClCompile Include="coding\hca_decoder.c" />
<ClCompile Include="coding\hca_decoder_clhca.c" /> <ClCompile Include="coding\hca_decoder_clhca.c" />
<ClCompile Include="coding\ice_decoder.c" />
<ClCompile Include="coding\ice_decoder_icelib.c" />
<ClCompile Include="coding\ima_decoder.c" /> <ClCompile Include="coding\ima_decoder.c" />
<ClCompile Include="coding\imuse_decoder.c" /> <ClCompile Include="coding\imuse_decoder.c" />
<ClCompile Include="coding\l5_555_decoder.c" /> <ClCompile Include="coding\l5_555_decoder.c" />

View File

@ -266,6 +266,9 @@
<ClInclude Include="coding\hca_decoder_clhca.h"> <ClInclude Include="coding\hca_decoder_clhca.h">
<Filter>coding\Header Files</Filter> <Filter>coding\Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="coding\hca_decoder_icelib.h">
<Filter>coding\Header Files</Filter>
</ClInclude>
<ClInclude Include="coding\mpeg_bitreader.h"> <ClInclude Include="coding\mpeg_bitreader.h">
<Filter>coding\Header Files</Filter> <Filter>coding\Header Files</Filter>
</ClInclude> </ClInclude>
@ -1369,6 +1372,12 @@
<ClCompile Include="coding\hca_decoder_clhca.c"> <ClCompile Include="coding\hca_decoder_clhca.c">
<Filter>coding\Source Files</Filter> <Filter>coding\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="coding\ice_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\ice_decoder_icelib.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\ima_decoder.c"> <ClCompile Include="coding\ima_decoder.c">
<Filter>coding\Source Files</Filter> <Filter>coding\Source Files</Filter>
</ClCompile> </ClCompile>
@ -1879,6 +1888,9 @@
<ClCompile Include="meta\bik.c"> <ClCompile Include="meta\bik.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="meta\bigrp.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\bkhd.c"> <ClCompile Include="meta\bkhd.c">
<Filter>meta\Source Files</Filter> <Filter>meta\Source Files</Filter>
</ClCompile> </ClCompile>

View File

@ -138,10 +138,8 @@ VGMSTREAM* init_vgmstream_akb(STREAMFILE* sf) {
/* enable encryption */ /* enable encryption */
if (version >= 3 && (flags & 8)) { if (version >= 3 && (flags & 8)) {
VGM_LOG("temp1\n");
temp_sf = setup_sqex_streamfile(sf, start_offset, stream_size, 1, 0x00, 0x00, "ogg"); temp_sf = setup_sqex_streamfile(sf, start_offset, stream_size, 1, 0x00, 0x00, "ogg");
if (!temp_sf) goto fail; if (!temp_sf) goto fail;
VGM_LOG("temp2\n");
ogg_vgmstream = init_vgmstream_ogg_vorbis_config(temp_sf, 0x00, &ovmi); ogg_vgmstream = init_vgmstream_ogg_vorbis_config(temp_sf, 0x00, &ovmi);
close_streamfile(temp_sf); close_streamfile(temp_sf);

View File

@ -78,7 +78,7 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
subfile_size = subfile_next - subfile_offset; subfile_size = subfile_next - subfile_offset;
} }
;VGM_LOG("awb: subfile offset=%x + %x\n", subfile_offset, subfile_size); //;VGM_LOG("awb: subfile offset=%x + %x\n", subfile_offset, subfile_size);
/* autodetect as there isn't anything, plus can mix types /* autodetect as there isn't anything, plus can mix types
* (waveid<>codec info is usually in the companion .acb) */ * (waveid<>codec info is usually in the companion .acb) */

110
src/meta/bigrp.c Normal file
View File

@ -0,0 +1,110 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../coding/ice_decoder_icelib.h"
/* .BIGRP - from Inti Creates "ICE"/"Imperial" engine [Blaster Master Zero 2 (SW), Gunvolt 3 (SW)] */
VGMSTREAM* init_vgmstream_bigrp(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
uint32_t header_size, entry_size, stream_size;
int total_subsongs, target_subsong = sf->stream_index;
int codec, channels, loop_flag, sample_rate;
int32_t loop_start, num_samples;
/* checks */
/* simple checks to avoid opening the lib if possible
* early games use smaller sizes [Bloodstained COTM (Vita), Mighty Gunvolt Burst (PC)] */
header_size = read_u32le(0x00,sf);
if (read_u32le(0x00,sf) != 0x0c && read_u32le(0x00,sf) != 0x10)
goto fail;
entry_size = read_u32le(0x04,sf);
if (entry_size != 0x34 && entry_size != 0x40)
goto fail;
if (!check_extensions(sf, "bigrp"))
goto fail;
if (target_subsong == 0) target_subsong = 1;
total_subsongs = read_s32le(0x08,sf);
if (target_subsong > total_subsongs || total_subsongs <= 0) goto fail;
/* could read all this from the lib, meh */
{
uint32_t offset = header_size + entry_size * (target_subsong - 1);
/* 00: hash */
/* 04: group? */
codec = read_u32le(offset + 0x08, sf);
switch(codec) {
case 0x00: /* range [BMZ2 (SW), Bloodstained COTM (Vita), BMZ1 (PS4)] */
case 0x03:
sample_rate = read_s32le(offset + 0x0c, sf);
channels = read_u8 (offset + 0x10, sf);
/* 0x11: spf */
/* 0x12: unknown (volume?) */
loop_flag = read_u32le(offset + 0x14, sf);
/* 0x18: frame codes */
loop_start = read_s32le(offset + 0x1c, sf);
stream_size = read_u32le(offset + 0x20, sf); /* intro block */
/* 0x24: intro offset */
num_samples = read_s32le(offset + 0x28, sf) + loop_start;
stream_size = read_u32le(offset + 0x2c, sf) + stream_size; /* body block */
/* 0x30: body offset */
break;
default:
/* dummy to avoid breaking some files that mix codecs with midi */
channels = 1;
sample_rate = 48000;
loop_flag = 0;
loop_start = 0;
num_samples = sample_rate;
stream_size = 0;
break;
}
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_BIGRP;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = num_samples;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
switch(codec) {
case 0x00:
case 0x03:
vgmstream->codec_data = init_ice(sf, target_subsong);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = codec == 0x00 ? coding_ICE_RANGE : coding_ICE_DCT;
vgmstream->layout_type = layout_none;
break;
case 0x01:
case 0x02:
vgmstream->coding_type = coding_SILENCE;
snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "[%s]", (codec == 0x01 ? "data" : "midi"));
break;
default:
goto fail;
}
//if (!vgmstream_open_stream(vgmstream, sf, 0x00))
// goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -991,4 +991,6 @@ VGMSTREAM* init_vgmstream_sndz(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_vab(STREAMFILE* sf); VGMSTREAM* init_vgmstream_vab(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_bigrp(STREAMFILE* sf);
#endif /*_META_H*/ #endif /*_META_H*/

View File

@ -33,10 +33,10 @@ VGMSTREAM * init_vgmstream_ps2_ccc(STREAMFILE *streamFile) {
vgmstream->channels = channel_count; vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x04,streamFile); vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
vgmstream->coding_type = coding_PSX; vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = (read_32bitLE(0x08,streamFile))/channel_count/32*28; vgmstream->num_samples = (read_32bitLE(0x08,streamFile))/channel_count/0x10*28;
if (loop_flag) { if (loop_flag) {
vgmstream->loop_start_sample = 0; vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = (read_32bitLE(0x08,streamFile))/channel_count/32*28; vgmstream->loop_end_sample = (read_32bitLE(0x08,streamFile))/channel_count/0x10*28;
} }
vgmstream->layout_type = layout_interleave; vgmstream->layout_type = layout_interleave;

View File

@ -1,5 +1,6 @@
#include "meta.h" #include "meta.h"
#include "../coding/coding.h" #include "../coding/coding.h"
#include "../util/endianness.h"
#include "sqex_streamfile.h" #include "sqex_streamfile.h"
@ -20,65 +21,67 @@ typedef struct {
int sample_rate; int sample_rate;
int loop_start; int loop_start;
int loop_end; int loop_end;
off_t mtrl_offset; uint32_t mtrl_offset;
off_t extradata_offset; uint32_t extradata_offset;
size_t extradata_size; uint32_t extradata_size;
size_t stream_size; uint32_t stream_size;
uint16_t extradata_id; uint16_t extradata_id;
off_t filename_offset; uint32_t filename_offset;
size_t filename_size; uint32_t filename_size;
off_t muscname_offset; uint32_t muscname_offset;
size_t muscname_size; uint32_t muscname_size;
off_t sectname_offset; uint32_t sectname_offset;
size_t sectname_size; uint32_t sectname_size;
off_t modename_offset; uint32_t modename_offset;
size_t modename_size; uint32_t modename_size;
off_t instname_offset; uint32_t instname_offset;
size_t instname_size; uint32_t instname_size;
off_t sndname_offset; //uint32_t sndname_offset;
size_t sndname_size; //uint32_t sndname_size;
off_t sections_offset; uint32_t sections_offset;
off_t snd_section_offset; uint32_t snd_section_offset;
off_t seq_section_offset; uint32_t seq_section_offset;
off_t trk_section_offset; uint32_t trk_section_offset;
off_t musc_section_offset; uint32_t musc_section_offset;
off_t inst_section_offset; uint32_t inst_section_offset;
off_t mtrl_section_offset; uint32_t mtrl_section_offset;
char readable_name[STREAM_NAME_SIZE]; char readable_name[STREAM_NAME_SIZE];
} sead_header; } sead_header_t;
static int parse_sead(sead_header *sead, STREAMFILE *sf); static int parse_sead(sead_header_t* sead, STREAMFILE* sf);
/* SABF/MABF - Square Enix's "sead" audio games [Dragon Quest Builders (PS3), Dissidia Opera Omnia (mobile), FF XV (PS4)] */ /* SABF/MABF - Square Enix's "sead" audio games [Dragon Quest Builders (PS3), Dissidia Opera Omnia (mobile), FF XV (PS4)] */
VGMSTREAM* init_vgmstream_sqex_sead(STREAMFILE* sf) { VGMSTREAM* init_vgmstream_sqex_sead(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
sead_header sead = {0}; sead_header_t sead = {0};
off_t start_offset; off_t start_offset;
int target_subsong = sf->stream_index; int target_subsong = sf->stream_index;
uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL; read_u32_t read_u32 = NULL;
uint16_t (*read_u16)(off_t,STREAMFILE*) = NULL; read_u16_t read_u16 = NULL;
/* checks */ /* checks */
if (is_id32be(0x00, sf, "sabf")) {
sead.is_sab = 1;
}
else if (is_id32be(0x00, sf, "mabf")) {
sead.is_mab = 1;
}
else {
goto fail;
}
/* .sab: sound/bgm /* .sab: sound/bgm
* .mab: music * .mab: music
* .sbin: Dissidia Opera Omnia .sab */ * .sbin: Dissidia Opera Omnia .sab */
if (!check_extensions(sf,"sab,mab,sbin")) if (!check_extensions(sf,"sab,mab,sbin"))
goto fail; goto fail;
if (read_u32be(0x00, sf) == 0x73616266) { /* "sabf" */
sead.is_sab = 1;
} else if (read_u32be(0x00, sf) == 0x6D616266) { /* "mabf" */
sead.is_mab = 1;
} else {
goto fail;
}
/* SEAD handles both sab/mab in the same lib (libsead), and other similar files (config, engine, etc). /* SEAD handles both sab/mab in the same lib (libsead), and other similar files (config, engine, etc).
* Has some chunks pointing to sections, and each section entry (usually starting with section * Has some chunks pointing to sections, and each section entry (usually starting with section
* version/reserved/size) is always padded to 0x10. Most values are unsigned. * version/reserved/size) is always padded to 0x10. Most values are unsigned.
@ -89,7 +92,7 @@ VGMSTREAM* init_vgmstream_sqex_sead(STREAMFILE* sf) {
* or is a separate audio lib derived from this "SEAD Engine". */ * or is a separate audio lib derived from this "SEAD Engine". */
sead.big_endian = guess_endianness16bit(0x06, sf); /* no flag, use size */ sead.big_endian = guess_endian16(0x06, sf); /* no flag, use size */
if (sead.big_endian) { if (sead.big_endian) {
read_u32 = read_u32be; read_u32 = read_u32be;
read_u16 = read_u16be; read_u16 = read_u16be;
@ -115,6 +118,14 @@ VGMSTREAM* init_vgmstream_sqex_sead(STREAMFILE* sf) {
strcpy(vgmstream->stream_name, sead.readable_name); strcpy(vgmstream->stream_name, sead.readable_name);
switch(sead.codec) { switch(sead.codec) {
case 0x00: /* NONE */
vgmstream->coding_type = coding_SILENCE;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = sead.sample_rate;
start_offset = 0;
break;
case 0x01: { /* PCM [Chrono Trigger (PC) sfx] */ case 0x01: { /* PCM [Chrono Trigger (PC) sfx] */
start_offset = sead.extradata_offset + sead.extradata_size; start_offset = sead.extradata_offset + sead.extradata_size;
@ -299,11 +310,10 @@ VGMSTREAM* init_vgmstream_sqex_sead(STREAMFILE* sf) {
} }
} }
case 0x00: /* NONE / dummy entry */
case 0x05: /* XMA2 (extradata may be a XMA2 fmt extra chunk) */ case 0x05: /* XMA2 (extradata may be a XMA2 fmt extra chunk) */
case 0x08: /* SWITCHOPUS (no extradata?) */ case 0x08: /* SWITCHOPUS (no extradata?) */
default: default:
VGM_LOG("SQEX SEAD: unknown codec %x\n", sead.codec); vgm_logi("SQEX SEAD: unknown codec %x\n", sead.codec);
goto fail; goto fail;
} }
@ -319,23 +329,47 @@ fail:
return NULL; return NULL;
} }
//todo safeops, avoid recalc lens
static void sead_cat(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);
}
static void build_readable_name(char * buf, size_t buf_size, sead_header *sead, STREAMFILE *sf) { static void build_readable_sab_name(sead_header_t* sead, STREAMFILE* sf, uint32_t sndname_offset, uint32_t sndname_size) {
char * buf = sead->readable_name;
if (sead->is_sab) { int buf_size = sizeof(sead->readable_name);
char descriptor[255], name[255]; char descriptor[255], name[255];
if (sead->filename_size > 255 || sead->sndname_size > 255) goto fail; if (sead->filename_size > 255 || sndname_size > 255)
goto fail;
if (buf[0] == '\0') { /* init */
read_string(descriptor,sead->filename_size+1, sead->filename_offset, sf); read_string(descriptor,sead->filename_size+1, sead->filename_offset, sf);
read_string(name,sead->sndname_size+1,sead->sndname_offset, sf); read_string(name, sndname_size+1, sndname_offset, sf);
snprintf(buf,buf_size, "%s/%s", descriptor, name); snprintf(buf,buf_size, "%s/%s", descriptor, name);
} }
else { else { /* add */
read_string(name, sndname_size+1, sndname_offset, sf);
sead_cat(buf, buf_size, "; ");
sead_cat(buf, buf_size, name);
}
return;
fail:
VGM_LOG("SEAD: bad sab name found\n");
}
static void build_readable_mab_name(sead_header_t* sead, STREAMFILE* sf) {
char * buf = sead->readable_name;
int buf_size = sizeof(sead->readable_name);
char descriptor[255], name[255], mode[255]; char descriptor[255], name[255], mode[255];
if (sead->filename_size > 255 || sead->muscname_size > 255 || sead->sectname_size > 255 || sead->modename_size > 255) goto fail; if (sead->filename_size > 255 || sead->muscname_size > 255 || sead->sectname_size > 255 || sead->modename_size > 255)
goto fail;
read_string(descriptor,sead->filename_size+1,sead->filename_offset, sf); read_string(descriptor,sead->filename_size+1,sead->filename_offset, sf);
//read_string(filename,sead->muscname_size+1,sead->muscname_offset, sf); /* same as filename, not too interesting */ //read_string(filename,sead->muscname_size+1,sead->muscname_offset, sf); /* same as filename, not too interesting */
@ -353,20 +387,18 @@ static void build_readable_name(char * buf, size_t buf_size, sead_header *sead,
snprintf(buf,buf_size, "%s/%s", descriptor, name); snprintf(buf,buf_size, "%s/%s", descriptor, name);
else else
snprintf(buf,buf_size, "%s/%s/%s", descriptor, name, mode); snprintf(buf,buf_size, "%s/%s/%s", descriptor, name, mode);
}
return; return;
fail: fail:
VGM_LOG("SEAD: bad name found\n"); VGM_LOG("SEAD: bad mab name found\n");
} }
static void parse_sead_mab_name(sead_header *sead, STREAMFILE *sf) { static void parse_sead_mab_name(sead_header_t* sead, STREAMFILE* sf) {
uint32_t (*read_u32)(off_t,STREAMFILE*) = sead->big_endian ? read_u32be : read_u32le; read_u32_t read_u32 = sead->big_endian ? read_u32be : read_u32le;
uint16_t (*read_u16)(off_t,STREAMFILE*) = sead->big_endian ? read_u16be : read_u16le; read_u16_t read_u16 = sead->big_endian ? read_u16be : read_u16le;
int i, j, k, entries; int i, j, k, entries;
off_t target_muscname_offset = 0, target_sectname_offset = 0; uint32_t target_muscname_offset = 0, target_sectname_offset = 0;
size_t target_muscname_size = 0, target_sectname_size = 0; uint32_t target_muscname_size = 0, target_sectname_size = 0;
/* find names referencing to our material stream, usually: /* find names referencing to our material stream, usually:
* - music > sections > layers (<> meters) > material index * - music > sections > layers (<> meters) > material index
@ -608,9 +640,9 @@ static void parse_sead_mab_name(sead_header *sead, STREAMFILE *sf) {
} }
} }
static void parse_sead_sab_name(sead_header *sead, STREAMFILE *sf) { static void parse_sead_sab_name(sead_header_t* sead, STREAMFILE* sf) {
uint32_t (*read_u32)(off_t,STREAMFILE*) = sead->big_endian ? read_u32be : read_u32le; read_u32_t read_u32 = sead->big_endian ? read_u32be : read_u32le;
uint16_t (*read_u16)(off_t,STREAMFILE*) = sead->big_endian ? read_u16be : read_u16le; read_u16_t read_u16 = sead->big_endian ? read_u16be : read_u16le;
int i, j, entries; int i, j, entries;
/* find names referencing to our material stream, usually: /* find names referencing to our material stream, usually:
@ -627,9 +659,9 @@ static void parse_sead_sab_name(sead_header *sead, STREAMFILE *sf) {
/* parse sounds */ /* parse sounds */
entries = read_u16(sead->snd_section_offset + 0x04, sf); entries = read_u16(sead->snd_section_offset + 0x04, sf);
for (i = 0; i < entries; i++) { for (i = 0; i < entries; i++) {
off_t snd_offset = sead->snd_section_offset + read_u32(sead->snd_section_offset + 0x10 + i*0x04, sf); uint32_t snd_offset = sead->snd_section_offset + read_u32(sead->snd_section_offset + 0x10 + i*0x04, sf);
size_t snd_size, sndname_size; uint32_t snd_size, sndname_size;
off_t seqi_start, seqi_offset, sndname_offset; uint32_t seqi_start, seqi_offset, sndname_offset;
int snd_version, seqi_count; int snd_version, seqi_count;
snd_version = read_u8(snd_offset + 0x00, sf); snd_version = read_u8(snd_offset + 0x00, sf);
@ -677,8 +709,8 @@ static void parse_sead_sab_name(sead_header *sead, STREAMFILE *sf) {
/* parse sequence */ /* parse sequence */
{ {
off_t seq_offset = sead->seq_section_offset + read_u32(sead->seq_section_offset + 0x10 + seq_index*0x04, sf); uint32_t seq_offset = sead->seq_section_offset + read_u32(sead->seq_section_offset + 0x10 + seq_index*0x04, sf);
off_t cmnd_start, cmnd_offset; uint32_t cmnd_start, cmnd_offset;
int seq_version; int seq_version;
seq_version = read_u8(seq_offset + 0x00, sf); seq_version = read_u8(seq_offset + 0x00, sf);
@ -724,7 +756,7 @@ static void parse_sead_sab_name(sead_header *sead, STREAMFILE *sf) {
/* parse track */ /* parse track */
{ {
off_t trk_offset = sead->trk_section_offset + read_u32(sead->trk_section_offset + 0x10 + trk_index*0x04, sf); uint32_t trk_offset = sead->trk_section_offset + read_u32(sead->trk_section_offset + 0x10 + trk_index*0x04, sf);
uint8_t trk_type; uint8_t trk_type;
uint16_t mtrl_index; uint16_t mtrl_index;
@ -743,8 +775,9 @@ static void parse_sead_sab_name(sead_header *sead, STREAMFILE *sf) {
/* assumes same bank, not sure if bank info is even inside .sab */ /* assumes same bank, not sure if bank info is even inside .sab */
if (mtrl_index == sead->mtrl_index) { if (mtrl_index == sead->mtrl_index) {
sead->sndname_offset = sndname_offset; build_readable_sab_name(sead, sf, sndname_offset, sndname_size);
sead->sndname_size = sndname_size; //sead->sndname_offset = sndname_offset;
//sead->sndname_size = sndname_size;
} }
} }
else if (trk_type == 0x02) { else if (trk_type == 0x02) {
@ -760,8 +793,10 @@ static void parse_sead_sab_name(sead_header *sead, STREAMFILE *sf) {
/* commands normally end when a type 0=none is found */ /* commands normally end when a type 0=none is found */
if (cmnd_type <= 0x00 || cmnd_type > 0x08) if (cmnd_type <= 0x00 || cmnd_type > 0x08)
break; break;
if (sead->sndname_offset > 0)
break; /* keep reading names as N sounds may point to current material */
//if (sead->sndname_offset > 0)
// break;
} }
} }
@ -770,9 +805,9 @@ static void parse_sead_sab_name(sead_header *sead, STREAMFILE *sf) {
} }
static int parse_sead(sead_header* sead, STREAMFILE* sf) { static int parse_sead(sead_header_t* sead, STREAMFILE* sf) {
uint32_t (*read_u32)(off_t,STREAMFILE*) = sead->big_endian ? read_u32be : read_u32le; read_u32_t read_u32 = sead->big_endian ? read_u32be : read_u32le;
uint16_t (*read_u16)(off_t,STREAMFILE*) = sead->big_endian ? read_u16be : read_u16le; read_u16_t read_u16 = sead->big_endian ? read_u16be : read_u16le;
/** base header **/ /** base header **/
/* 0x00: id */ /* 0x00: id */
@ -849,9 +884,9 @@ static int parse_sead(sead_header* sead, STREAMFILE* sf) {
for (i = 0; i < entries; i++) { for (i = 0; i < entries; i++) {
off_t entry_offset = sead->mtrl_section_offset + read_u32(sead->mtrl_section_offset + 0x10 + i*0x04, sf); off_t entry_offset = sead->mtrl_section_offset + read_u32(sead->mtrl_section_offset + 0x10 + i*0x04, sf);
if (read_u8(entry_offset + 0x05, sf) == 0) { //if (read_u8(entry_offset + 0x05, sf) == 0) {
continue; /* codec 0 when dummy (see stream header) */ // continue; /* codec 0 when dummy (see stream header) */
} //}
sead->total_subsongs++; sead->total_subsongs++;
if (!sead->mtrl_offset && sead->total_subsongs == sead->target_subsong) { if (!sead->mtrl_offset && sead->total_subsongs == sead->target_subsong) {
@ -882,17 +917,24 @@ static int parse_sead(sead_header* sead, STREAMFILE* sf) {
sead->extradata_id = read_u16(sead->mtrl_offset + 0x1c, sf); sead->extradata_id = read_u16(sead->mtrl_offset + 0x1c, sf);
/* 0x1e: reserved */ /* 0x1e: reserved */
if (sead->codec == 0x00) {
/* dummy entries have null fields, put defaults to allow playing them */
sead->channels = 1;
sead->sample_rate = 48000;
}
sead->loop_flag = (sead->loop_end > 0); sead->loop_flag = (sead->loop_end > 0);
sead->extradata_offset = sead->mtrl_offset + 0x20; sead->extradata_offset = sead->mtrl_offset + 0x20;
if (sead->is_sab) { if (sead->is_sab) {
parse_sead_sab_name(sead, sf); parse_sead_sab_name(sead, sf);
/* sab name is added during process */
} }
else if (sead->is_mab) { else if (sead->is_mab) {
parse_sead_mab_name(sead, sf); parse_sead_mab_name(sead, sf);
build_readable_mab_name(sead, sf);
} }
build_readable_name(sead->readable_name, sizeof(sead->readable_name), sead, sf);
return 1; return 1;
fail: fail:

View File

@ -406,7 +406,6 @@ int vgmstream_tags_next_tag(VGMSTREAM_TAGS* tags, STREAMFILE* tagfile) {
} }
else if (strncasecmp(tags->key, "EXACTMATCH", key_len) == 0) { else if (strncasecmp(tags->key, "EXACTMATCH", key_len) == 0) {
tags->exact_match = 1; tags->exact_match = 1;
VGM_LOG("exact\n");
} }
continue; /* not an actual tag */ continue; /* not an actual tag */

View File

@ -129,7 +129,6 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_idsp_ie, init_vgmstream_idsp_ie,
init_vgmstream_ngc_ymf, init_vgmstream_ngc_ymf,
init_vgmstream_sadl, init_vgmstream_sadl,
init_vgmstream_ps2_ccc,
init_vgmstream_fag, init_vgmstream_fag,
init_vgmstream_ps2_mihb, init_vgmstream_ps2_mihb,
init_vgmstream_ngc_pdt_split, init_vgmstream_ngc_pdt_split,
@ -526,6 +525,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_bw_riff_mp3, init_vgmstream_bw_riff_mp3,
init_vgmstream_sndz, init_vgmstream_sndz,
init_vgmstream_vab, init_vgmstream_vab,
init_vgmstream_bigrp,
/* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */ /* lower priority metas (no clean header identity, somewhat ambiguous, or need extension/companion file to identify) */
init_vgmstream_agsc, init_vgmstream_agsc,
@ -555,6 +555,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_ngc_ulw, /* .ulw raw u-Law */ init_vgmstream_ngc_ulw, /* .ulw raw u-Law */
init_vgmstream_exakt_sc, /* .sc raw PCM */ init_vgmstream_exakt_sc, /* .sc raw PCM */
init_vgmstream_zwdsp, /* fake format */ init_vgmstream_zwdsp, /* fake format */
init_vgmstream_ps2_ccc, /* fake format, to be removed */
init_vgmstream_ps2_adm, /* weird non-constant PSX blocks */ init_vgmstream_ps2_adm, /* weird non-constant PSX blocks */
init_vgmstream_baf_badrip, /* crap, to be removed */ init_vgmstream_baf_badrip, /* crap, to be removed */
init_vgmstream_rxws_badrip, /* crap, to be removed */ init_vgmstream_rxws_badrip, /* crap, to be removed */

View File

@ -7,7 +7,10 @@
/* reasonable limits */ /* reasonable limits */
enum { enum {
PATH_LIMIT = 32768, /* Windows generally only allows 260 chars in path, but other OSs have higher limits, and we handle
* UTF-8 (that typically uses 2-bytes for common non-latin codepages) plus player may append protocols
* to paths, so it should be a bit higher. Most people wouldn't use huge paths though. */
PATH_LIMIT = 4096, /* (256 * 8) * 2 = ~max_path * (other_os+extra) * codepage_bytes */
STREAM_NAME_SIZE = 255, STREAM_NAME_SIZE = 255,
VGMSTREAM_MAX_CHANNELS = 64, VGMSTREAM_MAX_CHANNELS = 64,
VGMSTREAM_MIN_SAMPLE_RATE = 300, /* 300 is Wwise min */ VGMSTREAM_MIN_SAMPLE_RATE = 300, /* 300 is Wwise min */
@ -182,6 +185,8 @@ typedef enum {
coding_RELIC, /* Relic Codec (DCT-based) */ coding_RELIC, /* Relic Codec (DCT-based) */
coding_CRI_HCA, /* CRI High Compression Audio (MDCT-based) */ coding_CRI_HCA, /* CRI High Compression Audio (MDCT-based) */
coding_TAC, /* tri-Ace Codec (MDCT-based) */ coding_TAC, /* tri-Ace Codec (MDCT-based) */
coding_ICE_RANGE, /* Inti Creates "range" codec */
coding_ICE_DCT, /* Inti Creates "DCT" codec */
#ifdef VGM_USE_VORBIS #ifdef VGM_USE_VORBIS
coding_OGG_VORBIS, /* Xiph Vorbis with Ogg layer (MDCT-based) */ coding_OGG_VORBIS, /* Xiph Vorbis with Ogg layer (MDCT-based) */
@ -762,6 +767,7 @@ typedef enum {
meta_TT_AD, meta_TT_AD,
meta_SNDZ, meta_SNDZ,
meta_VAB, meta_VAB,
meta_BIGRP,
} meta_t; } meta_t;