// FSB5 MPEG VGMSTREAM * init_vgmstream_fsb5_mpeg(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; off_t start_offset; int channel_count, channels, encoding, loop_flag, fsb_mainheader_len, fsb_subheader_len, FSBFlag; long sample_rate = 0, num_samples = 0, rate; uint16_t mp3ID; #ifdef VGM_USE_MPEG mpeg_codec_data *mpeg_data = NULL; coding_t mpeg_coding_type = coding_MPEG1_L3; #endif /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("fsb",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) == 0x46534235) /* "FSB5" */ { fsb_mainheader_len = 0x3C; } else { goto fail; } //fsb_subheader_len = read_16bitLE(fsb_mainheader_len,streamFile); /* "Check if the FSB is used as conatiner or as single file" */ if (read_32bitBE(0x04,streamFile) != 0x01000000) goto fail; #if 0 /* Check channel count, multi-channel not supported and will be refused */ if ((read_16bitLE(0x6E,streamFile) != 0x2) && (read_16bitLE(0x6E,streamFile) != 0x1)) goto fail; #endif start_offset = fsb_mainheader_len+fsb_subheader_len+0x10; /* Check the MPEG Sync Header */ mp3ID = read_16bitLE(start_offset,streamFile); if (mp3ID&0x7FF != 0x7FF) goto fail; channel_count = read_16bitLE(fsb_mainheader_len+0x3E,streamFile); if (channel_count != 1 && channel_count != 2) goto fail; FSBFlag = read_32bitLE(fsb_mainheader_len+0x30,streamFile); if (FSBFlag&0x2 || FSBFlag&0x4 || FSBFlag&0x6) loop_flag = 1; num_samples = (read_32bitLE(fsb_mainheader_len+0x2C,streamFile)); #ifdef VGM_USE_MPEG mpeg_data = init_mpeg_codec_data(streamFile, start_offset, -1, -1, &mpeg_coding_type, &rate, &channels); // -1 to not check sample rate or channels if (!mpeg_data) goto fail; //channel_count = channels; sample_rate = rate; #else // reject if no MPEG support goto fail; #endif /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; vgmstream->sample_rate = sample_rate; vgmstream->num_samples = num_samples; vgmstream->channels = channel_count; /* Still WIP */ if (loop_flag) { vgmstream->loop_start_sample = read_32bitLE(fsb_mainheader_len+0x28,streamFile); vgmstream->loop_end_sample = read_32bitLE(fsb_mainheader_len+0x2C,streamFile); } vgmstream->meta_type = meta_FSB_MPEG; #ifdef VGM_USE_MPEG /* NOTE: num_samples seems to be quite wrong for MPEG */ vgmstream->codec_data = mpeg_data; vgmstream->layout_type = layout_mpeg; vgmstream->coding_type = mpeg_coding_type; #else // reject if no MPEG support goto fail; #endif #if 0 if (loop_flag) { vgmstream->loop_start_sample = read_32bitBE(0x18,streamFile)/960*1152; vgmstream->loop_end_sample = read_32bitBE(0x1C,streamFile)/960*1152; } #endif /* open the file for reading */ { int i; STREAMFILE * file; if(vgmstream->layout_type == layout_interleave) { file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!file) goto fail; for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = file; vgmstream->ch[i].channel_start_offset= vgmstream->ch[i].offset=start_offset+ vgmstream->interleave_block_size*i; } } #ifdef VGM_USE_MPEG else if(vgmstream->layout_type == layout_mpeg) { for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,MPEG_BUFFER_SIZE); vgmstream->ch[i].channel_start_offset= vgmstream->ch[i].offset=start_offset; } } #endif else { goto fail; } } return vgmstream; /* clean up anything we may have opened */ fail: #ifdef VGM_USE_MPEG if (mpeg_data) { mpg123_delete(mpeg_data->m); free(mpeg_data); if (vgmstream) { vgmstream->codec_data = NULL; } } #endif if (vgmstream) close_vgmstream(vgmstream); return NULL; }
VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; off_t start_offset, meta_offset_offset, meta_offset, post_meta_offset; int32_t loop_start, loop_end; int loop_flag = 0; int channel_count; int codec_id; int aux_chunk_count; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("scd",filename_extension(filename))) goto fail; /* SEDB */ if (read_32bitBE(0,streamFile) != 0x53454442) goto fail; /* SSCF */ if (read_32bitBE(4,streamFile) != 0x53534346) goto fail; if (read_32bitBE(8,streamFile) == 2 || read_32bitBE(8,streamFile) == 3) { /* version 2 BE, as seen in FFXIII demo for PS3 */ /* version 3 BE, as seen in FFXIII for PS3 */ read_32bit = read_32bitBE; read_16bit = read_16bitBE; //size_offset = 0x14; meta_offset_offset = 0x40 + read_16bit(0xe,streamFile); } else if (read_32bitLE(8,streamFile) == 3 || read_32bitLE(8,streamFile) == 2) { /* version 2/3 LE, as seen in FFXIV for ?? */ read_32bit = read_32bitLE; read_16bit = read_16bitLE; //size_offset = 0x10; meta_offset_offset = 0x40 + read_16bit(0xe,streamFile); } else goto fail; /* never mind, FFXIII music_68tak.ps3.scd is 0x80 shorter */ #if 0 /* check file size with header value */ if (read_32bit(size_offset,streamFile) != get_streamfile_size(streamFile)) goto fail; #endif meta_offset = read_32bit(meta_offset_offset,streamFile); /* check that chunk size equals stream size (?) */ loop_start = read_32bit(meta_offset+0x10,streamFile); loop_end = read_32bit(meta_offset+0x14,streamFile); loop_flag = (loop_end > 0); channel_count = read_32bit(meta_offset+4,streamFile); codec_id = read_32bit(meta_offset+0xc,streamFile); post_meta_offset = meta_offset + 0x20; /* data at meta_offset is only 0x20 bytes, but there may be auxiliary chunks before anything else */ aux_chunk_count = read_32bit(meta_offset+0x1c,streamFile); for (; aux_chunk_count > 0; aux_chunk_count --) { /* skip aux chunks */ /*printf("skipping %08x\n", read_32bitBE(post_meta_offset, streamFile));*/ post_meta_offset += read_32bit(post_meta_offset+4,streamFile); } start_offset = post_meta_offset + read_32bit(meta_offset+0x18,streamFile); #ifdef VGM_USE_VORBIS if (codec_id == 0x6) { vgm_vorbis_info_t inf; uint32_t seek_table_size = read_32bit(post_meta_offset+0x10, streamFile); uint32_t vorb_header_size = read_32bit(post_meta_offset+0x14, streamFile); VGMSTREAM * result = NULL; memset(&inf, 0, sizeof(inf)); inf.loop_start = loop_start; inf.loop_end = loop_end; inf.loop_flag = loop_flag; inf.loop_end_found = loop_flag; inf.loop_length_found = 0; inf.layout_type = layout_ogg_vorbis; inf.meta_type = meta_SQEX_SCD; result = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf); if (result != NULL) { return result; } // try skipping seek table { if ((post_meta_offset-meta_offset) + seek_table_size + vorb_header_size != read_32bit(meta_offset+0x18, streamFile)) { return NULL; } start_offset = post_meta_offset + 0x20 + seek_table_size; result = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf); if (result != NULL) { return result; } } // failed with Ogg, try deobfuscating header { // skip chunks before xor_byte unsigned char xor_byte; xor_byte = read_8bit(post_meta_offset+2, streamFile); if (xor_byte == 0) { return NULL; } inf.scd_xor = xor_byte; inf.scd_xor_len = vorb_header_size; result = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf); return result; } } #endif /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bit(meta_offset+8,streamFile); switch (codec_id) { case 0x1: /* PCM */ vgmstream->coding_type = coding_PCM16LE_int; vgmstream->layout_type = layout_none; vgmstream->num_samples = read_32bit(meta_offset+0,streamFile) / 2 / channel_count; if (loop_flag) { vgmstream->loop_start_sample = loop_start / 2 / channel_count; vgmstream->loop_end_sample = loop_end / 2 / channel_count; } break; #ifdef VGM_USE_MPEG case 0x7: /* MPEG */ { mpeg_codec_data *mpeg_data = NULL; struct mpg123_frameinfo mi; coding_t ct; if (vgmstream->sample_rate == 47999) vgmstream->sample_rate = 48000; if (vgmstream->sample_rate == 44099) vgmstream->sample_rate = 44100; mpeg_data = init_mpeg_codec_data(streamFile, start_offset, vgmstream->sample_rate, vgmstream->channels, &ct, NULL, NULL); if (!mpeg_data) goto fail; vgmstream->codec_data = mpeg_data; if (MPG123_OK != mpg123_info(mpeg_data->m, &mi)) goto fail; vgmstream->coding_type = ct; vgmstream->layout_type = layout_mpeg; if (mi.vbr != MPG123_CBR) goto fail; vgmstream->num_samples = mpeg_bytes_to_samples(read_32bit(meta_offset+0,streamFile), &mi); vgmstream->num_samples -= vgmstream->num_samples%576; if (loop_flag) { vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, &mi); vgmstream->loop_start_sample -= vgmstream->loop_start_sample%576; vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, &mi); vgmstream->loop_end_sample -= vgmstream->loop_end_sample%576; } vgmstream->interleave_block_size = 0; } break; #endif case 0xC: /* MS ADPCM */ vgmstream->coding_type = coding_MSADPCM; vgmstream->layout_type = layout_none; vgmstream->interleave_block_size = read_16bit(post_meta_offset+0xc,streamFile); vgmstream->num_samples = msadpcm_bytes_to_samples(read_32bit(meta_offset+0,streamFile), vgmstream->interleave_block_size, vgmstream->channels); if (loop_flag) { vgmstream->loop_start_sample = msadpcm_bytes_to_samples(loop_start, vgmstream->interleave_block_size, vgmstream->channels); vgmstream->loop_end_sample = msadpcm_bytes_to_samples(loop_end, vgmstream->interleave_block_size, vgmstream->channels); } break; case 0xA: /* GC/Wii DSP ADPCM */ { STREAMFILE * file; int i; const off_t interleave_size = 0x800; const off_t stride_size = interleave_size * channel_count; size_t total_size; scd_int_codec_data * data = NULL; vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_scd_int; /* a normal DSP header... */ vgmstream->num_samples = read_32bitBE(start_offset+0,streamFile); total_size = (read_32bitBE(start_offset+4,streamFile)+1)/2; if (loop_flag) { vgmstream->loop_start_sample = loop_start; vgmstream->loop_end_sample = loop_end+1; } /* verify other channel headers */ for (i = 1; i < channel_count; i++) { if (read_32bitBE(start_offset+interleave_size*i+0,streamFile) != vgmstream->num_samples || (read_32bitBE(start_offset+4,streamFile)+1)/2 != total_size) { goto fail; } } /* the primary streamfile we'll be using */ file = streamFile->open(streamFile,filename,stride_size); if (!file) goto fail; vgmstream->ch[0].streamfile = file; data = malloc(sizeof(scd_int_codec_data)); data->substream_count = channel_count; data->substreams = calloc(channel_count, sizeof(VGMSTREAM *)); data->intfiles = calloc(channel_count, sizeof(STREAMFILE *)); vgmstream->codec_data = data; for (i=0;i<channel_count;i++) { STREAMFILE * intfile = open_scdint_with_STREAMFILE(file, "ARBITRARY.DSP", start_offset+interleave_size*i, interleave_size, stride_size, total_size); data->substreams[i] = init_vgmstream_ngc_dsp_std(intfile); data->intfiles[i] = intfile; if (!data->substreams[i]) goto fail; /* TODO: only handles mono substreams, though that's all we have with DSP */ /* save start things so we can restart for seeking/looping */ /* copy the channels */ memcpy(data->substreams[i]->start_ch,data->substreams[i]->ch,sizeof(VGMSTREAMCHANNEL)*1); /* copy the whole VGMSTREAM */ memcpy(data->substreams[i]->start_vgmstream,data->substreams[i],sizeof(VGMSTREAM)); } } break; #ifdef VGM_USE_FFMPEG case 0xB: /* XMA1/XMA2 */ { uint16_t codec_id = read_16bit(post_meta_offset, streamFile); if (codec_id == 0x165 || codec_id == 0x166) { ffmpeg_codec_data *ffmpeg_data = init_ffmpeg_faux_riff(streamFile, post_meta_offset, start_offset, streamFile->get_size(streamFile) - start_offset, read_32bit == read_32bitBE); if (!ffmpeg_data) goto fail; vgmstream->codec_data = ffmpeg_data; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; vgmstream->num_samples = ffmpeg_data->totalSamples; if (loop_flag) { vgmstream->loop_start_sample = loop_start; vgmstream->loop_end_sample = loop_end; } } else goto fail; } break; #endif default: goto fail; } vgmstream->meta_type = meta_SQEX_SCD; /* open the file for reading */ if (vgmstream->layout_type != layout_scd_int #ifdef VGM_USE_FFMPEG && vgmstream->coding_type != coding_FFmpeg #endif ) { int i; STREAMFILE * file; file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!file) goto fail; for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = file; vgmstream->ch[i].channel_start_offset= vgmstream->ch[i].offset=start_offset; } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* MSF header */ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; off_t start_offset; int32_t loop_start, loop_end; int loop_flag = 0; int channel_count; int codec_id; size_t fileLength; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("msf",filename_extension(filename))) goto fail; if (read_8bit(0x0,streamFile) != 0x4D) goto fail; /* M */ if (read_8bit(0x1,streamFile) != 0x53) goto fail; /* S */ if (read_8bit(0x2,streamFile) != 0x46) goto fail; /* F */ fileLength = get_streamfile_size(streamFile); loop_flag = (read_32bitBE(0x18,streamFile) != 0xFFFFFFFF); if (loop_flag) { loop_start = read_32bitBE(0x18,streamFile); loop_end = read_32bitBE(0x0C,streamFile); } channel_count = read_32bitBE(0x8,streamFile); codec_id = read_32bitBE(0x4,streamFile); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->channels = channel_count; /* Sample rate hack for strange files that don't have a specified frequency */ if (read_32bitBE(0x10,streamFile)==0x00000000) vgmstream->sample_rate = 48000; else vgmstream->sample_rate = read_32bitBE(0x10,streamFile); start_offset = 0x40; switch (codec_id) { case 0x0: /* PCM (Big Endian) */ { vgmstream->coding_type = coding_PCM16BE; vgmstream->num_samples = read_32bitBE(0x0C,streamFile)/2/channel_count; if (loop_flag){ vgmstream->loop_start_sample = loop_start/2/channel_count; vgmstream->loop_end_sample = loop_end/2/channel_count; } if (channel_count == 1) { vgmstream->layout_type = layout_none; } else if (channel_count > 1) { vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 2; } } break; case 0x3: /* PSx ADPCM */ { vgmstream->coding_type = coding_PSX; vgmstream->num_samples = read_32bitBE(0x0C,streamFile)*28/16/channel_count; if (vgmstream->num_samples == 0xFFFFFFFF) { vgmstream->num_samples = (fileLength - start_offset)*28/16/channel_count; } if (loop_flag) { vgmstream->loop_start_sample = loop_start*28/16/channel_count; vgmstream->loop_end_sample = loop_end*28/16/channel_count; } if (channel_count == 1) { vgmstream->layout_type = layout_none; } else if (channel_count > 1) { vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x10; // read_32bitBE(0x14,streamFile); } } break; #ifdef VGM_USE_MPEG case 0x7: /* MPEG */ { mpeg_codec_data *mpeg_data = NULL; struct mpg123_frameinfo mi; coding_t ct; mpeg_data = init_mpeg_codec_data(streamFile, start_offset, vgmstream->sample_rate, vgmstream->channels, &ct, NULL, NULL); if (!mpeg_data) goto fail; vgmstream->codec_data = mpeg_data; if (MPG123_OK != mpg123_info(mpeg_data->m, &mi)) goto fail; vgmstream->coding_type = ct; vgmstream->layout_type = layout_mpeg; if (mi.vbr != MPG123_CBR) goto fail; vgmstream->num_samples = mpeg_bytes_to_samples(read_32bitBE(0xC,streamFile), &mi); vgmstream->num_samples -= vgmstream->num_samples%576; if (loop_flag) { vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, &mi); vgmstream->loop_start_sample -= vgmstream->loop_start_sample%576; vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, &mi); vgmstream->loop_end_sample -= vgmstream->loop_end_sample%576; } vgmstream->interleave_block_size = 0; } break; #endif default: goto fail; } vgmstream->meta_type = meta_PS3_MSF; /* open the file for reading */ { int i; STREAMFILE * file; file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!file) goto fail; for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = file; vgmstream->ch[i].channel_start_offset= vgmstream->ch[i].offset=start_offset+vgmstream->interleave_block_size*i; } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }