void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) { int i, sample_count; int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE; for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { outbuf[sample_count]=read_16bit(stream->offset+i*2*channelspacing,stream->streamfile); } }
/* RWSD is quite similar to BRSTM, but can contain several streams. * Still, some games use it for single streams. We only support the * single stream form here */ VGMSTREAM * init_vgmstream_rwsd(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; coding_t coding_type; size_t wave_length; int codec_number; int channel_count; int loop_flag; int rwar = 0; int rwav = 0; struct rwav_data rwav_data; size_t stream_size; int big_endian = 1; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL; const char *ext; rwav_data.version = -1; rwav_data.start_offset = 0; rwav_data.info_chunk = -1; rwav_data.wave_offset = -1; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); ext = filename_extension(filename); if (strcasecmp("rwsd",ext)) { if (strcasecmp("rwar",ext)) { if (strcasecmp("rwav",ext)) { if (strcasecmp("bcwav",ext) && strcasecmp("bms",ext)) { goto fail; } else { // cwav, similar to little endian rwav rwav = 1; big_endian = 0; } } else { // matched rwav rwav = 1; } } else { // matched rwar rwar = 1; } } else { // match rwsd } if (big_endian) { read_16bit = read_16bitBE; read_32bit = read_32bitBE; } else { read_16bit = read_16bitLE; read_32bit = read_32bitLE; } /* check header */ if (rwar || rwav) { rwav_data.offset = 0; rwav_data.streamFile = streamFile; rwav_data.big_endian = big_endian; rwav_data.read_32bit = read_32bit; if (rwar) read_rwar(&rwav_data); if (rwav) read_rwav(&rwav_data); if (rwav_data.wave_offset < 0) goto fail; } else { if ((uint32_t)read_32bitBE(0,streamFile)!=0x52575344) /* "RWSD" */ goto fail; switch (read_32bitBE(4,streamFile)) { case 0xFEFF0102: /* ideally we would look through the chunk list for a WAVE chunk, * but it's always in the same order */ /* get WAVE offset, check */ rwav_data.wave_offset = read_32bit(0x18,streamFile); if ((uint32_t)read_32bitBE(rwav_data.wave_offset,streamFile)!=0x57415645) /* "WAVE" */ goto fail; /* get WAVE size, check */ wave_length = read_32bit(0x1c,streamFile); if (read_32bit(rwav_data.wave_offset+4,streamFile)!=wave_length) goto fail; /* check wave count */ if (read_32bit(rwav_data.wave_offset+8,streamFile) != 1) goto fail; /* only support 1 */ rwav_data.version = 2; break; case 0xFEFF0103: rwav_data.offset = 0xe0; rwav_data.streamFile = streamFile; rwav_data.big_endian = big_endian; rwav_data.read_32bit = read_32bit; read_rwar(&rwav_data); if (rwav_data.wave_offset < 0) goto fail; rwar = 1; break; default: goto fail; } } /* get type details */ codec_number = read_8bit(rwav_data.wave_offset+0x10,streamFile); loop_flag = read_8bit(rwav_data.wave_offset+0x11,streamFile); if (big_endian) channel_count = read_8bit(rwav_data.wave_offset+0x12,streamFile); else channel_count = read_32bit(rwav_data.wave_offset+0x24,streamFile); switch (codec_number) { case 0: coding_type = coding_PCM8; break; case 1: if (big_endian) coding_type = coding_PCM16BE; else coding_type = coding_PCM16LE; break; case 2: coding_type = coding_NGC_DSP; break; case 3: coding_type = coding_IMA; break; default: goto fail; } if (channel_count < 1) goto fail; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ if (big_endian) { vgmstream->num_samples = dsp_nibbles_to_samples(read_32bit(rwav_data.wave_offset+0x1c,streamFile)); vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bit(rwav_data.wave_offset+0x18,streamFile)); } else { vgmstream->num_samples = read_32bit(rwav_data.wave_offset+0x1c,streamFile); vgmstream->loop_start_sample = read_32bit(rwav_data.wave_offset+0x18,streamFile); } vgmstream->sample_rate = (uint16_t)read_16bit(rwav_data.wave_offset+0x14,streamFile); vgmstream->loop_end_sample = vgmstream->num_samples; vgmstream->coding_type = coding_type; vgmstream->layout_type = layout_none; if (rwar) vgmstream->meta_type = meta_RWAR; else if (rwav) { if (big_endian) vgmstream->meta_type = meta_RWAV; else vgmstream->meta_type = meta_CWAV; } else vgmstream->meta_type = meta_RWSD; { off_t data_start_offset; off_t codec_info_offset; int i,j; for (j=0;j<vgmstream->channels;j++) { if (rwar || rwav) { if (big_endian) { /* This is pretty nasty, so an explaination is in order. * At 0x10 in the info_chunk is the offset of a table with * one entry per channel. Each entry in this table is itself * an offset to a set of information for the channel. The * first element in the set is the offset into DATA of the * channel. * The second element is the * offset of the codec-specific setup for the channel. */ off_t channel_info_offset; channel_info_offset = rwav_data.info_chunk + read_32bit(rwav_data.info_chunk+ read_32bit(rwav_data.info_chunk+0x10,streamFile)+j*4, streamFile); data_start_offset = rwav_data.start_offset + read_32bit(channel_info_offset+0, streamFile); codec_info_offset = rwav_data.info_chunk + read_32bit(channel_info_offset+4, streamFile); } else { // CWAV uses some relative offsets off_t cur_pos = rwav_data.info_chunk + 0x14; // channel count cur_pos = cur_pos + read_32bit(cur_pos + 4 + j*8 + 4,streamFile); // size is at cur_pos + 4 data_start_offset = rwav_data.start_offset + read_32bit(cur_pos + 4, streamFile); // codec-specific info is at cur_pos + 0xC codec_info_offset = cur_pos + read_32bit(cur_pos + 0xC,streamFile); } vgmstream->ch[j].channel_start_offset= vgmstream->ch[j].offset=data_start_offset; } else { // dummy for RWSD, must be a proper way to work this out codec_info_offset=rwav_data.wave_offset+0x6c+j*0x30; } if (vgmstream->coding_type == coding_NGC_DSP) { for (i=0;i<16;i++) { vgmstream->ch[j].adpcm_coef[i]=read_16bit(codec_info_offset+i*2,streamFile); } } if (vgmstream->coding_type == coding_IMA) { vgmstream->ch[j].adpcm_history1_16 = read_16bit(codec_info_offset,streamFile); vgmstream->ch[j].adpcm_step_index = read_16bit(codec_info_offset+2,streamFile); } } } if (rwar || rwav) { /* */ } else { if (rwav_data.version == 2) rwav_data.start_offset = read_32bit(8,streamFile); } stream_size = read_32bit(rwav_data.wave_offset+0x50,streamFile); /* open the file for reading by each channel */ { int i; for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename, 0x1000); if (!vgmstream->ch[i].streamfile) goto fail; if (!(rwar || rwav)) { vgmstream->ch[i].channel_start_offset= vgmstream->ch[i].offset= rwav_data.start_offset + i*stream_size; } } } return vgmstream; /* clean up anything we may have opened */ fail: 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; }
/* SCD - Square-Enix games (FF XIII, XIV) */ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset, tables_offset, meta_offset, extradata_offset, name_offset = 0; int32_t stream_size, extradata_size, loop_start, loop_end; int loop_flag = 0, channel_count, codec, sample_rate; int version, target_entry, aux_chunk_count; int total_subsongs, target_subsong = streamFile->stream_index; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL; /* check extension, case insensitive */ if ( !check_extensions(streamFile, "scd") ) goto fail; /** main header **/ if (read_32bitBE(0x00,streamFile) != 0x53454442 && /* "SEDB" */ read_32bitBE(0x04,streamFile) != 0x53534346) /* "SSCF" */ goto fail; if (read_8bit(0x0c,streamFile) == 0x01) { /* big endian flag */ //size_offset = 0x14; read_32bit = read_32bitBE; read_16bit = read_16bitBE; } else { //size_offset = 0x10; read_32bit = read_32bitLE; read_16bit = read_16bitLE; } /* SSCF version? (older SSCFs from Crisis Core/FFXI X360 seem to be V3/2) */ if (read_8bit(0x0d,streamFile) != 0x04) goto fail; /* v2: FFXIII demo (PS3), FFT0 test files (PC); v3: common; v4: Kingdom Hearts 2.8 (PS4) */ version = read_32bit(0x08,streamFile); if (version != 2 && version != 3 && version != 4) goto fail; tables_offset = read_16bit(0x0e,streamFile); /* usually 0x30 or 0x20 */ #if 0 /* never mind, FFXIII music_68tak.ps3.scd is 0x80 shorter */ /* check file size with header value */ if (read_32bit(size_offset,streamFile) != get_streamfile_size(streamFile)) goto fail; #endif /** offset tables **/ /* 0x00(2): table1/4 (unknown) entries */ /* 0x02(2): table2 (unknown) entries */ /* 0x04(2): table3 (headers) entries */ /* 0x06(2): unknown, varies even for clone files */ /* (implicit: table1 starts at 0x20) */ /* 0x08: table2 (unknown) start offset */ /* 0x0c: table3 (headers) start offset */ /* 0x10: table4 (unknown) start offset */ /* 0x14: always null? */ /* 0x18: table5? (unknown) start offset? */ /* 0x1c: unknown, often null */ /* each table entry is an uint32_t offset; after entries there is padding */ /* if a table isn't present entries is 0 and offset points to next table */ /* find meta_offset in table3 (headers) and total subsongs */ { int i; int headers_entries = read_16bit(tables_offset+0x04,streamFile); off_t headers_offset = read_32bit(tables_offset+0x0c,streamFile); if (target_subsong == 0) target_subsong = 1; total_subsongs = 0; meta_offset = 0; /* manually find subsongs as entries can be dummy (ex. sfx banks in FF XIV or FF Type-0) */ for (i = 0; i < headers_entries; i++) { off_t entry_offset = read_32bit(headers_offset + i*0x04,streamFile); if (read_32bit(entry_offset+0x0c,streamFile) == -1) continue; /* codec -1 when dummy */ total_subsongs++; if (!meta_offset && total_subsongs == target_subsong) { meta_offset = entry_offset; target_entry = i; } } if (meta_offset == 0) goto fail; /* SCD can contain 0 entries too */ } /** stream header **/ stream_size = read_32bit(meta_offset+0x00,streamFile); channel_count = read_32bit(meta_offset+0x04,streamFile); sample_rate = read_32bit(meta_offset+0x08,streamFile); codec = read_32bit(meta_offset+0x0c,streamFile); loop_start = read_32bit(meta_offset+0x10,streamFile); loop_end = read_32bit(meta_offset+0x14,streamFile); extradata_size = read_32bit(meta_offset+0x18,streamFile); aux_chunk_count = read_32bit(meta_offset+0x1c,streamFile); /* 0x01e(2): unknown, seen in some FF XIV sfx (MSADPCM) */ loop_flag = (loop_end > 0); extradata_offset = meta_offset + 0x20; start_offset = extradata_offset + extradata_size; /* only "MARK" chunk is known (some FF XIV PS3 have "STBL" but it's not counted) */ if (aux_chunk_count > 1 && aux_chunk_count < 0xFFFF) { /* some FF XIV Heavensward IMA sfx have 0x01000000 */ VGM_LOG("SCD: unknown aux chunk count %i\n", aux_chunk_count); goto fail; } /* skips aux chunks, sometimes needed (Lightning Returns X360, FF XIV PC) */ if (aux_chunk_count && read_32bitBE(extradata_offset, streamFile) == 0x4D41524B) { /* "MARK" */ extradata_offset += read_32bit(extradata_offset+0x04, streamFile); } /* find name if possible */ if (version == 4) { int info_entries = read_16bit(tables_offset+0x00,streamFile); int headers_entries = read_16bit(tables_offset+0x04,streamFile); off_t info_offset = tables_offset+0x20; /* not very exact as table1 and table3 entries may differ in V3, not sure about V4 */ if (info_entries == headers_entries) { off_t entry_offset = read_16bit(info_offset + 0x04*target_entry,streamFile); name_offset = entry_offset+0x30; } } #ifdef VGM_USE_VORBIS /* special case using init_vgmstream_ogg_vorbis */ if (codec == 0x06) { VGMSTREAM *ogg_vgmstream; uint8_t ogg_version, ogg_byte; ogg_vorbis_meta_info_t ovmi = {0}; ovmi.meta_type = meta_SQEX_SCD; ovmi.total_subsongs = total_subsongs; /* loop values are in bytes, let init_vgmstream_ogg_vorbis find loop comments instead */ ogg_version = read_8bit(extradata_offset + 0x00, streamFile); /* 0x01(1): 0x20 in v2/3, this ogg miniheader size? */ ogg_byte = read_8bit(extradata_offset + 0x02, streamFile); /* 0x03(1): ? in v3 */ if (ogg_version == 0) { /* 0x10? header, then custom Vorbis header before regular Ogg (FF XIV PC v1) */ ovmi.stream_size = stream_size; } else { /* 0x20 header, then seek table */ size_t seek_table_size = read_32bit(extradata_offset+0x10, streamFile); size_t vorb_header_size = read_32bit(extradata_offset+0x14, streamFile); /* 0x18(4): ? (can be 0) */ if ((extradata_offset-meta_offset) + seek_table_size + vorb_header_size != extradata_size) goto fail; ovmi.stream_size = vorb_header_size + stream_size; start_offset = extradata_offset + 0x20 + seek_table_size; /* extradata_size skips vorb_header */ if (ogg_version == 2) { /* header is XOR'ed using byte (FF XIV PC) */ ovmi.decryption_callback = scd_ogg_v2_decryption_callback; ovmi.scd_xor = ogg_byte; ovmi.scd_xor_length = vorb_header_size; } else if (ogg_version == 3) { /* file is XOR'ed using table (FF XIV Heavensward PC) */ ovmi.decryption_callback = scd_ogg_v3_decryption_callback; ovmi.scd_xor = stream_size & 0xFF; /* ogg_byte not used? */ ovmi.scd_xor_length = vorb_header_size + stream_size; } else { VGM_LOG("SCD: unknown ogg_version 0x%x\n", ogg_version); } } /* actual Ogg init */ ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi); if (ogg_vgmstream && name_offset) read_string(ogg_vgmstream->stream_name, PATH_LIMIT, name_offset, streamFile); return ogg_vgmstream; } #endif /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; vgmstream->sample_rate = sample_rate; vgmstream->num_streams = total_subsongs; vgmstream->stream_size = stream_size; vgmstream->meta_type = meta_SQEX_SCD; if (name_offset) read_string(vgmstream->stream_name, PATH_LIMIT, name_offset, streamFile); switch (codec) { case 0x01: /* PCM */ vgmstream->coding_type = coding_PCM16LE; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x02; vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16); if (loop_flag) { vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, channel_count, 16); vgmstream->loop_end_sample = pcm_bytes_to_samples(loop_end, channel_count, 16); } break; case 0x03: /* PS-ADPCM [Final Fantasy Type-0] */ vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x10; vgmstream->num_samples = ps_bytes_to_samples(stream_size, channel_count); if (loop_flag) { vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, channel_count); vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, channel_count); } break; case 0x06: /* OGG [Final Fantasy XIII-2 (PC), Final Fantasy XIV (PC)] */ goto fail; /* handled above */ #ifdef VGM_USE_MPEG case 0x07: { /* MPEG [Final Fantasy XIII (PS3)] */ mpeg_codec_data *mpeg_data = NULL; mpeg_custom_config cfg = {0}; cfg.interleave = 0x800; /* for multistream [Final Fantasy XIII-2 (PS3)], otherwise ignored */ cfg.data_size = stream_size; mpeg_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_SCD, &cfg); if (!mpeg_data) goto fail; vgmstream->codec_data = mpeg_data; vgmstream->layout_type = layout_none; /* some Drakengard 3, Kingdom Hearts HD have adjusted sample rate (47999, 44099), for looping? */ vgmstream->num_samples = mpeg_bytes_to_samples(stream_size, mpeg_data); vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, mpeg_data); vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, mpeg_data); /* somehow loops offsets aren't always frame-aligned, and the code below supposedly helped, * but there isn't much difference since MPEG loops are rough (1152-aligned). Seems it * would help more loop_start - ~1000, loop_end + ~1000 (ex. FFXIII-2 music_SunMizu.ps3.scd) */ //vgmstream->num_samples -= vgmstream->num_samples % 576; //vgmstream->loop_start_sample -= vgmstream->loop_start_sample % 576; //vgmstream->loop_end_sample -= vgmstream->loop_end_sample % 576; break; } #endif case 0x0C: /* MS ADPCM [Final Fantasy XIV (PC) sfx] */ vgmstream->coding_type = coding_MSADPCM; vgmstream->layout_type = layout_none; vgmstream->interleave_block_size = read_16bit(extradata_offset+0x0c,streamFile); /* in extradata_offset is a WAVEFORMATEX (including coefs and all) */ vgmstream->num_samples = msadpcm_bytes_to_samples(stream_size, 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 0x0A: /* DSP ADPCM [Dragon Quest X (Wii)] */ case 0x15: { /* DSP ADPCM [Dragon Quest X (Wii U)] (no apparent differences except higher sample rate) */ const off_t interleave_size = 0x800; const off_t stride_size = interleave_size * channel_count; int i; size_t total_size; layered_layout_data * data = NULL; /* interleaved DSPs including the header (so the first 0x800 is 0x60 header + 0x740 data) * so interleave layout can't used; we'll setup de-interleaving streamfiles as layers/channels instead */ //todo this could be simplified using a block layout or adding interleave_first_block vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_layered; /* read from the first DSP header and verify other channel headers */ { total_size = (read_32bitBE(start_offset+0x04,streamFile)+1)/2; /* rounded nibbles / 2 */ vgmstream->num_samples = read_32bitBE(start_offset+0x00,streamFile); if (loop_flag) { vgmstream->loop_start_sample = loop_start; vgmstream->loop_end_sample = loop_end+1; } for (i = 1; i < channel_count; i++) { if ((read_32bitBE(start_offset+4,streamFile)+1)/2 != total_size || read_32bitBE(start_offset+interleave_size*i+0x00,streamFile) != vgmstream->num_samples) { goto fail; } } } /* init layout */ data = init_layout_layered(channel_count); if (!data) goto fail; vgmstream->layout_data = data; /* open each layer subfile */ for (i = 0; i < channel_count; i++) { STREAMFILE* temp_streamFile = setup_scd_dsp_streamfile(streamFile, start_offset+interleave_size*i, interleave_size, stride_size, total_size); if (!temp_streamFile) goto fail; data->layers[i] = init_vgmstream_ngc_dsp_std(temp_streamFile); close_streamfile(temp_streamFile); if (!data->layers[i]) goto fail; } /* setup layered VGMSTREAMs */ if (!setup_layout_layered(data)) goto fail; break; } #ifdef VGM_USE_FFMPEG case 0x0B: { /* XMA2 [Final Fantasy (X360), Lightning Returns (X360) sfx, Kingdom Hearts 2.8 (X1)] */ ffmpeg_codec_data *ffmpeg_data = NULL; uint8_t buf[200]; int32_t bytes; /* extradata_offset+0x00: fmt0x166 header (BE), extradata_offset+0x34: seek table */ bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,200, extradata_offset,0x34, stream_size, streamFile, 1); ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,stream_size); 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; vgmstream->loop_start_sample = loop_start; vgmstream->loop_end_sample = loop_end; xma_fix_raw_samples(vgmstream, streamFile, start_offset,stream_size, 0, 0,0); /* samples are ok, loops? */ break; } case 0x0E: { /* ATRAC3/ATRAC3plus [Lord of Arcana (PSP), Final Fantasy Type-0] */ ffmpeg_codec_data *ffmpeg_data = NULL; /* full RIFF header at start_offset/extradata_offset (same) */ 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; vgmstream->num_samples = ffmpeg_data->totalSamples; /* fact samples */ vgmstream->loop_start_sample = loop_start; vgmstream->loop_end_sample = loop_end; if (ffmpeg_data->skipSamples <= 0) /* in case FFmpeg didn't get them */ ffmpeg_set_skip_samples(ffmpeg_data, riff_get_fact_skip_samples(streamFile, start_offset)); /* SCD loop/sample values are relative (without skip samples) vs RIFF (with skip samples), no need to adjust */ break; } #endif #ifdef VGM_USE_ATRAC9 case 0x16: { /* ATRAC9 [Kingdom Hearts 2.8 (PS4)] */ atrac9_config cfg = {0}; /* post header has various typical ATRAC9 values */ cfg.channels = vgmstream->channels; cfg.config_data = read_32bit(extradata_offset+0x0c,streamFile); cfg.encoder_delay = read_32bit(extradata_offset+0x18,streamFile); vgmstream->codec_data = init_atrac9(&cfg); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_ATRAC9; vgmstream->layout_type = layout_none; vgmstream->num_samples = read_32bit(extradata_offset+0x10,streamFile); /* loop values above are also weird and ignored */ vgmstream->loop_start_sample = read_32bit(extradata_offset+0x20, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_start vgmstream->loop_end_sample = read_32bit(extradata_offset+0x24, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_end break; } #endif case -1: /* used for dummy entries */ default: VGM_LOG("SCD: unknown codec 0x%x\n", codec); goto fail; } if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; return vgmstream; fail: close_vgmstream(vgmstream); return NULL; }
int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk, struct riff_fmt_chunk * fmt, int sns, int mwv) { int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL; if (big_endian) { read_32bit = read_32bitBE; read_16bit = read_16bitBE; } else { read_32bit = read_32bitLE; read_16bit = read_16bitLE; } fmt->sample_rate = read_32bit(current_chunk+0x0c,streamFile); fmt->channel_count = read_16bit(current_chunk+0x0a,streamFile); fmt->block_size = read_16bit(current_chunk+0x14,streamFile); switch ((uint16_t)read_16bit(current_chunk+0x8,streamFile)) { case 1: /* PCM */ switch (read_16bit(current_chunk+0x16,streamFile)) { case 16: if (big_endian) { fmt->coding_type = coding_PCM16BE; } else { fmt->coding_type = coding_PCM16LE; } fmt->interleave = 2; break; case 8: fmt->coding_type = coding_PCM8_U_int; fmt->interleave = 1; break; default: goto fail; } break; case 2: /* MS ADPCM */ /* ensure 4bps */ if (read_16bit(current_chunk+0x16,streamFile)!=4) goto fail; fmt->coding_type = coding_MSADPCM; fmt->interleave = 0; break; case 0x11: /* MS IMA ADCM */ /* ensure 4bps */ if (read_16bit(current_chunk+0x16,streamFile)!=4) goto fail; fmt->coding_type = coding_MS_IMA; fmt->interleave = 0; break; case 0x69: /* MS IMA ADCM - Rayman Raving Rabbids 2 (PC) */ /* ensure 4bps */ if (read_16bit(current_chunk+0x16,streamFile)!=4) goto fail; fmt->coding_type = coding_MS_IMA; fmt->interleave = 0; break; case 0x555: /* Level-5 0x555 ADPCM */ if (!mwv) goto fail; fmt->coding_type = coding_L5_555; fmt->interleave = 0x12; break; case 0x5050: /* Ubisoft .sns uses this for DSP */ if (!sns) goto fail; fmt->coding_type = coding_NGC_DSP; fmt->interleave = 8; break; case 0xFFF0: /* */ fmt->coding_type = coding_NGC_DSP; fmt->interleave = 8; break; default: goto fail; } return 0; fail: return -1; }