Merge pull request #477 from bnnm/dirs-fsb-opusnx

dirs fsb opusnx
This commit is contained in:
bnnm 2019-09-24 01:08:18 +02:00 committed by GitHub
commit d8fce9de7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 128 additions and 38 deletions

View File

@ -483,6 +483,7 @@ static const char* extension_list[] = {
"va3",
"vag",
"vai",
"vam", //txth/reserved [Rocket Power: Beach Bandits (PS2)]
"vas",
"vawx",
"vb",

View File

@ -148,6 +148,7 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
fsb.loop_start = read_32bitLE(header_offset+0x38,streamFile);
fsb.loop_end = read_32bitLE(header_offset+0x3c,streamFile);
VGM_ASSERT(fsb.loop_end > fsb.num_samples, "FSB: loop end over samples (%i vs %i)\n", fsb.loop_end, fsb.num_samples);
fsb.channels = (fsb.mode & FSOUND_STEREO) ? 2 : 1;
if (fsb.loop_end > fsb.num_samples) /* this seems common... */
fsb.num_samples = fsb.loop_end;
@ -264,25 +265,6 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
}
/* XOR encryption for some FSB4, though the flag is only seen after decrypting */
//;VGM_ASSERT(fsb.flags & FMOD_FSB_SOURCE_ENCRYPTED, "FSB ENCRYPTED found\n");
/* sometimes there is garbage at the end or missing bytes due to improper ripping */
VGM_ASSERT(fsb.base_header_size + fsb.sample_headers_size + fsb.sample_data_size != streamFile->get_size(streamFile),
"FSB wrong head/data_size found (expected 0x%x vs 0x%x)\n",
fsb.base_header_size + fsb.sample_headers_size + fsb.sample_data_size, streamFile->get_size(streamFile));
/* Loops unless disabled. FMOD default seems to be full loops (0/num_samples-1) without flags, for repeating tracks
* that should loop and jingles/sfx that shouldn't. We'll try to disable looping if it looks jingly enough. */
fsb.loop_flag = !(fsb.mode & FSOUND_LOOP_OFF);
if(!(fsb.mode & FSOUND_LOOP_NORMAL) /* rarely set */
&& fsb.loop_start+fsb.loop_end+1 == fsb.num_samples /* full loop */
&& fsb.num_samples < 20*fsb.sample_rate) /* in seconds (lame but no other way to know) */
fsb.loop_flag = 0;
/* ping-pong looping = no looping? (forward > reverse > forward) [ex. Biker Mice from Mars (PS2)] */
VGM_ASSERT(fsb.mode & FSOUND_LOOP_BIDI, "FSB BIDI looping found\n");
/* convert to clean some code */
if (fsb.mode & FSOUND_MPEG) fsb.codec = MPEG;
else if (fsb.mode & FSOUND_IMAADPCM) fsb.codec = IMA;
@ -293,6 +275,55 @@ VGMSTREAM * init_vgmstream_fsb(STREAMFILE *streamFile) {
else if (fsb.mode & FSOUND_8BITS) fsb.codec = PCM8;
else fsb.codec = PCM16;
/* correct compared to FMOD's tools */
if (fsb.loop_end)
fsb.loop_end += 1;
/* ping-pong looping = no looping? (forward > reverse > forward) [ex. Biker Mice from Mars (PS2)] */
VGM_ASSERT(fsb.mode & FSOUND_LOOP_BIDI, "FSB BIDI looping found\n");
VGM_ASSERT(fsb.mode & FSOUND_LOOP_OFF, "FSB LOOP OFF found\n"); /* sometimes used */
VGM_ASSERT(fsb.mode & FSOUND_LOOP_NORMAL, "FSB LOOP NORMAL found\n"); /* very rarely set */
/* XOR encryption for some FSB4, though the flag is only seen after decrypting */
//;VGM_ASSERT(fsb.flags & FMOD_FSB_SOURCE_ENCRYPTED, "FSB ENCRYPTED found\n");
/* sometimes there is garbage at the end or missing bytes due to improper ripping */
VGM_ASSERT(fsb.base_header_size + fsb.sample_headers_size + fsb.sample_data_size != streamFile->get_size(streamFile),
"FSB wrong head/data_size found (expected 0x%x vs 0x%x)\n",
fsb.base_header_size + fsb.sample_headers_size + fsb.sample_data_size, streamFile->get_size(streamFile));
/* autodetect unwanted loops */
{
/* FMOD tool's default behaviour is creating files with full loops and no flags unless disabled
* manually (can be overriden during program too), for all FSB versions. This makes jingles/sfx/voices
* loop when they shouldn't, but most music does full loops seamlessly, so we only want to disable
* if it looks jingly enough. Incidentally, their tools can only make files with full loops. */
int enable_loop, full_loop, is_small;
/* seems to mean forced loop */
enable_loop = (fsb.mode & FSOUND_LOOP_NORMAL);
/* for MPEG and CELT sometimes full loops are given with around/exact 1 frame less than num_samples,
* probably to account for encoder/decoder delay (ex. The Witcher 2, Hard Reset, Timeshift) */
if (fsb.codec == CELT)
full_loop = fsb.loop_start == 0 && fsb.loop_end >= fsb.num_samples - 512; /* maybe around 300? */
else if (fsb.codec == MPEG)
full_loop = fsb.loop_start == 0 && fsb.loop_end >= fsb.num_samples - 1152;
else
full_loop = fsb.loop_start == 0 && fsb.loop_end == fsb.num_samples;
/* in seconds (lame but no better way) */
is_small = fsb.num_samples < 20 * fsb.sample_rate;
//;VGM_LOG("FSB loop start=%i, loop end=%i, samples=%i, mode=%x\n", fsb.loop_start, fsb.loop_end, fsb.num_samples, fsb.mode);
//;VGM_LOG("FSB: enable=%i, full=%i, small=%i\n",enable_loop,full_loop,is_small );
fsb.loop_flag = !(fsb.mode & FSOUND_LOOP_OFF); /* disabled manually */
if (fsb.loop_flag && !enable_loop && full_loop && is_small) {
VGM_LOG("FSB: disable unwanted loop\n");
fsb.loop_flag = 0;
}
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(fsb.channels,fsb.loop_flag);

View File

@ -643,6 +643,8 @@ VGMSTREAM * init_vgmstream_opus_nus3(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_opus_sps_n1(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_opus_nxa(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_opus_opusx(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_opus_prototype(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_opus_opusnx(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_pc_al2(STREAMFILE * streamFile);
@ -832,8 +834,6 @@ VGMSTREAM * init_vgmstream_fsb5_fev_bank(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_bwav(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_opus_prototype(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_awb(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_awb_memory(STREAMFILE * streamFile, STREAMFILE *acbFile);

View File

@ -326,8 +326,15 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
if (isl_name) {
STREAMFILE *islFile = NULL;
//todo could try in ../(file) first since that's how the .isl is stored
islFile = open_streamfile_by_filename(streamFile, isl_name);
if (!islFile) {
/* try in ../(file) too since that's how the .isl is stored on disc */
char isl_path[PATH_LIMIT];
snprintf(isl_path, sizeof(isl_path), "../%s", isl_name);
islFile = open_streamfile_by_filename(streamFile, isl_path);
}
if (islFile) {
STREAMFILE *dec_sf = NULL;

View File

@ -390,3 +390,24 @@ VGMSTREAM * init_vgmstream_opus_prototype(STREAMFILE *streamFile) {
fail:
return NULL;
}
/* Edelweiss variation [Astebreed (Switch)] */
VGMSTREAM * init_vgmstream_opus_opusnx(STREAMFILE *streamFile) {
off_t offset = 0;
int num_samples = 0, loop_start = 0, loop_end = 0;
/* checks */
if (!check_extensions(streamFile, "opus,lopus"))
goto fail;
if (read_64bitBE(0x00, streamFile) != 0x4F5055534E580000) /* "OPUSNX\0\0" */
goto fail;
offset = 0x10;
num_samples = 0; //read_32bitLE(0x08, streamFile); /* samples with encoder delay */
if (read_32bitLE(0x0c, streamFile) != 0)
goto fail;
return init_vgmstream_opus(streamFile, meta_OPUS, offset, num_samples, loop_start, loop_end);
fail:
return NULL;
}

View File

@ -2399,6 +2399,8 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
/* two configs with same id; use project file as identifier */
if (sb->version == 0x000A0007 && sb->platform == UBI_PS2) {
STREAMFILE * streamTest = open_streamfile_by_filename(streamFile, "BIAAUDIO.SP1");
if (!streamTest) /* try again for localized subfolders */
streamTest = open_streamfile_by_filename(streamFile, "../BIAAUDIO.SP1");
if (streamTest) {
is_bia_ps2 = 1;
close_streamfile(streamTest);

View File

@ -800,25 +800,51 @@ STREAMFILE * open_streamfile_by_ext(STREAMFILE *streamFile, const char * ext) {
return streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
}
STREAMFILE * open_streamfile_by_filename(STREAMFILE *streamFile, const char * name) {
char foldername[PATH_LIMIT];
char filename[PATH_LIMIT];
const char *path;
STREAMFILE * open_streamfile_by_filename(STREAMFILE *streamFile, const char * filename) {
char fullname[PATH_LIMIT];
char partname[PATH_LIMIT];
char *path, *name;
streamFile->get_name(streamFile,foldername,sizeof(foldername));
path = strrchr(foldername,DIR_SEPARATOR);
if (path!=NULL) path = path+1;
streamFile->get_name(streamFile, fullname, sizeof(fullname));
//todo normalize separators in a better way, safeops, improve copying
path = strrchr(fullname,DIR_SEPARATOR);
if (path) {
strcpy(filename, foldername);
filename[path-foldername] = '\0';
strcat(filename, name);
} else {
strcpy(filename, name);
path[1] = '\0'; /* remove name after separator */
strcpy(partname, filename);
fix_dir_separators(partname);
/* normalize relative paths as don't work ok in some plugins */
if (partname[0]=='.' && partname[1] == DIR_SEPARATOR) { /* './name' */
name = partname + 2; /* ignore './' */
}
else if (partname[0]=='.' && partname[1]=='.' && partname[2] == DIR_SEPARATOR) { /* '../name' */
char *pathprev;
path[0] = '\0'; /* remove last separator so next call works */
pathprev = strrchr(fullname,DIR_SEPARATOR);
if (pathprev) {
pathprev[1] = '\0'; /* remove prev dir after separator */
name = partname + 3; /* ignore '../' */
}
else { /* let plugin handle? */
path[0] = DIR_SEPARATOR;
name = partname;
}
/* could work with more relative paths but whatevs */
}
else {
name = partname;
}
strcat(fullname, name);
}
else {
strcpy(fullname, filename);
}
return streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
return streamFile->open(streamFile, fullname, STREAMFILE_DEFAULT_BUFFER_SIZE);
}
STREAMFILE * reopen_streamfile(STREAMFILE *streamFile, size_t buffer_size) {

View File

@ -119,8 +119,9 @@ STREAMFILE * open_streamfile(STREAMFILE *streamFile, const char * pathname);
* Can be used to get companion headers. */
STREAMFILE * open_streamfile_by_ext(STREAMFILE *streamFile, const char * ext);
/* Opens a STREAMFILE from a base path + new filename
* Can be used to get companion files. */
/* Opens a STREAMFILE from a base path + new filename.
* Can be used to get companion files. Relative paths like
* './filename', '../filename', 'dir/filename' also work. */
STREAMFILE * open_streamfile_by_filename(STREAMFILE *streamFile, const char * filename);
/* Reopen a STREAMFILE with a different buffer size, for fine-tuned bigfile parsing.

View File

@ -479,6 +479,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_xmv_valve,
init_vgmstream_ubi_hx,
init_vgmstream_bmp_konami,
init_vgmstream_opus_opusnx,
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */