예제 #1
0
/* STRM (from Final Fantasy Tactics A2 - Fuuketsu no Grimoire) */
VGMSTREAM * init_vgmstream_nds_strm_ffta2(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
    char filename[1024];
    off_t start_offset;

    int loop_flag;
	int channel_count;

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("strm",filename_extension(filename))) goto fail;

    /* check header */
    if (read_32bitBE(0x00,streamFile) != 0x52494646 ||	/* RIFF */
		read_32bitBE(0x08,streamFile) != 0x494D4120)	/* "IMA " */
        goto fail;

	loop_flag = (read_32bitLE(0x20,streamFile) !=0);
	channel_count = read_32bitLE(0x24,streamFile);
    
	/* build the VGMSTREAM */
    vgmstream = allocate_vgmstream(channel_count,loop_flag);
    if (!vgmstream) goto fail;

	/* fill in the vital statistics */
    start_offset = 0x2C;
	vgmstream->channels = channel_count;
    vgmstream->sample_rate = read_32bitLE(0x0C,streamFile);
    vgmstream->coding_type = coding_INT_IMA;
    vgmstream->num_samples = (read_32bitLE(0x04,streamFile)-start_offset);
    if (loop_flag) {
        vgmstream->loop_start_sample = read_32bitLE(0x20,streamFile);
        vgmstream->loop_end_sample = read_32bitLE(0x28,streamFile);
    }

    vgmstream->interleave_block_size = 0x80;
    vgmstream->interleave_smallblock_size = (vgmstream->loop_end_sample)%((vgmstream->loop_end_sample)/vgmstream->interleave_block_size);
    vgmstream->layout_type = layout_interleave_shortblock;
	vgmstream->meta_type = meta_NDS_STRM_FFTA2;

    /* 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;
}
예제 #2
0
/* F*G (Jackie Chan - Stuntmaster) */
VGMSTREAM * init_vgmstream_psx_fag(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
    char filename[PATH_LIMIT];
    off_t start_offset;
    int loop_flag = 0;
	int channel_count;

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("f*g",filename_extension(filename))) goto fail;

    /* check header */

	/* Look if there's more than 1 one file... */
    if (read_32bitBE(0x00,streamFile) != 0x01000000)
        goto fail;

	loop_flag = 0;
    channel_count = 2;
    
	/* build the VGMSTREAM */
    vgmstream = allocate_vgmstream(channel_count,loop_flag);
    if (!vgmstream) goto fail;

	/* fill in the vital statistics */
	start_offset = read_32bitLE(0x04,streamFile);
	vgmstream->channels = channel_count;
    vgmstream->sample_rate = 24000;
    vgmstream->coding_type = coding_PSX;
	vgmstream->num_samples = (read_32bitLE(0x08,streamFile))/channel_count/32*28;
    if (loop_flag) {
        vgmstream->loop_start_sample = 0;
        vgmstream->loop_end_sample = (read_32bitLE(0x08,streamFile))/channel_count/32*28;
	}

    vgmstream->layout_type = layout_interleave;
    vgmstream->interleave_block_size = 0x8000;
    vgmstream->meta_type = meta_PSX_FAG;

    /* 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;
}
예제 #3
0
파일: dc_str.c 프로젝트: flyingtime/boxee
VGMSTREAM * init_vgmstream_dc_str_v2(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("str",filename_extension(filename))) goto fail;
#if 0
    /* check header */
    if ((read_32bitBE(0x00,streamFile) != 0x00000002) &&
        (read_32bitBE(0x10,streamFile) != 0x00000100) &&
        (read_32bitBE(0x1C,streamFile) != 0x1F000000))
    goto fail;
#endif

    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(0x4,streamFile);
    vgmstream->coding_type = coding_PCM16LE;
    vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)/2/channel_count;
	if (loop_flag) {
        vgmstream->loop_start_sample = 0;
        vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset)/2/channel_count;
    }

    vgmstream->layout_type = layout_interleave;
    vgmstream->interleave_block_size = read_32bitLE(0xC,streamFile);
    vgmstream->meta_type = meta_DC_STR_V2;
    
    /* 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;
}
예제 #4
0
/* GUN (Gunvari Streams) */
VGMSTREAM * init_vgmstream_ps2_mcg(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("mcg",filename_extension(filename))) goto fail;

    /* check header */
    if (!((read_32bitBE(0x00,streamFile) == 0x4D434700) && 
         (read_32bitBE(0x20,streamFile) == 0x56414770) && 
	     (read_32bitBE(0x50,streamFile) == 0x56414770)))
        goto fail;

	loop_flag = (read_32bitLE(0x34,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 = 0x80;
	vgmstream->channels = channel_count;
    vgmstream->sample_rate = read_32bitBE(0x30,streamFile);
    vgmstream->coding_type = coding_PSX;
	vgmstream->num_samples = read_32bitBE(0x2C,streamFile)/16*14*channel_count;
    vgmstream->layout_type = layout_interleave;
    vgmstream->interleave_block_size = read_32bitLE(0x14,streamFile);
    vgmstream->meta_type = meta_PS2_MCG;

	if (vgmstream->loop_flag) 
	{
		vgmstream->loop_start_sample = read_32bitLE(0x34,streamFile);
		vgmstream->loop_end_sample = vgmstream->num_samples;
	}

    /* 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;
}
예제 #5
0
VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
    char filename[PATH_LIMIT];
    off_t start_offset, meta_offset_offset, meta_offset, post_meta_offset;
    int32_t loop_start, loop_end;

    int loop_flag = 0;
	int channel_count;
    int codec_id;
    int aux_chunk_count;

    int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
    int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("scd",filename_extension(filename))) goto fail;

    /* SEDB */
    if (read_32bitBE(0,streamFile) != 0x53454442) goto fail;
    /* SSCF */
    if (read_32bitBE(4,streamFile) != 0x53534346) goto fail;
    if (read_32bitBE(8,streamFile) == 2 ||
        read_32bitBE(8,streamFile) == 3) {
        /* version 2 BE, as seen in FFXIII demo for PS3 */
        /* version 3 BE, as seen in FFXIII for PS3 */
        read_32bit = read_32bitBE;
        read_16bit = read_16bitBE;
        //size_offset = 0x14;
        meta_offset_offset = 0x40 + read_16bit(0xe,streamFile);
    } else if (read_32bitLE(8,streamFile) == 3 ||
               read_32bitLE(8,streamFile) == 2) {
        /* version 2/3 LE, as seen in FFXIV for ?? */
        read_32bit = read_32bitLE;
        read_16bit = read_16bitLE;
        //size_offset = 0x10;
        meta_offset_offset = 0x40 + read_16bit(0xe,streamFile);
    } else goto fail;

    /* never mind, FFXIII music_68tak.ps3.scd is 0x80 shorter */
#if 0
    /* check file size with header value */
    if (read_32bit(size_offset,streamFile) != get_streamfile_size(streamFile))
        goto fail;
#endif

    meta_offset = read_32bit(meta_offset_offset,streamFile);

    /* check that chunk size equals stream size (?) */
    loop_start = read_32bit(meta_offset+0x10,streamFile);
    loop_end = read_32bit(meta_offset+0x14,streamFile);
    loop_flag = (loop_end > 0);

    channel_count = read_32bit(meta_offset+4,streamFile);
    codec_id = read_32bit(meta_offset+0xc,streamFile);

    post_meta_offset = meta_offset + 0x20;

    /* data at meta_offset is only 0x20 bytes, but there may be auxiliary chunks
       before anything else */

    aux_chunk_count = read_32bit(meta_offset+0x1c,streamFile);
    for (; aux_chunk_count > 0; aux_chunk_count --)
    {
        /* skip aux chunks */
        /*printf("skipping %08x\n", read_32bitBE(post_meta_offset, streamFile));*/
        post_meta_offset += read_32bit(post_meta_offset+4,streamFile);
    }

    start_offset = post_meta_offset + read_32bit(meta_offset+0x18,streamFile);

#ifdef VGM_USE_VORBIS
    if (codec_id == 0x6)
    {
        vgm_vorbis_info_t inf;
        uint32_t seek_table_size = read_32bit(post_meta_offset+0x10, streamFile);
        uint32_t vorb_header_size = read_32bit(post_meta_offset+0x14, streamFile);
        VGMSTREAM * result = NULL;

        memset(&inf, 0, sizeof(inf));
        inf.loop_start = loop_start;
        inf.loop_end = loop_end;
        inf.loop_flag = loop_flag;
        inf.loop_end_found = loop_flag;
        inf.loop_length_found = 0;
        inf.layout_type = layout_ogg_vorbis;
        inf.meta_type = meta_SQEX_SCD;

        result = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf);

        if (result != NULL) {
            return result;
        }

        // try skipping seek table
        {
            if ((post_meta_offset-meta_offset) + seek_table_size + vorb_header_size != read_32bit(meta_offset+0x18, streamFile)) {
                return NULL;
            }

            start_offset = post_meta_offset + 0x20 + seek_table_size;
            result = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf);
            if (result != NULL) {
                return result;
            }
        }

        // failed with Ogg, try deobfuscating header
        {
            // skip chunks before xor_byte
            unsigned char xor_byte;

            xor_byte = read_8bit(post_meta_offset+2, streamFile);

            if (xor_byte == 0) {
                return NULL;
            }

            inf.scd_xor = xor_byte;
            inf.scd_xor_len = vorb_header_size;

            result = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, start_offset, &inf);
            return result;
        }
    }
#endif
    
	/* 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_32bit(meta_offset+8,streamFile);

    switch (codec_id) {
        case 0x1:
            /* PCM */
            vgmstream->coding_type = coding_PCM16LE_int;
            vgmstream->layout_type = layout_none;
            vgmstream->num_samples = read_32bit(meta_offset+0,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;
            }
            break;
#ifdef VGM_USE_MPEG
        case 0x7:
            /* MPEG */
            {
                mpeg_codec_data *mpeg_data = NULL;
                struct mpg123_frameinfo mi;
                coding_t ct;

                if (vgmstream->sample_rate == 47999)
                    vgmstream->sample_rate = 48000;
                if (vgmstream->sample_rate == 44099)
                    vgmstream->sample_rate = 44100;

                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_32bit(meta_offset+0,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
        case 0xC:
            /* MS ADPCM */
            vgmstream->coding_type = coding_MSADPCM;
            vgmstream->layout_type = layout_none;
            vgmstream->interleave_block_size = read_16bit(post_meta_offset+0xc,streamFile);
            vgmstream->num_samples = msadpcm_bytes_to_samples(read_32bit(meta_offset+0,streamFile), vgmstream->interleave_block_size, vgmstream->channels);

            if (loop_flag) {
                vgmstream->loop_start_sample = msadpcm_bytes_to_samples(loop_start, vgmstream->interleave_block_size, vgmstream->channels);
                vgmstream->loop_end_sample = msadpcm_bytes_to_samples(loop_end, vgmstream->interleave_block_size, vgmstream->channels);
            }
            break;
        case 0xA:
            /* GC/Wii DSP ADPCM */
            {
                STREAMFILE * file;
                int i;
                const off_t interleave_size = 0x800;
                const off_t stride_size = interleave_size * channel_count;

                size_t total_size;

                scd_int_codec_data * data = NULL;

                vgmstream->coding_type = coding_NGC_DSP;
                vgmstream->layout_type = layout_scd_int;

                /* a normal DSP header... */
                vgmstream->num_samples = read_32bitBE(start_offset+0,streamFile);
                total_size = (read_32bitBE(start_offset+4,streamFile)+1)/2;

                if (loop_flag) {
                    vgmstream->loop_start_sample = loop_start;
                    vgmstream->loop_end_sample = loop_end+1;
                }

                /* verify other channel headers */
                for (i = 1; i < channel_count; i++) {
                    if (read_32bitBE(start_offset+interleave_size*i+0,streamFile) != vgmstream->num_samples ||
                        (read_32bitBE(start_offset+4,streamFile)+1)/2 != total_size) {
                        goto fail;
                    }

                }

                /* the primary streamfile we'll be using */
                file = streamFile->open(streamFile,filename,stride_size);
                if (!file)
                    goto fail;

                vgmstream->ch[0].streamfile = file;

                data = malloc(sizeof(scd_int_codec_data));
                data->substream_count = channel_count;
                data->substreams = calloc(channel_count, sizeof(VGMSTREAM *));
                data->intfiles = calloc(channel_count, sizeof(STREAMFILE *));

                vgmstream->codec_data = data;

                for (i=0;i<channel_count;i++) {
                    STREAMFILE * intfile =
                        open_scdint_with_STREAMFILE(file, "ARBITRARY.DSP", start_offset+interleave_size*i, interleave_size, stride_size, total_size);

                    data->substreams[i] = init_vgmstream_ngc_dsp_std(intfile);
                    data->intfiles[i] = intfile;
                    if (!data->substreams[i])
                        goto fail;

                    /* TODO: only handles mono substreams, though that's all we have with DSP */
                    /* save start things so we can restart for seeking/looping */
                    /* copy the channels */
                    memcpy(data->substreams[i]->start_ch,data->substreams[i]->ch,sizeof(VGMSTREAMCHANNEL)*1);
                    /* copy the whole VGMSTREAM */
                    memcpy(data->substreams[i]->start_vgmstream,data->substreams[i],sizeof(VGMSTREAM));

                }

            }
            break;
#ifdef VGM_USE_FFMPEG
        case 0xB:
            /* XMA1/XMA2 */
            {
                uint16_t codec_id = read_16bit(post_meta_offset, streamFile);
                if (codec_id == 0x165 || codec_id == 0x166)
                {
                    ffmpeg_codec_data *ffmpeg_data = init_ffmpeg_faux_riff(streamFile, post_meta_offset, start_offset, streamFile->get_size(streamFile) - start_offset, read_32bit == read_32bitBE);
                    if (!ffmpeg_data) goto fail;
                    
                    vgmstream->codec_data = ffmpeg_data;
                    
                    vgmstream->coding_type = coding_FFmpeg;
                    vgmstream->layout_type = layout_none;
                    
                    vgmstream->num_samples = ffmpeg_data->totalSamples;

                    if (loop_flag) {
                        vgmstream->loop_start_sample = loop_start;
                        vgmstream->loop_end_sample = loop_end;
                    }
                }
                else goto fail;
            }
            break;
#endif
        default:
            goto fail;
    }

    vgmstream->meta_type = meta_SQEX_SCD;

    /* open the file for reading */
    if (vgmstream->layout_type != layout_scd_int
#ifdef VGM_USE_FFMPEG
        && vgmstream->coding_type != coding_FFmpeg
#endif
        )
    {
        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;

        }
    }

    return vgmstream;

    /* clean up anything we may have opened */
fail:
    if (vgmstream) close_vgmstream(vgmstream);
    return NULL;
}
예제 #6
0
/* IAB: Ueki no Housoku - Taosu ze Robert Juudan!! (PS2) */
VGMSTREAM * init_vgmstream_ps2_iab(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
    char filename[260];
    int loop_flag = 0;
	int channel_count;
    int i;
	off_t start_offset;
	
    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("iab",filename_extension(filename))) goto fail;

    /* check header */
    if (read_32bitBE(0x00,streamFile) != 0x10000000)
        goto fail;
    
    /* check file size */
    if (read_32bitLE(0x1C,streamFile) != get_streamfile_size(streamFile))
        goto fail;

    loop_flag = 0;
    channel_count = 2;
    
	/* build the VGMSTREAM */
    vgmstream = allocate_vgmstream(channel_count,loop_flag);
    if (!vgmstream) goto fail;

	/* fill in the vital statistics */
    start_offset = 0x40;
	vgmstream->channels = channel_count;
    vgmstream->sample_rate = read_32bitLE(0x4,streamFile);
    vgmstream->coding_type = coding_PSX;

    vgmstream->layout_type = layout_ps2_iab_blocked;
    vgmstream->interleave_block_size = read_32bitLE(0xC, streamFile);
    vgmstream->meta_type = meta_PS2_IAB;
    
    /* open the file for reading by each channel */
    {
        for (i=0;i<channel_count;i++) 
		{
            vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename, vgmstream->interleave_block_size);            
			if (!vgmstream->ch[i].streamfile) goto fail;
        }
    }

    /* Calc num_samples */
    ps2_iab_block_update(start_offset, vgmstream);
    vgmstream->num_samples=0;

    do 
	{    
		vgmstream->num_samples += 0x4000 * 14 / 16;
        ps2_iab_block_update(vgmstream->next_block_offset, vgmstream);
    } while (vgmstream->next_block_offset < get_streamfile_size(streamFile));

    ps2_iab_block_update(start_offset, vgmstream);

    return vgmstream;

    /* clean up anything we may have opened */
fail:
    if (vgmstream) close_vgmstream(vgmstream);
    return NULL;
}
예제 #7
0
VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
    char filename[PATH_LIMIT];

    int loop_flag=0;
    int channel_count;
	off_t start_offset;
	off_t check_offset;
	int32_t streamSize;

	uint8_t	testBuffer[0x10];
	uint8_t isPCM = 0;

	off_t	readOffset = 0;
	off_t	loopEnd = 0;

	int i;

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("ads",filename_extension(filename)) && 
        strcasecmp("ss2",filename_extension(filename))) goto fail;

    /* check SShd Header */
    if (read_32bitBE(0x00,streamFile) != 0x53536864)
        goto fail;

    /* check SSbd Header */
    if (read_32bitBE(0x20,streamFile) != 0x53536264)
        goto fail;

    /* check if file is not corrupt */
	/* seems the Gran Turismo 4 ADS files are considered corrupt,*/
	/* so I changed it to adapt the stream size if that's the case */
	/* instead of failing playing them at all*/
	streamSize = read_32bitLE(0x24,streamFile);
    
	if (get_streamfile_size(streamFile) < (size_t)(streamSize + 0x28))
	{
		streamSize = get_streamfile_size(streamFile) - 0x28;
	}

    /* check loop */    
	if ((read_32bitLE(0x1C,streamFile) == 0xFFFFFFFF) || 
		((read_32bitLE(0x18,streamFile) == 0) && (read_32bitLE(0x1C,streamFile) == 0)))
	{
		loop_flag = 0;
	}
	else
	{
		loop_flag = 1;
	}
	
    channel_count=read_32bitLE(0x10,streamFile);

    /* build the VGMSTREAM */
    vgmstream = allocate_vgmstream(channel_count,loop_flag);
    if (!vgmstream) goto fail;

    /* fill in the vital statistics */
    vgmstream->channels = read_32bitLE(0x10,streamFile);
    vgmstream->sample_rate = read_32bitLE(0x0C,streamFile);

    /* Check for Compression Scheme */
    vgmstream->coding_type = coding_PSX;
    vgmstream->num_samples = ((streamSize-0x40)/16*28)/vgmstream->channels;

	/* SS2 container with RAW Interleaved PCM */
    if (read_32bitLE(0x08,streamFile)!=0x10) 
	{

        vgmstream->coding_type=coding_PCM16LE;
        vgmstream->num_samples = streamSize/2/vgmstream->channels;
    }

    vgmstream->interleave_block_size = read_32bitLE(0x14,streamFile);
    vgmstream->layout_type = layout_interleave;
    vgmstream->meta_type = meta_PS2_SShd;

    /* Get loop point values */
    if(vgmstream->loop_flag) {
		if((read_32bitLE(0x1C,streamFile)*0x10*vgmstream->channels+0x800)==get_streamfile_size(streamFile)) 
		{
			// Search for Loop Value
			readOffset=(off_t)get_streamfile_size(streamFile)-(4*vgmstream->interleave_block_size); 

			do {
				readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); 
	
				// Loop End ...
				if(testBuffer[0x01]==0x01) {
					if(loopEnd==0) loopEnd = readOffset-0x10;
					break;
				}

			} while (streamFile->get_offset(streamFile)<(int32_t)get_streamfile_size(streamFile));

			vgmstream->loop_start_sample = 0;
			vgmstream->loop_end_sample = (loopEnd/(vgmstream->interleave_block_size)*vgmstream->interleave_block_size)/16*28;
			vgmstream->loop_end_sample += (loopEnd%vgmstream->interleave_block_size)/16*28;
			vgmstream->loop_end_sample /=vgmstream->channels;

		} else {
			if(read_32bitLE(0x1C,streamFile)<=vgmstream->num_samples) {
				vgmstream->loop_start_sample = read_32bitLE(0x18,streamFile);
				vgmstream->loop_end_sample = read_32bitLE(0x1C,streamFile);
			} else {
				vgmstream->loop_start_sample = (read_32bitLE(0x18,streamFile)*0x10)/16*28/vgmstream->channels;;
				vgmstream->loop_end_sample = (read_32bitLE(0x1C,streamFile)*0x10)/16*28/vgmstream->channels;
			}
		}
    }

    /* don't know why, but it does happen, in ps2 too :( */
    if (vgmstream->loop_end_sample > vgmstream->num_samples)
        vgmstream->loop_end_sample = vgmstream->num_samples;
	{
		start_offset=0x28;
	}

		
	if ((streamSize * 2) == (get_streamfile_size(streamFile) - 0x18))
	{
		// True Fortune PS2
		streamSize = (read_32bitLE(0x24,streamFile) * 2) - 0x10;
		vgmstream->num_samples = streamSize / 16 * 28 / vgmstream->channels;
	}
	else if(get_streamfile_size(streamFile) - read_32bitLE(0x24,streamFile) >= 0x800)
	{
		// Hack for files with start_offset = 0x800
		start_offset=0x800;
	}

	if((vgmstream->coding_type == coding_PSX) && (start_offset==0x28)) 
	{
		start_offset=0x800;
		
		for(i=0;i<0x1f6;i+=4) 
		{
			if(read_32bitLE(0x28+(i*4),streamFile)!=0) 
			{
				start_offset=0x28;
				break;
			}
		}
	} 

	// check if we got a real pcm (ex: Clock Tower 3)
	if(vgmstream->coding_type==coding_PCM16LE) 
	{
		check_offset=start_offset;
		do 
		{
			if(read_8bit(check_offset+1,streamFile)>7) 
			{
				isPCM=1;
				break;
			} 
			else
			{
				check_offset+=0x10;
			}
			
		} while (check_offset<get_streamfile_size(streamFile));

		if(!isPCM) 
		{
			vgmstream->num_samples=(get_streamfile_size(streamFile)-start_offset)/16*28/vgmstream->channels;
			vgmstream->coding_type=coding_PSX;
		}
	}

	/* expect pcm format allways start @ 0x800, don't know if it's true :P */
	/*if(vgmstream->coding_type == coding_PCM16LE)
		start_offset=0x800;*/

    /* open the file for reading by each channel */
    {
        for (i=0;i<channel_count;i++) {
            vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000);

            if (!vgmstream->ch[i].streamfile) goto fail;

            vgmstream->ch[i].channel_start_offset=
                vgmstream->ch[i].offset=
                (off_t)(start_offset+vgmstream->interleave_block_size*i);
        }
    }

    return vgmstream;

    /* clean up anything we may have opened */
fail:
    if (vgmstream) close_vgmstream(vgmstream);
    return NULL;
}
예제 #8
0
파일: rsd.c 프로젝트: xbmcin/XBMCinTC
/* RSD6WADP */
VGMSTREAM * init_vgmstream_rsd6wadp(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("rsd",filename_extension(filename))) goto fail;

    /* check header */
    if (read_32bitBE(0x0,streamFile) != 0x52534436) /* RSD6 */
		goto fail;
	if (read_32bitBE(0x4,streamFile) != 0x57414450)	/* WADP */
        goto fail;

    loop_flag = 0;
    channel_count = read_32bitLE(0x8,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->coding_type = coding_NGC_DSP;
    vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count;
    if (loop_flag) {
        vgmstream->loop_start_sample = loop_flag;
        vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count;
    }

    vgmstream->layout_type = layout_interleave_byte; //layout_interleave;
    vgmstream->interleave_block_size = 2; //read_32bitLE(0xC,streamFile);
    vgmstream->meta_type = meta_RSD6WADP;

    if (vgmstream->coding_type == coding_NGC_DSP) {
        int i;
        for (i=0;i<16;i++) {
            vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x1A4+i*2,streamFile);
        }
        if (vgmstream->channels) {
            for (i=0;i<16;i++) {
                vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x1CC+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;
}
예제 #9
0
파일: mn_str.c 프로젝트: Sappharad/modizer
VGMSTREAM * init_vgmstream_mn_str(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
    char filename[1024];
    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;
}
예제 #10
0
파일: ps2_mib.c 프로젝트: xbmcin/XBMCinTC
VGMSTREAM * init_vgmstream_ps2_mib(STREAMFILE *streamFile) {
    
	VGMSTREAM * vgmstream = NULL;
    STREAMFILE * streamFileMIH = NULL;
    char filename[260];
    
	uint8_t mibBuffer[0x10];
	uint8_t	testBuffer[0x10];
	uint8_t doChannelUpdate=1;
	uint8_t bDoUpdateInterleave=1;

	size_t	fileLength;
	
	off_t	loopStart = 0;
	off_t	loopEnd = 0;

	off_t	interleave = 0;

	off_t	readOffset = 0;

	char	filenameMIH[260];
	off_t	loopStartPoints[0x10];
	int		loopStartPointsCount=0;

	off_t	loopEndPoints[0x10];
	int		loopEndPointsCount=0;

	int		loopToEnd=0;
	int		forceNoLoop=0;
	int		gotEmptyLine=0;

	uint8_t gotMIH=0;

	int i, channel_count=0;

	// Initialize loop point to 0
	for(i=0; i<0x10; i++) {
		loopStartPoints[i]=0;
		loopEndPoints[i]=0;
	}

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("mib",filename_extension(filename)) && 
		strcasecmp("mi4",filename_extension(filename)) && 
		strcasecmp("vb",filename_extension(filename))  &&
		strcasecmp("xag",filename_extension(filename))) goto fail;

	/* check for .MIH file */
	strcpy(filenameMIH,filename);
	strcpy(filenameMIH+strlen(filenameMIH)-3,"MIH");

	streamFileMIH = streamFile->open(streamFile,filenameMIH,STREAMFILE_DEFAULT_BUFFER_SIZE);
	if (streamFileMIH) gotMIH = 1;

    /* Search for interleave value & loop points */
	/* Get the first 16 values */
	fileLength = get_streamfile_size(streamFile);
	
	readOffset+=(off_t)read_streamfile(mibBuffer,0,0x10,streamFile); 
	readOffset=0;
	mibBuffer[0]=0;

	do {
		readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); 
		// be sure to point to an interleave value
		if(readOffset<(int32_t)(fileLength*0.5)) {

			if(memcmp(testBuffer+2, mibBuffer+2,0x0e)) {
				if(doChannelUpdate) {
					doChannelUpdate=0;
					channel_count++;
				}
				if(channel_count<2)
					bDoUpdateInterleave=1;
			}

			testBuffer[0]=0;
			if(!memcmp(testBuffer,mibBuffer,0x10)) {

				gotEmptyLine=1;

				if(bDoUpdateInterleave) {
					bDoUpdateInterleave=0;
					interleave=readOffset-0x10;
				}
				if(((readOffset-0x10)==(channel_count*interleave))) {
					doChannelUpdate=1;
				}
			}
		}

		// Loop Start ...
		if(testBuffer[0x01]==0x06) 
		{
			if(loopStartPointsCount<0x10) 
			{
				loopStartPoints[loopStartPointsCount] = readOffset-0x10;
				loopStartPointsCount++;
			}
		}

		// Loop End ...
		if((testBuffer[0x01]==0x03) && (testBuffer[0x03]!=0x77)) {
			if(loopEndPointsCount<0x10) 
			{
				loopEndPoints[loopEndPointsCount] = readOffset;
				loopEndPointsCount++;
			}
		}

		if(testBuffer[0x01]==0x04) 
		{
			// 0x04 loop points flag can't be with a 0x03 loop points flag
			if(loopStartPointsCount<0x10) 
			{
				loopStartPoints[loopStartPointsCount] = readOffset-0x10;
				loopStartPointsCount++;

				// Loop end value is not set by flags ...
				// go until end of file
				loopToEnd=1;
			}
		}

	} while (streamFile->get_offset(streamFile)<((int32_t)fileLength));

	if((testBuffer[0]==0x0c) && (testBuffer[1]==0))
		forceNoLoop=1;

	if(channel_count==0)
		channel_count=1;

	if(gotMIH) 
		channel_count=read_32bitLE(0x08,streamFileMIH);

	// force no loop
	if(!strcasecmp("vb",filename_extension(filename))) 
		loopStart=0;

	if(!strcasecmp("xag",filename_extension(filename))) 
		channel_count=2;

	// Calc Loop Points & Interleave ...
	if(loopStartPointsCount>=2) 
	{
		// can't get more then 0x10 loop point !
		if(loopStartPointsCount<=0x0F) {
			// Always took the first 2 loop points
			interleave=loopStartPoints[1]-loopStartPoints[0];
			loopStart=loopStartPoints[1];

			// Can't be one channel .mib with interleave values
			if((interleave>0) && (channel_count==1)) 
				channel_count=2;
		} else 
			loopStart=0;
	}

	if(loopEndPointsCount>=2) 
	{
		// can't get more then 0x10 loop point !
		if(loopEndPointsCount<=0x0F) {
			// No need to recalculate interleave value ...
			loopEnd=loopEndPoints[loopEndPointsCount-1];

			// Can't be one channel .mib with interleave values
			if(channel_count==1) channel_count=2;
		} else {
			loopToEnd=0;
			loopEnd=0;
		}
	}

	if (loopToEnd) 
		loopEnd=fileLength;

	// force no loop 
	if(forceNoLoop) 
		loopEnd=0;

	if((interleave>0x10) && (channel_count==1))
		channel_count=2;

	if(interleave==0) interleave=0x10;

	// further check on channel_count ...
	if(gotEmptyLine) 
	{
		int newChannelCount = 0;

		readOffset=0;

		do 
		{
			newChannelCount++;
			read_streamfile(testBuffer,readOffset,0x10,streamFile); 
			readOffset+=interleave;
		} while(!memcmp(testBuffer,mibBuffer,16));

		newChannelCount--;

		if(newChannelCount>channel_count)
			channel_count=newChannelCount;
	}

	/* build the VGMSTREAM */
    vgmstream = allocate_vgmstream(channel_count,(loopEnd!=0));
    if (!vgmstream) goto fail;

    /* fill in the vital statistics */
	vgmstream->coding_type = coding_PSX;
    vgmstream->layout_type = layout_interleave;

	if(gotMIH) {
		// Read stuff from the MIH file 
		vgmstream->channels = read_32bitLE(0x08,streamFileMIH);
		vgmstream->sample_rate = read_32bitLE(0x0C,streamFileMIH);
		vgmstream->interleave_block_size = read_32bitLE(0x10,streamFileMIH);
		vgmstream->num_samples=((read_32bitLE(0x10,streamFileMIH)*
								(read_32bitLE(0x14,streamFileMIH)-1)*2)+
								((read_32bitLE(0x04,streamFileMIH)>>8)*2))/16*28/2;
	} else {
예제 #11
0
파일: rsd.c 프로젝트: xbmcin/XBMCinTC
/* RSD2PCMB - Big Endian */
VGMSTREAM * init_vgmstream_rsd2pcmb(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("rsd",filename_extension(filename))) goto fail;

    /* check header */
    if (read_32bitBE(0x0,streamFile) != 0x52534432) /* RSD2 */
		goto fail;
	if (read_32bitBE(0x4,streamFile) != 0x50434D42)	/* PCMB */
        goto fail;

    loop_flag = 0;
    channel_count = read_32bitLE(0x8,streamFile);
    
	/* build the VGMSTREAM */
    vgmstream = allocate_vgmstream(channel_count,loop_flag);
    if (!vgmstream) goto fail;

	/* fill in the vital statistics */
	start_offset = read_32bitLE(0x18,streamFile);
	vgmstream->channels = channel_count;
    vgmstream->sample_rate = read_32bitLE(0x10,streamFile);
    vgmstream->coding_type = coding_PCM16BE;
    vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)/2/channel_count;
    if (loop_flag) {
        vgmstream->loop_start_sample = loop_flag;
        vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-start_offset)/2/channel_count;
    }

	
	if (channel_count == 1) {
		vgmstream->layout_type = layout_none;
	} else if (channel_count == 2) {
		vgmstream->layout_type = layout_interleave;
		vgmstream->interleave_block_size = 0x2;
	}


    vgmstream->meta_type = meta_RSD2PCMB;

    /* 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;
}
예제 #12
0
파일: ps2_ild.c 프로젝트: Sappharad/modizer
VGMSTREAM * init_vgmstream_ps2_ild(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("ild",filename_extension(filename))) goto fail;

    /* check ILD Header */
    if (read_32bitBE(0x00,streamFile) != 0x494C4400)
        goto fail;

	/* check loop */
	loop_flag = (read_32bitLE(0x2C,streamFile)!=0);
    channel_count=read_32bitLE(0x04,streamFile);
    
	/* build the VGMSTREAM */
    vgmstream = allocate_vgmstream(channel_count,loop_flag);
    if (!vgmstream) goto fail;

	/* fill in the vital statistics */
	vgmstream->channels = read_32bitLE(0x04,streamFile);
    vgmstream->sample_rate = read_32bitLE(0x28,streamFile);

	/* Check for Compression Scheme */
	vgmstream->coding_type = coding_PSX;
    vgmstream->num_samples = read_32bitLE(0x0C,streamFile)/16*28/vgmstream->channels;

	/* Get loop point values */
	if(vgmstream->loop_flag) {
		vgmstream->loop_start_sample = read_32bitLE(0x2C,streamFile)/16*28;
		vgmstream->loop_end_sample = read_32bitLE(0x30,streamFile)/16*28;
	}

	vgmstream->interleave_block_size = read_32bitLE(0x18,streamFile)/2;
    vgmstream->layout_type = layout_interleave;
    vgmstream->meta_type = meta_PS2_ILD;

	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;
}
예제 #13
0
/* probably Square Vag Stream */
VGMSTREAM * init_vgmstream_svs(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
    char filename[PATH_LIMIT];
    off_t start_offset;

    int loop_flag = 0;
	int channel_count;

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("svs",filename_extension(filename))) goto fail;

    /* check header */
    if (read_32bitBE(0x00,streamFile) != 0x53565300) /* "SVS\0" */
        goto fail;

    loop_flag = (read_32bitLE(0x08,streamFile)!=0);
    /* 63.SVS has start and end on the same sample, which crashes stuff */
    if (read_32bitLE(0x08,streamFile)==read_32bitLE(0x0c,streamFile))
        loop_flag = 0;
    channel_count = 2;
    
	/* build the VGMSTREAM */
    vgmstream = allocate_vgmstream(channel_count,loop_flag);
    if (!vgmstream) goto fail;

	/* fill in the vital statistics */
    start_offset = 0x40;
	vgmstream->channels = channel_count;
    vgmstream->sample_rate = 44100;
    vgmstream->coding_type = coding_PSX;
    vgmstream->num_samples = (get_streamfile_size(streamFile)-0x40)*28/16/channel_count;
    if (loop_flag) {
        vgmstream->loop_start_sample = (read_32bitLE(0x08,streamFile)-1)*28;
        vgmstream->loop_end_sample = (read_32bitLE(0x0c,streamFile)-1)*28;
    }

    vgmstream->layout_type = layout_interleave;
    vgmstream->interleave_block_size = 0x10;
    vgmstream->meta_type = meta_PS2_SVS;

    /* 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;
}
예제 #14
0
VGMSTREAM * init_vgmstream_nds_strm(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
    char filename[1024];

    coding_t coding_type;

    int codec_number;
    int channel_count;
    int loop_flag;

    off_t start_offset;

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("strm",filename_extension(filename))) goto fail;

    /* check header */
    if ((uint32_t)read_32bitBE(0x00,streamFile)!=0x5354524D)	/* STRM */
        goto fail;
	if ((uint32_t)read_32bitBE(0x04,streamFile)!=0xFFFE0001 &&	/* Old Header Check */
		((uint32_t)read_32bitBE(0x04,streamFile)!=0xFEFF0001))	/* Some newer games have a new flag */
		goto fail;



    /* check for HEAD section */
    if ((uint32_t)read_32bitBE(0x10,streamFile)!=0x48454144 && /* "HEAD" */
            (uint32_t)read_32bitLE(0x14,streamFile)!=0x50) /* 0x50-sized head is all I've seen */
        goto fail;

    /* check type details */
    codec_number = read_8bit(0x18,streamFile);
    loop_flag = read_8bit(0x19,streamFile);
    channel_count = read_8bit(0x1a,streamFile);

    switch (codec_number) {
        case 0:
            coding_type = coding_PCM8;
            break;
        case 1:
            coding_type = coding_PCM16LE;
            break;
        case 2:
            coding_type = coding_NDS_IMA;
            break;
        default:
            goto fail;
    }

    /* TODO: only mono and stereo supported */
    if (channel_count < 1 || channel_count > 2) 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(0x24,streamFile);
    vgmstream->sample_rate = (uint16_t)read_16bitLE(0x1c,streamFile);
    /* channels and loop flag are set by allocate_vgmstream */
    vgmstream->loop_start_sample = read_32bitLE(0x20,streamFile);
    vgmstream->loop_end_sample = vgmstream->num_samples;

    vgmstream->coding_type = coding_type;
    vgmstream->meta_type = meta_STRM;

    vgmstream->interleave_block_size = read_32bitLE(0x30,streamFile);
    vgmstream->interleave_smallblock_size = read_32bitLE(0x38,streamFile);

    if (coding_type==coding_PCM8 || coding_type==coding_PCM16LE)
        vgmstream->layout_type = layout_none;
    else
        vgmstream->layout_type = layout_interleave_shortblock;

    start_offset = read_32bitLE(0x28,streamFile);

    /* 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
                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;
}
예제 #15
0
VGMSTREAM * init_vgmstream_pc_mxst(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
    char filename[260];

    int loop_flag=0;
	int bits_per_sample;
	int channel_count;
    int sample_rate,bytes_per_second;
    long sample_count;
    int i;
    off_t file_size;
    off_t chunk_list_size=-1;
    off_t start_offset;

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("mxst",filename_extension(filename))) goto fail;

    /* looping info not found yet */
	//loop_flag = get_streamfile_size(streamFile) > 700000;

    /* check MxSt header */
    if (0x4d785374 != read_32bitBE(0, streamFile)) goto fail;
    file_size = read_32bitLE(4, streamFile) + 8;
    if (file_size != get_streamfile_size(streamFile)) goto fail;

    /* read chunks */
    {
        off_t MxDa=-1; /* points inside the MxDa chunk */
        off_t MxCh=-1; /* point at start of the first MxCh chunk */
        off_t chunk_offset = 8;
        uint32_t stream_id;
        while (chunk_offset < file_size)
        {
            uint32_t chunk_size = (read_32bitLE(chunk_offset+4, streamFile)+1)/2*2;
            switch (read_32bitBE(chunk_offset, streamFile))
            {
                case 0x4d784f62:    /* MxOb */
                    /* not interesting for playback */
                    break;
                case 0x20574156:    /* " WAV" */
                    if (chunk_size == 1)
                        chunk_size = 8;
                    break;
                case 0x4c495354:    /* LIST */
                {
                    off_t first_item_offset = chunk_offset+0x14;
                    off_t list_chunk_offset = first_item_offset+
                        read_32bitLE(chunk_offset+0x10,streamFile);

                    if (read_32bitBE(chunk_offset+0x8,streamFile) == 0x4d784461) /* MxDa */
                        MxDa = first_item_offset;
                    else
                        goto fail;

                    if (read_32bitBE(chunk_offset+0xC,streamFile) ==
                        0x4d784368) /* MxCh */
                    {
                        MxCh = list_chunk_offset;
                        chunk_list_size = chunk_size - (list_chunk_offset-(chunk_offset+8));
                    }
                    else
                        goto fail;

                    break;
                }
                default:
                    goto fail;
            }

            chunk_offset += 8 + chunk_size;
            if (chunk_offset > file_size) goto fail;
        }

        if (MxDa == -1 || MxCh == -1 || chunk_list_size == -1) goto fail;
        
        /* parse MxDa */
        {
            /* ??? */
            if (0 != read_16bitLE(MxDa+0x00,streamFile)) goto fail;
            stream_id = read_32bitLE(MxDa+0x2,streamFile);
            /* First sample (none in MxDa block) */
            if (-1 != read_32bitLE(MxDa+0x06,streamFile)) goto fail;
            /* size of format data */
            if (0x18 != read_32bitLE(MxDa+0x0a,streamFile)) goto fail;
            /* PCM */
            if (1 != read_16bitLE(MxDa+0x0e,streamFile)) goto fail;
            /* channel count */
            channel_count = read_16bitLE(MxDa+0x10,streamFile);
            /* only mono known */
            if (1 != channel_count) goto fail;
            sample_rate = read_32bitLE(MxDa+0x12,streamFile);
            bits_per_sample = read_16bitLE(MxDa+0x1c,streamFile);
            /* bytes per second */
            bytes_per_second = read_32bitLE(MxDa+0x16,streamFile);
            if (bits_per_sample/8*channel_count*sample_rate != bytes_per_second) goto fail;
            /* block align */
            if (bits_per_sample/8*channel_count !=
                read_16bitLE(MxDa+0x1a,streamFile)) goto fail;
            sample_count = read_32bitLE(MxDa+0x1e,streamFile)/(bits_per_sample/8)/channel_count;
            /* 2c? data offset in normal RIFF WAVE? */
            if (0x2c != read_32bitLE(MxDa+0x22,streamFile)) goto fail;
        }

        /* parse through all MxCh for consistency check */
        {
            long samples = 0;
            int split_frames_seen = 0;
            off_t MxCh_offset = MxCh;
            while (MxCh_offset < MxCh+chunk_list_size)
            {
                uint16_t flags;
                if (read_32bitBE(MxCh_offset,streamFile)!=0x70616420) /*pad*/
                {
                    if (read_32bitBE(MxCh_offset,streamFile)!=0x4d784368) /*MxCh*/
                        goto fail;

                    flags = read_16bitLE(MxCh_offset+8+0,streamFile);

                    if (read_32bitLE(MxCh_offset+8+2,streamFile)!=stream_id)
                        goto fail;

                    if (flags & 0x10)
                    {
                        split_frames_seen ++;
                        if (split_frames_seen == 1)
                        {
                            if (read_32bitLE(MxCh_offset+8+6,streamFile)!=(samples*UINT64_C(1000)+sample_rate-1)/sample_rate)
                                goto fail;
                        }
                        else if (split_frames_seen == 2)
                        {
                            if ( read_32bitLE(MxCh_offset+8+0xa,streamFile)!=
                                    read_32bitLE(MxCh_offset+4,streamFile)-0xe ) goto fail;
                            split_frames_seen = 0;
                        }
                        else goto fail;
                    }

                    if (!(flags & 0x10))
                    {
                        if (split_frames_seen != 0)
                        {
                            goto fail;
                        }
                        if (read_32bitLE(MxCh_offset+8+6,streamFile)!=(samples*UINT64_C(1000)+sample_rate-1)/sample_rate)
                            goto fail;

                        if ( read_32bitLE(MxCh_offset+8+0xa,streamFile)!=
                             read_32bitLE(MxCh_offset+4,streamFile)-0xe ) goto fail;
                    }
                    samples += (read_32bitLE(MxCh_offset+4,streamFile)-0xe)/(bits_per_sample/8/channel_count);

                }
                MxCh_offset += 8 + (read_32bitLE(MxCh_offset+4,streamFile)+1)/2*2;
                if (MxCh_offset > MxCh+chunk_list_size) goto fail;
            }
            //printf("samples=%d sample_count=%d\n",samples,sample_count);
            //samples = (samples * (bits_per_sample/8) * channel_count + 31)/32*32/(bits_per_sample/8)/channel_count;
            if (samples < sample_count)
            {
                sample_count = samples;
            }
            if (samples != sample_count) goto fail;
        }

        start_offset = MxCh;
    }
    
	/* 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 = sample_rate;
    vgmstream->layout_type = layout_mxch_blocked;
	
    vgmstream->meta_type = meta_PC_MXST;
	if(bits_per_sample == 8)
	{
		vgmstream->coding_type = coding_PCM8_U;
	}
	else if (bits_per_sample == 16)
	{
		vgmstream->coding_type = coding_PCM16LE;
	}
    else goto fail;
	vgmstream->num_samples = sample_count;
	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,STREAMFILE_DEFAULT_BUFFER_SIZE);

            if (!vgmstream->ch[i].streamfile) goto fail;
        }

    }
    mxch_block_update(start_offset, vgmstream);

    return vgmstream;

    /* clean up anything we may have opened */
fail:
    if (vgmstream) close_vgmstream(vgmstream);
    return NULL;
}
예제 #16
0
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("strm",filename_extension(filename)) &&
        strcasecmp("xa",filename_extension(filename)) &&
        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_PCM_BE:
		 	vgmstream->meta_type=meta_EA_PCM;
			vgmstream->coding_type=coding_PCM16BE;
			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;
}
예제 #17
0
파일: wii_sng.c 프로젝트: Sappharad/modizer
/* SNG (from Excite Truck [WII]) */
VGMSTREAM * init_vgmstream_wii_sng(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
    char filename[1024];
    off_t start_offset;
    int i;
    int loop_flag;
    int channel_count;
    int coef1;
    int coef2;
    int first_block_len;
    int second_channel_start;
    int dataBuffer = 0;
    int Founddata = 0;
    size_t file_size;
    off_t current_chunk;

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("sng",filename_extension(filename))) goto fail;

    /* check header */
    if (read_32bitBE(0x00,streamFile) != 0x30545352) /* "0STR" */
        goto fail;
    if (read_32bitBE(0x04,streamFile) != 0x34000000) /* 0x34000000 */
        goto fail;
    if (read_32bitBE(0x08,streamFile) != 0x08000000) /* 0x08000000" */
        goto fail;
    if (read_32bitBE(0x0C,streamFile) != 0x01000000) /* 0x01000000 */
        goto fail;
    if (read_32bitLE(0x10,streamFile) != (get_streamfile_size(streamFile)))
        goto fail;

    loop_flag = (read_32bitLE(0x130,streamFile) !=0); /* not sure */
    channel_count = 2;
    
    /* build the VGMSTREAM */
    vgmstream = allocate_vgmstream(channel_count,loop_flag);
    if (!vgmstream) goto fail;

    /* fill in the vital statistics */
    start_offset = 0x180;
    vgmstream->channels = channel_count;
    vgmstream->sample_rate = read_32bitLE(0x110,streamFile);
    vgmstream->coding_type = coding_NGC_DSP;
    vgmstream->num_samples = read_32bitLE(0x100,streamFile)/16*14*2;
    if (loop_flag) {
        vgmstream->loop_start_sample = read_32bitBE(0x130,streamFile)/16*14;
        vgmstream->loop_end_sample = read_32bitBE(0x134,streamFile)/16*14;
    }

    vgmstream->layout_type = layout_none;
    vgmstream->meta_type = meta_WII_SNG;


    /* scan file until we find a "data" string */
    first_block_len = read_32bitLE(0x100,streamFile);
    file_size = get_streamfile_size(streamFile);
    {
        current_chunk = first_block_len;
        /* Start at 0 and loop until we reached the
        file size, or until we found a "data string */
        while (!Founddata && current_chunk < file_size) {
        dataBuffer = (read_32bitLE(current_chunk,streamFile));
            if (dataBuffer == first_block_len) { /* The value from the first block length */
                /* if "data" string found, retrieve the needed infos */
                Founddata = 1;
                second_channel_start = current_chunk+0x80;
                /* We will cancel the search here if we have a match */
            break;	
            }
            /* else we will increase the search offset by 1 */
            current_chunk = current_chunk + 1;
        }
    }

    coef1 = 0x13C;
    if (Founddata == 0) {
        goto fail;
    } else if (Founddata == 1) {
        coef2 = current_chunk+0x3C;
    }


        for (i=0;i<16;i++)
            vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(coef1+i*2,streamFile);
		if (channel_count == 2) {
		for (i=0;i<16;i++)
            vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(coef2+i*2,streamFile);
        }

    /* open the file for reading */
    {
        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[i].channel_start_offset=
            vgmstream->ch[1].offset=second_channel_start;
	    }
    }
}

    return vgmstream;

    /* clean up anything we may have opened */
fail:
    if (vgmstream) close_vgmstream(vgmstream);
    return NULL;
}
예제 #18
0
VGMSTREAM * init_vgmstream_ps2_svag(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
    char filename[1024];

    int loop_flag=0;
    int channel_count;
    int i;

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("svag",filename_extension(filename))) goto fail;

    /* check SVAG Header */
    if (read_32bitBE(0x00,streamFile) != 0x53766167)
        goto fail;

    /* check loop */
    loop_flag = (read_32bitLE(0x14,streamFile)==1);

    channel_count=read_16bitLE(0x0C,streamFile);

    /* build the VGMSTREAM */
    vgmstream = allocate_vgmstream(channel_count,loop_flag);
    if (!vgmstream) goto fail;

    /* fill in the vital statistics */
    vgmstream->channels = read_16bitLE(0x0C,streamFile);
    vgmstream->sample_rate = read_32bitLE(0x08,streamFile);

    /* Compression Scheme */
    vgmstream->coding_type = coding_PSX;
    vgmstream->num_samples = read_32bitLE(0x04,streamFile)/16*28/vgmstream->channels;

    /* Get loop point values */
    if(vgmstream->loop_flag) {
        vgmstream->loop_start_sample = read_32bitLE(0x18,streamFile)/16*28;
        vgmstream->loop_end_sample = read_32bitLE(0x04,streamFile)/16*28/vgmstream->channels;
    }

    vgmstream->interleave_block_size = read_32bitLE(0x10,streamFile);
    if (channel_count > 1) {
        vgmstream->interleave_smallblock_size = (read_32bitLE(0x04,streamFile)%(vgmstream->channels*vgmstream->interleave_block_size))/vgmstream->channels;
        vgmstream->layout_type = layout_interleave_shortblock;
    } else {
        vgmstream->layout_type = layout_none;
    }
    vgmstream->meta_type = meta_PS2_SVAG;

    /* open the file for reading by each channel */
    {
        for (i=0;i<channel_count;i++) {
            if (channel_count > 1)
                vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size);
            else
                vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);

            if (!vgmstream->ch[i].streamfile) goto fail;

            vgmstream->ch[i].channel_start_offset=
                vgmstream->ch[i].offset=
                (off_t)(0x800+vgmstream->interleave_block_size*i);
        }
    }

    return vgmstream;

    /* clean up anything we may have opened */
fail:
    if (vgmstream) close_vgmstream(vgmstream);
    return NULL;
}
예제 #19
0
VGMSTREAM * init_vgmstream_ps2_str(STREAMFILE *streamFile) {
    
	VGMSTREAM * vgmstream = NULL;
	STREAMFILE * infileSTH = NULL;
	char filename[260];

	char * filenameSTH = NULL;

	int i, channel_count, loop_flag;

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("str",filename_extension(filename))) goto fail;

	/* check for .MIH file */
	filenameSTH=(char *)malloc(strlen(filename)+1);

	if (!filenameSTH) goto fail;

	strcpy(filenameSTH,filename);
	strcpy(filenameSTH+strlen(filenameSTH)-3,"STH");

	infileSTH = streamFile->open(streamFile,filenameSTH,STREAMFILE_DEFAULT_BUFFER_SIZE);

	/* STH File is necessary, so we can't confuse those file */
	/* with others .STR file as it is a very common extension */
	if (!infileSTH) goto fail;

	if(read_32bitLE(0x2C,infileSTH)==0)
		goto fail;

	if((read_32bitLE(0x2C,infileSTH)==0x07) ||
	   (read_32bitLE(0x2C,infileSTH)==0x06))
		channel_count=2;
	if(read_32bitLE(0x2C,infileSTH)==0x05)
		channel_count=1;

	loop_flag = read_32bitLE(0x2C,infileSTH) & 0x01;

    /* build the VGMSTREAM */
    vgmstream = allocate_vgmstream(channel_count,loop_flag);
    if (!vgmstream) goto fail;

    /* fill in the vital statistics */
	vgmstream->channels = channel_count;
	vgmstream->sample_rate = read_32bitLE(0x24,infileSTH);

	vgmstream->interleave_block_size=0x4000;

	if(read_32bitLE(0x40,infileSTH)==0x01) 
		vgmstream->interleave_block_size = 0x8000; 

	vgmstream->num_samples=read_32bitLE(0x20,infileSTH);

	vgmstream->coding_type = coding_PSX;
    vgmstream->layout_type = layout_interleave;
    
	vgmstream->meta_type = meta_PS2_STR;

	if(loop_flag) {
		vgmstream->loop_start_sample = 0;
		vgmstream->loop_end_sample = read_32bitLE(0x20,infileSTH);
	}

	close_streamfile(infileSTH); infileSTH=NULL;

    /* open the file for reading by each channel */
    {
        for (i=0;i<channel_count;i++) {
            vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size);

            if (!vgmstream->ch[i].streamfile) goto fail;

            vgmstream->ch[i].channel_start_offset=
                vgmstream->ch[i].offset+=(off_t)(vgmstream->interleave_block_size*i);

        }
    }

    return vgmstream;

    /* clean up anything we may have opened */
fail:
    if (infileSTH) close_streamfile(infileSTH);
    if (filenameSTH) {free(filenameSTH); filenameSTH=NULL;}
    if (vgmstream) close_vgmstream(vgmstream);
    return NULL;
}
예제 #20
0
VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
    char filename[PATH_LIMIT];

    ov_callbacks callbacks;

    off_t other_header_bytes = 0;
    int um3_ogg = 0;
    int kovs_ogg = 0;
    int psych_ogg = 0;

    vgm_vorbis_info_t inf;
    memset(&inf, 0, sizeof(inf));

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    
    /* It is only interesting to use oggs with vgmstream if they are looped.
       To prevent such files from being played by other plugins and such they
       may be renamed to .logg. This meta reader should still support .ogg,
       though. */
    if (strcasecmp("logg",filename_extension(filename)) &&
            strcasecmp("ogg",filename_extension(filename))) {
        if (!strcasecmp("um3",filename_extension(filename))) {
            um3_ogg = 1;
        } else if (!strcasecmp("kovs",filename_extension(filename))) {
            kovs_ogg = 1;
        } else {
            goto fail;
        }
    }

    /* not all um3-ogg are crypted */
    if (um3_ogg && read_32bitBE(0x0,streamFile)==0x4f676753) {
        um3_ogg = 0;
    }

    /* use KOVS header */
    if (kovs_ogg) {
        if (read_32bitBE(0x0,streamFile)!=0x4b4f5653) { /* "KOVS" */
            goto fail;
        }
        if (read_32bitLE(0x8,streamFile)!=0) {
            inf.loop_start = read_32bitLE(0x8,streamFile);
            inf.loop_flag = 1;
        }

        other_header_bytes = 0x20;
    }

    /* detect Psychic Software obfuscation (as seen in "Darkwind") */
    if (read_32bitBE(0x0,streamFile)==0x2c444430) {
        psych_ogg = 1;
    }

    if (um3_ogg) {
        callbacks.read_func = read_func_um3;
    } else if (kovs_ogg) {
        callbacks.read_func = read_func_kovs;
    } else if (psych_ogg) {
        callbacks.read_func = read_func_psych;
    } else {
        callbacks.read_func = read_func;
    }
    callbacks.seek_func = seek_func;
    callbacks.close_func = close_func;
    callbacks.tell_func = tell_func;

    if (um3_ogg) {
        inf.meta_type = meta_um3_ogg;
    } else if (kovs_ogg) {
        inf.meta_type = meta_KOVS_ogg;
    } else if (psych_ogg) {
        inf.meta_type = meta_psych_ogg;
    } else {
        inf.meta_type = meta_ogg_vorbis;
    }

    inf.layout_type = layout_ogg_vorbis;

    return init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, &callbacks, other_header_bytes, &inf);

fail:
    return NULL;
}
예제 #21
0
파일: gtd.c 프로젝트: kode54/vgmstream
/* GTD - found in Knights Contract (X360, PS3), Valhalla Knights 3 (PSV) */
VGMSTREAM * init_vgmstream_gtd(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
    off_t start_offset, chunk_offset, stpr_offset, name_offset = 0, loop_start_offset, loop_end_offset;
    size_t data_size, chunk_size;
    int loop_flag, channel_count, sample_rate;
    int num_samples, loop_start_sample, loop_end_sample;
    uint32_t at9_config_data;
    gtd_codec codec;


    /* check extension, case insensitive */
    if ( !check_extensions(streamFile,"gtd"))
        goto fail;

    if (read_32bitBE(0x00,streamFile) != 0x47485320)   /* "GHS " */
        goto fail;

    /* header type, not formally specified */
    if (read_32bitBE(0x04,streamFile) == 1 && read_16bitBE(0x0C,streamFile) == 0x0166) { /* XMA2 */
        /* 0x08(4): seek table size */
        chunk_offset = 0x0c; /* custom header with a "fmt " data chunk inside */
        chunk_size = 0x34;

        channel_count = read_16bitBE(chunk_offset+0x02,streamFile);
        sample_rate   = read_32bitBE(chunk_offset+0x04,streamFile);
        xma2_parse_fmt_chunk_extra(streamFile, chunk_offset, &loop_flag, &num_samples, &loop_start_sample, &loop_end_sample, 1);

        start_offset = read_32bitBE(0x58,streamFile); /* always 0x800 */
        data_size = read_32bitBE(0x5c,streamFile);
        /* 0x34(18): null,  0x54(4): seek table offset, 0x58(4): seek table size, 0x5c(8): null, 0x64: seek table */

        stpr_offset = read_32bitBE(chunk_offset+0x54,streamFile) + read_32bitBE(chunk_offset+0x58,streamFile);
        if (read_32bitBE(stpr_offset,streamFile) == 0x53545052) { /* "STPR" */
            name_offset = stpr_offset + 0xB8; /* there are offsets fields but seems to work */
        }

        codec = XMA2;
    }
    else if (0x34 + read_32bitLE(0x30,streamFile) + read_32bitLE(0x0c,streamFile) == get_streamfile_size(streamFile)) { /* ATRAC9 */

        data_size = read_32bitLE(0x0c,streamFile);
        start_offset = 0x34 + read_32bitLE(0x30,streamFile);
        channel_count   = read_32bitLE(0x10,streamFile);
        sample_rate     = read_32bitLE(0x14,streamFile);
        loop_start_offset = read_32bitLE(0x1c, streamFile);
        loop_end_offset = read_32bitLE(0x20, streamFile);
        loop_flag = loop_end_offset > loop_start_offset;
        at9_config_data = read_32bitBE(0x28,streamFile);
        /* 0x18-0x28: fixed/unknown values */

        stpr_offset = 0x2c;
        if (read_32bitBE(stpr_offset,streamFile) == 0x53545052) { /* "STPR" */
            name_offset = stpr_offset + 0xE8; /* there are offsets fields but seems to work */
        }

        codec = ATRAC9;
    }
    else {
        /* apparently there is a PS3 variation (MSF inside?) */
        goto fail;
    }



    /* build the VGMSTREAM */
    vgmstream = allocate_vgmstream(channel_count,loop_flag);
    if (!vgmstream) goto fail;

    vgmstream->sample_rate = sample_rate;
    vgmstream->loop_start_sample = loop_start_sample;
    vgmstream->loop_end_sample   = loop_end_sample;
    vgmstream->meta_type = meta_GTD;
    if (name_offset) //encoding is Shift-Jis in some PSV files
        read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamFile);

    switch(codec) {
#ifdef VGM_USE_FFMPEG
        case XMA2: {
            uint8_t buf[0x100];
            size_t bytes;

            bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, chunk_offset,chunk_size, data_size, streamFile, 1);
            if (bytes <= 0) goto fail;

            vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);
            if ( !vgmstream->codec_data ) goto fail;
            vgmstream->coding_type = coding_FFmpeg;
            vgmstream->layout_type = layout_none;

            vgmstream->num_samples = num_samples;

            xma_fix_raw_samples(vgmstream, streamFile, start_offset, data_size, chunk_offset, 1,1);
            break;
        }
#endif
#ifdef VGM_USE_ATRAC9
        case ATRAC9: {
            atrac9_config cfg = {0};

            cfg.channels = vgmstream->channels;
            cfg.config_data = at9_config_data;

            vgmstream->codec_data = init_atrac9(&cfg);
            if (!vgmstream->codec_data) goto fail;
            vgmstream->coding_type = coding_ATRAC9;
            vgmstream->layout_type = layout_none;
            if (loop_flag) {
                vgmstream->loop_start_sample = atrac9_bytes_to_samples(loop_start_offset - start_offset, vgmstream->codec_data);
                vgmstream->loop_end_sample = atrac9_bytes_to_samples(loop_end_offset - start_offset, vgmstream->codec_data);
            }
            vgmstream->num_samples = atrac9_bytes_to_samples(data_size, vgmstream->codec_data);
            break;
        }

#endif

        default:
            goto fail;
    }


    /* open the file for reading */
    if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
        goto fail;
    return vgmstream;

fail:
    close_vgmstream(vgmstream);
    return NULL;
}
예제 #22
0
VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
    off_t stream_offset;
    uint16_t version_signature;
    int loop_flag=0;
    int channel_count, i, j, channel_header_spacing;
    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[PATH_LIMIT];
    int coding_type = coding_CRI_ADX;
    uint16_t xor_start=0,xor_mult=0,xor_add=0;
	/* Xenoblade Chronicles 3D uses an adx extension as with
	   the Wii version, but it's actually DSP ADPCM. Adding 
	   this flag to account for it. */
	int xb3d_flag = 0;
	
    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("adx",filename_extension(filename))) goto fail;

    /* check first 2 bytes */
    if ((uint16_t)read_16bitBE(0,streamFile)!=0x8000) {
		if (read_8bit(0,streamFile)!=2)goto fail;
		else {xb3d_flag = 1; coding_type = coding_NGC_DSP;}
	}
	
	if (xb3d_flag) {
		channel_count = read_32bitLE(0, streamFile);
		loop_flag = read_16bitLE(0x6e, streamFile);
		channel_header_spacing = 0x34;
	}
	else {
		/* 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);
			}

			/* AINF header can also start after the loop points
			 *  (may be inserted by CRI's tools but is rarely used) */
			/* ainf_magic = read_32bitBE(0x38,streamFile); */ /* 0x41494E46 */
            /* ainf_length = read_32bitBE(0x3c,streamFile); */
            /* ainf_str_id = read_string(0x40,streamFile); */ /* max size 0x10 */
            /* ainf_volume = read_16bitBE(0x50,streamFile); */ /* 0=base/max?, negative=reduce */
            /* ainf_pan_l = read_16bitBE(0x54,streamFile); */ /* 0=base, max +-128 */
            /* ainf_pan_r = read_16bitBE(0x56,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 */
  
	if (xb3d_flag) {
		for (j=0;j<vgmstream->channels;j++) {
            for (i=0;i<16;i++) {
                vgmstream->ch[j].adpcm_coef[i]=read_16bitLE(4+j*channel_header_spacing+i*2,streamFile);
            }
        }
		vgmstream->layout_type = layout_none;
		vgmstream->coding_type = coding_type;
		vgmstream->meta_type = meta_XB3D_ADX;
		vgmstream->sample_rate = read_32bitLE(0x70,streamFile);
		vgmstream->num_samples = read_32bitLE(0x74, streamFile);
		vgmstream->loop_start_sample = read_32bitLE(0x78, streamFile);
		vgmstream->loop_end_sample = read_32bitLE(0x7c, streamFile);
		
		for (i = 0; i<channel_count; i++) {
			vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename, 0x1000);
			vgmstream->ch[i].channel_start_offset = vgmstream->ch[i].offset
			= read_32bitLE(0x34+i*channel_header_spacing, streamFile);
			if (!vgmstream->ch[i].streamfile) goto fail;
		}
		
	}
	else {
		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;
}
예제 #23
0
파일: sab.c 프로젝트: kode54/vgmstream
/* SAB - from Worms 4: Mayhem (PC/Xbox/PS2) */
VGMSTREAM * init_vgmstream_sab(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
    off_t start_offset;
    int loop_flag, channel_count = 0, is_stream, align, codec, sample_rate, stream_size, loop_start, loop_end;
    int total_subsongs, target_subsong  = streamFile->stream_index;

    /* .sab: main, .sob: config/names */
    if (!check_extensions(streamFile,"sab"))
        goto fail;
    if (read_32bitBE(0x00,streamFile) != 0x43535732 &&  /* "CSW2" (Windows) */
        read_32bitBE(0x00,streamFile) != 0x43535032 &&  /* "CSP2" (PS2) */
        read_32bitBE(0x00,streamFile) != 0x43535832)    /* "CSX2" (Xbox) */
        goto fail;

    is_stream = read_32bitLE(0x04,streamFile) & 0x04; /* other flags don't seem to matter */
    total_subsongs = is_stream ? 1 : read_32bitLE(0x08,streamFile);
    if (target_subsong == 0) target_subsong = 1;
    if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;

    align = read_32bitLE(0x0c,streamFile); /* doubles as interleave */

    /* stream config */
    codec         = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x00,streamFile);
    channel_count = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x04,streamFile);
    sample_rate   = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x08,streamFile);
    stream_size   = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x0c,streamFile);
    loop_start    = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x10,streamFile);
    loop_end      = read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x14,streamFile);
    loop_flag     = (loop_end > 0);

    start_offset  = 0x18 + 0x1c*total_subsongs;
    if (start_offset % align)
        start_offset += align - (start_offset % align);
    start_offset += read_32bitLE(0x18 + 0x1c*(target_subsong-1) + 0x18,streamFile);

    if (is_stream) {
        channel_count = read_32bitLE(0x08,streamFile); /* uncommon, but non-stream stereo exists */
        stream_size *= channel_count;
    }

    /* build the VGMSTREAM */
    vgmstream = allocate_vgmstream(channel_count,loop_flag);
    if (!vgmstream) goto fail;

    vgmstream->sample_rate = sample_rate;
    vgmstream->num_streams = total_subsongs;
    vgmstream->stream_size = stream_size;
    vgmstream->meta_type = meta_SAB;

    switch(codec) {
        case 0x01: /* PC */
            vgmstream->coding_type = coding_PCM16LE;
            vgmstream->layout_type = layout_interleave;
            vgmstream->interleave_block_size = is_stream ? align : 0x02;

            vgmstream->num_samples = pcm_bytes_to_samples(stream_size, vgmstream->channels, 16);
            vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, vgmstream->channels, 16);
            vgmstream->loop_end_sample = pcm_bytes_to_samples(loop_end, vgmstream->channels, 16);

            break;

        case 0x04: /* PS2 */
            vgmstream->coding_type = coding_PSX;
            vgmstream->layout_type = layout_interleave;
            vgmstream->interleave_block_size = is_stream ? align : 0x10;

            vgmstream->num_samples = ps_bytes_to_samples(stream_size, vgmstream->channels);
            vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, vgmstream->channels);
            vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, vgmstream->channels);
            break;

        case 0x08: /* Xbox */
            vgmstream->coding_type = is_stream ? coding_XBOX_IMA_int : coding_XBOX_IMA;
            vgmstream->layout_type = is_stream ? layout_interleave : layout_none;
            vgmstream->interleave_block_size = is_stream ? align : 0x00;

            vgmstream->num_samples = xbox_ima_bytes_to_samples(stream_size, vgmstream->channels);
            vgmstream->loop_start_sample = xbox_ima_bytes_to_samples(loop_start, vgmstream->channels);
            vgmstream->loop_end_sample = xbox_ima_bytes_to_samples(loop_end, vgmstream->channels);
            break;

        default:
            VGM_LOG("SAB: unknown codec\n");
            goto fail;
    }

    get_stream_name(vgmstream->stream_name, streamFile, target_subsong);

    if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
        goto fail;
    return vgmstream;

fail:
    close_vgmstream(vgmstream);
    return NULL;
}
예제 #24
0
VGMSTREAM * init_vgmstream_ps2_wmus(STREAMFILE *streamFile) 
{
    VGMSTREAM * vgmstream = NULL;
    char filename[260];

    int loop_flag = 1;
	int channel_count;
    off_t start_offset;
    int i;
	
	int blockCount;
	int shortBlockSize;
	int lastBlockLocation;

	char	filenameWHED[260];
	STREAMFILE * streamFileWHED = NULL;

	//_TCHAR szBuffer[100];

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    
	if (strcasecmp("wmus",filename_extension(filename))) 
	{
		goto fail;
	}
	
	/* check for .WHED file */
	strcpy(filenameWHED, filename);
	strcpy(filenameWHED + strlen(filenameWHED) - 4, "WHED");

	streamFileWHED = streamFile->open(streamFile, filenameWHED, STREAMFILE_DEFAULT_BUFFER_SIZE);
	if (!streamFileWHED)
	{
		goto fail;
	}

	/* check loopand channel */
	loop_flag = 1;
    channel_count = read_32bitLE(0x14, streamFileWHED);
    
	/* 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(0x04, streamFileWHED);

	vgmstream->coding_type = coding_PSX;
    
	vgmstream->interleave_block_size = read_32bitLE(0x18, streamFileWHED);
	blockCount = read_32bitLE(0x1C, streamFileWHED) * channel_count;
	shortBlockSize = read_32bitLE(0x20, streamFileWHED);

	vgmstream->num_samples = (vgmstream->interleave_block_size * blockCount) / 16 / channel_count * 28;
	vgmstream->loop_start_sample = 0;
	
	lastBlockLocation = (vgmstream->interleave_block_size * blockCount) - (vgmstream->interleave_block_size - shortBlockSize);
	vgmstream->loop_end_sample = lastBlockLocation / 16 / channel_count * 28;

	//_stprintf(szBuffer, _T("%x"), lastBlockLocation);
	//MessageBox(NULL, szBuffer, _T("Foo"), MB_OK);


    vgmstream->layout_type = layout_interleave;
    vgmstream->meta_type = meta_PS2_WMUS;

	start_offset = 0;

    /* 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 (streamFileWHED) close_streamfile(streamFileWHED);
	if (vgmstream) close_vgmstream(vgmstream);
    return NULL;
}
예제 #25
0
VGMSTREAM * init_vgmstream_ps2_vbk(STREAMFILE *streamFile) 
{
    VGMSTREAM * vgmstream = NULL;
	char filename[260];
	off_t start_offset;
	uint8_t	testBuffer[0x10];
	off_t	loopStart = 0;
	off_t	loopEnd = 0;
	off_t	readOffset = 0;
	size_t	fileLength;
	int loop_flag;
	int channel_count;

    //_TCHAR szBuffer[100];

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("vbk",filename_extension(filename))) goto fail;

    /* check header */
    if (read_32bitBE(0x00,streamFile) != 0x2E56424B) /* .VBK */
        goto fail;

    loop_flag = 1;
    channel_count = read_32bitLE(0x28,streamFile) + 1;

	//_stprintf(szBuffer, _T("%x"), channel_count);
	//MessageBox(NULL, szBuffer, _T("Foo"), MB_OK);

	/* build the VGMSTREAM */
    vgmstream = allocate_vgmstream(channel_count,loop_flag);
    if (!vgmstream) goto fail;

	/* fill in the vital statistics */
    fileLength = get_streamfile_size(streamFile);
	start_offset = read_32bitLE(0x0C, streamFile);
	vgmstream->channels = channel_count;
    vgmstream->sample_rate = read_32bitLE(0x20,streamFile);
    vgmstream->coding_type = coding_PSX;
	vgmstream->num_samples = (fileLength - start_offset)*28/16/channel_count;
		
	// get loop start
	do {
		
		readOffset+=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); 

		if(testBuffer[0x01]==0x06) 
		{
			loopStart = readOffset-0x10;
			break;
		}

	} while (streamFile->get_offset(streamFile)<(int32_t)fileLength);
	
	
	// get loop end
	readOffset = fileLength - 0x10;
	
	do {		
		readOffset-=(off_t)read_streamfile(testBuffer,readOffset,0x10,streamFile); 

		/* Loop End */
		if(testBuffer[0x01]==0x03) 
		{
			loopEnd = readOffset-0x10;
			break;
		}
	} while (readOffset > 0);

	loop_flag = 1;
	vgmstream->loop_start_sample = (loopStart-start_offset)*28/16/channel_count;
    vgmstream->loop_end_sample = (loopEnd-start_offset)*28/16/channel_count;

    vgmstream->layout_type = layout_interleave;
    vgmstream->interleave_block_size = read_32bitLE(0x24,streamFile);
    vgmstream->meta_type = meta_PS2_VBK;

    /* 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;
}
예제 #26
0
VGMSTREAM * init_vgmstream_wii_str(STREAMFILE *streamFile) {
    
	VGMSTREAM * vgmstream = NULL;
	STREAMFILE * infileSTH = NULL;
	char filename[PATH_LIMIT];

	char * filenameSTH = NULL;

	int i, j, channel_count, loop_flag;

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("str",filename_extension(filename))) goto fail;

	/* check for .MIH file */
	filenameSTH=(char *)malloc(strlen(filename)+1);

	if (!filenameSTH) goto fail;

	strcpy(filenameSTH,filename);
	strcpy(filenameSTH+strlen(filenameSTH)-3,"sth");

	infileSTH = streamFile->open(streamFile,filenameSTH,STREAMFILE_DEFAULT_BUFFER_SIZE);

	/* STH File is necessary, so we can't confuse those file */
	/* with others .STR file as it is a very common extension */
	if (!infileSTH) goto fail;

	if(read_32bitLE(0x2C,infileSTH)!=0) 
		goto fail;

	channel_count = read_32bitBE(0x70,infileSTH);

	if(channel_count==1)
		loop_flag = (read_32bitBE(0xD4,infileSTH)==0x00740000);
	else
		loop_flag = (read_32bitBE(0x124,infileSTH)==0x00740000);

    /* 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(0x38,infileSTH);

	vgmstream->interleave_block_size=0x8000;
	vgmstream->num_samples=read_32bitBE(0x34,infileSTH);

	vgmstream->coding_type = coding_NGC_DSP;
    vgmstream->layout_type = layout_interleave;
    
	vgmstream->meta_type = meta_WII_STR;

	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,vgmstream->interleave_block_size);

            if (!vgmstream->ch[i].streamfile) goto fail;

            vgmstream->ch[i].channel_start_offset=
                vgmstream->ch[i].offset+=(off_t)(vgmstream->interleave_block_size*i);

			for(j=0; j<16; j++) {
				vgmstream->ch[i].adpcm_coef[j]=read_16bitBE(0xAC+(j*2)+(i*0x50),infileSTH);
			}
        }
    }

	close_streamfile(infileSTH); infileSTH=NULL;

    return vgmstream;

    /* clean up anything we may have opened */
fail:
    if (infileSTH) close_streamfile(infileSTH);
    if (filenameSTH) {free(filenameSTH); filenameSTH=NULL;}
    if (vgmstream) close_vgmstream(vgmstream);
    return NULL;
}
예제 #27
0
파일: emff.c 프로젝트: 1c0n/xbmc
/* EMFF - Eidos Music File Format (PS2),
Legacy of Kain - Defiance, possibly more... */
VGMSTREAM * init_vgmstream_emff_ps2(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
    char filename[260];
    off_t start_offset;
    int loop_flag = 0;
    int channel_count;
    int frequency;
    int i;

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("emff",filename_extension(filename))) goto fail;

    /* do some checks on the file, cause we	have no magic words to check the header...
    it seems if 0x800 and 0x804 = 0 then the file has only audio, if 0x800 = 1
    it has a text section, if both are 1 it's video with a text section included... */
    if (read_32bitBE(0x800,streamFile) == 0x01000000	|| /* "0x01000000" */
        read_32bitBE(0x804,streamFile) == 0x01000000)	/* "0x01000000" */
    goto fail;

    frequency = read_32bitLE(0x0,streamFile);
    channel_count = read_32bitLE(0xC,streamFile);

    if (frequency > 48000 ||
        channel_count > 8) {
        goto fail;
    }

    loop_flag = (read_32bitLE(0x4,streamFile) != 0xFFFFFFFF);
    
    /* build the VGMSTREAM */
    vgmstream = allocate_vgmstream(channel_count,loop_flag);
    if (!vgmstream) goto fail;

    /* fill in the vital statistics */
    start_offset = 0x800;
    vgmstream->sample_rate = frequency;
    vgmstream->channels = channel_count;
    vgmstream->coding_type = coding_PSX;

    vgmstream->layout_type = layout_emff_ps2_blocked;
    vgmstream->interleave_block_size = 0x10;
    vgmstream->meta_type = meta_EMFF_PS2;

    /* open the file for reading */
    {
        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;
        }
    }

    /* Calc num_samples */
    emff_ps2_block_update(start_offset,vgmstream);
    vgmstream->num_samples = read_32bitLE(0x8,streamFile);;
    if (loop_flag) {
        vgmstream->loop_start_sample = (read_32bitLE(0x28,streamFile)-start_offset)*28/16/channel_count;
        vgmstream->loop_end_sample = read_32bitLE(0x8,streamFile);
    }

    return vgmstream;

/* clean up anything we may have opened */
fail:
    if (vgmstream) close_vgmstream(vgmstream);
    return NULL;
}
예제 #28
0
/* 2PFS
	- Mahoromatic: Moetto - KiraKira Maid-San (PS2)

	
*/
VGMSTREAM * init_vgmstream_ps2_2pfs(STREAMFILE *streamFile) 
{
    VGMSTREAM * vgmstream = NULL;
    char filename[260];
    
	size_t fileLength;
	off_t readOffset = 0;
	off_t start_offset;

	int loop_flag = 0;
	int channel_count;

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("2pfs",filename_extension(filename))) goto fail;

    /* check header */
    if (read_32bitBE(0x00,streamFile) != 0x32504653) 
        goto fail;

	// channel count
	channel_count = read_8bit(0x40,streamFile);

	// header size
	start_offset = 0x800;
    
	// loop flag
	//if ((read_32bitLE(0x38, streamFile) != 0 || 
	//	(read_32bitLE(0x34, streamFile) != 0)))
	//{
	//	loop_flag = 1;
	//}

	// Loop info unknown right now
	//if (loop_flag) 
	//{
	//	vgmstream->loop_start_sample = read_32bitLE(0x38,streamFile)*28/16/channel_count;
	//	vgmstream->loop_end_sample = read_32bitLE(0x34,streamFile)*28/16/channel_count;
	//}

	/* 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(0x44,streamFile);
    vgmstream->coding_type = coding_PSX;
	vgmstream->num_samples = read_32bitLE(0x0C,streamFile)*28/16/channel_count;
 
    vgmstream->layout_type = layout_interleave;
    vgmstream->interleave_block_size = 0x1000;
    vgmstream->meta_type = meta_PS2_2PFS;

    /* 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;
}
예제 #29
0
파일: dc_str.c 프로젝트: flyingtime/boxee
VGMSTREAM * init_vgmstream_dc_str(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
    char filename[260];
    off_t start_offset;
    int loop_flag = 0;
    int interleave;
	int channel_count;
    int samples;
    int i;

    /* check extension, case insensitive */
    streamFile->get_name(streamFile,filename,sizeof(filename));
    if (strcasecmp("str",filename_extension(filename))) goto fail;

    /* check header */
    if (read_32bitBE(0xD5,streamFile) != 0x53656761) /* "Sega" */
        goto fail;

    interleave = read_32bitLE(0xC,streamFile);
    if ((get_streamfile_size(streamFile)-0x800) != (read_32bitLE(0x10,streamFile) *
        ((read_32bitLE(0x0,streamFile)*(read_32bitLE(0x18,streamFile))))*interleave))
        goto fail;
    

    loop_flag = 0; /* (read_32bitLE(0x00,streamFile)!=0x00000000); */
    samples = read_32bitLE(0x08,streamFile);
    channel_count = (read_32bitLE(0x0,streamFile))*(read_32bitLE(0x18,streamFile));

    vgmstream = allocate_vgmstream(channel_count,loop_flag);
    if (!vgmstream) goto fail;


	/* fill in the vital statistics */
    switch (samples) {
        case 4:
            vgmstream->coding_type = coding_AICA;
            vgmstream->num_samples = read_32bitLE(0x14,streamFile);
        if (loop_flag) {
            vgmstream->loop_start_sample = 0;
            vgmstream->loop_end_sample = read_32bitLE(0x14,streamFile);
        }
            break;
        case 16:
            vgmstream->coding_type = coding_PCM16LE;
            vgmstream->num_samples = read_32bitLE(0x14,streamFile)/2/channel_count;
        if (loop_flag) {
            vgmstream->loop_start_sample = 0;
            vgmstream->loop_end_sample = read_32bitLE(0x14,streamFile)/2/channel_count;
        }
            break;
        default:
    goto fail;
}

    
    start_offset = 0x800;
	vgmstream->channels = channel_count;
    vgmstream->sample_rate = read_32bitLE(0x04,streamFile);

    if (vgmstream->channels == 1) {
        vgmstream->layout_type = layout_none;
    } else if (vgmstream->channels > 1) {
        vgmstream->interleave_block_size = interleave;
        vgmstream->layout_type = layout_interleave;
    }
    
    vgmstream->meta_type = meta_DC_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;
}
예제 #30
0
/* .ADS - Sony's "Audio Stream" format [Edit Racing (PS2), Evergrace II (PS2), Pri-Saga! Portable (PSP)] */
VGMSTREAM * init_vgmstream_ps2_ads(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
    off_t start_offset;
    int loop_flag, channel_count, sample_rate, interleave, is_loop_samples = 0;
    size_t body_size, stream_size, file_size;
    uint32_t codec, loop_start_sample = 0, loop_end_sample = 0, loop_start_offset = 0, loop_end_offset = 0;
    coding_t coding_type;
    int ignore_silent_frame_cavia = 0, ignore_silent_frame_capcom = 0;


    /* checks */
    /* .ads: actual extension
     * .ss2: demuxed videos (fake?)
     * .pcm: Taisho Mononoke Ibunroku (PS2)
     * .adx: Armored Core 3 (PS2)
     * [no actual extension]: MotoGP (PS2)
     * .800: Mobile Suit Gundam: The One Year War (PS2) */
    if (!check_extensions(streamFile, "ads,ss2,pcm,adx,,800"))
        goto fail;

    if (read_32bitBE(0x00,streamFile) != 0x53536864 &&  /* "SShd" */
        read_32bitBE(0x20,streamFile) != 0x53536264)    /* "SSbd" */
        goto fail;
    if (read_32bitLE(0x04,streamFile) != 0x18 && /* standard header size */
        read_32bitLE(0x04,streamFile) != 0x20)   /* True Fortune (PS2) */
        goto fail;


    /* base values (a bit unorderly since devs hack ADS too much and detection is messy) */
    {
        codec = read_32bitLE(0x08,streamFile);
        sample_rate = read_32bitLE(0x0C,streamFile);
        channel_count = read_32bitLE(0x10,streamFile); /* up to 4 [Eve of Extinction (PS2)]*/
        interleave = read_32bitLE(0x14,streamFile); /* set even when mono */


        switch(codec) {
            case 0x01: /* official definition */
            case 0x80000001: /* [Evergrace II (PS2), but not other From Soft games] */
                coding_type = coding_PCM16LE;

                /* Angel Studios/Rockstar San Diego videos codec hijack [Red Dead Revolver (PS2), Spy Hunter 2 (PS2)] */
                if (sample_rate == 12000 && interleave == 0x200) {
                    sample_rate = 48000;
                    interleave = 0x40;
                    coding_type = coding_DVI_IMA_int;
                    /* should try to detect IMA data but it's not so easy, this works ok since
                     * no known games use these settings, videos normally are 48000/24000hz */
                }
                break;

            case 0x10: /* official definition */
            case 0x02: /* Capcom games extension, stereo only [Megaman X7 (PS2), Breath of Fire V (PS2), Clock Tower 3 (PS2)] */
                coding_type = coding_PSX;
                break;

            case 0x00: /* PCM16BE from official docs, probably never used */
            default:
                VGM_LOG("ADS: unknown codec\n");
                goto fail;
        }
    }


    /* sizes */
    {
        file_size = get_streamfile_size(streamFile);
        body_size = read_32bitLE(0x24,streamFile);

        /* bigger than file_size in rare cases, even if containing all data (ex. Megaman X7's SY04.ADS) */
        if (body_size + 0x28 > file_size) {
            body_size = file_size - 0x28;
        }

        /* True Fortune: weird stream size */
        if (body_size * 2 == file_size - 0x18) {
            body_size = (body_size * 2) - 0x10;
        }

        stream_size = body_size;
    }


    /* offset */
    {
        start_offset = 0x28;

        /* start padding (body size is ok, may have end padding) [Evergrace II (PS2), Armored Core 3 (PS2)] */
        /*  detection depends on files being properly ripped, so broken/cut files won't play ok */
        if (file_size - body_size >= 0x800) {
            start_offset = 0x800; /* aligned to sector */

            /* too much end padding, happens in Super Galdelic Hour's SEL.ADS, maybe in bad rips too */
            VGM_ASSERT(file_size - body_size > 0x8000, "ADS: big end padding %x\n", file_size - body_size);
        }

        /* "ADSC" container */
        if (coding_type == coding_PSX
                && read_32bitLE(0x28,streamFile) == 0x1000 /* real start */
                && read_32bitLE(0x2c,streamFile) == 0
                && read_32bitLE(0x1008,streamFile) != 0) {
            int i;
            int is_adsc = 1;

            /* should be empty up to data start */
            for (i = 0; i < 0xFDC/4; i++) {
                if (read_32bitLE(0x2c+(i*4),streamFile) != 0) {
                    is_adsc = 0;
                    break;
                }
            }

            if (is_adsc) {
                start_offset = 0x1000 - 0x08; /* remove "ADSC" alignment */
                /* stream_size doesn't count start offset padding */
            }
        }
    }


    /* loops */
    {
        uint32_t loop_start, loop_end;

        loop_start = read_32bitLE(0x18,streamFile);
        loop_end = read_32bitLE(0x1C,streamFile);

        loop_flag = 0;

        /* detect loops the best we can; docs say those are loop block addresses,
         * but each maker does whatever (no games seem to use PS-ADPCM loop flags though) */


        if (loop_start != 0xFFFFFFFF && loop_end == 0xFFFFFFFF) {

            if (codec == 0x02) { /* Capcom codec */
                /* Capcom games: loop_start is address * 0x10 [Mega Man X7, Breath of Fire V, Clock Tower 3] */
                loop_flag = ((loop_start * 0x10) + 0x200 < body_size); /* near the end (+0x20~80) means no loop */
                loop_start_offset = loop_start * 0x10;
                ignore_silent_frame_capcom = 1;
            }
            else if (read_32bitBE(0x28,streamFile) == 0x50414421) { /* "PAD!" padding until 0x800 */
                /* Super Galdelic Hour: loop_start is PCM bytes */
                loop_flag = 1;
                loop_start_sample = loop_start / 2 / channel_count;
                is_loop_samples = 1;
            }
            else if ((loop_start % 0x800 == 0) && loop_start > 0) {/* sector-aligned, min/0 is 0x800 */
                /* cavia games: loop_start is offset [Drakengard 1/2, GITS: Stand Alone Complex] */
                /* offset is absolute from the "cavia stream format" container that adjusts ADS start */
                loop_flag = 1;
                loop_start_offset = loop_start - 0x800;
                ignore_silent_frame_cavia = 1;
            }
            else if (loop_start % 0x800 != 0 || loop_start == 0) { /* not sector aligned */
                /* Katakamuna: loop_start is address * 0x10 */
                loop_flag = 1;
                loop_start_offset = loop_start * 0x10;
            }
        }
        else if (loop_start != 0xFFFFFFFF && loop_end != 0xFFFFFFFF
                && loop_end > 0) { /* ignore Kamen Rider Blade and others */
#if 0
            //todo improve detection to avoid clashing with address*0x20
            if (loop_end == body_size / 0x10) { /* always body_size? but not all files should loop */
                /* Akane Iro ni Somaru Saka - Parallel: loops is address * 0x10 */
                loop_flag = 1;
                loop_start_offset = loop_start * 0x10;
                loop_end_offset = loop_end * 0x10;
            }
#endif
            if (loop_end <= body_size / 0x70 && coding_type == coding_PCM16LE) { /* close to body_size */
                /* Armored Core - Nexus: loops is address * 0x70 */
                loop_flag = 1;
                loop_start_offset = loop_start * 0x70;
                loop_end_offset = loop_end * 0x70;
            }
            else if (loop_end <= body_size / 0x20 && coding_type == coding_PCM16LE) { /* close to body_size */
                /* Armored Core - Nine Breaker: loops is address * 0x20 */
                loop_flag = 1;
                loop_start_offset = loop_start * 0x20;
                loop_end_offset = loop_end * 0x20;
            }
            else if (loop_end <= body_size / 0x20 && coding_type == coding_PSX) { /* close to body_size */
                /* various games: loops is address * 0x20 [Fire Pro Wrestling Returns, A.C.E. - Another Century's Episode] */
                loop_flag = 1;
                loop_start_offset = loop_start * 0x20;
                loop_end_offset = loop_end * 0x20;
            }
            else if ((loop_end > body_size / 0x20 && coding_type == coding_PSX) ||
                     (loop_end > body_size / 0x70 && coding_type == coding_PCM16LE)) {
                /* various games: loops in samples [Eve of Extinction, Culdcept, WWE Smackdown! 3] */
                loop_flag = 1;
                loop_start_sample = loop_start;
                loop_end_sample = loop_end;
                is_loop_samples = 1;
            }
        }

        //todo Jet Ion Grand Prix seems to have some loop-like values at 0x28
        //todo Yoake mae yori Ruriiro na has loops in unknown format
    }


    /* most games have empty PS-ADPCM frames in the last interleave block that should be skipped for smooth looping */
    if (coding_type == coding_PSX) {
        off_t offset, min_offset;

        offset = start_offset + stream_size;
        min_offset = offset - interleave;

        do {
            offset -= 0x10;

            if (read_8bit(offset+0x01,streamFile) == 0x07) {
                stream_size -= 0x10*channel_count;/* ignore don't decode flag/padding frame (most common) [ex. Capcom games] */
            }
            else if (read_32bitBE(offset+0x00,streamFile) == 0x00000000 && read_32bitBE(offset+0x04,streamFile) == 0x00000000 &&
                     read_32bitBE(offset+0x08,streamFile) == 0x00000000 && read_32bitBE(offset+0x0c,streamFile) == 0x00000000) {
                stream_size -= 0x10*channel_count; /* ignore null frame [ex. A.C.E. Another Century Episode 1/2/3] */
            }
            else if (read_32bitBE(offset+0x00,streamFile) == 0x00007777 && read_32bitBE(offset+0x04,streamFile) == 0x77777777 &&
                     read_32bitBE(offset+0x08,streamFile) == 0x77777777 && read_32bitBE(offset+0x0c,streamFile) == 0x77777777) {
                stream_size -= 0x10*channel_count; /* ignore padding frame [ex. Akane Iro ni Somaru Saka - Parallel]  */
            }
            else if (read_32bitBE(offset+0x00,streamFile) == 0x0C020000 && read_32bitBE(offset+0x04,streamFile) == 0x00000000 &&
                     read_32bitBE(offset+0x08,streamFile) == 0x00000000 && read_32bitBE(offset+0x0c,streamFile) == 0x00000000 &&
                     ignore_silent_frame_cavia) {
                stream_size -= 0x10*channel_count; /* ignore silent frame [ex. cavia games]  */
            }
            else if (read_32bitBE(offset+0x00,streamFile) == 0x0C010000 && read_32bitBE(offset+0x04,streamFile) == 0x00000000 &&
                     read_32bitBE(offset+0x08,streamFile) == 0x00000000 && read_32bitBE(offset+0x0c,streamFile) == 0x00000000 &&
                     ignore_silent_frame_capcom) {
                stream_size -= 0x10*channel_count; /* ignore silent frame [ex. Capcom games]  */
            }
            else {
                break; /* standard frame */
            }
        }
        while(offset > min_offset);

        /* don't bother fixing loop_end_offset since will be adjusted to num_samples later, if needed */
    }


    /* build the VGMSTREAM */
    vgmstream = allocate_vgmstream(channel_count,loop_flag);
    if (!vgmstream) goto fail;

    vgmstream->sample_rate = sample_rate;
    vgmstream->coding_type = coding_type;
    vgmstream->interleave_block_size = interleave;
    vgmstream->layout_type = layout_interleave;
    vgmstream->meta_type = meta_PS2_SShd;

    switch(coding_type) {
        case coding_PCM16LE:
            vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16);
            break;
        case coding_PSX:
            vgmstream->num_samples = ps_bytes_to_samples(stream_size, channel_count);
            break;
        case coding_DVI_IMA_int:
            vgmstream->num_samples = ima_bytes_to_samples(stream_size, channel_count);
            break;
        default:
            goto fail;
    }

    if (vgmstream->loop_flag) {
        if (is_loop_samples) {
            vgmstream->loop_start_sample = loop_start_sample;
            vgmstream->loop_end_sample = loop_end_sample;
        }
        else {
            switch(vgmstream->coding_type) {
                case coding_PCM16LE:
                    vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start_offset,channel_count,16);
                    vgmstream->loop_end_sample = pcm_bytes_to_samples(loop_end_offset,channel_count,16);
                    break;
                case coding_PSX:
                    vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start_offset,channel_count);
                    vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end_offset,channel_count);
                    break;
                default:
                    goto fail;
            }
        }

        /* when loop_end = 0xFFFFFFFF */
        if (vgmstream->loop_end_sample == 0)
            vgmstream->loop_end_sample = vgmstream->num_samples;

        /* happens even when loops are directly samples, loops sound fine (ex. Culdcept) */
        if (vgmstream->loop_end_sample > vgmstream->num_samples)
            vgmstream->loop_end_sample = vgmstream->num_samples;
    }


    if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
        goto fail;
    return vgmstream;

fail:
    close_vgmstream(vgmstream);
    return NULL;
}