Fix AKB2 subsongs [Mobius Final Fantasy (PC)]

This commit is contained in:
bnnm 2018-03-24 14:22:37 +01:00
parent eb4168f9b9
commit 8534006035
3 changed files with 73 additions and 45 deletions

View File

@ -3,7 +3,7 @@
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
/* AKB (AAC only) - found in SQEX iOS games */
VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
VGMSTREAM * init_vgmstream_akb_mp4(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
size_t filesize;
@ -34,7 +34,7 @@ fail:
/* AKB - found in SQEX iOS games */
VGMSTREAM * init_vgmstream_akb_multi(STREAMFILE *streamFile) {
VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, extra_data_offset = 0;
size_t file_size, header_size, extra_header_size = 0, extra_data_size = 0;
@ -113,7 +113,7 @@ VGMSTREAM * init_vgmstream_akb_multi(STREAMFILE *streamFile) {
}
case 0x06: { /* aac [The World Ends with You (iPad)] */
/* init_vgmstream_akb above has priority, but this works fine too */
/* init_vgmstream_akb_mp4 above has priority, but this works fine too */
ffmpeg_codec_data *ffmpeg_data;
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,file_size-start_offset);
@ -149,80 +149,108 @@ fail:
/* AKB2 - found in later SQEX iOS games */
VGMSTREAM * init_vgmstream_akb2_multi(STREAMFILE *streamFile) {
VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, header_offset;
size_t datasize;
int loop_flag = 0, channel_count, codec;
int akb_header_size, sound_index = 0, sound_offset_data, sound, sound_header_size, material_offset_data, material_index = 0, material, extradata, encryption_flag;
off_t start_offset, material_offset, extradata_offset;
size_t material_size, extradata_size, stream_size;
int loop_flag = 0, channel_count, encryption_flag, codec, sample_rate, num_samples, loop_start, loop_end;
int total_subsongs, target_subsong = streamFile->stream_index;
/* check extensions */
/* .akb.bytes is the usual extension in later games */
if ( !check_extensions(streamFile, "akb") )
if ( !check_extensions(streamFile, "akb,bytes") )
goto fail;
/* check header */
/* checks */
if (read_32bitBE(0x00,streamFile) != 0x414B4232) /* "AKB2" */
goto fail;
if (read_32bitLE(0x08,streamFile) != get_streamfile_size(streamFile))
goto fail;
akb_header_size = read_16bitLE(0x06, streamFile);
sound_offset_data = akb_header_size + sound_index * 0x10;
sound = read_32bitLE(sound_offset_data + 0x04, streamFile);
sound_header_size = read_16bitLE(sound + 0x02, streamFile);
material_offset_data = sound + sound_header_size + material_index * 0x10;
material = sound + read_32bitLE(material_offset_data + 0x04, streamFile);
encryption_flag = read_8bit(material + 0x03, streamFile) & 0x08;
extradata = material + read_16bitLE(material + 0x04, streamFile);
/* parse tables */
{
off_t table_offset;
size_t table_size, entry_size;
off_t akb_header_size = read_16bitLE(0x06, streamFile);
int table_count = read_8bit(0x0c, streamFile);
start_offset = material + read_16bitLE(material + 0x04, streamFile) + read_32bitLE(material + 0x18, streamFile);
header_offset = material;
/* probably each table has its type somewhere, but only seen last table = sound table */
if (table_count > 2) /* 2 only seen in some Mobius FF sound banks */
goto fail;
entry_size = 0x10; /* technically every entry/table has its own size but to simplify... */
table_offset = read_32bitLE(akb_header_size + (table_count-1)*entry_size + 0x04, streamFile);
table_size = read_16bitLE(table_offset + 0x02, streamFile);
total_subsongs = read_8bit(table_offset + 0x0f, streamFile); /* can contain 0 entries too */
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
material_offset = table_offset + read_32bitLE(table_offset + table_size + (target_subsong-1)*entry_size + 0x04, streamFile);
}
/** stream header **/
/* 0x00: 0? */
codec = read_8bit(material_offset+0x01,streamFile);
channel_count = read_8bit(material_offset+0x02,streamFile);
encryption_flag = read_8bit(material_offset+0x03,streamFile);
material_size = read_16bitLE(material_offset+0x04,streamFile);
sample_rate = (uint16_t)read_16bitLE(material_offset+0x06,streamFile);
stream_size = read_32bitLE(material_offset+0x08,streamFile);
num_samples = read_32bitLE(material_offset+0x0c,streamFile);
loop_start = read_32bitLE(material_offset+0x10,streamFile);
loop_end = read_32bitLE(material_offset+0x14,streamFile);
extradata_size = read_32bitLE(material_offset+0x18,streamFile);
/* rest: ? (empty or 0x3f80) */
loop_flag = (loop_end > 0);
extradata_offset = material_offset + material_size;
start_offset = material_offset + material_size + extradata_size;
channel_count = read_8bit(header_offset+0x02,streamFile);
loop_flag = read_32bitLE(header_offset+0x14,streamFile) > 0; /* loop end */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* 0x04: version? 0x08: filesize, 0x28: file_id?, others: no idea */
codec = read_8bit(header_offset+0x01,streamFile);
datasize = read_32bitLE(header_offset+0x08,streamFile);
vgmstream->sample_rate = (uint16_t)read_16bitLE(header_offset+0x06,streamFile);
/* When loop_flag num_samples may be much larger than real num_samples (it's fine when looping is off)
* Actual num_samples would be loop_end_sample+1, but more testing is needed */
vgmstream->num_samples = read_32bitLE(header_offset+0x0c,streamFile);
vgmstream->loop_start_sample = read_32bitLE(header_offset+0x10,streamFile);
vgmstream->loop_end_sample = read_32bitLE(header_offset+0x14,streamFile);
vgmstream->sample_rate = sample_rate;
vgmstream->num_streams = total_subsongs;
vgmstream->stream_size = stream_size;
vgmstream->meta_type = meta_AKB;
switch (codec) {
case 0x02: { /* MSAPDCM [The Irregular at Magic High School Lost Zero (Android)] */
if (encryption_flag) goto fail;
case 0x02: { /* MSADPCM [The Irregular at Magic High School Lost Zero (Android)] */
if (encryption_flag & 0x08) goto fail;
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = read_16bitLE(extradata + 0x02, streamFile);
vgmstream->interleave_block_size = read_16bitLE(extradata_offset + 0x02, streamFile);
/* adjusted samples; bigger or smaller than base samples, but seems more accurate
* (base samples may have more than possible and read over file size otherwise, very strange)
* loop_end seems to exist even with loop disabled */
vgmstream->num_samples = read_32bitLE(extradata + 0x04, streamFile);
vgmstream->loop_start_sample = read_32bitLE(extradata + 0x08, streamFile);
vgmstream->loop_end_sample = read_32bitLE(extradata + 0x0c, streamFile);
vgmstream->num_samples = read_32bitLE(extradata_offset + 0x04, streamFile);
vgmstream->loop_start_sample = read_32bitLE(extradata_offset + 0x08, streamFile);
vgmstream->loop_end_sample = read_32bitLE(extradata_offset + 0x0c, streamFile);
break;
}
#ifdef VGM_USE_FFMPEG
case 0x05: { /* ogg vorbis [The World Ends with You (iPhone / latest update)] */
case 0x05: { /* Ogg Vorbis [The World Ends with You (iOS / latest update)] */
ffmpeg_codec_data *ffmpeg_data;
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,datasize);
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
/* When loop_flag num_samples may be much larger than real num_samples (it's fine when looping is off)
* Actual num_samples would be loop_end_sample+1, but more testing is needed */
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
break;
}
#endif

View File

@ -125,7 +125,7 @@ VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_mp4_aac(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_mp4_aac_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size);
VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_akb_mp4(STREAMFILE *streamFile);
#endif
VGMSTREAM * init_vgmstream_sfl(STREAMFILE * streamFile);
@ -622,8 +622,8 @@ VGMSTREAM * init_vgmstream_x360_cxs(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_dsp_adx(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_akb_multi(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_akb2_multi(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_x360_ast(STREAMFILE *streamFile);

View File

@ -69,7 +69,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_mp4_aac,
#endif
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
init_vgmstream_akb,
init_vgmstream_akb_mp4,
#endif
init_vgmstream_sadb,
init_vgmstream_ps2_bmdx,
@ -330,8 +330,8 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_ps2_vds_vdm,
init_vgmstream_x360_cxs,
init_vgmstream_dsp_adx,
init_vgmstream_akb_multi,
init_vgmstream_akb2_multi,
init_vgmstream_akb,
init_vgmstream_akb2,
#ifdef VGM_USE_FFMPEG
init_vgmstream_mp4_aac_ffmpeg,
#endif