mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-17 23:36:41 +01:00
Clean FSB5 for future changes, also fix >2.5GB last subsongs
This commit is contained in:
parent
36db25e876
commit
b27e559e42
282
src/meta/fsb5.c
282
src/meta/fsb5.c
@ -2,18 +2,42 @@
|
||||
#include "../coding/coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
typedef struct {
|
||||
int total_subsongs;
|
||||
int version;
|
||||
int codec;
|
||||
int flags;
|
||||
|
||||
int channel_count;
|
||||
int sample_rate;
|
||||
int32_t num_samples;
|
||||
int32_t loop_start;
|
||||
int32_t loop_end;
|
||||
int loop_flag;
|
||||
|
||||
off_t sample_header_offset;
|
||||
size_t sample_header_size;
|
||||
size_t name_table_size;
|
||||
size_t sample_data_size;
|
||||
size_t base_header_size;
|
||||
|
||||
off_t extradata_offset;
|
||||
size_t extradata_size;
|
||||
|
||||
off_t stream_offset;
|
||||
size_t stream_size;
|
||||
off_t name_offset;
|
||||
} fsb5_header;
|
||||
|
||||
|
||||
/* FSB5 - FMOD Studio multiplatform format */
|
||||
VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t StartOffset = 0, NameOffset = 0;
|
||||
off_t SampleHeaderStart = 0, ExtraInfoStart = 0;
|
||||
size_t SampleHeaderLength, NameTableLength, SampleDataLength, BaseHeaderLength, StreamSize = 0, ExtraInfoSize = 0;
|
||||
|
||||
uint32_t NumSamples = 0, LoopStart = 0, LoopEnd = 0;
|
||||
int LoopFlag = 0, ChannelCount = 0, Version, SampleRate = 0, Codec, Flags = 0;
|
||||
int TotalSubsongs, TargetSubsong = streamFile->stream_index;
|
||||
fsb5_header fsb5 = {0};
|
||||
int target_subsong = streamFile->stream_index;
|
||||
int i;
|
||||
|
||||
|
||||
/* check extension, case insensitive */
|
||||
if (!check_extensions(streamFile,"fsb"))
|
||||
goto fail;
|
||||
@ -22,125 +46,125 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
goto fail;
|
||||
|
||||
/* 0x00 is rare (seen in Tales from Space Vita) */
|
||||
Version = read_32bitLE(0x04,streamFile);
|
||||
if (Version != 0x00 && Version != 0x01) goto fail;
|
||||
fsb5.version = read_32bitLE(0x04,streamFile);
|
||||
if (fsb5.version != 0x00 && fsb5.version != 0x01) goto fail;
|
||||
|
||||
TotalSubsongs = read_32bitLE(0x08,streamFile);
|
||||
SampleHeaderLength = read_32bitLE(0x0C,streamFile);
|
||||
NameTableLength = read_32bitLE(0x10,streamFile);
|
||||
SampleDataLength = read_32bitLE(0x14,streamFile);
|
||||
Codec = read_32bitLE(0x18,streamFile);
|
||||
fsb5.total_subsongs = read_32bitLE(0x08,streamFile);
|
||||
fsb5.sample_header_size = read_32bitLE(0x0C,streamFile);
|
||||
fsb5.name_table_size = read_32bitLE(0x10,streamFile);
|
||||
fsb5.sample_data_size = read_32bitLE(0x14,streamFile);
|
||||
fsb5.codec = read_32bitLE(0x18,streamFile);
|
||||
/* version 0x01 - 0x1c(4): zero, 0x24(16): hash, 0x34(8): unk
|
||||
* version 0x00 has an extra field (always 0?) at 0x1c */
|
||||
if (Version == 0x01) {
|
||||
Flags = read_32bitLE(0x20,streamFile); /* found by tests and assumed to be flags, no games known */
|
||||
if (fsb5.version == 0x01) {
|
||||
/* found by tests and assumed to be flags, no games known */
|
||||
fsb5.flags = read_32bitLE(0x20,streamFile);
|
||||
}
|
||||
BaseHeaderLength = (Version==0x00) ? 0x40 : 0x3C;
|
||||
fsb5.base_header_size = (fsb5.version==0x00) ? 0x40 : 0x3C;
|
||||
|
||||
if ((SampleHeaderLength + NameTableLength + SampleDataLength + BaseHeaderLength) != get_streamfile_size(streamFile)) {
|
||||
VGM_LOG("FSB5: bad size (%x + %x + %x + %x != %x)\n", SampleHeaderLength, NameTableLength, SampleDataLength, BaseHeaderLength, get_streamfile_size(streamFile));
|
||||
if ((fsb5.sample_header_size + fsb5.name_table_size + fsb5.sample_data_size + fsb5.base_header_size) != get_streamfile_size(streamFile)) {
|
||||
VGM_LOG("FSB5: bad size (%x + %x + %x + %x != %x)\n", fsb5.sample_header_size, fsb5.name_table_size, fsb5.sample_data_size, fsb5.base_header_size, get_streamfile_size(streamFile));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (TargetSubsong == 0) TargetSubsong = 1;
|
||||
if (TargetSubsong > TotalSubsongs || TotalSubsongs <= 0) goto fail;
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong > fsb5.total_subsongs || fsb5.total_subsongs <= 0) goto fail;
|
||||
|
||||
SampleHeaderStart = BaseHeaderLength;
|
||||
fsb5.sample_header_offset = fsb5.base_header_size;
|
||||
|
||||
/* find target stream header and data offset, and read all needed values for later use
|
||||
* (reads one by one as the size of a single stream header is variable) */
|
||||
for (i = 1; i <= TotalSubsongs; i++) {
|
||||
off_t DataStart = 0;
|
||||
size_t StreamHeaderLength = 0;
|
||||
uint32_t SampleMode1, SampleMode2; /* maybe one uint64? */
|
||||
for (i = 1; i <= fsb5.total_subsongs; i++) {
|
||||
size_t stream_header_size = 0;
|
||||
off_t data_offset = 0;
|
||||
uint32_t sample_mode1, sample_mode2; /* maybe one uint64? */
|
||||
|
||||
|
||||
SampleMode1 = (uint32_t)read_32bitLE(SampleHeaderStart+0x00,streamFile);
|
||||
SampleMode2 = (uint32_t)read_32bitLE(SampleHeaderStart+0x04,streamFile);
|
||||
StreamHeaderLength += 0x08;
|
||||
sample_mode1 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+0x00,streamFile);
|
||||
sample_mode2 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+0x04,streamFile);
|
||||
stream_header_size += 0x08;
|
||||
|
||||
/* get samples */
|
||||
NumSamples = ((SampleMode2 >> 2) & 0x3FFFFFFF); /* bits2: 31..2 (30) */
|
||||
fsb5.num_samples = ((sample_mode2 >> 2) & 0x3FFFFFFF); /* bits2: 31..2 (30) */
|
||||
|
||||
/* get offset inside data section */
|
||||
/* up to 0x07FFFFFF * 0x20 = full 32b offset 0xFFFFFFE0 (recheck, after 0x80000000 some calcs may be off?) */
|
||||
DataStart = ((SampleMode2 & 0x03) << 25) | ((SampleMode1 >> 7) & 0x1FFFFFF) << 5; /* bits2: 1..0 (2) | bits1: 31..8 (25) */
|
||||
/* up to 0x07FFFFFF * 0x20 = full 32b offset 0xFFFFFFE0 */
|
||||
data_offset = ((sample_mode2 & 0x03) << 25) | ((sample_mode1 >> 7) & 0x1FFFFFF) << 5; /* bits2: 1..0 (2) | bits1: 31..8 (25) */
|
||||
|
||||
/* get channels */
|
||||
switch ((SampleMode1 >> 5) & 0x03) { /* bits1: 7..6 (2) */
|
||||
case 0: ChannelCount = 1; break;
|
||||
case 1: ChannelCount = 2; break;
|
||||
case 2: ChannelCount = 6; break;/* some Dark Souls 2 MPEG; some IMA ADPCM */
|
||||
case 3: ChannelCount = 8; break;/* some IMA ADPCM */
|
||||
switch ((sample_mode1 >> 5) & 0x03) { /* bits1: 7..6 (2) */
|
||||
case 0: fsb5.channel_count = 1; break;
|
||||
case 1: fsb5.channel_count = 2; break;
|
||||
case 2: fsb5.channel_count = 6; break; /* some Dark Souls 2 MPEG; some IMA ADPCM */
|
||||
case 3: fsb5.channel_count = 8; break; /* some IMA ADPCM */
|
||||
/* other channels (ex. 4/10/12ch) use 0 here + set extra flags */
|
||||
default: /* not possible */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* get sample rate */
|
||||
switch ((SampleMode1 >> 1) & 0x0f) { /* bits1: 5..1 (4) */
|
||||
case 0: SampleRate = 4000; break;
|
||||
case 1: SampleRate = 8000; break;
|
||||
case 2: SampleRate = 11000; break;
|
||||
case 3: SampleRate = 11025; break;
|
||||
case 4: SampleRate = 16000; break;
|
||||
case 5: SampleRate = 22050; break;
|
||||
case 6: SampleRate = 24000; break;
|
||||
case 7: SampleRate = 32000; break;
|
||||
case 8: SampleRate = 44100; break;
|
||||
case 9: SampleRate = 48000; break;
|
||||
case 10: SampleRate = 96000; break;
|
||||
switch ((sample_mode1 >> 1) & 0x0f) { /* bits1: 5..1 (4) */
|
||||
case 0: fsb5.sample_rate = 4000; break;
|
||||
case 1: fsb5.sample_rate = 8000; break;
|
||||
case 2: fsb5.sample_rate = 11000; break;
|
||||
case 3: fsb5.sample_rate = 11025; break;
|
||||
case 4: fsb5.sample_rate = 16000; break;
|
||||
case 5: fsb5.sample_rate = 22050; break;
|
||||
case 6: fsb5.sample_rate = 24000; break;
|
||||
case 7: fsb5.sample_rate = 32000; break;
|
||||
case 8: fsb5.sample_rate = 44100; break;
|
||||
case 9: fsb5.sample_rate = 48000; break;
|
||||
case 10: fsb5.sample_rate = 96000; break;
|
||||
/* other sample rates (ex. 3000/64000/192000) use 0 here + set extra flags */
|
||||
default: /* 11-15: rejected (FMOD error) */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* get extra flags */
|
||||
if (SampleMode1 & 0x01) { /* bits1: 0 (1) */
|
||||
uint32_t ExtraFlag, ExtraFlagStart, ExtraFlagType, ExtraFlagSize, ExtraFlagEnd;
|
||||
if (sample_mode1 & 0x01) { /* bits1: 0 (1) */
|
||||
off_t extraflag_offset = fsb5.sample_header_offset+0x08;
|
||||
uint32_t extraflag, extraflag_type, extraflag_size, extraflag_end;
|
||||
|
||||
ExtraFlagStart = SampleHeaderStart+0x08;
|
||||
do {
|
||||
ExtraFlag = read_32bitLE(ExtraFlagStart,streamFile);
|
||||
ExtraFlagType = (ExtraFlag >> 25) & 0x7F; /* bits 32..26 (7) */
|
||||
ExtraFlagSize = (ExtraFlag >> 1) & 0xFFFFFF; /* bits 25..1 (24)*/
|
||||
ExtraFlagEnd = (ExtraFlag & 0x01); /* bit 0 (1) */
|
||||
extraflag = read_32bitLE(extraflag_offset,streamFile);
|
||||
extraflag_type = (extraflag >> 25) & 0x7F; /* bits 32..26 (7) */
|
||||
extraflag_size = (extraflag >> 1) & 0xFFFFFF; /* bits 25..1 (24)*/
|
||||
extraflag_end = (extraflag & 0x01); /* bit 0 (1) */
|
||||
|
||||
switch(ExtraFlagType) {
|
||||
switch(extraflag_type) {
|
||||
case 0x01: /* channels */
|
||||
ChannelCount = read_8bit(ExtraFlagStart+0x04,streamFile);
|
||||
fsb5.channel_count = read_8bit(extraflag_offset+0x04,streamFile);
|
||||
break;
|
||||
case 0x02: /* sample rate */
|
||||
SampleRate = read_32bitLE(ExtraFlagStart+0x04,streamFile);
|
||||
fsb5.sample_rate = read_32bitLE(extraflag_offset+0x04,streamFile);
|
||||
break;
|
||||
case 0x03: /* loop info */
|
||||
LoopStart = read_32bitLE(ExtraFlagStart+0x04,streamFile);
|
||||
if (ExtraFlagSize > 0x04) /* probably not needed */
|
||||
LoopEnd = read_32bitLE(ExtraFlagStart+0x08,streamFile);
|
||||
fsb5.loop_start = read_32bitLE(extraflag_offset+0x04,streamFile);
|
||||
if (extraflag_size > 0x04) /* probably not needed */
|
||||
fsb5.loop_end = read_32bitLE(extraflag_offset+0x08,streamFile);
|
||||
|
||||
/* when start is 0 seems the song repeats with no real looping (ex. Sonic Boom Fire & Ice jingles) */
|
||||
LoopFlag = (LoopStart != 0x00);
|
||||
fsb5.loop_flag = (fsb5.loop_start != 0x00);
|
||||
break;
|
||||
case 0x04: /* free comment, or maybe SFX info */
|
||||
break;
|
||||
//case 0x05: /* Unknown (32b) */
|
||||
//case 0x05: /* Unknown (32b) */ //todo multistream marker?
|
||||
// /* found in Tearaway Vita, value 0, first stream only */
|
||||
// break;
|
||||
case 0x06: /* XMA seek table */
|
||||
/* no need for it */
|
||||
break;
|
||||
case 0x07: /* DSP coefs */
|
||||
ExtraInfoStart = ExtraFlagStart + 0x04;
|
||||
fsb5.extradata_offset = extraflag_offset + 0x04;
|
||||
break;
|
||||
case 0x09: /* ATRAC9 config */
|
||||
ExtraInfoStart = ExtraFlagStart + 0x04;
|
||||
ExtraInfoSize = ExtraFlagSize;
|
||||
fsb5.extradata_offset = extraflag_offset + 0x04;
|
||||
fsb5.extradata_size = extraflag_size;
|
||||
break;
|
||||
case 0x0a: /* XWMA config */
|
||||
ExtraInfoStart = ExtraFlagStart + 0x04;
|
||||
fsb5.extradata_offset = extraflag_offset + 0x04;
|
||||
break;
|
||||
case 0x0b: /* Vorbis setup ID and seek table */
|
||||
ExtraInfoStart = ExtraFlagStart + 0x04;
|
||||
fsb5.extradata_offset = extraflag_offset + 0x04;
|
||||
/* seek table format:
|
||||
* 0x08: table_size (total_entries = seek_table_size / (4+4)), not counting this value; can be 0
|
||||
* 0x0C: sample number (only some samples are saved in the table)
|
||||
@ -152,73 +176,78 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
// /* found in some XMA2/Vorbis/FADPCM */
|
||||
// break;
|
||||
default:
|
||||
VGM_LOG("FSB5: unknown extra flag 0x%x at 0x%04x + 0x04 (size 0x%x)\n", ExtraFlagType, ExtraFlagStart, ExtraFlagSize);
|
||||
VGM_LOG("FSB5: unknown extraflag 0x%x at %lx + 0x04 (size 0x%x)\n", extraflag_type, extraflag_offset, extraflag_size);
|
||||
break;
|
||||
}
|
||||
|
||||
ExtraFlagStart += 0x04 + ExtraFlagSize;
|
||||
StreamHeaderLength += 0x04 + ExtraFlagSize;
|
||||
} while (ExtraFlagEnd != 0x00);
|
||||
extraflag_offset += 0x04 + extraflag_size;
|
||||
stream_header_size += 0x04 + extraflag_size;
|
||||
} while (extraflag_end != 0x00);
|
||||
}
|
||||
|
||||
/* stream found */
|
||||
if (i == TargetSubsong) {
|
||||
StartOffset = BaseHeaderLength + SampleHeaderLength + NameTableLength + DataStart;
|
||||
if (i == target_subsong) {
|
||||
fsb5.stream_offset = fsb5.base_header_size + fsb5.sample_header_size + fsb5.name_table_size + data_offset;
|
||||
|
||||
/* get stream size from next stream or datasize if there is only one */
|
||||
if (i == TotalSubsongs) {
|
||||
StreamSize = SampleDataLength - DataStart;
|
||||
} else {
|
||||
uint32_t NextSampleMode = (uint32_t)read_32bitLE(SampleHeaderStart+StreamHeaderLength+0x00,streamFile);
|
||||
StreamSize = (((NextSampleMode >> 7) & 0x00FFFFFF) << 5) - DataStart;
|
||||
/* get stream size from next stream offset or full size if there is only one */
|
||||
if (i == fsb5.total_subsongs) {
|
||||
fsb5.stream_size = fsb5.sample_data_size - data_offset;
|
||||
}
|
||||
else {
|
||||
off_t next_data_offset;
|
||||
uint32_t next_sample_mode1, next_sample_mode2;
|
||||
next_sample_mode1 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+stream_header_size+0x00,streamFile);
|
||||
next_sample_mode2 = (uint32_t)read_32bitLE(fsb5.sample_header_offset+stream_header_size+0x04,streamFile);
|
||||
next_data_offset = ((next_sample_mode2 & 0x03) << 25) | ((next_sample_mode1 >> 7) & 0x1FFFFFF) << 5;
|
||||
|
||||
fsb5.stream_size = next_data_offset - data_offset;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* continue searching */
|
||||
SampleHeaderStart += StreamHeaderLength;
|
||||
fsb5.sample_header_offset += stream_header_size;
|
||||
}
|
||||
/* target stream not found*/
|
||||
if (!StartOffset || !StreamSize) goto fail;
|
||||
if (!fsb5.stream_offset || !fsb5.stream_size) goto fail;
|
||||
|
||||
/* get stream name */
|
||||
if (NameTableLength) {
|
||||
NameOffset = BaseHeaderLength + SampleHeaderLength + read_32bitLE(BaseHeaderLength + SampleHeaderLength + 0x04*(TargetSubsong-1),streamFile);
|
||||
if (fsb5.name_table_size) {
|
||||
off_t name_suboffset = fsb5.base_header_size + fsb5.sample_header_size + 0x04*(target_subsong-1);
|
||||
fsb5.name_offset = fsb5.base_header_size + fsb5.sample_header_size + read_32bitLE(name_suboffset,streamFile);
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(ChannelCount,LoopFlag);
|
||||
vgmstream = allocate_vgmstream(fsb5.channel_count,fsb5.loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = SampleRate;
|
||||
vgmstream->num_samples = NumSamples;
|
||||
if (LoopFlag) {
|
||||
vgmstream->loop_start_sample = LoopStart;
|
||||
vgmstream->loop_end_sample = LoopEnd;
|
||||
vgmstream->sample_rate = fsb5.sample_rate;
|
||||
vgmstream->num_samples = fsb5.num_samples;
|
||||
if (fsb5.loop_flag) {
|
||||
vgmstream->loop_start_sample = fsb5.loop_start;
|
||||
vgmstream->loop_end_sample = fsb5.loop_end;
|
||||
}
|
||||
vgmstream->num_streams = TotalSubsongs;
|
||||
vgmstream->stream_size = StreamSize;
|
||||
vgmstream->num_streams = fsb5.total_subsongs;
|
||||
vgmstream->stream_size = fsb5.stream_size;
|
||||
vgmstream->meta_type = meta_FSB5;
|
||||
if (NameOffset)
|
||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, NameOffset,streamFile);
|
||||
if (fsb5.name_offset)
|
||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, fsb5.name_offset,streamFile);
|
||||
|
||||
|
||||
/* parse codec */
|
||||
switch (Codec) {
|
||||
switch (fsb5.codec) {
|
||||
case 0x00: /* FMOD_SOUND_FORMAT_NONE */
|
||||
goto fail;
|
||||
|
||||
case 0x01: /* FMOD_SOUND_FORMAT_PCM8 [Anima - Gate of Memories (PC)] */
|
||||
vgmstream->coding_type = coding_PCM8_U;
|
||||
vgmstream->layout_type = ChannelCount == 1 ? layout_none : layout_interleave;
|
||||
vgmstream->layout_type = fsb5.channel_count == 1 ? layout_none : layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x01;
|
||||
break;
|
||||
|
||||
case 0x02: /* FMOD_SOUND_FORMAT_PCM16 [Shantae Risky's Revenge (PC)] */
|
||||
vgmstream->coding_type = (Flags & 0x01) ? coding_PCM16BE : coding_PCM16LE;
|
||||
vgmstream->layout_type = ChannelCount == 1 ? layout_none : layout_interleave;
|
||||
vgmstream->coding_type = (fsb5.flags & 0x01) ? coding_PCM16BE : coding_PCM16LE;
|
||||
vgmstream->layout_type = fsb5.channel_count == 1 ? layout_none : layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
break;
|
||||
|
||||
@ -232,23 +261,22 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
|
||||
case 0x05: /* FMOD_SOUND_FORMAT_PCMFLOAT [Anima: Gate of Memories (PC)] */
|
||||
vgmstream->coding_type = coding_PCMFLOAT;
|
||||
vgmstream->layout_type = (ChannelCount == 1) ? layout_none : layout_interleave;
|
||||
vgmstream->layout_type = (fsb5.channel_count == 1) ? layout_none : layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x04;
|
||||
break;
|
||||
|
||||
case 0x06: /* FMOD_SOUND_FORMAT_GCADPCM [Sonic Boom: Fire and Ice (3DS)] */
|
||||
if (Flags & 0x02) { /* non-interleaved mode */
|
||||
if (fsb5.flags & 0x02) { /* non-interleaved mode */
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = (StreamSize / ChannelCount);
|
||||
vgmstream->interleave_block_size = (fsb5.stream_size / fsb5.channel_count);
|
||||
}
|
||||
else {
|
||||
vgmstream->coding_type = coding_NGC_DSP_subint;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
}
|
||||
|
||||
dsp_read_coefs_be(vgmstream,streamFile,ExtraInfoStart,0x2E);
|
||||
dsp_read_coefs_be(vgmstream,streamFile,fsb5.extradata_offset,0x2E);
|
||||
break;
|
||||
|
||||
case 0x07: /* FMOD_SOUND_FORMAT_IMAADPCM [Skylanders] */
|
||||
@ -259,8 +287,8 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
case 0x08: /* FMOD_SOUND_FORMAT_VAG [from fsbankex tests, no known games] */
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
if (Flags & 0x02) { /* non-interleaved mode */
|
||||
vgmstream->interleave_block_size = (StreamSize / ChannelCount);
|
||||
if (fsb5.flags & 0x02) { /* non-interleaved mode */
|
||||
vgmstream->interleave_block_size = (fsb5.stream_size / fsb5.channel_count);
|
||||
}
|
||||
else {
|
||||
vgmstream->interleave_block_size = 0x10;
|
||||
@ -279,10 +307,10 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
int bytes, block_size, block_count;
|
||||
|
||||
block_size = 0x8000; /* FSB default */
|
||||
block_count = StreamSize / block_size + (StreamSize % block_size ? 1 : 0);
|
||||
block_count = fsb5.stream_size / block_size + (fsb5.stream_size % block_size ? 1 : 0);
|
||||
|
||||
bytes = ffmpeg_make_riff_xma2(buf, 0x100, vgmstream->num_samples, StreamSize, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, StartOffset,StreamSize);
|
||||
bytes = ffmpeg_make_riff_xma2(buf, 0x100, vgmstream->num_samples, fsb5.stream_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, fsb5.stream_offset,fsb5.stream_size);
|
||||
if ( !vgmstream->codec_data ) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
@ -296,14 +324,14 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
|
||||
cfg.fsb_padding = (vgmstream->channels > 2 ? 16 : 4); /* observed default */
|
||||
|
||||
vgmstream->codec_data = init_mpeg_custom(streamFile, StartOffset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg);
|
||||
vgmstream->codec_data = init_mpeg_custom(streamFile, fsb5.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->layout_type = layout_none;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case 0x0C: /* FMOD_SOUND_FORMAT_CELT [BIT.TRIP Presents Runner2 (PC), Full Bore (PC)] */
|
||||
VGM_LOG("FSB5: FMOD_SOUND_FORMAT_CELT found\n");
|
||||
goto fail;
|
||||
|
||||
#ifdef VGM_USE_ATRAC9
|
||||
@ -311,20 +339,20 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
atrac9_config cfg = {0};
|
||||
|
||||
cfg.channels = vgmstream->channels;
|
||||
switch(ExtraInfoSize) {
|
||||
switch(fsb5.extradata_size) {
|
||||
case 0x04: /* Little Big Planet 2ch (Vita), Guacamelee (Vita) */
|
||||
cfg.config_data = read_32bitBE(ExtraInfoStart,streamFile);
|
||||
cfg.config_data = read_32bitBE(fsb5.extradata_offset,streamFile);
|
||||
break;
|
||||
case 0x08: /* Day of the Tentacle Remastered (Vita) */
|
||||
/* 0x00: superframe size (also in config_data) */
|
||||
cfg.config_data = read_32bitBE(ExtraInfoStart+0x04,streamFile);
|
||||
cfg.config_data = read_32bitBE(fsb5.extradata_offset+0x04,streamFile);
|
||||
break;
|
||||
//case 0x0c: /* Little Big Planet 6ch (Vita) */
|
||||
// //todo: this is just 0x04 x3, in case of 4ch would be 0x08 --must improve detection
|
||||
// //each stream has its own config_data (but seem to be the same), interleaves 1 super frame per stream
|
||||
// break;
|
||||
default:
|
||||
VGM_LOG("FSB5: unknown extra info size 0x%x\n", ExtraInfoSize);
|
||||
VGM_LOG("FSB5: unknown extra info size 0x%x\n", fsb5.extradata_size);
|
||||
goto fail;
|
||||
}
|
||||
//cfg.encoder_delay = 0x100; //todo not used? num_samples seems to count all data
|
||||
@ -342,14 +370,14 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
uint8_t buf[0x100];
|
||||
int bytes, format, average_bps, block_align;
|
||||
|
||||
format = read_16bitBE(ExtraInfoStart+0x00,streamFile);
|
||||
block_align = (uint16_t)read_16bitBE(ExtraInfoStart+0x02,streamFile);
|
||||
average_bps = (uint32_t)read_32bitBE(ExtraInfoStart+0x04,streamFile);
|
||||
format = read_16bitBE(fsb5.extradata_offset+0x00,streamFile);
|
||||
block_align = (uint16_t)read_16bitBE(fsb5.extradata_offset+0x02,streamFile);
|
||||
average_bps = (uint32_t)read_32bitBE(fsb5.extradata_offset+0x04,streamFile);
|
||||
/* rest: seek entries + mini seek table? */
|
||||
/* XWMA encoder only does up to 6ch (doesn't use FSB multistreams for more) */
|
||||
|
||||
bytes = ffmpeg_make_riff_xwma(buf,0x100, format, StreamSize, vgmstream->channels, vgmstream->sample_rate, average_bps, block_align);
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, StartOffset,StreamSize);
|
||||
bytes = ffmpeg_make_riff_xwma(buf,0x100, format, fsb5.stream_size, vgmstream->channels, vgmstream->sample_rate, average_bps, block_align);
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, fsb5.stream_offset,fsb5.stream_size);
|
||||
if ( !vgmstream->codec_data ) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
@ -363,11 +391,11 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
|
||||
cfg.channels = vgmstream->channels;
|
||||
cfg.sample_rate = vgmstream->sample_rate;
|
||||
cfg.setup_id = read_32bitLE(ExtraInfoStart,streamFile);
|
||||
cfg.setup_id = read_32bitLE(fsb5.extradata_offset,streamFile);
|
||||
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->coding_type = coding_VORBIS_custom;
|
||||
vgmstream->codec_data = init_vorbis_custom(streamFile, StartOffset, VORBIS_FSB, &cfg);
|
||||
vgmstream->codec_data = init_vorbis_custom(streamFile, fsb5.stream_offset, VORBIS_FSB, &cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
|
||||
break;
|
||||
@ -381,11 +409,11 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
break;
|
||||
|
||||
default:
|
||||
VGM_LOG("FSB5: unknown codec %x found\n", Codec);
|
||||
VGM_LOG("FSB5: unknown codec %x found\n", fsb5.codec);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,StartOffset))
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,fsb5.stream_offset))
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
Loading…
x
Reference in New Issue
Block a user