Beispiel #1
0
VGMSTREAM * init_vgmstream_sab(STREAMFILE *streamFile) {
    VGMSTREAM * vgmstream = NULL;
	STREAMFILE* sob = NULL;
    char filename[1024];
	int i;
	int loop_flag, channel_count, numSounds;

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

	/* read information from sob file*/
	filename[strlen(filename)-2]='o'; //change extension in sob of file
	sob = open_stdio_streamfile(filename);
	if(!sob) goto fail;
	filename[strlen(filename)-2]='a';//change back to original file

	if (read_32bitBE(0,streamFile)!=0x43535732)//CSW2 header sab file
	{
		goto fail;
	}
	if (read_32bitBE(0,sob)!=0x43544632)//CTF2 header sob file
	{
		goto fail;
	}
	numSounds = read_32bitLE(8,sob);
	if(numSounds==1)
	{//it means it's a single stream and not a voice bank
		loop_flag = 1;
	}else
	{
		loop_flag = 0;
	}
    
	/* Read channels */
	channel_count = read_32bitLE(0x30,sob);
	if( (channel_count>2)||(numSounds>1))/* dirty hack for number of channels*/
		channel_count = 1;

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

    /* fill in the vital statistics */
	//is offset OK. sab files can contain more audio files, but without the sob it's just a long stream of sound effects
	vgmstream->current_block_offset=8+32*numSounds;
    vgmstream->channels = channel_count;
	vgmstream->sample_rate = read_32bitLE(0x20,streamFile);
    vgmstream->coding_type = coding_PCM16LE_int;
    vgmstream->num_samples = (int32_t)((get_streamfile_size(streamFile)-vgmstream->current_block_offset)/2/channel_count);
	if(loop_flag)
	{
		vgmstream->loop_start_sample = 0;
		vgmstream->loop_end_sample = vgmstream->num_samples;
	}
    vgmstream->layout_type = layout_none;
    vgmstream->meta_type = meta_PC_SOB_SAB;
	
    {
        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;
            vgmstream->ch[i].channel_start_offset=
                vgmstream->ch[i].offset=vgmstream->current_block_offset+2*i;
        }
    }
	close_streamfile(sob);
    return vgmstream;

    /* clean up anything we may have opened */
fail:
	if (sob) close_streamfile(sob);
    if (vgmstream) close_vgmstream(vgmstream);
    return NULL;
}
Beispiel #2
0
static int play_vgmstream(const char *filename, struct params *par) {
    int ret = 0;
    STREAMFILE *sf;
    VGMSTREAM *vgms;
    FILE *save_fps[4];
    int loop_count;
    int64_t total_samples;
    size_t buffer_size;
    int64_t buffer_samples;
    int64_t fade_time_samples, fade_start;
    int time_total_min;
    double time_total_sec;
    int64_t s;
    int i;

    sf = open_stdio_streamfile(filename);
    if (!sf) {
        fprintf(stderr, "%s: cannot open file\n", filename);
        return -1;
    }

    sf->stream_index = par->stream_index;
    vgms = init_vgmstream_from_STREAMFILE(sf);
    close_streamfile(sf);

    if (!vgms) {
        fprintf(stderr, "%s: error opening stream\n", filename);
        return -1;
    }

    printf("Playing stream: %s\n", filename);

    /* Print metadata in verbose mode
     */
    if (verbose) {
        char description[4096] = { '\0' };
        describe_vgmstream(vgms, description, sizeof(description));
        puts(description);
        putchar('\n');
    }

    /* If the audio device hasn't been opened yet, then describe it
     */
    if (!device) {
        ao_info *info = ao_driver_info(driver_id);
        printf("Audio device: %s\n", info->name);
        printf("Comment: %s\n", info->comment);
        putchar('\n');
    }

    /* Stupid hack to hang onto a few low-numbered file descriptors
     * so that play_compressed_file() doesn't break, due to POSIX
     * wackiness like https://bugs.debian.org/590920
     */
    for (i = 0; i < 4; i++)
        save_fps[i] = fopen("/dev/null", "r");

    ret = set_sample_format(vgms);
    if (ret) goto fail;

    loop_count = par->loop_count;

    if (vgms->loop_flag && loop_count < 0) {
        /*
         * Calculate how many loops are needed to achieve a minimum
         * playback time. Note: This calculation is derived from the
         * logic in get_vgmstream_play_samples().
         */
        double intro = (double)vgms->loop_start_sample / vgms->sample_rate;
        double loop = (double)(vgms->loop_end_sample - vgms->loop_start_sample) / vgms->sample_rate;
        double end = par->fade_time + par->fade_delay;
        if (loop < 1.0) loop = 1.0;
        loop_count = (int)((par->min_time - intro - end) / loop + 0.99);
        if (loop_count < 1) loop_count = 1;
    }

    total_samples = get_vgmstream_play_samples(loop_count, par->fade_time, par->fade_delay, vgms);

    {
        double total = (double)total_samples / vgms->sample_rate;
        time_total_min = (int)total / 60;
        time_total_sec = total - 60 * time_total_min;
    }

    /* Buffer size in bytes
     */
    buffer_size = 1024 * buffer_size_kb;

    if (!buffer) {
        if (buffer_size_kb < 1) {
            fprintf(stderr, "Invalid buffer size '%d'\n", buffer_size_kb);
            return -1;
        }

        buffer = malloc(buffer_size);
        if (!buffer) goto fail;
    }

    buffer_samples = buffer_size / (vgms->channels * sizeof(sample));

    fade_time_samples = (int64_t)(par->fade_time * vgms->sample_rate);
    fade_start = total_samples - fade_time_samples;
    if (fade_start < 0)
        fade_start = total_samples;

    for (s = 0; s < total_samples && !interrupted; s += buffer_samples) {
        int64_t buffer_used_samples = MIN(buffer_samples, total_samples - s);
        char *suffix = "";

        render_vgmstream(buffer, buffer_used_samples, vgms);

#ifdef LITTLE_ENDIAN_OUTPUT
        swap_samples_le(buffer, vgms->channels * buffer_used_samples);
#endif

        if (vgms->loop_flag && fade_time_samples > 0 && s >= fade_start) {
            /* Got to do the fade-out ourselves :p */
            int64_t b;
            for (b = 0; b < buffer_used_samples; b++) {
                double factor = 1.0 - (double)(s + b - fade_start) / fade_time_samples;
                int c;
                for (c = 0; c < vgms->channels; c++)
                    buffer[vgms->channels * b + c] *= factor;
            }
            suffix = " (fading)";
        }

        if (verbose && !out_filename) {
            double played = (double)s / vgms->sample_rate;
            double remain = (double)(total_samples - s) / vgms->sample_rate;

            int time_played_min = (int)played / 60;
            double time_played_sec = played - 60 * time_played_min;
            int time_remain_min = (int)remain / 60;
            double time_remain_sec = remain - 60 * time_remain_min;

            /* Time: 01:02.34 [08:57.66] of 10:00.00 */
            printf("\rTime: %02d:%05.2f [%02d:%05.2f] of %02d:%05.2f%s ",
                time_played_min, time_played_sec,
                time_remain_min, time_remain_sec,
                time_total_min,  time_total_sec,
                suffix);

            fflush(stdout);
        }

        if (!ao_play(device, (char *)buffer, buffer_used_samples * vgms->channels * sizeof(sample))) {
            fputs("\nAudio playback error\n", stderr);
            ao_close(device);
            device = NULL;
            ret = -1;
            break;
        }
    }

    if (verbose && !ret) {
        /* Clear time status line */
        putchar('\r');
        for (i = 0; i < 64; i++)
            putchar(' ');
        putchar('\r');
        fflush(stdout);
    }

    if (out_filename && !ret)
        printf("Wrote %02d:%05.2f of audio to %s\n\n",
            time_total_min, time_total_sec, out_filename);

    if (interrupted) {
        fputs("Playback terminated.\n\n", stdout);
        ret = record_interrupt();
        if (ret) fputs("Exiting...\n", stdout);
    }

    fail:

    close_vgmstream(vgms);

    for (i = 0; i < 4; i++)
        fclose(save_fps[i]);

    return ret;
}