misc issues and cleanup

This commit is contained in:
bnnm 2021-09-15 23:22:17 +02:00
parent bdd641d218
commit 7bb2434b56
5 changed files with 99 additions and 128 deletions

View File

@ -463,7 +463,7 @@ You can also choose which channels to play using *TXTP*. For example, create
a file named `song.adx#C1,2.txtp` to play only channels 1 and 2 from `song.adx`. a file named `song.adx#C1,2.txtp` to play only channels 1 and 2 from `song.adx`.
*TXTP* also has command to set how files are downmixed. *TXTP* also has command to set how files are downmixed.
### 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
codec, `.hca/awb` with missing decryption key, bank has no audio, `.txth` is codec, `.hca/awb` with missing decryption key, bank has no audio, `.txth` is

View File

@ -456,7 +456,7 @@ static size_t make_oggs_page(uint8_t* buf, int buf_size, size_t data_size, int p
} }
segment_count = (int)(data_size / 0xFF + 1); segment_count = (int)(data_size / 0xFF + 1);
put_u32be(buf+0x00, 0x4F676753); /* capture pattern ("OggS") */ put_u32be(buf+0x00, get_id32be("OggS")); /* capture pattern */
put_u8 (buf+0x04, 0); /* stream structure version, fixed */ put_u8 (buf+0x04, 0); /* stream structure version, fixed */
put_u8 (buf+0x05, header_type_flag); /* bitflags (0: normal, continued = 1, first = 2, last = 4) */ put_u8 (buf+0x05, header_type_flag); /* bitflags (0: normal, continued = 1, first = 2, last = 4) */
put_u32le(buf+0x06, (uint32_t)(absolute_granule >> 0 & 0xFFFFFFFF)); /* lower */ put_u32le(buf+0x06, (uint32_t)(absolute_granule >> 0 & 0xFFFFFFFF)); /* lower */
@ -517,8 +517,8 @@ static size_t make_opus_header(uint8_t* buf, int buf_size, opus_config *cfg) {
goto fail; goto fail;
} }
put_u32be(buf+0x00, 0x4F707573); /* "Opus" header magic */ put_u32be(buf+0x00, get_id32be("Opus"));
put_u32be(buf+0x04, 0x48656164); /* "Head" header magic */ put_u32be(buf+0x04, get_id32be("Head"));
put_u8 (buf+0x08, 1); /* version */ put_u8 (buf+0x08, 1); /* version */
put_u8 (buf+0x09, cfg->channels); put_u8 (buf+0x09, cfg->channels);
put_s16le(buf+0x0A, cfg->skip); put_s16le(buf+0x0A, cfg->skip);
@ -575,19 +575,23 @@ fail:
static size_t make_oggs_first(uint8_t* buf, int buf_size, opus_config* cfg) { static size_t make_oggs_first(uint8_t* buf, int buf_size, opus_config* cfg) {
int buf_done = 0; int buf_done = 0;
size_t bytes; size_t bytes;
size_t page_size = 0x1c; /* fixed for header page */
if (buf_size < 0x100) /* approx */ if (buf_size < 0x100) /* approx */
goto fail; goto fail;
/* make header */ /* make header (first data, then page for checksum) */
bytes = make_opus_header(buf+buf_done + 0x1c,buf_size, cfg); bytes = make_opus_header(buf + page_size, buf_size - page_size, cfg);
make_oggs_page(buf+buf_done + 0x00,buf_size, bytes, 0, 0); make_oggs_page(buf, buf_size, bytes, 0, 0);
buf_done += 0x1c + bytes; buf_done += (page_size + bytes);
buf += buf_done;
buf_size -= buf_done;
/* make comment */ /* make comment */
bytes = make_opus_comment(buf+buf_done + 0x1c,buf_size); bytes = make_opus_comment(buf + page_size, buf_size - page_size);
make_oggs_page(buf+buf_done + 0x00,buf_size, bytes, 1, 0); make_oggs_page(buf, buf_size, bytes, 1, 0);
buf_done += 0x1c + bytes; buf_done += (page_size + bytes);
return buf_done; return buf_done;
fail: fail:

View File

@ -177,9 +177,6 @@ int setup_layout_segmented(segmented_layout_data* data) {
for (i = 0; i < data->segment_count; i++) { for (i = 0; i < data->segment_count; i++) {
int segment_input_channels, segment_output_channels; int segment_input_channels, segment_output_channels;
/* allow config if set for fine-tuned parts (usually TXTP only) */
data->segments[i]->config_enabled = data->segments[i]->config.config_set;
if (data->segments[i] == NULL) { if (data->segments[i] == NULL) {
VGM_LOG("SEGMENTED: no vgmstream in segment %i\n", i); VGM_LOG("SEGMENTED: no vgmstream in segment %i\n", i);
goto fail; goto fail;
@ -190,6 +187,9 @@ int setup_layout_segmented(segmented_layout_data* data) {
goto fail; goto fail;
} }
/* allow config if set for fine-tuned parts (usually TXTP only) */
data->segments[i]->config_enabled = data->segments[i]->config.config_set;
/* disable so that looping is controlled by render_vgmstream_segmented */ /* disable so that looping is controlled by render_vgmstream_segmented */
if (data->segments[i]->loop_flag != 0) { if (data->segments[i]->loop_flag != 0) {
VGM_LOG("SEGMENTED: segment %i is looped\n", i); VGM_LOG("SEGMENTED: segment %i is looped\n", i);

View File

@ -1,7 +1,7 @@
#include "meta.h" #include "meta.h"
#include "../coding/coding.h" #include "../coding/coding.h"
typedef enum { ADX, HCA, VAG, RIFF, CWAV, DSP, CWAC, M4A } awb_type; //typedef enum { ADX, HCA, VAG, RIFF, CWAV, DSP, CWAC, M4A } awb_type_t;
static void load_awb_name(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstream, int waveid); static void load_awb_name(STREAMFILE* sf, STREAMFILE* sf_acb, VGMSTREAM* vgmstream, int waveid);
@ -13,26 +13,21 @@ VGMSTREAM* init_vgmstream_awb(STREAMFILE* sf) {
VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) { VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL; STREAMFILE* temp_sf = NULL;
off_t offset, subfile_offset, subfile_next; uint32_t offset, subfile_offset, subfile_next, subfile_size;
size_t subfile_size;
int total_subsongs, target_subsong = sf->stream_index; int total_subsongs, target_subsong = sf->stream_index;
//uint32_t flags;
uint8_t offset_size; uint8_t offset_size;
uint16_t alignment, subkey; uint16_t alignment, subkey;
awb_type type;
const char* extension = NULL;
int waveid; int waveid;
/* checks /* checks */
* .awb: standard if (!is_id32be(0x00,sf, "AFS2"))
goto fail;
/* .awb: standard
* .afs2: sometimes [Okami HD (PS4)] */ * .afs2: sometimes [Okami HD (PS4)] */
if (!check_extensions(sf, "awb,afs2")) if (!check_extensions(sf, "awb,afs2"))
goto fail; goto fail;
if (read_u32be(0x00,sf) != 0x41465332) /* "AFS2" */
goto fail;
//flags = read_32bitLE(0x08,sf);
/* 0x04(1): version? 0x01=common, 0x02=2018+ (no apparent differences) */ /* 0x04(1): version? 0x01=common, 0x02=2018+ (no apparent differences) */
offset_size = read_u8(0x05,sf); offset_size = read_u8(0x05,sf);
/* 0x06(2): always 0x0002? */ /* 0x06(2): always 0x0002? */
@ -45,9 +40,9 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
offset = 0x10; offset = 0x10;
/* id(?) table: read target */ /* id table: read target */
{ {
off_t waveid_offset = offset + (target_subsong-1) * 0x02; uint32_t waveid_offset = offset + (target_subsong-1) * 0x02;
waveid = read_u16le(waveid_offset,sf); waveid = read_u16le(waveid_offset,sf);
@ -56,7 +51,7 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
/* offset table: find target */ /* offset table: find target */
{ {
off_t file_size = get_streamfile_size(sf); uint32_t file_size = get_streamfile_size(sf);
/* last sub-offset is always file end, so table entries = total_subsongs+1 */ /* last sub-offset is always file end, so table entries = total_subsongs+1 */
offset += (target_subsong-1) * offset_size; offset += (target_subsong-1) * offset_size;
@ -71,7 +66,7 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
subfile_next = read_u16le(offset+0x02,sf); subfile_next = read_u16le(offset+0x02,sf);
break; break;
default: default:
VGM_LOG("AWB: unknown offset size\n"); vgm_logi("AWB: unknown offset size (report)\n");
goto fail; goto fail;
} }
@ -83,50 +78,55 @@ 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=%lx + %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) */
if (read_u16be(subfile_offset, sf) == 0x8000) { /* ADX id (type 0) */ {
type = ADX; VGMSTREAM* (*init_vgmstream)(STREAMFILE* sf) = NULL;
VGMSTREAM* (*init_vgmstream_subkey)(STREAMFILE* sf, uint16_t subkey) = NULL;
const char* extension = NULL;
if (read_u16be(subfile_offset, sf) == 0x8000) { /* (type 0=ADX) */
init_vgmstream_subkey = init_vgmstream_adx_subkey; /* Okami HD (PS4) */
extension = "adx"; extension = "adx";
} }
else if ((read_u32be(subfile_offset,sf) & 0x7f7f7f7f) == 0x48434100) { /* "HCA\0" (type 2=HCA, 6=HCA-MX) */ else if ((read_u32be(subfile_offset,sf) & 0x7f7f7f7f) == get_id32be("HCA\0")) { /* (type 2=HCA, 6=HCA-MX) */
type = HCA; init_vgmstream_subkey = init_vgmstream_hca_subkey; /* most common */
extension = "hca"; extension = "hca";
} }
else if (read_u32be(subfile_offset,sf) == 0x56414770) { /* "VAGp" (type 7=VAG, 10=HEVAG) */ else if (is_id32be(subfile_offset,sf, "VAGp") == 0x56414770) { /* (type 7=VAG, 10=HEVAG) */
type = VAG; init_vgmstream = init_vgmstream_vag; /* Ukiyo no Roushi (Vita) */
extension = "vag"; extension = "vag";
} }
else if (read_u32be(subfile_offset,sf) == 0x52494646) { /* "RIFF" (type 8=ATRAC3, 11=ATRAC9) */ else if (is_id32be(subfile_offset,sf, "RIFF")) { /* (type 8=ATRAC3, 11=ATRAC9) */
type = RIFF; init_vgmstream = init_vgmstream_riff; /* Ukiyo no Roushi (Vita) */
extension = "wav"; extension = "wav";
subfile_size = read_u32le(subfile_offset + 0x04,sf) + 0x08; /* rough size, use RIFF's */ subfile_size = read_u32le(subfile_offset + 0x04,sf) + 0x08; /* padded size, use RIFF's */
} }
else if (read_u32be(subfile_offset,sf) == 0x43574156) { /* "CWAV" (type 9) */ else if (is_id32be(subfile_offset,sf, "CWAV")) { /* (type 9=CWAV) */
type = CWAV; init_vgmstream = init_vgmstream_rwsd; /* Sonic: Lost World (3DS) */
extension = "bcwav"; extension = "bcwav";
} }
else if (read_u32be(subfile_offset + 0x08,sf) >= 8000 && else if (read_u32be(subfile_offset + 0x08,sf) >= 8000 && read_u32be(subfile_offset + 0x08,sf) <= 48000 &&
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) { /* probably should call some check function (type 13) */ read_u32be(subfile_offset + 0x50,sf) == 0) { /* (type 13=DSP), probably should call some check function */
type = DSP; init_vgmstream = init_vgmstream_ngc_dsp_std; /* Sonic: Lost World (WiiU) */
extension = "dsp"; extension = "dsp";
} }
else if (is_id32be(subfile_offset,sf, "CWAC")) { /* type 13 again */ else if (is_id32be(subfile_offset,sf, "CWAC")) { /* (type 13=DSP, again) */
type = CWAC; init_vgmstream = init_vgmstream_dsp_cwac; /* Mario & Sonic at the Rio 2016 Olympic Games (WiiU) */
extension = "dsp"; extension = "dsp";
} }
else if (read_u32be(subfile_offset+0x00,sf) == 0x00000018 && #ifdef VGM_USE_FFMPEG
read_u32be(subfile_offset+0x04,sf) == 0x66747970) { /* chunk size + "ftyp" (type 19) */ else if (read_u32be(subfile_offset+0x00,sf) == 0x00000018 && is_id32be(subfile_offset+0x04,sf, "ftyp")) { /* (type 19=M4A) */
type = M4A; init_vgmstream = init_vgmstream_mp4_aac_ffmpeg; /* Imperial SaGa Eclipse (Browser) */
extension = "m4a"; extension = "m4a";
} }
#endif
else { else {
VGM_LOG("AWB: unknown codec\n"); vgm_logi("AWB: unknown codec (report)\n");
goto fail; goto fail;
} }
@ -134,46 +134,14 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
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;
switch(type) { if (init_vgmstream_subkey)
case HCA: /* most common */ vgmstream = init_vgmstream_subkey(temp_sf, subkey);
vgmstream = init_vgmstream_hca_subkey(temp_sf, subkey); else
vgmstream = init_vgmstream(temp_sf);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
break;
case ADX: /* Okami HD (PS4) */
vgmstream = init_vgmstream_adx_subkey(temp_sf, subkey);
if (!vgmstream) goto fail;
break;
case VAG: /* Ukiyo no Roushi (Vita) */
vgmstream = init_vgmstream_vag(temp_sf);
if (!vgmstream) goto fail;
break;
case RIFF: /* Ukiyo no Roushi (Vita) */
vgmstream = init_vgmstream_riff(temp_sf);
if (!vgmstream) goto fail;
break;
case CWAV: /* Sonic: Lost World (3DS) */
vgmstream = init_vgmstream_rwsd(temp_sf);
if (!vgmstream) goto fail;
break;
case DSP: /* Sonic: Lost World (WiiU) */
vgmstream = init_vgmstream_ngc_dsp_std(temp_sf);
if (!vgmstream) goto fail;
break;
case CWAC: /* Mario & Sonic at the Rio 2016 Olympic Games (WiiU) */
vgmstream = init_vgmstream_dsp_cwac(temp_sf);
if (!vgmstream) goto fail;
break;
#ifdef VGM_USE_FFMPEG
case M4A: /* Imperial SaGa Eclipse (Browser) */
vgmstream = init_vgmstream_mp4_aac_ffmpeg(temp_sf);
if (!vgmstream) goto fail;
break;
#endif
default:
goto fail;
}
vgmstream->num_streams = total_subsongs; vgmstream->num_streams = total_subsongs;
}
/* try to load cue names */ /* try to load cue names */
load_awb_name(sf, sf_acb, vgmstream, waveid); load_awb_name(sf, sf_acb, vgmstream, waveid);

View File

@ -19,15 +19,15 @@ typedef struct {
int32_t num_samples; int32_t num_samples;
int32_t loop_start; int32_t loop_start;
int loop_flag; int loop_flag;
off_t extra_offset; uint32_t extra_offset;
uint32_t channel_layout; uint32_t channel_layout;
int is_external; int is_external;
uint32_t stream_offsets[MAX_CHANNELS]; uint32_t stream_offsets[MAX_CHANNELS];
uint32_t stream_sizes[MAX_CHANNELS]; uint32_t stream_sizes[MAX_CHANNELS];
off_t sound_name_offset; uint32_t sound_name_offset;
off_t config_name_offset; uint32_t config_name_offset;
char name[255+1]; char name[255+1];
} ktsr_header; } ktsr_header;
@ -266,12 +266,12 @@ static int parse_codec(ktsr_header* ktsr) {
return 1; return 1;
fail: fail:
VGM_LOG("KTSR: unknown codec combo: ext=%x, fmt=%x, ptf=%x\n", ktsr->is_external, ktsr->format, ktsr->platform); VGM_LOG("ktsr: unknown codec combo: ext=%x, fmt=%x, ptf=%x\n", ktsr->is_external, ktsr->format, ktsr->platform);
return 0; return 0;
} }
static int parse_ktsr_subfile(ktsr_header* ktsr, STREAMFILE* sf, off_t offset) { static int parse_ktsr_subfile(ktsr_header* ktsr, STREAMFILE* sf, uint32_t offset) {
off_t suboffset, starts_offset, sizes_offset; uint32_t suboffset, starts_offset, sizes_offset;
int i; int i;
uint32_t type; uint32_t type;
@ -318,7 +318,7 @@ static int parse_ktsr_subfile(ktsr_header* ktsr, STREAMFILE* sf, off_t offset) {
ktsr->is_external = 1; ktsr->is_external = 1;
if (ktsr->format != 0x05) { if (ktsr->format != 0x05) {
VGM_LOG("KTSR: unknown subcodec at %lx\n", offset); VGM_LOG("ktsr: unknown subcodec at %x\n", offset);
goto fail; goto fail;
} }
@ -362,7 +362,7 @@ static int parse_ktsr_subfile(ktsr_header* ktsr, STREAMFILE* sf, off_t offset) {
suboffset = offset + 0x30; suboffset = offset + 0x30;
if (ktsr->channels > MAX_CHANNELS) { if (ktsr->channels > MAX_CHANNELS) {
VGM_LOG("KTSR: max channels found\n"); VGM_LOG("ktsr: max channels found\n");
goto fail; goto fail;
} }
@ -379,7 +379,7 @@ static int parse_ktsr_subfile(ktsr_header* ktsr, STREAMFILE* sf, off_t offset) {
default: default:
/* streams also have their own chunks like 0x09D4F415, not needed here */ /* streams also have their own chunks like 0x09D4F415, not needed here */
VGM_LOG("KTSR: unknown subheader at %lx\n", offset); VGM_LOG("ktsr: unknown subheader at %x\n", offset);
goto fail; goto fail;
} }
@ -388,7 +388,7 @@ static int parse_ktsr_subfile(ktsr_header* ktsr, STREAMFILE* sf, off_t offset) {
return 1; return 1;
fail: fail:
VGM_LOG("KTSR: error parsing subheader\n"); VGM_LOG("ktsr: error parsing subheader\n");
return 0; return 0;
} }
@ -419,7 +419,7 @@ static void build_name(ktsr_header* ktsr, STREAMFILE* sf) {
static void parse_longname(ktsr_header* ktsr, STREAMFILE* sf, uint32_t target_id) { static void parse_longname(ktsr_header* ktsr, STREAMFILE* sf, uint32_t target_id) {
/* more configs than sounds is possible so we need target_id first */ /* more configs than sounds is possible so we need target_id first */
off_t offset, end, name_offset; uint32_t offset, end, name_offset;
uint32_t stream_id; uint32_t stream_id;
offset = 0x40; offset = 0x40;
@ -447,7 +447,7 @@ static void parse_longname(ktsr_header* ktsr, STREAMFILE* sf, uint32_t target_id
} }
static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf) { static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf) {
off_t offset, end, header_offset, name_offset; uint32_t offset, end, header_offset, name_offset;
uint32_t stream_id = 0, stream_count; uint32_t stream_id = 0, stream_count;
/* 00: KTSR /* 00: KTSR
@ -486,7 +486,6 @@ static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf) {
break; break;
case 0xC5CCCB70: /* sound (internal data or external stream) */ case 0xC5CCCB70: /* sound (internal data or external stream) */
//VGM_LOG("info at %lx\n", offset);
ktsr->total_subsongs++; ktsr->total_subsongs++;
/* sound table: /* sound table:
@ -503,13 +502,12 @@ static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf) {
if (ktsr->total_subsongs == ktsr->target_subsong) { if (ktsr->total_subsongs == ktsr->target_subsong) {
//;VGM_LOG("KTSR: target at %lx\n", offset);
stream_id = read_u32be(offset + 0x08,sf); stream_id = read_u32be(offset + 0x08,sf);
//ktsr->is_external = read_u16le(offset + 0x0e,sf); //ktsr->is_external = read_u16le(offset + 0x0e,sf);
stream_count = read_u32le(offset + 0x10,sf); stream_count = read_u32le(offset + 0x10,sf);
if (stream_count != 1) { if (stream_count != 1) {
VGM_LOG("KTSR: unknown stream count\n"); VGM_LOG("ktsr: unknown stream count\n");
goto fail; goto fail;
} }
@ -527,7 +525,7 @@ static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf) {
default: default:
/* streams also have their own chunks like 0x09D4F415, not needed here */ /* streams also have their own chunks like 0x09D4F415, not needed here */
VGM_LOG("KTSR: unknown chunk at %lx\n", offset); VGM_LOG("ktsr: unknown chunk at %x\n", offset);
goto fail; goto fail;
} }
@ -542,5 +540,6 @@ static int parse_ktsr(ktsr_header* ktsr, STREAMFILE* sf) {
return 1; return 1;
fail: fail:
vgm_logi("KTSR: unknown variation (report)\n");
return 0; return 0;
} }