VGMSTREAM * init_vgmstream_ps3_sgd(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("sgd",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x53475844) /* "SGXD" */ goto fail; loop_flag = (read_32bitLE(0x44,streamFile) != 0xFFFFFFFF); channel_count = read_8bit(0x29,streamFile); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ start_offset = read_32bitLE(0x8,streamFile); vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitLE(0x2C,streamFile); vgmstream->coding_type = coding_PSX; vgmstream->num_samples = read_32bitLE(0x40,streamFile)/16/channel_count*28; if (loop_flag) { vgmstream->loop_start_sample = read_32bitLE(0x44,streamFile); vgmstream->loop_end_sample = read_32bitLE(0x48,streamFile); } vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = read_8bit(0x39,streamFile); // just a guess, all of my samples seem to be 0x10 interleave vgmstream->meta_type = meta_PS3_SGX; /* 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; }
static int parse_fixed_header(STREAMFILE* streamFile, ea_header* ea, off_t begin_offset) { off_t offset = begin_offset; if (read_32bitBE(offset+0x00, streamFile) != 0x5041546C && /* "PATl" */ read_32bitBE(offset+0x38, streamFile) != 0x544D706C) /* "TMpl" */ goto fail; offset += 0x3c; /* after TMpl */ ea->version = read_8bit(offset+0x00, streamFile); ea->bps = read_8bit(offset+0x01, streamFile); ea->channels = read_8bit(offset+0x02, streamFile); ea->codec = read_8bit(offset+0x03, streamFile); VGM_ASSERT(read_16bitLE(offset+0x04, streamFile) != 0, "EA SCHl fixed: unknown1 found\n"); /* 0x04(16): unknown */ ea->sample_rate = (uint16_t)read_16bitLE(offset+0x06, streamFile); ea->num_samples = read_32bitLE(offset+0x08, streamFile); VGM_ASSERT(read_32bitLE(offset+0x0c, streamFile) != -1, "EA SCHl fixed: unknown2 found\n"); /* loop start? */ VGM_ASSERT(read_32bitLE(offset+0x10, streamFile) != -1, "EA SCHl fixed: unknown3 found\n"); /* loop end? */ VGM_ASSERT(read_32bitLE(offset+0x14, streamFile) != 0, "EA SCHl fixed: unknown4 found\n"); /* data start? */ VGM_ASSERT(read_32bitLE(offset+0x18, streamFile) != -1, "EA SCHl fixed: unknown5 found\n"); VGM_ASSERT(read_32bitLE(offset+0x1c, streamFile) != 0x7F, "EA SCHl fixed: unknown6 found\n"); //ea->loop_flag = (ea->loop_end_sample); return 1; fail: return 0; }
VGMSTREAM * init_vgmstream_xbox_xmu(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; int loop_flag=0; int channel_count; int i; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("xmu",filename_extension(filename))) goto fail; if((read_32bitBE(0x00,streamFile)!=0x584D5520) && (read_32bitBE(0x08,streamFile)!=0x46524D54)) goto fail; /* No Loop found atm */ loop_flag = read_8bit(0x16,streamFile);; /* Always stereo files */ channel_count=read_8bit(0x14,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(0x10,streamFile); vgmstream->coding_type = coding_XBOX; vgmstream->num_samples = read_32bitLE(0x7FC,streamFile) / 36 * 64 / vgmstream->channels; vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_XBOX_XMU; if(loop_flag) { vgmstream->loop_start_sample=0; 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; } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/** * Sony's HEVAG (High Efficiency VAG) ADPCM, used in PSVita games (hardware decoded). * Evolution of the regular VAG (same flags and frames), uses 4 history samples and a bigger table. * * Original research and algorithm by id-daemon / daemon1. */ void decode_hevag(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { uint8_t predict_nr, shift, flag, byte; int32_t scale = 0; int32_t sample; int32_t hist1 = stream->adpcm_history1_32; int32_t hist2 = stream->adpcm_history2_32; int32_t hist3 = stream->adpcm_history3_32; int32_t hist4 = stream->adpcm_history4_32; int i, sample_count; int framesin = first_sample / 28; /* 4 byte header: predictor = 3rd and 1st, shift = 2nd, flag = 4th */ byte = (uint8_t)read_8bit(stream->offset+framesin*16+0,stream->streamfile); predict_nr = byte >> 4; shift = byte & 0x0f; byte = (uint8_t)read_8bit(stream->offset+framesin*16+1,stream->streamfile); predict_nr = (byte & 0xF0) | predict_nr; flag = byte & 0x0f; /* no change in flags */ first_sample = first_sample % 28; if (first_sample & 1) { /* if first sample is odd, read byte first */ byte = read_8bit(stream->offset+(framesin*16)+2+first_sample/2,stream->streamfile); } for (i = first_sample, sample_count = 0; i < first_sample + samples_to_do; i++, sample_count += channelspacing) { sample = 0; if (flag < 7 && predict_nr < 128) { if (i & 1) {/* odd/even nibble */ scale = byte >> 4; } else { byte = read_8bit(stream->offset+(framesin*16)+2+i/2,stream->streamfile); scale = byte & 0x0f; } if (scale > 7) { /* sign extend */ scale = scale - 16; } sample = (hist1 * HEVAG_coefs[predict_nr][0] + hist2 * HEVAG_coefs[predict_nr][1] + hist3 * HEVAG_coefs[predict_nr][2] + hist4 * HEVAG_coefs[predict_nr][3] ) / 32; sample = (sample + (scale << (20 - shift)) + 128) >> 8; }
VGMSTREAM * init_vgmstream_ss_stream(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("ss7",filename_extension(filename))) goto fail; loop_flag = 0; channel_count=read_8bit(0x0C,streamFile)+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 = 44100; if(channel_count==1) vgmstream->coding_type = coding_IMA; else vgmstream->coding_type = coding_EACS_IMA; vgmstream->num_samples = (int32_t)((get_streamfile_size(streamFile) -0x44)* 2 / vgmstream->channels); vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_XBOX_WAVM; vgmstream->get_high_nibble=0; /* 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 = 0x44; vgmstream->ch[i].adpcm_history1_32=(int32_t)read_16bitLE(0x10+i*4,streamFile); vgmstream->ch[i].adpcm_step_index =(int)read_8bit(0x12+i*4,streamFile); if (!vgmstream->ch[i].streamfile) goto fail; } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
uint32_t readPatch(STREAMFILE* streamFile, off_t* offset) { uint32_t result=0; uint8_t byteCount; byteCount = read_8bit(*offset,streamFile); (*offset)++; for(;byteCount>0;byteCount--) { result <<=8; result+=(uint8_t)read_8bit(*offset,streamFile); (*offset)++; } return result; }
/* Read a line into dst. The source files are MS-DOS style, * separated (not terminated) by CRLF. Return 1 if the full line was * retrieved (if it could fit in dst), 0 otherwise. In any case the result * will be properly terminated. The CRLF will be removed if there is one. * Return the number of bytes read (including CRLF line ending). Note that * this is not the length of the string, and could be larger than the buffer. * *line_done_ptr is set to 1 if the complete line was read into dst, * otherwise it is set to 0. line_done_ptr can be NULL if you aren't * interested in this info. */ size_t get_streamfile_dos_line(int dst_length, char * dst, off_t offset, STREAMFILE * infile, int *line_done_ptr) { int i; off_t file_length = get_streamfile_size(infile); /* how many bytes over those put in the buffer were read */ int extra_bytes = 0; if (line_done_ptr) *line_done_ptr = 0; for (i=0;i<dst_length-1 && offset+i < file_length;i++) { char in_char = read_8bit(offset+i,infile); /* check for end of line */ if (in_char == 0x0d && read_8bit(offset+i+1,infile) == 0x0a) { extra_bytes = 2; if (line_done_ptr) *line_done_ptr = 1; break; } dst[i]=in_char; } dst[i]='\0'; /* did we fill the buffer? */ if (i==dst_length) { /* did the bytes we missed just happen to be the end of the line? */ if (read_8bit(offset+i,infile) == 0x0d && read_8bit(offset+i+1,infile) == 0x0a) { extra_bytes = 2; /* if so be proud! */ if (line_done_ptr) *line_done_ptr = 1; } } /* did we hit the file end? */ if (offset+i == file_length) { /* then we did in fact finish reading the last line */ if (line_done_ptr) *line_done_ptr = 1; } return i+extra_bytes; }
VGMSTREAM * init_vgmstream_ngc_adpdtk(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; STREAMFILE * chstreamfile; char filename[PATH_LIMIT]; size_t file_size; int i; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("adp",filename_extension(filename)) && strcasecmp("dtk",filename_extension(filename))) goto fail; /* file size is the only way to determine sample count */ file_size = get_streamfile_size(streamFile); /* .adp files have no header, so all we can do is look for a valid first frame */ if (read_8bit(0,streamFile)!=read_8bit(2,streamFile) || read_8bit(1,streamFile)!=read_8bit(3,streamFile)) goto fail; /* Hopefully we haven't falsely detected something else... */ /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(2,0); /* always stereo, no loop */ if (!vgmstream) goto fail; vgmstream->num_samples = file_size/32*28; vgmstream->sample_rate = 48000; vgmstream->coding_type = coding_NGC_DTK; vgmstream->layout_type = layout_dtk_interleave; vgmstream->meta_type = meta_NGC_ADPDTK; /* locality is such that two streamfiles is silly */ chstreamfile = streamFile->open(streamFile,filename,32*0x400); if (!chstreamfile) goto fail; for (i=0;i<2;i++) { vgmstream->ch[i].channel_start_offset = vgmstream->ch[i].offset = 0; vgmstream->ch[i].streamfile = chstreamfile; } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i; int32_t sample_count; for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { outbuf[sample_count]=read_8bit(stream->offset+i*channelspacing,stream->streamfile)*0x100; } }
/* decodes a-law (ITU G.711 non-linear PCM), from g711.c */ void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i, sample_count; for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { uint8_t alawbyte = read_8bit(stream->offset+i,stream->streamfile); outbuf[sample_count] = expand_alaw(alawbyte);; } }
/*******************读按键命令************************/ uchar TM1650_read() { uchar key; TM1650_START(); write_8bit(0x49);//读按键指令 key=read_8bit(); TM1650_STOP(); return key; }
void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i; int32_t sample_count; for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { int16_t v = (uint8_t)read_8bit(stream->offset+i,stream->streamfile); outbuf[sample_count] = v*0x100 - 0x8000; } }
/* set up for the block at the given offset */ void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream) { int i; int8_t currentChannel=0; int8_t subAudio=0; init_get_high_nibble(vgmstream); if(vgmstream->samples_into_block!=0) // don't change this variable in the init process vgmstream->xa_sector_length+=128; // We get to the end of a sector ? if(vgmstream->xa_sector_length==(18*128)) { vgmstream->xa_sector_length=0; // 0x30 of unused bytes/sector :( block_offset+=0x30; begin: // Search for selected channel & valid audio currentChannel=read_8bit(block_offset-7,vgmstream->ch[0].streamfile); subAudio=read_8bit(block_offset-6,vgmstream->ch[0].streamfile); // audio is coded as 0x64 if(!((subAudio==0x64) && (currentChannel==vgmstream->xa_channel))) { // go to next sector block_offset+=2352; if(currentChannel!=-1) goto begin; } } vgmstream->current_block_offset = block_offset; // Quid : how to stop the current channel ??? // i set up 0 to current_block_size to make vgmstream not playing bad samples // another way to do it ??? // (as the number of samples can be false in cd-xa due to multi-channels) vgmstream->current_block_size = (currentChannel==-1?0:112); vgmstream->next_block_offset = vgmstream->current_block_offset+128; for (i=0;i<vgmstream->channels;i++) { vgmstream->ch[i].offset = vgmstream->current_block_offset; } }
VGMSTREAM * init_vgmstream_ngc_adpdtk(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset = 0; int channel_count = 2, loop_flag = 0; /* always stereo, no loop */ /* check extension, case insensitive */ if ( !check_extensions(streamFile,"dtk,adp")) goto fail; /* .adp files have no header, and the ext is common, so all we can do is look for valid first frames */ if (check_extensions(streamFile,"adp")) { int i; for (i = 0; i < 10; i++) { /* try a bunch of frames */ if (read_8bit(0x00 + i*0x20,streamFile) != read_8bit(0x02 + i*0x20,streamFile) || read_8bit(0x01 + i*0x20,streamFile) != read_8bit(0x03 + i*0x20,streamFile)) goto fail; } } /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count, loop_flag); if (!vgmstream) goto fail; vgmstream->num_samples = get_streamfile_size(streamFile) / 32 * 28; vgmstream->sample_rate = 48000; vgmstream->coding_type = coding_NGC_DTK; vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_NGC_ADPDTK; /* open the file for reading */ if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; return vgmstream; fail: close_vgmstream(vgmstream); return NULL; }
off_t init_xa_channel(int* channel,STREAMFILE* streamFile) { off_t block_offset=0x44; size_t filelength=get_streamfile_size(streamFile); int8_t currentChannel; int8_t subAudio; // 0 can't be a correct value if(block_offset>=(off_t)filelength) return 0; currentChannel=read_8bit(block_offset-7,streamFile); subAudio=read_8bit(block_offset-6,streamFile); *channel=currentChannel; //if (!((currentChannel==channel) && (subAudio==0x64))) { // block_offset+=2352; // goto begin; //} return block_offset; }
void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i=first_sample; int32_t sample_count; int framesin = first_sample/14; int8_t header = read_8bit(framesin*8+stream->offset,stream->streamfile); int32_t scale = 1 << (header & 0xf); int coef_index = (header >> 4) & 0xf; int32_t hist1 = stream->adpcm_history1_16; int32_t hist2 = stream->adpcm_history2_16; int coef1 = stream->adpcm_coef[coef_index*2]; int coef2 = stream->adpcm_coef[coef_index*2+1]; first_sample = first_sample%14; for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { int sample_byte = read_8bit(framesin*8+stream->offset+1+i/2,stream->streamfile); #ifdef DEBUG if (hist1==stream->loop_history1 && hist2==stream->loop_history2) fprintf(stderr,"yo! %#x (start %#x) %d\n",stream->offset+framesin*8+i/2,stream->channel_start_offset,stream->samples_done); stream->samples_done++; #endif outbuf[sample_count] = clamp16(( (((i&1? get_low_nibble_signed(sample_byte): get_high_nibble_signed(sample_byte) ) * scale)<<11) + 1024 + (coef1 * hist1 + coef2 * hist2))>>11 ); hist2 = hist1; hist1 = outbuf[sample_count]; } stream->adpcm_history1_16 = hist1; stream->adpcm_history2_16 = hist2; }
// OMU is a PS2 .INT file with header ... // found in Alter Echo VGMSTREAM * init_vgmstream_ps2_omu(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[1024]; int i,channel_count; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("omu",filename_extension(filename))) goto fail; /* check header */ if((read_32bitBE(0,streamFile)!=0x4F4D5520) && (read_32bitBE(0x08,streamFile)!=0x46524D54)) goto fail; channel_count = (int)read_8bit(0x14,streamFile); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,1); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->channels=channel_count; vgmstream->sample_rate = read_32bitLE(0x10,streamFile); vgmstream->coding_type = coding_PCM16LE; vgmstream->num_samples = (int32_t)(read_32bitLE(0x3C,streamFile)/(vgmstream->channels*2)); vgmstream->interleave_block_size = 0x200; vgmstream->layout_type = layout_interleave; vgmstream->meta_type = meta_PS2_OMU; vgmstream->loop_start_sample=0; vgmstream->loop_end_sample=vgmstream->num_samples; /* open the file for reading by each channel */ { for (i=0;i<vgmstream->channels;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=0x40+(i*vgmstream->interleave_block_size); } } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
void decode_sdx2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int32_t hist = stream->adpcm_history1_32; int i; int32_t sample_count; for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) { int8_t sample_byte = read_8bit(stream->offset+i*channelspacing,stream->streamfile); int16_t sample; if (!(sample_byte & 1)) hist = 0; sample = hist + squares[sample_byte+128]; hist = outbuf[sample_count] = clamp16(sample); } stream->adpcm_history1_32=hist; }
/* reads a c-string (ANSI only), up to maxsize or NULL, returning size. buf is optional (works as get_string_size). */ size_t read_string(char * buf, size_t maxsize, off_t offset, STREAMFILE *streamFile) { size_t pos; for (pos = 0; pos < maxsize; pos++) { char c = read_8bit(offset + pos, streamFile); if (buf) buf[pos] = c; if (c == '\0') return pos; if (pos+1 == maxsize) { /* null at maxsize and don't validate (expected to be garbage) */ if (buf) buf[pos] = '\0'; return maxsize; } if (c < 0x20 || c > 0xA5) goto fail; } fail: if (buf) buf[0] = '\0'; return 0; }
/* reads a c-string, up to maxsize or NULL, returning size. buf is optional. */ int read_string(char * buf, size_t maxsize, off_t offset, STREAMFILE *streamFile) { int i; for (i=0; i < maxsize; i++) { char c = read_8bit(offset + i, streamFile); if (buf) buf[i] = c; if (c == '\0') return i; if (i+1 == maxsize) { /* null at maxsize and don't validate (expected to be garbage) */ if (buf) buf[i] = '\0'; return maxsize; } if (c < 0x20 || c > 0xA5) goto fail; } fail: if (buf) buf[0] = '\0'; return 0; }
/* ASTL - found in Dead Rising (PC) */ VGMSTREAM * init_vgmstream_pc_ast(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset, data_size; int loop_flag, channel_count; /* check extension, case insensitive */ if ( !check_extensions(streamFile,"ast")) goto fail; if (read_32bitBE(0x00,streamFile) != 0x4153544C) /* "ASTL" */ goto fail; loop_flag = 0; //TODO - Find hidden loop point calc and flag channel_count = read_8bit(0x32, streamFile); data_size = read_32bitLE(0x20,streamFile); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* TODO - Find non-obvious loop points and flag (if any) */ start_offset = read_32bitLE(0x10,streamFile); vgmstream->sample_rate = read_32bitLE(0x34,streamFile); vgmstream->coding_type = coding_PCM16LE; vgmstream->num_samples = data_size/(channel_count*2); vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x2; vgmstream->meta_type = meta_PC_AST; /* open the file for reading */ if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; return vgmstream; fail: close_vgmstream(vgmstream); return NULL; }
/* Xilam DERF DPCM for Stupid Invaders (PC), decompiled from the exe */ void decode_derf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) { int i, sample_pos = 0, index; int32_t hist = stream->adpcm_history1_32; off_t frame_offset = stream->offset; /* frame size is 1 */ for(i = first_sample; i < first_sample + samples_to_do; i++) { uint8_t code = (uint8_t)read_8bit(frame_offset+i,stream->streamfile); /* original exe doesn't clamp the index, so presumably codes can't over it */ index = code & 0x7f; if (index > 95) index = 95; if (code & 0x80) hist -= derf_steps[index]; else hist += derf_steps[index]; outbuf[sample_pos] = clamp16(hist); sample_pos += channelspacing; } stream->adpcm_history1_32 = hist; }
/* VAWX - No More Heroes: Heroes Paradise (PS3) */ VGMSTREAM * init_vgmstream_ps3_vawx(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("vawx",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x56415758) // "VAWX" goto fail; if (read_8bit(0xF,streamFile) == 2) { loop_flag = 1; } channel_count = read_8bit(0x39,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(0x40,streamFile); vgmstream->coding_type = coding_PSX; vgmstream->num_samples = ((get_streamfile_size(streamFile)-start_offset)/16/channel_count*28); if (loop_flag) { vgmstream->loop_start_sample = read_32bitBE(0x44,streamFile); vgmstream->loop_end_sample = read_32bitBE(0x48,streamFile);; } vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 0x10; vgmstream->meta_type = meta_PS3_VAWX; /* 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_gbts(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; int loop_flag=0; int channel_count; off_t start_offset; off_t loopStart = 0; off_t loopEnd = 0; size_t filelength; int i; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("gbts",filename_extension(filename))) goto fail; /* check loop */ start_offset=0x801; filelength = get_streamfile_size(streamFile); do { // Loop Start ... if(read_8bit(start_offset,streamFile)==0x06) { if(loopStart==0) loopStart = start_offset-0x801; } // Loop End ... if(read_8bit(start_offset,streamFile)==0x03) { if(loopEnd==0) loopEnd = start_offset-0x801-0x10; } start_offset+=0x10; } while (start_offset<(int32_t)filelength); loop_flag = (loopEnd!=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 */ vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitLE(0x18,streamFile);; /* Check for Compression Scheme */ vgmstream->coding_type = coding_PSX; vgmstream->num_samples = read_32bitLE(0x0C,streamFile)/16*28/vgmstream->channels; vgmstream->interleave_block_size = 0x10; /* Get loop point values */ if(vgmstream->loop_flag) { vgmstream->loop_start_sample = (loopStart/(vgmstream->interleave_block_size)*vgmstream->interleave_block_size)/16*28; vgmstream->loop_start_sample += (loopStart%vgmstream->interleave_block_size)/16*28; vgmstream->loop_start_sample /=vgmstream->channels; 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; } vgmstream->layout_type = layout_interleave; vgmstream->meta_type = meta_PS2_GBTS; 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; }
VGMSTREAM * init_vgmstream_g1l(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; coding_t coding_type; off_t head_offset; int channel_count; int loop_flag; off_t start_offset; /* check extension, case insensitive */ streamFile->get_name(streamFile, filename, sizeof(filename)); if (strcasecmp("g1l", filename_extension(filename))) goto fail; /* check header */ if ((uint32_t)read_32bitBE(0, streamFile) != 0x47314C5F) /* "G1L_" */ goto fail; if ((uint32_t)read_32bitBE(0x1c, streamFile) != 0x57696942) /* "WiiB" */ goto fail; /* check type details */ // loop_flag = read_8bit(head_offset + 0x21, streamFile); if (read_32bitBE(0x30, streamFile) > 0) loop_flag = 1; else loop_flag = 0; channel_count = read_8bit(0x3f, streamFile); coding_type = coding_NGC_DSP; 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(0x2c, streamFile); vgmstream->sample_rate = (uint16_t)read_16bitBE(0x42, streamFile); /* channels and loop flag are set by allocate_vgmstream */ vgmstream->loop_start_sample = read_32bitBE(0x30, streamFile); vgmstream->loop_end_sample = vgmstream->num_samples; vgmstream->coding_type = coding_type; if (channel_count == 1) vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_interleave_byte; vgmstream->meta_type = meta_G1L; vgmstream->interleave_block_size = 0x1; if (vgmstream->coding_type == coding_NGC_DSP) { off_t coef_offset = 0x78; int i, j; int coef_spacing = 0x60; for (j = 0; j<vgmstream->channels; j++) { for (i = 0; i<16; i++) { vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(coef_offset + j*coef_spacing + i * 2, streamFile); } } } if (vgmstream->coding_type == coding_NGC_DSP) start_offset = 0x81c; else // Will add AT3 G1L support later goto fail; /* 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_ws_aud(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; coding_t coding_type = -1; off_t format_offset; int channel_count; int new_type = 0; /* if 0 is old type */ int bytes_per_sample = 0; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("aud",filename_extension(filename))) goto fail; /* check for 0x0000DEAF chunk marker for first chunk */ if (read_32bitLE(0x10,streamFile)==0x0000DEAF) { /* new */ new_type = 1; } else if (read_32bitLE(0x0C,streamFile)==0x0000DEAF) { /* old */ new_type = 0; } else goto fail; if (new_type) format_offset = 0xa; else format_offset = 0x6; /* get channel count */ if (read_8bit(format_offset,streamFile) & 1) channel_count = 2; else channel_count = 1; if (channel_count == 2) goto fail; /* TODO: not yet supported (largely because not yet seen) */ /* get output format */ if (read_8bit(format_offset+1,streamFile) & 2) bytes_per_sample = 2; else bytes_per_sample = 1; /* check codec type */ switch (read_8bit(format_offset+1,streamFile)) { case 1: /* Westwood custom */ coding_type = coding_WS; /* shouldn't happen? */ if (bytes_per_sample != 1) goto fail; break; case 99: /* IMA ADPCM */ coding_type = coding_IMA; break; default: goto fail; break; } /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,0); if (!vgmstream) goto fail; /* fill in the vital statistics */ if (new_type) { vgmstream->num_samples = read_32bitLE(0x06,streamFile)/bytes_per_sample/channel_count; } else { /* Doh, no output size in old type files. We have to read through the * file looking at chunk headers! Crap! */ int32_t out_size = 0; off_t current_offset = 0x8; off_t file_size = get_streamfile_size(streamFile); while (current_offset < file_size) { int16_t chunk_size; chunk_size = read_16bitLE(current_offset,streamFile); out_size += read_16bitLE(current_offset+2,streamFile); /* while we're here might as well check for valid chunks */ if (read_32bitLE(current_offset+4,streamFile) != 0x0000DEAF) goto fail; current_offset+=8+chunk_size; } vgmstream->num_samples = out_size/bytes_per_sample/channel_count; } /* they tend to not actually have data for the last odd sample */ if (vgmstream->num_samples & 1) vgmstream->num_samples--; vgmstream->sample_rate = (uint16_t)read_16bitLE(0x00,streamFile); vgmstream->coding_type = coding_type; if (new_type) { vgmstream->meta_type = meta_WS_AUD; } else { vgmstream->meta_type = meta_WS_AUD_old; } vgmstream->layout_type = layout_ws_aud_blocked; /* open the file for reading by each channel */ { 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; } } /* start me up */ if (new_type) { ws_aud_block_update(0xc,vgmstream); } else { ws_aud_block_update(0x8,vgmstream); } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* @UTF table reading, abridged */ static struct utf_query_result analyze_utf(STREAMFILE *infile, const long offset, const struct utf_query *query) { unsigned char buf[4]; struct utf_table_info table_info; char *string_table = NULL; struct utf_column_info * schema = NULL; struct utf_query_result result; uint32_t table_name_string; int string_table_size; result.valid = 0; table_info.table_offset = offset; /* check header */ { static const char UTF_signature[4] = "@UTF"; /* intentionally unterminated */ if (4 != read_streamfile(buf, offset, 4, infile)) goto cleanup_error; if (memcmp(buf, UTF_signature, sizeof(UTF_signature))) { goto cleanup_error; } } /* get table size */ table_info.table_size = read_32bitBE(offset+4, infile); table_info.schema_offset = 0x20; table_info.rows_offset = read_32bitBE(offset+8, infile); table_info.string_table_offset = read_32bitBE(offset+0xc,infile); table_info.data_offset = read_32bitBE(offset+0x10,infile); table_name_string = read_32bitBE(offset+0x14,infile); table_info.columns = read_16bitBE(offset+0x18,infile); table_info.row_width = read_16bitBE(offset+0x1a,infile); table_info.rows = read_32bitBE(offset+0x1c,infile); /* allocate for string table */ string_table_size = table_info.data_offset-table_info.string_table_offset; string_table = malloc(string_table_size+1); if (!string_table) goto cleanup_error; table_info.string_table = string_table; memset(string_table, 0, string_table_size+1); /* load schema */ schema = malloc(sizeof(struct utf_column_info) * table_info.columns); if (!schema) goto cleanup_error; { int i; long schema_current_offset = table_info.schema_offset; for (i = 0; i < table_info.columns; i++) { schema[i].type = read_8bit(schema_current_offset,infile); schema_current_offset ++; schema[i].column_name = string_table + read_32bitBE(schema_current_offset,infile); schema_current_offset += 4; if ((schema[i].type & COLUMN_STORAGE_MASK) == COLUMN_STORAGE_CONSTANT) { schema[i].constant_offset = schema_current_offset; switch (schema[i].type & COLUMN_TYPE_MASK) { case COLUMN_TYPE_8BYTE: case COLUMN_TYPE_DATA: schema_current_offset+=8; break; case COLUMN_TYPE_STRING: case COLUMN_TYPE_FLOAT: case COLUMN_TYPE_4BYTE: schema_current_offset+=4; break; case COLUMN_TYPE_2BYTE2: case COLUMN_TYPE_2BYTE: schema_current_offset+=2; break; case COLUMN_TYPE_1BYTE2: case COLUMN_TYPE_1BYTE: schema_current_offset++; break; default: goto cleanup_error; } } } } table_info.schema = schema; /* read string table */ read_streamfile((unsigned char *)string_table, table_info.string_table_offset+8+offset, string_table_size, infile); table_info.table_name = table_info.string_table+table_name_string; /* fill in the default stuff */ result.found = 0; result.rows = table_info.rows; result.name_offset = table_name_string; result.string_table_offset = table_info.string_table_offset; result.data_offset = table_info.data_offset; /* explore the values */ if (query) { int i, j; for (i = 0; i < table_info.rows; i++) { uint32_t row_offset = table_info.table_offset + 8 + table_info.rows_offset + i * table_info.row_width; const uint32_t row_start_offset = row_offset; if (query && i != query->index) continue; for (j = 0; j < table_info.columns; j++) { uint8_t type = table_info.schema[j].type; long constant_offset = table_info.schema[j].constant_offset; int constant = 0; int qthis = (query && i == query->index && !strcmp(table_info.schema[j].column_name, query->name)); if (qthis) { result.found = 1; result.type = schema[j].type & COLUMN_TYPE_MASK; } switch (schema[j].type & COLUMN_STORAGE_MASK) { case COLUMN_STORAGE_PERROW: break; case COLUMN_STORAGE_CONSTANT: constant = 1; break; case COLUMN_STORAGE_ZERO: if (qthis) { memset(&result.value, 0, sizeof(result.value)); } continue; default: goto cleanup_error; } if (1) { long data_offset; int bytes_read; if (constant) { data_offset = constant_offset; } else { data_offset = row_offset; } switch (type & COLUMN_TYPE_MASK) { case COLUMN_TYPE_STRING: { uint32_t string_offset; string_offset = read_32bitBE(data_offset, infile); bytes_read = 4; if (qthis) { result.value.value_string = string_offset; } } break; case COLUMN_TYPE_DATA: { uint32_t vardata_offset, vardata_size; vardata_offset = read_32bitBE(data_offset, infile); vardata_size = read_32bitBE(data_offset+4, infile); bytes_read = 8; if (qthis) { result.value.value_data.offset = vardata_offset; result.value.value_data.size = vardata_size; } } break; case COLUMN_TYPE_8BYTE: { uint64_t value = read_32bitBE(data_offset, infile); value <<= 32; value |= read_32bitBE(data_offset+4, infile); if (qthis) { result.value.value_u64 = value; } bytes_read = 8; break; } case COLUMN_TYPE_4BYTE: { uint32_t value = read_32bitBE(data_offset, infile); if (qthis) { result.value.value_u32 = value; } bytes_read = 4; } break; case COLUMN_TYPE_2BYTE2: case COLUMN_TYPE_2BYTE: { uint16_t value = read_16bitBE(data_offset, infile); if (qthis) { result.value.value_u16 = value; } bytes_read = 2; } break; case COLUMN_TYPE_FLOAT: if (sizeof(float) == 4) { union { float float_value; uint32_t int_value; } int_float; int_float.int_value = read_32bitBE(data_offset, infile); if (qthis) { result.value.value_float = int_float.float_value; } } else { read_32bitBE(data_offset, infile); if (qthis) { goto cleanup_error; } } bytes_read = 4; break; case COLUMN_TYPE_1BYTE2: case COLUMN_TYPE_1BYTE: { uint8_t value = read_8bit(data_offset, infile); if (qthis) { result.value.value_u8 = value; } bytes_read = 1; } break; default: goto cleanup_error; } if (!constant) { row_offset += bytes_read; } } /* useless if end */ } /* column for loop end */ if (row_offset - row_start_offset != table_info.row_width) goto cleanup_error; if (query && i >= query->index) break; } /* row for loop end */ } /* explore values block end */ //cleanup: result.valid = 1; cleanup_error: if (string_table) { free(string_table); string_table = NULL; } if (schema) { free(schema); schema = NULL; } return result; }
VGMSTREAM * init_vgmstream_cdxa(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[1024]; int channel_count; int headerless=0; int xa_channel=0; uint8_t bCoding; off_t start_offset; int i; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("xa",filename_extension(filename))) goto fail; /* check RIFF Header */ if (!((read_32bitBE(0x00,streamFile) == 0x52494646) && (read_32bitBE(0x08,streamFile) == 0x43445841) && (read_32bitBE(0x0C,streamFile) == 0x666D7420))) headerless=1; /* First init to have the correct info of the channel */ if (!headerless) { start_offset=init_xa_channel(&xa_channel,streamFile); /* No sound ? */ if(start_offset==0) goto fail; bCoding = read_8bit(start_offset-5,streamFile); switch (AUDIO_CODING_GET_STEREO(bCoding)) { case 0: channel_count = 1; break; case 1: channel_count = 2; break; default: channel_count = 0; break; } /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,0); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->channels = channel_count; vgmstream->xa_channel = xa_channel; switch (AUDIO_CODING_GET_FREQ(bCoding)) { case 0: vgmstream->sample_rate = 37800; break; case 1: vgmstream->sample_rate = 18900; break; default: vgmstream->sample_rate = 0; break; } /* Check for Compression Scheme */ vgmstream->num_samples = (int32_t)((((get_streamfile_size(streamFile) - 0x3C)/2352)*0x1F80)/(2*channel_count)); } else { channel_count=2; vgmstream = allocate_vgmstream(2,0); if (!vgmstream) goto fail; vgmstream->xa_headerless=1; vgmstream->sample_rate=44100; vgmstream->channels=2; vgmstream->num_samples = (int32_t)(((get_streamfile_size(streamFile)/ 0x80)*0xE0)/2); start_offset=0; } vgmstream->coding_type = coding_XA; vgmstream->layout_type = layout_xa_blocked; vgmstream->meta_type = meta_PSX_XA; /* open the file for reading by each channel */ { STREAMFILE *chstreamfile; chstreamfile = streamFile->open(streamFile,filename,2352); if (!chstreamfile) goto fail; for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = chstreamfile; } } xa_block_update(start_offset,vgmstream); return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* .OPUS - from Switch games (Lego City Undercover, Ultra SF II, Disgaea 5) */ VGMSTREAM * init_vgmstream_nsw_opus(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset; int loop_flag = 0, channel_count; int num_samples = 0, loop_start = 0, loop_end = 0; off_t offset = 0; /* check extension, case insensitive */ if ( !check_extensions(streamFile,"opus,lopus")) /* no relation to Ogg Opus */ goto fail; /* variations, maybe custom */ if (read_32bitBE(0x00,streamFile) == 0x01000080) { /* Lego City Undercover */ offset = 0x00; } else if ((read_32bitBE(0x04,streamFile) == 0x00000000 && read_32bitBE(0x0c,streamFile) == 0x00000000) || (read_32bitBE(0x04,streamFile) == 0xFFFFFFFF && read_32bitBE(0x0c,streamFile) == 0xFFFFFFFF)) { /* Disgaea 5 */ offset = 0x10; loop_start = read_32bitLE(0x00,streamFile); loop_end = read_32bitLE(0x08,streamFile); } else if (read_32bitLE(0x04,streamFile) == 0x02) { /* Ultra Street Fighter II */ offset = read_32bitLE(0x1c,streamFile); num_samples = read_32bitLE(0x00,streamFile); loop_start = read_32bitLE(0x08,streamFile); loop_end = read_32bitLE(0x0c,streamFile); } else { offset = 0x00; } if (read_32bitBE(offset + 0x00,streamFile) != 0x01000080) goto fail; start_offset = offset + 0x28; channel_count = read_8bit(offset + 0x09,streamFile); /* assumed */ /* 0x0a: packet size if CBR?, other values: no idea */ loop_flag = (loop_end > 0); /* -1 when not set */ /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; vgmstream->sample_rate = read_32bitLE(offset + 0x0c,streamFile); vgmstream->meta_type = meta_NSW_OPUS; vgmstream->num_samples = num_samples; vgmstream->loop_start_sample = loop_start; vgmstream->loop_end_sample = loop_end; #ifdef VGM_USE_FFMPEG { uint8_t buf[0x100]; size_t bytes, skip, data_size; ffmpeg_custom_config cfg; data_size = get_streamfile_size(streamFile) - start_offset; skip = 0; //todo bytes = ffmpeg_make_opus_header(buf,0x100, vgmstream->channels, skip, vgmstream->sample_rate); if (bytes <= 0) goto fail; memset(&cfg, 0, sizeof(ffmpeg_custom_config)); cfg.type = FFMPEG_SWITCH_OPUS; vgmstream->codec_data = init_ffmpeg_config(streamFile, buf,bytes, start_offset,data_size, &cfg); if (!vgmstream->codec_data) goto fail; vgmstream->coding_type = coding_FFmpeg; vgmstream->layout_type = layout_none; if (vgmstream->num_samples == 0) vgmstream->num_samples = switch_opus_get_samples(start_offset, data_size, vgmstream->sample_rate, streamFile); } #else goto fail; #endif /* open the file for reading */ if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) ) goto fail; return vgmstream; fail: close_vgmstream(vgmstream); return NULL; }
/* PSND (from Crash Bandicoot Nitro Kart 2 (iOS) */ VGMSTREAM * init_vgmstream_ios_psnd(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("psnd",filename_extension(filename))) goto fail; /* check header */ if (read_32bitBE(0x00,streamFile) != 0x50534E44) /* "PSND" */ goto fail; if (read_16bitBE(0xC,streamFile)==0x2256){ loop_flag = 1; } else { loop_flag = 0; } channel_count = read_8bit(0xE,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; if (read_16bitBE(0xC,streamFile)==0x44AC){ vgmstream->sample_rate = 44100; } else { vgmstream->sample_rate = read_16bitLE(0xC,streamFile); } vgmstream->coding_type = coding_PCM16LE; vgmstream->num_samples = (read_32bitLE(0x4,streamFile)-8)/4; if (loop_flag) { vgmstream->loop_start_sample = 0; vgmstream->loop_end_sample = vgmstream->num_samples; } vgmstream->layout_type = layout_interleave; vgmstream->interleave_block_size = 2; vgmstream->meta_type = meta_IOS_PSND; /* 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; }