mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-16 11:33:20 +01:00
commit
4f9df81f9b
@ -404,7 +404,7 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#if XMA_CHECK_SKIPS
|
||||
// more header stuff (info from FFmpeg)
|
||||
{
|
||||
int flag;
|
||||
@ -432,6 +432,7 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
frame_offset_b += 1;
|
||||
if (flag) {
|
||||
VGM_LOG("start_skip at 0x%I64x\n", frame_offset_b);
|
||||
new_skip = read_bitsBE_b(frame_offset_b, 10, streamFile);
|
||||
frame_offset_b += 10;
|
||||
VGM_ASSERT(start_skip, "XMA: more than one start_skip (%i)\n", new_skip);
|
||||
@ -449,6 +450,7 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
frame_offset_b += 1;
|
||||
if (flag) {
|
||||
VGM_LOG("end_skip at 0x%I64x\n", frame_offset_b);
|
||||
new_skip = read_bitsBE_b(frame_offset_b, 10, streamFile);
|
||||
frame_offset_b += 10;
|
||||
VGM_ASSERT(end_skip, "XMA: more than one end_skip (%i)\n", new_skip);
|
||||
|
@ -93,7 +93,7 @@ static uint32_t bik_get_num_samples(STREAMFILE *streamFile, int bits_per_sample)
|
||||
* (num_samples for other streams seem erratic though) */
|
||||
if (target_stream > num_tracks) goto fail;
|
||||
if (target_stream == 0) target_stream = 1;
|
||||
VGM_ASSERT(num_tracks > 1, "BIK: multiple streams found (%i entries)\n", num_tracks);
|
||||
//VGM_ASSERT(num_tracks > 1, "BIK: multiple streams found (%i entries)\n", num_tracks);//FFmpeg data has this
|
||||
|
||||
/* read each frame header and sum all samples
|
||||
* a frame has N audio packets with header (one per track) + video packet */
|
||||
|
@ -225,7 +225,7 @@ ffmpeg_codec_data * init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t *
|
||||
|
||||
int errcode, i;
|
||||
|
||||
int streamIndex;
|
||||
int streamIndex, streamCount;
|
||||
AVStream *stream;
|
||||
AVCodecParameters *codecPar;
|
||||
|
||||
@ -273,6 +273,7 @@ ffmpeg_codec_data * init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t *
|
||||
|
||||
/* find valid audio stream inside */
|
||||
streamIndex = -1;
|
||||
streamCount = 0; /* audio streams only */
|
||||
|
||||
for (i = 0; i < data->formatCtx->nb_streams; ++i) {
|
||||
stream = data->formatCtx->streams[i];
|
||||
@ -282,12 +283,15 @@ ffmpeg_codec_data * init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t *
|
||||
} else {
|
||||
stream->discard = AVDISCARD_ALL; /* disable demuxing unneded streams */
|
||||
}
|
||||
if (codecPar->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||
streamCount++;
|
||||
}
|
||||
|
||||
if (streamIndex < 0) goto fail;
|
||||
|
||||
|
||||
data->streamIndex = streamIndex;
|
||||
stream = data->formatCtx->streams[streamIndex];
|
||||
data->streamCount = streamCount;
|
||||
|
||||
|
||||
/* prepare codec and frame/packet buffers */
|
||||
|
@ -243,8 +243,6 @@ VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset) {
|
||||
}
|
||||
}
|
||||
|
||||
VGM_ASSERT(fsbh.numsamples > 1, "FSB: multiple streams found (%i entries)\n", fsbh.numsamples);
|
||||
|
||||
/* XOR encryption for some FSB4 */
|
||||
if (fsbh.flags & FMOD_FSB_SOURCE_ENCRYPTED) {
|
||||
VGM_LOG("FSB ENCRYPTED found\n");
|
||||
@ -272,6 +270,7 @@ VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset) {
|
||||
vgmstream->num_samples = fsbh.lengthsamples;
|
||||
vgmstream->loop_start_sample = fsbh.loopstart;
|
||||
vgmstream->loop_end_sample = fsbh.loopend;
|
||||
vgmstream->num_streams = fsbh.numsamples;
|
||||
vgmstream->meta_type = fsbh.meta_type;
|
||||
|
||||
/* parse format */
|
||||
|
417
src/meta/fsb5.c
417
src/meta/fsb5.c
@ -5,115 +5,131 @@
|
||||
/* FSB5 header */
|
||||
VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t StartOffset;
|
||||
|
||||
int LoopFlag = 0;
|
||||
int32_t LoopStart, LoopEnd;
|
||||
|
||||
int NumSamples;
|
||||
int ChannelCount;
|
||||
int SampleRate;
|
||||
int DSPInfoStart = 0;
|
||||
off_t StartOffset = 0;
|
||||
off_t SampleHeaderStart = 0, DSPInfoStart = 0;
|
||||
size_t SampleHeaderLength, NameTableLength, SampleDataLength, BaseHeaderLength;
|
||||
|
||||
uint32_t BaseSamples = 0, LoopStart = 0, LoopEnd = 0, NumSamples = 0;
|
||||
int LoopFlag = 0, ChannelCount = 0, SampleRate = 0, CodingID;
|
||||
int TotalStreams, TargetStream = 0;
|
||||
int i;
|
||||
|
||||
|
||||
int SampleHeaderStart, SampleHeaderLength, NameTableLength, SampleDataLength, CodingID, SampleMode;
|
||||
int ExtraFlag, ExtraFlagStart, ExtraFlagType, ExtraFlagSize, ExtraFlagEnd;
|
||||
int freq_mode, ch_mode;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
if (!check_extensions(streamFile,"fsb")) goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,streamFile) != 0x46534235) goto fail; /* "FSB5" */
|
||||
if (read_32bitLE(0x04,streamFile) != 0x01) goto fail; /* Version ID */
|
||||
if (read_32bitLE(0x08,streamFile) != 0x01) goto fail; /* Number of Sample Files */
|
||||
|
||||
SampleHeaderStart = 0x3C;
|
||||
//v0 has extra flags at 0x1c and SampleHeaderStart = 0x40?
|
||||
if (read_32bitLE(0x04,streamFile) != 0x01) goto fail; /* Version ID */
|
||||
|
||||
TotalStreams = read_32bitLE(0x08,streamFile);
|
||||
SampleHeaderLength = read_32bitLE(0x0C,streamFile);
|
||||
NameTableLength = read_32bitLE(0x10,streamFile);
|
||||
SampleDataLength = read_32bitLE(0x14,streamFile);
|
||||
NameTableLength = read_32bitLE(0x10,streamFile);
|
||||
SampleDataLength = read_32bitLE(0x14,streamFile);
|
||||
CodingID = read_32bitLE(0x18,streamFile);
|
||||
/* 0x1c (8): zero, 0x24 (16): hash, 0x34 (8): unk */
|
||||
BaseHeaderLength = 0x3C;
|
||||
|
||||
SampleHeaderStart = BaseHeaderLength;
|
||||
|
||||
if ((SampleHeaderLength + NameTableLength + SampleDataLength + 0x3C) != get_streamfile_size(streamFile)) goto fail;
|
||||
if (TargetStream == 0) TargetStream = 1; /* default to 1 */
|
||||
if (TargetStream > TotalStreams || TotalStreams < 0) goto fail;
|
||||
|
||||
StartOffset = SampleHeaderLength + NameTableLength + 0x3C;
|
||||
SampleMode = read_32bitLE(SampleHeaderStart+0x00,streamFile);
|
||||
|
||||
/* get sample rate */
|
||||
freq_mode = (SampleMode >> 1) & 0x0f; /* bits 5..1 */
|
||||
switch (freq_mode) {
|
||||
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; //???
|
||||
default:
|
||||
SampleRate = 44100;
|
||||
//goto fail; /* probably better? */
|
||||
break;
|
||||
}
|
||||
/* 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 = 0; i < TotalStreams; i++) {
|
||||
off_t DataStart = 0;
|
||||
size_t StreamHeaderLength = 0;
|
||||
uint32_t SampleMode;
|
||||
|
||||
/* get channels (from tests seems correct, but multichannel isn't very common, ex. no 4ch mode?) */
|
||||
ch_mode = (SampleMode >> 5) & 0x03; /* bits 7..6 (maybe 8 too?) */
|
||||
switch (ch_mode) {
|
||||
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 */
|
||||
/* other values (ex. 10ch) seem specified in the extra flags */
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
SampleMode = read_32bitLE(SampleHeaderStart+0x00,streamFile);
|
||||
BaseSamples = read_32bitLE(SampleHeaderStart+0x04,streamFile);
|
||||
StreamHeaderLength += 0x08;
|
||||
|
||||
/* get extra flags */
|
||||
ExtraFlagStart = SampleHeaderStart+0x08;
|
||||
if (SampleMode&0x01) /* bit 0 */
|
||||
{
|
||||
do
|
||||
{
|
||||
ExtraFlag = read_32bitLE(ExtraFlagStart,streamFile);
|
||||
ExtraFlagType = (ExtraFlag>>25)&0x7F;
|
||||
ExtraFlagSize = (ExtraFlag>>1)&0xFFFFFF;
|
||||
ExtraFlagEnd = (ExtraFlag&0x01);
|
||||
|
||||
switch(ExtraFlagType)
|
||||
{
|
||||
case 0x01: /* Channel Info */
|
||||
{
|
||||
ChannelCount = read_8bit(ExtraFlagStart+0x04,streamFile);
|
||||
}
|
||||
break;
|
||||
case 0x02: /* Sample Rate Info */
|
||||
{
|
||||
SampleRate = read_32bitLE(ExtraFlagStart+0x04,streamFile);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x03: /* Loop Info */
|
||||
{
|
||||
LoopStart = read_32bitLE(ExtraFlagStart+0x04,streamFile);
|
||||
if (LoopStart != 0x00) {
|
||||
LoopFlag = 1;
|
||||
LoopEnd = read_32bitLE(ExtraFlagStart+0x08,streamFile);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x07: /* DSP Info (Coeffs), only used if coding is DSP??? */
|
||||
{
|
||||
DSPInfoStart = ExtraFlagStart+0x04;
|
||||
}
|
||||
break;
|
||||
/* get global offset */
|
||||
DataStart = (SampleMode >> 7) * 0x20;
|
||||
|
||||
/* get sample rate */
|
||||
switch ((SampleMode >> 1) & 0x0f) { /* bits 5..1 */
|
||||
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; //???
|
||||
default:
|
||||
SampleRate = 44100;
|
||||
break; /* probably specified in the extra flags */
|
||||
}
|
||||
ExtraFlagStart+=ExtraFlagSize+0x04;
|
||||
}
|
||||
while (ExtraFlagEnd != 0x00);
|
||||
|
||||
/* get channels (from tests seems correct, but multichannel isn't very common, ex. no 4ch mode?) */
|
||||
switch ((SampleMode >> 5) & 0x03) { /* bits 7..6 */
|
||||
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 */
|
||||
default: /* other values (ex. 10ch) seem specified in the extra flags */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* get extra flags */
|
||||
if (SampleMode&0x01) { /* bit 0 */
|
||||
uint32_t ExtraFlag, ExtraFlagStart, ExtraFlagType, ExtraFlagSize, ExtraFlagEnd;
|
||||
|
||||
ExtraFlagStart = SampleHeaderStart+0x08;
|
||||
do {
|
||||
ExtraFlag = read_32bitLE(ExtraFlagStart,streamFile);
|
||||
ExtraFlagType = (ExtraFlag>>25)&0x7F;
|
||||
ExtraFlagSize = (ExtraFlag>>1)&0xFFFFFF;
|
||||
ExtraFlagEnd = (ExtraFlag&0x01);
|
||||
|
||||
switch(ExtraFlagType) {
|
||||
case 0x01: /* Channel Info */
|
||||
ChannelCount = read_8bit(ExtraFlagStart+0x04,streamFile);
|
||||
break;
|
||||
case 0x02: /* Sample Rate Info */
|
||||
SampleRate = read_32bitLE(ExtraFlagStart+0x04,streamFile);
|
||||
break;
|
||||
case 0x03: /* Loop Info */
|
||||
LoopStart = read_32bitLE(ExtraFlagStart+0x04,streamFile);
|
||||
if (ExtraFlagSize > 0x04) /* probably no needed */
|
||||
LoopEnd = read_32bitLE(ExtraFlagStart+0x08,streamFile);
|
||||
|
||||
/* when start is 0 seems the song reoeats with no real looping (ex. Sonic Boom Fire & Ice jingles) */
|
||||
LoopFlag = (LoopStart != 0x00);
|
||||
break;
|
||||
case 0x07: /* DSP Info (Coeffs), only used if coding is DSP??? */
|
||||
DSPInfoStart = ExtraFlagStart + 0x04;
|
||||
break;
|
||||
default:
|
||||
VGM_LOG("FSB5: unknown extra flag %i at 0x%04x\n", ExtraFlagType, ExtraFlagStart);
|
||||
break;
|
||||
}
|
||||
|
||||
ExtraFlagStart += 0x04 + ExtraFlagSize;
|
||||
StreamHeaderLength += 0x04 + ExtraFlagSize;
|
||||
} while (ExtraFlagEnd != 0x00);
|
||||
}
|
||||
|
||||
/* stream found */
|
||||
if (i == TotalStreams-1) {
|
||||
StartOffset = BaseHeaderLength + SampleHeaderLength + NameTableLength + DataStart;
|
||||
break;
|
||||
}
|
||||
|
||||
/* continue searching */
|
||||
SampleHeaderStart += StreamHeaderLength;
|
||||
}
|
||||
/* target stream not found*/
|
||||
if (!StartOffset) goto fail;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(ChannelCount,LoopFlag);
|
||||
@ -122,179 +138,128 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = ChannelCount;
|
||||
vgmstream->sample_rate = SampleRate;
|
||||
vgmstream->num_streams = TotalStreams;
|
||||
vgmstream->meta_type = meta_FSB5;
|
||||
|
||||
switch (CodingID) {
|
||||
case 0x00: /* FMOD_SOUND_FORMAT_NONE */
|
||||
goto fail;
|
||||
|
||||
switch (CodingID)
|
||||
{
|
||||
case 0x00: /* FMOD_SOUND_FORMAT_NONE */
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case 0x01: /* FMOD_SOUND_FORMAT_PCM8 */
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case 0x01: /* FMOD_SOUND_FORMAT_PCM8 */
|
||||
goto fail;
|
||||
|
||||
case 0x02: /* FMOD_SOUND_FORMAT_PCM16 */
|
||||
{
|
||||
case 0x02: /* FMOD_SOUND_FORMAT_PCM16 */
|
||||
NumSamples = BaseSamples / 4;
|
||||
if (ChannelCount == 1) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
} else {
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
}
|
||||
|
||||
NumSamples = read_32bitLE(SampleHeaderStart+0x04,streamFile)/4;
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
break;
|
||||
|
||||
if (ChannelCount == 1)
|
||||
{
|
||||
vgmstream->layout_type = layout_none;
|
||||
} else {
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
}
|
||||
case 0x03: /* FMOD_SOUND_FORMAT_PCM24 */
|
||||
goto fail;
|
||||
|
||||
case 0x04: /* FMOD_SOUND_FORMAT_PCM32 */
|
||||
goto fail;
|
||||
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
}
|
||||
break;
|
||||
case 0x05: /* FMOD_SOUND_FORMAT_PCMFLOAT */
|
||||
goto fail;
|
||||
|
||||
case 0x03:/* FMOD_SOUND_FORMAT_PCM24 */
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case 0x06: /* FMOD_SOUND_FORMAT_GCADPCM */
|
||||
if (ChannelCount == 1) {
|
||||
NumSamples = BaseSamples / 4;
|
||||
vgmstream->layout_type = layout_none;
|
||||
} else {
|
||||
NumSamples = BaseSamples / (2*ChannelCount);
|
||||
vgmstream->layout_type = layout_interleave_byte;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
}
|
||||
|
||||
case 0x04: /* FMOD_SOUND_FORMAT_PCM32 */
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
dsp_read_coefs_be(vgmstream,streamFile,DSPInfoStart,0x2E);
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
break;
|
||||
|
||||
case 0x05: /* FMOD_SOUND_FORMAT_PCMFLOAT */
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case 0x07: /* FMOD_SOUND_FORMAT_IMAADPCM */
|
||||
NumSamples = BaseSamples / 4;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->coding_type = coding_XBOX;
|
||||
if (vgmstream->channels > 2) /* multichannel FSB IMA (interleaved header) */
|
||||
vgmstream->coding_type = coding_FSB_IMA;
|
||||
break;
|
||||
|
||||
case 0x06: /* FMOD_SOUND_FORMAT_GCADPCM */
|
||||
{
|
||||
if (ChannelCount == 1)
|
||||
{
|
||||
NumSamples = read_32bitLE(SampleHeaderStart+0x04,streamFile)/4;
|
||||
vgmstream->layout_type = layout_none;
|
||||
} else {
|
||||
NumSamples = read_32bitLE(SampleHeaderStart+0x04,streamFile)/(2*ChannelCount);
|
||||
vgmstream->layout_type = layout_interleave_byte;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
}
|
||||
case 0x08: /* FMOD_SOUND_FORMAT_VAG */
|
||||
goto fail;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
case 0x09: /* FMOD_SOUND_FORMAT_HEVAG */
|
||||
goto fail;
|
||||
|
||||
dsp_read_coefs_be(vgmstream,streamFile,DSPInfoStart,0x2E);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x07: /* FMOD_SOUND_FORMAT_IMAADPCM */
|
||||
{
|
||||
NumSamples = read_32bitLE(SampleHeaderStart+0x04,streamFile)/4;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->coding_type = coding_XBOX;
|
||||
if (vgmstream->channels > 2) /* multichannel FSB IMA (interleaved header) */
|
||||
vgmstream->coding_type = coding_FSB_IMA;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x08: /* FMOD_SOUND_FORMAT_VAG */
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x09: /* FMOD_SOUND_FORMAT_HEVAG */
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0A: /* FMOD_SOUND_FORMAT_XMA */
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0B: /* FMOD_SOUND_FORMAT_MPEG */
|
||||
{
|
||||
NumSamples = read_32bitLE(SampleHeaderStart+0x04,streamFile)/2/ChannelCount;
|
||||
case 0x0A: /* FMOD_SOUND_FORMAT_XMA */
|
||||
goto fail;
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
{
|
||||
mpeg_codec_data *mpeg_data = NULL;
|
||||
coding_t mpeg_coding_type;
|
||||
case 0x0B: {/* FMOD_SOUND_FORMAT_MPEG */
|
||||
mpeg_codec_data *mpeg_data = NULL;
|
||||
coding_t mpeg_coding_type;
|
||||
|
||||
NumSamples = BaseSamples / 2 / ChannelCount;
|
||||
|
||||
#if 0
|
||||
int fsb_padding = vgmstream->channels > 2 ? 16 : 0;//todo fix
|
||||
int fsb_padding = vgmstream->channels > 2 ? 16 : 0;//todo fix
|
||||
|
||||
mpeg_data = init_mpeg_codec_data_interleaved(streamFile, StartOffset, &mpeg_coding_type, vgmstream->channels, 0, fsb_padding);
|
||||
if (!mpeg_data) goto fail;
|
||||
mpeg_data = init_mpeg_codec_data_interleaved(streamFile, StartOffset, &mpeg_coding_type, vgmstream->channels, 0, fsb_padding);
|
||||
if (!mpeg_data) goto fail;
|
||||
|
||||
vgmstream->interleave_block_size = mpeg_data->current_frame_size + mpeg_data->current_padding;
|
||||
if (vgmstream->channels > 2) vgmstream->loop_flag = 0;//todo not implemented yet
|
||||
vgmstream->interleave_block_size = mpeg_data->current_frame_size + mpeg_data->current_padding;
|
||||
if (vgmstream->channels > 2) vgmstream->loop_flag = 0;//todo not implemented yet
|
||||
#endif
|
||||
|
||||
mpeg_data = init_mpeg_codec_data(streamFile, StartOffset, &mpeg_coding_type, vgmstream->channels);
|
||||
if (!mpeg_data) goto fail;
|
||||
if (vgmstream->channels > 2)
|
||||
goto fail; /* no multichannel for now */
|
||||
|
||||
vgmstream->codec_data = mpeg_data;
|
||||
vgmstream->coding_type = mpeg_coding_type;
|
||||
vgmstream->layout_type = layout_mpeg;
|
||||
mpeg_data = init_mpeg_codec_data(streamFile, StartOffset, &mpeg_coding_type, vgmstream->channels);
|
||||
if (!mpeg_data) goto fail;
|
||||
|
||||
mpeg_set_error_logging(mpeg_data, 0);
|
||||
}
|
||||
vgmstream->codec_data = mpeg_data;
|
||||
vgmstream->coding_type = mpeg_coding_type;
|
||||
vgmstream->layout_type = layout_mpeg;
|
||||
|
||||
mpeg_set_error_logging(mpeg_data, 0);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 0x0C: /* FMOD_SOUND_FORMAT_CELT */
|
||||
goto fail;
|
||||
|
||||
case 0x0C: /* FMOD_SOUND_FORMAT_CELT */
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case 0x0D: /* FMOD_SOUND_FORMAT_AT9 */
|
||||
goto fail;
|
||||
|
||||
case 0x0D: /* FMOD_SOUND_FORMAT_AT9 */
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case 0x0E: /* FMOD_SOUND_FORMAT_XWMA */
|
||||
goto fail;
|
||||
|
||||
case 0x0E: /* FMOD_SOUND_FORMAT_XWMA */
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case 0x0F: /* FMOD_SOUND_FORMAT_VORBIS */
|
||||
goto fail;
|
||||
|
||||
case 0x0F: /* FMOD_SOUND_FORMAT_VORBIS */
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
vgmstream->num_samples = NumSamples;
|
||||
vgmstream->meta_type = meta_FSB5;
|
||||
|
||||
if (LoopFlag)
|
||||
{
|
||||
vgmstream->loop_start_sample = LoopStart;
|
||||
vgmstream->loop_end_sample = LoopEnd;
|
||||
vgmstream->num_samples = NumSamples;
|
||||
if (LoopFlag) {
|
||||
vgmstream->loop_start_sample = LoopStart;
|
||||
vgmstream->loop_end_sample = LoopEnd;
|
||||
}
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,StartOffset))
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1,27 +1,19 @@
|
||||
/*
|
||||
Capcom MADP format found in Capcom 3DS games.
|
||||
*/
|
||||
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* Capcom MADP - found in Capcom 3DS games */
|
||||
VGMSTREAM * init_vgmstream_mca(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
int channel_count;
|
||||
int loop_flag;
|
||||
int version;
|
||||
int channel_count, loop_flag, version;
|
||||
size_t head_size, data_size, file_size;
|
||||
off_t start_offset, coef_offset, coef_start, coef_shift;
|
||||
int i, j;
|
||||
int coef_spacing;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile, filename, sizeof(filename));
|
||||
if (strcasecmp("mca", filename_extension(filename)))
|
||||
if (!check_extensions(streamFile,"mca"))
|
||||
goto fail;
|
||||
|
||||
|
||||
/* check header */
|
||||
if ((uint32_t)read_32bitBE(0, streamFile) != 0x4D414450) /* "MADP" */
|
||||
goto fail;
|
||||
@ -41,10 +33,7 @@ VGMSTREAM * init_vgmstream_mca(STREAMFILE *streamFile) {
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x18, streamFile);
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
if (channel_count == 1)
|
||||
vgmstream->layout_type = layout_none;
|
||||
else
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave;
|
||||
vgmstream->meta_type = meta_MCA;
|
||||
|
||||
|
||||
@ -78,7 +67,7 @@ VGMSTREAM * init_vgmstream_mca(STREAMFILE *streamFile) {
|
||||
coef_offset = coef_start + coef_shift * 0x14;
|
||||
}
|
||||
|
||||
/* sanity check */
|
||||
/* sanity check (for bad rips with the header manually truncated to in attempt to "fix" v5 headers) */
|
||||
file_size = get_streamfile_size(streamFile);
|
||||
|
||||
if (start_offset + data_size > file_size) {
|
||||
@ -88,40 +77,16 @@ VGMSTREAM * init_vgmstream_mca(STREAMFILE *streamFile) {
|
||||
start_offset = file_size - data_size;
|
||||
}
|
||||
|
||||
|
||||
/* set up ADPCM coefs */
|
||||
for (j = 0; j<vgmstream->channels; j++) {
|
||||
for (i = 0; i<16; i++) {
|
||||
vgmstream->ch[j].adpcm_coef[i] = read_16bitLE(coef_offset + j*coef_spacing + i * 2, streamFile);
|
||||
}
|
||||
}
|
||||
|
||||
/* set up ADPCM coefs */
|
||||
dsp_read_coefs_le(vgmstream, streamFile, coef_offset, coef_spacing);
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
for (i = 0; i<channel_count; i++) {
|
||||
if (vgmstream->layout_type == layout_interleave_shortblock)
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
|
||||
vgmstream->interleave_block_size);
|
||||
else if (vgmstream->layout_type == layout_interleave)
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
|
||||
STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
else
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
|
||||
0x1000);
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset =
|
||||
vgmstream->ch[i].offset =
|
||||
start_offset + i*vgmstream->interleave_block_size;
|
||||
}
|
||||
}
|
||||
/* open the file for reading */
|
||||
if ( !vgmstream_open_stream(vgmstream,streamFile, start_offset) )
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -28,14 +28,14 @@ VGMSTREAM * init_vgmstream_ps3_sgdx(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamHeader = NULL;
|
||||
|
||||
off_t start_offset, data_offset;
|
||||
int32_t data_size;
|
||||
off_t start_offset, data_offset, chunk_offset;
|
||||
size_t data_size;
|
||||
|
||||
int is_sgx, is_sgb;
|
||||
int loop_flag, channels, type;
|
||||
int sample_rate, num_samples, loop_start_sample, loop_end_sample;
|
||||
|
||||
int target_stream = 0;
|
||||
int target_stream = 0, total_streams;
|
||||
|
||||
|
||||
/* check extension, case insensitive */
|
||||
@ -54,7 +54,7 @@ VGMSTREAM * init_vgmstream_ps3_sgdx(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
|
||||
/* SGXD chunk (size 0x10) */
|
||||
/* SGXD base (size 0x10) */
|
||||
if (read_32bitBE(0x00,streamHeader) != 0x53475844) /* "SGXD" */
|
||||
goto fail;
|
||||
/* 0x04 SGX: full header_size; SGD/SGH: unknown header_size (counting from 0x0/0x8/0x10, varies) */
|
||||
@ -70,24 +70,23 @@ VGMSTREAM * init_vgmstream_ps3_sgdx(STREAMFILE *streamFile) {
|
||||
|
||||
|
||||
/* WAVE chunk (size 0x10 + files * 0x38 + optional padding) */
|
||||
/* the format reads chunks until header_size, but we only want WAVE in the first position meaning BGM */
|
||||
if (read_32bitBE(0x10,streamHeader) != 0x57415645) /* "WAVE" */
|
||||
goto fail;
|
||||
/* 0x04 SGX: unknown; SGD/SGH: chunk length */
|
||||
/* 0x08 null */
|
||||
|
||||
/* validate multi-streams (usually only SE containers) */
|
||||
{
|
||||
int total_streams = read_32bitLE(0x1c,streamHeader);
|
||||
VGM_ASSERT(total_streams > 1, "SGXD: multiple streams found (%i entries)\n", total_streams);
|
||||
if (target_stream == 0) target_stream = 1; /* auto: default to 1 */
|
||||
if (target_stream > total_streams) goto fail;
|
||||
/* 0x04 SGX: unknown; SGD/SGH: chunk length, 0x08 null */
|
||||
if (is_sgx) { /* position after chunk+size */
|
||||
if (read_32bitBE(0x10,streamHeader) != 0x57415645) goto fail; /* "WAVE" */
|
||||
chunk_offset = 0x18;
|
||||
} else {
|
||||
if (!find_chunk_le(streamHeader, 0x57415645,0x10,0, &chunk_offset,NULL)) goto fail; /* "WAVE" */
|
||||
}
|
||||
|
||||
/* check multi-streams (usually only SE containers; Puppeteer) */
|
||||
total_streams = read_32bitLE(chunk_offset+0x04,streamHeader);
|
||||
if (target_stream == 0) target_stream = 1;
|
||||
if (target_stream > total_streams) goto fail;
|
||||
|
||||
/* read stream header */
|
||||
{
|
||||
off_t chunk_offset, stream_offset;
|
||||
chunk_offset = 0x10 + 0x10 + 0x38 * (target_stream-1); /* position in target header*/
|
||||
off_t stream_offset;
|
||||
chunk_offset += 0x08 + 0x38 * (target_stream-1); /* position in target header*/
|
||||
|
||||
/* 0x00 ? (00/01/02) */
|
||||
/* 0x04 sometimes global offset to wave_name */
|
||||
@ -122,11 +121,11 @@ VGMSTREAM * init_vgmstream_ps3_sgdx(STREAMFILE *streamFile) {
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->num_samples = num_samples;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = num_samples;
|
||||
vgmstream->loop_start_sample = loop_start_sample;
|
||||
vgmstream->loop_end_sample = loop_end_sample;
|
||||
|
||||
vgmstream->num_streams = total_streams;
|
||||
vgmstream->meta_type = meta_PS3_SGDX;
|
||||
|
||||
switch (type) {
|
||||
|
@ -109,7 +109,6 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||
/* 0x18: unknown offset */
|
||||
/* 0x1c: unknown (0x0) */
|
||||
headers_entries = read_16bit(tables_offset+0x04,streamFile);
|
||||
VGM_ASSERT(headers_entries > 1, "SCD: multiple streams found (%i entries)\n", headers_entries);
|
||||
if (target_stream == 0) target_stream = 1; /* auto: default to 1 */
|
||||
if (target_stream > headers_entries) goto fail;
|
||||
headers_offset = read_32bit(tables_offset+0x0c,streamFile);
|
||||
@ -220,6 +219,8 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bit(meta_offset+8,streamFile);
|
||||
vgmstream->num_streams = headers_entries;
|
||||
vgmstream->meta_type = meta_SQEX_SCD;
|
||||
|
||||
switch (codec_id) {
|
||||
case 0x1:
|
||||
@ -409,8 +410,6 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
vgmstream->meta_type = meta_SQEX_SCD;
|
||||
|
||||
/* open the file for reading */
|
||||
if (vgmstream->layout_type != layout_scd_int
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
|
@ -88,7 +88,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
|
||||
xwb.xact = 1; /* XACT1: XBOX [The King of Fighters 2003] */
|
||||
} else if (xwb.version < 42) {
|
||||
xwb.xact = 2; /* XACT2: early XBOX360 [Kameo, Table Tennis, Blue Dragon], Windows */
|
||||
} else {
|
||||
} else { /* highest seen: tool=v46, header=v44 */
|
||||
xwb.xact = 3; /* XACT3: late XBOX360, Windows */
|
||||
}
|
||||
|
||||
@ -118,7 +118,6 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
|
||||
xwb.format = read_32bit(off+suboff+0x0c, streamFile); /* compact mode only */
|
||||
/* suboff+0x10: build time 64b (XACT2/3) */
|
||||
|
||||
VGM_ASSERT(xwb.streams > 1, "XWB: multiple streams found (%i entries)\n", xwb.streams);
|
||||
if (target_stream == 0) target_stream = 1; /* auto: default to 1 */
|
||||
if (xwb.streams < 1 || target_stream > xwb.streams) goto fail;
|
||||
|
||||
@ -155,7 +154,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
|
||||
if (xwb.xact == 1) { //LoopRegion (bytes within data)
|
||||
xwb.loop_start = (uint32_t)read_32bit(off+0x10, streamFile);
|
||||
xwb.loop_end = (uint32_t)read_32bit(off+0x14, streamFile);//length
|
||||
} else if (xwb.xact == 2) {//LoopRegion (bytes within data) or XMALoopRegion (bits within data)
|
||||
} else if (xwb.xact == 2 && xwb.version <= 38) {//LoopRegion (bytes within data) or XMALoopRegion (bits within data)
|
||||
xwb.loop_start = (uint32_t)read_32bit(off+0x10, streamFile);
|
||||
xwb.loop_end = (uint32_t)read_32bit(off+0x14, streamFile);//length (LoopRegion) or offset (XMALoopRegion)
|
||||
} else {//LoopRegion (samples)
|
||||
@ -240,7 +239,8 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
|
||||
xwb.loop_start_sample = (xwb.loop_start) / block_size / samples_per_frame;
|
||||
xwb.loop_end_sample = (xwb.loop_start + xwb.loop_end) / block_size / samples_per_frame;
|
||||
}
|
||||
else if (xwb.xact == 2 && (xwb.codec == XMA1 || xwb.codec == XMA2) && xwb.loop_flag) {
|
||||
else if (xwb.xact == 2 && xwb.version <= 38 /* v38: byte offset, v40+: sample offset, v39: ? */
|
||||
&& (xwb.codec == XMA1 || xwb.codec == XMA2) && xwb.loop_flag) {
|
||||
/* need to manually find sample offsets, thanks to Microsoft dumb headers */
|
||||
xma_sample_data xma_sd;
|
||||
memset(&xma_sd,0,sizeof(xma_sample_data));
|
||||
@ -259,9 +259,15 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
|
||||
xma_get_samples(&xma_sd, streamFile);
|
||||
xwb.loop_start_sample = xma_sd.loop_start_sample;
|
||||
xwb.loop_end_sample = xma_sd.loop_end_sample;
|
||||
|
||||
// todo fix properly (XWB loop_start/end seem to count padding samples while XMA1 RIFF doesn't)
|
||||
xwb.loop_start_sample -= 512;
|
||||
xwb.loop_end_sample -= 512;
|
||||
//this doesn't seem ok because can fall within 0 to 512 (ie.- first frame)
|
||||
//if (xwb.loop_start_sample) xwb.loop_start_sample -= 512;
|
||||
//if (xwb.loop_end_sample) xwb.loop_end_sample -= 512;
|
||||
|
||||
//add padding back until it's fixed (affects looping)
|
||||
// (in rare cases this causes a glitch in FFmpeg since it has a bug where it's missing some samples)
|
||||
xwb.num_samples += 64 + 512;
|
||||
}
|
||||
|
||||
|
||||
@ -273,6 +279,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
|
||||
vgmstream->num_samples = xwb.num_samples;
|
||||
vgmstream->loop_start_sample = xwb.loop_start_sample;
|
||||
vgmstream->loop_end_sample = xwb.loop_end_sample;
|
||||
vgmstream->num_streams = xwb.streams;
|
||||
vgmstream->meta_type = meta_XWB;
|
||||
|
||||
switch(xwb.codec) {
|
||||
|
@ -408,6 +408,16 @@ VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) {
|
||||
try_dual_file_stereo(vgmstream, streamFile);
|
||||
}
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
/* check FFmpeg streams here, for lack of a better place */
|
||||
if (vgmstream->coding_type == coding_FFmpeg) {
|
||||
ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data;
|
||||
if (data->streamCount && !vgmstream->num_streams) {
|
||||
vgmstream->num_streams = data->streamCount;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* save start things so we can restart for seeking */
|
||||
/* copy the channels */
|
||||
memcpy(vgmstream->start_ch,vgmstream->ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels);
|
||||
@ -1942,6 +1952,12 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
||||
break;
|
||||
}
|
||||
concatn(length,desc,temp);
|
||||
|
||||
/* only interesting if more than one */
|
||||
if (vgmstream->num_streams > 1) {
|
||||
snprintf(temp,TEMPSIZE,"\nnumber of streams: %d",vgmstream->num_streams);
|
||||
concatn(length,desc,temp);
|
||||
}
|
||||
}
|
||||
|
||||
/* filename search pairs for dual file stereo */
|
||||
|
@ -678,6 +678,7 @@ typedef struct {
|
||||
coding_t coding_type; /* type of encoding */
|
||||
layout_t layout_type; /* type of layout for data */
|
||||
meta_t meta_type; /* how we know the metadata */
|
||||
int num_streams; /* info only, for a few multi-stream formats (0=not set/one, 1=one stream) */
|
||||
|
||||
/* looping */
|
||||
int loop_flag; /* is this stream looped? */
|
||||
@ -909,6 +910,7 @@ typedef struct {
|
||||
int64_t blockAlign; // coded block of bytes, counting channels (the block can be joint stereo)
|
||||
int64_t frameSize; // decoded samples per block
|
||||
int64_t skipSamples; // number of start samples that will be skipped (encoder delay), for looping adjustments
|
||||
int streamCount; // number of FFmpeg audio streams
|
||||
|
||||
/*** internal state ***/
|
||||
// Intermediate byte buffer
|
||||
|
@ -257,6 +257,11 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
|
||||
buf = malloc(BUFSIZE*sizeof(sample)*s->channels);
|
||||
if (!buf) {
|
||||
fprintf(stderr,"failed allocating output buffer\n");
|
||||
close_vgmstream(s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
len = get_vgmstream_play_samples(loop_count,fade_seconds,fade_delay_seconds,s);
|
||||
if (!play && !adxencd && !oggenc && !batchvar) printf("samples to play: %d (%.4lf seconds)\n",len,(double)len/s->sample_rate);
|
||||
|
Loading…
Reference in New Issue
Block a user