Merge pull request #1351 from bnnm/sli-thp

- Add .wav.sli [Perfect Cherry Blossom Trial+ (PC)]
- Fix sound in mono .thp
This commit is contained in:
bnnm 2023-04-29 23:00:16 +02:00 committed by GitHub
commit e6883cbd34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 103 additions and 88 deletions

View File

@ -78,7 +78,7 @@ def get_txtp_name(args, file):
txtp_name = os.path.splitext(os.path.basename(file))[0]
else:
txtp_name = os.path.splitext(os.path.basename(args.files))[0]
txtp_name = os.path.splitext(os.path.basename(file))[0]
txtp_name = txtp_name.replace('*', '')
txtp_name = txtp_name.replace('?', '')

View File

@ -1280,8 +1280,6 @@ static const meta_info meta_info_list[] = {
{meta_PC_FLX, "Ultima IX .FLX header"},
{meta_MOGG, "Harmonix Music Systems MOGG Vorbis"},
{meta_OGG_VORBIS, "Ogg Vorbis header"},
{meta_OGG_SLI, "Ogg Vorbis header (.sli looping)"},
{meta_OPUS_SLI, "Ogg Opus header (.sli looping)"},
{meta_OGG_SFL, "Ogg Vorbis header (SFPL looping)"},
{meta_OGG_KOVS, "Ogg Vorbis header (KOVS)"},
{meta_OGG_encrypted, "Ogg Vorbis header (encrypted)"},

View File

@ -8,15 +8,15 @@ void block_update_thp(off_t block_offset, VGMSTREAM* vgmstream) {
off_t audio_offset;
size_t next_block_size, video_size;
next_block_size = read_u32be(block_offset + 0x00, sf);
/* 0x04: frame size previous */
next_block_size = read_u32be(block_offset + 0x00, sf); /* block may have padding, so need to save for next time */
/* 0x04: previous frame size */
video_size = read_u32be(block_offset + 0x08,sf);
/* 0x0c: audio size */
audio_offset = block_offset + 0x10 + video_size;
vgmstream->current_block_offset = block_offset;
vgmstream->next_block_offset = block_offset + vgmstream->full_block_size;
vgmstream->next_block_offset = block_offset + vgmstream->full_block_size; /* use prev saved data */
vgmstream->full_block_size = next_block_size;
/* block samples can be smaller than block size, normally in the last block,
@ -27,9 +27,10 @@ void block_update_thp(off_t block_offset, VGMSTREAM* vgmstream) {
audio_offset += 0x08;
for (i = 0; i < vgmstream->channels; i++) {
/* always size of 2 channels even in mono [WarioWare Inc. (GC)] */
off_t coef_offset = audio_offset + i*0x20;
off_t hist_offset = audio_offset + vgmstream->channels*0x20 + i*0x04;
off_t data_offset = audio_offset + 2*0x24 + i*vgmstream->current_block_size; /* reserved for 2 even in mono [WarioWare Inc. (GC)] */
off_t hist_offset = audio_offset + 2*0x20 + i*0x04;
off_t data_offset = audio_offset + 2*0x24 + i*vgmstream->current_block_size;
for (j = 0; j < 16; j++) {
vgmstream->ch[i].adpcm_coef[j] = read_s16be(coef_offset + (j*0x02),sf);

View File

@ -160,7 +160,7 @@ VGMSTREAM * init_vgmstream_mp4_aac(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_mp4_aac_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size);
#endif
VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE * streamFile);
VGMSTREAM* init_vgmstream_sli_loops(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_sfl_ogg(STREAMFILE * streamFile);

View File

@ -1,105 +1,53 @@
#include "meta.h"
#include <ctype.h>
#include <stdbool.h>
static bool get_loops(STREAMFILE* sf, int32_t* p_loop_start, int32_t* p_loop_end);
/* .sli+ogg/opus - KiriKiri engine / WaveLoopManager loop points loader [Fate/Stay Night (PC), World End Economica (PC)] */
VGMSTREAM* init_vgmstream_sli_ogg(STREAMFILE* sf) {
/* .sli+ogg/opus/wav - KiriKiri engine / WaveLoopManager loop points loader [Fate/Stay Night (PC), World End Economica (PC)] */
VGMSTREAM* init_vgmstream_sli_loops(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* sf_data = NULL;
int32_t loop_start = -1, loop_length = -1;
int32_t loop_from = -1, loop_to = -1;
int32_t loop_start = 0, loop_end = 0;
VGMSTREAM* (*init_vgmstream)(STREAMFILE* sf) = NULL;
/* checks */
if (!check_extensions(sf, "sli"))
goto fail;
{
/* try with file.ogg/opus.sli=header and file.ogg/opus=data */
/* try with file.ogg/opus/wav.sli=header and file.ogg/opus/wav=data */
char basename[PATH_LIMIT];
get_streamfile_basename(sf,basename,PATH_LIMIT);
sf_data = open_streamfile_by_filename(sf, basename);
if (!sf_data) goto fail;
}
if (!is_id32be(0x00, sf_data, "OggS"))
goto fail;
/* let the real initer do the parsing */
if (is_id32be(0x1c, sf_data, "Opus")) { /* Sabbat of the Witch (PC) */
vgmstream = init_vgmstream_ogg_opus(sf_data);
if (!vgmstream) goto fail;
/* somehow sli+opus use 0 encoder delay in the OpusHead (to simplify looping?) */
vgmstream->meta_type = meta_OPUS_SLI;
}
else { /* Fate/Stay Night (PC) */
vgmstream = init_vgmstream_ogg_vorbis(sf_data);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_OGG_SLI;
}
/* find loop text */
{
char line[PATH_LIMIT];
size_t bytes_read;
off_t sli_offset;
int line_ok;
sli_offset = 0;
while ((loop_start == -1 || loop_length == -1) && sli_offset < get_streamfile_size(sf)) {
char *endptr, *foundptr;
bytes_read = read_line(line, sizeof(line), sli_offset, sf, &line_ok);
if (!line_ok) goto fail;
sli_offset += bytes_read;
/* files may be padded with 0s */
/* comments in v2.0 [Sabbath of the Witch (PC), KARAKARA (PC)] */
if (line[0] == '#')
continue;
if (memcmp("LoopStart=", line,10) == 0 && line[10] != '\0') {
loop_start = strtol(line + 10, &endptr, 10);
if (*endptr != '\0') {
loop_start = -1; /* if it didn't parse cleanly */
}
}
else if (memcmp("LoopLength=", line, 11) == 0 && line[11] != '\0') {
loop_length = strtol(line + 11, &endptr, 10);
if (*endptr != '\0') {
loop_length = -1; /* if it didn't parse cleanly */
}
}
/* a completely different format ("#2.00"?), can be handled similarly */
if ((foundptr = strstr(line,"To=")) != NULL && isdigit(foundptr[3])) {
loop_to = strtol(foundptr + 3, &endptr, 10);
if (*endptr != ';') {
loop_to = -1;
}
}
if ((foundptr = strstr(line,"From=")) != NULL && isdigit(foundptr[5])) {
loop_from = strtol(foundptr + 5, &endptr, 10);
if (*endptr != ';') {
loop_from = -1;
}
}
if (is_id32be(0x00, sf_data, "OggS")) {
if (is_id32be(0x1c, sf_data, "Opus")) { /* Sabbat of the Witch (PC) */
init_vgmstream = init_vgmstream_ogg_opus;
/* somehow sli+opus use 0 encoder delay in the OpusHead (to simplify looping?) */
}
else { /* Fate/Stay Night (PC) */
init_vgmstream = init_vgmstream_ogg_vorbis;
}
}
if (loop_start != -1 && loop_length != -1) { /* v1 */
vgmstream_force_loop(vgmstream, 1, loop_start, loop_start + loop_length);
}
else if (loop_from != -1 && loop_to != -1) { /* v2 */
vgmstream_force_loop(vgmstream, 1, loop_to, loop_from);
else if (is_id32be(0x00, sf_data, "RIFF")) {
/* Perfect Cherry Blossom Trial+ (PC) (RIFF created by extractor?) */
init_vgmstream = init_vgmstream_riff;
}
else {
goto fail; /* if there's no loop points the .sli wasn't valid */
goto fail;
}
vgmstream = init_vgmstream(sf_data);
if (!vgmstream) goto fail;
if (!get_loops(sf, &loop_start, &loop_end))
goto fail;
vgmstream_force_loop(vgmstream, 1, loop_start, loop_end);
close_streamfile(sf_data);
return vgmstream;
@ -108,3 +56,71 @@ fail:
close_vgmstream(vgmstream);
return NULL;
}
static bool get_loops(STREAMFILE* sf, int32_t* p_loop_start, int32_t* p_loop_end) {
int32_t loop_start = -1, loop_length = -1;
int32_t loop_from = -1, loop_to = -1;
char line[PATH_LIMIT];
size_t bytes_read;
off_t sli_offset;
int line_ok;
sli_offset = 0;
while ((loop_start == -1 || loop_length == -1) && sli_offset < get_streamfile_size(sf)) {
char *endptr, *foundptr;
bytes_read = read_line(line, sizeof(line), sli_offset, sf, &line_ok);
if (!line_ok) goto fail;
sli_offset += bytes_read;
/* files may be padded with 0s */
/* comments in v2.0 [Sabbath of the Witch (PC), KARAKARA (PC)] */
if (line[0] == '#')
continue;
if (memcmp("LoopStart=", line,10) == 0 && line[10] != '\0') {
loop_start = strtol(line + 10, &endptr, 10);
if (*endptr != '\0') {
loop_start = -1; /* if it didn't parse cleanly */
}
}
else if (memcmp("LoopLength=", line, 11) == 0 && line[11] != '\0') {
loop_length = strtol(line + 11, &endptr, 10);
if (*endptr != '\0') {
loop_length = -1; /* if it didn't parse cleanly */
}
}
/* a completely different format ("#2.00"?), can be handled similarly */
if ((foundptr = strstr(line,"To=")) != NULL && isdigit(foundptr[3])) {
loop_to = strtol(foundptr + 3, &endptr, 10);
if (*endptr != ';') {
loop_to = -1;
}
}
if ((foundptr = strstr(line,"From=")) != NULL && isdigit(foundptr[5])) {
loop_from = strtol(foundptr + 5, &endptr, 10);
if (*endptr != ';') {
loop_from = -1;
}
}
}
if (loop_start != -1 && loop_length != -1) { /* v1 */
*p_loop_start = loop_start;
*p_loop_end = loop_start + loop_length;
}
else if (loop_from != -1 && loop_to != -1) { /* v2 */
*p_loop_start = loop_to;
*p_loop_end = loop_from;
}
else {
goto fail; /* if there's no loop points the .sli wasn't valid */
}
return true;
fail:
return false;
}

View File

@ -537,7 +537,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_mic_koei,
init_vgmstream_seb,
init_vgmstream_ps2_pnb,
init_vgmstream_sli_ogg,
init_vgmstream_sli_loops,
init_vgmstream_tgc,
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */