mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 16:30:54 +01:00
Add .wav.sli [Perfect Cherry Blossom Trial+ (PC)]
This commit is contained in:
parent
7e25cd6a54
commit
da8da91321
@ -1280,8 +1280,6 @@ static const meta_info meta_info_list[] = {
|
|||||||
{meta_PC_FLX, "Ultima IX .FLX header"},
|
{meta_PC_FLX, "Ultima IX .FLX header"},
|
||||||
{meta_MOGG, "Harmonix Music Systems MOGG Vorbis"},
|
{meta_MOGG, "Harmonix Music Systems MOGG Vorbis"},
|
||||||
{meta_OGG_VORBIS, "Ogg Vorbis header"},
|
{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_SFL, "Ogg Vorbis header (SFPL looping)"},
|
||||||
{meta_OGG_KOVS, "Ogg Vorbis header (KOVS)"},
|
{meta_OGG_KOVS, "Ogg Vorbis header (KOVS)"},
|
||||||
{meta_OGG_encrypted, "Ogg Vorbis header (encrypted)"},
|
{meta_OGG_encrypted, "Ogg Vorbis header (encrypted)"},
|
||||||
|
@ -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);
|
VGMSTREAM * init_vgmstream_mp4_aac_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE * streamFile);
|
VGMSTREAM* init_vgmstream_sli_loops(STREAMFILE* sf);
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_sfl_ogg(STREAMFILE * streamFile);
|
VGMSTREAM * init_vgmstream_sfl_ogg(STREAMFILE * streamFile);
|
||||||
|
|
||||||
|
172
src/meta/sli.c
172
src/meta/sli.c
@ -1,105 +1,53 @@
|
|||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include <ctype.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)] */
|
/* .sli+ogg/opus/wav - KiriKiri engine / WaveLoopManager loop points loader [Fate/Stay Night (PC), World End Economica (PC)] */
|
||||||
VGMSTREAM* init_vgmstream_sli_ogg(STREAMFILE* sf) {
|
VGMSTREAM* init_vgmstream_sli_loops(STREAMFILE* sf) {
|
||||||
VGMSTREAM* vgmstream = NULL;
|
VGMSTREAM* vgmstream = NULL;
|
||||||
STREAMFILE* sf_data = NULL;
|
STREAMFILE* sf_data = NULL;
|
||||||
int32_t loop_start = -1, loop_length = -1;
|
int32_t loop_start = 0, loop_end = 0;
|
||||||
int32_t loop_from = -1, loop_to = -1;
|
VGMSTREAM* (*init_vgmstream)(STREAMFILE* sf) = NULL;
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
if (!check_extensions(sf, "sli"))
|
if (!check_extensions(sf, "sli"))
|
||||||
goto fail;
|
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];
|
char basename[PATH_LIMIT];
|
||||||
get_streamfile_basename(sf,basename,PATH_LIMIT);
|
get_streamfile_basename(sf,basename,PATH_LIMIT);
|
||||||
sf_data = open_streamfile_by_filename(sf, basename);
|
sf_data = open_streamfile_by_filename(sf, basename);
|
||||||
if (!sf_data) goto fail;
|
if (!sf_data) goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_id32be(0x00, sf_data, "OggS"))
|
if (is_id32be(0x00, sf_data, "OggS")) {
|
||||||
goto fail;
|
if (is_id32be(0x1c, sf_data, "Opus")) { /* Sabbat of the Witch (PC) */
|
||||||
|
init_vgmstream = init_vgmstream_ogg_opus;
|
||||||
/* let the real initer do the parsing */
|
/* somehow sli+opus use 0 encoder delay in the OpusHead (to simplify looping?) */
|
||||||
if (is_id32be(0x1c, sf_data, "Opus")) { /* Sabbat of the Witch (PC) */
|
}
|
||||||
vgmstream = init_vgmstream_ogg_opus(sf_data);
|
else { /* Fate/Stay Night (PC) */
|
||||||
if (!vgmstream) goto fail;
|
init_vgmstream = init_vgmstream_ogg_vorbis;
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (is_id32be(0x00, sf_data, "RIFF")) {
|
||||||
if (loop_start != -1 && loop_length != -1) { /* v1 */
|
/* Perfect Cherry Blossom Trial+ (PC) (RIFF created by extractor?) */
|
||||||
vgmstream_force_loop(vgmstream, 1, loop_start, loop_start + loop_length);
|
init_vgmstream = init_vgmstream_riff;
|
||||||
}
|
|
||||||
else if (loop_from != -1 && loop_to != -1) { /* v2 */
|
|
||||||
vgmstream_force_loop(vgmstream, 1, loop_to, loop_from);
|
|
||||||
}
|
}
|
||||||
else {
|
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);
|
close_streamfile(sf_data);
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
@ -108,3 +56,71 @@ fail:
|
|||||||
close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
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;
|
||||||
|
}
|
||||||
|
@ -537,7 +537,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
|
|||||||
init_vgmstream_mic_koei,
|
init_vgmstream_mic_koei,
|
||||||
init_vgmstream_seb,
|
init_vgmstream_seb,
|
||||||
init_vgmstream_ps2_pnb,
|
init_vgmstream_ps2_pnb,
|
||||||
init_vgmstream_sli_ogg,
|
init_vgmstream_sli_loops,
|
||||||
init_vgmstream_tgc,
|
init_vgmstream_tgc,
|
||||||
|
|
||||||
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
|
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
|
||||||
|
Loading…
Reference in New Issue
Block a user