#include "meta.h" #include "../coding/coding.h" /* .IMC - from iNiS Gitaroo Man (PS2) */ VGMSTREAM * init_vgmstream_imc(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset; int loop_flag, channel_count, sample_rate, interleave, blocks; size_t file_size, data_size; /* checks */ /* .imc: extension from the main container */ if (!check_extensions(streamFile, "imc")) goto fail; channel_count = read_32bitLE(0x00, streamFile); sample_rate = read_32bitLE(0x04, streamFile); interleave = read_32bitLE(0x08, streamFile) * 0x10; /* number of frames in a block */ blocks = read_32bitLE(0x0c, streamFile); /* number of interleave blocks (even in mono) */ file_size = get_streamfile_size(streamFile); loop_flag = 0; start_offset = 0x10; /* extra checks since the header is so simple */ if (channel_count < 1 || channel_count > 8) goto fail; if (sample_rate < 11025 || sample_rate > 48000) /* game can play 11025, 16000, 22050, 32000, 44100, 48000. Anything else will be silent in-game. ST10.IMC subsongs 42-47 use 22000, those are unused silent audio */ goto fail; if (interleave*blocks + start_offset != file_size) goto fail; data_size = file_size - start_offset; data_size -= ps_find_padding(streamFile, start_offset, data_size, channel_count, interleave, 0); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count, loop_flag); if (!vgmstream) goto fail; vgmstream->meta_type = meta_IMC; vgmstream->sample_rate = sample_rate; vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count); vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = interleave; if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; return vgmstream; fail: close_vgmstream(vgmstream); return NULL; } /* ****************************************************************************** */ /* .IMC in containers */ VGMSTREAM * init_vgmstream_imc_container(STREAMFILE *streamFile) { VGMSTREAM *vgmstream = NULL; STREAMFILE *temp_streamFile = NULL; off_t header_offset, subfile_offset, next_offset, name_offset; size_t subfile_size; int total_subsongs, target_subsong = streamFile->stream_index; /* checks */ if (!check_extensions(streamFile, "imc")) goto fail; total_subsongs = read_32bitLE(0x00, streamFile); if (target_subsong == 0) target_subsong = 1; if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail; header_offset = 0x04 + 0x20*(target_subsong-1); name_offset = header_offset + 0x00; /* 0x08: flags? (0x702ADE77|0x002ADE77|0x20000000|etc) */ /* 0x0c: same for all songs in single .imc but varies between .imc */ subfile_offset = read_32bitLE(header_offset + 0x10,streamFile); /* 0x14: flags/size? (0xF0950000|0x3CFA1200|etc) */ /* 0x18: same for all songs in single .imc but varies between .imc */ /* 0x1c: flags? (0 or 2) */ if (target_subsong == total_subsongs) { next_offset = get_streamfile_size(streamFile); } else { next_offset = read_32bitLE(header_offset + 0x20 + 0x10,streamFile); } subfile_size = next_offset - subfile_offset; temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL); if (!temp_streamFile) goto fail; vgmstream = init_vgmstream_imc(temp_streamFile); if (!vgmstream) goto fail; close_streamfile(temp_streamFile); vgmstream->num_streams = total_subsongs; read_string(vgmstream->stream_name,0x08+1, name_offset,streamFile); return vgmstream; fail: close_streamfile(temp_streamFile); close_vgmstream(vgmstream); return NULL; }