/* STHD - Dream Factory .stx [Kakuto Chojin (Xbox)] */ VGMSTREAM * init_vgmstream_sthd(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset; int loop_flag, channel_count; /* checks */ if (!check_extensions(streamFile, "stx")) goto fail; if (read_32bitBE(0x00,streamFile) != 0x53544844) /* "STHD" */ goto fail; /* first block has special values */ if (read_32bitLE(0x04,streamFile) != 0x0800 && read_32bitLE(0x0c,streamFile) != 0x0001 && read_32bitLE(0x14,streamFile) != 0x0000) goto fail; channel_count = read_16bitLE(0x06,streamFile); loop_flag = read_16bitLE(0x18,streamFile) != -1; start_offset = 0x800; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count, loop_flag); if (!vgmstream) goto fail; vgmstream->meta_type = meta_STHD; vgmstream->sample_rate = read_32bitLE(0x20, streamFile); /* repeated ~8 times? */ vgmstream->coding_type = coding_XBOX_IMA_int; vgmstream->layout_type = layout_blocked_sthd; if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; /* calc num_samples manually (blocks data varies in size) */ { /* loop values may change to +1 in first actual block, but this works ok enough */ int loop_start_block = (uint16_t)read_16bitLE(0x1a,streamFile); int loop_end_block = (uint16_t)read_16bitLE(0x1c,streamFile); int block_count = 1; /* header block = 0 */ vgmstream->next_block_offset = start_offset; do { block_update(vgmstream->next_block_offset,vgmstream); if (block_count == loop_start_block) vgmstream->loop_start_sample = vgmstream->num_samples; if (block_count == loop_end_block) vgmstream->loop_end_sample = vgmstream->num_samples; vgmstream->num_samples += xbox_ima_bytes_to_samples(vgmstream->current_block_size, 1); block_count++; } while (vgmstream->next_block_offset < get_streamfile_size(streamFile)); block_update(start_offset, vgmstream); } return vgmstream; fail: close_vgmstream(vgmstream); return NULL; }
/* NGCA (from GoldenEye 007) */ VGMSTREAM * init_vgmstream_ngca(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("ngca",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x4E474341) /* "NGCA" */ goto fail; loop_flag = 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 = 0x40; vgmstream->channels = channel_count; vgmstream->sample_rate = 32000; vgmstream->coding_type = coding_NGC_DSP; vgmstream->num_samples = (((read_32bitBE(0x4,streamFile))/2) - 1) / 8 * 14; vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_NGCA; if (vgmstream->coding_type == coding_NGC_DSP) { int i; for (i=0;i<16;i++) { vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0xC+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; }
/* AUS (found in various Capcom games) */ VGMSTREAM * init_vgmstream_aus(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[1024]; off_t start_offset; int loop_flag = 0; int channel_count; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("aus",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x41555320) /* "AUS " */ goto fail; loop_flag = (read_32bitLE(0x0c,streamFile)!=0); channel_count = read_32bitLE(0xC,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_32bitLE(0x10,streamFile); vgmstream->num_samples = read_32bitLE(0x08,streamFile); if(read_16bitLE(0x06,streamFile)==0x02) { vgmstream->coding_type = coding_XBOX; vgmstream->layout_type=layout_none; } else { vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x800; } if (loop_flag) { vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile); vgmstream->loop_end_sample = read_32bitLE(0x08,streamFile); } vgmstream->meta_type = meta_AUS; /* 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; }
/* ivaud (from GTA IV (PC)) */ VGMSTREAM * init_vgmstream_ivaud(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; off_t start_offset; off_t block_table_offset; int loop_flag = 0; int channel_count; int i; /* at this time, i only check for extension */ /* i'll make further checks later */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("ivaud",filename_extension(filename))) goto fail; /* multiple sounds .ivaud files are not implemented */ /* only used for voices & sfx */ if(read_32bitLE(0x10,streamFile)!=0) goto fail; /* never looped and allways 2 channels */ 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 */ block_table_offset = read_32bitLE(0,streamFile); vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitLE(block_table_offset + 0x04,streamFile); vgmstream->coding_type = coding_INT_IMA; vgmstream->layout_type = layout_ivaud_blocked; vgmstream->meta_type = meta_PC_IVAUD; /* 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 */ start_offset = read_32bitLE(0x2C,streamFile); //block_count = read_32bitLE(0x08,streamFile); vgmstream->next_block_offset = read_32bitLE(0x2C,streamFile); // to avoid troubles with "extra" samples vgmstream->num_samples=((read_32bitLE(0x60,streamFile)/2)*2); ivaud_block_update(start_offset,vgmstream); return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
VGMSTREAM * init_vgmstream_ps2_vpk(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[1024]; 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("vpk",filename_extension(filename))) goto fail; /* check VPK Header */ if (read_32bitBE(0x00,streamFile) != 0x204B5056) goto fail; /* check loop */ loop_flag = (read_32bitLE(0x7FC,streamFile)!=0); channel_count=read_32bitLE(0x14,streamFile); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->channels = read_32bitLE(0x14,streamFile); vgmstream->sample_rate = read_32bitLE(0x10,streamFile); /* Check for Compression Scheme */ vgmstream->coding_type = coding_PSX; vgmstream->num_samples = read_32bitLE(0x04,streamFile)/16*28; /* Get loop point values */ if(vgmstream->loop_flag) { vgmstream->loop_start_sample = read_32bitLE(0x7FC,streamFile); vgmstream->loop_end_sample = vgmstream->num_samples; } vgmstream->interleave_block_size = read_32bitLE(0x0C,streamFile)/2; vgmstream->layout_type = layout_interleave; vgmstream->meta_type = meta_PS2_VPK; start_offset = (off_t)read_32bitLE(0x08,streamFile); /* 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; }
VGMSTREAM * init_vgmstream_gh3_bar(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; // don't close, this is just the source streamFile wrapped STREAMFILE* streamFileBAR = NULL; char filename[260]; off_t start_offset; off_t ch2_start_offset; int loop_flag; int channel_count; long file_size; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("bar",filename_extension(filename))) goto fail; /* decryption wrapper for header reading */ streamFileBAR = wrap_bar_STREAMFILE(streamFile); if (!streamFileBAR) goto fail; file_size = get_streamfile_size(streamFileBAR); /* check header */ if (read_32bitBE(0x00,streamFileBAR) != 0x11000100 || read_32bitBE(0x04,streamFileBAR) != 0x01000200) goto fail; if (read_32bitLE(0x50,streamFileBAR) != file_size) goto fail; start_offset = read_32bitLE(0x18,streamFileBAR); if (0x54 != start_offset) goto fail; ch2_start_offset = read_32bitLE(0x48,streamFileBAR); if (ch2_start_offset >= file_size) goto fail; /* build the VGMSTREAM */ channel_count = 2; loop_flag = 0; vgmstream = allocate_vgmstream(channel_count, loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->channels = channel_count; vgmstream->sample_rate = 11025; vgmstream->coding_type = coding_IMA; vgmstream->num_samples = (file_size-ch2_start_offset)*2; vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_GH3_BAR; { STREAMFILE *file1, *file2; file1 = streamFileBAR->open(streamFileBAR,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!file1) goto fail; file2 = streamFileBAR->open(streamFileBAR,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!file2) { close_streamfile(file1); goto fail; } vgmstream->ch[0].streamfile = file1; vgmstream->ch[1].streamfile = file2; vgmstream->ch[0].channel_start_offset= vgmstream->ch[0].offset=start_offset; vgmstream->ch[1].channel_start_offset= vgmstream->ch[1].offset=ch2_start_offset; } // discard our decrypt wrapper, without closing the original streamfile free(streamFileBAR); return vgmstream; fail: if (streamFileBAR) free(streamFileBAR); if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* .XPS - From Software games banks [Metal Wolf Chaos (Xbox), Otogi (Xbox)] */ VGMSTREAM * init_vgmstream_xps(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; STREAMFILE * streamData = NULL; int i, entries; off_t entry_offset = 0x10; int total_subsongs, target_subsong = streamFile->stream_index; /* checks */ if (!check_extensions(streamFile, "xps")) goto fail; if (read_32bitLE(0x00,streamFile) != get_streamfile_size(streamFile)) goto fail; if (read_32bitBE(0x0c,streamFile) != 0x64696666) /* "diff" */ goto fail; /* handle .xps alone (stream .xps+data are done above) */ streamData = open_streamfile_by_ext(streamFile, "dat"); if (streamData) goto fail; /* main section + bank sections (usually same number but not always) */ entries = read_32bitLE(0x04,streamFile); total_subsongs = 0; if (target_subsong == 0) target_subsong = 1; if (target_subsong < 0 /*|| target_subsong > total_subsongs || total_subsongs < 1*/) goto fail; /* parse entries: skip (there is probably a stream/bank flag here) */ for (i = 0; i < entries; i++) { off_t entry_base = entry_offset; size_t entry_size = read_32bitLE(entry_base+0x00,streamFile); uint32_t entry_id = read_32bitBE(entry_base+0x04,streamFile); size_t entry_pad = read_32bitLE(entry_base+0x08,streamFile); /* 0x0c: always null, rest: entry (format varies) */ entry_offset += entry_size + entry_pad + 0x10; /* sound info entry */ if (entry_id == 0x73696400) { /* "sid\0" */ /* keep looking for sound banks */ continue; } /* sound bank entry, otherwise no good */ if (entry_id != 0x75647362) { /* "udsb" */ goto fail; } total_subsongs++; /* open internal RIFF */ if (target_subsong == total_subsongs && vgmstream == NULL) { STREAMFILE* temp_streamFile; off_t subsong_offset = entry_base+0x18; size_t subsong_size = read_32bitLE(entry_base+0x14,streamFile); temp_streamFile = setup_subfile_streamfile(streamFile, subsong_offset,subsong_size, "wav"); if (!temp_streamFile) goto fail; vgmstream = init_vgmstream_riff(temp_streamFile); close_streamfile(temp_streamFile); if (!vgmstream) goto fail; } } /* subsong not found */ if (!vgmstream) goto fail; vgmstream->num_streams = total_subsongs; return vgmstream; fail: close_streamfile(streamData); close_vgmstream(vgmstream); return NULL; }
VGMSTREAM * init_vgmstream_str_snds(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; int channel_count; int loop_flag = 0; off_t SHDR_offset = -1; int FoundSHDR = 0; int CTRL_size = -1; size_t file_size; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("str",filename_extension(filename))) goto fail; /* check for opening CTRL or SNDS chunk */ if (read_32bitBE(0x0,streamFile) != 0x4354524c && /* CTRL */ read_32bitBE(0x0,streamFile) != 0x534e4453 && // SNDS read_32bitBE(0x0,streamFile) != 0x53484452) // SHDR goto fail; file_size = get_streamfile_size(streamFile); /* scan chunks until we find a SNDS containing a SHDR */ { off_t current_chunk; current_chunk = 0; while (!FoundSHDR && current_chunk < file_size) { if (current_chunk < 0) goto fail; if (current_chunk+read_32bitBE(current_chunk+4,streamFile) >= file_size) goto fail; switch (read_32bitBE(current_chunk,streamFile)) { case 0x4354524C: /* CTRL */ /* to distinguish between styles */ CTRL_size = read_32bitBE(current_chunk+4,streamFile); break; case 0x534e4453: /* SNDS */ switch (read_32bitBE(current_chunk+16,streamFile)) { case 0x53484452: /* SHDR */ FoundSHDR = 1; SHDR_offset = current_chunk+16; break; default: break; } break; case 0x53484452: /* SHDR */ switch (read_32bitBE(current_chunk+0x7C, streamFile)) { case 0x4354524C: /* CTRL */ // to distinguish between styles CTRL_size = read_32bitBE(current_chunk + 0x80, streamFile); break; default: break; } break; default: /* ignore others for now */ break; } current_chunk += read_32bitBE(current_chunk+4,streamFile); } } if (!FoundSHDR) goto fail; /* details */ channel_count = read_32bitBE(SHDR_offset+0x20,streamFile); loop_flag = 0; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ if ((CTRL_size == 0x1C) || (CTRL_size == 0x0B) || (CTRL_size == -1)) { vgmstream->num_samples = read_32bitBE(SHDR_offset+0x2c,streamFile)-1; /* sample count? */ } else { vgmstream->num_samples = read_32bitBE(SHDR_offset+0x2c,streamFile) /* frame count? */ * 0x10; } vgmstream->num_samples/=vgmstream->channels; vgmstream->sample_rate = read_32bitBE(SHDR_offset+0x1c,streamFile); switch (read_32bitBE(SHDR_offset+0x24,streamFile)) { case 0x53445832: /* SDX2 */ if (channel_count > 1) { vgmstream->coding_type = coding_SDX2_int; vgmstream->interleave_block_size = 1; } else vgmstream->coding_type = coding_SDX2; break; default: goto fail; } vgmstream->layout_type = layout_blocked_str_snds; vgmstream->meta_type = meta_STR_SNDS; /* channels and loop flag are set by allocate_vgmstream */ if (loop_flag) { /* just guessin', no way to set loop flag anyway */ vgmstream->loop_start_sample = 0; vgmstream->loop_end_sample = vgmstream->num_samples; } /* open the file for reading by 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; } } /* start me up */ block_update_str_snds(0,vgmstream); return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
VGMSTREAM * init_vgmstream_mn_str(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; off_t start_offset; int loop_flag = 0; int channel_count; int bitspersample; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("mnstr",filename_extension(filename))) goto fail; loop_flag = 0; channel_count = read_32bitLE(0x50,streamFile); bitspersample = read_32bitLE(0x58,streamFile); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ start_offset = read_32bitLE(0x20,streamFile)+0x48; vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitLE(0x54,streamFile); switch (bitspersample) { case 0x10: vgmstream->coding_type = coding_PCM16LE; if (channel_count == 1) { vgmstream->layout_type = layout_none; } else { vgmstream->interleave_block_size = 0x2; vgmstream->layout_type = layout_interleave; } break; case 0x4: if (read_32bitLE(0x20,streamFile) == 0x24) { vgmstream->interleave_block_size = 0x800; vgmstream->layout_type = layout_none; } } vgmstream->num_samples = read_32bitLE(0x4C,streamFile); //vgmstream->layout_type = layout_interleave; //vgmstream->interleave_block_size = 0x2; vgmstream->meta_type = meta_MN_STR; /* 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; }
/* IDSP (Defender NGC) */ VGMSTREAM * init_vgmstream_idsp4(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; int loop_flag = 0; int channel_count; off_t start_offset; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("idsp",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x49445350) /* "IDSP" */ goto fail; channel_count = read_32bitBE(0x0C,streamFile); if (channel_count > 2) // Refuse everything else for now { goto fail; } /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ start_offset = 0x70; vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitBE(0x08,streamFile); vgmstream->coding_type = coding_NGC_DSP; vgmstream->num_samples = read_32bitBE(0x04,streamFile)/channel_count/8*14; if (loop_flag) { vgmstream->loop_start_sample = 0; vgmstream->loop_end_sample = read_32bitBE(0x04,streamFile)/channel_count/8*14; } if (channel_count == 1) { vgmstream->layout_type = layout_none; } else { vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = read_32bitBE(0x10,streamFile); } vgmstream->meta_type = meta_IDSP; { int i; for (i=0;i<16;i++) vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x14+i*2,streamFile); if (channel_count == 2) { for (i=0;i<16;i++) vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x42+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; }
/* "idsp/IDSP" Soul Calibur Legends (Wii) Sky Crawlers: Innocent Aces (Wii) */ VGMSTREAM * init_vgmstream_idsp2(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; int loop_flag; int channel_count; int i, j; off_t start_offset; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("idsp",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x69647370 || /* "idsp" */ read_32bitBE(0xBC,streamFile) != 0x49445350) /* IDSP */ goto fail; loop_flag = read_32bitBE(0x20,streamFile); channel_count = read_32bitBE(0xC4,streamFile); if (channel_count > 8) { goto fail; } /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ start_offset = (channel_count * 0x60) + 0x100; vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitBE(0xC8,streamFile); vgmstream->coding_type = coding_NGC_DSP; vgmstream->num_samples = (read_32bitBE(0x14,streamFile))*14/8/channel_count; if (loop_flag) { vgmstream->loop_start_sample = (read_32bitBE(0xD0,streamFile)); vgmstream->loop_end_sample = (read_32bitBE(0xD4,streamFile)); } if (channel_count == 1) { vgmstream->layout_type = layout_none; } else if (channel_count > 1) { if (read_32bitBE(0xD8,streamFile) == 0) { vgmstream->layout_type = layout_none; vgmstream->interleave_block_size = (get_streamfile_size(streamFile)-start_offset)/2; } else if (read_32bitBE(0xD8,streamFile) > 0) { vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = read_32bitBE(0xD8,streamFile); } } vgmstream->meta_type = meta_IDSP; { if (vgmstream->coding_type == coding_NGC_DSP) { off_t coef_table[8] = {0x118,0x178,0x1D8,0x238,0x298,0x2F8,0x358,0x3B8}; for (j=0;j<vgmstream->channels;j++) { for (i=0;i<16;i++) { vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(coef_table[j]+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_ngc_sck_dsp(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; STREAMFILE * streamFileDSP = NULL; char filename[PATH_LIMIT]; char filenameDSP[PATH_LIMIT]; int i; int channel_count; int loop_flag; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("sck",filename_extension(filename))) goto fail; strcpy(filenameDSP,filename); strcpy(filenameDSP+strlen(filenameDSP)-3,"dsp"); streamFileDSP = streamFile->open(streamFile,filenameDSP,STREAMFILE_DEFAULT_BUFFER_SIZE); if (read_32bitBE(0x5C,streamFile) != 0x60A94000) goto fail; if (!streamFile) 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(0x18,streamFile); vgmstream->num_samples=read_32bitBE(0x14,streamFile)/8/channel_count*14; vgmstream->coding_type = coding_NGC_DSP; if(loop_flag) { vgmstream->loop_start_sample = 0; vgmstream->loop_end_sample = read_32bitBE(0x10,streamFile)/8/channel_count*14; } if (channel_count == 1) { vgmstream->layout_type = layout_none; } else if (channel_count == 2) { vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size=read_32bitBE(0xC,streamFile); } vgmstream->meta_type = meta_NGC_SCK_DSP; /* open the file for reading */ { for (i=0;i<channel_count;i++) { /* Not sure, i'll put a fake value here for now */ vgmstream->ch[i].streamfile = streamFile->open(streamFileDSP,filenameDSP,0x8000); vgmstream->ch[i].offset = 0; if (!vgmstream->ch[i].streamfile) goto fail; } } if (vgmstream->coding_type == coding_NGC_DSP) { int i; for (i=0;i<16;i++) { vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x2C+i*2,streamFile); } if (vgmstream->channels == 2) { for (i=0;i<16;i++) { vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x2C+i*2,streamFile); } } } close_streamfile(streamFileDSP); streamFileDSP=NULL; return vgmstream; /* clean up anything we may have opened */ fail: if (streamFileDSP) close_streamfile(streamFileDSP); if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* VAS (from Pro Baseball Spirits 5) */ VGMSTREAM * init_vgmstream_ps2_vas(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; off_t start_offset; int loop_flag; int channel_count; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("vas",filename_extension(filename))) goto fail; /* check header */ #if 0 if (read_32bitBE(0x00,streamFile) != 0x00000000) /* 0x0 */ goto fail; #endif loop_flag = (read_32bitLE(0x10,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 = read_32bitLE(0x04,streamFile); vgmstream->coding_type = coding_PSX; vgmstream->num_samples = read_32bitLE(0x00,streamFile)*28/16/channel_count; if (loop_flag) { vgmstream->loop_start_sample = read_32bitLE(0x14,streamFile)*28/16/channel_count; vgmstream->loop_end_sample = read_32bitLE(0x00,streamFile)*28/16/channel_count; } vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x200; vgmstream->meta_type = meta_PS2_VAS; /* 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; }
/* VAGp - Sony SDK format, created by various tools */ VGMSTREAM * init_vgmstream_vag(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset; size_t file_size, channel_size, interleave; meta_t meta_type; int channel_count = 0, loop_flag, sample_rate; uint32_t vag_id, version; int32_t loop_start_sample = 0, loop_end_sample = 0; int allow_dual_stereo = 0; /* checks */ /* .vag: standard * .swag: Frantix (PSP) * .str: Ben10 Galactic Racing * .vig: MX vs. ATV Untamed (PS2) * .l/r: Crash Nitro Kart (PS2), Gradius V (PS2) */ if ( !check_extensions(streamFile,"vag,swag,str,vig,l,r") ) goto fail; /* check VAG Header */ if (((read_32bitBE(0x00,streamFile) & 0xFFFFFF00) != 0x56414700) && /* "VAG" */ ((read_32bitLE(0x00,streamFile) & 0xFFFFFF00) != 0x56414700)) goto fail; file_size = get_streamfile_size(streamFile); /* version used to create the file: * - 00000000 = v1.8 PC, * - 00000002 = v1.3 Mac (used?) * - 00000003 = v1.6+ Mac * - 00000020 = v2.0 PC (most common) * - 00000004 = ? (later games) * - 00000006 = ? (vagconv) * - 00020001 = v2.1 (vagconv2) * - 00030000 = v3.0 (vagconv2) */ version = (uint32_t)read_32bitBE(0x04,streamFile); /* 0x08-0c: reserved */ channel_size = read_32bitBE(0x0c,streamFile); sample_rate = read_32bitBE(0x10,streamFile); /* 0x14-20 reserved */ /* 0x20-30: name (optional) */ /* 0x30: data start (first 0x10 usually 0s to init SPU) */ /* check variation */ vag_id = read_32bitBE(0x00,streamFile); switch(vag_id) { case 0x56414731: /* "VAG1" (1 channel) [Metal Gear Solid 3 (PS2)] */ meta_type = meta_PS2_VAG1; start_offset = 0x40; /* 0x30 is extra data in VAG1 */ channel_count = 1; interleave = 0; loop_flag = 0; break; case 0x56414732: /* "VAG2" (2 channels) [Metal Gear Solid 3 (PS2)] */ meta_type = meta_PS2_VAG2; start_offset = 0x40; /* 0x30 is extra data in VAG2 */ channel_count = 2; interleave = 0x800; loop_flag = 0; break; case 0x56414769: /* "VAGi" (interleaved) */ meta_type = meta_PS2_VAGi; start_offset = 0x800; channel_count = 2; interleave = read_32bitLE(0x08,streamFile); loop_flag = 0; break; case 0x70474156: /* pGAV (little endian / stereo) [Jak 3 (PS2), Jak X (PS2)] */ meta_type = meta_PS2_pGAV; start_offset = 0x00; //todo 0x30, requires interleave_first if (read_32bitBE(0x20,streamFile) == 0x53746572) { /* "Ster" */ channel_count = 2; if (read_32bitLE(0x2000,streamFile) == 0x56414770) /* "pGAV" */ interleave = 0x2000; /* Jak 3 interleave, includes header */ else if (read_32bitLE(0x1000,streamFile) == 0x56414770) /* "pGAV" */ interleave = 0x1000; /* Jak X interleave, includes header */ else goto fail; //todo interleave_first = interleave - start_offset; /* interleave includes header */ } else { channel_count = 1; interleave = 0; } channel_size = read_32bitLE(0x0C,streamFile) / channel_count; sample_rate = read_32bitLE(0x10,streamFile); //todo adjust channel_size, includes part of header? loop_flag = 0; break; case 0x56414770: /* "VAGp" (standard and variations) */ meta_type = meta_PS2_VAGp; if (check_extensions(streamFile,"vig")) { /* MX vs. ATV Untamed (PS2) */ start_offset = 0x800 - 0x20; channel_count = 2; interleave = 0x10; loop_flag = 0; } else if (check_extensions(streamFile,"swag")) { /* algo "VAGp" at (file_size / channels) */ /* Frantix (PSP) */ start_offset = 0x40; /* channel_size ignores empty frame */ channel_count = 2; interleave = file_size / channel_count; channel_size = read_32bitLE(0x0c,streamFile); sample_rate = read_32bitLE(0x10,streamFile); loop_flag = ps_find_loop_offsets(streamFile, start_offset, channel_size*channel_count, channel_count, interleave, &loop_start_sample, &loop_end_sample); } else if (read_32bitBE(0x6000,streamFile) == 0x56414770) { /* "VAGp" */ /* The Simpsons Wrestling (PS1) */ start_offset = 0x00; //todo 0x30, requires interleave_first channel_count = 2; interleave = 0x6000; //todo interleave_first = interleave - start_offset; /* includes header */ channel_size += 0x30; loop_flag = 0; } else if (read_32bitBE(0x1000,streamFile) == 0x56414770) { /* "VAGp" */ /* Shikigami no Shiro (PS2) */ start_offset = 0x00; //todo 0x30, requires interleave_first channel_count = 2; interleave = 0x1000; //todo interleave_first = interleave - start_offset; /* includes header */ channel_size += 0x30; loop_flag = ps_find_loop_offsets(streamFile, start_offset, channel_size*channel_count, channel_count, interleave, &loop_start_sample, &loop_end_sample); } else if (read_32bitBE(0x30,streamFile) == 0x56414770) { /* "VAGp" */ /* The Red Star (PS2) */ start_offset = 0x60; /* two VAGp headers */ channel_count = 2; if ((file_size - start_offset) % 0x4000 == 0) interleave = 0x4000; else if ((file_size - start_offset) % 0x4180 == 0) interleave = 0x4180; else goto fail; loop_flag = 0; /* loop segments */ } else if (version == 0x40000000) { /* Killzone (PS2) */ start_offset = 0x30; channel_count = 1; interleave = 0; channel_size = read_32bitLE(0x0C,streamFile) / channel_count; sample_rate = read_32bitLE(0x10,streamFile); loop_flag = 0; } else if (version == 0x00020001 || version == 0x00030000) { /* standard Vita/PS4 .vag [Chronovolt (Vita), Grand Kingdom (PS4)] */ start_offset = 0x30; interleave = 0x10; /* channels are at 0x1e, except Ukiyo no Roushi (Vita), which has * loop start/end frame (but also uses PS-ADPCM flags) */ if (read_32bitBE(0x18,streamFile) == 0 && (read_32bitBE(0x1c,streamFile) & 0xFFFF00FF) == 0 && read_8bit(0x1e,streamFile) < 16) { channel_count = read_8bit(0x1e,streamFile); if (channel_count == 0) channel_count = 1; /* ex. early games [Lumines (Vita)] */ } else { channel_count = 1; } channel_size = channel_size / channel_count; loop_flag = ps_find_loop_offsets(streamFile, start_offset, channel_size*channel_count, channel_count, interleave, &loop_start_sample, &loop_end_sample); } else { /* standard PS1/PS2/PS3 .vag [Ecco the Dolphin (PS2), Legasista (PS3)] */ start_offset = 0x30; interleave = 0; channel_count = 1; loop_flag = ps_find_loop_offsets_full(streamFile, start_offset, channel_size*channel_count, channel_count, interleave, &loop_start_sample, &loop_end_sample); allow_dual_stereo = 1; /* often found with external L/R files */ } break; default: goto fail; } /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; vgmstream->meta_type = meta_type; vgmstream->allow_dual_stereo = allow_dual_stereo; vgmstream->sample_rate = sample_rate; vgmstream->num_samples = ps_bytes_to_samples(channel_size,1); vgmstream->loop_start_sample = loop_start_sample; vgmstream->loop_end_sample = loop_end_sample; vgmstream->coding_type = coding_PSX; if (version == 0x00020001 || version == 0x00030000) vgmstream->coding_type = coding_HEVAG; vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave; vgmstream->interleave_block_size = interleave; read_string(vgmstream->stream_name,0x10+1, 0x20,streamFile); /* always, can be null */ if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; return vgmstream; fail: close_vgmstream(vgmstream); return NULL; }
/* MSF header */ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; off_t start_offset; int32_t loop_start, loop_end; int loop_flag = 0; int channel_count; int codec_id; size_t fileLength; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("msf",filename_extension(filename))) goto fail; if (read_8bit(0x0,streamFile) != 0x4D) goto fail; /* M */ if (read_8bit(0x1,streamFile) != 0x53) goto fail; /* S */ if (read_8bit(0x2,streamFile) != 0x46) goto fail; /* F */ fileLength = get_streamfile_size(streamFile); loop_flag = (read_32bitBE(0x18,streamFile) != 0xFFFFFFFF); if (loop_flag) { loop_start = read_32bitBE(0x18,streamFile); loop_end = read_32bitBE(0x0C,streamFile); } channel_count = read_32bitBE(0x8,streamFile); codec_id = read_32bitBE(0x4,streamFile); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->channels = channel_count; /* Sample rate hack for strange files that don't have a specified frequency */ if (read_32bitBE(0x10,streamFile)==0x00000000) vgmstream->sample_rate = 48000; else vgmstream->sample_rate = read_32bitBE(0x10,streamFile); start_offset = 0x40; switch (codec_id) { case 0x0: /* PCM (Big Endian) */ { vgmstream->coding_type = coding_PCM16BE; vgmstream->num_samples = read_32bitBE(0x0C,streamFile)/2/channel_count; if (loop_flag){ vgmstream->loop_start_sample = loop_start/2/channel_count; vgmstream->loop_end_sample = loop_end/2/channel_count; } if (channel_count == 1) { vgmstream->layout_type = layout_none; } else if (channel_count > 1) { vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 2; } } break; case 0x3: /* PSx ADPCM */ { vgmstream->coding_type = coding_PSX; vgmstream->num_samples = read_32bitBE(0x0C,streamFile)*28/16/channel_count; if (vgmstream->num_samples == 0xFFFFFFFF) { vgmstream->num_samples = (fileLength - start_offset)*28/16/channel_count; } if (loop_flag) { vgmstream->loop_start_sample = loop_start*28/16/channel_count; vgmstream->loop_end_sample = loop_end*28/16/channel_count; } if (channel_count == 1) { vgmstream->layout_type = layout_none; } else if (channel_count > 1) { vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x10; // read_32bitBE(0x14,streamFile); } } break; #ifdef VGM_USE_MPEG case 0x7: /* MPEG */ { mpeg_codec_data *mpeg_data = NULL; struct mpg123_frameinfo mi; coding_t ct; mpeg_data = init_mpeg_codec_data(streamFile, start_offset, vgmstream->sample_rate, vgmstream->channels, &ct, NULL, NULL); if (!mpeg_data) goto fail; vgmstream->codec_data = mpeg_data; if (MPG123_OK != mpg123_info(mpeg_data->m, &mi)) goto fail; vgmstream->coding_type = ct; vgmstream->layout_type = layout_mpeg; if (mi.vbr != MPG123_CBR) goto fail; vgmstream->num_samples = mpeg_bytes_to_samples(read_32bitBE(0xC,streamFile), &mi); vgmstream->num_samples -= vgmstream->num_samples%576; if (loop_flag) { vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, &mi); vgmstream->loop_start_sample -= vgmstream->loop_start_sample%576; vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, &mi); vgmstream->loop_end_sample -= vgmstream->loop_end_sample%576; } vgmstream->interleave_block_size = 0; } break; #endif default: goto fail; } vgmstream->meta_type = meta_PS3_MSF; /* open the file for reading */ { int i; STREAMFILE * file; file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!file) goto fail; for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = file; vgmstream->ch[i].channel_start_offset= vgmstream->ch[i].offset=start_offset+vgmstream->interleave_block_size*i; } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* 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; }
VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t stream_offset; size_t filesize; uint16_t version_signature; int loop_flag=0; int channel_count; int32_t loop_start_offset=0; int32_t loop_end_offset=0; int32_t loop_start_sample=0; int32_t loop_end_sample=0; meta_t header_type; int16_t coef1, coef2; uint16_t cutoff; char filename[260]; int coding_type = coding_CRI_ADX; uint16_t xor_start=0,xor_mult=0,xor_add=0; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("adx",filename_extension(filename))) goto fail; filesize = get_streamfile_size(streamFile); /* check first 2 bytes */ if ((uint16_t)read_16bitBE(0,streamFile)!=0x8000) goto fail; /* get stream offset, check for CRI signature just before */ stream_offset = (uint16_t)read_16bitBE(2,streamFile) + 4; if ((uint16_t)read_16bitBE(stream_offset-6,streamFile)!=0x2863 ||/* "(c" */ (uint32_t)read_32bitBE(stream_offset-4,streamFile)!=0x29435249 /* ")CRI" */ ) goto fail; /* check for encoding type */ /* 2 is for some unknown fixed filter, 3 is standard ADX, 4 is * ADX with exponential scale, 0x11 is AHX */ if (read_8bit(4,streamFile) != 3) goto fail; /* check for frame size (only 18 is supported at the moment) */ if (read_8bit(5,streamFile) != 18) goto fail; /* check for bits per sample? (only 4 makes sense for ADX) */ if (read_8bit(6,streamFile) != 4) goto fail; /* check version signature, read loop info */ version_signature = read_16bitBE(0x12,streamFile); /* encryption */ if (version_signature == 0x0408) { if (find_key(streamFile, 8, &xor_start, &xor_mult, &xor_add)) { coding_type = coding_CRI_ADX_enc_8; version_signature = 0x0400; } } else if (version_signature == 0x0409) { if (find_key(streamFile, 9, &xor_start, &xor_mult, &xor_add)) { coding_type = coding_CRI_ADX_enc_9; version_signature = 0x0400; } } if (version_signature == 0x0300) { /* type 03 */ header_type = meta_ADX_03; if (stream_offset-6 >= 0x2c) { /* enough space for loop info? */ loop_flag = (read_32bitBE(0x18,streamFile) != 0); loop_start_sample = read_32bitBE(0x1c,streamFile); loop_start_offset = read_32bitBE(0x20,streamFile); loop_end_sample = read_32bitBE(0x24,streamFile); loop_end_offset = read_32bitBE(0x28,streamFile); } } else if (version_signature == 0x0400) { off_t ainf_info_length=0; if((uint32_t)read_32bitBE(0x24,streamFile)==0x41494E46) /* AINF Header */ ainf_info_length = (off_t)read_32bitBE(0x28,streamFile); header_type = meta_ADX_04; if (stream_offset-ainf_info_length-6 >= 0x38) { /* enough space for loop info? */ if (read_32bitBE(0x24,streamFile) == 0xFFFEFFFE) loop_flag = 0; else loop_flag = (read_32bitBE(0x24,streamFile) != 0); loop_start_sample = read_32bitBE(0x28,streamFile); loop_start_offset = read_32bitBE(0x2c,streamFile); loop_end_sample = read_32bitBE(0x30,streamFile); loop_end_offset = read_32bitBE(0x34,streamFile); } } else if (version_signature == 0x0500) { /* found in some SFD : Buggy Heat, appears to have no loop */ header_type = meta_ADX_05; } else goto fail; /* not a known/supported version signature */ /* At this point we almost certainly have an ADX file, * so let's build the VGMSTREAM. */ /* high-pass cutoff frequency, always 500 that I've seen */ cutoff = (uint16_t)read_16bitBE(0x10,streamFile); if (loop_start_sample == 0 && loop_end_sample == 0) { loop_flag = 0; } channel_count = read_8bit(7,streamFile); vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->num_samples = read_32bitBE(0xc,streamFile); vgmstream->sample_rate = read_32bitBE(8,streamFile); /* channels and loop flag are set by allocate_vgmstream */ vgmstream->loop_start_sample = loop_start_sample; vgmstream->loop_end_sample = loop_end_sample; vgmstream->coding_type = coding_type; if (channel_count==1) vgmstream->layout_type = layout_none; else vgmstream->layout_type = layout_interleave; vgmstream->meta_type = header_type; vgmstream->interleave_block_size=18; /* calculate filter coefficients */ { double x,y,z,a,b,c; x = cutoff; y = vgmstream->sample_rate; z = cos(2.0*M_PI*x/y); a = M_SQRT2-z; b = M_SQRT2-1.0; c = (a-sqrt((a+b)*(a-b)))/b; coef1 = floor(c*8192); coef2 = floor(c*c*-4096); } { int i; STREAMFILE * chstreamfile; /* ADX is so tightly interleaved that having two buffers is silly */ chstreamfile = streamFile->open(streamFile,filename,18*0x400); if (!chstreamfile) goto fail; for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = chstreamfile; vgmstream->ch[i].channel_start_offset= vgmstream->ch[i].offset= stream_offset+18*i; vgmstream->ch[i].adpcm_coef[0] = coef1; vgmstream->ch[i].adpcm_coef[1] = coef2; if (coding_type == coding_CRI_ADX_enc_8 || coding_type == coding_CRI_ADX_enc_9) { int j; vgmstream->ch[i].adx_channels = channel_count; vgmstream->ch[i].adx_xor = xor_start; vgmstream->ch[i].adx_mult = xor_mult; vgmstream->ch[i].adx_add = xor_add; for (j=0;j<i;j++) adx_next_key(&vgmstream->ch[i]); } } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* FLX - from Ultima IX (.FLX is actually an archive format with sometimes sound data, let's support both anyway) */ VGMSTREAM * init_vgmstream_flx(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset, stream_offset = 0; size_t data_size; int loop_flag, channel_count, codec; int total_subsongs = 0, target_subsong = streamFile->stream_index; size_t stream_size = 0; /* check extensions (.flx: name of archive, files inside don't have extensions) */ if (!check_extensions(streamFile,"flx")) goto fail; /* all spaces up to 0x50 = archive FLX */ if (read_32bitBE(0x00,streamFile) == 0x20202020 && read_32bitBE(0x40,streamFile) == 0x20202020) { int i; int entries = read_32bitLE(0x50,streamFile); off_t offset = 0x80; if (read_32bitLE(0x54,streamFile) != 0x02 || read_32bitLE(0x58,streamFile) != get_streamfile_size(streamFile)) goto fail; if (target_subsong == 0) target_subsong = 1; for (i = 0; i < entries; i++) { off_t entry_offset = read_32bitLE(offset + 0x00, streamFile); size_t entry_size = read_32bitLE(offset + 0x04, streamFile); offset += 0x08; if (entry_offset != 0x00) total_subsongs++; /* many entries are empty */ if (total_subsongs == target_subsong && stream_offset == 0) { stream_offset = entry_offset; /* found but let's keep adding total_streams */ stream_size = entry_size; } } if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; if (stream_offset == 0x00) goto fail; } else { stream_offset = 0x00; stream_size = get_streamfile_size(streamFile); } if (read_32bitLE(stream_offset + 0x30,streamFile) != 0x10) goto fail; data_size = read_32bitLE(stream_offset + 0x28,streamFile); channel_count = read_32bitLE(stream_offset + 0x34,streamFile); codec = read_32bitLE(stream_offset + 0x38,streamFile); loop_flag = (channel_count > 1); /* full seamless repeats in music */ start_offset = stream_offset + 0x3c; /* 0x00: id */ /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; vgmstream->sample_rate = read_32bitLE(stream_offset + 0x2c,streamFile); vgmstream->num_streams = total_subsongs; vgmstream->stream_size = stream_size; vgmstream->meta_type = meta_PC_FLX; switch(codec) { case 0x00: /* PCM (sfx) */ vgmstream->coding_type = coding_PCM16LE; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x02; vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, 16); break; case 0x01: /* EA-XA (music, sfx) */ vgmstream->coding_type = channel_count > 1 ? coding_EA_XA : coding_EA_XA_int; vgmstream->layout_type = layout_none; vgmstream->num_samples = read_32bitLE(stream_offset + 0x28,streamFile) / 0x0f*channel_count * 28; /* ea_xa_bytes_to_samples */ vgmstream->loop_start_sample = 0; vgmstream->loop_end_sample = vgmstream->num_samples; break; case 0x02: /* EA-MT (voices) */ vgmstream->coding_type = coding_EA_MT; vgmstream->codec_data = init_ea_mt(vgmstream->channels, 0); if (!vgmstream->codec_data) goto fail; vgmstream->num_samples = read_32bitLE(start_offset,streamFile); start_offset += 0x04; break; default: VGM_LOG("FLX: unknown codec 0x%x\n", codec); goto fail; } read_string(vgmstream->stream_name,0x20+1, stream_offset + 0x04,streamFile); /* open the file for reading */ if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; return vgmstream; fail: 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; }
VGMSTREAM * init_vgmstream_dsp_ygo(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; int loop_flag; int channel_count; off_t start_offset; int i; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("dsp",filename_extension(filename))) goto fail; /* check file size with size given in header */ if ((read_32bitBE(0x0,streamFile)+0xE0) != (get_streamfile_size(streamFile))) goto fail; loop_flag = (uint16_t)(read_16bitBE(0x2C,streamFile) != 0x0); channel_count = 1; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ start_offset = 0xE0; vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitBE(0x28,streamFile); vgmstream->coding_type = coding_NGC_DSP; vgmstream->num_samples = read_32bitBE(0x20,streamFile); vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_DSP_YGO; if (loop_flag) { vgmstream->loop_start_sample = (read_32bitBE(0x30,streamFile)*14/16); vgmstream->loop_end_sample = (read_32bitBE(0x34,streamFile)*14/16); } // read coef stuff { for (i=0;i<16;i++) { vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x3C+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; fail: /* clean up anything we may have opened */ if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* .XPS+DAT - From Software games streams [Metal Wolf Chaos (Xbox), Otogi (Xbox)] */ VGMSTREAM * init_vgmstream_xps_dat(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; STREAMFILE * streamData = NULL; off_t start_offset, header_offset; size_t stream_size; int loop_flag, channel_count, sample_rate, codec, loop_start_sample, loop_end_sample, file_id; int total_subsongs, target_subsong = streamFile->stream_index; /* checks */ if (!check_extensions(streamFile, "xps")) goto fail; if (read_32bitLE(0x00,streamFile) != get_streamfile_size(streamFile)) goto fail; if (read_32bitBE(0x0c,streamFile) != 0x64696666) /* "diff" */ goto fail; /* handle .xps+dat (bank .xps are done below) */ streamData = open_streamfile_by_ext(streamFile, "dat"); if (!streamData) goto fail; /* 0x00: approximate file size */ total_subsongs = read_32bitLE(0x04,streamData); if (target_subsong == 0) target_subsong = 1; if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; header_offset = 0x20 + 0x94*(target_subsong-1); /* could start at 0x0c too */ file_id = read_32bitLE(header_offset+0x00,streamData); start_offset = read_32bitLE(header_offset+0x04,streamData); stream_size = read_32bitLE(header_offset+0x08,streamData); /* 0x0c: loop start offset? */ /* 0x10: loop end offset? */ /* 0x14: always null? */ codec = read_16bitLE(header_offset+0x18,streamData); channel_count = read_16bitLE(header_offset+0x1a,streamData); sample_rate = read_32bitLE(header_offset+0x1c,streamData); /* 0x20: average bitrate */ /* 0x24: block size, bps */ loop_flag = read_32bitLE(header_offset+0x5c,streamData); loop_start_sample = read_32bitLE(header_offset+0x6c,streamData); loop_end_sample = read_32bitLE(header_offset+0x70,streamData) + 1; /* a "smpl" chunk basically */ /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count, loop_flag); if (!vgmstream) goto fail; vgmstream->sample_rate = sample_rate; vgmstream->meta_type = meta_XPS_DAT; vgmstream->loop_start_sample = loop_start_sample; vgmstream->loop_end_sample = loop_end_sample; vgmstream->num_streams = total_subsongs; vgmstream->stream_size = stream_size; switch(codec) { case 0x01: 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); break; case 0x69: vgmstream->coding_type = coding_XBOX_IMA; vgmstream->layout_type = layout_none; vgmstream->num_samples = xbox_ima_bytes_to_samples(stream_size, channel_count); break; default: goto fail; } read_xps_name(vgmstream, streamFile, file_id); if (!vgmstream_open_stream(vgmstream,streamData,start_offset)) goto fail; close_streamfile(streamData); return vgmstream; fail: close_streamfile(streamData); close_vgmstream(vgmstream); return NULL; }
VGMSTREAM * init_vgmstream_ps2_svag_snk(STREAMFILE* streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; off_t start_offset = 0x20; int loop_flag; int channel_count; int loop_start_block; int loop_end_block; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("svag",filename_extension(filename))) goto fail; /* check SNK SVAG Header ("VAGm") */ if (read_32bitBE(0x00,streamFile) != 0x5641476D) goto fail; channel_count = read_32bitLE(0x0c,streamFile); loop_start_block = read_32bitLE(0x18,streamFile); loop_end_block = read_32bitLE(0x1c,streamFile); loop_flag = loop_end_block > 0; /* loop_start_block can be 0 */ /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* header data */ vgmstream->coding_type = coding_PSX; vgmstream->meta_type = meta_PS2_SVAG_SNK; vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitLE(0x08,streamFile); vgmstream->num_samples = read_32bitLE(0x10,streamFile) * 28; /* size in blocks */ if( vgmstream->loop_flag ) { vgmstream->loop_start_sample = loop_start_block * 28; vgmstream->loop_end_sample = loop_end_block * 28; } vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x10; /* 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_his(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; int channel_count; int loop_flag = 0; int bps = 0; off_t start_offset; const uint8_t header_magic_expected[0x16] = "Her Interactive Sound\x1a"; uint8_t header_magic[0x16]; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("his",filename_extension(filename))) goto fail; /* check header magic */ if (0x16 != streamFile->read(streamFile, header_magic, 0, 0x16)) goto fail; if (memcmp(header_magic_expected, header_magic, 0x16)) goto fail; /* data chunk label */ if (0x64617461 != read_32bitBE(0x24,streamFile)) goto fail; start_offset = 0x2c; channel_count = read_16bitLE(0x16,streamFile); /* 8-bit or 16-bit expected */ switch (read_16bitLE(0x22,streamFile)) { case 8: bps = 1; break; case 16: bps = 2; break; default: goto fail; } /* check bytes per frame */ if (read_16bitLE(0x20,streamFile) != channel_count*bps) goto fail; /* check size */ /* file size -8 */ if ((read_32bitLE(0x1c,streamFile)+8) != get_streamfile_size(streamFile)) goto fail; /* data chunk size, assume it occupies the rest of the file */ //if ((read_32bitLE(0x28,streamFile)+start_offset) != get_streamfile_size(streamFile)) // 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_32bitLE(0x28,streamFile) / channel_count / bps; vgmstream->sample_rate = read_32bitLE(0x18,streamFile); vgmstream->meta_type = meta_HIS; vgmstream->layout_type = layout_none; if (bps == 2) { vgmstream->coding_type = coding_PCM16LE; if (channel_count == 2) { vgmstream->coding_type = coding_PCM16LE_int; vgmstream->interleave_block_size = 2; } } else // bps == 1 { vgmstream->coding_type = coding_PCM8_U; if (channel_count == 2) { vgmstream->coding_type = coding_PCM8_U_int; vgmstream->interleave_block_size = 1; } } /* open the file for reading */ { STREAMFILE * file; file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!file) goto fail; vgmstream->ch[0].streamfile = file; vgmstream->ch[0].channel_start_offset= vgmstream->ch[0].offset=start_offset; if (channel_count == 2) { file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!file) goto fail; vgmstream->ch[1].streamfile = file; vgmstream->ch[0].channel_start_offset= vgmstream->ch[1].offset=start_offset + vgmstream->interleave_block_size; } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; struct riff_fmt_chunk fmt; off_t file_size = -1; int sample_count = 0; int fact_sample_count = -1; off_t start_offset = -1; int loop_flag = 0; long loop_start_ms = -1; long loop_end_ms = -1; off_t loop_start_offset = -1; off_t loop_end_offset = -1; uint32_t riff_size; uint32_t data_size = 0; int FormatChunkFound = 0; int DataChunkFound = 0; /* Level-5 mwv */ int mwv = 0; off_t mwv_pflt_offset = -1; off_t mwv_ctrl_offset = -1; /* Ubisoft sns */ int sns = 0; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("wav",filename_extension(filename)) && strcasecmp("lwav",filename_extension(filename))) { if (!strcasecmp("mwv",filename_extension(filename))) mwv = 1; else if (!strcasecmp("sns",filename_extension(filename))) sns = 1; else goto fail; } /* check header */ if ((uint32_t)read_32bitBE(0,streamFile)!=0x52494646) /* "RIFF" */ goto fail; /* check for WAVE form */ if ((uint32_t)read_32bitBE(8,streamFile)!=0x57415645) /* "WAVE" */ goto fail; riff_size = read_32bitLE(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_32bitLE(current_chunk+4,streamFile); if (current_chunk+8+chunk_size > file_size) goto fail; switch(chunk_type) { case 0x666d7420: /* "fmt " */ /* only one per file */ if (FormatChunkFound) goto fail; FormatChunkFound = 1; if (-1 == read_fmt(0, /* big endian == false*/ streamFile, current_chunk, &fmt, sns, mwv)) goto fail; break; case 0x64617461: /* data */ /* at most one per file */ if (DataChunkFound) goto fail; DataChunkFound = 1; start_offset = current_chunk + 8; data_size = chunk_size; break; case 0x4C495354: /* LIST */ /* what lurks within?? */ switch (read_32bitBE(current_chunk + 8, streamFile)) { case 0x6164746C: /* adtl */ /* yay, atdl is its own little world */ parse_adtl(current_chunk + 8, chunk_size, streamFile, &loop_start_ms,&loop_end_ms,&loop_flag); break; default: break; } break; case 0x736D706C: /* smpl */ /* check loop count */ if (read_32bitLE(current_chunk+0x24, streamFile)==1) { /* check loop info */ if (read_32bitLE(current_chunk+0x2c+4, streamFile)==0) { loop_flag = 1; loop_start_offset = read_32bitLE(current_chunk+0x2c+8, streamFile); loop_end_offset = read_32bitLE(current_chunk+0x2c+0xc,streamFile); } } break; case 0x70666c74: /* pflt */ if (!mwv) break; /* ignore if not in an mwv */ /* predictor filters */ mwv_pflt_offset = current_chunk; break; case 0x6374726c: /* ctrl */ if (!mwv) break; /* ignore if not in an mwv */ /* loops! */ if (read_32bitLE(current_chunk+8, streamFile)) { loop_flag = 1; } mwv_ctrl_offset = current_chunk; break; case 0x66616374: /* fact */ if (chunk_size != 4 && (!(sns && chunk_size == 0x10))) break; fact_sample_count = read_32bitLE(current_chunk+8, streamFile); break; default: /* ignorance is bliss */ break; } current_chunk += 8+chunk_size; } } if (!FormatChunkFound || !DataChunkFound) goto fail; switch (fmt.coding_type) { case coding_PCM16LE: sample_count = data_size/2/fmt.channel_count; break; case coding_PCM8_U_int: sample_count = data_size/fmt.channel_count; break; case coding_L5_555: sample_count = data_size/0x12/fmt.channel_count*32; break; case coding_MSADPCM: sample_count = msadpcm_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count); break; case coding_MS_IMA: sample_count = (data_size / fmt.block_size) * (fmt.block_size - 4 * fmt.channel_count) * 2 / fmt.channel_count + ((data_size % fmt.block_size) ? (data_size % fmt.block_size - 4 * fmt.channel_count) * 2 / fmt.channel_count : 0); break; case coding_NGC_DSP: break; default: goto fail; } /* .sns uses fact chunk */ if (sns) { if (-1 == fact_sample_count) goto fail; sample_count = fact_sample_count; } /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(fmt.channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->num_samples = sample_count; vgmstream->sample_rate = fmt.sample_rate; vgmstream->coding_type = fmt.coding_type; vgmstream->layout_type = layout_none; if (fmt.channel_count > 1) { switch (fmt.coding_type) { case coding_PCM8_U_int: case coding_MS_IMA: case coding_MSADPCM: // use layout_none from above break; default: vgmstream->layout_type = layout_interleave; break; } } vgmstream->interleave_block_size = fmt.interleave; switch (fmt.coding_type) { case coding_MSADPCM: case coding_MS_IMA: // override interleave_block_size with frame size vgmstream->interleave_block_size = fmt.block_size; break; default: // use interleave from above break; } if (loop_flag) { if (loop_start_ms >= 0) { vgmstream->loop_start_sample = (long long)loop_start_ms*fmt.sample_rate/1000; vgmstream->loop_end_sample = (long long)loop_end_ms*fmt.sample_rate/1000; vgmstream->meta_type = meta_RIFF_WAVE_labl_Marker; } else if (loop_start_offset >= 0) { vgmstream->loop_start_sample = loop_start_offset; vgmstream->loop_end_sample = loop_end_offset; vgmstream->meta_type = meta_RIFF_WAVE_smpl; } else if (mwv && mwv_ctrl_offset != -1) { vgmstream->loop_start_sample = read_32bitLE(mwv_ctrl_offset+12, streamFile); vgmstream->loop_end_sample = sample_count; } } else { vgmstream->meta_type = meta_RIFF_WAVE; } if (mwv) { int i, c; if (fmt.coding_type == coding_L5_555) { const int filter_order = 3; int filter_count = read_32bitLE(mwv_pflt_offset+12, streamFile); if (mwv_pflt_offset == -1 || read_32bitLE(mwv_pflt_offset+8, streamFile) != filter_order || read_32bitLE(mwv_pflt_offset+4, streamFile) < 8 + filter_count * 4 * filter_order) goto fail; if (filter_count > 0x20) goto fail; for (c = 0; c < fmt.channel_count; c++) { for (i = 0; i < filter_count * filter_order; i++) { vgmstream->ch[c].adpcm_coef_3by32[i] = read_32bitLE( mwv_pflt_offset+16+i*4, streamFile ); } } } vgmstream->meta_type = meta_RIFF_WAVE_MWV; } if (sns) { int c; /* common codebook? */ static const int16_t coef[16] = {0x04ab,0xfced,0x0789,0xfedf,0x09a2,0xfae5,0x0c90,0xfac1, 0x084d,0xfaa4,0x0982,0xfdf7,0x0af6,0xfafa,0x0be6,0xfbf5}; for (c = 0; c < fmt.channel_count; c++) { int i; for (i = 0; i < 16; i++) { vgmstream->ch[c].adpcm_coef[i] = coef[i]; } } vgmstream->meta_type = meta_RIFF_WAVE_SNS; } /* 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<fmt.channel_count;i++) { vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile; vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset = start_offset+i*fmt.interleave; } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
void __declspec(dllexport) DLL_FreeVGM(long vgm) { close_vgmstream((VGMSTREAM*)vgm); }
VGMSTREAM * init_vgmstream_rifx(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; struct riff_fmt_chunk fmt; off_t file_size = -1; int sample_count = 0; int fact_sample_count = -1; off_t start_offset = -1; off_t wiih_offset = -1; uint32_t wiih_size = 0; int loop_flag = 0; off_t loop_start_offset = -1; off_t loop_end_offset = -1; uint32_t riff_size; uint32_t data_size = 0; int FormatChunkFound = 0; int DataChunkFound = 0; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("wav",filename_extension(filename)) && strcasecmp("lwav",filename_extension(filename))) { goto fail; } /* check header */ if ((uint32_t)read_32bitBE(0,streamFile)!=0x52494658) /* "RIFX" */ goto fail; /* check for WAVE form */ if ((uint32_t)read_32bitBE(8,streamFile)!=0x57415645) /* "WAVE" */ 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 0x666d7420: /* "fmt " */ /* only one per file */ if (FormatChunkFound) goto fail; FormatChunkFound = 1; if (-1 == read_fmt(1, /* big endian == true */ streamFile, current_chunk, &fmt, 0, /* sns == false */ 0)) /* mwv == false */ goto fail; break; case 0x64617461: /* data */ /* at most one per file */ if (DataChunkFound) goto fail; DataChunkFound = 1; start_offset = current_chunk + 8; data_size = chunk_size; break; case 0x736D706C: /* smpl */ /* check loop count */ if (read_32bitBE(current_chunk+0x24, streamFile)==1) { /* check loop info */ if (read_32bitBE(current_chunk+0x2c+4, streamFile)==0) { loop_flag = 1; loop_start_offset = read_32bitBE(current_chunk+0x2c+8, streamFile); loop_end_offset = read_32bitBE(current_chunk+0x2c+0xc,streamFile); } } break; case 0x66616374: /* fact */ if (chunk_size != 4) break; fact_sample_count = read_32bitBE(current_chunk+8, streamFile); break; case 0x57696948: /* WiiH */ wiih_size = read_32bitBE(current_chunk+4, streamFile); wiih_offset = current_chunk+8; break; default: /* ignorance is bliss */ break; } current_chunk += 8+chunk_size; } } if (!FormatChunkFound || !DataChunkFound) goto fail; switch (fmt.coding_type) { case coding_PCM16BE: sample_count = data_size/2/fmt.channel_count; break; case coding_PCM8_U_int: sample_count = data_size/fmt.channel_count; break; case coding_NGC_DSP: /* the only way of getting DSP info right now */ if (wiih_offset < 0 || wiih_size != 0x2e*fmt.channel_count) goto fail; sample_count = data_size/8/fmt.channel_count*14; break; #if 0 /* found in RE:ORC, looks like it should be MS_IMA instead */ case coding_MSADPCM: sample_count = msadpcm_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count); break; #endif default: goto fail; } /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(fmt.channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->num_samples = sample_count; vgmstream->sample_rate = fmt.sample_rate; vgmstream->coding_type = fmt.coding_type; vgmstream->layout_type = layout_none; if (fmt.channel_count > 1) { switch (fmt.coding_type) { case coding_PCM8_U_int: case coding_MS_IMA: case coding_MSADPCM: // use layout_none from above break; default: vgmstream->layout_type = layout_interleave; break; } } vgmstream->interleave_block_size = fmt.interleave; switch (fmt.coding_type) { case coding_MSADPCM: case coding_MS_IMA: // override interleave_block_size with frame size vgmstream->interleave_block_size = fmt.block_size; break; default: // use interleave from above break; } if (fmt.coding_type == coding_MS_IMA) vgmstream->interleave_block_size = fmt.block_size; if (loop_flag) { if (loop_start_offset >= 0) { vgmstream->loop_start_sample = loop_start_offset; vgmstream->loop_end_sample = loop_end_offset; vgmstream->meta_type = meta_RIFX_WAVE_smpl; } } else { vgmstream->meta_type = meta_RIFX_WAVE; } /* read from WiiH */ if (wiih_offset >= 0) { int i,j; for (i=0;i<fmt.channel_count;i++) { for (j=0;j<16;j++) vgmstream->ch[i].adpcm_coef[j] = read_16bitBE(wiih_offset + i * 0x2e + j * 2,streamFile); vgmstream->ch[i].adpcm_history1_16 = read_16bitBE(wiih_offset + i * 0x2e + 0x24,streamFile); vgmstream->ch[i].adpcm_history2_16 = read_16bitBE(wiih_offset + i * 0x2e + 0x26,streamFile); } } /* 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<fmt.channel_count;i++) { vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile; vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset = start_offset+i*fmt.interleave; } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
VGMSTREAM * init_vgmstream_aix(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; STREAMFILE * streamFileAIX = NULL; STREAMFILE * streamFileADX = NULL; char filename[260]; off_t *segment_offset = NULL; int32_t *samples_in_segment = NULL; int32_t sample_count; int loop_flag = 0; int32_t loop_start_sample=0; int32_t loop_end_sample=0; aix_codec_data *data = NULL; off_t first_AIXP; off_t stream_list_offset; off_t stream_list_end; const int segment_list_entry_size = 0x10; const off_t segment_list_offset = 0x20; int stream_count,channel_count,segment_count; int sample_rate; int i; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("aix",filename_extension(filename))) goto fail; if (read_32bitBE(0x0,streamFile) != 0x41495846 || /* "AIXF" */ read_32bitBE(0x08,streamFile) != 0x01000014 || read_32bitBE(0x0c,streamFile) != 0x00000800) goto fail; first_AIXP = read_32bitBE(0x4,streamFile)+8; segment_count = (uint16_t)read_16bitBE(0x18,streamFile); stream_list_offset = segment_list_offset+segment_list_entry_size*segment_count+0x10; if (stream_list_offset >= first_AIXP) goto fail; if (segment_count < 1) goto fail; sample_rate = read_32bitBE(stream_list_offset+8,streamFile); if (!check_sample_rate(sample_rate)) goto fail; samples_in_segment = calloc(segment_count,sizeof(int32_t)); if (!samples_in_segment) goto fail; segment_offset = calloc(segment_count,sizeof(off_t)); if (!segment_offset) goto fail; for (i = 0; i < segment_count; i++) { segment_offset[i] = read_32bitBE(segment_list_offset+segment_list_entry_size*i+0,streamFile); samples_in_segment[i] = read_32bitBE(segment_list_offset+segment_list_entry_size*i+0x08,streamFile); /*printf("samples_in_segment[%d]=%d\n",i,samples_in_segment[i]);*/ /* all segments must have equal sample rate */ if (read_32bitBE(segment_list_offset+segment_list_entry_size*i+0x0c,streamFile) != sample_rate) { /* segments > 0 can have 0 sample rate (Ryu ga gotoku: Kenzan! tenkei_sng1.aix), seems to indicate same sample rate as first */ if (!(i > 0 && read_32bitBE(segment_list_offset+segment_list_entry_size*i+0x0c,streamFile) == 0)) goto fail; } } if (segment_offset[0] != first_AIXP) goto fail; stream_count = (uint8_t)read_8bit(stream_list_offset,streamFile); if (stream_count < 1) goto fail; stream_list_end = stream_list_offset + 0x8 + stream_count * 8; if (stream_list_end >= first_AIXP) goto fail; channel_count = 0; for (i = 0; i < stream_count; i++) { /* all streams must have same samplerate as segments */ if (read_32bitBE(stream_list_offset+8+i*8,streamFile)!=sample_rate) goto fail; channel_count += read_8bit(stream_list_offset+8+i*8+4,streamFile); } /* check for existence of segments */ for (i = 0; i < segment_count; i++) { int j; off_t AIXP_offset = segment_offset[i]; for (j = 0; j < stream_count; j++) { if (read_32bitBE(AIXP_offset,streamFile)!=0x41495850) /* "AIXP" */ goto fail; if (read_8bit(AIXP_offset+8,streamFile)!=j) goto fail; AIXP_offset += read_32bitBE(AIXP_offset+4,streamFile)+8; } } /*streamFileAIX = streamFile->open(streamFile,filename,sample_rate*0.0375*2/32*18segment_count);*/ streamFileAIX = streamFile->open(streamFile,filename,sample_rate*0.1*segment_count); if (!streamFileAIX) goto fail; data = malloc(sizeof(aix_codec_data)); if (!data) goto fail; data->segment_count = segment_count; data->stream_count = stream_count; data->adxs = malloc(sizeof(STREAMFILE *)*segment_count*stream_count); if (!data->adxs) goto fail; for (i=0;i<segment_count*stream_count;i++) { data->adxs[i] = NULL; } data->sample_counts = calloc(segment_count,sizeof(int32_t)); if (!data->sample_counts) goto fail; memcpy(data->sample_counts,samples_in_segment,segment_count*sizeof(int32_t)); /* for each segment */ for (i = 0; i < segment_count; i++) { int j; /* for each stream */ for (j = 0; j < stream_count; j++) { VGMSTREAM *adx; /*printf("try opening segment %d/%d stream %d/%d %x\n",i,segment_count,j,stream_count,segment_offset[i]);*/ streamFileADX = open_aix_with_STREAMFILE(streamFileAIX,segment_offset[i],j); if (!streamFileADX) goto fail; adx = data->adxs[i*stream_count+j] = init_vgmstream_adx(streamFileADX); if (!adx) goto fail; close_streamfile(streamFileADX); streamFileADX = NULL; if (adx->num_samples != data->sample_counts[i] || 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)); } } if (segment_count > 1) { loop_flag = 1; } sample_count = 0; for (i = 0; i < segment_count; i++) { sample_count += data->sample_counts[i]; if (i == 0) loop_start_sample = sample_count; if (i == 1) loop_end_sample = sample_count; } 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_aix; vgmstream->meta_type = meta_AIX; vgmstream->ch[0].streamfile = streamFileAIX; data->current_segment = 0; vgmstream->codec_data = data; free(segment_offset); free(samples_in_segment); return vgmstream; /* clean up anything we may have opened */ fail: if (streamFileAIX) close_streamfile(streamFileAIX); if (streamFileADX) close_streamfile(streamFileADX); if (vgmstream) close_vgmstream(vgmstream); if (samples_in_segment) free(samples_in_segment); if (segment_offset) free(segment_offset); if (data) { if (data->adxs) { int i; for (i=0;i<data->segment_count*data->stream_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; }
/* XNBm (Windows 7 Phone) */ VGMSTREAM * init_vgmstream_xnbm(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; struct riff_fmt_chunk fmt; off_t file_size = -1; int sample_count = 0; off_t start_offset = -1; int loop_flag = 0; #if 0 long loop_start_ms = -1; long loop_end_ms = -1; off_t loop_start_offset = -1; off_t loop_end_offset = -1; #endif uint32_t xnbm_size; uint32_t data_size = 0; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("xnb",filename_extension(filename))) { goto fail; } /* check header */ if ((uint32_t)read_32bitBE(0,streamFile)!=0x584E426d) /* "XNBm" */ goto fail; /* check version? */ if ((uint32_t)read_16bitLE(4,streamFile)!=5) goto fail; xnbm_size = read_32bitLE(6,streamFile); file_size = get_streamfile_size(streamFile); /* check for tructated XNBm */ if (file_size < xnbm_size) goto fail; /* read through chunks to verify format and find metadata */ { off_t current_chunk = 0xa; /* start with first chunk */ int id_string_len; uint32_t fmt_chunk_size; /* flag? count of strings? */ if (read_8bit(current_chunk ++, streamFile) != 1) goto fail; /* string length */ id_string_len = read_8bit(current_chunk ++, streamFile); /* skip string */ /* may want to check this ID "Microsoft.Xna.Framework.Content.SoundEffectReader" */ current_chunk += id_string_len; /* ???? */ if (read_32bitLE(current_chunk, streamFile) != 0) goto fail; current_chunk += 4; /* ???? */ if (read_8bit(current_chunk ++, streamFile) != 0) goto fail; /* flag? count of chunks? */ if (read_8bit(current_chunk++, streamFile) != 1) goto fail; /* fmt size */ fmt_chunk_size = read_32bitLE(current_chunk, streamFile); current_chunk += 4; if (-1 == read_fmt(0, /* big endian == false */ streamFile, current_chunk-8, /* read_fmt() expects to skip "fmt "+size */ &fmt, 0, /* sns == false */ 0)) /* mwv == false */ goto fail; current_chunk += fmt_chunk_size; /* data size! */ data_size = read_32bitLE(current_chunk, streamFile); current_chunk += 4; start_offset = current_chunk; } switch (fmt.coding_type) { case coding_PCM16LE: sample_count = data_size/2/fmt.channel_count; break; case coding_PCM8_U_int: sample_count = data_size/fmt.channel_count; break; case coding_MSADPCM: sample_count = msadpcm_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count); break; case coding_MS_IMA: sample_count = (data_size / fmt.block_size) * (fmt.block_size - 4 * fmt.channel_count) * 2 / fmt.channel_count + ((data_size % fmt.block_size) ? (data_size % fmt.block_size - 4 * fmt.channel_count) * 2 / fmt.channel_count : 0); break; default: goto fail; } /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(fmt.channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->num_samples = sample_count; vgmstream->sample_rate = fmt.sample_rate; vgmstream->coding_type = fmt.coding_type; vgmstream->layout_type = layout_none; if (fmt.channel_count > 1) { switch (fmt.coding_type) { case coding_PCM8_U_int: case coding_MS_IMA: case coding_MSADPCM: // use layout_none from above break; default: vgmstream->layout_type = layout_interleave; break; } } vgmstream->interleave_block_size = fmt.interleave; switch (fmt.coding_type) { case coding_MSADPCM: case coding_MS_IMA: // override interleave_block_size with frame size vgmstream->interleave_block_size = fmt.block_size; break; default: // use interleave from above break; } vgmstream->meta_type = meta_XNBm; /* 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<fmt.channel_count;i++) { vgmstream->ch[i].streamfile = vgmstream->ch[0].streamfile; vgmstream->ch[i].offset = vgmstream->ch[i].channel_start_offset = start_offset+i*fmt.interleave; } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* GCUB - found in 'Sega Soccer Slam' */ VGMSTREAM * init_vgmstream_ngc_gcub(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("gcub",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x47437562) /* "GCub" */ goto fail; loop_flag = 0; channel_count = read_32bitBE(0x04,streamFile); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ if (read_32bitBE(0x60,streamFile) == 0x47437878) /* "GCxx" */ { start_offset = 0x88; } else { start_offset = 0x60; } vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitBE(0x08,streamFile); vgmstream->coding_type = coding_NGC_DSP; vgmstream->num_samples = (read_32bitBE(0x0C,streamFile)-start_offset)/8/channel_count*14; if (loop_flag) { vgmstream->loop_start_sample = 0; vgmstream->loop_end_sample = (read_32bitBE(0x0C,streamFile)-start_offset)/8/channel_count*14; } if (channel_count == 1) { vgmstream->layout_type = layout_none; } else { vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x8000; // read_32bitBE(0x04,streamFile); } vgmstream->meta_type = meta_NGC_GCUB; if (vgmstream->coding_type == coding_NGC_DSP) { int i; for (i=0; i<16; i++) { vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x10+i*2,streamFile); } if (vgmstream->channels == 2) { for (i=0; i<16; i++) { vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x30+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; /* The first channel */ vgmstream->ch[0].channel_start_offset= vgmstream->ch[0].offset=start_offset; /* The second channel */ if (channel_count == 2) { vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!vgmstream->ch[1].streamfile) goto fail; vgmstream->ch[1].channel_start_offset= vgmstream->ch[1].offset=start_offset+vgmstream->interleave_block_size; } } } 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[260]; 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; }