VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; int loop_flag=0; int channel_count; off_t start_offset; uint8_t testBuffer[0x10]; off_t readOffset = 0; off_t loopEnd = 0; int i; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("ads",filename_extension(filename)) && strcasecmp("ss2",filename_extension(filename))) goto fail; /* check SShd Header */ if (read_32bitBE(0x00,streamFile) != 0x53536864) goto fail; /* check SSbd Header */ if (read_32bitBE(0x20,streamFile) != 0x53536264) goto fail; /* check if file is not corrupt */ if (get_streamfile_size(streamFile)<(size_t)(read_32bitLE(0x24,streamFile) + 0x28)) goto fail; /* check loop */ loop_flag = (read_32bitLE(0x1C,streamFile)!=0xFFFFFFFF); channel_count=read_32bitLE(0x10,streamFile); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->channels = read_32bitLE(0x10,streamFile); vgmstream->sample_rate = read_32bitLE(0x0C,streamFile); /* Check for Compression Scheme */ vgmstream->coding_type = coding_PSX; vgmstream->num_samples = ((read_32bitLE(0x24,streamFile)-0x40)/16*28)/vgmstream->channels; /* SS2 container with RAW Interleaved PCM */ if (read_32bitLE(0x08,streamFile)!=0x10) { vgmstream->coding_type=coding_PCM16LE; vgmstream->num_samples = read_32bitLE(0x24,streamFile)/2/vgmstream->channels; } vgmstream->interleave_block_size = read_32bitLE(0x14,streamFile); vgmstream->layout_type = layout_interleave; vgmstream->meta_type = meta_PS2_SShd; /* Get loop point values */ if(vgmstream->loop_flag) { if((read_32bitLE(0x1C,streamFile)*0x10*vgmstream->channels+0x800)==get_streamfile_size(streamFile)) { // Search for Loop Value readOffset=(off_t)get_streamfile_size(streamFile)-(4*vgmstream->interleave_block_size); do { readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); // Loop End ... if(testBuffer[0x01]==0x01) { if(loopEnd==0) loopEnd = readOffset-0x10; break; } } while (streamFile->get_offset(streamFile)<(int32_t)get_streamfile_size(streamFile)); vgmstream->loop_start_sample = 0; vgmstream->loop_end_sample = (loopEnd/(vgmstream->interleave_block_size)*vgmstream->interleave_block_size)/16*28; vgmstream->loop_end_sample += (loopEnd%vgmstream->interleave_block_size)/16*28; vgmstream->loop_end_sample /=vgmstream->channels; } else { if(read_32bitLE(0x1C,streamFile)<=vgmstream->num_samples) { vgmstream->loop_start_sample = read_32bitLE(0x18,streamFile); vgmstream->loop_end_sample = read_32bitLE(0x1C,streamFile); } else { vgmstream->loop_start_sample = (read_32bitLE(0x18,streamFile)*0x10)/16*28/vgmstream->channels;; vgmstream->loop_end_sample = (read_32bitLE(0x1C,streamFile)*0x10)/16*28/vgmstream->channels; } } } /* don't know why, but it does happen, in ps2 too :( */ if (vgmstream->loop_end_sample > vgmstream->num_samples) vgmstream->loop_end_sample = vgmstream->num_samples; start_offset=0x28; // Hack for files with start_offset = 0x800 if(get_streamfile_size(streamFile)-read_32bitLE(0x24,streamFile)>=0x800) start_offset=0x800; if((vgmstream->coding_type == coding_PSX) && (start_offset==0x28)) { start_offset=0x800; for(i=0;i<0x1f6;i+=4) { if(read_32bitLE(0x28+(i*4),streamFile)!=0) { start_offset=0x28; break; } } } /* expect pcm format allways start @ 0x800, don't know if it's true :P */ /*if(vgmstream->coding_type == coding_PCM16LE) start_offset=0x800;*/ /* open the file for reading by each channel */ { for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000); if (!vgmstream->ch[i].streamfile) goto fail; vgmstream->ch[i].channel_start_offset= vgmstream->ch[i].offset= (off_t)(start_offset+vgmstream->interleave_block_size*i); } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* BO2 (Blood Omen 2 NGC) */ VGMSTREAM * init_vgmstream_ngc_bo2(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[1024]; int loop_flag; int channels; int channel_count; off_t start_offset; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("bo2",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x0) /* "IDSP" */ goto fail; switch (read_32bitBE(0x10,streamFile)) { case 0x0: channels = 1; break; case 0x1: channels = 2; break; default: goto fail; } if ((get_streamfile_size(streamFile)) < ((read_32bitBE(0x0C,streamFile)/14*8*channels)+0x800)) { goto fail; } channel_count = channels; loop_flag = (read_32bitBE(0x08,streamFile) != 0xFFFFFFFF); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ start_offset = 0x800; vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitBE(0x04,streamFile); vgmstream->coding_type = coding_NGC_DSP; vgmstream->num_samples = read_32bitBE(0x0C,streamFile); if (loop_flag) { vgmstream->loop_start_sample = read_32bitBE(0x08,streamFile); vgmstream->loop_end_sample = read_32bitBE(0x0C,streamFile); } if (channel_count == 1) { vgmstream->layout_type = layout_none; } else { vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x400; } vgmstream->meta_type = meta_NGC_BO2; { int i; for (i=0;i<16;i++) vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x24+i*2,streamFile); if (channel_count == 2) { for (i=0;i<16;i++) vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x52+i*2,streamFile); } } /* 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; }
VGMSTREAM * init_vgmstream_ps2_npsf(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; int loop_flag=0; int channel_count; off_t start_offset; int i; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("npsf",filename_extension(filename))) goto fail; /* check NPSF Header */ if (read_32bitBE(0x00,streamFile) != 0x4E505346) goto fail; /* check loop */ loop_flag = (read_32bitLE(0x14,streamFile)!=0xFFFFFFFF); channel_count=read_32bitLE(0x0C,streamFile); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->channels = read_32bitLE(0x0C,streamFile); vgmstream->sample_rate = read_32bitLE(0x18,streamFile); /* Check for Compression Scheme */ vgmstream->coding_type = coding_PSX; vgmstream->num_samples = read_32bitLE(0x08,streamFile)*28/16; /* Get loop point values */ if(vgmstream->loop_flag) { vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile); vgmstream->loop_end_sample = read_32bitLE(0x08,streamFile)*28/16; } vgmstream->interleave_block_size = read_32bitLE(0x04,streamFile)/2; vgmstream->meta_type = meta_PS2_NPSF; start_offset = (off_t)read_32bitLE(0x10,streamFile); if (vgmstream->channels == 1) { vgmstream->layout_type = layout_none; } else { vgmstream->layout_type = layout_interleave; } /* open the file for reading by each channel */ { for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000); if (!vgmstream->ch[i].streamfile) goto fail; vgmstream->ch[i].channel_start_offset= vgmstream->ch[i].offset= (off_t)(start_offset+vgmstream->interleave_block_size*i); } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const char * filename, ov_callbacks *callbacks_p, off_t other_header_bytes, const vgm_vorbis_info_t *vgm_inf) { VGMSTREAM * vgmstream = NULL; OggVorbis_File temp_ovf; ogg_vorbis_streamfile temp_streamfile; ogg_vorbis_codec_data * data = NULL; OggVorbis_File *ovf; int inited_ovf = 0; vorbis_info *info; int loop_flag = vgm_inf->loop_flag; int32_t loop_start = vgm_inf->loop_start; int loop_length_found = vgm_inf->loop_length_found; int32_t loop_length = vgm_inf->loop_length; int loop_end_found = vgm_inf->loop_end_found; int32_t loop_end = vgm_inf->loop_end; ov_callbacks default_callbacks; if (!callbacks_p) { default_callbacks.read_func = read_func; default_callbacks.seek_func = seek_func; default_callbacks.close_func = close_func; default_callbacks.tell_func = tell_func; if (vgm_inf->scd_xor != 0) { default_callbacks.read_func = read_func_scd; } callbacks_p = &default_callbacks; } temp_streamfile.streamfile = streamFile; temp_streamfile.offset = 0; temp_streamfile.size = get_streamfile_size(temp_streamfile.streamfile); temp_streamfile.other_header_bytes = other_header_bytes; temp_streamfile.scd_xor = vgm_inf->scd_xor; temp_streamfile.scd_xor_len = vgm_inf->scd_xor_len; /* can we open this as a proper ogg vorbis file? */ memset(&temp_ovf, 0, sizeof(temp_ovf)); if (ov_test_callbacks(&temp_streamfile, &temp_ovf, NULL, 0, *callbacks_p)) goto fail; /* we have to close this as it has the init_vgmstream meta-reading STREAMFILE */ ov_clear(&temp_ovf); /* proceed to open a STREAMFILE just for this stream */ data = calloc(1,sizeof(ogg_vorbis_codec_data)); if (!data) goto fail; data->ov_streamfile.streamfile = streamFile->open(streamFile,filename, STREAMFILE_DEFAULT_BUFFER_SIZE); if (!data->ov_streamfile.streamfile) goto fail; data->ov_streamfile.offset = 0; data->ov_streamfile.size = get_streamfile_size(data->ov_streamfile.streamfile); data->ov_streamfile.other_header_bytes = other_header_bytes; data->ov_streamfile.scd_xor = vgm_inf->scd_xor; data->ov_streamfile.scd_xor_len = vgm_inf->scd_xor_len; /* open the ogg vorbis file for real */ if (ov_open_callbacks(&data->ov_streamfile, &data->ogg_vorbis_file, NULL, 0, *callbacks_p)) goto fail; ovf = &data->ogg_vorbis_file; inited_ovf = 1; data->bitstream = DEFAULT_BITSTREAM; info = ov_info(ovf,DEFAULT_BITSTREAM); /* grab the comments */ { int i; vorbis_comment *comment; comment = ov_comment(ovf,DEFAULT_BITSTREAM); /* search for a "loop_start" comment */ for (i=0;i<comment->comments;i++) { if (strstr(comment->user_comments[i],"loop_start=")== comment->user_comments[i] || strstr(comment->user_comments[i],"LOOP_START=")== comment->user_comments[i] || strstr(comment->user_comments[i],"COMMENT=LOOPPOINT=")== comment->user_comments[i] || strstr(comment->user_comments[i],"LOOPSTART=")== comment->user_comments[i] || strstr(comment->user_comments[i],"um3.stream.looppoint.start=")== comment->user_comments[i] || strstr(comment->user_comments[i],"LOOP_BEGIN=")== comment->user_comments[i] || strstr(comment->user_comments[i],"LoopStart=")== comment->user_comments[i] ) { loop_start=atol(strrchr(comment->user_comments[i],'=')+1); if (loop_start >= 0) loop_flag=1; } else if (strstr(comment->user_comments[i],"LOOPLENGTH=")== comment->user_comments[i]) { loop_length=atol(strrchr(comment->user_comments[i],'=')+1); loop_length_found=1; } else if (strstr(comment->user_comments[i],"title=-lps")== comment->user_comments[i]) { loop_start=atol(comment->user_comments[i]+10); if (loop_start >= 0) loop_flag=1; } else if (strstr(comment->user_comments[i],"album=-lpe")== comment->user_comments[i]) { loop_end=atol(comment->user_comments[i]+10); loop_flag=1; loop_end_found=1; } else if (strstr(comment->user_comments[i],"LoopEnd=")== comment->user_comments[i]) { if(loop_flag) { loop_length=atol(strrchr(comment->user_comments[i],'=')+1)-loop_start; loop_length_found=1; } } else if (strstr(comment->user_comments[i],"LOOP_END=")== comment->user_comments[i]) { if(loop_flag) { loop_length=atol(strrchr(comment->user_comments[i],'=')+1)-loop_start; loop_length_found=1; } } else if (strstr(comment->user_comments[i],"lp=")== comment->user_comments[i]) { sscanf(strrchr(comment->user_comments[i],'=')+1,"%d,%d", &loop_start,&loop_end); loop_flag=1; loop_end_found=1; } else if (strstr(comment->user_comments[i],"COMMENT=loop(")== comment->user_comments[i]) { sscanf(strrchr(comment->user_comments[i],'(')+1,"%d,%d", &loop_start,&loop_end); loop_flag=1; loop_end_found=1; } } } /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(info->channels,loop_flag); if (!vgmstream) goto fail; /* store our fun extra datas */ vgmstream->codec_data = data; /* fill in the vital statistics */ vgmstream->channels = info->channels; vgmstream->sample_rate = info->rate; /* let's play the whole file */ vgmstream->num_samples = ov_pcm_total(ovf,-1); if (loop_flag) { vgmstream->loop_start_sample = loop_start; if (loop_length_found) vgmstream->loop_end_sample = loop_start+loop_length; else if (loop_end_found) vgmstream->loop_end_sample = loop_end; else vgmstream->loop_end_sample = vgmstream->num_samples; vgmstream->loop_flag = loop_flag; if (vgmstream->loop_end_sample > vgmstream->num_samples) vgmstream->loop_end_sample = vgmstream->num_samples; } vgmstream->coding_type = coding_ogg_vorbis; vgmstream->layout_type = vgm_inf->layout_type; vgmstream->meta_type = vgm_inf->meta_type; return vgmstream; /* clean up anything we may have opened */ fail: if (data) { if (inited_ovf) ov_clear(&data->ogg_vorbis_file); if (data->ov_streamfile.streamfile) close_streamfile(data->ov_streamfile.streamfile); free(data); } if (vgmstream) { vgmstream->codec_data = NULL; close_vgmstream(vgmstream); } return NULL; }
/* PCM (from Ephemeral Fantasia) */ VGMSTREAM * init_vgmstream_pcm(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; off_t start_offset; int loop_flag; int channel_count; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("pcm",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x0C,streamFile) ==0x0AA00AA0) { loop_flag = (read_32bitLE(0x02,streamFile)!=0); channel_count = 1; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ start_offset = 0x200; vgmstream->channels = channel_count; vgmstream->sample_rate = 44100; vgmstream->coding_type = coding_PCM8_SB_int; vgmstream->num_samples = read_32bitBE(0x06,streamFile)*2; if(loop_flag) { vgmstream->loop_start_sample = read_32bitBE(0x02,streamFile)*2; vgmstream->loop_end_sample = read_32bitBE(0x06,streamFile)*2; } vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x2; vgmstream->meta_type = meta_PCM; } else if (read_32bitBE(0x410,streamFile) ==0x9CDB0740) { loop_flag = (read_32bitLE(0x0C,streamFile)!=0); channel_count = 2; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ start_offset = 0x800; vgmstream->channels = channel_count; vgmstream->sample_rate = 22050; vgmstream->coding_type = coding_PCM16LE; vgmstream->num_samples = read_32bitLE(0x4,streamFile); if(loop_flag == 1) { vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile); vgmstream->loop_end_sample = read_32bitLE(0x0C,streamFile); } vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x2; vgmstream->meta_type = meta_PCM; } else if ((read_32bitBE(0x0,streamFile) ==0x786D6402) || (read_32bitBE(0x0,streamFile) ==0x786D6401)) { loop_flag = 0; channel_count = read_8bit(0x03,streamFile); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ start_offset = 0x10; vgmstream->channels = channel_count; vgmstream->sample_rate = (int32_t)(read_16bitLE(0x4,streamFile) & 0x0000ffff); vgmstream->coding_type = coding_PCM8_int; vgmstream->num_samples = read_32bitLE(0x6,streamFile); if(loop_flag == 1) { vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile); vgmstream->loop_end_sample = read_32bitLE(0x0C,streamFile); } vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x8; vgmstream->meta_type = meta_PCM; } else goto fail; /* 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; }
/* BGW - from Final Fantasy XI (PC) music files */ VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; STREAMFILE *temp_streamFile = NULL; uint32_t codec, file_size, block_size, sample_rate, block_align; int32_t loop_start; off_t start_offset; int channel_count, loop_flag = 0; /* check extensions */ if ( !check_extensions(streamFile, "bgw") ) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x42474d53 || /* "BGMS" */ read_32bitBE(0x04,streamFile) != 0x74726561 || /* "trea" */ read_32bitBE(0x08,streamFile) != 0x6d000000 ) /* "m\0\0\0" */ goto fail; codec = read_32bitLE(0x0c,streamFile); file_size = read_32bitLE(0x10,streamFile); /*file_id = read_32bitLE(0x14,streamFile);*/ block_size = read_32bitLE(0x18,streamFile); loop_start = read_32bitLE(0x1c,streamFile); sample_rate = (read_32bitLE(0x20,streamFile) + read_32bitLE(0x24,streamFile)) & 0x7FFFFFFF; /* bizarrely obfuscated sample rate */ start_offset = read_32bitLE(0x28,streamFile); /*0x2c: unk (vol?) */ /*0x2d: unk (0x10?) */ channel_count = read_8bit(0x2e,streamFile); block_align = (uint8_t)read_8bit(0x2f,streamFile); if (file_size != get_streamfile_size(streamFile)) goto fail; loop_flag = (loop_start > 0); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; vgmstream->meta_type = meta_FFXI_BGW; vgmstream->sample_rate = sample_rate; switch (codec) { case 0: /* PS ADPCM */ vgmstream->coding_type = coding_PSX_cfg; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = (block_align / 2) + 1; /* half, even if channels = 1 */ vgmstream->num_samples = block_size * block_align; if (loop_flag) { vgmstream->loop_start_sample = (loop_start-1) * block_align; vgmstream->loop_end_sample = vgmstream->num_samples; } break; #ifdef VGM_USE_FFMPEG case 3: { /* ATRAC3 (encrypted) */ uint8_t buf[0x100]; int bytes, joint_stereo, skip_samples; size_t data_size = file_size - start_offset; vgmstream->num_samples = block_size; /* atrac3_bytes_to_samples gives the same value */ if (loop_flag) { vgmstream->loop_start_sample = loop_start; vgmstream->loop_end_sample = vgmstream->num_samples; } block_align = 0xC0 * vgmstream->channels; /* 0x00 in header */ joint_stereo = 0; skip_samples = 0; bytes = ffmpeg_make_riff_atrac3(buf, 0x100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_align, joint_stereo, skip_samples); if (bytes <= 0) goto fail; temp_streamFile = setup_bgw_atrac3_streamfile(streamFile, start_offset,data_size, 0xC0,channel_count); if (!temp_streamFile) goto fail; vgmstream->codec_data = init_ffmpeg_header_offset(temp_streamFile, buf,bytes, 0,data_size); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; close_streamfile(temp_streamFile); break; } #endif default: goto fail; } if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; return vgmstream; fail: close_streamfile(temp_streamFile); close_vgmstream(vgmstream); return NULL; }
/* Old MUSX format, this one handles "Sphinx and the cursed Mummy", it's different from the other formats */ VGMSTREAM * init_vgmstream_musx_v201(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; off_t start_offset; //int musx_version; /* 0x08 provides a "version" byte */ int loop_flag; int channel_count; int loop_detect; int loop_offsets; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("musx",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */ goto fail; if (read_32bitBE(0x08,streamFile) != 0xC9000000) /* "0xC9000000" */ goto fail; channel_count = 2; loop_detect = read_32bitBE(0x800,streamFile); switch (loop_detect) { case 0x02000000: loop_offsets = 0x8E0; break; case 0x03000000: loop_offsets = 0x880; break; case 0x04000000: loop_offsets = 0x8B4; break; case 0x05000000: loop_offsets = 0x8E8; break; case 0x06000000: loop_offsets = 0x91C; break; default: goto fail; } loop_flag = (read_32bitLE(loop_offsets+0x04,streamFile) !=0x00000000); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ start_offset = read_32bitLE(0x18,streamFile); vgmstream->channels = channel_count; vgmstream->sample_rate = 32000; vgmstream->coding_type = coding_PSX; vgmstream->num_samples = read_32bitLE(loop_offsets,streamFile)*28/16/channel_count; if (loop_flag) { vgmstream->loop_start_sample = read_32bitLE(loop_offsets+0x10,streamFile)*28/16/channel_count; vgmstream->loop_end_sample = read_32bitLE(loop_offsets,streamFile)*28/16/channel_count; } vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x80; vgmstream->meta_type = meta_MUSX_V201; /* 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; }
/* IVAG - The Idolm@ster: Gravure For You! Vol. 3 (PS3) Appears to be two VAGp streams interleaved. */ VGMSTREAM * init_vgmstream_ps3_ivag(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; size_t fileLength; off_t readOffset = 0; off_t start_offset; int loop_flag = 0; int channel_count; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("ivag",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x49564147) // "IVAG" goto fail; // channel count channel_count = read_32bitBE(0x08, streamFile); // header size start_offset = 0x40 + (0x40 * channel_count); // loop flag if ((read_32bitBE(0x14, streamFile) != 0 || (read_32bitBE(0x18, streamFile) != 0))) { loop_flag = 1; } /* 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_32bitBE(0x0C,streamFile); vgmstream->coding_type = coding_PSX; vgmstream->num_samples = read_32bitBE(0x10,streamFile); if (loop_flag) { vgmstream->loop_start_sample = read_32bitBE(0x14,streamFile); vgmstream->loop_end_sample = read_32bitBE(0x18,streamFile); } vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = read_32bitBE(0x1C,streamFile); vgmstream->meta_type = meta_PS3_IVAG; /* 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; }
/* manakoAT 28.01.2009 : BAKA - found in "Crypt Killer (Saturn)... looks like some developers were really bored, every file starts with the word "BAKA" which is the japanese word for "IDIOT" :o) Files containing "begloop" markers at EOF... some files should loop, but i don't know how to get the loopstart here!*/ VGMSTREAM * init_vgmstream_sat_baka(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; off_t start_offset; int loop_flag = 0; int channel_count; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("baka",filename_extension(filename))) goto fail; /* check header */ if ((read_32bitBE(0x00,streamFile) != 0x42414B41 && /* "BAKA" */ read_32bitBE(0x08,streamFile) != 0x2041484F && /* " AHO" */ read_32bitBE(0x0C,streamFile) != 0x50415041 && /* "PAPA" */ read_32bitBE(0x26,streamFile) != 0x4D414D41)) /* "MAMA" */ goto fail; channel_count = 2; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ start_offset = 0x2E; vgmstream->channels = channel_count; vgmstream->sample_rate = 44100; vgmstream->coding_type = coding_PCM16BE; vgmstream->num_samples = read_32bitBE(0x16,streamFile); if (loop_flag) { vgmstream->loop_start_sample = 0; vgmstream->loop_end_sample = read_32bitBE(0x16,streamFile); } vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x2; vgmstream->meta_type = meta_SAT_BAKA; /* 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; }
/* VS (from Men in Black) */ VGMSTREAM * init_vgmstream_vs(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; off_t start_offset; int loop_flag = 0; int channel_count; int i; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("vs",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0xC8000000) /* "0xC8000000" */ goto fail; loop_flag = 0; channel_count = 2; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ start_offset = 0x08; vgmstream->channels = channel_count; vgmstream->interleave_block_size=0x10; vgmstream->sample_rate = read_32bitLE(0x04,streamFile); vgmstream->coding_type = coding_PSX; #if 0 if (loop_flag) { vgmstream->loop_start_sample = 0; vgmstream->loop_end_sample = (read_32bitLE(0x0c,streamFile)-start_offset); } #endif vgmstream->layout_type = layout_vs_blocked; vgmstream->meta_type = meta_VS; /* open the file for reading */ { for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x2000); if (!vgmstream->ch[i].streamfile) goto fail; } } /* Calc num_samples */ vs_block_update(start_offset,vgmstream); vgmstream->num_samples=0; do { vgmstream->num_samples += vgmstream->current_block_size*28/16; vs_block_update(vgmstream->next_block_offset,vgmstream); } while (vgmstream->next_block_offset<get_streamfile_size(streamFile)); vs_block_update(start_offset,vgmstream); return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* KCES (from Dance Dance Revolution) */ VGMSTREAM * init_vgmstream_ps2_kces(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; off_t start_offset; int loop_flag = 0; int channel_count; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("kces",filename_extension(filename)) && strcasecmp("vig",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x01006408) goto fail; loop_flag = 0; /* (read_32bitLE(0x08,streamFile)!=0); */ channel_count = read_32bitLE(0x1C,streamFile); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ start_offset = read_32bitLE(0x08,streamFile); vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitLE(0x18,streamFile); vgmstream->coding_type = coding_PSX; vgmstream->num_samples = read_32bitLE(0x0C,streamFile)*28/16/channel_count; if (loop_flag) { vgmstream->loop_start_sample = 0; vgmstream->loop_end_sample = read_32bitLE(0x0C,streamFile)*28/16/channel_count; } if(vgmstream->channels==1) { vgmstream->layout_type=layout_none; } else { vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = read_32bitLE(0x24,streamFile); } vgmstream->meta_type = meta_PS2_KCES; /* 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; }
/* 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; }
VGMSTREAM * init_vgmstream_bfstm(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; coding_t coding_type; off_t head_offset; off_t seek_offset; off_t data_offset; int codec_number; int channel_count; int loop_flag; int ima = 0; off_t start_offset; int founddata; off_t tempoffset1; /* check extension, case insensitive */ streamFile->get_name(streamFile, filename, sizeof(filename)); if (strcasecmp("bfstm", filename_extension(filename))) goto fail; /* check header */ if ((uint32_t)read_32bitBE(0, streamFile) != 0x4653544D) /* "FSTM" */ goto fail; if ((uint32_t)read_32bitBE(4, streamFile) != 0xFEFF0040 && (uint32_t)read_32bitBE(4, streamFile) != 0xFEFF0060) goto fail; founddata = 0; tempoffset1 = 0x8; while (!(founddata)) { if ((uint32_t)read_32bitBE(tempoffset1, streamFile) == 0x40020000) { data_offset = read_32bitBE(tempoffset1 + 4, streamFile); founddata++; break; } tempoffset1++; } /* get head offset, check */ head_offset = read_32bitBE(0x18, streamFile); if ((uint32_t)read_32bitBE(head_offset, streamFile) != 0x494E464F) /* "INFO" */ goto fail; seek_offset = read_32bitBE(0x24, streamFile); /* check type details */ codec_number = read_8bit(head_offset + 0x20, streamFile); loop_flag = read_8bit(head_offset + 0x21, streamFile); channel_count = read_8bit(head_offset + 0x22, streamFile); switch (codec_number) { case 0: coding_type = coding_PCM8; break; case 1: coding_type = coding_PCM16BE; break; case 2: coding_type = coding_NGC_DSP; 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 */ vgmstream->num_samples = read_32bitBE(head_offset + 0x2c, streamFile); vgmstream->sample_rate = (uint16_t)read_16bitBE(head_offset + 0x26, streamFile); /* channels and loop flag are set by allocate_vgmstream */ if (ima) //Shift the loop points back slightly to avoid stupid pops in some IMA streams due to DC offsetting { vgmstream->loop_start_sample = read_32bitBE(head_offset + 0x28, streamFile); if (vgmstream->loop_start_sample > 10000) { vgmstream->loop_start_sample -= 5000; vgmstream->loop_end_sample = vgmstream->num_samples - 5000; } else vgmstream->loop_end_sample = vgmstream->num_samples; } else { vgmstream->loop_start_sample = read_32bitBE(head_offset + 0x28, streamFile); vgmstream->loop_end_sample = vgmstream->num_samples; } vgmstream->coding_type = coding_type; if (channel_count == 1) vgmstream->layout_type = layout_none; else { if (ima) vgmstream->layout_type = layout_interleave; else vgmstream->layout_type = layout_interleave_shortblock; } vgmstream->meta_type = meta_FSTM; if (ima) vgmstream->interleave_block_size = 0x200; else { vgmstream->interleave_block_size = read_32bitBE(head_offset + 0x34, streamFile); vgmstream->interleave_smallblock_size = read_32bitBE(head_offset + 0x44, streamFile); } if (vgmstream->coding_type == coding_NGC_DSP) { off_t coef_offset; off_t tempoffset2 = head_offset; int foundcoef = 0; int i, j; int coef_spacing = 0x2E; while (!(foundcoef)) { if ((uint32_t)read_32bitBE(tempoffset2, streamFile) == 0x41020000) { coef_offset = read_32bitBE(tempoffset2 + 4, streamFile) + tempoffset2 + (channel_count * 8) - 4 - head_offset; foundcoef++; break; } tempoffset2++; } for (j = 0; j<vgmstream->channels; j++) { for (i = 0; i<16; i++) { vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(head_offset + coef_offset + j*coef_spacing + i * 2, streamFile); } } } if (ima) // No SEEK (ADPC) header, so just start where the SEEK header is supposed to be. start_offset = seek_offset; else if (vgmstream->coding_type == coding_NGC_DSP) start_offset = data_offset + 0x20; else // No SEEK header and not IMA, so just start after the DATA header start_offset = 0x120; /* open the file for reading by each channel */ { int i; 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; } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
VGMSTREAM * init_vgmstream_ps2_str(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; STREAMFILE * infileSTH = NULL; char filename[260]; char * filenameSTH = NULL; int i, channel_count, loop_flag; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("str",filename_extension(filename))) goto fail; /* check for .MIH file */ filenameSTH=(char *)malloc(strlen(filename)+1); if (!filenameSTH) goto fail; strcpy(filenameSTH,filename); strcpy(filenameSTH+strlen(filenameSTH)-3,"STH"); infileSTH = streamFile->open(streamFile,filenameSTH,STREAMFILE_DEFAULT_BUFFER_SIZE); /* STH File is necessary, so we can't confuse those file */ /* with others .STR file as it is a very common extension */ if (!infileSTH) goto fail; if((read_32bitLE(0x2C,infileSTH)==0x07) || (read_32bitLE(0x2C,infileSTH)==0x06)) channel_count=2; if(read_32bitLE(0x2C,infileSTH)==0x05) channel_count=1; loop_flag = read_32bitLE(0x2C,infileSTH) & 0x01; /* 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_32bitLE(0x24,infileSTH); vgmstream->interleave_block_size=0x4000; if(read_32bitLE(0x40,infileSTH)==0x01) vgmstream->interleave_block_size = 0x8000; vgmstream->num_samples=read_32bitLE(0x20,infileSTH); vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_interleave; vgmstream->meta_type = meta_PS2_STR; if(loop_flag) { vgmstream->loop_start_sample = 0; vgmstream->loop_end_sample = read_32bitLE(0x20,infileSTH); } close_streamfile(infileSTH); infileSTH=NULL; /* open the file for reading by each channel */ { for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size); if (!vgmstream->ch[i].streamfile) goto fail; vgmstream->ch[i].channel_start_offset= vgmstream->ch[i].offset+=(off_t)(vgmstream->interleave_block_size*i); } } return vgmstream; /* clean up anything we may have opened */ fail: if (infileSTH) close_streamfile(infileSTH); if (filenameSTH) {free(filenameSTH); filenameSTH=NULL;} if (vgmstream) close_vgmstream(vgmstream); return NULL; }
VGMSTREAM * init_vgmstream_Cstr(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; int loop_flag; off_t start_offset; off_t first_data; off_t loop_offset; size_t interleave; int loop_adjust; int double_loop_end = 0; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("dsp",filename_extension(filename))) goto fail; /* check header */ if ((uint32_t)read_32bitBE(0,streamFile)!=0x43737472) /* "Cstr" */ goto fail; #ifdef DEBUG fprintf(stderr,"header ok\n"); #endif if (read_8bit(0x1b,streamFile)==1) { /* mono version, much simpler to handle */ /* Only seen in R Racing Evolution radio sfx */ start_offset = 0x80; loop_flag = read_16bitBE(0x2c,streamFile); /* check initial predictor/scale */ if (read_16bitBE(0x5e,streamFile) != (uint8_t)read_8bit(start_offset,streamFile)) goto fail; /* check type==0 and gain==0 */ if (read_16bitBE(0x2e,streamFile) || read_16bitBE(0x5c,streamFile)) goto fail; loop_offset = start_offset+read_32bitBE(0x10,streamFile); if (loop_flag) { if (read_16bitBE(0x64,streamFile) != (uint8_t)read_8bit(loop_offset,streamFile)) goto fail; } /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(1,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->sample_rate = read_32bitBE(0x28,streamFile); vgmstream->num_samples = read_32bitBE(0x20,streamFile); if (loop_flag) { vgmstream->loop_start_sample = dsp_nibbles_to_samples( read_32bitBE(0x30,streamFile)); vgmstream->loop_end_sample = dsp_nibbles_to_samples( read_32bitBE(0x34,streamFile))+1; } vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_DSP_CSTR; { int i; for (i=0; i<16; i++) vgmstream->ch[0].adpcm_coef[i]=read_16bitBE(0x3c+i*2,streamFile); } /* open the file for reading by each channel */ vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!vgmstream->ch[0].streamfile) goto fail; vgmstream->ch[0].channel_start_offset= vgmstream->ch[0].offset= start_offset; return vgmstream; } /* end mono */ interleave = read_16bitBE(0x06,streamFile); start_offset = 0xe0; first_data = start_offset+read_32bitBE(0x0c,streamFile); loop_flag = read_16bitBE(0x2c,streamFile); if (!loop_flag) { /* Nonlooped tracks seem to follow no discernable pattern * with where they actually start. * But! with the magic of initial p/s redundancy, we can guess. */ while (first_data<start_offset+0x800 && (read_16bitBE(0x5e,streamFile) != (uint8_t)read_8bit(first_data,streamFile) || read_16bitBE(0xbe,streamFile) != (uint8_t)read_8bit(first_data+interleave,streamFile))) first_data+=8; #ifdef DEBUG fprintf(stderr,"guessed first_data at %#x\n",first_data); #endif } /* check initial predictor/scale */ if (read_16bitBE(0x5e,streamFile) != (uint8_t)read_8bit(first_data,streamFile)) goto fail; if (read_16bitBE(0xbe,streamFile) != (uint8_t)read_8bit(first_data+interleave,streamFile)) goto fail; #ifdef DEBUG fprintf(stderr,"p/s ok\n"); #endif /* check type==0 and gain==0 */ if (read_16bitBE(0x2e,streamFile) || read_16bitBE(0x5c,streamFile)) goto fail; if (read_16bitBE(0x8e,streamFile) || read_16bitBE(0xbc,streamFile)) goto fail; #ifdef DEBUG fprintf(stderr,"type & gain ok\n"); #endif /* check for loop flag agreement */ if (read_16bitBE(0x2c,streamFile) != read_16bitBE(0x8c,streamFile)) goto fail; #ifdef DEBUG fprintf(stderr,"loop flags agree\n"); #endif loop_offset = start_offset+read_32bitBE(0x10,streamFile)*2; if (loop_flag) { int loops_ok=0; /* check loop predictor/scale */ /* some fuzz allowed */ for (loop_adjust=0; loop_adjust>=-0x10; loop_adjust-=8) { #ifdef DEBUG fprintf(stderr,"looking for loop p/s at %#x,%#x\n",loop_offset-interleave+loop_adjust,loop_offset+loop_adjust); #endif if (read_16bitBE(0x64,streamFile) == (uint8_t)read_8bit(loop_offset-interleave+loop_adjust,streamFile) && read_16bitBE(0xc4,streamFile) == (uint8_t)read_8bit(loop_offset+loop_adjust,streamFile)) { loops_ok=1; break; } } if (!loops_ok) for (loop_adjust=interleave; loop_adjust<=interleave+0x10; loop_adjust+=8) { #ifdef DEBUG fprintf(stderr,"looking for loop p/s at %#x,%#x\n",loop_offset-interleave+loop_adjust,loop_offset+loop_adjust); #endif if (read_16bitBE(0x64,streamFile) == (uint8_t)read_8bit(loop_offset-interleave+loop_adjust,streamFile) && read_16bitBE(0xc4,streamFile) == (uint8_t)read_8bit(loop_offset+loop_adjust,streamFile)) { loops_ok=1; break; } } if (!loops_ok) goto fail; #ifdef DEBUG fprintf(stderr,"loop p/s ok (with %#4x adjust)\n",loop_adjust); #endif /* check for agreement */ /* loop end (channel 1 & 2 headers) */ if (read_32bitBE(0x34,streamFile) != read_32bitBE(0x94,streamFile)) goto fail; /* Mr. Driller oddity */ if (dsp_nibbles_to_samples(read_32bitBE(0x34,streamFile)*2)+1 <= read_32bitBE(0x20,streamFile)) { #ifdef DEBUG fprintf(stderr,"loop end <= half total samples, should be doubled\n"); #endif double_loop_end = 1; } /* loop start (Cstr header and channel 1 header) */ if (read_32bitBE(0x30,streamFile) != read_32bitBE(0x10,streamFile) #if 0 /* this particular glitch only true for SFA, though it * seems like something similar happens in Donkey Konga */ /* loop start (Cstr, channel 1 & 2 headers) */ || (read_32bitBE(0x0c,streamFile)+read_32bitLE(0x30,streamFile)) != read_32bitBE(0x90,streamFile) #endif ) /* alternatively (Donkey Konga) the header loop is 0x0c+0x10 */ if ( /* loop start (Cstr header and channel 1 header) */ read_32bitBE(0x30,streamFile) != read_32bitBE(0x10,streamFile)+ read_32bitBE(0x0c,streamFile)) /* further alternatively (Donkey Konga), if we loop back to * the very first frame 0x30 might be 0x00000002 (which * is a *valid* std dsp loop start, imagine that) while 0x10 * is 0x00000000 */ if (!(read_32bitBE(0x30,streamFile) == 2 && read_32bitBE(0x10,streamFile) == 0)) /* lest there be too few alternatives, in Mr. Driller we * find that [0x30] + [0x0c] + 8 = [0x10]*2 */ if (!(double_loop_end && read_32bitBE(0x30,streamFile) + read_32bitBE(0x0c,streamFile) + 8 == read_32bitBE(0x10,streamFile)*2)) goto fail; #ifdef DEBUG fprintf(stderr,"loop points agree\n"); #endif } /* assure that sample counts, sample rates agree */ if ( /* sample count (channel 1 & 2 headers) */ read_32bitBE(0x20,streamFile) != read_32bitBE(0x80,streamFile) || /* sample rate (channel 1 & 2 headers) */ read_32bitBE(0x28,streamFile) != read_32bitBE(0x88,streamFile) || /* sample count (Cstr header and channel 1 header) */ read_32bitLE(0x14,streamFile) != read_32bitBE(0x20,streamFile) || /* sample rate (Cstr header and channel 1 header) */ (uint16_t)read_16bitLE(0x18,streamFile) != read_32bitBE(0x28,streamFile)) goto fail; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(2,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->sample_rate = read_32bitBE(0x28,streamFile); /* This is a slight hack to counteract their hack. * All the data is ofset by first_data so that the loop * point occurs at a block boundary. However, I always begin decoding * right after the header, as that is the start of the first block and * my interleave code relies on starting at the beginning of a block. * So we decode a few silent samples at the beginning, and here we make up * for it by lengthening the track by that much. */ vgmstream->num_samples = read_32bitBE(0x20,streamFile) + (first_data-start_offset)/8*14; if (loop_flag) { off_t loop_start_bytes = loop_offset-start_offset-interleave; vgmstream->loop_start_sample = dsp_nibbles_to_samples((loop_start_bytes/(2*interleave)*interleave+loop_start_bytes%(interleave*2))*2); /*dsp_nibbles_to_samples(loop_start_bytes);*/ /*dsp_nibbles_to_samples(read_32bitBE(0x30,streamFile)*2-inter);*/ vgmstream->loop_end_sample = dsp_nibbles_to_samples( read_32bitBE(0x34,streamFile))+1; if (double_loop_end) vgmstream->loop_end_sample = dsp_nibbles_to_samples(read_32bitBE(0x34,streamFile)*2)+1; if (vgmstream->loop_end_sample > vgmstream->num_samples) { #ifdef DEBUG fprintf(stderr,"loop_end_sample > num_samples, adjusting\n"); #endif vgmstream->loop_end_sample = vgmstream->num_samples; } } vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = interleave; vgmstream->meta_type = meta_DSP_CSTR; { int i; for (i=0; i<16; i++) vgmstream->ch[0].adpcm_coef[i]=read_16bitBE(0x3c+i*2,streamFile); for (i=0; i<16; i++) vgmstream->ch[1].adpcm_coef[i]=read_16bitBE(0x9c+i*2,streamFile); } #ifdef DEBUG vgmstream->ch[0].loop_history1 = read_16bitBE(0x66,streamFile); vgmstream->ch[0].loop_history2 = read_16bitBE(0x68,streamFile); vgmstream->ch[1].loop_history1 = read_16bitBE(0xc6,streamFile); vgmstream->ch[1].loop_history2 = read_16bitBE(0xc8,streamFile); #endif /* open the file for reading by each channel */ { int i; for (i=0; i<2; i++) { vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,interleave); if (!vgmstream->ch[i].streamfile) goto fail; vgmstream->ch[i].channel_start_offset= vgmstream->ch[i].offset= start_offset+interleave*i; } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* PDT - Custom Generated File (Mario Party) */ VGMSTREAM * init_vgmstream_ngc_pdt(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; int loop_flag; int channel_count; off_t start_offset; int second_channel_start = -1; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("pdt",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x50445420) /* "PDT " */ goto fail; if (read_32bitBE(0x04,streamFile) != 0x44535020) /* "DSP " */ goto fail; if (read_32bitBE(0x08,streamFile) != 0x48454144) /* "HEAD " */ goto fail; if (read_16bitBE(0x0C,streamFile) != 0x4552) /* "ER " */ goto fail; loop_flag = (read_32bitBE(0x1C,streamFile)!=2); channel_count = (uint16_t)(read_16bitLE(0x0E,streamFile)); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ start_offset = 0x800; vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitBE(0x14,streamFile); vgmstream->coding_type = coding_NGC_DSP; if (channel_count == 1) { vgmstream->num_samples = read_32bitBE(0x18,streamFile)*14/8/channel_count/2; if (loop_flag) { vgmstream->loop_start_sample = read_32bitBE(0x1C,streamFile)*14/8/channel_count/2; vgmstream->loop_end_sample = read_32bitBE(0x18,streamFile)*14/8/channel_count/2; } } else if (channel_count == 2) { vgmstream->num_samples = read_32bitBE(0x18,streamFile)*14/8/channel_count; if (loop_flag) { vgmstream->loop_start_sample = read_32bitBE(0x1C,streamFile)*14/8/channel_count; vgmstream->loop_end_sample = read_32bitBE(0x18,streamFile)*14/8/channel_count; } second_channel_start = (get_streamfile_size(streamFile)+start_offset)/2; } else { goto fail; } vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_NGC_PDT; if (vgmstream->coding_type == coding_NGC_DSP) { int i; for (i=0;i<16;i++) { vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x50+i*2,streamFile); } if (vgmstream->channels == 2) { for (i=0;i<16;i++) { vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x70+i*2,streamFile); } } } /* 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[0].channel_start_offset=start_offset; if (channel_count == 2) { if (second_channel_start == -1) goto fail; vgmstream->ch[1].channel_start_offset=second_channel_start; } vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset; } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* SPW (SEWave) - from PlayOnline viewer for Final Fantasy XI (PC) */ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; uint32_t codec, file_size, block_size, sample_rate, block_align; int32_t loop_start; off_t start_offset; int channel_count, loop_flag = 0; /* check extensions */ if ( !check_extensions(streamFile, "spw") ) goto fail; /* check header */ if (read_32bitBE(0,streamFile) != 0x53655761 || /* "SeWa" */ read_32bitBE(4,streamFile) != 0x76650000) /* "ve\0\0" */ goto fail; file_size = read_32bitLE(0x08,streamFile); codec = read_32bitLE(0x0c,streamFile); /*file_id = read_32bitLE(0x10,streamFile);*/ block_size = read_32bitLE(0x14,streamFile); loop_start = read_32bitLE(0x18,streamFile); sample_rate = (read_32bitLE(0x1c,streamFile) + read_32bitLE(0x20,streamFile)) & 0x7FFFFFFF; /* bizarrely obfuscated sample rate */ start_offset = read_32bitLE(0x24,streamFile); /*0x2c: unk (0x00?) */ /*0x2d: unk (0x00/01?) */ channel_count = read_8bit(0x2a,streamFile); block_align = read_8bit(0x2b,streamFile); /*0x2c: unk (0x01 when PCM, 0x10 when VAG?) */ if (file_size != get_streamfile_size(streamFile)) goto fail; loop_flag = (loop_start > 0); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; vgmstream->meta_type = meta_FFXI_SPW; vgmstream->sample_rate = sample_rate; switch (codec) { case 0: /* PS ADPCM */ vgmstream->coding_type = coding_PSX_cfg; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = (block_align / 2) + 1; /* half, even if channels = 1 */ vgmstream->num_samples = block_size * block_align; if (loop_flag) { vgmstream->loop_start_sample = (loop_start-1) * block_align;; vgmstream->loop_end_sample = vgmstream->num_samples; } break; case 1: /* PCM */ vgmstream->coding_type = coding_PCM16LE; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x02; vgmstream->num_samples = block_size; if (loop_flag) { vgmstream->loop_start_sample = (loop_start-1); vgmstream->loop_end_sample = vgmstream->num_samples; } break; default: goto fail; } /* open the file for reading */ if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; return vgmstream; fail: close_vgmstream(vgmstream); return NULL; }
VGMSTREAM * init_vgmstream_ps2_p2bt(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; int loop_flag=0; int channel_count; off_t start_offset; int i; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("p2bt",filename_extension(filename))) goto fail; if((read_32bitBE(0x00,streamFile)!=0x4d4F5645) && // MOVE (read_32bitBE(0x00,streamFile)!=0x50324254)) // P2BT goto fail; /* check loop */ loop_flag = (read_32bitLE(0x0C,streamFile)!=0); channel_count=read_32bitLE(0x20,streamFile); /* 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_32bitLE(0x08,streamFile);; /* Check for Compression Scheme */ vgmstream->coding_type = coding_PSX; vgmstream->num_samples = read_32bitLE(0x10,streamFile)/16*28/vgmstream->channels; /* Get loop point values */ if(vgmstream->loop_flag) { vgmstream->loop_start_sample = read_32bitLE(0x0C,streamFile)/16*28/vgmstream->channels; vgmstream->loop_end_sample = vgmstream->num_samples; } vgmstream->interleave_block_size = read_32bitLE(0x14,streamFile);; vgmstream->layout_type = layout_interleave; vgmstream->meta_type = meta_PS2_P2BT; start_offset = (off_t)0x800; /* open the file for reading by each channel */ { for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size); if (!vgmstream->ch[i].streamfile) goto fail; vgmstream->ch[i].channel_start_offset= vgmstream->ch[i].offset= (off_t)(start_offset+vgmstream->interleave_block_size*i); } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* New MUSX formats, found in Quantum of Solace, The Mummy 3, possibly more */ VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; off_t start_offset; int musx_type; /* determining the decoder by strings like "PS2_", "GC__" and so on */ //int musx_version; /* 0x08 provides a "version" byte */ int loop_flag = 0; int channel_count; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("musx",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */ goto fail; if (read_32bitBE(0x08,streamFile) != 0x0A000000) /* "0x0A000000" */ goto fail; loop_flag = (read_32bitLE(0x34,streamFile)!=0x00000000); channel_count = 2; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ musx_type=(read_32bitBE(0x10,streamFile)); switch (musx_type) { case 0x5053325F: /* PS2_ */ start_offset = 0x800; vgmstream->channels = channel_count; vgmstream->sample_rate = 32000; vgmstream->coding_type = coding_PSX; vgmstream->num_samples = read_32bitLE(0x40,streamFile); vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x80; vgmstream->meta_type = meta_MUSX_V010; if (loop_flag) { vgmstream->loop_start_sample = read_32bitLE(0x44,streamFile); vgmstream->loop_end_sample = read_32bitLE(0x40,streamFile); } break; default: goto fail; } /* 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; }
/* ZWDSP (hcs' custom DSP files from Zack & Wiki) */ VGMSTREAM * init_vgmstream_zwdsp(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; off_t start_offset; int loop_flag; int channel_count; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("zwdsp",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x00000000) /* 0x0 */ goto fail; /* Retrieve the loop flag, some files have 0x0 and some 0x02 as "no loop" */ switch (read_32bitBE(0x10, streamFile)) { case 0: case 2: loop_flag = 0; break; default: loop_flag = 1; } channel_count = read_32bitBE(0x1C,streamFile); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ start_offset = 0x90; vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitBE(0x08,streamFile); vgmstream->coding_type = coding_NGC_DSP; vgmstream->num_samples = read_32bitBE(0x18,streamFile)*14/8/channel_count; if (loop_flag) { vgmstream->loop_start_sample = read_32bitBE(0x10,streamFile)*14/8/channel_count; vgmstream->loop_end_sample = read_32bitBE(0x14,streamFile)*14/8/channel_count; } vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_ZWDSP; if (vgmstream->coding_type == coding_NGC_DSP) { int i; for (i=0;i<16;i++) { vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x20+i*2,streamFile); } if (vgmstream->channels == 2) { for (i=0;i<16;i++) { vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x60+i*2,streamFile); } } } /* 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+ ((get_streamfile_size(streamFile)-start_offset)/2)*i; } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* Old MUSX formats, found in Spyro, Ty and other games */ VGMSTREAM * init_vgmstream_musx_v004(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; off_t start_offset; int musx_type; /* determining the decoder by strings like "PS2_", "GC__" and so on */ //int musx_version; /* 0x08 provides a "version" byte */ int loop_flag = 0; int channel_count; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("musx",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */ goto fail; if (read_32bitBE(0x08,streamFile) != 0x04000000) /* "0x04000000" */ goto fail; /* This is tricky, the header changes it's layout if the file is unlooped */ loop_flag = (read_32bitLE(0x840,streamFile)!=0xFFFFFFFF); channel_count = 2; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ musx_type=(read_32bitBE(0x10,streamFile)); switch (musx_type) { case 0x5053325F: /* PS2_ */ start_offset = read_32bitLE(0x28,streamFile); vgmstream->channels = channel_count; vgmstream->sample_rate = 32000; vgmstream->coding_type = coding_PSX; vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))*28/16/channel_count; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x80; vgmstream->meta_type = meta_MUSX_V004; if (loop_flag) { vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))*28/16/channel_count; vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))*28/16/channel_count; } break; /* seems to not work for Spyro, maybe i find other games for testing case 0x58425F5F: XB__ start_offset = read_32bitLE(0x28,streamFile); vgmstream->channels = channel_count; vgmstream->sample_rate = 32000; vgmstream->coding_type = coding_XBOX; vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))*64/36/channel_count; vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_MUSX_V004; if (loop_flag) { vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))*64/36/channel_count; vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))*64/36/channel_count; } break; */ default: goto fail; } /* 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; if (vgmstream->coding_type == coding_XBOX) { /* xbox interleaving is a little odd */ vgmstream->ch[i].channel_start_offset=start_offset; } else { vgmstream->ch[i].channel_start_offset= start_offset+vgmstream->interleave_block_size*i; } vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset; } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* Actual AAX init fcn */ VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; STREAMFILE * streamFileAAX = NULL; STREAMFILE * streamFileADX = NULL; char filename[PATH_LIMIT]; off_t *segment_offset = NULL; off_t *segment_size = NULL; int32_t sample_count; int table_error = 0; int loop_flag = 0; int32_t loop_start_sample=0; int32_t loop_end_sample=0; int loop_segment = 0; aax_codec_data *data = NULL; const long AAX_offset = 0; int channel_count = 0, segment_count; int sample_rate = 0; int i; long aax_data_offset; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("aax",filename_extension(filename))) goto fail; /* get AAX entry count, data offset */ { struct utf_query_result result; long aax_string_table_offset; long aax_string_table_size; result = query_utf_nofail(streamFile, AAX_offset, NULL, &table_error); if (table_error) goto fail; segment_count = result.rows; aax_string_table_offset = AAX_offset + 8 + result.string_table_offset; aax_data_offset = AAX_offset + 8 + result.data_offset; aax_string_table_size = aax_data_offset - aax_string_table_offset; if (result.name_offset+4 > aax_string_table_size) goto fail; if (read_32bitBE(aax_string_table_offset + result.name_offset, streamFile) != 0x41415800) /* "AAX\0" */ goto fail; } segment_offset = calloc(segment_count,sizeof(off_t)); if (!segment_offset) goto fail; segment_size = calloc(segment_count,sizeof(off_t)); if (!segment_size) goto fail; /* get offsets of constituent ADXs */ for (i = 0; i < segment_count; i++) { struct offset_size_pair offset_size; offset_size = query_utf_data(streamFile, AAX_offset, i, "data", &table_error); if (table_error) goto fail; segment_offset[i] = aax_data_offset + offset_size.offset; segment_size[i] = offset_size.size; } streamFileAAX = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!streamFileAAX) goto fail; data = malloc(sizeof(aax_codec_data)); if (!data) goto fail; data->segment_count = segment_count; data->adxs = malloc(sizeof(STREAMFILE *)*segment_count); if (!data->adxs) goto fail; for (i=0;i<segment_count;i++) { data->adxs[i] = NULL; } data->sample_counts = calloc(segment_count,sizeof(int32_t)); if (!data->sample_counts) goto fail; /* for each segment */ for (i = 0; i < segment_count; i++) { VGMSTREAM *adx; /*printf("try opening segment %d/%d %x\n",i,segment_count,segment_offset[i]);*/ streamFileADX = open_aax_with_STREAMFILE(streamFileAAX,segment_offset[i],segment_size[i]); if (!streamFileADX) goto fail; adx = data->adxs[i] = init_vgmstream_adx(streamFileADX); if (!adx) goto fail; data->sample_counts[i] = adx->num_samples; close_streamfile(streamFileADX); streamFileADX = NULL; if (i == 0) { channel_count = adx->channels; sample_rate = adx->sample_rate; } else { if (channel_count != adx->channels) goto fail; if (sample_rate != adx->sample_rate) goto fail; } if (adx->loop_flag != 0) goto fail; /* save start things so we can restart for seeking/looping */ /* copy the channels */ memcpy(adx->start_ch,adx->ch,sizeof(VGMSTREAMCHANNEL)*adx->channels); /* copy the whole VGMSTREAM */ memcpy(adx->start_vgmstream,adx,sizeof(VGMSTREAM)); } sample_count = 0; loop_flag = 0; for (i = 0; i < segment_count; i++) { int segment_loop_flag = query_utf_1byte(streamFile, AAX_offset, i, "lpflg", &table_error); if (table_error) segment_loop_flag = 0; if (!loop_flag && segment_loop_flag) { loop_start_sample = sample_count; loop_segment = i; } sample_count += data->sample_counts[i]; if (!loop_flag && segment_loop_flag) { loop_end_sample = sample_count; loop_flag = 1; } } vgmstream = allocate_vgmstream(channel_count,loop_flag); vgmstream->num_samples = sample_count; vgmstream->sample_rate = sample_rate; vgmstream->loop_start_sample = loop_start_sample; vgmstream->loop_end_sample = loop_end_sample; vgmstream->coding_type = data->adxs[0]->coding_type; vgmstream->layout_type = layout_aax; vgmstream->meta_type = meta_AAX; vgmstream->ch[0].streamfile = streamFileAAX; data->current_segment = 0; data->loop_segment = loop_segment; vgmstream->codec_data = data; free(segment_offset); free(segment_size); return vgmstream; /* clean up anything we may have opened */ fail: if (streamFileAAX) close_streamfile(streamFileAAX); if (streamFileADX) close_streamfile(streamFileADX); if (vgmstream) close_vgmstream(vgmstream); if (segment_offset) free(segment_offset); if (segment_size) free(segment_size); if (data) { if (data->adxs) { int i; for (i=0;i<data->segment_count;i++) if (data->adxs) close_vgmstream(data->adxs[i]); free(data->adxs); } if (data->sample_counts) { free(data->sample_counts); } free(data); } return NULL; }
VGMSTREAM * init_vgmstream_bnsf(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; off_t file_size = -1; uint32_t riff_size; uint32_t bnsf_form; enum { form_IS14 = UINT32_C(0x49533134), /* IS14 */ }; int channel_count = 0; int sample_count = 0; int sample_rate = 0; int coding_type = -1; off_t start_offset = -1; int loop_flag = 0; off_t loop_start = -1; off_t loop_end = -1; uint32_t data_size = 0; uint32_t block_size = 0; uint32_t block_samples = 0; int FormatChunkFound = 0; int DataChunkFound = 0; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("bnsf",filename_extension(filename))) { goto fail; } /* check header */ if ((uint32_t)read_32bitBE(0,streamFile)!=0x424E5346) /* BNSF */ goto fail; /* check form */ bnsf_form = read_32bitBE(8,streamFile); switch (bnsf_form) { #ifdef VGM_USE_G7221 case form_IS14: break; #endif default: goto fail; } riff_size = read_32bitBE(4,streamFile); file_size = get_streamfile_size(streamFile); /* check for tructated RIFF */ if (file_size < riff_size+8) goto fail; /* read through chunks to verify format and find metadata */ { off_t current_chunk = 0xc; /* start with first chunk */ while (current_chunk < file_size && current_chunk < riff_size+8) { uint32_t chunk_type = read_32bitBE(current_chunk,streamFile); off_t chunk_size = read_32bitBE(current_chunk+4,streamFile); if (current_chunk+8+chunk_size > file_size) goto fail; switch(chunk_type) { case 0x73666d74: /* "sfmt" */ /* only one per file */ if (FormatChunkFound) goto fail; FormatChunkFound = 1; sample_rate = read_32bitBE(current_chunk+0x0c,streamFile); channel_count = read_16bitBE(current_chunk+0x0a,streamFile); // read_32bitBE(current_chunk+0x10,streamFile); // ? // read_32bitBE(current_chunk+0x14,streamFile); // ? block_size = read_16bitBE(current_chunk+0x18,streamFile); block_samples = read_16bitBE(current_chunk+0x1a,streamFile); /* I assume this is still the codec id, but as the codec is specified by the BNSF "form" I've only seen this zero */ switch ((uint16_t)read_16bitBE(current_chunk+0x8,streamFile)) { case 0: break; default: goto fail; } break; case 0x73646174: /* sdat */ /* at most one per file */ if (DataChunkFound) goto fail; DataChunkFound = 1; start_offset = current_chunk + 8; data_size = chunk_size; break; case 0x6C6F6F70: /* loop */ loop_flag = 1; loop_start = read_32bitBE(current_chunk+8, streamFile); loop_end = read_32bitBE(current_chunk+0xc,streamFile); break; default: /* ignorance is bliss */ break; } current_chunk += 8+chunk_size; } } if (!FormatChunkFound || !DataChunkFound) goto fail; switch (bnsf_form) { #ifdef VGM_USE_G7221 case form_IS14: coding_type = coding_G7221C; sample_count = data_size/block_size*block_samples; break; #endif default: goto fail; } /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->num_samples = sample_count; vgmstream->sample_rate = sample_rate; vgmstream->coding_type = coding_type; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = block_size/channel_count; if (loop_flag) { vgmstream->loop_start_sample = loop_start; vgmstream->loop_end_sample = loop_end; } vgmstream->meta_type = meta_BNSF; #ifdef VGM_USE_G7221 if (coding_G7221C == coding_type) { int i; g7221_codec_data *data; /* one data structure per channel */ data = malloc(sizeof(g7221_codec_data) * channel_count); if (!data) { goto fail; } memset(data,0,sizeof(g7221_codec_data) * channel_count); vgmstream->codec_data = data; for (i = 0; i < channel_count; i++) { /* Siren 14 == 14khz bandwidth */ data[i].handle = g7221_init(vgmstream->interleave_block_size, 14000); if (!data[i].handle) { goto fail; /* close_vgmstream is able to clean up */ } } } #endif /* open the file, set up each channel */ { int i; vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename, STREAMFILE_DEFAULT_BUFFER_SIZE); if (!vgmstream->ch[0].streamfile) goto fail; for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile; vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset = start_offset+i*vgmstream->interleave_block_size; } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* CRI's UTF wrapper around DSP */ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; int table_error = 0; int loop_flag = 0; const long top_offset = 0; int channel_count; int sample_rate; long sample_count; long top_data_offset, segment_count; long body_offset, body_size; long header_offset, header_size; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); //if (strcasecmp("aax",filename_extension(filename))) goto fail; /* get entry count, data offset */ { struct utf_query_result result; long top_string_table_offset; long top_string_table_size; long name_offset; result = query_utf_nofail(streamFile, top_offset, NULL, &table_error); if (table_error) goto fail; segment_count = result.rows; if (segment_count != 1) goto fail; // only simple stuff for now top_string_table_offset = top_offset + 8 + result.string_table_offset; top_data_offset = top_offset + 8 + result.data_offset; top_string_table_size = top_data_offset - top_string_table_offset; if (result.name_offset+10 > top_string_table_size) goto fail; name_offset = top_string_table_offset + result.name_offset; if (read_32bitBE(name_offset, streamFile) != 0x41445043 ||// "ADPC" read_32bitBE(name_offset+4, streamFile) != 0x4D5F5749 ||// "M_WI" read_16bitBE(name_offset+8, streamFile) != 0x4900) // "I\0" goto fail; } { struct offset_size_pair offset_size; offset_size = query_utf_data(streamFile, top_offset, 0, "data", &table_error); if (table_error) goto fail; body_offset = top_data_offset + offset_size.offset; body_size = offset_size.size; offset_size = query_utf_data(streamFile, top_offset, 0, "header", &table_error); if (table_error) goto fail; header_offset = top_data_offset + offset_size.offset; header_size = offset_size.size; } channel_count = query_utf_1byte(streamFile, top_offset, 0, "nch", &table_error); sample_count = query_utf_4byte(streamFile, top_offset, 0, "nsmpl", &table_error); sample_rate = query_utf_4byte(streamFile, top_offset, 0, "sfreq", &table_error); if (table_error) goto fail; if (channel_count != 1 && channel_count != 2) goto fail; if (header_size != channel_count * 0x60) goto fail; vgmstream = allocate_vgmstream(channel_count,loop_flag); vgmstream->num_samples = sample_count; vgmstream->sample_rate = sample_rate; vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_UTF_DSP; { int i,j; long channel_size = (body_size+7)/8*8/channel_count; for (i = 0; i < channel_count; i++) { vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!vgmstream->ch[i].streamfile) goto fail; vgmstream->ch[i].channel_start_offset = vgmstream->ch[i].offset = body_offset + i * channel_size; for (j=0;j<16;j++) { vgmstream->ch[i].adpcm_coef[j] = read_16bitBE(header_offset + 0x60*i + 0x1c + j*2, streamFile); } } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
VGMSTREAM * init_vgmstream_xbox_xvas(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; int loop_flag=0; int channel_count; int i; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("xvas",filename_extension(filename))) goto fail; if((read_32bitLE(0x00,streamFile)!=0x69) && (read_32bitLE(0x08,streamFile)!=0x48)) goto fail; /* No Loop found atm */ loop_flag = (read_32bitLE(0x14,streamFile)==read_32bitLE(0x24,streamFile)); /* Always stereo files */ channel_count=read_32bitLE(0x04,streamFile); /* 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_32bitLE(0x0c,streamFile); vgmstream->coding_type = coding_XBOX; vgmstream->num_samples = read_32bitLE(0x24,streamFile); vgmstream->num_samples -= ((vgmstream->num_samples/0x20000)*0x20); vgmstream->num_samples = vgmstream->num_samples / 36 * 64 / vgmstream->channels; vgmstream->layout_type = layout_xvas_blocked; vgmstream->meta_type = meta_XBOX_XVAS; if(loop_flag) { vgmstream->loop_start_sample = read_32bitLE(0x10,streamFile); vgmstream->loop_start_sample -= ((vgmstream->loop_start_sample/0x20000)*0x20); vgmstream->loop_start_sample = vgmstream->loop_start_sample / 36 * 64 / vgmstream->channels; vgmstream->loop_end_sample=vgmstream->num_samples; } /* open the file for reading by each channel */ { for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,36); vgmstream->ch[i].offset = 0x800; if (!vgmstream->ch[i].streamfile) goto fail; } } xvas_block_update(0x800,vgmstream); return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* IAB: Ueki no Housoku - Taosu ze Robert Juudan!! (PS2) */ VGMSTREAM * init_vgmstream_ps2_iab(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; int loop_flag = 0; int channel_count; int i; off_t start_offset; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("iab",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x10000000) goto fail; /* check file size */ if (read_32bitLE(0x1C,streamFile) != get_streamfile_size(streamFile)) goto fail; loop_flag = 0; channel_count = 2; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ start_offset = 0x40; vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitLE(0x4,streamFile); vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_ps2_iab_blocked; vgmstream->interleave_block_size = read_32bitLE(0xC, streamFile); vgmstream->meta_type = meta_PS2_IAB; /* open the file for reading by each channel */ { for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename, vgmstream->interleave_block_size); if (!vgmstream->ch[i].streamfile) goto fail; } } /* Calc num_samples */ ps2_iab_block_update(start_offset, vgmstream); vgmstream->num_samples=0; do { vgmstream->num_samples += 0x4000 * 14 / 16; ps2_iab_block_update(vgmstream->next_block_offset, vgmstream); } while (vgmstream->next_block_offset < get_streamfile_size(streamFile)); ps2_iab_block_update(start_offset, vgmstream); return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* BH2PCM (from Bio Hazard 2) */ VGMSTREAM * init_vgmstream_ngc_bh2pcm(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; off_t start_offset; int channel_count; int format_detect; int loop_flag; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("bh2pcm",filename_extension(filename))) goto fail; #if 0 /* check header */ if (read_32bitBE(0x00,streamFile) != 0x00000000) goto fail; #endif loop_flag = 0; channel_count = 2; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ format_detect=read_32bitLE(0x00,streamFile); switch (format_detect) { case 1: start_offset = 0x20; channel_count = 2; vgmstream->channels = channel_count; vgmstream->sample_rate = 32000; vgmstream->num_samples = read_32bitLE(0x04,streamFile)/2; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = read_32bitLE(0x04,streamFile); if (loop_flag) { vgmstream->loop_start_sample = 0; vgmstream->loop_end_sample = read_32bitLE(0x14,streamFile); } break; case 0: start_offset = 0x20; channel_count = 1; vgmstream->channels = channel_count; vgmstream->sample_rate = 32000; vgmstream->num_samples = read_32bitLE(0x0C,streamFile); vgmstream->layout_type = layout_none; if (loop_flag) { vgmstream->loop_start_sample = read_32bitLE(0x08,streamFile); vgmstream->loop_end_sample = read_32bitLE(0x0C,streamFile); } break; default: goto fail; } vgmstream->coding_type = coding_PCM16BE; vgmstream->meta_type = meta_NGC_BH2PCM; /* 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; }
VGMSTREAM * init_vgmstream_dsp_bdsp(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; int channel_count; int loop_flag; int i; off_t start_offset; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("bdsp",filename_extension(filename))) goto fail; channel_count = 2; loop_flag = 0; /* 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_32bitBE(0x8,streamFile); vgmstream->coding_type = coding_NGC_DSP; #if 0 if(loop_flag) { vgmstream->loop_start_sample = read_32bitBE(0x64,streamFile); vgmstream->loop_end_sample = read_32bitBE(0x68,streamFile); } #endif vgmstream->layout_type = layout_dsp_bdsp_blocked; vgmstream->interleave_block_size = 0x8; vgmstream->meta_type = meta_DSP_BDSP; /* open the file for reading by each channel */ { for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size); if (!vgmstream->ch[i].streamfile) goto fail; vgmstream->ch[i].channel_start_offset= vgmstream->ch[i].offset=i*vgmstream->interleave_block_size; } } if (vgmstream->coding_type == coding_NGC_DSP) { int i; for (i=0;i<16;i++) { vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x1C+i*2,streamFile); } if (vgmstream->channels == 2) { for (i=0;i<16;i++) { vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x7C+i*2,streamFile); } } } /* Calc num_samples */ start_offset = 0x0; dsp_bdsp_block_update(start_offset,vgmstream); vgmstream->num_samples=0; do { vgmstream->num_samples += vgmstream->current_block_size*14/8; dsp_bdsp_block_update(vgmstream->next_block_offset,vgmstream); } while (vgmstream->next_block_offset<get_streamfile_size(streamFile)); dsp_bdsp_block_update(start_offset,vgmstream); return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* Guerrilla's MSS - Found in ShellShock Nam '67 (PS2/Xbox), Killzone (PS2) */ VGMSTREAM * init_vgmstream_mss(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset; size_t data_size; int loop_flag = 0, channel_count; /* checks */ if (!check_extensions(streamFile, "mss")) goto fail; if (read_32bitBE(0x00,streamFile) != 0x4D435353) /* "MCSS" */ goto fail; loop_flag = 0; channel_count = read_16bitLE(0x16,streamFile); /* 0x04: version? (always 0x00000100 LE) */ start_offset = read_32bitLE(0x08,streamFile); data_size = read_32bitLE(0x0c,streamFile); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; vgmstream->sample_rate = read_32bitLE(0x10,streamFile); /* 0x14(1): 1/2/3/4 if 2/4/6/8ch, 0x15(1): 0/1?, 0x16: ch */ vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = read_32bitLE(0x18,streamFile); vgmstream->num_samples = read_32bitLE(0x1C,streamFile); vgmstream->meta_type = meta_MSS; /* no other way to know */ if (vgmstream->interleave_block_size == 0x4800) { vgmstream->coding_type = coding_XBOX_IMA; /* in stereo multichannel this value is distance between 2ch pair, but we need * interleave*ch = full block (2ch 0x4800 + 2ch 0x4800 = 4ch, 0x4800+4800 / 4 = 0x2400) */ vgmstream->interleave_block_size = vgmstream->interleave_block_size / 2; if (vgmstream->channels > 2 && vgmstream->channels % 2 != 0) goto fail; /* only 2ch+..+2ch layout is known */ /* header values are somehow off? */ data_size = get_streamfile_size(streamFile) - start_offset; vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, vgmstream->channels); } else { /* 0x800 interleave */ vgmstream->coding_type = coding_PSX; if (vgmstream->num_samples * vgmstream->channels <= data_size) vgmstream->num_samples = vgmstream->num_samples / 16 * 28; } /* open the file for reading */ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; return vgmstream; fail: close_vgmstream(vgmstream); return NULL; }
/* IDVI (Eldorado Gate Volume 1-7) */ VGMSTREAM * init_vgmstream_dc_idvi(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; off_t start_offset; int loop_flag; int channel_count; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("idvi",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x49445649) /* "IDVI." */ goto fail; loop_flag = read_32bitLE(0x0C,streamFile); channel_count = read_32bitLE(0x04,streamFile); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->channels = channel_count; start_offset = 0x800; vgmstream->sample_rate = read_32bitLE(0x08,streamFile); vgmstream->coding_type = coding_INT_DVI_IMA; vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset); if (loop_flag) { vgmstream->loop_start_sample = read_32bitLE(0x0C,streamFile); vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset); } vgmstream->meta_type = meta_DC_IDVI; /* Calculating the short block... */ if (channel_count > 1) { vgmstream->interleave_block_size = 0x400; vgmstream->interleave_smallblock_size = ((get_streamfile_size(streamFile)-start_offset)%(vgmstream->channels*vgmstream->interleave_block_size))/vgmstream->channels; vgmstream->layout_type = layout_interleave_shortblock; } else { vgmstream->layout_type = layout_none; } /* 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; }