void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream) { int i; off_t block_size=vgmstream->current_block_size; if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E6C) { block_offset+=0x0C; } vgmstream->current_block_offset = block_offset; if(read_32bitBE(block_offset,vgmstream->ch[0].streamfile)==0x31534E64) { /* 1Snd */ block_offset+=4; if(vgmstream->ea_platform==0) block_size=read_32bitLE(vgmstream->current_block_offset+0x04, vgmstream->ch[0].streamfile); else block_size=read_32bitBE(vgmstream->current_block_offset+0x04, vgmstream->ch[0].streamfile); block_offset+=4; } vgmstream->current_block_size=block_size-8; if(vgmstream->coding_type==coding_EACS_IMA) { init_get_high_nibble(vgmstream); vgmstream->current_block_size=read_32bitLE(block_offset,vgmstream->ch[0].streamfile); for(i=0;i<vgmstream->channels;i++) { vgmstream->ch[i].adpcm_step_index = read_32bitLE(block_offset+0x04+i*4,vgmstream->ch[0].streamfile); vgmstream->ch[i].adpcm_history1_32 = read_32bitLE(block_offset+0x04+i*4+(4*vgmstream->channels),vgmstream->ch[0].streamfile); vgmstream->ch[i].offset = block_offset+0x14; } } else { if(vgmstream->coding_type==coding_PSX) { for (i=0;i<vgmstream->channels;i++) vgmstream->ch[i].offset = vgmstream->current_block_offset+8+(i*(vgmstream->current_block_size/2)); } else { for (i=0;i<vgmstream->channels;i++) { if(vgmstream->coding_type==coding_PCM16LE_int) vgmstream->ch[i].offset = block_offset+(i*2); else vgmstream->ch[i].offset = block_offset+i; } } vgmstream->current_block_size/=vgmstream->channels; } vgmstream->next_block_offset = vgmstream->current_block_offset + (off_t)block_size; }
/* 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_ea(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; EA_STRUCT ea; char filename[260]; int loop_flag=0; int channel_count; int header_length; off_t start_offset; int i; memset(&ea,0,sizeof(EA_STRUCT)); /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("sng",filename_extension(filename)) && strcasecmp("asf",filename_extension(filename)) && strcasecmp("str",filename_extension(filename)) && strcasecmp("xsf",filename_extension(filename)) && strcasecmp("eam",filename_extension(filename))) goto fail; /* check Header */ if (read_32bitBE(0x00,streamFile) != 0x5343486C) // SCHl goto fail; header_length = read_32bitLE(0x04,streamFile); start_offset=8; if(header_length>0x100) goto fail; Parse_Header(streamFile,&ea,start_offset,header_length-8); /* unknown loop value for the moment */ loop_flag = 0; channel_count=ea.channels; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->channels = channel_count; vgmstream->ea_platform=ea.platform; vgmstream->ea_compression_type=ea.compression_type; vgmstream->ea_compression_version=ea.compression_version; // Set defaut sample rate if not define in the header if(ea.sample_rate!=0) { vgmstream->sample_rate = ea.sample_rate; } else { if(read_32bitBE(0x08,streamFile)==0x47535452) { // GSTR vgmstream->sample_rate=44100; } else { switch(vgmstream->ea_platform) { case EA_XBOX: vgmstream->sample_rate=24000; break; case EA_X360: vgmstream->sample_rate=44100; break; default: vgmstream->sample_rate=22050; } } } // Set default compression scheme if not define in the header switch(vgmstream->ea_platform) { case EA_X360: vgmstream->ea_compression_version=0x03; break; } vgmstream->num_samples=ea.num_samples; switch(vgmstream->ea_compression_type) { case EA_EAXA: if(vgmstream->ea_compression_version==0x03) vgmstream->meta_type=meta_EAXA_R3; else { // seems there's no EAXA R2 on PC if(ea.platform==EA_PC) { vgmstream->ea_compression_version=0x03; vgmstream->meta_type=meta_EAXA_R3; } else vgmstream->meta_type=meta_EAXA_R2; } vgmstream->coding_type=coding_EAXA; vgmstream->layout_type=layout_ea_blocked; if((vgmstream->ea_platform==EA_GC) || (vgmstream->ea_platform==EA_X360)) vgmstream->ea_big_endian=1; break; case EA_VAG: vgmstream->meta_type=meta_EAXA_PSX; vgmstream->coding_type=coding_PSX; vgmstream->layout_type=layout_ea_blocked; break; case EA_PCM_LE: vgmstream->meta_type=meta_EA_PCM; vgmstream->coding_type=coding_PCM16LE_int; vgmstream->layout_type=layout_ea_blocked; break; case EA_ADPCM: vgmstream->meta_type=meta_EA_ADPCM; vgmstream->coding_type=coding_EA_ADPCM; vgmstream->layout_type=layout_ea_blocked; break; case EA_IMA: vgmstream->meta_type=meta_EA_IMA; vgmstream->coding_type=coding_XBOX; vgmstream->layout_type=layout_ea_blocked; break; } /* open the file for reading by each channel */ { for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000); if (!vgmstream->ch[i].streamfile) goto fail; } } // Special function for .EAM files ... if(!strcasecmp("eam",filename_extension(filename))) { size_t file_length=get_streamfile_size(streamFile); size_t block_length; vgmstream->next_block_offset=start_offset+header_length; vgmstream->num_samples=0; // to initialize the block length ea_block_update(start_offset+header_length,vgmstream); block_length=vgmstream->next_block_offset-start_offset+header_length; do { ea_block_update(vgmstream->next_block_offset,vgmstream); if(vgmstream->coding_type==coding_PSX) vgmstream->num_samples+=(int32_t)vgmstream->current_block_size/16*28; else if (vgmstream->coding_type==coding_EA_ADPCM) vgmstream->num_samples+=(int32_t)vgmstream->current_block_size; else if (vgmstream->coding_type==coding_PCM16LE_int) vgmstream->num_samples+=(int32_t)vgmstream->current_block_size/vgmstream->channels; else vgmstream->num_samples+=(int32_t)vgmstream->current_block_size*28; } while(vgmstream->next_block_offset<(off_t)(file_length-block_length)); } ea_block_update(start_offset+header_length,vgmstream); init_get_high_nibble(vgmstream); return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); return NULL; }
VGMSTREAM * init_vgmstream_eacs(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[260]; int channel_count; int loop_flag=0; char little_endian=0; off_t start_offset; EACSHeader *ea_header = NULL; int32_t samples_count=0; int i; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("cnk",filename_extension(filename)) && strcasecmp("as4",filename_extension(filename)) && strcasecmp("asf",filename_extension(filename))) goto fail; ea_header=(EACSHeader *)malloc(sizeof(EACSHeader)); /* check header */ if ((uint32_t)read_32bitBE(0,streamFile)!=0x31534E68) /* "1SNh" */ goto fail; /* check if we are little or big endian */ if ((uint32_t)read_32bitBE(4,streamFile)<0x40) little_endian=1; /* check type details */ start_offset = read_32bitLE(0x04,streamFile); if((uint32_t)read_32bitBE(0x08,streamFile)==0x45414353) { /* EACS */ read_streamfile((uint8_t*)ea_header,0x08,sizeof(EACSHeader),streamFile); loop_flag = 0; //(ea_header->dwLoopStart!=0); channel_count = (ea_header->bChannels); /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,0); if (!vgmstream) goto fail; /* fill in the vital statistics */ init_get_high_nibble(vgmstream); vgmstream->sample_rate = ea_header->dwSampleRate; if(ea_header->bCompression==0) { vgmstream->coding_type = coding_PCM16LE_int; if(ea_header->bBits==1) vgmstream->coding_type = coding_PCM8_int; } else vgmstream->coding_type = coding_EACS_IMA; vgmstream->layout_type = layout_eacs_blocked; vgmstream->meta_type = meta_EACS_PC; if(little_endian) vgmstream->meta_type = meta_EACS_SAT; } else { channel_count=read_32bitLE(0x20,streamFile); vgmstream = allocate_vgmstream(channel_count,0); if (!vgmstream) goto fail; vgmstream->sample_rate = read_32bitLE(0x08,streamFile); vgmstream->coding_type = coding_PSX; vgmstream->layout_type=layout_eacs_blocked; vgmstream->meta_type=meta_EACS_PSX; } vgmstream->ea_platform=little_endian; /* open the file for reading by each channel */ { for (i=0;i<channel_count;i++) { vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000); if (!vgmstream->ch[i].streamfile) goto fail; } } // calc the samples length ... if(little_endian) vgmstream->next_block_offset=read_32bitBE(0x04,streamFile); else vgmstream->next_block_offset=read_32bitLE(0x04,streamFile); if(vgmstream->next_block_offset>0x30) { vgmstream->current_block_size=vgmstream->next_block_offset-sizeof(EACSHeader); samples_count=(int32_t)vgmstream->current_block_size/get_vgmstream_frame_size(vgmstream)*get_vgmstream_samples_per_frame(vgmstream); samples_count/=vgmstream->channels; } do { if(read_32bitBE(vgmstream->next_block_offset,vgmstream->ch[0].streamfile)==0x31534E6C) { ea_header->dwLoopStart=read_32bitLE(vgmstream->next_block_offset+0x08,vgmstream->ch[0].streamfile); vgmstream->next_block_offset+=0x0C; } if(read_32bitBE(vgmstream->next_block_offset,vgmstream->ch[0].streamfile)==0x31534E65) break; eacs_block_update(vgmstream->next_block_offset,vgmstream); samples_count+=vgmstream->current_block_size/get_vgmstream_frame_size(vgmstream)*get_vgmstream_samples_per_frame(vgmstream); } while(vgmstream->next_block_offset<get_streamfile_size(streamFile)-8); // Reset values ... // setting up the first header by calling the eacs_block_update sub if(little_endian) vgmstream->next_block_offset=read_32bitBE(0x04,streamFile); else vgmstream->next_block_offset=read_32bitLE(0x04,streamFile); vgmstream->current_block_size=vgmstream->next_block_offset-sizeof(EACSHeader); if(vgmstream->coding_type!=coding_PSX) vgmstream->current_block_size-=8; if(vgmstream->coding_type==coding_PSX) eacs_block_update(0x2C,vgmstream); else eacs_block_update(0x28,vgmstream); // re-allocate the sample count vgmstream->num_samples=samples_count; if(loop_flag) { vgmstream->loop_start_sample = ea_header->dwLoopStart; vgmstream->loop_end_sample = vgmstream->num_samples; } if(ea_header) free(ea_header); return vgmstream; /* clean up anything we may have opened */ fail: if(ea_header) free(ea_header); if (vgmstream) close_vgmstream(vgmstream); return NULL; }
/* set up for the block at the given offset */ void ea_block_update(off_t block_offset, VGMSTREAM * vgmstream) { int i; init_get_high_nibble(vgmstream); // Search for next SCDL or SCEl block ... do { block_offset+=4; if(block_offset>=(off_t)get_streamfile_size(vgmstream->ch[0].streamfile)) { vgmstream->next_block_offset=block_offset; return; } } while (read_32bitBE(block_offset,vgmstream->ch[0].streamfile)!=0x5343446C); // reset channel offset for(i=0;i<vgmstream->channels;i++) { vgmstream->ch[i].channel_start_offset=0; } vgmstream->current_block_offset = block_offset; vgmstream->next_block_offset = block_offset+read_32bitLE(block_offset+4,vgmstream->ch[0].streamfile)-4; if(vgmstream->ea_big_endian) { vgmstream->current_block_size = read_32bitBE(block_offset+8,vgmstream->ch[0].streamfile); for(i=0;i<vgmstream->channels;i++) { vgmstream->ch[i].offset=read_32bitBE(block_offset+0x0C+(i*4),vgmstream->ch[0].streamfile)+(4*vgmstream->channels); vgmstream->ch[i].offset+=vgmstream->current_block_offset+0x0C; } vgmstream->current_block_size /= 28; } else { switch(vgmstream->coding_type) { case coding_PSX: vgmstream->ch[0].offset=vgmstream->current_block_offset+0x10; vgmstream->ch[1].offset=(read_32bitLE(block_offset+0x04,vgmstream->ch[0].streamfile)-0x10)/vgmstream->channels; vgmstream->ch[1].offset+=vgmstream->ch[0].offset; vgmstream->current_block_size=read_32bitLE(block_offset+0x04,vgmstream->ch[0].streamfile)-0x10; vgmstream->current_block_size/=vgmstream->channels; break; case coding_EA_ADPCM: vgmstream->current_block_size = read_32bitLE(block_offset+4,vgmstream->ch[0].streamfile); for(i=0;i<vgmstream->channels;i++) { vgmstream->ch[i].offset=vgmstream->current_block_offset+0x0C+(4*vgmstream->channels); vgmstream->ch[i].adpcm_history1_32=(uint32_t)read_16bitLE(vgmstream->current_block_offset+0x0c+(i*4),vgmstream->ch[0].streamfile); vgmstream->ch[i].adpcm_history2_32=(uint32_t)read_16bitLE(vgmstream->current_block_offset+0x0e +(i*4),vgmstream->ch[0].streamfile); } break; case coding_PCM16LE_int: vgmstream->current_block_size = read_32bitLE(block_offset+4,vgmstream->ch[0].streamfile)-0x0C; for(i=0;i<vgmstream->channels;i++) { vgmstream->ch[i].offset=block_offset+0x0C+(i*2); } vgmstream->current_block_size/=2; vgmstream->current_block_size-=2; break; case coding_XBOX: vgmstream->current_block_size = read_32bitLE(block_offset+0x10,vgmstream->ch[0].streamfile); for(i=0;i<vgmstream->channels;i++) { vgmstream->ch[i].offset=read_32bitLE(block_offset+0x0C+(i*4),vgmstream->ch[0].streamfile)+(4*vgmstream->channels); vgmstream->ch[i].offset+=vgmstream->current_block_offset+0x0C; } break; default: vgmstream->current_block_size = read_32bitLE(block_offset+8,vgmstream->ch[0].streamfile); for(i=0;i<vgmstream->channels;i++) { vgmstream->ch[i].offset=read_32bitLE(block_offset+0x0C+(i*4),vgmstream->ch[0].streamfile)+(4*vgmstream->channels); vgmstream->ch[i].offset+=vgmstream->current_block_offset+0x0C; } vgmstream->current_block_size /= 28; } } if((vgmstream->ea_compression_version<3) && (vgmstream->coding_type!=coding_PSX) && (vgmstream->coding_type!=coding_EA_ADPCM) && (vgmstream->coding_type!=coding_XBOX)) { for(i=0;i<vgmstream->channels;i++) { if(vgmstream->ea_big_endian) { vgmstream->ch[i].adpcm_history1_32=read_16bitBE(vgmstream->ch[i].offset,vgmstream->ch[0].streamfile); vgmstream->ch[i].adpcm_history2_32=read_16bitBE(vgmstream->ch[i].offset+2,vgmstream->ch[0].streamfile); } else { vgmstream->ch[i].adpcm_history1_32=read_16bitLE(vgmstream->ch[i].offset,vgmstream->ch[0].streamfile); vgmstream->ch[i].adpcm_history2_32=read_16bitLE(vgmstream->ch[i].offset+2,vgmstream->ch[0].streamfile); } vgmstream->ch[i].offset+=4; } } }